libMesh::GmshIO Class Reference

#include <gmsh_io.h>

Inheritance diagram for libMesh::GmshIO:

Classes

struct  ElementDefinition
 
struct  ElementMaps
 

Public Member Functions

 GmshIO (MeshBase &mesh)
 
 GmshIO (const MeshBase &mesh)
 
virtual void read (const std::string &name) override
 
virtual void write (const std::string &name) override
 
virtual void write_nodal_data (const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
 
bool & binary ()
 
bool & write_lower_dimensional_elements ()
 
virtual void write_equation_systems (const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
 
virtual void write_discontinuous_equation_systems (const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
 
virtual void write_nodal_data (const std::string &, const NumericVector< Number > &, const std::vector< std::string > &)
 
virtual void write_nodal_data_discontinuous (const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
 
unsigned int & ascii_precision ()
 

Protected Member Functions

MeshBasemesh ()
 
void set_n_partitions (unsigned int n_parts)
 
void skip_comment_lines (std::istream &in, const char comment_start)
 
const MeshBasemesh () const
 

Protected Attributes

std::vector< bool > elems_of_dimension
 
const bool _is_parallel_format
 
const bool _serial_only_needed_on_proc_0
 

Private Member Functions

void read_mesh (std::istream &in)
 
void write_mesh (std::ostream &out)
 
void write_post (const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
 

Static Private Member Functions

static ElementMaps build_element_maps ()
 

Private Attributes

bool _binary
 
bool _write_lower_dimensional_elements
 

Static Private Attributes

static ElementMaps _element_maps = GmshIO::build_element_maps()
 

Detailed Description

This class implements writing meshes in the Gmsh format. For a full description of the Gmsh format and to obtain the GMSH software see the Gmsh home page

Author
John W. Peterson
Date
2004, 2014
Author
Martin Luthi
Date
2005

Definition at line 50 of file gmsh_io.h.

Constructor & Destructor Documentation

◆ GmshIO() [1/2]

libMesh::GmshIO::GmshIO ( MeshBase mesh)
explicit

Constructor. Takes a non-const Mesh reference which it will fill up with elements via the read() command.

Definition at line 120 of file gmsh_io.C.

120  :
121  MeshInput<MeshBase> (mesh),
122  MeshOutput<MeshBase> (mesh),
123  _binary (false),
125 {
126 }
bool _write_lower_dimensional_elements
Definition: gmsh_io.h:148

◆ GmshIO() [2/2]

libMesh::GmshIO::GmshIO ( const MeshBase mesh)
explicit

Constructor. Takes a reference to a constant mesh object. This constructor will only allow us to write the mesh.

Definition at line 111 of file gmsh_io.C.

111  :
112  MeshOutput<MeshBase>(mesh),
113  _binary(false),
115 {
116 }
bool _write_lower_dimensional_elements
Definition: gmsh_io.h:148

Member Function Documentation

◆ ascii_precision()

unsigned int & libMesh::MeshOutput< MeshBase >::ascii_precision ( )
inlineinherited

Return/set the precision to use when writing ASCII files.

By default we use numeric_limits<Real>::digits10 + 2, which should be enough to write out to ASCII and get the exact same Real back when reading in.

Definition at line 244 of file mesh_output.h.

Referenced by libMesh::TecplotIO::write_ascii(), libMesh::GMVIO::write_ascii_new_impl(), and libMesh::GMVIO::write_ascii_old_impl().

245 {
246  return _ascii_precision;
247 }

◆ binary()

bool & libMesh::GmshIO::binary ( )

Flag indicating whether or not to write a binary file. While binary files may end up being smaller than equivalent ASCII files, they will almost certainly take longer to write. The reason for this is that the ostream::write() function which is used to write "binary" data to streams, only takes a pointer to char as its first argument. This means if you want to write anything other than a buffer of chars, you first have to use a strange memcpy hack to get the data into the desired format. See the templated to_binary_stream() function below.

Definition at line 130 of file gmsh_io.C.

References _binary.

Referenced by write_post().

131 {
132  return _binary;
133 }

◆ build_element_maps()

GmshIO::ElementMaps libMesh::GmshIO::build_element_maps ( )
staticprivate

A static function used to construct the _element_maps struct, statically.

Definition at line 42 of file gmsh_io.C.

References libMesh::GmshIO::ElementMaps::add_def(), libMesh::EDGE2, libMesh::EDGE3, libMesh::HEX20, libMesh::HEX27, libMesh::HEX8, libMesh::GmshIO::ElementMaps::in, libMesh::GmshIO::ElementDefinition::nnodes, libMesh::NODEELEM, libMesh::GmshIO::ElementDefinition::nodes, libMesh::PRISM15, libMesh::PRISM18, libMesh::PRISM6, libMesh::PYRAMID5, libMesh::QUAD4, libMesh::QUAD8, libMesh::QUAD9, swap(), libMesh::TET10, libMesh::TET4, libMesh::TRI3, and libMesh::TRI6.

43 {
44  // Object to be filled up
45  ElementMaps em;
46 
47  // POINT (import only)
48  em.in.insert(std::make_pair(15, ElementDefinition(NODEELEM, 15, 0, 1)));
49 
50  // Add elements with trivial node mappings
51  em.add_def(ElementDefinition(EDGE2, 1, 1, 2));
52  em.add_def(ElementDefinition(EDGE3, 8, 1, 3));
53  em.add_def(ElementDefinition(TRI3, 2, 2, 3));
54  em.add_def(ElementDefinition(TRI6, 9, 2, 6));
55  em.add_def(ElementDefinition(QUAD4, 3, 2, 4));
56  em.add_def(ElementDefinition(QUAD8, 16, 2, 8));
57  em.add_def(ElementDefinition(QUAD9, 10, 2, 9));
58  em.add_def(ElementDefinition(HEX8, 5, 3, 8));
59  em.add_def(ElementDefinition(TET4, 4, 3, 4));
60  em.add_def(ElementDefinition(PRISM6, 6, 3, 6));
61  em.add_def(ElementDefinition(PYRAMID5, 7, 3, 5));
62 
63  // Add elements with non-trivial node mappings
64 
65  // HEX20
66  {
67  ElementDefinition eledef(HEX20, 17, 3, 20);
68  const unsigned int nodes[] = {0,1,2,3,4,5,6,7,8,11,12,9,13,10,14,15,16,19,17,18};
69  std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
70  em.add_def(eledef);
71  }
72 
73  // HEX27
74  {
75  ElementDefinition eledef(HEX27, 12, 3, 27);
76  const unsigned int nodes[] = {0,1,2,3,4,5,6,7,8,11,12,9,13,10,14,
77  15,16,19,17,18,20,21,24,22,23,25,26};
78  std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
79  em.add_def(eledef);
80  }
81 
82  // TET10
83  {
84  ElementDefinition eledef(TET10, 11, 3, 10);
85  const unsigned int nodes[] = {0,1,2,3,4,5,6,7,9,8};
86  std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
87  em.add_def(eledef);
88  }
89 
90  // PRISM15
91  {
92  ElementDefinition eledef(PRISM15, 18, 3, 15);
93  const unsigned int nodes[] = {0,1,2,3,4,5,6,8,9,7,10,11,12,14,13};
94  std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
95  em.add_def(eledef);
96  }
97 
98  // PRISM18
99  {
100  ElementDefinition eledef(PRISM18, 13, 3, 18);
101  const unsigned int nodes[] = {0,1,2,3,4,5,6,8,9,7,10,11,12,14,13,15,17,16};
102  std::vector<unsigned int>(nodes, nodes+eledef.nnodes).swap(eledef.nodes); // swap trick
103  em.add_def(eledef);
104  }
105 
106  return em;
107 }
void swap(Iterator &lhs, Iterator &rhs)

◆ mesh() [1/2]

MeshBase & libMesh::MeshInput< MeshBase >::mesh ( )
inlineprotectedinherited
Returns
The object as a writable reference.

Definition at line 169 of file mesh_input.h.

Referenced by libMesh::GMVIO::_read_one_cell(), libMesh::VTKIO::cells_to_vtk(), libMesh::TetGenIO::element_in(), libMesh::UNVIO::elements_in(), libMesh::UNVIO::elements_out(), libMesh::UNVIO::groups_in(), libMesh::TetGenIO::node_in(), libMesh::UNVIO::nodes_in(), libMesh::UNVIO::nodes_out(), libMesh::VTKIO::nodes_to_vtk(), libMesh::Nemesis_IO::prepare_to_write_nodal_data(), libMesh::Nemesis_IO::read(), libMesh::ExodusII_IO::read(), libMesh::GMVIO::read(), libMesh::XdrIO::read(), libMesh::CheckpointIO::read(), libMesh::VTKIO::read(), libMesh::CheckpointIO::read_bcs(), libMesh::CheckpointIO::read_connectivity(), libMesh::CheckpointIO::read_header(), libMesh::XdrIO::read_header(), libMesh::UCDIO::read_implementation(), libMesh::UNVIO::read_implementation(), read_mesh(), libMesh::CheckpointIO::read_nodes(), libMesh::CheckpointIO::read_nodesets(), libMesh::CheckpointIO::read_remote_elem(), libMesh::XdrIO::read_serialized_bcs_helper(), libMesh::XdrIO::read_serialized_connectivity(), libMesh::XdrIO::read_serialized_nodes(), libMesh::XdrIO::read_serialized_nodesets(), libMesh::XdrIO::read_serialized_subdomain_names(), libMesh::OFFIO::read_stream(), libMesh::MatlabIO::read_stream(), libMesh::CheckpointIO::read_subdomain_names(), libMesh::TetGenIO::write(), libMesh::Nemesis_IO::write(), libMesh::ExodusII_IO::write(), libMesh::XdrIO::write(), libMesh::CheckpointIO::write(), libMesh::GMVIO::write_ascii_new_impl(), libMesh::GMVIO::write_ascii_old_impl(), libMesh::GMVIO::write_binary(), libMesh::GMVIO::write_discontinuous_gmv(), libMesh::Nemesis_IO::write_element_data(), libMesh::ExodusII_IO::write_element_data(), libMesh::UCDIO::write_header(), libMesh::UCDIO::write_implementation(), libMesh::UCDIO::write_interior_elems(), write_mesh(), libMesh::VTKIO::write_nodal_data(), libMesh::UCDIO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data(), libMesh::ExodusII_IO::write_nodal_data_common(), libMesh::ExodusII_IO::write_nodal_data_discontinuous(), libMesh::UCDIO::write_nodes(), libMesh::CheckpointIO::write_nodesets(), libMesh::XdrIO::write_parallel(), write_post(), libMesh::XdrIO::write_serialized_bcs_helper(), libMesh::XdrIO::write_serialized_connectivity(), libMesh::XdrIO::write_serialized_nodes(), libMesh::XdrIO::write_serialized_nodesets(), libMesh::XdrIO::write_serialized_subdomain_names(), libMesh::UCDIO::write_soln(), and libMesh::CheckpointIO::write_subdomain_names().

170 {
171  if (_obj == nullptr)
172  libmesh_error_msg("ERROR: _obj should not be nullptr!");
173  return *_obj;
174 }

◆ mesh() [2/2]

◆ read()

void libMesh::GmshIO::read ( const std::string &  name)
overridevirtual

Reads in a mesh in the Gmsh *.msh format from the ASCII file given by name.

The user is responsible for calling Mesh::prepare_for_use() after reading the mesh and before using it.

Implements libMesh::MeshInput< MeshBase >.

Definition at line 144 of file gmsh_io.C.

References libMesh::Quality::name(), and read_mesh().

Referenced by libMesh::NameBasedIO::read().

145 {
146  std::ifstream in (name.c_str());
147  this->read_mesh (in);
148 }
std::string name(const ElemQuality q)
Definition: elem_quality.C:42
void read_mesh(std::istream &in)
Definition: gmsh_io.C:152

◆ read_mesh()

void libMesh::GmshIO::read_mesh ( std::istream &  in)
private

Implementation of the read() function. This function is called by the public interface function and implements reading the file.

Definition at line 152 of file gmsh_io.C.

References _element_maps, libMesh::MeshBase::active_element_ptr_range(), libMesh::MeshBase::add_elem(), libMesh::BoundaryInfo::add_node(), libMesh::MeshBase::add_point(), libMesh::BoundaryInfo::add_side(), libMesh::as_range(), libMesh::Elem::build(), libMesh::MeshBase::clear(), libMesh::MeshBase::delete_elem(), libMesh::GmshIO::ElementDefinition::dim, libMesh::err, libMesh::MeshBase::get_boundary_info(), libMesh::GmshIO::ElementMaps::in, std::max(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshInput< MT >::mesh(), std::min(), libMesh::Elem::n_nodes(), libMesh::GmshIO::ElementDefinition::nnodes, libMesh::MeshBase::node_ptr(), libMesh::GmshIO::ElementDefinition::nodes, libMesh::Real, libMesh::MeshBase::reserve_elem(), libMesh::MeshBase::reserve_nodes(), libMesh::DofObject::set_id(), libMesh::MeshBase::set_mesh_dimension(), libMesh::Elem::set_node(), side, libMesh::BoundaryInfo::sideset_name(), libMesh::Elem::subdomain_id(), libMesh::MeshBase::subdomain_name(), and libMesh::GmshIO::ElementDefinition::type.

Referenced by read().

153 {
154  // This is a serial-only process for now;
155  // the Mesh should be read on processor 0 and
156  // broadcast later
157  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
158 
159  libmesh_assert(in.good());
160 
161  // clear any data in the mesh
162  MeshBase & mesh = MeshInput<MeshBase>::mesh();
163  mesh.clear();
164 
165  // some variables
166  int format=0, size=0;
167  Real version = 1.0;
168 
169  // Keep track of lower-dimensional blocks which are not BCs, but
170  // actually blocks of lower-dimensional elements.
171  std::set<subdomain_id_type> lower_dimensional_blocks;
172 
173  // Mapping from physical id -> (physical dim, physical name) pairs.
174  // These can refer to either "sidesets" or "subdomains"; we need to
175  // wait until the Mesh has been read to know which is which. Note
176  // that we are using 'int' as the key here rather than
177  // subdomain_id_type or boundary_id_type, since at this point, it
178  // could be either.
179  typedef std::pair<unsigned, std::string> GmshPhysical;
180  std::map<int, GmshPhysical> gmsh_physicals;
181 
182  // map to hold the node numbers for translation
183  // note the the nodes can be non-consecutive
184  std::map<unsigned int, unsigned int> nodetrans;
185 
186  // For reading the file line by line
187  std::string s;
188 
189  while (true)
190  {
191  // Try to read something. This may set EOF!
192  std::getline(in, s);
193 
194  if (in)
195  {
196  // Process s...
197 
198  if (s.find("$MeshFormat") == static_cast<std::string::size_type>(0))
199  {
200  in >> version >> format >> size;
201  if ((version != 2.0) && (version != 2.1) && (version != 2.2))
202  {
203  // Some notes on gmsh mesh versions:
204  //
205  // Mesh version 2.0 goes back as far as I know. It's not explicitly
206  // mentioned here: http://www.geuz.org/gmsh/doc/VERSIONS.txt
207  //
208  // As of gmsh-2.4.0:
209  // bumped mesh version format to 2.1 (small change in the $PhysicalNames
210  // section, where the group dimension is now required);
211  // [Since we don't even parse the PhysicalNames section at the time
212  // of this writing, I don't think this change affects us.]
213  //
214  // Mesh version 2.2 tested by Manav Bhatia; no other
215  // libMesh code changes were required for support
216  libmesh_error_msg("Error: Unknown msh file version " << version);
217  }
218 
219  if (format)
220  libmesh_error_msg("Error: Unknown data format for mesh in Gmsh reader.");
221  }
222 
223  // Read and process the "PhysicalNames" section.
224  else if (s.find("$PhysicalNames") == static_cast<std::string::size_type>(0))
225  {
226  // The lines in the PhysicalNames section should look like the following:
227  // 2 1 "frac" lower_dimensional_block
228  // 2 3 "top"
229  // 2 4 "bottom"
230  // 3 2 "volume"
231 
232  // Read in the number of physical groups to expect in the file.
233  unsigned int num_physical_groups = 0;
234  in >> num_physical_groups;
235 
236  // Read rest of line including newline character.
237  std::getline(in, s);
238 
239  for (unsigned int i=0; i<num_physical_groups; ++i)
240  {
241  // Read an entire line of the PhysicalNames section.
242  std::getline(in, s);
243 
244  // Use an istringstream to extract the physical
245  // dimension, physical id, and physical name from
246  // this line.
247  std::istringstream s_stream(s);
248  unsigned phys_dim;
249  int phys_id;
250  std::string phys_name;
251  s_stream >> phys_dim >> phys_id >> phys_name;
252 
253  // Not sure if this is true for all Gmsh files, but
254  // my test file has quotes around the phys_name
255  // string. So let's erase any quotes now...
256  phys_name.erase(std::remove(phys_name.begin(), phys_name.end(), '"'), phys_name.end());
257 
258  // Record this ID for later assignment of subdomain/sideset names.
259  gmsh_physicals[phys_id] = std::make_pair(phys_dim, phys_name);
260 
261  // If 's' also contains the libmesh-specific string
262  // "lower_dimensional_block", add this block ID to
263  // the list of blocks which are not boundary
264  // conditions.
265  if (s.find("lower_dimensional_block") != std::string::npos)
266  {
267  lower_dimensional_blocks.insert(cast_int<subdomain_id_type>(phys_id));
268 
269  // The user has explicitly told us that this
270  // block is a subdomain, so set that association
271  // in the Mesh.
272  mesh.subdomain_name(cast_int<subdomain_id_type>(phys_id)) = phys_name;
273  }
274  }
275  }
276 
277  // read the node block
278  else if (s.find("$NOD") == static_cast<std::string::size_type>(0) ||
279  s.find("$NOE") == static_cast<std::string::size_type>(0) ||
280  s.find("$Nodes") == static_cast<std::string::size_type>(0))
281  {
282  unsigned int num_nodes = 0;
283  in >> num_nodes;
284  mesh.reserve_nodes (num_nodes);
285 
286  // read in the nodal coordinates and form points.
287  Real x, y, z;
288  unsigned int id;
289 
290  // add the nodal coordinates to the mesh
291  for (unsigned int i=0; i<num_nodes; ++i)
292  {
293  in >> id >> x >> y >> z;
294  mesh.add_point (Point(x, y, z), i);
295  nodetrans[id] = i;
296  }
297 
298  // read the $ENDNOD delimiter
299  std::getline(in, s);
300  }
301 
302 
303  // Read the element block
304  else if (s.find("$ELM") == static_cast<std::string::size_type>(0) ||
305  s.find("$Elements") == static_cast<std::string::size_type>(0))
306  {
307  // For reading the number of elements and the node ids from the stream
308  unsigned int
309  num_elem = 0,
310  node_id = 0;
311 
312  // read how many elements are there, and reserve space in the mesh
313  in >> num_elem;
314  mesh.reserve_elem (num_elem);
315 
316  // As of version 2.2, the format for each element line is:
317  // elm-number elm-type number-of-tags < tag > ... node-number-list
318  // From the Gmsh docs:
319  // * the first tag is the number of the
320  // physical entity to which the element belongs
321  // * the second is the number of the elementary geometrical
322  // entity to which the element belongs
323  // * the third is the number of mesh partitions to which the element
324  // belongs
325  // * The rest of the tags are the partition ids (negative
326  // partition ids indicate ghost cells). A zero tag is
327  // equivalent to no tag. Gmsh and most codes using the
328  // MSH 2 format require at least the first two tags
329  // (physical and elementary tags).
330 
331  // Keep track of all the element dimensions seen
332  std::vector<unsigned> elem_dimensions_seen(3);
333 
334  // read the elements
335  for (unsigned int iel=0; iel<num_elem; ++iel)
336  {
337  unsigned int
338  id, type,
339  physical=1, elementary=1,
340  nnodes=0, ntags;
341 
342  // Note: tag has to be an int because it could be negative,
343  // see above.
344  int tag;
345 
346  if (version <= 1.0)
347  in >> id >> type >> physical >> elementary >> nnodes;
348 
349  else
350  {
351  in >> id >> type >> ntags;
352 
353  if (ntags > 2)
354  libmesh_do_once(libMesh::err << "Warning, ntags=" << ntags << ", but we currently only support reading 2 flags." << std::endl;);
355 
356  for (unsigned int j = 0; j < ntags; j++)
357  {
358  in >> tag;
359  if (j == 0)
360  physical = tag;
361  else if (j == 1)
362  elementary = tag;
363  }
364  }
365 
366  // Consult the import element table to determine which element to build
367  auto eletypes_it = _element_maps.in.find(type);
368 
369  // Make sure we actually found something
370  if (eletypes_it == _element_maps.in.end())
371  libmesh_error_msg("Element type " << type << " not found!");
372 
373  // Get a reference to the ElementDefinition
374  const GmshIO::ElementDefinition & eletype = eletypes_it->second;
375 
376  // If we read nnodes, make sure it matches the number in eletype.nnodes
377  if (nnodes != 0 && nnodes != eletype.nnodes)
378  libmesh_error_msg("nnodes = " << nnodes << " and eletype.nnodes = " << eletype.nnodes << " do not match.");
379 
380  // Assign the value from the eletype object.
381  nnodes = eletype.nnodes;
382 
383  // Don't add 0-dimensional "point" elements to the
384  // Mesh. They should *always* be treated as boundary
385  // "nodeset" data.
386  if (eletype.dim > 0)
387  {
388  // Record this element dimension as being "seen".
389  // We will treat all elements with dimension <
390  // max(dimension) as specifying boundary conditions,
391  // but we won't know what max_elem_dimension_seen is
392  // until we read the entire file.
393  elem_dimensions_seen[eletype.dim-1] = 1;
394 
395  // Add the element to the mesh
396  {
397  Elem * elem = Elem::build(eletype.type).release();
398  elem->set_id(iel);
399  elem = mesh.add_elem(elem);
400 
401  // Make sure that the libmesh element we added has nnodes nodes.
402  if (elem->n_nodes() != nnodes)
403  libmesh_error_msg("Number of nodes for element " \
404  << id \
405  << " of type " << eletype.type \
406  << " (Gmsh type " << type \
407  << ") does not match Libmesh definition. " \
408  << "I expected " << elem->n_nodes() \
409  << " nodes, but got " << nnodes);
410 
411  // Add node pointers to the elements.
412  // If there is a node translation table, use it.
413  if (eletype.nodes.size() > 0)
414  for (unsigned int i=0; i<nnodes; i++)
415  {
416  in >> node_id;
417  elem->set_node(eletype.nodes[i]) = mesh.node_ptr(nodetrans[node_id]);
418  }
419  else
420  {
421  for (unsigned int i=0; i<nnodes; i++)
422  {
423  in >> node_id;
424  elem->set_node(i) = mesh.node_ptr(nodetrans[node_id]);
425  }
426  }
427 
428  // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will
429  // eventually go into the Mesh's BoundaryInfo object.
430  elem->subdomain_id() = static_cast<subdomain_id_type>(physical);
431  }
432  }
433 
434  // Handle 0-dimensional elements (points) by adding
435  // them to the BoundaryInfo object with
436  // boundary_id == physical.
437  else
438  {
439  // This seems like it should always be the same
440  // number as the 'id' we already read in on this
441  // line. At least it was in the example gmsh
442  // file I had...
443  in >> node_id;
445  (nodetrans[node_id],
446  static_cast<boundary_id_type>(physical));
447  }
448  } // element loop
449 
450  // read the $ENDELM delimiter
451  std::getline(in, s);
452 
453  // Record the max and min element dimension seen while reading the file.
454  unsigned char
455  max_elem_dimension_seen=1,
456  min_elem_dimension_seen=3;
457 
458  for (std::size_t i=0; i<elem_dimensions_seen.size(); ++i)
459  if (elem_dimensions_seen[i])
460  {
461  // Debugging
462  // libMesh::out << "Seen elements of dimension " << i+1 << std::endl;
463  max_elem_dimension_seen =
464  std::max(max_elem_dimension_seen, cast_int<unsigned char>(i+1));
465  min_elem_dimension_seen =
466  std::min(min_elem_dimension_seen, cast_int<unsigned char>(i+1));
467  }
468 
469  // Debugging:
470  // libMesh::out << "max_elem_dimension_seen=" << max_elem_dimension_seen << std::endl;
471  // libMesh::out << "min_elem_dimension_seen=" << min_elem_dimension_seen << std::endl;
472 
473  // If the difference between the max and min element dimension seen is larger than
474  // 1, (e.g. the file has 1D and 3D elements only) we don't handle this case.
475  if (max_elem_dimension_seen - min_elem_dimension_seen > 1)
476  libmesh_error_msg("Cannot handle meshes with dimension mismatch greater than 1.");
477 
478  // How many different element dimensions did we see while reading from file?
479  unsigned n_dims_seen = std::accumulate(elem_dimensions_seen.begin(),
480  elem_dimensions_seen.end(),
481  static_cast<unsigned>(0),
482  std::plus<unsigned>());
483 
484  // Have not yet tested a case where 1, 2, and 3D elements are all in the same Mesh,
485  // though it should theoretically be possible to handle.
486  if (n_dims_seen == 3)
487  libmesh_error_msg("Reading meshes with 1, 2, and 3D elements not currently supported.");
488 
489  // Set mesh_dimension based on the largest element dimension seen.
490  mesh.set_mesh_dimension(max_elem_dimension_seen);
491 
492  // Now that we know the maximum element dimension seen,
493  // we know whether the physical names are subdomain
494  // names or sideset names.
495  for (const auto & pr : gmsh_physicals)
496  {
497  // Extract data
498  int phys_id = pr.first;
499  unsigned phys_dim = pr.second.first;
500  const std::string & phys_name = pr.second.second;
501 
502  // If the physical's dimension matches the largest
503  // dimension we've seen, it's a subdomain name.
504  if (phys_dim == max_elem_dimension_seen)
505  mesh.subdomain_name(cast_int<subdomain_id_type>(phys_id)) = phys_name;
506 
507  // Otherwise, if it's not a lower-dimensional
508  // block, it's a sideset name.
509  else if (phys_dim < max_elem_dimension_seen &&
510  !lower_dimensional_blocks.count(cast_int<boundary_id_type>(phys_id)))
511  mesh.get_boundary_info().sideset_name(cast_int<boundary_id_type>(phys_id)) = phys_name;
512  }
513 
514  if (n_dims_seen > 1)
515  {
516  // Store lower-dimensional elements in a map sorted
517  // by Elem::key(). We use a multimap for two reasons:
518  // 1.) The hash function is not guaranteed to be
519  // unique, so different lower-dimensional elements
520  // could theoretically hash to the same value,
521  // although this is pretty unlikely.
522  // 2.) The Gmsh file may contain multiple
523  // lower-dimensional elements for a single side in
524  // order to implement multiple boundary ids for a
525  // single side. These lower-dimensional elements
526  // will all hash to the same value, and we need to
527  // be able to store all of them.
528  typedef std::unordered_multimap<dof_id_type, Elem *> provide_container_t;
529  provide_container_t provide_bcs;
530 
531  // 1st loop over active elements - get info about lower-dimensional elements.
532  for (auto & elem : mesh.active_element_ptr_range())
533  if (elem->dim() < max_elem_dimension_seen &&
534  !lower_dimensional_blocks.count(elem->subdomain_id()))
535  {
536  // To be consistent with the previous
537  // GmshIO behavior, add all the
538  // lower-dimensional elements' nodes to
539  // the Mesh's BoundaryInfo object with the
540  // lower-dimensional element's subdomain
541  // ID.
542  for (auto n : elem->node_index_range())
543  mesh.get_boundary_info().add_node(elem->node_id(n),
544  elem->subdomain_id());
545 
546  // Store this elem in a quickly-searchable
547  // container to use it to assign boundary
548  // conditions later.
549  provide_bcs.insert(std::make_pair(elem->key(), elem));
550  }
551 
552  // 2nd loop over active elements - use lower dimensional element data to set BCs for higher dimensional elements
553  for (auto & elem : mesh.active_element_ptr_range())
554  if (elem->dim() == max_elem_dimension_seen)
555  {
556  // This is a max-dimension element that
557  // may require BCs. For each of its
558  // sides, including internal sides, we'll
559  // see if one more more lower-dimensional elements
560  // provides boundary information for it.
561  // Note that we have not yet called
562  // find_neighbors(), so we can't use
563  // elem->neighbor(sn) in this algorithm...
564  for (auto sn : elem->side_index_range())
565  for (const auto & pr : as_range(provide_bcs.equal_range(elem->key(sn))))
566  {
567  // For each side side in the provide_bcs multimap...
568  // Construct the side for hash verification.
569  std::unique_ptr<Elem> side (elem->build_side_ptr(sn));
570 
571  // Construct the lower-dimensional element to compare to the side.
572  Elem * lower_dim_elem = pr.second;
573 
574  // This was a hash, so it might not be perfect. Let's verify...
575  if (*lower_dim_elem == *side)
576  {
577  // Add the lower-dimensional
578  // element's subdomain_id as a
579  // boundary_id for the
580  // higher-dimensional element.
581  boundary_id_type bid = cast_int<boundary_id_type>(lower_dim_elem->subdomain_id());
582  mesh.get_boundary_info().add_side(elem, sn, bid);
583  }
584  }
585  }
586 
587  // 3rd loop over active elements - Remove the lower-dimensional elements
588  for (auto & elem : mesh.active_element_ptr_range())
589  if (elem->dim() < max_elem_dimension_seen &&
590  !lower_dimensional_blocks.count(elem->subdomain_id()))
591  mesh.delete_elem(elem);
592  } // end if (n_dims_seen > 1)
593  } // if $ELM
594 
595  continue;
596  } // if (in)
597 
598 
599  // If !in, check to see if EOF was set. If so, break out
600  // of while loop.
601  if (in.eof())
602  break;
603 
604  // If !in and !in.eof(), stream is in a bad state!
605  libmesh_error_msg("Stream is bad! Perhaps the file does not exist?");
606 
607  } // while true
608 }
const MeshBase & mesh() const
Definition: mesh_output.h:234
virtual void reserve_nodes(const dof_id_type nn)=0
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2024
TestClass subdomain_id_type
Definition: id_types.h:43
unsigned short int side
Definition: xdr_io.C:50
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
const BoundaryInfo & get_boundary_info() const
Definition: mesh_base.h:131
std::map< unsigned int, ElementDefinition > in
Definition: gmsh_io.h:186
long double max(long double a, double b)
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
void add_node(const Node *node, const boundary_id_type id)
int8_t boundary_id_type
Definition: id_types.h:51
virtual void delete_elem(Elem *e)=0
virtual Elem * add_elem(Elem *e)=0
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:245
SimpleRange< I > as_range(const std::pair< I, I > &p)
Definition: simple_range.h:57
std::string & subdomain_name(subdomain_id_type id)
Definition: mesh_base.C:538
OStreamProxy err(std::cerr)
void set_mesh_dimension(unsigned char d)
Definition: mesh_base.h:213
virtual void clear()
Definition: mesh_base.C:260
std::string & sideset_name(boundary_id_type id)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
static ElementMaps _element_maps
Definition: gmsh_io.h:193
virtual const Node * node_ptr(const dof_id_type i) const =0
long double min(long double a, double b)
virtual void reserve_elem(const dof_id_type ne)=0

◆ set_n_partitions()

void libMesh::MeshInput< MeshBase >::set_n_partitions ( unsigned int  n_parts)
inlineprotectedinherited

Sets the number of partitions in the mesh. Typically this gets done by the partitioner, but some parallel file formats begin "pre-partitioned".

Definition at line 91 of file mesh_input.h.

References libMesh::MeshInput< MT >::mesh().

Referenced by libMesh::Nemesis_IO::read(), and libMesh::XdrIO::read_header().

91 { this->mesh().set_n_partitions() = n_parts; }
unsigned int & set_n_partitions()
Definition: mesh_base.h:1371

◆ skip_comment_lines()

void libMesh::MeshInput< MeshBase >::skip_comment_lines ( std::istream &  in,
const char  comment_start 
)
protectedinherited

Reads input from in, skipping all the lines that start with the character comment_start.

Definition at line 179 of file mesh_input.h.

Referenced by libMesh::TetGenIO::read(), and libMesh::UCDIO::read_implementation().

181 {
182  char c, line[256];
183 
184  while (in.get(c), c==comment_start)
185  in.getline (line, 255);
186 
187  // put back first character of
188  // first non-comment line
189  in.putback (c);
190 }

◆ write()

void libMesh::GmshIO::write ( const std::string &  name)
overridevirtual

This method implements writing a mesh to a specified file in the Gmsh *.msh format.

Implements libMesh::MeshOutput< MeshBase >.

Definition at line 612 of file gmsh_io.C.

References libMesh::Quality::name(), and write_mesh().

Referenced by libMesh::NameBasedIO::write().

613 {
614  if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
615  {
616  // Open the output file stream
617  std::ofstream out_stream (name.c_str());
618 
619  // Make sure it opened correctly
620  if (!out_stream.good())
621  libmesh_file_error(name.c_str());
622 
623  this->write_mesh (out_stream);
624  }
625 }
std::string name(const ElemQuality q)
Definition: elem_quality.C:42
const MeshBase & mesh() const
Definition: mesh_output.h:234
void write_mesh(std::ostream &out)
Definition: gmsh_io.C:641

◆ write_discontinuous_equation_systems()

void libMesh::MeshOutput< MeshBase >::write_discontinuous_equation_systems ( const std::string &  fname,
const EquationSystems es,
const std::set< std::string > *  system_names = nullptr 
)
virtualinherited

This method implements writing a mesh with discontinuous data to a specified file where the data is taken from the EquationSystems object.

Definition at line 92 of file mesh_output.C.

References libMesh::EquationSystems::build_discontinuous_solution_vector(), libMesh::EquationSystems::build_variable_names(), libMesh::EquationSystems::get_mesh(), and libMesh::out.

Referenced by libMesh::ExodusII_IO::write_timestep_discontinuous().

95 {
96  LOG_SCOPE("write_discontinuous_equation_systems()", "MeshOutput");
97 
98  // We may need to gather and/or renumber a DistributedMesh to output
99  // it, making that const qualifier in our constructor a dirty lie
100  MT & my_mesh = const_cast<MT &>(*_obj);
101 
102  // If we're asked to write data that's associated with a different
103  // mesh, output files full of garbage are the result.
104  libmesh_assert_equal_to(&es.get_mesh(), _obj);
105 
106  // A non-renumbered mesh may not have a contiguous numbering, and
107  // that needs to be fixed before we can build a solution vector.
108  if (my_mesh.max_elem_id() != my_mesh.n_elem() ||
109  my_mesh.max_node_id() != my_mesh.n_nodes())
110  {
111  // If we were allowed to renumber then we should have already
112  // been properly renumbered...
113  libmesh_assert(!my_mesh.allow_renumbering());
114 
115  libmesh_do_once(libMesh::out <<
116  "Warning: This MeshOutput subclass only supports meshes which are contiguously renumbered!"
117  << std::endl;);
118 
119  my_mesh.allow_renumbering(true);
120 
121  my_mesh.renumber_nodes_and_elements();
122 
123  // Not sure what good going back to false will do here, the
124  // renumbering horses have already left the barn...
125  my_mesh.allow_renumbering(false);
126  }
127 
128  MeshSerializer serialize(const_cast<MT &>(*_obj), !_is_parallel_format, _serial_only_needed_on_proc_0);
129 
130  // Build the list of variable names that will be written.
131  std::vector<std::string> names;
132  es.build_variable_names (names, nullptr, system_names);
133 
134  if (!_is_parallel_format)
135  {
136  // Build the nodal solution values & get the variable
137  // names from the EquationSystems object
138  std::vector<Number> soln;
139  es.build_discontinuous_solution_vector (soln, system_names);
140 
141  this->write_nodal_data_discontinuous (fname, soln, names);
142  }
143  else // _is_parallel_format
144  {
145  libmesh_not_implemented();
146  }
147 }
virtual void write_nodal_data_discontinuous(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
Definition: mesh_output.h:114
const MeshBase *const _obj
Definition: mesh_output.h:177
OStreamProxy out(std::cout)

◆ write_equation_systems()

void libMesh::MeshOutput< MeshBase >::write_equation_systems ( const std::string &  fname,
const EquationSystems es,
const std::set< std::string > *  system_names = nullptr 
)
virtualinherited

This method implements writing a mesh with data to a specified file where the data is taken from the EquationSystems object.

Reimplemented in libMesh::NameBasedIO.

Definition at line 31 of file mesh_output.C.

References libMesh::EquationSystems::build_parallel_solution_vector(), libMesh::EquationSystems::build_solution_vector(), libMesh::EquationSystems::build_variable_names(), libMesh::EquationSystems::get_mesh(), and libMesh::out.

Referenced by libMesh::Nemesis_IO::write_timestep(), and libMesh::ExodusII_IO::write_timestep().

34 {
35  LOG_SCOPE("write_equation_systems()", "MeshOutput");
36 
37  // We may need to gather and/or renumber a DistributedMesh to output
38  // it, making that const qualifier in our constructor a dirty lie
39  MT & my_mesh = const_cast<MT &>(*_obj);
40 
41  // If we're asked to write data that's associated with a different
42  // mesh, output files full of garbage are the result.
43  libmesh_assert_equal_to(&es.get_mesh(), _obj);
44 
45  // A non-renumbered mesh may not have a contiguous numbering, and
46  // that needs to be fixed before we can build a solution vector.
47  if (my_mesh.max_elem_id() != my_mesh.n_elem() ||
48  my_mesh.max_node_id() != my_mesh.n_nodes())
49  {
50  // If we were allowed to renumber then we should have already
51  // been properly renumbered...
52  libmesh_assert(!my_mesh.allow_renumbering());
53 
54  libmesh_do_once(libMesh::out <<
55  "Warning: This MeshOutput subclass only supports meshes which are contiguously renumbered!"
56  << std::endl;);
57 
58  my_mesh.allow_renumbering(true);
59 
60  my_mesh.renumber_nodes_and_elements();
61 
62  // Not sure what good going back to false will do here, the
63  // renumbering horses have already left the barn...
64  my_mesh.allow_renumbering(false);
65  }
66 
67  MeshSerializer serialize(const_cast<MT &>(*_obj), !_is_parallel_format, _serial_only_needed_on_proc_0);
68 
69  // Build the list of variable names that will be written.
70  std::vector<std::string> names;
71  es.build_variable_names (names, nullptr, system_names);
72 
74  {
75  // Build the nodal solution values & get the variable
76  // names from the EquationSystems object
77  std::vector<Number> soln;
78  es.build_solution_vector (soln, system_names);
79 
80  this->write_nodal_data (fname, soln, names);
81  }
82  else // _is_parallel_format
83  {
84  std::unique_ptr<NumericVector<Number>> parallel_soln =
85  es.build_parallel_solution_vector(system_names);
86 
87  this->write_nodal_data (fname, *parallel_soln, names);
88  }
89 }
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
Definition: mesh_output.h:105
const MeshBase *const _obj
Definition: mesh_output.h:177
OStreamProxy out(std::cout)

◆ write_lower_dimensional_elements()

bool & libMesh::GmshIO::write_lower_dimensional_elements ( )

Access to the flag which controls whether boundary elements are written to the Mesh file.

Definition at line 137 of file gmsh_io.C.

References _write_lower_dimensional_elements.

Referenced by write_mesh().

138 {
140 }
bool _write_lower_dimensional_elements
Definition: gmsh_io.h:148

◆ write_mesh()

void libMesh::GmshIO::write_mesh ( std::ostream &  out)
private

This method implements writing a mesh to a specified file. This will write an ASCII *.msh file.

Definition at line 641 of file gmsh_io.C.

References _element_maps, libMesh::MeshBase::active_element_ptr_range(), libMesh::BoundaryInfo::build_side_list(), libMesh::Elem::build_side_ptr(), libMesh::MeshBase::elem_ref(), libMesh::MeshBase::get_boundary_info(), libMesh::GmshIO::ElementDefinition::gmsh_type, libMesh::DofObject::id(), libMesh::MeshBase::max_elem_id(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshOutput< MT >::mesh(), libMesh::MeshBase::n_active_elem(), libMesh::BoundaryInfo::n_boundary_conds(), libMesh::MeshBase::n_nodes(), libMesh::MeshBase::node_ref(), libMesh::GmshIO::ElementDefinition::nodes, libMesh::GmshIO::ElementMaps::out, libMesh::DofObject::processor_id(), libMesh::Real, side, and write_lower_dimensional_elements().

Referenced by write().

642 {
643  // Be sure that the stream is valid.
644  libmesh_assert (out_stream.good());
645 
646  // Get a const reference to the mesh
647  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
648 
649  // If requested, write out lower-dimensional elements for
650  // element-side-based boundary conditions.
651  std::size_t n_boundary_faces = 0;
653  n_boundary_faces = mesh.get_boundary_info().n_boundary_conds();
654 
655  // Note: we are using version 2.0 of the gmsh output format.
656 
657  // Write the file header.
658  out_stream << "$MeshFormat\n";
659  out_stream << "2.0 0 " << sizeof(Real) << '\n';
660  out_stream << "$EndMeshFormat\n";
661 
662  // write the nodes in (n x y z) format
663  out_stream << "$Nodes\n";
664  out_stream << mesh.n_nodes() << '\n';
665 
666  for (unsigned int v=0; v<mesh.n_nodes(); v++)
667  out_stream << mesh.node_ref(v).id()+1 << " "
668  << mesh.node_ref(v)(0) << " "
669  << mesh.node_ref(v)(1) << " "
670  << mesh.node_ref(v)(2) << '\n';
671  out_stream << "$EndNodes\n";
672 
673  {
674  // write the connectivity
675  out_stream << "$Elements\n";
676  out_stream << mesh.n_active_elem() + n_boundary_faces << '\n';
677 
678  // loop over the elements
679  for (const auto & elem : mesh.active_element_ptr_range())
680  {
681  // Make sure we have a valid entry for
682  // the current element type.
683  libmesh_assert (_element_maps.out.count(elem->type()));
684 
685  // consult the export element table
686  auto def_it = _element_maps.out.find(elem->type());
687 
688  // Assert that we found it
689  if (def_it == _element_maps.out.end())
690  libmesh_error_msg("Element type " << elem->type() << " not found in _element_maps.");
691 
692  // Get a reference to the ElementDefinition object
693  const ElementDefinition & eletype = def_it->second;
694 
695  // The element mapper better not require any more nodes
696  // than are present in the current element!
697  libmesh_assert_less_equal (eletype.nodes.size(), elem->n_nodes());
698 
699  // elements ids are 1 based in Gmsh
700  out_stream << elem->id()+1 << " ";
701  // element type
702  out_stream << eletype.gmsh_type;
703 
704  // write the number of tags (3) and their values:
705  // 1 (physical entity)
706  // 2 (geometric entity)
707  // 3 (partition entity)
708  out_stream << " 3 "
709  << static_cast<unsigned int>(elem->subdomain_id())
710  << " 0 "
711  << elem->processor_id()+1
712  << " ";
713 
714  // if there is a node translation table, use it
715  if (eletype.nodes.size() > 0)
716  for (auto i : elem->node_index_range())
717  out_stream << elem->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
718  // otherwise keep the same node order
719  else
720  for (auto i : elem->node_index_range())
721  out_stream << elem->node_id(i)+1 << " "; // gmsh is 1-based
722  out_stream << "\n";
723  } // element loop
724  }
725 
726  {
727  // A counter for writing surface elements to the Gmsh file
728  // sequentially. We start numbering them with a number strictly
729  // larger than the largest element ID in the mesh. Note: the
730  // MeshBase docs say "greater than or equal to" the maximum
731  // element id in the mesh, so technically we might need a +1 here,
732  // but all of the implementations return an ID strictly greater
733  // than the largest element ID in the Mesh.
734  unsigned int e_id = mesh.max_elem_id();
735 
736  // loop over the elements, writing out boundary faces
737  if (n_boundary_faces)
738  {
739  // Build a list of (elem, side, bc) tuples.
740  auto bc_triples = mesh.get_boundary_info().build_side_list();
741 
742  // Loop over these lists, writing data to the file.
743  for (const auto & t : bc_triples)
744  {
745  const Elem & elem = mesh.elem_ref(std::get<0>(t));
746 
747  std::unique_ptr<const Elem> side = elem.build_side_ptr(std::get<1>(t));
748 
749  // Map from libmesh elem type to gmsh elem type.
750  auto def_it = _element_maps.out.find(side->type());
751 
752  // If we didn't find it, that's an error
753  if (def_it == _element_maps.out.end())
754  libmesh_error_msg("Element type " << side->type() << " not found in _element_maps.");
755 
756  // consult the export element table
757  const GmshIO::ElementDefinition & eletype = def_it->second;
758 
759  // The element mapper better not require any more nodes
760  // than are present in the current element!
761  libmesh_assert_less_equal (eletype.nodes.size(), side->n_nodes());
762 
763  // elements ids are 1-based in Gmsh
764  out_stream << e_id+1 << " ";
765 
766  // element type
767  out_stream << eletype.gmsh_type;
768 
769  // write the number of tags:
770  // 1 (physical entity)
771  // 2 (geometric entity)
772  // 3 (partition entity)
773  out_stream << " 3 "
774  << std::get<2>(t)
775  << " 0 "
776  << elem.processor_id()+1
777  << " ";
778 
779  // if there is a node translation table, use it
780  if (eletype.nodes.size() > 0)
781  for (auto i : side->node_index_range())
782  out_stream << side->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
783 
784  // otherwise keep the same node order
785  else
786  for (auto i : side->node_index_range())
787  out_stream << side->node_id(i)+1 << " "; // gmsh is 1-based
788 
789  // Go to the next line
790  out_stream << "\n";
791 
792  // increment this index too...
793  ++e_id;
794  }
795  }
796 
797  out_stream << "$EndElements\n";
798  }
799 }
const MT & mesh() const
Definition: mesh_output.h:234
std::size_t n_boundary_conds() const
virtual dof_id_type n_active_elem() const =0
bool & write_lower_dimensional_elements()
Definition: gmsh_io.C:137
unsigned short int side
Definition: xdr_io.C:50
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
const BoundaryInfo & get_boundary_info() const
Definition: mesh_base.h:131
void build_side_list(std::vector< dof_id_type > &element_id_list, std::vector< unsigned short int > &side_list, std::vector< boundary_id_type > &bc_id_list) const
std::map< ElemType, ElementDefinition > out
Definition: gmsh_io.h:185
dof_id_type id() const
Definition: dof_object.h:655
virtual dof_id_type max_elem_id() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:504
static ElementMaps _element_maps
Definition: gmsh_io.h:193
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:434
virtual dof_id_type n_nodes() const =0

◆ write_nodal_data() [1/2]

void libMesh::GmshIO::write_nodal_data ( const std::string &  fname,
const std::vector< Number > &  soln,
const std::vector< std::string > &  names 
)
overridevirtual

This method implements writing a mesh with nodal data to a specified file where the nodal data and variable names are provided.

Reimplemented from libMesh::MeshOutput< MeshBase >.

Definition at line 629 of file gmsh_io.C.

References write_post().

Referenced by libMesh::NameBasedIO::write_nodal_data().

632 {
633  LOG_SCOPE("write_nodal_data()", "GmshIO");
634 
635  if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
636  this->write_post (fname, &soln, &names);
637 }
const MeshBase & mesh() const
Definition: mesh_output.h:234
void write_post(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
Definition: gmsh_io.C:803

◆ write_nodal_data() [2/2]

void libMesh::MeshOutput< MeshBase >::write_nodal_data ( const std::string &  fname,
const NumericVector< Number > &  parallel_soln,
const std::vector< std::string > &  names 
)
virtualinherited

This method should be overridden by "parallel" output formats for writing nodal data. Instead of getting a localized copy of the nodal solution vector, it is passed a NumericVector of type=PARALLEL which is in node-major order i.e. (u0,v0,w0, u1,v1,w1, u2,v2,w2, u3,v3,w3, ...) and contains n_nodes*n_vars total entries. Then, it is up to the individual I/O class to extract the required solution values from this vector and write them in parallel.

If not implemented, localizes the parallel vector into a std::vector and calls the other version of this function.

Reimplemented in libMesh::Nemesis_IO.

Definition at line 150 of file mesh_output.C.

References libMesh::NumericVector< T >::localize().

153 {
154  // This is the fallback implementation for parallel I/O formats that
155  // do not yet implement proper writing in parallel, and instead rely
156  // on the full solution vector being available on all processors.
157  std::vector<Number> soln;
158  parallel_soln.localize(soln);
159  this->write_nodal_data(fname, soln, names);
160 }
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
Definition: mesh_output.h:105
virtual void localize(std::vector< T > &v_local) const =0

◆ write_nodal_data_discontinuous()

virtual void libMesh::MeshOutput< MeshBase >::write_nodal_data_discontinuous ( const std::string &  ,
const std::vector< Number > &  ,
const std::vector< std::string > &   
)
inlinevirtualinherited

This method implements writing a mesh with discontinuous data to a specified file where the nodal data and variables names are provided.

Reimplemented in libMesh::ExodusII_IO.

Definition at line 114 of file mesh_output.h.

117  { libmesh_not_implemented(); }

◆ write_post()

void libMesh::GmshIO::write_post ( const std::string &  fname,
const std::vector< Number > *  v = nullptr,
const std::vector< std::string > *  solution_names = nullptr 
)
private

This method implements writing a mesh with nodal data to a specified file where the nodal data and variable names are optionally provided. This will write an ASCII or binary *.pos file, depending on the binary flag.

Definition at line 803 of file gmsh_io.C.

References libMesh::MeshBase::active_element_ptr_range(), binary(), libMesh::EDGE2, libMesh::EDGE3, libMesh::EDGE4, libMesh::err, libMesh::HEX20, libMesh::HEX27, libMesh::HEX8, libMesh::libmesh_real(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshOutput< MT >::mesh(), libMesh::MeshBase::n_nodes(), n_vars, libMesh::out, libMesh::PRISM15, libMesh::PRISM18, libMesh::PRISM6, libMesh::PYRAMID5, libMesh::QUAD4, libMesh::QUAD8, libMesh::QUAD9, libMesh::TET10, libMesh::TET4, libMesh::TRI3, and libMesh::TRI6.

Referenced by write_nodal_data().

806 {
807 
808  // Should only do this on processor 0!
809  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
810 
811  // Create an output stream
812  std::ofstream out_stream(fname.c_str());
813 
814  // Make sure it opened correctly
815  if (!out_stream.good())
816  libmesh_file_error(fname.c_str());
817 
818  // create a character buffer
819  char buf[80];
820 
821  // Get a constant reference to the mesh.
822  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
823 
824  // write the data
825  if ((solution_names != nullptr) && (v != nullptr))
826  {
827  const unsigned int n_vars =
828  cast_int<unsigned int>(solution_names->size());
829 
830  if (!(v->size() == mesh.n_nodes()*n_vars))
831  libMesh::err << "ERROR: v->size()=" << v->size()
832  << ", mesh.n_nodes()=" << mesh.n_nodes()
833  << ", n_vars=" << n_vars
834  << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars
835  << "\n";
836 
837  libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars);
838 
839  // write the header
840  out_stream << "$PostFormat\n";
841  if (this->binary())
842  out_stream << "1.2 1 " << sizeof(double) << "\n";
843  else
844  out_stream << "1.2 0 " << sizeof(double) << "\n";
845  out_stream << "$EndPostFormat\n";
846 
847  // Loop over the elements to see how much of each type there are
848  unsigned int n_points=0, n_lines=0, n_triangles=0, n_quadrangles=0,
849  n_tetrahedra=0, n_hexahedra=0, n_prisms=0, n_pyramids=0;
850  unsigned int n_scalar=0, n_vector=0, n_tensor=0;
851  unsigned int nb_text2d=0, nb_text2d_chars=0, nb_text3d=0, nb_text3d_chars=0;
852 
853  {
854  for (const auto & elem : mesh.active_element_ptr_range())
855  {
856  const ElemType elemtype = elem->type();
857 
858  switch (elemtype)
859  {
860  case EDGE2:
861  case EDGE3:
862  case EDGE4:
863  {
864  n_lines += 1;
865  break;
866  }
867  case TRI3:
868  case TRI6:
869  {
870  n_triangles += 1;
871  break;
872  }
873  case QUAD4:
874  case QUAD8:
875  case QUAD9:
876  {
877  n_quadrangles += 1;
878  break;
879  }
880  case TET4:
881  case TET10:
882  {
883  n_tetrahedra += 1;
884  break;
885  }
886  case HEX8:
887  case HEX20:
888  case HEX27:
889  {
890  n_hexahedra += 1;
891  break;
892  }
893  case PRISM6:
894  case PRISM15:
895  case PRISM18:
896  {
897  n_prisms += 1;
898  break;
899  }
900  case PYRAMID5:
901  {
902  n_pyramids += 1;
903  break;
904  }
905  default:
906  libmesh_error_msg("ERROR: Nonexistent element type " << elem->type());
907  }
908  }
909  }
910 
911  // create a view for each variable
912  for (unsigned int ivar=0; ivar < n_vars; ivar++)
913  {
914  std::string varname = (*solution_names)[ivar];
915 
916  // at the moment, we just write out scalar quantities
917  // later this should be made configurable through
918  // options to the writer class
919  n_scalar = 1;
920 
921  // write the variable as a view, and the number of time steps
922  out_stream << "$View\n" << varname << " " << 1 << "\n";
923 
924  // write how many of each geometry type are written
925  out_stream << n_points * n_scalar << " "
926  << n_points * n_vector << " "
927  << n_points * n_tensor << " "
928  << n_lines * n_scalar << " "
929  << n_lines * n_vector << " "
930  << n_lines * n_tensor << " "
931  << n_triangles * n_scalar << " "
932  << n_triangles * n_vector << " "
933  << n_triangles * n_tensor << " "
934  << n_quadrangles * n_scalar << " "
935  << n_quadrangles * n_vector << " "
936  << n_quadrangles * n_tensor << " "
937  << n_tetrahedra * n_scalar << " "
938  << n_tetrahedra * n_vector << " "
939  << n_tetrahedra * n_tensor << " "
940  << n_hexahedra * n_scalar << " "
941  << n_hexahedra * n_vector << " "
942  << n_hexahedra * n_tensor << " "
943  << n_prisms * n_scalar << " "
944  << n_prisms * n_vector << " "
945  << n_prisms * n_tensor << " "
946  << n_pyramids * n_scalar << " "
947  << n_pyramids * n_vector << " "
948  << n_pyramids * n_tensor << " "
949  << nb_text2d << " "
950  << nb_text2d_chars << " "
951  << nb_text3d << " "
952  << nb_text3d_chars << "\n";
953 
954  // if binary, write a marker to identify the endianness of the file
955  if (this->binary())
956  {
957  const int one = 1;
958  std::memcpy(buf, &one, sizeof(int));
959  out_stream.write(buf, sizeof(int));
960  }
961 
962  // the time steps (there is just 1 at the moment)
963  if (this->binary())
964  {
965  double one = 1;
966  std::memcpy(buf, &one, sizeof(double));
967  out_stream.write(buf, sizeof(double));
968  }
969  else
970  out_stream << "1\n";
971 
972  // Loop over the elements and write out the data
973  for (const auto & elem : mesh.active_element_ptr_range())
974  {
975  // this is quite crappy, but I did not invent that file format!
976  for (unsigned int d=0; d<3; d++) // loop over the dimensions
977  {
978  for (unsigned int n=0; n < elem->n_vertices(); n++) // loop over vertices
979  {
980  const Point & vertex = elem->point(n);
981  if (this->binary())
982  {
983  double tmp = vertex(d);
984  std::memcpy(buf, &tmp, sizeof(double));
985  out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
986  }
987  else
988  out_stream << vertex(d) << " ";
989  }
990  if (!this->binary())
991  out_stream << "\n";
992  }
993 
994  // now finally write out the data
995  for (unsigned int i=0; i < elem->n_vertices(); i++) // loop over vertices
996  if (this->binary())
997  {
998 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
999  libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1000  << "complex numbers. Will only write the real part of "
1001  << "variable " << varname << std::endl;
1002 #endif
1003  double tmp = libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]);
1004  std::memcpy(buf, &tmp, sizeof(double));
1005  out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
1006  }
1007  else
1008  {
1009 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1010  libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1011  << "complex numbers. Will only write the real part of "
1012  << "variable " << varname << std::endl;
1013 #endif
1014  out_stream << libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]) << "\n";
1015  }
1016  }
1017  if (this->binary())
1018  out_stream << "\n";
1019  out_stream << "$EndView\n";
1020 
1021  } // end variable loop (writing the views)
1022  }
1023 }
T libmesh_real(T a)
const MeshBase & mesh() const
Definition: mesh_output.h:234
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
bool & binary()
Definition: gmsh_io.C:130
const unsigned int n_vars
Definition: tecplot_io.C:69
OStreamProxy err(std::cerr)
OStreamProxy out(std::cout)
virtual dof_id_type n_nodes() const =0

Member Data Documentation

◆ _binary

bool libMesh::GmshIO::_binary
private

Flag to write binary data.

Definition at line 142 of file gmsh_io.h.

Referenced by binary().

◆ _element_maps

GmshIO::ElementMaps libMesh::GmshIO::_element_maps = GmshIO::build_element_maps()
staticprivate

A static ElementMaps object that is built statically and used by all instances of this class.

Definition at line 193 of file gmsh_io.h.

Referenced by read_mesh(), and write_mesh().

◆ _is_parallel_format

const bool libMesh::MeshOutput< MeshBase >::_is_parallel_format
protectedinherited

Flag specifying whether this format is parallel-capable. If this is false (default) I/O is only permitted when the mesh has been serialized.

Definition at line 159 of file mesh_output.h.

Referenced by libMesh::FroIO::write(), libMesh::PostscriptIO::write(), and libMesh::EnsightIO::write().

◆ _serial_only_needed_on_proc_0

const bool libMesh::MeshOutput< MeshBase >::_serial_only_needed_on_proc_0
protectedinherited

Flag specifying whether this format can be written by only serializing the mesh to processor zero

If this is false (default) the mesh will be serialized to all processors

Definition at line 168 of file mesh_output.h.

◆ _write_lower_dimensional_elements

bool libMesh::GmshIO::_write_lower_dimensional_elements
private

If true, lower-dimensional elements based on the boundary conditions get written to the output file.

Definition at line 148 of file gmsh_io.h.

Referenced by write_lower_dimensional_elements().

◆ elems_of_dimension


The documentation for this class was generated from the following files: