libMesh
Classes | Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Static Private Member Functions | Private Attributes | Static Private Attributes | List of all members
libMesh::GmshIO Class Reference

Reading and writing meshes in the Gmsh format. More...

#include <gmsh_io.h>

Inheritance diagram for libMesh::GmshIO:
[legend]

Classes

struct  ElementDefinition
 Defines mapping from libMesh element types to Gmsh element types or vice-versa. More...
 
struct  ElementMaps
 struct which holds a map from Gmsh to libMesh element numberings and vice-versa. More...
 

Public Member Functions

 GmshIO (MeshBase &mesh)
 Constructor. More...
 
 GmshIO (const MeshBase &mesh)
 Constructor. More...
 
virtual void read (const std::string &name) override
 Reads in a mesh in the Gmsh *.msh format from the ASCII file given by name. More...
 
virtual void write (const std::string &name) override
 This method implements writing a mesh to a specified file in the Gmsh *.msh format. More...
 
virtual void write_nodal_data (const std::string &, const std::vector< Number > &, const std::vector< std::string > &) override
 This method implements writing a mesh with nodal data to a specified file where the nodal data and variable names are provided. More...
 
bool & binary ()
 Flag indicating whether or not to write a binary file. More...
 
bool & write_lower_dimensional_elements ()
 Access to the flag which controls whether boundary elements are written to the Mesh file. More...
 
bool is_parallel_format () const
 Returns true iff this mesh file format and input class are parallelized, so that all processors can read their share of the data at once. More...
 
virtual void write_equation_systems (const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
 This method implements writing a mesh with data to a specified file where the data is taken from the EquationSystems object. More...
 
virtual void write_discontinuous_equation_systems (const std::string &, const EquationSystems &, const std::set< std::string > *system_names=nullptr)
 This method implements writing a mesh with discontinuous data to a specified file where the data is taken from the EquationSystems object. More...
 
virtual void write_nodal_data (const std::string &, const NumericVector< Number > &, const std::vector< std::string > &)
 This method may be overridden by "parallel" output formats for writing nodal data. More...
 
virtual void write_nodal_data (const std::string &, const EquationSystems &, const std::set< std::string > *)
 This method should be overridden by "parallel" output formats for writing nodal data. More...
 
virtual void write_nodal_data_discontinuous (const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
 This method implements writing a mesh with discontinuous data to a specified file where the nodal data and variables names are provided. More...
 
unsigned intascii_precision ()
 Return/set the precision to use when writing ASCII files. More...
 

Protected Member Functions

MeshBasemesh ()
 
void set_n_partitions (unsigned int n_parts)
 Sets the number of partitions in the mesh. More...
 
void skip_comment_lines (std::istream &in, const char comment_start)
 Reads input from in, skipping all the lines that start with the character comment_start. More...
 
const MeshBasemesh () const
 
virtual bool get_add_sides ()
 

Protected Attributes

std::vector< bool > elems_of_dimension
 A vector of bools describing what dimension elements have been encountered when reading a mesh. More...
 
const bool _is_parallel_format
 Flag specifying whether this format is parallel-capable. More...
 
const bool _serial_only_needed_on_proc_0
 Flag specifying whether this format can be written by only serializing the mesh to processor zero. More...
 

Private Member Functions

void read_mesh (std::istream &in)
 Implementation of the read() function. More...
 
void write_mesh (std::ostream &out)
 This method implements writing a mesh to a specified file. More...
 
void write_post (const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
 This method implements writing a mesh with nodal data to a specified file where the nodal data and variable names are optionally provided. More...
 

Static Private Member Functions

static ElementMaps build_element_maps ()
 A static function used to construct the _element_maps struct, statically. More...
 

Private Attributes

bool _binary
 Flag to write binary data. More...
 
bool _write_lower_dimensional_elements
 If true, lower-dimensional elements based on the boundary conditions get written to the output file. More...
 

Static Private Attributes

static ElementMaps _element_maps = GmshIO::build_element_maps()
 A static ElementMaps object that is built statically and used by all instances of this class. More...
 

Detailed Description

Reading and 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 51 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 124 of file gmsh_io.C.

124  :
125  MeshInput<MeshBase> (mesh),
127  _binary (false),
129 {
130 }
bool _binary
Flag to write binary data.
Definition: gmsh_io.h:149
template class LIBMESH_EXPORT MeshOutput< MeshBase >
Definition: mesh_output.C:180
bool _write_lower_dimensional_elements
If true, lower-dimensional elements based on the boundary conditions get written to the output file...
Definition: gmsh_io.h:155

◆ 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 115 of file gmsh_io.C.

115  :
117  _binary(false),
119 {
120 }
bool _binary
Flag to write binary data.
Definition: gmsh_io.h:149
template class LIBMESH_EXPORT MeshOutput< MeshBase >
Definition: mesh_output.C:180
bool _write_lower_dimensional_elements
If true, lower-dimensional elements based on the boundary conditions get written to the output file...
Definition: gmsh_io.h:155

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>::max_digits10, which should be enough to write out to ASCII and get the exact same Real back when reading in.

Definition at line 269 of file mesh_output.h.

Referenced by libMesh::UNVIO::nodes_out(), libMesh::FroIO::write(), libMesh::MEDITIO::write_ascii(), libMesh::TecplotIO::write_ascii(), libMesh::GMVIO::write_ascii_new_impl(), and libMesh::GMVIO::write_ascii_old_impl().

270 {
271  return _ascii_precision;
272 }
unsigned int _ascii_precision
Precision to use when writing ASCII files.
Definition: mesh_output.h:207

◆ 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 134 of file gmsh_io.C.

References _binary.

Referenced by write_post().

135 {
136  return _binary;
137 }
bool _binary
Flag to write binary data.
Definition: gmsh_io.h:149

◆ 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 46 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, libMesh::TET10, libMesh::TET4, libMesh::TRI3, and libMesh::TRI6.

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

◆ get_add_sides()

virtual bool libMesh::MeshOutput< MeshBase >::get_add_sides ( )
inlineprotectedvirtualinherited
Returns
Whether or not added sides are expected to be output, to plot SIDE_DISCONTINUOUS data. Subclasses should override this if they are capable of plotting such data.

Reimplemented in libMesh::ExodusII_IO.

Definition at line 176 of file mesh_output.h.

176 { return false; }

◆ is_parallel_format()

bool libMesh::MeshInput< MeshBase >::is_parallel_format ( ) const
inlineinherited

Returns true iff this mesh file format and input class are parallelized, so that all processors can read their share of the data at once.

Definition at line 87 of file mesh_input.h.

References libMesh::MeshInput< MT >::_is_parallel_format.

87 { return this->_is_parallel_format; }
const bool _is_parallel_format
Flag specifying whether this format is parallel-capable.
Definition: mesh_input.h:130

◆ mesh() [1/2]

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

Definition at line 178 of file mesh_input.h.

Referenced by libMesh::GMVIO::_read_one_cell(), libMesh::VTKIO::cells_to_vtk(), libMesh::ExodusII_IO::copy_elemental_solution(), libMesh::Nemesis_IO::copy_elemental_solution(), libMesh::ExodusII_IO::copy_nodal_solution(), libMesh::TetGenIO::element_in(), libMesh::UNVIO::elements_in(), libMesh::UNVIO::elements_out(), libMesh::VTKIO::get_local_node_values(), libMesh::ExodusII_IO::get_sideset_data_indices(), 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::GMVIO::read(), libMesh::Nemesis_IO::read(), libMesh::ExodusII_IO::read(), libMesh::XdrIO::read(), libMesh::CheckpointIO::read(), libMesh::VTKIO::read(), libMesh::CheckpointIO::read_bcs(), libMesh::CheckpointIO::read_connectivity(), libMesh::ExodusII_IO::read_header(), libMesh::CheckpointIO::read_header(), libMesh::XdrIO::read_header(), libMesh::UCDIO::read_implementation(), libMesh::UNVIO::read_implementation(), read_mesh(), libMesh::DynaIO::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::ExodusII_IO::read_sideset_data(), libMesh::OFFIO::read_stream(), libMesh::MatlabIO::read_stream(), libMesh::CheckpointIO::read_subdomain_names(), libMesh::TetGenIO::write(), libMesh::Nemesis_IO::write(), libMesh::XdrIO::write(), libMesh::CheckpointIO::write(), libMesh::ExodusII_IO::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::ExodusII_IO::write_elemsets(), libMesh::UCDIO::write_header(), libMesh::UCDIO::write_implementation(), libMesh::UCDIO::write_interior_elems(), write_mesh(), libMesh::UCDIO::write_nodal_data(), libMesh::VTKIO::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::ExodusII_IO::write_sideset_data(), libMesh::UCDIO::write_soln(), and libMesh::CheckpointIO::write_subdomain_names().

179 {
180  libmesh_error_msg_if(_obj == nullptr, "ERROR: _obj should not be nullptr!");
181  return *_obj;
182 }
MeshBase * _obj
A pointer to a non-const object object.
Definition: mesh_input.h:123

◆ mesh() [2/2]

const MeshBase & libMesh::MeshOutput< MeshBase >::mesh ( ) const
inlineprotectedinherited

◆ 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.

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

The physical group names defined in the Gmsh-file are stored, depending on the element dimension, as either subdomain name or as side name. The IDs of the former can be retrieved by using the MeshBase::get_id_by_name method; the IDs of the latter can be retrieved by using the MeshBase::get_boundary_info and the BoundaryInfo::get_id_by_name methods.

Implements libMesh::MeshInput< MeshBase >.

Definition at line 148 of file gmsh_io.C.

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

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

149 {
150  std::ifstream in (name.c_str());
151  this->read_mesh (in);
152 }
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
void read_mesh(std::istream &in)
Implementation of the read() function.
Definition: gmsh_io.C:156

◆ 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 156 of file gmsh_io.C.

References _element_maps, libMesh::MeshBase::add_elem(), libMesh::BoundaryInfo::add_node(), libMesh::MeshBase::add_point(), libMesh::BoundaryInfo::add_side(), libMesh::as_range(), libMesh::Elem::build_with_id(), libMesh::MeshBase::clear(), libMesh::MeshBase::delete_elem(), libMesh::GmshIO::ElementDefinition::dim, libMesh::err, libMesh::MeshBase::get_boundary_info(), libMesh::GmshIO::ElementMaps::in, libMesh::index_range(), libMesh::is, libMesh::libmesh_assert(), libMesh::MeshInput< MT >::mesh(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::Elem::n_nodes(), libMesh::GmshIO::ElementDefinition::nnodes, libMesh::MeshBase::node_ptr(), libMesh::GmshIO::ElementDefinition::nodes, libMesh::BoundaryInfo::nodeset_name(), libMesh::Real, libMesh::MeshBase::reserve_elem(), libMesh::MeshBase::reserve_nodes(), libMesh::MeshBase::set_mesh_dimension(), libMesh::Elem::set_node(), libMesh::BoundaryInfo::sideset_name(), libMesh::Elem::subdomain_id(), libMesh::MeshBase::subdomain_name(), and libMesh::GmshIO::ElementDefinition::type.

Referenced by read().

157 {
158  // This is a serial-only process for now;
159  // the Mesh should be read on processor 0 and
160  // broadcast later
161  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
162 
163  libmesh_assert(in.good());
164 
165  // clear any data in the mesh
166  MeshBase & mesh = MeshInput<MeshBase>::mesh();
167  mesh.clear();
168 
169  // some variables
170  int format=0, size=0;
171  Real version = 1.0;
172 
173  // Keep track of lower-dimensional blocks which are not BCs, but
174  // actually blocks of lower-dimensional elements.
175  std::set<subdomain_id_type> lower_dimensional_blocks;
176 
177  // Mapping from physical id -> (physical dim, physical name) pairs.
178  // These can refer to either "sidesets" or "subdomains"; we need to
179  // wait until the Mesh has been read to know which is which. Note
180  // that we are using 'int' as the key here rather than
181  // subdomain_id_type or boundary_id_type, since at this point, it
182  // could be either.
183  typedef std::pair<unsigned, std::string> GmshPhysical;
184  std::map<int, GmshPhysical> gmsh_physicals;
185 
186  // map to hold the node numbers for translation
187  // note the the nodes can be non-consecutive
188  std::map<unsigned int, unsigned int> nodetrans;
189 
190  // Map from entity tag to physical id. The key is a pair with the first
191  // item being the dimension of the entity and the second item being
192  // the entity tag/id
193  std::map<std::pair<unsigned, int>, int> entity_to_physical_id;
194 
195  // For reading the file line by line
196  std::string s;
197 
198  while (true)
199  {
200  // Try to read something. This may set EOF!
201  std::getline(in, s);
202 
203  if (in)
204  {
205  // Process s...
206 
207  if (s.find("$MeshFormat") == static_cast<std::string::size_type>(0))
208  {
209  in >> version >> format >> size;
210 
211  // Some notes on gmsh mesh versions:
212  //
213  // Mesh version 2.0 goes back as far as I know. It's not explicitly
214  // mentioned here: http://www.geuz.org/gmsh/doc/VERSIONS.txt
215  //
216  // As of gmsh-2.4.0:
217  // bumped mesh version format to 2.1 (small change in the $PhysicalNames
218  // section, where the group dimension is now required);
219  // [Since we don't even parse the PhysicalNames section at the time
220  // of this writing, I don't think this change affects us.]
221  //
222  // Mesh version 2.2 tested by Manav Bhatia; no other
223  // libMesh code changes were required for support
224  //
225  // Mesh version 4.0 is a near complete rewrite of the previous mesh version
226  libmesh_error_msg_if(version < 2.0, "Error: Unknown msh file version " << version);
227  libmesh_error_msg_if(format, "Error: Unknown data format for mesh in Gmsh reader.");
228  }
229 
230  // Read and process the "PhysicalNames" section.
231  else if (s.find("$PhysicalNames") == static_cast<std::string::size_type>(0))
232  {
233  // The lines in the PhysicalNames section should look like the following:
234  // 2 1 "frac" lower_dimensional_block
235  // 2 3 "top"
236  // 2 4 "bottom"
237  // 3 2 "volume"
238 
239  // Read in the number of physical groups to expect in the file.
240  unsigned int num_physical_groups = 0;
241  in >> num_physical_groups;
242 
243  // Read rest of line including newline character.
244  std::getline(in, s);
245 
246  for (unsigned int i=0; i<num_physical_groups; ++i)
247  {
248  // Read an entire line of the PhysicalNames section.
249  std::getline(in, s);
250 
251  // Use an istringstream to extract the physical
252  // dimension, physical id, and physical name from
253  // this line.
254  std::istringstream s_stream(s);
255  unsigned phys_dim;
256  int phys_id;
257  std::string phys_name;
258  s_stream >> phys_dim >> phys_id >> phys_name;
259 
260  // Not sure if this is true for all Gmsh files, but
261  // my test file has quotes around the phys_name
262  // string. So let's erase any quotes now...
263  phys_name.erase(std::remove(phys_name.begin(), phys_name.end(), '"'), phys_name.end());
264 
265  // Record this ID for later assignment of subdomain/sideset names.
266  gmsh_physicals[phys_id] = std::make_pair(phys_dim, phys_name);
267 
268  // If 's' also contains the libmesh-specific string
269  // "lower_dimensional_block", add this block ID to
270  // the list of blocks which are not boundary
271  // conditions.
272  if (s.find("lower_dimensional_block") != std::string::npos)
273  {
274  lower_dimensional_blocks.insert(cast_int<subdomain_id_type>(phys_id));
275 
276  // The user has explicitly told us that this
277  // block is a subdomain, so set that association
278  // in the Mesh.
279  mesh.subdomain_name(cast_int<subdomain_id_type>(phys_id)) = phys_name;
280  }
281  }
282  }
283 
284  else if (s.find("$Entities") == static_cast<std::string::size_type>(0))
285  {
286  if (version >= 4.0)
287  {
288  std::size_t num_point_entities, num_curve_entities, num_surface_entities, num_volume_entities;
289  in >> num_point_entities >> num_curve_entities >> num_surface_entities >> num_volume_entities;
290 
291  for (std::size_t n = 0; n < num_point_entities; ++n)
292  {
293  int point_tag, physical_tag;
294  Real x, y, z;
295  std::size_t num_physical_tags;
296  in >> point_tag >> x >> y >> z >> num_physical_tags;
297 
298  libmesh_error_msg_if(num_physical_tags > 1,
299  "Sorry, you cannot currently specify multiple subdomain or "
300  "boundary ids for a given geometric entity");
301 
302  if (num_physical_tags)
303  {
304  in >> physical_tag;
305  entity_to_physical_id[std::make_pair(0, point_tag)] = physical_tag;
306  }
307  }
308  for (std::size_t n = 0; n < num_curve_entities; ++n)
309  {
310  int curve_tag, physical_tag;
311  Real minx, miny, minz, maxx, maxy, maxz;
312  std::size_t num_physical_tags;
313  in >> curve_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
314 
315  libmesh_error_msg_if(num_physical_tags > 1,
316  "I don't believe that we can specify multiple subdomain or "
317  "boundary ids for a given geometric entity");
318 
319  if (num_physical_tags)
320  {
321  in >> physical_tag;
322  entity_to_physical_id[std::make_pair(1, curve_tag)] = physical_tag;
323  }
324 
325  // Read to end of line; this captures bounding information that we don't care about
326  std::getline(in, s);
327  }
328  for (std::size_t n = 0; n < num_surface_entities; ++n)
329  {
330  int surface_tag, physical_tag;
331  Real minx, miny, minz, maxx, maxy, maxz;
332  std::size_t num_physical_tags;
333  in >> surface_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
334 
335  libmesh_error_msg_if(num_physical_tags > 1,
336  "I don't believe that we can specify multiple subdomain or "
337  "boundary ids for a given geometric entity");
338 
339  if (num_physical_tags)
340  {
341  in >> physical_tag;
342  entity_to_physical_id[std::make_pair(2, surface_tag)] = physical_tag;
343  }
344 
345  // Read to end of line; this captures bounding information that we don't care about
346  std::getline(in, s);
347  }
348  for (std::size_t n = 0; n < num_volume_entities; ++n)
349  {
350  int volume_tag, physical_tag;
351  Real minx, miny, minz, maxx, maxy, maxz;
352  std::size_t num_physical_tags;
353  in >> volume_tag >> minx >> miny >> minz >> maxx >> maxy >> maxz >> num_physical_tags;
354 
355  libmesh_error_msg_if(num_physical_tags > 1,
356  "I don't believe that we can specify multiple subdomain or "
357  "boundary ids for a given geometric entity");
358 
359  if (num_physical_tags)
360  {
361  in >> physical_tag;
362  entity_to_physical_id[std::make_pair(3, volume_tag)] = physical_tag;
363  }
364 
365  // Read to end of line; this captures bounding information that we don't care about
366  std::getline(in, s);
367  }
368  // Read the $EndEntities
369  std::getline(in, s);
370  } // end if (version >= 4.0)
371 
372  else
373  libmesh_error_msg("The Entities block was introduced in mesh version 4.0");
374  } // end if $Entities
375 
376  // read the node block
377  else if (s.find("$NOD") == static_cast<std::string::size_type>(0) ||
378  s.find("$NOE") == static_cast<std::string::size_type>(0) ||
379  s.find("$Nodes") == static_cast<std::string::size_type>(0))
380  {
381  if (version < 4.0)
382  {
383  unsigned int num_nodes = 0;
384  in >> num_nodes;
385  mesh.reserve_nodes (num_nodes);
386 
387  // read in the nodal coordinates and form points.
388  Real x, y, z;
389  unsigned int id;
390 
391  // add the nodal coordinates to the mesh
392  for (unsigned int i=0; i<num_nodes; ++i)
393  {
394  in >> id >> x >> y >> z;
395  mesh.add_point (Point(x, y, z), i);
396  nodetrans[id] = i;
397  }
398  }
399  else
400  {
401  // Read numEntityBlocks line
402  std::size_t num_entities = 0, num_nodes = 0, min_node_tag, max_node_tag;
403  in >> num_entities >> num_nodes >> min_node_tag >> max_node_tag;
404 
405  mesh.reserve_nodes(num_nodes);
406 
407  std::size_t node_counter = 0;
408 
409  // Now loop over entities
410  for (std::size_t i = 0; i < num_entities; ++i)
411  {
412  int entity_dim, entity_tag, parametric;
413  std::size_t num_nodes_in_block = 0;
414  in >> entity_dim >> entity_tag >> parametric >> num_nodes_in_block;
415  libmesh_error_msg_if(parametric, "We don't currently support reading parametric gmsh entities");
416 
417  // Read the node tags/ids
418  std::size_t gmsh_id;
419  for (std::size_t n = 0; n < num_nodes_in_block; ++n)
420  {
421 
422  in >> gmsh_id;
423  nodetrans[gmsh_id] = node_counter++;
424  }
425 
426  // Read the node coordinates and add the nodes to the mesh
427  Real x, y, z;
428  for (std::size_t libmesh_id = node_counter - num_nodes_in_block;
429  libmesh_id < node_counter;
430  ++libmesh_id)
431  {
432  in >> x >> y >> z;
433  mesh.add_point(Point(x, y, z), libmesh_id);
434  }
435  }
436  }
437  // read the $ENDNOD delimiter
438  std::getline(in, s);
439  }
440 
441  // Read the element block
442  else if (s.find("$ELM") == static_cast<std::string::size_type>(0) ||
443  s.find("$Elements") == static_cast<std::string::size_type>(0))
444  {
445  // Keep track of element dimensions seen
446  std::vector<unsigned> elem_dimensions_seen(3);
447 
448  if (version < 4.0)
449  {
450  // For reading the number of elements and the node ids from the stream
451  unsigned int
452  num_elem = 0,
453  node_id = 0;
454 
455  // read how many elements are there, and reserve space in the mesh
456  in >> num_elem;
457  mesh.reserve_elem (num_elem);
458 
459  // As of version 2.2, the format for each element line is:
460  // elm-number elm-type number-of-tags < tag > ... node-number-list
461  // From the Gmsh docs:
462  // * the first tag is the number of the
463  // physical entity to which the element belongs
464  // * the second is the number of the elementary geometrical
465  // entity to which the element belongs
466  // * the third is the number of mesh partitions to which the element
467  // belongs
468  // * The rest of the tags are the partition ids (negative
469  // partition ids indicate ghost cells). A zero tag is
470  // equivalent to no tag. Gmsh and most codes using the
471  // MSH 2 format require at least the first two tags
472  // (physical and elementary tags).
473 
474  // read the elements
475  for (unsigned int iel=0; iel<num_elem; ++iel)
476  {
477  unsigned int
478  id, type,
479  physical=1, elementary=1,
480  nnodes=0, ntags;
481 
482  // Note: tag has to be an int because it could be negative,
483  // see above.
484  int tag;
485 
486  if (version <= 1.0)
487  in >> id >> type >> physical >> elementary >> nnodes;
488 
489  else
490  {
491  in >> id >> type >> ntags;
492 
493  if (ntags > 2)
494  libmesh_do_once(libMesh::err << "Warning, ntags=" << ntags << ", but we currently only support reading 2 flags." << std::endl;);
495 
496  for (unsigned int j = 0; j < ntags; j++)
497  {
498  in >> tag;
499  if (j == 0)
500  physical = tag;
501  else if (j == 1)
502  elementary = tag;
503  }
504  }
505 
506  // Get a reference to the ElementDefinition, throw an error if not found.
507  const GmshIO::ElementDefinition & eletype =
508  libmesh_map_find(_element_maps.in, type);
509 
510  // If we read nnodes, make sure it matches the number in eletype.nnodes
511  libmesh_error_msg_if(nnodes != 0 && nnodes != eletype.nnodes,
512  "nnodes = " << nnodes << " and eletype.nnodes = " << eletype.nnodes << " do not match.");
513 
514  // Assign the value from the eletype object.
515  nnodes = eletype.nnodes;
516 
517  // Don't add 0-dimensional "point" elements to the
518  // Mesh. They should *always* be treated as boundary
519  // "nodeset" data.
520  if (eletype.dim > 0)
521  {
522  // Record this element dimension as being "seen".
523  // We will treat all elements with dimension <
524  // max(dimension) as specifying boundary conditions,
525  // but we won't know what max_elem_dimension_seen is
526  // until we read the entire file.
527  elem_dimensions_seen[eletype.dim-1] = 1;
528 
529  // Add the element to the mesh
530  {
531  Elem * elem =
532  mesh.add_elem(Elem::build_with_id(eletype.type, iel));
533 
534  // Make sure that the libmesh element we added has nnodes nodes.
535  libmesh_error_msg_if(elem->n_nodes() != nnodes,
536  "Number of nodes for element "
537  << id
538  << " of type " << eletype.type
539  << " (Gmsh type " << type
540  << ") does not match Libmesh definition. "
541  << "I expected " << elem->n_nodes()
542  << " nodes, but got " << nnodes);
543 
544  // Add node pointers to the elements.
545  // If there is a node translation table, use it.
546  if (eletype.nodes.size() > 0)
547  for (unsigned int i=0; i<nnodes; i++)
548  {
549  in >> node_id;
550  elem->set_node(eletype.nodes[i]) = mesh.node_ptr(nodetrans[node_id]);
551  }
552  else
553  {
554  for (unsigned int i=0; i<nnodes; i++)
555  {
556  in >> node_id;
557  elem->set_node(i) = mesh.node_ptr(nodetrans[node_id]);
558  }
559  }
560 
561  // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will
562  // eventually go into the Mesh's BoundaryInfo object.
563  elem->subdomain_id() = static_cast<subdomain_id_type>(physical);
564  }
565  }
566 
567  // Handle 0-dimensional elements (points) by adding
568  // them to the BoundaryInfo object with
569  // boundary_id == physical.
570  else
571  {
572  // This seems like it should always be the same
573  // number as the 'id' we already read in on this
574  // line. At least it was in the example gmsh
575  // file I had...
576  in >> node_id;
578  (nodetrans[node_id],
579  static_cast<boundary_id_type>(physical));
580  }
581  } // element loop
582  } // end if (version < 4.0)
583 
584  else
585  {
586  std::size_t num_entity_blocks = 0, num_elem = 0, min_element_tag, max_element_tag;
587 
588  // Read entity information
589  in >> num_entity_blocks >> num_elem >> min_element_tag >> max_element_tag;
590 
591  mesh.reserve_elem(num_elem);
592 
593  std::size_t iel = 0;
594 
595  // Loop over entity blocks
596  for (std::size_t i = 0; i < num_entity_blocks; ++i)
597  {
598  int entity_dim, entity_tag;
599  unsigned int element_type;
600  std::size_t num_elems_in_block = 0;
601  in >> entity_dim >> entity_tag >> element_type >> num_elems_in_block;
602 
603  // Get a reference to the ElementDefinition
604  const GmshIO::ElementDefinition & eletype =
605  libmesh_map_find(_element_maps.in, element_type);
606 
607  // Don't add 0-dimensional "point" elements to the
608  // Mesh. They should *always* be treated as boundary
609  // "nodeset" data.
610  if (eletype.dim > 0)
611  {
612  // Record this element dimension as being "seen".
613  // We will treat all elements with dimension <
614  // max(dimension) as specifying boundary conditions,
615  // but we won't know what max_elem_dimension_seen is
616  // until we read the entire file.
617  elem_dimensions_seen[eletype.dim-1] = 1;
618 
619  // Loop over elements with dim > 0
620  for (std::size_t n = 0; n < num_elems_in_block; ++n)
621  {
622  Elem * elem =
623  mesh.add_elem(Elem::build_with_id(eletype.type, iel++));
624 
625  std::size_t gmsh_element_id;
626  in >> gmsh_element_id;
627 
628  // Get the remainder of the line that includes the nodes ids
629  std::getline(in, s);
630  std::istringstream is(s);
631  std::size_t local_node_counter = 0, gmsh_node_id;
632  while (is >> gmsh_node_id)
633  {
634  // Add node pointers to the elements.
635  // If there is a node translation table, use it.
636  if (eletype.nodes.size() > 0)
637  elem->set_node(eletype.nodes[local_node_counter++]) =
638  mesh.node_ptr(nodetrans[gmsh_node_id]);
639  else
640  elem->set_node(local_node_counter++) = mesh.node_ptr(nodetrans[gmsh_node_id]);
641  }
642 
643  // Make sure that the libmesh element we added has nnodes nodes.
644  libmesh_error_msg_if(elem->n_nodes() != local_node_counter,
645  "Number of nodes for element "
646  << gmsh_element_id
647  << " of type " << eletype.type
648  << " (Gmsh type " << element_type
649  << ") does not match Libmesh definition. "
650  << "I expected " << elem->n_nodes()
651  << " nodes, but got " << local_node_counter);
652 
653  // Finally, set the subdomain ID to physical. If this is a lower-dimension element, this ID will
654  // eventually go into the Mesh's BoundaryInfo object.
655  elem->subdomain_id() = static_cast<subdomain_id_type>(
656  entity_to_physical_id[std::make_pair(entity_dim, entity_tag)]);
657 
658  } // end for (loop over elements in entity block)
659  } // end if (eletype.dim > 0)
660 
661  else
662  {
663  for (std::size_t n = 0; n < num_elems_in_block; ++n)
664  {
665  std::size_t gmsh_element_id, gmsh_node_id;
666  in >> gmsh_element_id;
667  in >> gmsh_node_id;
669  nodetrans[gmsh_node_id],
670  static_cast<boundary_id_type>(entity_to_physical_id[
671  std::make_pair(entity_dim, entity_tag)]));
672  } // end for (loop over elements in entity block)
673  } // end if (eletype.dim == 0)
674  } // end for (loop over entity blocks)
675  } // end if (version >= 4.0)
676 
677  // read the $ENDELM delimiter
678  std::getline(in, s);
679 
680  // Record the max and min element dimension seen while reading the file.
681  unsigned char
682  max_elem_dimension_seen=1,
683  min_elem_dimension_seen=3;
684 
685  for (auto i : index_range(elem_dimensions_seen))
686  if (elem_dimensions_seen[i])
687  {
688  // Debugging
689  // libMesh::out << "Seen elements of dimension " << i+1 << std::endl;
690  max_elem_dimension_seen =
691  std::max(max_elem_dimension_seen, cast_int<unsigned char>(i+1));
692  min_elem_dimension_seen =
693  std::min(min_elem_dimension_seen, cast_int<unsigned char>(i+1));
694  }
695 
696  // Debugging:
697  // libMesh::out << "max_elem_dimension_seen=" << max_elem_dimension_seen << std::endl;
698  // libMesh::out << "min_elem_dimension_seen=" << min_elem_dimension_seen << std::endl;
699 
700 
701  // How many different element dimensions did we see while reading from file?
702  unsigned n_dims_seen = std::accumulate(elem_dimensions_seen.begin(),
703  elem_dimensions_seen.end(),
704  static_cast<unsigned>(0),
705  std::plus<unsigned>());
706 
707 
708  // Set mesh_dimension based on the largest element dimension seen.
709  mesh.set_mesh_dimension(max_elem_dimension_seen);
710 
711  // Now that we know the maximum element dimension seen,
712  // we know whether the physical names are subdomain
713  // names or sideset names.
714  for (const auto & pr : gmsh_physicals)
715  {
716  // Extract data
717  int phys_id = pr.first;
718  unsigned phys_dim = pr.second.first;
719  const std::string & phys_name = pr.second.second;
720 
721  // If the physical's dimension matches the largest
722  // dimension we've seen, it's a subdomain name.
723  if (phys_dim == max_elem_dimension_seen)
724  mesh.subdomain_name(cast_int<subdomain_id_type>(phys_id)) = phys_name;
725 
726  // If it's zero-dimensional then it's a nodeset
727  else if (phys_dim == 0)
728  mesh.get_boundary_info().nodeset_name(cast_int<boundary_id_type>(phys_id)) = phys_name;
729 
730  // Otherwise, if it's not a lower-dimensional
731  // block, it's a sideset name.
732  else if (phys_dim < max_elem_dimension_seen &&
733  !lower_dimensional_blocks.count(cast_int<boundary_id_type>(phys_id)))
734  mesh.get_boundary_info().sideset_name(cast_int<boundary_id_type>(phys_id)) = phys_name;
735  }
736 
737  if (n_dims_seen > 1)
738  {
739  // Store lower-dimensional elements in a map sorted
740  // by Elem::key(). We use a multimap for two reasons:
741  // 1.) The hash function is not guaranteed to be
742  // unique, so different lower-dimensional elements
743  // could theoretically hash to the same value,
744  // although this is pretty unlikely.
745  // 2.) The Gmsh file may contain multiple
746  // lower-dimensional elements for a single side in
747  // order to implement multiple boundary ids for a
748  // single side. These lower-dimensional elements
749  // will all hash to the same value, and we need to
750  // be able to store all of them.
751  typedef std::unordered_multimap<dof_id_type, Elem *> provide_container_t;
752  provide_container_t provide_bcs;
753 
754  // 1st loop over active elements - get info about lower-dimensional elements.
755  for (auto & elem : mesh.active_element_ptr_range())
756  if (elem->dim() < max_elem_dimension_seen &&
757  !lower_dimensional_blocks.count(elem->subdomain_id()))
758  {
759  // To be consistent with the previous
760  // GmshIO behavior, add all the
761  // lower-dimensional elements' nodes to
762  // the Mesh's BoundaryInfo object with the
763  // lower-dimensional element's subdomain
764  // ID.
765  for (auto n : elem->node_index_range())
766  mesh.get_boundary_info().add_node(elem->node_id(n),
767  elem->subdomain_id());
768 
769  // Store this elem in a quickly-searchable
770  // container to use it to assign boundary
771  // conditions later.
772  provide_bcs.emplace(elem->key(), elem);
773  }
774 
775  // 2nd loop over active elements - use lower dimensional element data to set BCs for higher dimensional elements
776  for (auto & elem : mesh.active_element_ptr_range())
777  if (elem->dim() == max_elem_dimension_seen)
778  {
779  // This is a max-dimension element that
780  // may require BCs. For each of its
781  // sides, including internal sides, we'll
782  // see if one more more lower-dimensional elements
783  // provides boundary information for it.
784  // Note that we have not yet called
785  // find_neighbors(), so we can't use
786  // elem->neighbor(sn) in this algorithm...
787  for (auto sn : elem->side_index_range())
788  for (const auto & pr : as_range(provide_bcs.equal_range(elem->key(sn))))
789  {
790  // For each side side in the provide_bcs multimap...
791  // Construct the side for hash verification.
792  std::unique_ptr<Elem> side (elem->build_side_ptr(sn));
793 
794  // Construct the lower-dimensional element to compare to the side.
795  Elem * lower_dim_elem = pr.second;
796 
797  // This was a hash, so it might not be perfect. Let's verify...
798  if (*lower_dim_elem == *side)
799  {
800  // Add the lower-dimensional
801  // element's subdomain_id as a
802  // boundary_id for the
803  // higher-dimensional element.
804  boundary_id_type bid = cast_int<boundary_id_type>(lower_dim_elem->subdomain_id());
805  mesh.get_boundary_info().add_side(elem, sn, bid);
806  }
807  }
808  }
809 
810  // 3rd loop over active elements - Remove the lower-dimensional elements
811  for (auto & elem : mesh.active_element_ptr_range())
812  if (elem->dim() < max_elem_dimension_seen &&
813  !lower_dimensional_blocks.count(elem->subdomain_id()))
814  mesh.delete_elem(elem);
815  } // end if (n_dims_seen > 1)
816  } // if $ELM
817 
818  continue;
819  } // if (in)
820 
821 
822  // If !in, check to see if EOF was set. If so, break out
823  // of while loop.
824  if (in.eof())
825  break;
826 
827  // If !in and !in.eof(), stream is in a bad state!
828  libmesh_error_msg("Stream is bad! Perhaps the file does not exist?");
829 
830  } // while true
831 }
OStreamProxy err
const MeshBase & mesh() const
Definition: mesh_output.h:259
virtual void reserve_nodes(const dof_id_type nn)=0
Reserves space for a known number of nodes.
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2381
std::string & nodeset_name(boundary_id_type id)
TestClass subdomain_id_type
Based on the 4-byte comment warning above, this probably doesn&#39;t work with exodusII at all...
Definition: id_types.h:43
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:159
std::map< unsigned int, ElementDefinition > in
Definition: gmsh_io.h:193
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
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
void add_node(const Node *node, const boundary_id_type id)
Add Node node with boundary id id to the boundary information data structures.
int8_t boundary_id_type
Definition: id_types.h:51
virtual void delete_elem(Elem *e)=0
Removes element e from the mesh.
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
Definition: simple_range.h:57
libmesh_assert(ctx)
PetscErrorCode PetscInt const PetscInt IS * is
std::string & subdomain_name(subdomain_id_type id)
Definition: mesh_base.C:1619
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:269
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:862
std::string & sideset_name(boundary_id_type id)
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
static std::unique_ptr< Elem > build_with_id(const ElemType type, dof_id_type id)
Calls the build() method above with a nullptr parent, and additionally sets the newly-created Elem&#39;s ...
Definition: elem.C:375
void add_side(const dof_id_type elem, const unsigned short int side, const boundary_id_type id)
Add side side of element number elem with boundary id id to the boundary information data structure...
static ElementMaps _element_maps
A static ElementMaps object that is built statically and used by all instances of this class...
Definition: gmsh_io.h:200
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual void reserve_elem(const dof_id_type ne)=0
Reserves space for a known number of elements.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition: int_range.h:111

◆ 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 101 of file mesh_input.h.

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

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

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

◆ 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 187 of file mesh_input.h.

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

189 {
190  char c, line[256];
191 
192  while (in.get(c), c==comment_start)
193  in.getline (line, 255);
194 
195  // put back first character of
196  // first non-comment line
197  in.putback (c);
198 }

◆ 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 835 of file gmsh_io.C.

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

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

836 {
837  if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
838  {
839  // Open the output file stream
840  std::ofstream out_stream (name.c_str());
841 
842  // Make sure it opened correctly
843  if (!out_stream.good())
844  libmesh_file_error(name.c_str());
845 
846  this->write_mesh (out_stream);
847  }
848 }
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42
const MeshBase & mesh() const
Definition: mesh_output.h:259
void write_mesh(std::ostream &out)
This method implements writing a mesh to a specified file.
Definition: gmsh_io.C:864

◆ 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 89 of file mesh_output.C.

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

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

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

◆ 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_solution_vector(), libMesh::EquationSystems::build_variable_names(), libMesh::EquationSystems::get_mesh(), libMesh::libmesh_assert(), 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-parallel format, non-renumbered mesh may not have a contiguous
46  // numbering, and that needs to be fixed before we can build a solution vector.
47  if (!_is_parallel_format &&
48  (my_mesh.max_elem_id() != my_mesh.n_elem() ||
49  my_mesh.max_node_id() != my_mesh.n_nodes()))
50  {
51  // If we were allowed to renumber then we should have already
52  // been properly renumbered...
53  libmesh_assert(!my_mesh.allow_renumbering());
54 
55  libmesh_do_once(libMesh::out <<
56  "Warning: This MeshOutput subclass only supports meshes which are contiguously renumbered!"
57  << std::endl;);
58 
59  my_mesh.allow_renumbering(true);
60 
61  my_mesh.renumber_nodes_and_elements();
62 
63  // Not sure what good going back to false will do here, the
64  // renumbering horses have already left the barn...
65  my_mesh.allow_renumbering(false);
66  }
67 
69  {
70  MeshSerializer serialize(const_cast<MT &>(*_obj), !_is_parallel_format, _serial_only_needed_on_proc_0);
71 
72  // Build the list of variable names that will be written.
73  std::vector<std::string> names;
74  es.build_variable_names (names, nullptr, system_names);
75 
76  // Build the nodal solution values & get the variable
77  // names from the EquationSystems object
78  std::vector<Number> soln;
79  es.build_solution_vector (soln, system_names,
80  this->get_add_sides());
81 
82  this->write_nodal_data (fname, soln, names);
83  }
84  else // _is_parallel_format
85  this->write_nodal_data (fname, es, system_names);
86 }
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: mesh_output.h:109
const MeshBase *const _obj
A pointer to a constant object.
Definition: mesh_output.h:202
const bool _is_parallel_format
Flag specifying whether this format is parallel-capable.
Definition: mesh_output.h:184
libmesh_assert(ctx)
OStreamProxy out
const bool _serial_only_needed_on_proc_0
Flag specifying whether this format can be written by only serializing the mesh to processor zero...
Definition: mesh_output.h:193

◆ 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 141 of file gmsh_io.C.

References _write_lower_dimensional_elements.

Referenced by write_mesh().

142 {
144 }
bool _write_lower_dimensional_elements
If true, lower-dimensional elements based on the boundary conditions get written to the output file...
Definition: gmsh_io.h:155

◆ 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 864 of file gmsh_io.C.

References _element_maps, 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::libmesh_assert(), libMesh::make_range(), 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, and write_lower_dimensional_elements().

Referenced by write().

865 {
866  // Be sure that the stream is valid.
867  libmesh_assert (out_stream.good());
868 
869  // Get a const reference to the mesh
870  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
871 
872  // If requested, write out lower-dimensional elements for
873  // element-side-based boundary conditions.
874  std::size_t n_boundary_faces = 0;
876  n_boundary_faces = mesh.get_boundary_info().n_boundary_conds();
877 
878  // Note: we are using version 2.0 of the gmsh output format.
879 
880  // Write the file header.
881  out_stream << "$MeshFormat\n";
882  out_stream << "2.0 0 " << sizeof(Real) << '\n';
883  out_stream << "$EndMeshFormat\n";
884 
885  // write the nodes in (n x y z) format
886  out_stream << "$Nodes\n";
887  out_stream << mesh.n_nodes() << '\n';
888 
889  for (auto v : make_range(mesh.n_nodes()))
890  out_stream << mesh.node_ref(v).id()+1 << " "
891  << mesh.node_ref(v)(0) << " "
892  << mesh.node_ref(v)(1) << " "
893  << mesh.node_ref(v)(2) << '\n';
894  out_stream << "$EndNodes\n";
895 
896  {
897  // write the connectivity
898  out_stream << "$Elements\n";
899  out_stream << mesh.n_active_elem() + n_boundary_faces << '\n';
900 
901  // loop over the elements
902  for (const auto & elem : mesh.active_element_ptr_range())
903  {
904  // Get a reference to the ElementDefinition object
905  const ElementDefinition & eletype =
906  libmesh_map_find(_element_maps.out, elem->type());
907 
908  // The element mapper better not require any more nodes
909  // than are present in the current element!
910  libmesh_assert_less_equal (eletype.nodes.size(), elem->n_nodes());
911 
912  // elements ids are 1 based in Gmsh
913  out_stream << elem->id()+1 << " ";
914  // element type
915  out_stream << eletype.gmsh_type;
916 
917  // write the number of tags (3) and their values:
918  // 1 (physical entity)
919  // 2 (geometric entity)
920  // 3 (partition entity)
921  out_stream << " 3 "
922  << static_cast<unsigned int>(elem->subdomain_id())
923  << " 0 "
924  << elem->processor_id()+1
925  << " ";
926 
927  // if there is a node translation table, use it
928  if (eletype.nodes.size() > 0)
929  for (auto i : elem->node_index_range())
930  out_stream << elem->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
931  // otherwise keep the same node order
932  else
933  for (auto i : elem->node_index_range())
934  out_stream << elem->node_id(i)+1 << " "; // gmsh is 1-based
935  out_stream << "\n";
936  } // element loop
937  }
938 
939  {
940  // A counter for writing surface elements to the Gmsh file
941  // sequentially. We start numbering them with a number strictly
942  // larger than the largest element ID in the mesh. Note: the
943  // MeshBase docs say "greater than or equal to" the maximum
944  // element id in the mesh, so technically we might need a +1 here,
945  // but all of the implementations return an ID strictly greater
946  // than the largest element ID in the Mesh.
947  unsigned int e_id = mesh.max_elem_id();
948 
949  // loop over the elements, writing out boundary faces
950  if (n_boundary_faces)
951  {
952  // Build a list of (elem, side, bc) tuples.
953  auto bc_triples = mesh.get_boundary_info().build_side_list();
954 
955  // Loop over these lists, writing data to the file.
956  for (const auto & t : bc_triples)
957  {
958  const Elem & elem = mesh.elem_ref(std::get<0>(t));
959 
960  std::unique_ptr<const Elem> side = elem.build_side_ptr(std::get<1>(t));
961 
962  // consult the export element table
963  const GmshIO::ElementDefinition & eletype =
964  libmesh_map_find(_element_maps.out, side->type());
965 
966  // The element mapper better not require any more nodes
967  // than are present in the current element!
968  libmesh_assert_less_equal (eletype.nodes.size(), side->n_nodes());
969 
970  // elements ids are 1-based in Gmsh
971  out_stream << e_id+1 << " ";
972 
973  // element type
974  out_stream << eletype.gmsh_type;
975 
976  // write the number of tags:
977  // 1 (physical entity)
978  // 2 (geometric entity)
979  // 3 (partition entity)
980  out_stream << " 3 "
981  << std::get<2>(t)
982  << " 0 "
983  << elem.processor_id()+1
984  << " ";
985 
986  // if there is a node translation table, use it
987  if (eletype.nodes.size() > 0)
988  for (auto i : side->node_index_range())
989  out_stream << side->node_id(eletype.nodes[i])+1 << " "; // gmsh is 1-based
990 
991  // otherwise keep the same node order
992  else
993  for (auto i : side->node_index_range())
994  out_stream << side->node_id(i)+1 << " "; // gmsh is 1-based
995 
996  // Go to the next line
997  out_stream << "\n";
998 
999  // increment this index too...
1000  ++e_id;
1001  }
1002  }
1003 
1004  out_stream << "$EndElements\n";
1005  }
1006 }
const MT & mesh() const
Definition: mesh_output.h:259
std::size_t n_boundary_conds() const
virtual dof_id_type n_active_elem() const =0
bool & write_lower_dimensional_elements()
Access to the flag which controls whether boundary elements are written to the Mesh file...
Definition: gmsh_io.C:141
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=false)=0
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:159
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
Creates a list of element numbers, sides, and ids for those sides.
std::map< ElemType, ElementDefinition > out
Definition: gmsh_io.h:192
dof_id_type id() const
Definition: dof_object.h:823
virtual dof_id_type max_elem_id() const =0
libmesh_assert(ctx)
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:618
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...
Definition: int_range.h:134
static ElementMaps _element_maps
A static ElementMaps object that is built statically and used by all instances of this class...
Definition: gmsh_io.h:200
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:575
virtual dof_id_type n_nodes() const =0

◆ write_nodal_data() [1/3]

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 852 of file gmsh_io.C.

References write_post().

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

855 {
856  LOG_SCOPE("write_nodal_data()", "GmshIO");
857 
858  if (MeshOutput<MeshBase>::mesh().processor_id() == 0)
859  this->write_post (fname, &soln, &names);
860 }
const MeshBase & mesh() const
Definition: mesh_output.h:259
void write_post(const std::string &, const std::vector< Number > *=nullptr, const std::vector< std::string > *=nullptr)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: gmsh_io.C:1010

◆ write_nodal_data() [2/3]

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 may 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 149 of file mesh_output.C.

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

152 {
153  // This is the fallback implementation for parallel I/O formats that
154  // do not yet implement proper writing in parallel, and instead rely
155  // on the full solution vector being available on all processors.
156  std::vector<Number> soln;
157  parallel_soln.localize(soln);
158  this->write_nodal_data(fname, soln, names);
159 }
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: mesh_output.h:109
virtual void localize(std::vector< T > &v_local) const =0
Creates a copy of the global vector in the local vector v_local.

◆ write_nodal_data() [3/3]

void libMesh::MeshOutput< MeshBase >::write_nodal_data ( const std::string &  fname,
const EquationSystems es,
const std::set< std::string > *  system_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 directly uses EquationSystems current_local_solution vectors to look up nodal values.

If not implemented, reorders the solutions into a nodal-only NumericVector and calls the above version of this function.

Reimplemented in libMesh::Nemesis_IO.

Definition at line 162 of file mesh_output.C.

References libMesh::EquationSystems::build_parallel_solution_vector(), and libMesh::EquationSystems::build_variable_names().

165 {
166  std::vector<std::string> names;
167  es.build_variable_names (names, nullptr, system_names);
168 
169  std::unique_ptr<NumericVector<Number>> parallel_soln =
170  es.build_parallel_solution_vector(system_names);
171 
172  this->write_nodal_data (fname, *parallel_soln, names);
173 }
virtual void write_nodal_data(const std::string &, const std::vector< Number > &, const std::vector< std::string > &)
This method implements writing a mesh with nodal data to a specified file where the nodal data and va...
Definition: mesh_output.h:109

◆ 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 118 of file mesh_output.h.

121  { 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 1010 of file gmsh_io.C.

References binary(), libMesh::EDGE2, libMesh::EDGE3, libMesh::EDGE4, libMesh::Utility::enum_to_string(), 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().

1013 {
1014 
1015  // Should only do this on processor 0!
1016  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
1017 
1018  // Create an output stream
1019  std::ofstream out_stream(fname.c_str());
1020 
1021  // Make sure it opened correctly
1022  if (!out_stream.good())
1023  libmesh_file_error(fname.c_str());
1024 
1025  // create a character buffer
1026  char buf[80];
1027 
1028  // Get a constant reference to the mesh.
1029  const MeshBase & mesh = MeshOutput<MeshBase>::mesh();
1030 
1031  // write the data
1032  if ((solution_names != nullptr) && (v != nullptr))
1033  {
1034  const unsigned int n_vars =
1035  cast_int<unsigned int>(solution_names->size());
1036 
1037  if (!(v->size() == mesh.n_nodes()*n_vars))
1038  libMesh::err << "ERROR: v->size()=" << v->size()
1039  << ", mesh.n_nodes()=" << mesh.n_nodes()
1040  << ", n_vars=" << n_vars
1041  << ", mesh.n_nodes()*n_vars=" << mesh.n_nodes()*n_vars
1042  << "\n";
1043 
1044  libmesh_assert_equal_to (v->size(), mesh.n_nodes()*n_vars);
1045 
1046  // write the header
1047  out_stream << "$PostFormat\n";
1048  if (this->binary())
1049  out_stream << "1.2 1 " << sizeof(double) << "\n";
1050  else
1051  out_stream << "1.2 0 " << sizeof(double) << "\n";
1052  out_stream << "$EndPostFormat\n";
1053 
1054  // Loop over the elements to see how much of each type there are
1055  unsigned int n_points=0, n_lines=0, n_triangles=0, n_quadrangles=0,
1056  n_tetrahedra=0, n_hexahedra=0, n_prisms=0, n_pyramids=0;
1057  unsigned int n_scalar=0, n_vector=0, n_tensor=0;
1058  unsigned int nb_text2d=0, nb_text2d_chars=0, nb_text3d=0, nb_text3d_chars=0;
1059 
1060  {
1061  for (const auto & elem : mesh.active_element_ptr_range())
1062  {
1063  const ElemType elemtype = elem->type();
1064 
1065  switch (elemtype)
1066  {
1067  case EDGE2:
1068  case EDGE3:
1069  case EDGE4:
1070  {
1071  n_lines += 1;
1072  break;
1073  }
1074  case TRI3:
1075  case TRI6:
1076  {
1077  n_triangles += 1;
1078  break;
1079  }
1080  case QUAD4:
1081  case QUAD8:
1082  case QUAD9:
1083  {
1084  n_quadrangles += 1;
1085  break;
1086  }
1087  case TET4:
1088  case TET10:
1089  {
1090  n_tetrahedra += 1;
1091  break;
1092  }
1093  case HEX8:
1094  case HEX20:
1095  case HEX27:
1096  {
1097  n_hexahedra += 1;
1098  break;
1099  }
1100  case PRISM6:
1101  case PRISM15:
1102  case PRISM18:
1103  {
1104  n_prisms += 1;
1105  break;
1106  }
1107  case PYRAMID5:
1108  {
1109  n_pyramids += 1;
1110  break;
1111  }
1112  default:
1113  libmesh_error_msg("ERROR: Nonexistent element type " << Utility::enum_to_string(elem->type()));
1114  }
1115  }
1116  }
1117 
1118  // create a view for each variable
1119  for (unsigned int ivar=0; ivar < n_vars; ivar++)
1120  {
1121  std::string varname = (*solution_names)[ivar];
1122 
1123  // at the moment, we just write out scalar quantities
1124  // later this should be made configurable through
1125  // options to the writer class
1126  n_scalar = 1;
1127 
1128  // write the variable as a view, and the number of time steps
1129  out_stream << "$View\n" << varname << " " << 1 << "\n";
1130 
1131  // write how many of each geometry type are written
1132  out_stream << n_points * n_scalar << " "
1133  << n_points * n_vector << " "
1134  << n_points * n_tensor << " "
1135  << n_lines * n_scalar << " "
1136  << n_lines * n_vector << " "
1137  << n_lines * n_tensor << " "
1138  << n_triangles * n_scalar << " "
1139  << n_triangles * n_vector << " "
1140  << n_triangles * n_tensor << " "
1141  << n_quadrangles * n_scalar << " "
1142  << n_quadrangles * n_vector << " "
1143  << n_quadrangles * n_tensor << " "
1144  << n_tetrahedra * n_scalar << " "
1145  << n_tetrahedra * n_vector << " "
1146  << n_tetrahedra * n_tensor << " "
1147  << n_hexahedra * n_scalar << " "
1148  << n_hexahedra * n_vector << " "
1149  << n_hexahedra * n_tensor << " "
1150  << n_prisms * n_scalar << " "
1151  << n_prisms * n_vector << " "
1152  << n_prisms * n_tensor << " "
1153  << n_pyramids * n_scalar << " "
1154  << n_pyramids * n_vector << " "
1155  << n_pyramids * n_tensor << " "
1156  << nb_text2d << " "
1157  << nb_text2d_chars << " "
1158  << nb_text3d << " "
1159  << nb_text3d_chars << "\n";
1160 
1161  // if binary, write a marker to identify the endianness of the file
1162  if (this->binary())
1163  {
1164  const int one = 1;
1165  std::memcpy(buf, &one, sizeof(int));
1166  out_stream.write(buf, sizeof(int));
1167  }
1168 
1169  // the time steps (there is just 1 at the moment)
1170  if (this->binary())
1171  {
1172  double one = 1;
1173  std::memcpy(buf, &one, sizeof(double));
1174  out_stream.write(buf, sizeof(double));
1175  }
1176  else
1177  out_stream << "1\n";
1178 
1179  // Loop over the elements and write out the data
1180  for (const auto & elem : mesh.active_element_ptr_range())
1181  {
1182  const unsigned int nv = elem->n_vertices();
1183  // this is quite crappy, but I did not invent that file format!
1184  for (unsigned int d=0; d<3; d++) // loop over the dimensions
1185  {
1186  for (unsigned int n=0; n < nv; n++) // loop over vertices
1187  {
1188  const Point & vertex = elem->point(n);
1189  if (this->binary())
1190  {
1191 #if defined(LIBMESH_DEFAULT_TRIPLE_PRECISION) || defined(LIBMESH_DEFAULT_QUADRUPLE_PRECISION)
1192  libmesh_warning("Gmsh binary writes use only double precision!");
1193 #endif
1194  double tmp = double(vertex(d));
1195  std::memcpy(buf, &tmp, sizeof(double));
1196  out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
1197  }
1198  else
1199  out_stream << vertex(d) << " ";
1200  }
1201  if (!this->binary())
1202  out_stream << "\n";
1203  }
1204 
1205  // now finally write out the data
1206  for (unsigned int i=0; i < nv; i++) // loop over vertices
1207  if (this->binary())
1208  {
1209 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1210  libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1211  << "complex numbers. Will only write the real part of "
1212  << "variable " << varname << std::endl;
1213 #endif
1214  double tmp = double(libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]));
1215  std::memcpy(buf, &tmp, sizeof(double));
1216  out_stream.write(reinterpret_cast<char *>(buf), sizeof(double));
1217  }
1218  else
1219  {
1220 #ifdef LIBMESH_USE_COMPLEX_NUMBERS
1221  libMesh::out << "WARNING: Gmsh::write_post does not fully support "
1222  << "complex numbers. Will only write the real part of "
1223  << "variable " << varname << std::endl;
1224 #endif
1225  out_stream << libmesh_real((*v)[elem->node_id(i)*n_vars + ivar]) << "\n";
1226  }
1227  }
1228  if (this->binary())
1229  out_stream << "\n";
1230  out_stream << "$EndView\n";
1231 
1232  } // end variable loop (writing the views)
1233  }
1234 }
T libmesh_real(T a)
OStreamProxy err
const MeshBase & mesh() const
Definition: mesh_output.h:259
ElemType
Defines an enum for geometric element types.
bool & binary()
Flag indicating whether or not to write a binary file.
Definition: gmsh_io.C:134
unsigned int n_vars
std::string enum_to_string(const T e)
OStreamProxy out
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 149 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 200 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 184 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 193 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 155 of file gmsh_io.h.

Referenced by write_lower_dimensional_elements().

◆ elems_of_dimension

std::vector<bool> libMesh::MeshInput< MeshBase >::elems_of_dimension
protectedinherited

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