$extrastylesheet
gmsh_io.C
Go to the documentation of this file.
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