libMesh
Public Member Functions | Protected Member Functions | Protected Attributes | Private Member Functions | Private Attributes | List of all members
libMesh::STLIO Class Reference

This class implements reading and writing triangle meshes in the STL format. More...

#include <stl_io.h>

Inheritance diagram for libMesh::STLIO:
[legend]

Public Member Functions

 STLIO (const MeshBase &)
 Constructor. More...
 
 STLIO (MeshBase &)
 Constructor. More...
 
virtual void write (const std::string &) override
 This method implements writing a mesh to a specified file. More...
 
virtual void read (const std::string &mesh_file) override
 This method implements reading a mesh from a specified file. More...
 
virtual void read_ascii (std::istream &input)
 This method implements reading a mesh from a specified ASCII input stream. More...
 
virtual void read_binary (std::istream &input, std::size_t input_size=0)
 This method implements reading a mesh from a specified binary input stream. More...
 
const std::string & name ()
 This method gets a name after a set or an ASCII read. More...
 
virtual void set_name (const std::string &name)
 This method sets a name to write. More...
 
bool subdivide_second_order ()
 Flag indicating whether or not to subdivide second order elements when writing. More...
 
void set_subdivide_second_order (bool subdivide)
 
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 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 variable names are provided. 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

std::unique_ptr< std::istream > open_file (const std::string &filename)
 Helper to open possibly-zipped files. More...
 

Private Attributes

bool _subdivide_second_order
 Flag to subdivide second order elements. More...
 
std::string _name
 

Detailed Description

This class implements reading and writing triangle meshes in the STL format.

Author
Roy H. Stogner
Date
2024

Definition at line 45 of file stl_io.h.

Constructor & Destructor Documentation

◆ STLIO() [1/2]

libMesh::STLIO::STLIO ( 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 64 of file stl_io.C.

64  :
67 {
68 }
template class LIBMESH_EXPORT MeshOutput< MeshBase >
Definition: mesh_output.C:180
bool _subdivide_second_order
Flag to subdivide second order elements.
Definition: stl_io.h:120

◆ STLIO() [2/2]

libMesh::STLIO::STLIO ( MeshBase mesh)
explicit

Constructor.

Takes a writable reference to a mesh object. This constructor is required to let us read in a mesh.

Definition at line 72 of file stl_io.C.

72  :
73  MeshInput<MeshBase> (mesh),
76 {
77 }
template class LIBMESH_EXPORT MeshOutput< MeshBase >
Definition: mesh_output.C:180
bool _subdivide_second_order
Flag to subdivide second order elements.
Definition: stl_io.h:120

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(), 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

◆ 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(), read(), libMesh::Nemesis_IO::read(), libMesh::XdrIO::read(), libMesh::ExodusII_IO::read(), libMesh::CheckpointIO::read(), libMesh::VTKIO::read(), read_ascii(), libMesh::CheckpointIO::read_bcs(), read_binary(), 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(), libMesh::GmshIO::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(), write(), 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(), libMesh::GmshIO::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(), libMesh::GmshIO::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

◆ name()

const std::string& libMesh::STLIO::name ( )
inline

This method gets a name after a set or an ASCII read.

Definition at line 94 of file stl_io.h.

References _name.

Referenced by set_name().

94 { return _name; }
std::string _name
Definition: stl_io.h:122

◆ open_file()

std::unique_ptr< std::istream > libMesh::STLIO::open_file ( const std::string &  filename)
private

Helper to open possibly-zipped files.

Definition at line 223 of file stl_io.C.

References libMesh::Utility::ends_with(), libMesh::libmesh_assert(), and libMesh::Utility::unzip_file().

Referenced by read().

224 {
225  const bool gzipped_file = Utility::ends_with(filename, ".gz");
226 
227  std::unique_ptr<std::istream> file;
228 
229  if (gzipped_file)
230  {
231 #ifdef LIBMESH_HAVE_GZSTREAM
232  auto inf = std::make_unique<igzstream>();
233  libmesh_assert(inf);
234  inf->open(filename.c_str(), std::ios::in);
235  file = std::move(inf);
236 #else
237  libmesh_error_msg("ERROR: need gzstream to handle .gz files!!!");
238 #endif
239  }
240  else
241  {
242  auto inf = std::make_unique<std::ifstream>();
243  libmesh_assert(inf);
244 
245  std::string new_name = Utility::unzip_file(filename);
246 
247  inf->open(new_name.c_str(), std::ios::in);
248  file = std::move(inf);
249  }
250 
251  return file;
252 }
bool ends_with(std::string_view superstring, std::string_view suffix)
Look for a substring at the very end of a string.
Definition: utility.C:213
std::string unzip_file(std::string_view name)
Create an unzipped copy of a bz2 or xz file, returning the name of the now-unzipped file that can be ...
Definition: utility.C:164
libmesh_assert(ctx)

◆ read()

void libMesh::STLIO::read ( const std::string &  mesh_file)
overridevirtual

This method implements reading a mesh from a specified file.

Implements libMesh::MeshInput< MeshBase >.

Definition at line 165 of file stl_io.C.

References libMesh::MeshBase::clear(), libMesh::MeshInput< MT >::mesh(), libMesh::MeshInput< MeshBase >::mesh(), open_file(), read_ascii(), read_binary(), and libMesh::MeshBase::set_mesh_dimension().

Referenced by libMesh::NameBasedIO::read(), MeshInputTest::testGoodSTL(), and MeshInputTest::testGoodSTLBinary().

166 {
167  LOG_SCOPE("read()", "STLIO");
168 
169  // This is a serial-only process for now;
170  // the Mesh should be read on processor 0 and
171  // broadcast later
172  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
173 
174  // Clear the mesh so we are sure to start from a pristine state.
175  MeshBase & mesh = MeshInput<MeshBase>::mesh();
176  mesh.clear();
178 
179  std::unique_ptr<std::istream> fstream =
180  this->open_file(filename);
181 
182  char c;
183  const char * expected_header = "solid!";
184  bool is_ascii_stl = false,
185  is_binary_stl = false;
186  while (fstream->get(c))
187  {
188  if (c == ' ')
189  continue;
190  if (c == *expected_header)
191  {
192  ++expected_header;
193  if (*expected_header == '!')
194  {
195  is_ascii_stl = true;
196  break;
197  }
198  }
199  else
200  {
201  is_binary_stl = true; // probably
202  break;
203  }
204  }
205 
206  if (is_ascii_stl)
207  {
208  fstream->seekg(0);
209  this->read_ascii(*fstream);
210  }
211  else if (is_binary_stl)
212  {
213  fstream->seekg(0, std::ios_base::end);
214  std::size_t length = fstream->tellg();
215  fstream->seekg(0);
216  this->read_binary(*fstream, length);
217  }
218  else
219  libmesh_error_msg("Failed to read an STL header in " << filename);
220 }
const MeshBase & mesh() const
Definition: mesh_output.h:259
std::unique_ptr< std::istream > open_file(const std::string &filename)
Helper to open possibly-zipped files.
Definition: stl_io.C:223
virtual void read_ascii(std::istream &input)
This method implements reading a mesh from a specified ASCII input stream.
Definition: stl_io.C:256
void set_mesh_dimension(unsigned char d)
Resets the logical dimension of the mesh.
Definition: mesh_base.h:275
virtual void read_binary(std::istream &input, std::size_t input_size=0)
This method implements reading a mesh from a specified binary input stream.
Definition: stl_io.C:433
virtual void clear()
Deletes all the element and node data that is currently stored.
Definition: mesh_base.C:920

◆ read_ascii()

void libMesh::STLIO::read_ascii ( std::istream &  input)
virtual

This method implements reading a mesh from a specified ASCII input stream.

Definition at line 256 of file stl_io.C.

References _name, libMesh::MeshBase::add_point(), libMesh::libmesh_ignore(), libMesh::MeshInput< MT >::mesh(), and libMesh::MeshInput< MeshBase >::mesh().

Referenced by read().

257 {
258  LOG_SCOPE("read_ascii()", "STLIO");
259 
260 #ifndef LIBMESH_HAVE_CXX11_REGEX
261  libmesh_not_implemented(); // What is your compiler?!? Email us!
262  libmesh_ignore(file);
263 #else
264 
265  MeshBase & mesh = MeshInput<MeshBase>::mesh();
266 
267  const std::regex all_expected_chars
268  ("^[\\w\\d\\-\\.\\^\\$]*$");
269 
270  const std::regex start_regex
271  ("^\\s*solid");
272  const std::regex start_with_name_regex
273  ("^\\s*solid\\s+(\\w+)");
274 
275  const std::regex start_facet_regex
276  ("^\\s*facet");
277 
278  // We'll ignore facets' normals for now
279  /*
280  const std::regex facet_with_normal_regex
281  ("^\\s*facet\\s+normal"
282  "\\s+([+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)"
283  "\\s+[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)"
284  "\\s+[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?))");
285  */
286 
287  const std::regex start_loop_regex
288  ("^\\s*outer\\s+loop");
289 
290  const std::regex vertex_regex
291  ("^\\s*vertex"
292  "\\s+([+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)"
293  "\\s+[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?)"
294  "\\s+[+-]?(\\d+([.]\\d*)?([eE][+-]?\\d+)?|[.]\\d+([eE][+-]?\\d+)?))");
295 
296  const std::regex end_facet_regex
297  ("^\\s*end\\s*facet");
298 
299  const std::regex end_loop_regex
300  ("^\\s*end\\s*loop");
301 
302  bool have_started = false;
303  bool in_facet = false;
304  bool in_vertex_loop = false;
305  std::unique_ptr<Tri3> triangle;
306  int next_vertex = 0;
307  int line_num = 0;
308 
309  std::unordered_map<Point, Node *> mesh_points;
310 
311  for (std::string line; std::getline(file, line);)
312  {
313  ++line_num;
314  std::smatch sm;
315 
316  for (char & c : line)
317  {
318  libmesh_error_msg_if
319  (c != '\n' && c != '\r' &&
320  (c < ' ' || c > '~'),
321  "Found non-ASCII character " << int(c) << " on line " <<
322  line_num << "\nSTLIO does not yet support binary files.");
323  }
324 
325  if (std::regex_search(line, sm, start_regex))
326  {
327  if (std::regex_search(line, sm, start_with_name_regex))
328  this->_name = sm[1];
329  libmesh_error_msg_if
330  (have_started,
331  "Found two 'solid' lines starting the same STL file?");
332  have_started = true;
333  }
334 
335  else if (std::regex_search(line, sm, start_facet_regex))
336  {
337  libmesh_error_msg_if
338  (in_facet,
339  "Found a repeated 'facet' line with no 'endfacet' between them.");
340  in_facet = true;
341 
342  /*
343  if (std::regex_search(line, sm, facet_with_normal_regex))
344  {
345  const std::string normalvec = sm[1];
346 
347  // Try to be compatible with higher-than-double T; maybe
348  // *someone* out there is doing STL in 128 bits? ...
349  std::stringstream ss(normalvec);
350  ss >> normal(0);
351  ss >> normal(1);
352  ss >> normal(2);
353  }
354  */
355  }
356 
357  else if (std::regex_search(line, end_facet_regex))
358  {
359  libmesh_error_msg_if
360  (!in_facet,
361  "Found an 'endfacet' line with no matching 'facet'.");
362  in_facet = false;
363  }
364 
365  else if (std::regex_search(line, start_loop_regex))
366  {
367  libmesh_error_msg_if
368  (!in_facet,
369  "Found an 'outer loop' line with no matching 'facet'.");
370  libmesh_error_msg_if
371  (in_vertex_loop,
372  "Found a repeated 'outer loop' line with no 'endloop' between them.");
373  in_vertex_loop = true;
374  triangle = std::make_unique<Tri3>();
375  next_vertex = 0;
376  }
377 
378  else if (std::regex_search(line, sm, vertex_regex))
379  {
380  const std::string normalvec = sm[1];
381 
382  // Try to be compatible with higher-than-double-precision T;
383  // maybe *someone* out there is doing STL in 128 bits? ...
384  std::stringstream ss(normalvec);
385  Point p;
386  ss >> p(0);
387  ss >> p(1);
388  ss >> p(2);
389 
390  Node * node;
391  if (auto it = mesh_points.find(p); it != mesh_points.end())
392  {
393  node = it->second;
394  }
395  else
396  {
397  node = mesh.add_point(p);
398  mesh_points[p] = node;
399  }
400 
401  libmesh_error_msg_if
402  (next_vertex > 2,
403  "Found more than 3 vertices in a loop; STLIO only supports Tri3.");
404  triangle->set_node(next_vertex++, node);
405  }
406 
407  else if (std::regex_search(line, end_loop_regex))
408  {
409  libmesh_error_msg_if
410  (next_vertex != 3,
411  "Found an 'endloop' line after only seeing " << next_vertex << " vertices in 'loop'.");
412  libmesh_error_msg_if
413  (!in_vertex_loop,
414  "Found an 'endloop' line with no matching 'loop'.");
415  in_vertex_loop = false;
416 
417  test_and_add(std::move(triangle), mesh);
418  }
419  }
420 
421  libmesh_error_msg_if
422  (in_facet,
423  "File ended without ending a facet first.");
424 
425  libmesh_error_msg_if
426  (in_vertex_loop,
427  "File ended without ending an outer loop first.");
428 #endif // LIBMESH_HAVE_CXX11_REGEX
429 }
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 libmesh_ignore(const Args &...)
std::string _name
Definition: stl_io.h:122

◆ read_binary()

void libMesh::STLIO::read_binary ( std::istream &  input,
std::size_t  input_size = 0 
)
virtual

This method implements reading a mesh from a specified binary input stream.

If the size in bytes is known a priori then it can be passed in to allow for additional error checking.

Definition at line 433 of file stl_io.C.

References libMesh::MeshBase::add_point(), libMesh::libmesh_ignore(), libMesh::make_range(), libMesh::MeshInput< MT >::mesh(), libMesh::MeshInput< MeshBase >::mesh(), and libMesh::MeshTools::n_elem().

Referenced by read().

435 {
436  LOG_SCOPE("read_binary()", "STLIO");
437 
438  MeshBase & mesh = MeshInput<MeshBase>::mesh();
439 
440  char header_buffer[80];
441 
442  // 80-character header which is generally ignored - Wikipedia
443  file.read(header_buffer, 80);
444 
445  // What's our endianness here? Input binary files are specified to
446  // be little endian, and we might need to do conversions.
447 
448  uint32_t test_int = 0x87654321;
449  const bool big_endian = ((*reinterpret_cast<char *>(&test_int)) != 0x21);
450  const Utility::ReverseBytes endian_fix{big_endian};
451 
452  // C++ doesn't specify a size for float, but we really need 4-byte
453  // floats here. Fortunately basically every implementation ever
454  // uses exactly 4 bytes for float.
455  if constexpr (sizeof(float) != 4)
456  libmesh_error_msg("Trying to read 4 byte floats without 4-byte float?");
457 
458  uint32_t n_elem = 0;
459 
460  file.read(reinterpret_cast<char*>(&n_elem), 4);
461  endian_fix(n_elem);
462 
463  libmesh_error_msg_if
464  (input_size &&
465  (input_size < 84+n_elem*50),
466  "Not enough data for " << n_elem << " STL triangles in " <<
467  input_size << " uncompressed bytes.");
468 
469  std::unique_ptr<Tri3> triangle;
470  std::unordered_map<Point, Node *> mesh_points;
471 
472  for (unsigned int e : make_range(n_elem))
473  {
474  libmesh_ignore(e);
475 
476  triangle = std::make_unique<Tri3>();
477 
478  // We'll ignore facets' normals for now
479  char ignored_buffer[12];
480  file.read(ignored_buffer, 12);
481 
482  // Read vertex locations
483  for (int i : make_range(3))
484  {
485  float point_buffer[3];
486  file.read(reinterpret_cast<char*>(point_buffer), 12);
487  endian_fix(point_buffer[0]);
488  endian_fix(point_buffer[1]);
489  endian_fix(point_buffer[2]);
490  const Point p {point_buffer[0],
491  point_buffer[1],
492  point_buffer[2]};
493 
494  Node * node;
495  if (auto it = mesh_points.find(p); it != mesh_points.end())
496  {
497  node = it->second;
498  }
499  else
500  {
501  node = mesh.add_point(p);
502  mesh_points[p] = node;
503  }
504 
505  triangle->set_node(i, node);
506  }
507 
508  // The 2-byte "attribute byte count" is unstandardized; typically
509  // 0, or sometimes triangle color. Ignore it.
510  file.read(ignored_buffer, 2);
511 
512  test_and_add(std::move(triangle), mesh);
513  }
514 }
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:969
virtual void read(const std::string &mesh_file) override
This method implements reading a mesh from a specified file.
Definition: stl_io.C:165
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 libmesh_ignore(const Args &...)
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:140

◆ 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:1871

◆ set_name()

virtual void libMesh::STLIO::set_name ( const std::string &  name)
inlinevirtual

This method sets a name to write.

Definition at line 99 of file stl_io.h.

References _name, and name().

99 { _name = name; }
std::string _name
Definition: stl_io.h:122
const std::string & name()
This method gets a name after a set or an ASCII read.
Definition: stl_io.h:94

◆ set_subdivide_second_order()

void libMesh::STLIO::set_subdivide_second_order ( bool  subdivide)
inline

Definition at line 107 of file stl_io.h.

References _subdivide_second_order.

108  { _subdivide_second_order = subdivide; }
bool _subdivide_second_order
Flag to subdivide second order elements.
Definition: stl_io.h:120

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

◆ subdivide_second_order()

bool libMesh::STLIO::subdivide_second_order ( )
inline

Flag indicating whether or not to subdivide second order elements when writing.

This option is not yet supported.

Definition at line 105 of file stl_io.h.

References _subdivide_second_order.

105 { return _subdivide_second_order; }
bool _subdivide_second_order
Flag to subdivide second order elements.
Definition: stl_io.h:120

◆ write()

void libMesh::STLIO::write ( const std::string &  fname)
overridevirtual

This method implements writing a mesh to a specified file.

We currently only support ASCII writes.

Implements libMesh::MeshOutput< MeshBase >.

Definition at line 81 of file stl_io.C.

References _name, _subdivide_second_order, libMesh::MeshOutput< MeshBase >::ascii_precision(), libMesh::ParallelObject::comm(), libMesh::MeshBase::is_serial(), libMesh::MeshInput< MeshBase >::mesh(), libMesh::MeshOutput< MT >::mesh(), libMesh::ParallelObject::processor_id(), libMesh::TRI3, libMesh::TRI6, and libMesh::TRI7.

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

82 {
83  LOG_SCOPE("write()", "STLIO");
84 
85  // Get a reference to the mesh
86  const MeshBase * mesh_ptr = &MeshOutput<MeshBase>::mesh();
87 
88  libmesh_parallel_only(mesh_ptr->comm());
89 
90  // If necessary, serialize to proc 0, which will do all the writing
91  std::unique_ptr<DistributedMesh> mesh_copy;
92  std::unique_ptr<MeshSerializer> serializer;
93  if (!mesh_ptr->is_serial())
94  {
95  mesh_copy = std::make_unique<DistributedMesh>(*mesh_ptr);
96  mesh_ptr = mesh_copy.get();
97  serializer = std::make_unique<MeshSerializer>(*mesh_copy, true, true);
98  }
99 
100  const MeshBase & mesh = *mesh_ptr;
101 
102  if (mesh.processor_id() != 0)
103  return;
104 
105  // Open the output file stream
106  std::ofstream out_stream (fname.c_str());
107 
108  out_stream << std::setprecision(this->ascii_precision());
109 
110  // Make sure it opened correctly
111  if (!out_stream.good())
112  libmesh_file_error(fname.c_str());
113 
114  // Write the header
115  out_stream << "solid " << this->_name << '\n';
116 
117  // Write all our triangles
118  // scream if we see a non-triangle
119  for (auto elem : mesh.element_ptr_range())
120  {
121  // Get to this later
122  if (elem->type() == TRI6 || elem->type() == TRI7)
123  {
124  if (this->_subdivide_second_order)
125  libmesh_not_implemented();
126 
127  libmesh_error_msg("Tried to write a non-linear triangle to an STL file");
128  }
129 
130  libmesh_error_msg_if(elem->type() != TRI3,
131  "Tried to write a non-triangle to an STL file");
132 
133  auto n = (elem->point(1)-elem->point(0)).cross(elem->point(2)-elem->point(0));
134 
135  // Other STL files have slivers, I guess ours can too
136  if (auto length = n.norm())
137  n /= length;
138 
139  out_stream << "facet normal " <<
140  n(0) << ' ' <<
141  n(1) << ' ' <<
142  n(2) << "\n"
143  " outer loop\n"
144  " vertex " <<
145  elem->point(0)(0) << ' ' <<
146  elem->point(0)(1) << ' ' <<
147  elem->point(0)(2) << "\n"
148  " vertex " <<
149  elem->point(1)(0) << ' ' <<
150  elem->point(1)(1) << ' ' <<
151  elem->point(1)(2) << "\n"
152  " vertex " <<
153  elem->point(2)(0) << ' ' <<
154  elem->point(2)(1) << ' ' <<
155  elem->point(2)(2) << "\n"
156  " endloop\n"
157  "endfacet\n";
158  }
159 
160  out_stream << "endsolid" << std::endl;
161 }
const MT & mesh() const
Definition: mesh_output.h:259
unsigned int & ascii_precision()
Return/set the precision to use when writing ASCII files.
Definition: mesh_output.h:269
bool _subdivide_second_order
Flag to subdivide second order elements.
Definition: stl_io.h:120
std::string _name
Definition: stl_io.h:122
processor_id_type processor_id() const

◆ 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::ExodusII_IO, and 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().

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_nodal_data() [1/3]

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

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

Reimplemented in libMesh::ExodusII_IO, libMesh::Nemesis_IO, libMesh::GmshIO, libMesh::NameBasedIO, libMesh::VTKIO, libMesh::UCDIO, libMesh::GMVIO, libMesh::MEDITIO, libMesh::GnuPlotIO, and libMesh::TecplotIO.

Definition at line 109 of file mesh_output.h.

112  { libmesh_not_implemented(); }

◆ 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(); }

Member Data Documentation

◆ _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().

◆ _name

std::string libMesh::STLIO::_name
private

Definition at line 122 of file stl_io.h.

Referenced by name(), read_ascii(), set_name(), and 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.

◆ _subdivide_second_order

bool libMesh::STLIO::_subdivide_second_order
private

Flag to subdivide second order elements.

Definition at line 120 of file stl_io.h.

Referenced by set_subdivide_second_order(), subdivide_second_order(), and write().

◆ elems_of_dimension

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

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