$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 // C++ includes 00019 #include <fstream> 00020 #include <set> 00021 #include <cstring> // std::memcpy 00022 #include <numeric> 00023 00024 // Local includes 00025 #include "libmesh/libmesh_config.h" 00026 #include "libmesh/libmesh_logging.h" 00027 #include "libmesh/boundary_info.h" 00028 #include "libmesh/elem.h" 00029 #include "libmesh/gmsh_io.h" 00030 #include "libmesh/mesh_base.h" 00031 00032 00033 // anonymous namespace to hold local data 00034 namespace 00035 { 00036 using namespace libMesh; 00037 00041 struct elementDefinition 00042 { 00043 std::string label; 00044 std::vector<unsigned int> nodes; 00045 ElemType type; 00046 unsigned int exptype; 00047 unsigned int dim; 00048 unsigned int nnodes; 00049 }; 00050 00051 00052 // maps from a libMesh element type to the proper 00053 // Gmsh elementDefinition. Placing the data structure 00054 // here in this anonymous namespace gives us the 00055 // benefits of a global variable without the nasty 00056 // side-effects 00057 std::map<ElemType, elementDefinition> eletypes_exp; 00058 std::map<unsigned int, elementDefinition> eletypes_imp; 00059 00060 00061 00062 // ------------------------------------------------------------ 00063 // helper function to initialize the eletypes map 00064 void init_eletypes () 00065 { 00066 if (eletypes_exp.empty() && eletypes_imp.empty()) 00067 { 00068 // This should happen only once. The first time this method 00069 // is called the eletypes data struture will be empty, and 00070 // we will fill it. Any subsequent calls will find an initialized 00071 // eletypes map and will do nothing. 00072 00073 // set up the element definitions 00074 elementDefinition eledef; 00075 00076 // use "swap trick" from Scott Meyer's "Effective STL" to initialize 00077 // eledef.nodes vector 00078 00079 // POINT (only Gmsh) 00080 { 00081 eledef.type = NODEELEM; 00082 eledef.exptype = 15; 00083 eledef.dim = 0; 00084 eledef.nnodes = 1; 00085 eledef.nodes.clear(); 00086 00087 // import only 00088 eletypes_imp[15] = eledef; 00089 } 00090 00091 // EDGE2 00092 { 00093 eledef.type = EDGE2; 00094 eledef.dim = 1; 00095 eledef.nnodes = 2; 00096 eledef.exptype = 1; 00097 eledef.nodes.clear(); 00098 00099 eletypes_exp[EDGE2] = eledef; 00100 eletypes_imp[1] = eledef; 00101 } 00102 00103 // EDGE3 00104 { 00105 eledef.type = EDGE3; 00106 eledef.dim = 1; 00107 eledef.nnodes = 3; 00108 eledef.exptype = 8; 00109 eledef.nodes.clear(); 00110 00111 eletypes_exp[EDGE3] = eledef; 00112 eletypes_imp[8] = eledef; 00113 } 00114 00115 // TRI3 00116 { 00117 eledef.type = TRI3; 00118 eledef.dim = 2; 00119 eledef.nnodes = 3; 00120 eledef.exptype = 2; 00121 eledef.nodes.clear(); 00122 00123 eletypes_exp[TRI3] = eledef; 00124 eletypes_imp[2] = eledef; 00125 } 00126 00127 // TRI6 00128 { 00129 eledef.type = TRI6; 00130 eledef.dim = 2; 00131 eledef.nnodes = 6; 00132 eledef.exptype = 9; 00133 eledef.nodes.clear(); 00134 00135 eletypes_exp[TRI6] = eledef; 00136 eletypes_imp[9] = eledef; 00137 } 00138 00139 // QUAD4 00140 { 00141 eledef.type = QUAD4; 00142 eledef.dim = 2; 00143 eledef.nnodes = 4; 00144 eledef.exptype = 3; 00145 eledef.nodes.clear(); 00146 00147 eletypes_exp[QUAD4] = eledef; 00148 eletypes_imp[3] = eledef; 00149 } 00150 00151 // QUAD8 00152 // TODO: what should be done with this on writing? 00153 { 00154 eledef.type = QUAD8; 00155 eledef.dim = 2; 00156 eledef.nnodes = 8; 00157 eledef.exptype = 100; 00158 const unsigned int nodes[] = {1,2,3,4,5,6,7,8}; 00159 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); 00160 00161 eletypes_exp[QUAD8] = eledef; 00162 eletypes_imp[10] = eledef; 00163 } 00164 00165 // QUAD9 00166 { 00167 eledef.type = QUAD9; 00168 eledef.dim = 2; 00169 eledef.nnodes = 9; 00170 eledef.exptype = 10; 00171 eledef.nodes.clear(); 00172 00173 eletypes_exp[QUAD9] = eledef; 00174 eletypes_imp[10] = eledef; 00175 } 00176 00177 // HEX8 00178 { 00179 eledef.type = HEX8; 00180 eledef.dim = 3; 00181 eledef.nnodes = 8; 00182 eledef.exptype = 5; 00183 eledef.nodes.clear(); 00184 00185 eletypes_exp[HEX8] = eledef; 00186 eletypes_imp[5] = eledef; 00187 } 00188 00189 // HEX20 00190 // TODO: what should be done with this on writing? 00191 { 00192 eledef.type = HEX20; 00193 eledef.dim = 3; 00194 eledef.nnodes = 20; 00195 eledef.exptype = 101; 00196 const unsigned int nodes[] = {1,2,3,4,5,6,7,8,9,10,11,16,17,18,19,12,13,14,15,16}; 00197 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); 00198 00199 eletypes_exp[HEX20] = eledef; 00200 eletypes_imp[12] = eledef; 00201 } 00202 00203 // HEX27 00204 { 00205 eledef.type = HEX27; 00206 eledef.dim = 3; 00207 eledef.nnodes = 27; 00208 eledef.exptype = 12; 00209 const unsigned int nodes[] = {0,1,2,3,4,5,6,7,8,11,12,9,13,10,14, 00210 15,16,19,17,18,20,21,24,22,23,25,26}; 00211 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); 00212 00213 eletypes_exp[HEX27] = eledef; 00214 eletypes_imp[12] = eledef; 00215 } 00216 00217 // TET4 00218 { 00219 eledef.type = TET4; 00220 eledef.dim = 3; 00221 eledef.nnodes = 4; 00222 eledef.exptype = 4; 00223 eledef.nodes.clear(); 00224 00225 eletypes_exp[TET4] = eledef; 00226 eletypes_imp[4] = eledef; 00227 } 00228 00229 // TET10 00230 { 00231 eledef.type = TET10; 00232 eledef.dim = 3; 00233 eledef.nnodes = 10; 00234 eledef.exptype = 11; 00235 const unsigned int nodes[] = {0,1,2,3,4,5,6,7,9,8}; 00236 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); 00237 eletypes_exp[TET10] = eledef; 00238 eletypes_imp[11] = eledef; 00239 } 00240 00241 // PRISM6 00242 { 00243 eledef.type = PRISM6; 00244 eledef.dim = 3; 00245 eledef.nnodes = 6; 00246 eledef.exptype = 6; 00247 eledef.nodes.clear(); 00248 00249 eletypes_exp[PRISM6] = eledef; 00250 eletypes_imp[6] = eledef; 00251 } 00252 00253 // PRISM15 00254 // TODO: what should be done with this on writing? 00255 { 00256 eledef.type = PRISM15; 00257 eledef.dim = 3; 00258 eledef.nnodes = 15; 00259 eledef.exptype = 103; 00260 eledef.nodes.clear(); 00261 00262 eletypes_exp[PRISM15] = eledef; 00263 eletypes_imp[13] = eledef; 00264 } 00265 00266 // PRISM18 00267 { 00268 eledef.type = PRISM18; 00269 eledef.dim = 3; 00270 eledef.nnodes = 18; 00271 eledef.exptype = 13; 00272 const unsigned int nodes[] = {0,1,2,3,4,5,6,8,9,7,10,11, 00273 12,14,13,15,17,16}; 00274 std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); 00275 00276 eletypes_exp[PRISM18] = eledef; 00277 eletypes_imp[13] = eledef; 00278 } 00279 00280 // PYRAMID5 00281 { 00282 eledef.type = PYRAMID5; 00283 eledef.dim = 3; 00284 eledef.nnodes = 5; 00285 eledef.exptype = 7; 00286 eledef.nodes.clear(); 00287 00288 eletypes_exp[PYRAMID5] = eledef; 00289 eletypes_imp[7] = eledef; 00290 } 00291 } 00292 } 00293 00294 } // end anonymous namespace 00295 00296 00297 namespace libMesh 00298 { 00299 00300 // ------------------------------------------------------------ 00301 // GmshIO members 00302 00303 GmshIO::GmshIO (const MeshBase& mesh) : 00304 MeshOutput<MeshBase>(mesh), 00305 _binary(false) 00306 { 00307 } 00308 00309 00310 00311 GmshIO::GmshIO (MeshBase& mesh) : 00312 MeshInput<MeshBase> (mesh), 00313 MeshOutput<MeshBase> (mesh), 00314 _binary (false) 00315 { 00316 } 00317 00318 00319 00320 bool & GmshIO::binary () 00321 { 00322 return _binary; 00323 } 00324 00325 00326 00327 void GmshIO::read (const std::string& name) 00328 { 00329 std::ifstream in (name.c_str()); 00330 this->read_mesh (in); 00331 } 00332 00333 00334 00335 void GmshIO::read_mesh(std::istream& in) 00336 { 00337 // This is a serial-only process for now; 00338 // the Mesh should be read on processor 0 and 00339 // broadcast later 00340 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); 00341 00342 libmesh_assert(in.good()); 00343 00344 // initialize the map with element types 00345 init_eletypes(); 00346 00347 // clear any data in the mesh 00348 MeshBase& mesh = MeshInput<MeshBase>::mesh(); 00349 mesh.clear(); 00350 00351 // some variables 00352 int format=0, size=0; 00353 Real version = 1.0; 00354 00355 // map to hold the node numbers for translation 00356 // note the the nodes can be non-consecutive 00357 std::map<unsigned int, unsigned int> nodetrans; 00358 00359 // For reading the file line by line 00360 std::string s; 00361 00362 while (true) 00363 { 00364 // Try to read something. This may set EOF! 00365 std::getline(in, s); 00366 00367 if (in) 00368 { 00369 // Process s... 00370 00371 if (s.find("$MeshFormat") == static_cast<std::string::size_type>(0)) 00372 { 00373 in >> version >> format >> size; 00374 if ((version != 2.0) && (version != 2.1) && (version != 2.2)) 00375 { 00376 // Some notes on gmsh mesh versions: 00377 // 00378 // Mesh version 2.0 goes back as far as I know. It's not explicitly 00379 // mentioned here: http://www.geuz.org/gmsh/doc/VERSIONS.txt 00380 // 00381 // As of gmsh-2.4.0: 00382 // bumped mesh version format to 2.1 (small change in the $PhysicalNames 00383 // section, where the group dimension is now required); 00384 // [Since we don't even parse the PhysicalNames section at the time 00385 // of this writing, I don't think this change affects us.] 00386 // 00387 // Mesh version 2.2 tested by Manav Bhatia; no other 00388 // libMesh code changes were required for support 00389 libmesh_error_msg("Error: Unknown msh file version " << version); 00390 } 00391 00392 if (format) 00393 libmesh_error_msg("Error: Unknown data format for mesh in Gmsh reader."); 00394 } 00395 00396 // read the node block 00397 else if (s.find("$NOD") == static_cast<std::string::size_type>(0) || 00398 s.find("$NOE") == static_cast<std::string::size_type>(0) || 00399 s.find("$Nodes") == static_cast<std::string::size_type>(0)) 00400 { 00401 unsigned int num_nodes = 0; 00402 in >> num_nodes; 00403 mesh.reserve_nodes (num_nodes); 00404 00405 // read in the nodal coordinates and form points. 00406 Real x, y, z; 00407 unsigned int id; 00408 00409 // add the nodal coordinates to the mesh 00410 for (unsigned int i=0; i<num_nodes; ++i) 00411 { 00412 in >> id >> x >> y >> z; 00413 mesh.add_point (Point(x, y, z), i); 00414 nodetrans[id] = i; 00415 } 00416 00417 // read the $ENDNOD delimiter 00418 std::getline(in, s); 00419 } 00420 00421 00422 // Read the element block 00423 else if (s.find("$ELM") == static_cast<std::string::size_type>(0) || 00424 s.find("$Elements") == static_cast<std::string::size_type>(0)) 00425 { 00426 // For reading the number of elements and the node ids from the stream 00427 unsigned int 00428 num_elem = 0, 00429 node_id = 0; 00430 00431 // read how many elements are there, and reserve space in the mesh 00432 in >> num_elem; 00433 mesh.reserve_elem (num_elem); 00434 00435 // As of version 2.2, the format for each element line is: 00436 // elm-number elm-type number-of-tags < tag > ... node-number-list 00437 // From the Gmsh docs: 00438 // * the first tag is the number of the 00439 // physical entity to which the element belongs 00440 // * the second is the number of the elementary geometrical 00441 // entity to which the element belongs 00442 // * the third is the number of mesh partitions to which the element 00443 // belongs 00444 // * The rest of the tags are the partition ids (negative 00445 // partition ids indicate ghost cells). A zero tag is 00446 // equivalent to no tag. Gmsh and most codes using the 00447 // MSH 2 format require at least the first two tags 00448 // (physical and elementary tags). 00449 00450 // Keep track of all the element dimensions seen 00451 std::vector<unsigned> elem_dimensions_seen(3); 00452 00453 // read the elements 00454 for (unsigned int iel=0; iel<num_elem; ++iel) 00455 { 00456 unsigned int 00457 id, type, 00458 physical=1, elementary=1, 00459 nnodes=0, ntags; 00460 00461 // Note: tag has to be an int because it could be negative, 00462 // see above. 00463 int tag; 00464 00465 if (version <= 1.0) 00466 in >> id >> type >> physical >> elementary >> nnodes; 00467 00468 else 00469 { 00470 in >> id >> type >> ntags; 00471 00472 if (ntags > 2) 00473 libmesh_do_once(libMesh::err << "Warning, ntags=" << ntags << ", but we currently only support reading 2 flags." << std::endl;); 00474 00475 for (unsigned int j = 0; j < ntags; j++) 00476 { 00477 in >> tag; 00478 if (j == 0) 00479 physical = tag; 00480 else if (j == 1) 00481 elementary = tag; 00482 } 00483 } 00484 00485 // Consult the import element table to determine which element to build 00486 std::map<unsigned int, elementDefinition>::iterator eletypes_it = eletypes_imp.find(type); 00487 00488 // Make sure we actually found something 00489 if (eletypes_it == eletypes_imp.end()) 00490 libmesh_error_msg("Element type " << type << " not found!"); 00491 00492 // Get a reference to the elementDefinition 00493 const elementDefinition& eletype = eletypes_it->second; 00494 00495 // If we read nnodes, make sure it matches the number in eletype.nnodes 00496 if (nnodes != 0 && nnodes != eletype.nnodes) 00497 libmesh_error_msg("nnodes = " << nnodes << " and eletype.nnodes = " << eletype.nnodes << " do not match."); 00498 00499 // Assign the value from the eletype object. 00500 nnodes = eletype.nnodes; 00501 00502 // Don't add 0-dimensional "point" elements to the 00503 // Mesh. They should *always* be treated as boundary 00504 // "nodeset" data. 00505 if (eletype.dim > 0) 00506 { 00507 // Record this element dimension as being "seen". 00508 // We will treat all elements with dimension < 00509 // max(dimension) as specifying boundary conditions, 00510 // but we won't know what max_elem_dimension_seen is 00511 // until we read the entire file. 00512 elem_dimensions_seen[eletype.dim-1] = 1; 00513 00514 // Add the element to the mesh 00515 { 00516 Elem* elem = Elem::build(eletype.type).release(); 00517 elem->set_id(iel); 00518 elem = mesh.add_elem(elem); 00519 00520 // Make sure that the libmesh element we added has nnodes nodes. 00521 if (elem->n_nodes() != nnodes) 00522 libmesh_error_msg("Number of nodes for element " \ 00523 << id \ 00524 << " of type " << eletypes_imp[type].type \ 00525 << " (Gmsh type " << type \ 00526 << ") does not match Libmesh definition. " \ 00527 << "I expected " << elem->n_nodes() \ 00528 << " nodes, but got " << nnodes); 00529 00530 // Add node pointers to the elements. 00531 // If there is a node translation table, use it. 00532 if (eletype.nodes.size() > 0) 00533 for (unsigned int i=0; i<nnodes; i++) 00534 { 00535 in >> node_id; 00536 elem->set_node(eletype.nodes[i]) = mesh.node_ptr(nodetrans[node_id]); 00537 } 00538 else 00539 { 00540 for (unsigned int i=0; i<nnodes; i++) 00541 { 00542 in >> node_id; 00543 elem->set_node(i) = mesh.node_ptr(nodetrans[node_id]); 00544 } 00545 } 00546 00547 // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will 00548 // eventually go into the Mesh's BoundaryInfo object. 00549 elem->subdomain_id() = static_cast<subdomain_id_type>(physical); 00550 } 00551 } 00552 00553 // Handle 0-dimensional elements (points) by adding 00554 // them to the BoundaryInfo object with 00555 // boundary_id == physical. 00556 else 00557 { 00558 // This seems like it should always be the same 00559 // number as the 'id' we already read in on this 00560 // line. At least it was in the example gmsh 00561 // file I had... 00562 in >> node_id; 00563 mesh.get_boundary_info().add_node 00564 (nodetrans[node_id], 00565 static_cast<boundary_id_type>(physical)); 00566 } 00567 } // element loop 00568 00569 // read the $ENDELM delimiter 00570 std::getline(in, s); 00571 00572 // Record the max and min element dimension seen while reading the file. 00573 unsigned char 00574 max_elem_dimension_seen=1, 00575 min_elem_dimension_seen=3; 00576 00577 for (unsigned char i=0; i<elem_dimensions_seen.size(); ++i) 00578 if (elem_dimensions_seen[i]) 00579 { 00580 // Debugging 00581 // libMesh::out << "Seen elements of dimension " << i+1 << std::endl; 00582 max_elem_dimension_seen = 00583 std::max(max_elem_dimension_seen, cast_int<unsigned char>(i+1)); 00584 min_elem_dimension_seen = 00585 std::min(min_elem_dimension_seen, cast_int<unsigned char>(i+1)); 00586 } 00587 00588 // Debugging: 00589 // libMesh::out << "max_elem_dimension_seen=" << max_elem_dimension_seen << std::endl; 00590 // libMesh::out << "min_elem_dimension_seen=" << min_elem_dimension_seen << std::endl; 00591 00592 // If the difference between the max and min element dimension seen is larger than 00593 // 1, (e.g. the file has 1D and 3D elements only) we don't handle this case. 00594 if (max_elem_dimension_seen - min_elem_dimension_seen > 1) 00595 libmesh_error_msg("Cannot handle meshes with dimension mismatch greater than 1."); 00596 00597 // How many different element dimensions did we see while reading from file? 00598 unsigned n_dims_seen = std::accumulate(elem_dimensions_seen.begin(), 00599 elem_dimensions_seen.end(), 00600 static_cast<unsigned>(0), 00601 std::plus<unsigned>()); 00602 00603 // Have not yet tested a case where 1, 2, and 3D elements are all in the same Mesh, 00604 // though it should theoretically be possible to handle. 00605 if (n_dims_seen == 3) 00606 libmesh_error_msg("Reading meshes with 1, 2, and 3D elements not currently supported."); 00607 00608 // Set mesh_dimension based on the largest element dimension seen. 00609 mesh.set_mesh_dimension(max_elem_dimension_seen); 00610 00611 if (n_dims_seen > 1) 00612 { 00613 // map from (node ids) -> elem of lower dimensional elements that can provide boundary conditions 00614 typedef std::map<std::vector<dof_id_type>, Elem*> provide_container_t; 00615 provide_container_t provide_bcs; 00616 00617 // 1st loop over active elements - get info about lower-dimensional elements. 00618 { 00619 MeshBase::element_iterator it = mesh.active_elements_begin(); 00620 const MeshBase::element_iterator end = mesh.active_elements_end(); 00621 for ( ; it != end; ++it) 00622 { 00623 Elem* elem = *it; 00624 00625 if (elem->dim() < max_elem_dimension_seen) 00626 { 00627 // Debugging status 00628 // libMesh::out << "Processing Elem " << elem->id() << " as a boundary element." << std::endl; 00629 00630 // To be pushed into the provide_bcs data structure 00631 std::vector<dof_id_type> node_ids(elem->n_nodes()); 00632 00633 // To be consistent with the previous GmshIO behavior, add all the lower-dimensional elements' nodes to 00634 // the Mesh's BoundaryInfo object with the lower-dimensional element's subdomain ID. 00635 for (unsigned n=0; n<elem->n_nodes(); n++) 00636 { 00637 mesh.get_boundary_info().add_node 00638 (elem->node(n), elem->subdomain_id()); 00639 00640 // And save for our local data structure 00641 node_ids[n] = elem->node(n); 00642 } 00643 00644 // Sort before putting into the map 00645 std::sort(node_ids.begin(), node_ids.end()); 00646 provide_bcs[node_ids] = elem; 00647 } 00648 } 00649 } // end 1st loop over active elements 00650 00651 // Debugging: What did we put in the provide_bcs data structure? 00652 // { 00653 // provide_container_t::iterator provide_it = provide_bcs.begin(); 00654 // provide_container_t::iterator provide_end = provide_bcs.end(); 00655 // for ( ; provide_it != provide_end; ++provide_it) 00656 // { 00657 // std::vector<dof_id_type> node_list = (*provide_it).first; 00658 // Elem* elem = (*provide_it).second; 00659 // 00660 // libMesh::out << "Elem " << elem->id() << " provides BCs for the face: "; 00661 // for (unsigned i=0; i<node_list.size(); ++i) 00662 // libMesh::out << node_list[i] << " "; 00663 // libMesh::out << std::endl; 00664 // } 00665 // } 00666 00667 // 2nd loop over active elements - use lower dimensional element data to set BCs for higher dimensional elements 00668 { 00669 MeshBase::element_iterator it = mesh.active_elements_begin(); 00670 const MeshBase::element_iterator end = mesh.active_elements_end(); 00671 for ( ; it != end; ++it) 00672 { 00673 Elem* elem = *it; 00674 00675 if (elem->dim() == max_elem_dimension_seen) 00676 { 00677 // This is a max-dimension element that 00678 // may require BCs. For each of its 00679 // sides, including internal sides, we'll 00680 // see if a lower-dimensional element 00681 // provides boundary information for it. 00682 // Note that we have not yet called 00683 // find_neighbors(), so we can't use 00684 // elem->neighbor(sn) in this algorithm... 00685 00686 for (unsigned short sn=0; 00687 sn<elem->n_sides(); sn++) 00688 { 00689 UniquePtr<Elem> side (elem->build_side(sn)); 00690 00691 // Build up a node_ids vector, which is the key 00692 std::vector<dof_id_type> node_ids(side->n_nodes()); 00693 for (unsigned n=0; n<side->n_nodes(); n++) 00694 node_ids[n] = side->node(n); 00695 00696 // Sort the vector before using it as a key 00697 std::sort(node_ids.begin(), node_ids.end()); 00698 00699 // Look for this key in the provide_bcs map 00700 provide_container_t::iterator iter = provide_bcs.find(node_ids); 00701 00702 if (iter != provide_bcs.end()) 00703 { 00704 Elem* lower_dim_elem = (*iter).second; 00705 00706 // libMesh::out << "Elem " 00707 // << lower_dim_elem->id() 00708 // << " provides BCs for side " 00709 // << sn 00710 // << " of Elem " 00711 // << elem->id() 00712 // << std::endl; 00713 00714 // Add boundary information based on the lower-dimensional element's subdomain id. 00715 mesh.get_boundary_info().add_side(elem, 00716 sn, 00717 cast_int<boundary_id_type>(lower_dim_elem->subdomain_id())); 00718 } 00719 } 00720 } 00721 } 00722 } // end 2nd loop over active elements 00723 00724 // 3rd loop over active elements - Remove the lower-dimensional elements 00725 { 00726 MeshBase::element_iterator it = mesh.active_elements_begin(); 00727 const MeshBase::element_iterator end = mesh.active_elements_end(); 00728 for ( ; it != end; ++it) 00729 { 00730 Elem* elem = *it; 00731 00732 if (elem->dim() < max_elem_dimension_seen) 00733 mesh.delete_elem(elem); 00734 } 00735 } // end 3rd loop over active elements 00736 } // end if (n_dims_seen > 1) 00737 } // if $ELM 00738 00739 continue; 00740 } // if (in) 00741 00742 00743 // If !in, check to see if EOF was set. If so, break out 00744 // of while loop. 00745 if (in.eof()) 00746 break; 00747 00748 // If !in and !in.eof(), stream is in a bad state! 00749 libmesh_error_msg("Stream is bad! Perhaps the file does not exist?"); 00750 00751 } // while true 00752 } 00753 00754 00755 00756 void GmshIO::write (const std::string& name) 00757 { 00758 if (MeshOutput<MeshBase>::mesh().processor_id() == 0) 00759 { 00760 // Open the output file stream 00761 std::ofstream out_stream (name.c_str()); 00762 00763 // Make sure it opened correctly 00764 if (!out_stream.good()) 00765 libmesh_file_error(name.c_str()); 00766 00767 this->write_mesh (out_stream); 00768 } 00769 } 00770 00771 00772 00773 void GmshIO::write_nodal_data (const std::string& fname, 00774 const std::vector<Number>& soln, 00775 const std::vector<std::string>& names) 00776 { 00777 START_LOG("write_nodal_data()", "GmshIO"); 00778 00779 //this->_binary = true; 00780 if (MeshOutput<MeshBase>::mesh().processor_id() == 0) 00781 this->write_post (fname, &soln, &names); 00782 00783 STOP_LOG("write_nodal_data()", "GmshIO"); 00784 } 00785 00786 00787 00788 void GmshIO::write_mesh (std::ostream& out_stream) 00789 { 00790 // Be sure that the stream is valid. 00791 libmesh_assert (out_stream.good()); 00792 00793 // initialize the map with element types 00794 init_eletypes(); 00795 00796 // Get a const reference to the mesh 00797 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00798 00799 // Note: we are using version 2.0 of the gmsh output format. 00800 00801 // Write the file header. 00802 out_stream << "$MeshFormat\n"; 00803 out_stream << "2.0 0 " << sizeof(Real) << '\n'; 00804 out_stream << "$EndMeshFormat\n"; 00805 00806 // write the nodes in (n x y z) format 00807 out_stream << "$Nodes\n"; 00808 out_stream << mesh.n_nodes() << '\n'; 00809 00810 for (unsigned int v=0; v<mesh.n_nodes(); v++) 00811 out_stream << mesh.node(v).id()+1 << " " 00812 << mesh.node(v)(0) << " " 00813 << mesh.node(v)(1) << " " 00814 << mesh.node(v)(2) << '\n'; 00815 out_stream << "$EndNodes\n"; 00816 00817 { 00818 // write the connectivity 00819 out_stream << "$Elements\n"; 00820 out_stream << mesh.n_active_elem() << '\n'; 00821 00822 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00823 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00824 00825 // loop over the elements 00826 for ( ; it != end; ++it) 00827 { 00828 const Elem* elem = *it; 00829 00830 // Make sure we have a valid entry for 00831 // the current element type. 00832 libmesh_assert (eletypes_exp.count(elem->type())); 00833 00834 // consult the export element table 00835 const elementDefinition& eletype = eletypes_exp[elem->type()]; 00836 00837 // The element mapper better not require any more nodes 00838 // than are present in the current element! 00839 libmesh_assert_less_equal (eletype.nodes.size(), elem->n_nodes()); 00840 00841 // elements ids are 1 based in Gmsh 00842 out_stream << elem->id()+1 << " "; 00843 00844 // element type 00845 out_stream << eletype.exptype; 00846 00847 // write the number of tags and 00848 // tag1 (physical entity), tag2 (geometric entity), and tag3 (partition entity) 00849 out_stream << " 3 " 00850 << static_cast<unsigned int>(elem->subdomain_id()) 00851 << " 1 " 00852 << (elem->processor_id()+1) << " "; 00853 00854 // if there is a node translation table, use it 00855 if (eletype.nodes.size() > 0) 00856 for (unsigned int i=0; i < elem->n_nodes(); i++) 00857 out_stream << elem->node(eletype.nodes[i])+1 << " "; // gmsh is 1-based 00858 // otherwise keep the same node order 00859 else 00860 for (unsigned int i=0; i < elem->n_nodes(); i++) 00861 out_stream << elem->node(i)+1 << " "; // gmsh is 1-based 00862 out_stream << "\n"; 00863 } // element loop 00864 out_stream << "$EndElements\n"; 00865 } 00866 } 00867 00868 00869 00870 void GmshIO::write_post (const std::string& fname, 00871 const std::vector<Number>* v, 00872 const std::vector<std::string>* solution_names) 00873 { 00874 00875 // Should only do this on processor 0! 00876 libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0); 00877 00878 // Create an output stream 00879 std::ofstream out_stream(fname.c_str()); 00880 00881 // Make sure it opened correctly 00882 if (!out_stream.good()) 00883 libmesh_file_error(fname.c_str()); 00884 00885 // initialize the map with element types 00886 init_eletypes(); 00887 00888 // create a character buffer 00889 char buf[80]; 00890 00891 // Get a constant reference to the mesh. 00892 const MeshBase& mesh = MeshOutput<MeshBase>::mesh(); 00893 00894 // write the data 00895 if ((solution_names != NULL) && (v != NULL)) 00896 { 00897 const unsigned int n_vars = 00898 cast_int<unsigned int>(solution_names->size()); 00899 00900 if (!(v->size() == mesh.n_nodes()*n_vars)) 00901 libMesh::err << "ERROR: v->size()=" << v->size() 00902 << ", mesh.n_nodes()=" << mesh.n_nodes() 00903 << ", n_vars=" << n_vars 00904 << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars 00905 << "\n"; 00906 00907 libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars); 00908 00909 // write the header 00910 out_stream << "$PostFormat\n"; 00911 if (this->binary()) 00912 out_stream << "1.2 1 " << sizeof(double) << "\n"; 00913 else 00914 out_stream << "1.2 0 " << sizeof(double) << "\n"; 00915 out_stream << "$EndPostFormat\n"; 00916 00917 // Loop over the elements to see how much of each type there are 00918 unsigned int n_points=0, n_lines=0, n_triangles=0, n_quadrangles=0, 00919 n_tetrahedra=0, n_hexahedra=0, n_prisms=0, n_pyramids=0; 00920 unsigned int n_scalar=0, n_vector=0, n_tensor=0; 00921 unsigned int nb_text2d=0, nb_text2d_chars=0, nb_text3d=0, nb_text3d_chars=0; 00922 00923 { 00924 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 00925 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 00926 00927 00928 for ( ; it != end; ++it) 00929 { 00930 const ElemType elemtype = (*it)->type(); 00931 00932 switch (elemtype) 00933 { 00934 case EDGE2: 00935 case EDGE3: 00936 case EDGE4: 00937 { 00938 n_lines += 1; 00939 break; 00940 } 00941 case TRI3: 00942 case TRI6: 00943 { 00944 n_triangles += 1; 00945 break; 00946 } 00947 case QUAD4: 00948 case QUAD8: 00949 case QUAD9: 00950 { 00951 n_quadrangles += 1; 00952 break; 00953 } 00954 case TET4: 00955 case TET10: 00956 { 00957 n_tetrahedra += 1; 00958 break; 00959 } 00960 case HEX8: 00961 case HEX20: 00962 case HEX27: 00963 { 00964 n_hexahedra += 1; 00965 break; 00966 } 00967 case PRISM6: 00968 case PRISM15: 00969 case PRISM18: 00970 { 00971 n_prisms += 1; 00972 break; 00973 } 00974 case PYRAMID5: 00975 { 00976 n_pyramids += 1; 00977 break; 00978 } 00979 default: 00980 libmesh_error_msg("ERROR: Nonexistent element type " << (*it)->type()); 00981 } 00982 } 00983 } 00984 00985 // create a view for each variable 00986 for (unsigned int ivar=0; ivar < n_vars; ivar++) 00987 { 00988 std::string varname = (*solution_names)[ivar]; 00989 00990 // at the moment, we just write out scalar quantities 00991 // later this should be made configurable through 00992 // options to the writer class 00993 n_scalar = 1; 00994 00995 // write the variable as a view, and the number of time steps 00996 out_stream << "$View\n" << varname << " " << 1 << "\n"; 00997 00998 // write how many of each geometry type are written 00999 out_stream << n_points * n_scalar << " " 01000 << n_points * n_vector << " " 01001 << n_points * n_tensor << " " 01002 << n_lines * n_scalar << " " 01003 << n_lines * n_vector << " " 01004 << n_lines * n_tensor << " " 01005 << n_triangles * n_scalar << " " 01006 << n_triangles * n_vector << " " 01007 << n_triangles * n_tensor << " " 01008 << n_quadrangles * n_scalar << " " 01009 << n_quadrangles * n_vector << " " 01010 << n_quadrangles * n_tensor << " " 01011 << n_tetrahedra * n_scalar << " " 01012 << n_tetrahedra * n_vector << " " 01013 << n_tetrahedra * n_tensor << " " 01014 << n_hexahedra * n_scalar << " " 01015 << n_hexahedra * n_vector << " " 01016 << n_hexahedra * n_tensor << " " 01017 << n_prisms * n_scalar << " " 01018 << n_prisms * n_vector << " " 01019 << n_prisms * n_tensor << " " 01020 << n_pyramids * n_scalar << " " 01021 << n_pyramids * n_vector << " " 01022 << n_pyramids * n_tensor << " " 01023 << nb_text2d << " " 01024 << nb_text2d_chars << " " 01025 << nb_text3d << " " 01026 << nb_text3d_chars << "\n"; 01027 01028 // if binary, write a marker to identify the endianness of the file 01029 if (this->binary()) 01030 { 01031 const int one = 1; 01032 std::memcpy(buf, &one, sizeof(int)); 01033 out_stream.write(buf, sizeof(int)); 01034 } 01035 01036 // the time steps (there is just 1 at the moment) 01037 if (this->binary()) 01038 { 01039 double one = 1; 01040 std::memcpy(buf, &one, sizeof(double)); 01041 out_stream.write(buf, sizeof(double)); 01042 } 01043 else 01044 out_stream << "1\n"; 01045 01046 // Loop over the elements and write out the data 01047 MeshBase::const_element_iterator it = mesh.active_elements_begin(); 01048 const MeshBase::const_element_iterator end = mesh.active_elements_end(); 01049 01050 for ( ; it != end; ++it) 01051 { 01052 const Elem* elem = *it; 01053 01054 // this is quite crappy, but I did not invent that file format! 01055 for (unsigned int d=0; d<3; d++) // loop over the dimensions 01056 { 01057 for (unsigned int n=0; n < elem->n_vertices(); n++) // loop over vertices 01058 { 01059 const Point& vertex = elem->point(n); 01060 if (this->binary()) 01061 { 01062 double tmp = vertex(d); 01063 std::memcpy(buf, &tmp, sizeof(double)); 01064 out_stream.write(reinterpret_cast<char *>(buf), sizeof(double)); 01065 } 01066 else 01067 out_stream << vertex(d) << " "; 01068 } 01069 if (!this->binary()) 01070 out_stream << "\n"; 01071 } 01072 01073 // now finally write out the data 01074 for (unsigned int i=0; i < elem->n_vertices(); i++) // loop over vertices 01075 if (this->binary()) 01076 { 01077 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 01078 libMesh::out << "WARNING: Gmsh::write_post does not fully support " 01079 << "complex numbers. Will only write the real part of " 01080 << "variable " << varname << std::endl; 01081 #endif 01082 double tmp = libmesh_real((*v)[elem->node(i)*n_vars + ivar]); 01083 std::memcpy(buf, &tmp, sizeof(double)); 01084 out_stream.write(reinterpret_cast<char *>(buf), sizeof(double)); 01085 } 01086 else 01087 { 01088 #ifdef LIBMESH_USE_COMPLEX_NUMBERS 01089 libMesh::out << "WARNING: Gmsh::write_post does not fully support " 01090 << "complex numbers. Will only write the real part of " 01091 << "variable " << varname << std::endl; 01092 #endif 01093 out_stream << libmesh_real((*v)[elem->node(i)*n_vars + ivar]) << "\n"; 01094 } 01095 } 01096 if (this->binary()) 01097 out_stream << "\n"; 01098 out_stream << "$EndView\n"; 01099 01100 } // end variable loop (writing the views) 01101 } 01102 } 01103 01104 } // namespace libMesh