$extrastylesheet
00001 // The libMesh Finite Element Library. 00002 // Copyright (C) 2002-2014 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner 00003 00004 // This library is free software; you can redistribute it and/or 00005 // modify it under the terms of the GNU Lesser General Public 00006 // License as published by the Free Software Foundation; either 00007 // version 2.1 of the License, or (at your option) any later version. 00008 00009 // This library is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 // Lesser General Public License for more details. 00013 00014 // You should have received a copy of the GNU Lesser General Public 00015 // License along with this library; if not, write to the Free Software 00016 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00017 00018 00019 // C++ includes 00020 #include <iomanip> 00021 #include <algorithm> // for std::sort 00022 #include <fstream> 00023 #include <ctype.h> // isspace 00024 #include <sstream> // std::istringstream 00025 00026 // Local includes 00027 #include "libmesh/libmesh_config.h" 00028 #include "libmesh/libmesh_logging.h" 00029 #include "libmesh/unv_io.h" 00030 #include "libmesh/mesh_data.h" 00031 #include "libmesh/mesh_base.h" 00032 #include "libmesh/edge_edge2.h" 00033 #include "libmesh/face_quad4.h" 00034 #include "libmesh/face_tri3.h" 00035 #include "libmesh/face_tri6.h" 00036 #include "libmesh/face_quad8.h" 00037 #include "libmesh/face_quad9.h" 00038 #include "libmesh/cell_tet4.h" 00039 #include "libmesh/cell_hex8.h" 00040 #include "libmesh/cell_hex20.h" 00041 #include "libmesh/cell_tet10.h" 00042 #include "libmesh/cell_prism6.h" 00043 00044 #ifdef LIBMESH_HAVE_GZSTREAM 00045 # include "gzstream.h" // For reading/writing compressed streams 00046 #endif 00047 00048 00049 00050 namespace libMesh 00051 { 00052 00053 00054 00055 //----------------------------------------------------------------------------- 00056 // UNVIO class static members 00057 const std::string UNVIO::_nodes_dataset_label = "2411"; 00058 const std::string UNVIO::_elements_dataset_label = "2412"; 00059 const std::string UNVIO::_groups_dataset_label = "2467"; 00060 00061 00062 00063 // ------------------------------------------------------------ 00064 // UNVIO class members 00065 00066 UNVIO::UNVIO (MeshBase& mesh, MeshData* mesh_data) : 00067 MeshInput<MeshBase> (mesh), 00068 MeshOutput<MeshBase>(mesh), 00069 _verbose (false), 00070 _mesh_data (mesh_data) 00071 { 00072 } 00073 00074 00075 00076 UNVIO::UNVIO (const MeshBase& mesh, MeshData* mesh_data) : 00077 MeshOutput<MeshBase> (mesh), 00078 _verbose (false), 00079 _mesh_data (mesh_data) 00080 { 00081 } 00082 00083 00084 00085 UNVIO::~UNVIO () 00086 { 00087 } 00088 00089 00090 00091 bool & UNVIO::verbose () 00092 { 00093 return _verbose; 00094 } 00095 00096 00097 00098 void UNVIO::read (const std::string& file_name) 00099 { 00100 if (file_name.rfind(".gz") < file_name.size()) 00101 { 00102 #ifdef LIBMESH_HAVE_GZSTREAM 00103 00104 igzstream in_stream (file_name.c_str()); 00105 this->read_implementation (in_stream); 00106 00107 #else 00108 00109 libmesh_error_msg("ERROR: You must have the zlib.h header files and libraries to read and write compressed streams."); 00110 00111 #endif 00112 return; 00113 } 00114 00115 else 00116 { 00117 std::ifstream in_stream (file_name.c_str()); 00118 this->read_implementation (in_stream); 00119 return; 00120 } 00121 } 00122 00123 00124 void UNVIO::read_implementation (std::istream& in_stream) 00125 { 00126 // Keep track of what kinds of elements this file contains 00127 elems_of_dimension.clear(); 00128 elems_of_dimension.resize(4, false); 00129 00130 { 00131 if ( !in_stream.good() ) 00132 libmesh_error_msg("ERROR: Input file not good."); 00133 00134 // Flags to be set when certain sections are encountered 00135 bool 00136 found_node = false, 00137 found_elem = false, 00138 found_group = false; 00139 00140 // strings for reading the file line by line 00141 std::string 00142 old_line, 00143 current_line; 00144 00145 while (true) 00146 { 00147 // Save off the old_line. This will provide extra reliability 00148 // for detecting the beginnings of the different sections. 00149 old_line = current_line; 00150 00151 // Try to read something. This may set EOF! 00152 std::getline(in_stream, current_line); 00153 00154 // If the stream is still "valid", parse the line 00155 if (in_stream) 00156 { 00157 // UNV files always have some amount of leading 00158 // whitespace, let's not rely on exactly how much... This 00159 // command deletes it. 00160 current_line.erase(std::remove_if(current_line.begin(), current_line.end(), isspace), 00161 current_line.end()); 00162 00163 // Parse the nodes section 00164 if (current_line == _nodes_dataset_label && 00165 old_line == "-1") 00166 { 00167 found_node = true; 00168 this->nodes_in(in_stream); 00169 } 00170 00171 // Parse the elements section 00172 else if (current_line == _elements_dataset_label && 00173 old_line == "-1") 00174 { 00175 // The current implementation requires the nodes to 00176 // have been read before reaching the elements 00177 // section. 00178 if (!found_node) 00179 libmesh_error_msg("ERROR: The Nodes section must come before the Elements section of the UNV file!"); 00180 00181 found_elem = true; 00182 this->elements_in(in_stream); 00183 } 00184 00185 // Parse the groups section 00186 else if (current_line == _groups_dataset_label && 00187 old_line == "-1") 00188 { 00189 // The current implementation requires the nodes and 00190 // elements to have already been read before reaching 00191 // the groups section. 00192 if (!found_node || !found_elem) 00193 libmesh_error_msg("ERROR: The Nodes and Elements sections must come before the Groups section of the UNV file!"); 00194 00195 found_group = true; 00196 this->groups_in(in_stream); 00197 } 00198 00199 // We can stop reading once we've found the nodes, elements, 00200 // and group sections. 00201 if (found_node && found_elem && found_group) 00202 break; 00203 00204 // If we made it here, we're not done yet, so keep reading 00205 continue; 00206 } 00207 00208 // if (!in_stream) check to see if EOF was set. If so, break out of while loop. 00209 if (in_stream.eof()) 00210 break; 00211 00212 // If !in_stream and !in_stream.eof(), stream is in a bad state! 00213 libmesh_error_msg("Stream is bad! Perhaps the file does not exist?"); 00214 } // end while (true) 00215 00216 // By now we better have found the datasets for nodes and elements, 00217 // otherwise the unv file is bad! 00218 if (!found_node) 00219 libmesh_error_msg("ERROR: Could not find nodes!"); 00220 00221 if (!found_elem) 00222 libmesh_error_msg("ERROR: Could not find elements!"); 00223 } 00224 00225 00226 00227 { 00228 // Set the mesh dimension to the largest element dimension encountered 00229 MeshInput<MeshBase>::mesh().set_mesh_dimension(max_elem_dimension_seen()); 00230 00231 #if LIBMESH_DIM < 3 00232 if (MeshInput<MeshBase>::mesh().mesh_dimension() > LIBMESH_DIM) 00233 libmesh_error_msg("Cannot open dimension " \ 00234 << MeshInput<MeshBase>::mesh().mesh_dimension() \ 00235 << " mesh file when configured without " \ 00236 << MeshInput<MeshBase>::mesh().mesh_dimension() \ 00237 << "D support." ); 00238 #endif 00239 00240 // Possibly tell the MeshData object that we are finished 00241 // reading data. 00242 if (_mesh_data) 00243 _mesh_data->close_foreign_id_maps (); 00244 00245 // Delete any lower-dimensional elements that might have been 00246 // added to the mesh stricly for setting BCs. 00247 { 00248 // Grab reference to the Mesh 00249 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00250 00251 unsigned char max_dim = this->max_elem_dimension_seen(); 00252 00253 MeshBase::const_element_iterator el = mesh.elements_begin(); 00254 const MeshBase::const_element_iterator end_el = mesh.elements_end(); 00255 00256 for (; el != end_el; ++el) 00257 { 00258 Elem* elem = *el; 00259 00260 if (elem->dim() < max_dim) 00261 mesh.delete_elem(elem); 00262 } 00263 } 00264 00265 if (this->verbose()) 00266 libMesh::out << " Finished." << std::endl << std::endl; 00267 } 00268 } 00269 00270 00271 00272 00273 00274 void UNVIO::write (const std::string& file_name) 00275 { 00276 if (file_name.rfind(".gz") < file_name.size()) 00277 { 00278 #ifdef LIBMESH_HAVE_GZSTREAM 00279 00280 ogzstream out_stream(file_name.c_str()); 00281 this->write_implementation (out_stream); 00282 00283 #else 00284 00285 libmesh_error_msg("ERROR: You must have the zlib.h header files and libraries to read and write compressed streams."); 00286 00287 #endif 00288 00289 return; 00290 } 00291 00292 else 00293 { 00294 std::ofstream out_stream (file_name.c_str()); 00295 this->write_implementation (out_stream); 00296 return; 00297 } 00298 } 00299 00300 00301 00302 00303 void UNVIO::write_implementation (std::ostream& out_file) 00304 { 00305 if ( !out_file.good() ) 00306 libmesh_error_msg("ERROR: Output file not good."); 00307 00308 // If we have a MeshData object, possibly set it to use "compatibility" mode. 00309 if (_mesh_data && !(_mesh_data->active()) && !(_mesh_data->compatibility_mode())) 00310 { 00311 libMesh::err << std::endl 00312 << "*************************************************************************" << std::endl 00313 << "* WARNING: MeshData neither active nor in compatibility mode. *" << std::endl 00314 << "* Enable compatibility mode for MeshData. Use this Universal *" << std::endl 00315 << "* file with caution: libMesh node and element ids are used. *" << std::endl 00316 << "*************************************************************************" << std::endl 00317 << std::endl; 00318 _mesh_data->enable_compatibility_mode(); 00319 } 00320 00321 // write the nodes, then the elements 00322 this->nodes_out (out_file); 00323 this->elements_out (out_file); 00324 } 00325 00326 00327 00328 00329 void UNVIO::nodes_in (std::istream& in_file) 00330 { 00331 START_LOG("nodes_in()","UNVIO"); 00332 00333 if (this->verbose()) 00334 libMesh::out << " Reading nodes" << std::endl; 00335 00336 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00337 00338 // node label, we use an int here so we can read in a -1 00339 int node_label; 00340 00341 // always 3 coordinates in the UNV file, no matter 00342 // what LIBMESH_DIM is. 00343 Point xyz; 00344 00345 // We'll just read the floating point values as strings even when 00346 // there are no "D" characters in the file. This will make parsing 00347 // the file a bit slower but the logic to do so will all be 00348 // simplified and in one place... 00349 std::string line; 00350 std::istringstream coords_stream; 00351 00352 // Continue reading nodes until there are none left 00353 unsigned ctr = 0; 00354 while (true) 00355 { 00356 // Read the node label 00357 in_file >> node_label; 00358 00359 // Break out of the while loop when we hit -1 00360 if (node_label == -1) 00361 break; 00362 00363 // Read and discard the the rest of the node data on this line 00364 // which we do not currently use: 00365 // .) exp_coord_sys_num 00366 // .) disp_coord_sys_num 00367 // .) color 00368 std::getline(in_file, line); 00369 00370 // read the floating-point data 00371 std::getline(in_file, line); 00372 00373 // Replace any "D" characters used for exponents with "E" 00374 size_t last_pos = 0; 00375 while (true) 00376 { 00377 last_pos = line.find("D", last_pos); 00378 00379 if (last_pos != std::string::npos) 00380 line.replace(last_pos, 1, "E"); 00381 else 00382 break; 00383 } 00384 00385 // Construct a stream object from the current line and then 00386 // stream in the xyz values. 00387 coords_stream.str(line); 00388 coords_stream.clear(); // clear iostate bits! Important! 00389 coords_stream >> xyz(0) >> xyz(1) >> xyz(2); 00390 00391 // set up the id map 00392 _unv_node_id_to_libmesh_node_id[node_label] = ctr; 00393 00394 // add node to the Mesh 00395 Node* added_node = mesh.add_point(xyz, ctr++); 00396 00397 // tell the MeshData object the foreign node id 00398 if (_mesh_data) 00399 _mesh_data->add_foreign_node_id (added_node, node_label); 00400 } 00401 00402 STOP_LOG("nodes_in()","UNVIO"); 00403 } 00404 00405 00406 00407 unsigned char UNVIO::max_elem_dimension_seen () 00408 { 00409 unsigned char max_dim = 0; 00410 00411 unsigned char elem_dimensions_size = cast_int<unsigned char> 00412 (elems_of_dimension.size()); 00413 // The elems_of_dimension array is 1-based in the UNV reader 00414 for (unsigned char i=1; i<elem_dimensions_size; ++i) 00415 if (elems_of_dimension[i]) 00416 max_dim = i; 00417 00418 return max_dim; 00419 } 00420 00421 00422 00423 void UNVIO::groups_in (std::istream& in_file) 00424 { 00425 // Grab reference to the Mesh, so we can add boundary info data to it 00426 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00427 00428 // Record the max and min element dimension seen while reading the file. 00429 unsigned char max_dim = this->max_elem_dimension_seen(); 00430 00431 // map from (node ids) to elem of lower dimensional elements that can provide boundary conditions 00432 typedef std::map<std::vector<dof_id_type>, Elem*> provide_bcs_t; 00433 provide_bcs_t provide_bcs; 00434 00435 // Read groups until there aren't any more to read... 00436 while (true) 00437 { 00438 // If we read a -1, it means there is nothing else to read in this section. 00439 int group_number; 00440 in_file >> group_number; 00441 00442 if (group_number == -1) 00443 break; 00444 00445 // The first record consists of 8 entries: 00446 // Field 1 -- group number (that we just read) 00447 // Field 2 -- active constraint set no. for group 00448 // Field 3 -- active restraint set no. for group 00449 // Field 4 -- active load set no. for group 00450 // Field 5 -- active dof set no. for group 00451 // Field 6 -- active temperature set no. for group 00452 // Field 7 -- active contact set no. for group 00453 // Field 8 -- number of entities in group 00454 // Only the first and last of these are relevant to us... 00455 unsigned num_entities; 00456 std::string group_name; 00457 { 00458 unsigned dummy; 00459 in_file >> dummy >> dummy >> dummy >> dummy >> dummy >> dummy 00460 >> num_entities; 00461 00462 // The second record has 1 field, the group name 00463 in_file >> group_name; 00464 } 00465 00466 // The dimension of the elements in the group will determine 00467 // whether this is a sideset group or a subdomain group. 00468 bool 00469 is_subdomain_group = false, 00470 is_sideset_group = false; 00471 00472 // Each subsequent line has 8 entries, there are two entity type 00473 // codes and two tags per line that we need to read. In all my 00474 // examples, the entity type code was always "8", which stands for 00475 // "finite elements" but it's possible that we could eventually 00476 // support other entity type codes... 00477 // Field 1 -- entity type code 00478 // Field 2 -- entity tag 00479 // Field 3 -- entity node leaf id. 00480 // Field 4 -- entity component/ ham id. 00481 // Field 5 -- entity type code 00482 // Field 6 -- entity tag 00483 // Field 7 -- entity node leaf id. 00484 // Field 8 -- entity component/ ham id. 00485 { 00486 unsigned entity_type_code, entity_tag, dummy; 00487 for (unsigned entity=0; entity<num_entities; ++entity) 00488 { 00489 in_file >> entity_type_code >> entity_tag >> dummy >> dummy; 00490 00491 if (entity_type_code != 8) 00492 libMesh::err << "Warning, unrecognized entity type code = " 00493 << entity_type_code 00494 << " in group " 00495 << group_name 00496 << std::endl; 00497 00498 // Try to find this ID in the map from UNV element ids to libmesh ids. 00499 std::map<unsigned, unsigned>::iterator it = 00500 _unv_elem_id_to_libmesh_elem_id.find(entity_tag); 00501 00502 if (it != _unv_elem_id_to_libmesh_elem_id.end()) 00503 { 00504 unsigned libmesh_elem_id = it->second; 00505 00506 // Attempt to get a pointer to the elem listed in the group 00507 Elem* group_elem = mesh.elem(libmesh_elem_id); 00508 if (!group_elem) 00509 libmesh_error_msg("Group referred to non-existent element with ID " << libmesh_elem_id); 00510 00511 // dim < max_dim means the Elem defines a boundary condition 00512 if (group_elem->dim() < max_dim) 00513 { 00514 is_sideset_group = true; 00515 00516 // We can only handle elements that are *exactly* 00517 // one dimension lower than the max element 00518 // dimension. Not sure if "edge" BCs in 3D 00519 // actually make sense/are required... 00520 if (group_elem->dim()+1 != max_dim) 00521 libmesh_error_msg 00522 ("ERROR: Expected boundary element of dimension " << 00523 max_dim-1 << " but got " << group_elem->dim()); 00524 00525 // To be pushed into the provide_bcs data container 00526 std::vector<dof_id_type> group_elem_node_ids(group_elem->n_nodes()); 00527 00528 // Save node IDs in a local vector which will be used as a key for the map. 00529 for (unsigned n=0; n<group_elem->n_nodes(); n++) 00530 group_elem_node_ids[n] = group_elem->node(n); 00531 00532 // Set the current group number as the lower-dimensional element's subdomain ID. 00533 // We will use this later to set a boundary ID. 00534 group_elem->subdomain_id() = 00535 cast_int<subdomain_id_type>(group_number); 00536 00537 // Sort before putting into the map 00538 std::sort(group_elem_node_ids.begin(), group_elem_node_ids.end()); 00539 00540 // Ensure that this key doesn't already exist when 00541 // inserting it. We would need to use a multimap if 00542 // the same element appears in multiple group numbers! 00543 // This actually seems like it could be relatively 00544 // common, but I don't have a test for it at the 00545 // moment... 00546 std::pair<provide_bcs_t::iterator, bool> result = 00547 provide_bcs.insert(std::make_pair(group_elem_node_ids, group_elem)); 00548 00549 if (!result.second) 00550 libmesh_error_msg("Boundary element " << group_elem->id() << " was not inserted, it was already in the map!"); 00551 } 00552 00553 // dim == max_dim means this group defines a subdomain ID 00554 else if (group_elem->dim() == max_dim) 00555 { 00556 is_subdomain_group = true; 00557 group_elem->subdomain_id() = 00558 cast_int<subdomain_id_type>(group_number); 00559 } 00560 00561 else 00562 libmesh_error_msg("ERROR: Found an elem with dim=" 00563 << group_elem->dim() << " > " << 00564 "max_dim=" << +max_dim); 00565 } 00566 else 00567 libMesh::err << "WARNING: UNV Element " << entity_tag << " not found while parsing groups." << std::endl; 00568 } // end for (entity) 00569 } // end scope 00570 00571 // Associate this group_number with the group_name in the BoundaryInfo object. 00572 if (is_sideset_group) 00573 mesh.get_boundary_info().sideset_name 00574 (cast_int<boundary_id_type>(group_number)) = group_name; 00575 00576 if (is_subdomain_group) 00577 mesh.subdomain_name 00578 (cast_int<subdomain_id_type>(group_number)) = group_name; 00579 00580 } // end while (true) 00581 00582 // Loop over elements and try to assign boundary information 00583 { 00584 MeshBase::element_iterator it = mesh.active_elements_begin(); 00585 const MeshBase::element_iterator end = mesh.active_elements_end(); 00586 for ( ; it != end; ++it) 00587 { 00588 Elem* elem = *it; 00589 00590 if (elem->dim() == max_dim) 00591 { 00592 // This is a max-dimension element that may require BCs. 00593 // For each of its sides, including internal sides, we'll 00594 // see if a lower-dimensional element provides boundary 00595 // information for it. Note that we have not yet called 00596 // find_neighbors(), so we can't use elem->neighbor(sn) in 00597 // this algorithm... 00598 for (unsigned short sn=0; sn<elem->n_sides(); sn++) 00599 { 00600 UniquePtr<Elem> side (elem->build_side(sn)); 00601 00602 // Build up a node_ids vector, which is the key 00603 std::vector<dof_id_type> node_ids(side->n_nodes()); 00604 for (unsigned n=0; n<side->n_nodes(); n++) 00605 node_ids[n] = side->node(n); 00606 00607 // Sort the vector before using it as a key 00608 std::sort(node_ids.begin(), node_ids.end()); 00609 00610 // Look for this key in the provide_bcs map 00611 provide_bcs_t::iterator iter = provide_bcs.find(node_ids); 00612 00613 if (iter != provide_bcs.end()) 00614 { 00615 Elem* lower_dim_elem = iter->second; 00616 00617 // Add boundary information based on the lower-dimensional element's subdomain id. 00618 mesh.get_boundary_info().add_side 00619 (elem, sn, lower_dim_elem->subdomain_id()); 00620 } 00621 } 00622 } 00623 } 00624 } 00625 } 00626 00627 00628 00629 void UNVIO::elements_in (std::istream& in_file) 00630 { 00631 START_LOG("elements_in()","UNVIO"); 00632 00633 if (this->verbose()) 00634 libMesh::out << " Reading elements" << std::endl; 00635 00636 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00637 00638 // node label, we use an int here so we can read in a -1 00639 int element_label; 00640 00641 unsigned 00642 n_nodes, // number of nodes on element 00643 fe_descriptor_id, // FE descriptor id 00644 phys_prop_tab_num, // physical property table number (not supported yet) 00645 mat_prop_tab_num, // material property table number (not supported yet) 00646 color; // color (not supported yet) 00647 00648 // vector that temporarily holds the node labels defining element 00649 std::vector<unsigned int> node_labels (21); 00650 00651 // vector that assigns element nodes to their correct position 00652 // for example: 00653 // 44:plane stress | QUAD4 00654 // linear quadrilateral | 00655 // position in UNV-file | position in libmesh 00656 // assign_elem_node[1] = 0 00657 // assign_elem_node[2] = 3 00658 // assign_elem_node[3] = 2 00659 // assign_elem_node[4] = 1 00660 // 00661 // UNV is 1-based, we leave the 0th element of the vectors unused in order 00662 // to prevent confusion, this way we can store elements with up to 20 nodes 00663 unsigned int assign_elem_nodes[21]; 00664 00665 // Read elements until there are none left 00666 unsigned ctr = 0; 00667 while (true) 00668 { 00669 // read element label, break out when we read -1 00670 in_file >> element_label; 00671 00672 if (element_label == -1) 00673 break; 00674 00675 in_file >> fe_descriptor_id // read FE descriptor id 00676 >> phys_prop_tab_num // (not supported yet) 00677 >> mat_prop_tab_num // (not supported yet) 00678 >> color // (not supported yet) 00679 >> n_nodes; // read number of nodes on element 00680 00681 // For "beam" type elements, the next three numbers are: 00682 // .) beam orientation node number 00683 // .) beam fore-end cross section number 00684 // .) beam aft-end cross section number 00685 // which we discard in libmesh. The "beam" type elements: 00686 // 11 Rod 00687 // 21 Linear beam 00688 // 22 Tapered beam 00689 // 23 Curved beam 00690 // 24 Parabolic beam 00691 // all have fe_descriptor_id < 25. 00692 // http://www.sdrl.uc.edu/universal-file-formats-for-modal-analysis-testing-1/file-format-storehouse/unv_2412.htm 00693 if (fe_descriptor_id < 25) 00694 { 00695 unsigned dummy; 00696 in_file >> dummy >> dummy >> dummy; 00697 } 00698 00699 // read node labels (1-based) 00700 for (unsigned int j=1; j<=n_nodes; j++) 00701 in_file >> node_labels[j]; 00702 00703 // element pointer, to be allocated 00704 Elem* elem = NULL; 00705 00706 switch (fe_descriptor_id) 00707 { 00708 case 11: // Rod 00709 { 00710 elem = new Edge2; 00711 00712 assign_elem_nodes[1]=0; 00713 assign_elem_nodes[2]=1; 00714 break; 00715 } 00716 00717 case 41: // Plane Stress Linear Triangle 00718 case 91: // Thin Shell Linear Triangle 00719 { 00720 elem = new Tri3; // create new element 00721 00722 assign_elem_nodes[1]=0; 00723 assign_elem_nodes[2]=2; 00724 assign_elem_nodes[3]=1; 00725 break; 00726 } 00727 00728 case 42: // Plane Stress Quadratic Triangle 00729 case 92: // Thin Shell Quadratic Triangle 00730 { 00731 elem = new Tri6; // create new element 00732 00733 assign_elem_nodes[1]=0; 00734 assign_elem_nodes[2]=5; 00735 assign_elem_nodes[3]=2; 00736 assign_elem_nodes[4]=4; 00737 assign_elem_nodes[5]=1; 00738 assign_elem_nodes[6]=3; 00739 break; 00740 } 00741 00742 case 43: // Plane Stress Cubic Triangle 00743 libmesh_error_msg("ERROR: UNV-element type 43: Plane Stress Cubic Triangle not supported."); 00744 00745 case 44: // Plane Stress Linear Quadrilateral 00746 case 94: // Thin Shell Linear Quadrilateral 00747 { 00748 elem = new Quad4; // create new element 00749 00750 assign_elem_nodes[1]=0; 00751 assign_elem_nodes[2]=3; 00752 assign_elem_nodes[3]=2; 00753 assign_elem_nodes[4]=1; 00754 break; 00755 } 00756 00757 case 45: // Plane Stress Quadratic Quadrilateral 00758 case 95: // Thin Shell Quadratic Quadrilateral 00759 { 00760 elem = new Quad8; // create new element 00761 00762 assign_elem_nodes[1]=0; 00763 assign_elem_nodes[2]=7; 00764 assign_elem_nodes[3]=3; 00765 assign_elem_nodes[4]=6; 00766 assign_elem_nodes[5]=2; 00767 assign_elem_nodes[6]=5; 00768 assign_elem_nodes[7]=1; 00769 assign_elem_nodes[8]=4; 00770 break; 00771 } 00772 00773 case 300: // Thin Shell Quadratic Quadrilateral (nine nodes) 00774 { 00775 elem = new Quad9; // create new element 00776 00777 assign_elem_nodes[1]=0; 00778 assign_elem_nodes[2]=7; 00779 assign_elem_nodes[3]=3; 00780 assign_elem_nodes[4]=6; 00781 assign_elem_nodes[5]=2; 00782 assign_elem_nodes[6]=5; 00783 assign_elem_nodes[7]=1; 00784 assign_elem_nodes[8]=4; 00785 assign_elem_nodes[9]=8; 00786 break; 00787 } 00788 00789 case 46: // Plane Stress Cubic Quadrilateral 00790 libmesh_error_msg("ERROR: UNV-element type 46: Plane Stress Cubic Quadrilateral not supported."); 00791 00792 case 111: // Solid Linear Tetrahedron 00793 { 00794 elem = new Tet4; // create new element 00795 00796 assign_elem_nodes[1]=0; 00797 assign_elem_nodes[2]=1; 00798 assign_elem_nodes[3]=2; 00799 assign_elem_nodes[4]=3; 00800 break; 00801 } 00802 00803 case 112: // Solid Linear Prism 00804 { 00805 elem = new Prism6; // create new element 00806 00807 assign_elem_nodes[1]=0; 00808 assign_elem_nodes[2]=1; 00809 assign_elem_nodes[3]=2; 00810 assign_elem_nodes[4]=3; 00811 assign_elem_nodes[5]=4; 00812 assign_elem_nodes[6]=5; 00813 break; 00814 } 00815 00816 case 115: // Solid Linear Brick 00817 { 00818 elem = new Hex8; // create new element 00819 00820 assign_elem_nodes[1]=0; 00821 assign_elem_nodes[2]=4; 00822 assign_elem_nodes[3]=5; 00823 assign_elem_nodes[4]=1; 00824 assign_elem_nodes[5]=3; 00825 assign_elem_nodes[6]=7; 00826 assign_elem_nodes[7]=6; 00827 assign_elem_nodes[8]=2; 00828 break; 00829 } 00830 00831 case 116: // Solid Quadratic Brick 00832 { 00833 elem = new Hex20; // create new element 00834 00835 assign_elem_nodes[1]=0; 00836 assign_elem_nodes[2]=12; 00837 assign_elem_nodes[3]=4; 00838 assign_elem_nodes[4]=16; 00839 assign_elem_nodes[5]=5; 00840 assign_elem_nodes[6]=13; 00841 assign_elem_nodes[7]=1; 00842 assign_elem_nodes[8]=8; 00843 00844 assign_elem_nodes[9]=11; 00845 assign_elem_nodes[10]=19; 00846 assign_elem_nodes[11]=17; 00847 assign_elem_nodes[12]=9; 00848 00849 assign_elem_nodes[13]=3; 00850 assign_elem_nodes[14]=15; 00851 assign_elem_nodes[15]=7; 00852 assign_elem_nodes[16]=18; 00853 assign_elem_nodes[17]=6; 00854 assign_elem_nodes[18]=14; 00855 assign_elem_nodes[19]=2; 00856 assign_elem_nodes[20]=10; 00857 break; 00858 } 00859 00860 case 117: // Solid Cubic Brick 00861 libmesh_error_msg("Error: UNV-element type 117: Solid Cubic Brick not supported."); 00862 00863 case 118: // Solid Quadratic Tetrahedron 00864 { 00865 elem = new Tet10; // create new element 00866 00867 assign_elem_nodes[1]=0; 00868 assign_elem_nodes[2]=4; 00869 assign_elem_nodes[3]=1; 00870 assign_elem_nodes[4]=5; 00871 assign_elem_nodes[5]=2; 00872 assign_elem_nodes[6]=6; 00873 assign_elem_nodes[7]=7; 00874 assign_elem_nodes[8]=8; 00875 assign_elem_nodes[9]=9; 00876 assign_elem_nodes[10]=3; 00877 break; 00878 } 00879 00880 default: // Unrecognized element type 00881 libmesh_error_msg("ERROR: UNV-element type " << fe_descriptor_id << " not supported."); 00882 } 00883 00884 // nodes are being stored in element 00885 for (dof_id_type j=1; j<=n_nodes; j++) 00886 { 00887 // Map the UNV node ID to the libmesh node ID 00888 std::map<unsigned, unsigned>::iterator it = 00889 _unv_node_id_to_libmesh_node_id.find(node_labels[j]); 00890 00891 if (it != _unv_node_id_to_libmesh_node_id.end()) 00892 elem->set_node(assign_elem_nodes[j]) = mesh.node_ptr(it->second); 00893 else 00894 libmesh_error_msg("ERROR: UNV node " << node_labels[j] << " not found!"); 00895 } 00896 00897 elems_of_dimension[elem->dim()] = true; 00898 00899 // Set the element's ID 00900 elem->set_id(ctr); 00901 00902 // Maintain a map from the libmesh (0-based) numbering to the 00903 // UNV numbering. This probably duplicates what the MeshData 00904 // object does, but hopefully the MeshData object will be going 00905 // away at some point... 00906 //_libmesh_elem_id_to_unv_elem_id[i] = element_label; 00907 _unv_elem_id_to_libmesh_elem_id[element_label] = ctr; 00908 00909 // Add the element to the Mesh 00910 Elem* added_elem = mesh.add_elem(elem); 00911 00912 // Tell the MeshData object the foreign elem id 00913 if (_mesh_data) 00914 _mesh_data->add_foreign_elem_id (added_elem, element_label); 00915 00916 // Increment the counter for the next iteration 00917 ctr++; 00918 } // end while(true) 00919 00920 STOP_LOG("elements_in()","UNVIO"); 00921 } 00922 00923 00924 00925 00926 00927 00928 void UNVIO::nodes_out (std::ostream& out_file) 00929 { 00930 if (_mesh_data) 00931 libmesh_assert (_mesh_data->active() || 00932 _mesh_data->compatibility_mode()); 00933 00934 if (this->verbose()) 00935 libMesh::out << " Writing " << MeshOutput<MeshBase>::mesh().n_nodes() << " nodes" << std::endl; 00936 00937 // Write beginning of dataset 00938 out_file << " -1\n" 00939 << " " 00940 << _nodes_dataset_label 00941 << '\n'; 00942 00943 unsigned int 00944 exp_coord_sys_dummy = 0, // export coordinate sys. (not supported yet) 00945 disp_coord_sys_dummy = 0, // displacement coordinate sys. (not supp. yet) 00946 color_dummy = 0; // color(not supported yet) 00947 00948 // A reference to the parent class's mesh 00949 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00950 00951 // Use scientific notation with captial E and 16 digits for printing out the coordinates 00952 out_file << std::scientific << std::setprecision(16) << std::uppercase; 00953 00954 MeshBase::const_node_iterator nd = mesh.nodes_begin(); 00955 const MeshBase::const_node_iterator end = mesh.nodes_end(); 00956 00957 for (; nd != end; ++nd) 00958 { 00959 const Node* current_node = *nd; 00960 00961 dof_id_type node_id = current_node->id(); 00962 00963 // If possible, use the MeshData object to get the right node ID. 00964 if (_mesh_data) 00965 node_id = _mesh_data->node_to_foreign_id(current_node); 00966 00967 out_file << std::setw(10) << node_id 00968 << std::setw(10) << exp_coord_sys_dummy 00969 << std::setw(10) << disp_coord_sys_dummy 00970 << std::setw(10) << color_dummy 00971 << '\n'; 00972 00973 // The coordinates - always write out three coords regardless of LIBMESH_DIM 00974 Real x = (*current_node)(0); 00975 Real y = mesh.spatial_dimension() > 1 ? (*current_node)(1) : 0.0; 00976 Real z = mesh.spatial_dimension() > 2 ? (*current_node)(2) : 0.0; 00977 00978 out_file << std::setw(25) << x 00979 << std::setw(25) << y 00980 << std::setw(25) << z 00981 << '\n'; 00982 } 00983 00984 // Write end of dataset 00985 out_file << " -1\n"; 00986 } 00987 00988 00989 00990 00991 00992 00993 void UNVIO::elements_out(std::ostream& out_file) 00994 { 00995 if (_mesh_data) 00996 libmesh_assert (_mesh_data->active() || 00997 _mesh_data->compatibility_mode()); 00998 00999 if (this->verbose()) 01000 libMesh::out << " Writing elements" << std::endl; 01001 01002 // Write beginning of dataset 01003 out_file << " -1\n" 01004 << " " 01005 << _elements_dataset_label 01006 << "\n"; 01007 01008 unsigned 01009 fe_descriptor_id = 0, // FE descriptor id 01010 phys_prop_tab_dummy = 2, // physical property (not supported yet) 01011 mat_prop_tab_dummy = 1, // material property (not supported yet) 01012 color_dummy = 7; // color (not supported yet) 01013 01014 // vector that assigns element nodes to their correct position 01015 // currently only elements with up to 20 nodes 01016 // 01017 // Example: 01018 // QUAD4 | 44:plane stress 01019 // | linear quad 01020 // position in libMesh | UNV numbering 01021 // (note: 0-based) | (note: 1-based) 01022 // 01023 // assign_elem_node[0] = 0 01024 // assign_elem_node[1] = 3 01025 // assign_elem_node[2] = 2 01026 // assign_elem_node[3] = 1 01027 unsigned int assign_elem_nodes[20]; 01028 01029 unsigned int n_elem_written=0; 01030 01031 // A reference to the parent class's mesh 01032 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 01033 01034 MeshBase::const_element_iterator it = mesh.elements_begin(); 01035 const MeshBase::const_element_iterator end = mesh.elements_end(); 01036 01037 for (; it != end; ++it) 01038 { 01039 const Elem* elem = *it; 01040 01041 elem->n_nodes(); 01042 01043 switch (elem->type()) 01044 { 01045 01046 case TRI3: 01047 { 01048 fe_descriptor_id = 41; // Plane Stress Linear Triangle 01049 assign_elem_nodes[0] = 0; 01050 assign_elem_nodes[1] = 2; 01051 assign_elem_nodes[2] = 1; 01052 break; 01053 } 01054 01055 case TRI6: 01056 { 01057 fe_descriptor_id = 42; // Plane Stress Quadratic Triangle 01058 assign_elem_nodes[0] = 0; 01059 assign_elem_nodes[1] = 5; 01060 assign_elem_nodes[2] = 2; 01061 assign_elem_nodes[3] = 4; 01062 assign_elem_nodes[4] = 1; 01063 assign_elem_nodes[5] = 3; 01064 break; 01065 } 01066 01067 case QUAD4: 01068 { 01069 fe_descriptor_id = 44; // Plane Stress Linear Quadrilateral 01070 assign_elem_nodes[0] = 0; 01071 assign_elem_nodes[1] = 3; 01072 assign_elem_nodes[2] = 2; 01073 assign_elem_nodes[3] = 1; 01074 break; 01075 } 01076 01077 case QUAD8: 01078 { 01079 fe_descriptor_id = 45; // Plane Stress Quadratic Quadrilateral 01080 assign_elem_nodes[0] = 0; 01081 assign_elem_nodes[1] = 7; 01082 assign_elem_nodes[2] = 3; 01083 assign_elem_nodes[3] = 6; 01084 assign_elem_nodes[4] = 2; 01085 assign_elem_nodes[5] = 5; 01086 assign_elem_nodes[6] = 1; 01087 assign_elem_nodes[7] = 4; 01088 break; 01089 } 01090 01091 case QUAD9: 01092 { 01093 fe_descriptor_id = 300; // Plane Stress Quadratic Quadrilateral 01094 assign_elem_nodes[0] = 0; 01095 assign_elem_nodes[1] = 7; 01096 assign_elem_nodes[2] = 3; 01097 assign_elem_nodes[3] = 6; 01098 assign_elem_nodes[4] = 2; 01099 assign_elem_nodes[5] = 5; 01100 assign_elem_nodes[6] = 1; 01101 assign_elem_nodes[7] = 4; 01102 assign_elem_nodes[8] = 8; 01103 break; 01104 } 01105 01106 case TET4: 01107 { 01108 fe_descriptor_id = 111; // Solid Linear Tetrahedron 01109 assign_elem_nodes[0] = 0; 01110 assign_elem_nodes[1] = 1; 01111 assign_elem_nodes[2] = 2; 01112 assign_elem_nodes[3] = 3; 01113 break; 01114 } 01115 01116 case PRISM6: 01117 { 01118 fe_descriptor_id = 112; // Solid Linear Prism 01119 assign_elem_nodes[0] = 0; 01120 assign_elem_nodes[1] = 1; 01121 assign_elem_nodes[2] = 2; 01122 assign_elem_nodes[3] = 3; 01123 assign_elem_nodes[4] = 4; 01124 assign_elem_nodes[5] = 5; 01125 break; 01126 } 01127 01128 case HEX8: 01129 { 01130 fe_descriptor_id = 115; // Solid Linear Brick 01131 assign_elem_nodes[0] = 0; 01132 assign_elem_nodes[1] = 4; 01133 assign_elem_nodes[2] = 5; 01134 assign_elem_nodes[3] = 1; 01135 assign_elem_nodes[4] = 3; 01136 assign_elem_nodes[5] = 7; 01137 assign_elem_nodes[6] = 6; 01138 assign_elem_nodes[7] = 2; 01139 break; 01140 } 01141 01142 case HEX20: 01143 { 01144 fe_descriptor_id = 116; // Solid Quadratic Brick 01145 assign_elem_nodes[ 0] = 0; 01146 assign_elem_nodes[ 1] = 12; 01147 assign_elem_nodes[ 2] = 4; 01148 assign_elem_nodes[ 3] = 16; 01149 assign_elem_nodes[ 4] = 5; 01150 assign_elem_nodes[ 5] = 13; 01151 assign_elem_nodes[ 6] = 1; 01152 assign_elem_nodes[ 7] = 8; 01153 01154 assign_elem_nodes[ 8] = 11; 01155 assign_elem_nodes[ 9] = 19; 01156 assign_elem_nodes[10] = 17; 01157 assign_elem_nodes[11] = 9; 01158 01159 assign_elem_nodes[12] = 3; 01160 assign_elem_nodes[13] = 15; 01161 assign_elem_nodes[14] = 7; 01162 assign_elem_nodes[15] = 18; 01163 assign_elem_nodes[16] = 6; 01164 assign_elem_nodes[17] = 14; 01165 assign_elem_nodes[18] = 2; 01166 assign_elem_nodes[19] = 10; 01167 01168 01169 break; 01170 } 01171 01172 case TET10: 01173 { 01174 fe_descriptor_id = 118; // Solid Quadratic Tetrahedron 01175 assign_elem_nodes[0] = 0; 01176 assign_elem_nodes[1] = 4; 01177 assign_elem_nodes[2] = 1; 01178 assign_elem_nodes[3] = 5; 01179 assign_elem_nodes[4] = 2; 01180 assign_elem_nodes[5] = 6; 01181 assign_elem_nodes[6] = 7; 01182 assign_elem_nodes[7] = 8; 01183 assign_elem_nodes[8] = 9; 01184 assign_elem_nodes[9] = 3; 01185 break; 01186 } 01187 01188 default: 01189 libmesh_error_msg("ERROR: Element type = " << elem->type() << " not supported in " << "UNVIO!"); 01190 } 01191 01192 dof_id_type elem_id = elem->id(); 01193 01194 // If possible, use the MeshData object to get the right node ID. 01195 if (_mesh_data) 01196 _mesh_data->elem_to_foreign_id(elem); 01197 01198 out_file << std::setw(10) << elem_id // element ID 01199 << std::setw(10) << fe_descriptor_id // type of element 01200 << std::setw(10) << phys_prop_tab_dummy // not supported 01201 << std::setw(10) << mat_prop_tab_dummy // not supported 01202 << std::setw(10) << color_dummy // not supported 01203 << std::setw(10) << elem->n_nodes() // No. of nodes per element 01204 << '\n'; 01205 01206 for (unsigned int j=0; j<elem->n_nodes(); j++) 01207 { 01208 // assign_elem_nodes[j]-th node: i.e., j loops over the 01209 // libMesh numbering, and assign_elem_nodes[j] over the 01210 // UNV numbering. 01211 const Node* node_in_unv_order = elem->get_node(assign_elem_nodes[j]); 01212 01213 // new record after 8 id entries 01214 if (j==8 || j==16) 01215 out_file << '\n'; 01216 01217 // Write foreign label for this node 01218 dof_id_type node_id = node_in_unv_order->id(); 01219 01220 // If possible, use the MeshData object to determine this 01221 if (_mesh_data) 01222 _mesh_data->node_to_foreign_id(node_in_unv_order); 01223 01224 out_file << std::setw(10) << node_id; 01225 } 01226 01227 out_file << '\n'; 01228 01229 n_elem_written++; 01230 } 01231 01232 if (this->verbose()) 01233 libMesh::out << " Finished writing " << n_elem_written << " elements" << std::endl; 01234 01235 // Write end of dataset 01236 out_file << " -1\n"; 01237 } 01238 01239 } // namespace libMesh