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::basename_of(), libMesh::libmesh_assert(), and libMesh::Utility::unzip_file().

Referenced by read().

224 {
225  std::string_view basename = Utility::basename_of(filename);
226  const bool gzipped_file = (basename.rfind(".gz") == basename.size() - 3);
227 
228  std::unique_ptr<std::istream> file;
229 
230  if (gzipped_file)
231  {
232 #ifdef LIBMESH_HAVE_GZSTREAM
233  auto inf = std::make_unique<igzstream>();
234  libmesh_assert(inf);
235  inf->open(filename.c_str(), std::ios::in);
236  file = std::move(inf);
237 #else
238  libmesh_error_msg("ERROR: need gzstream to handle .gz files!!!");
239 #endif
240  }
241  else
242  {
243  auto inf = std::make_unique<std::ifstream>();
244  libmesh_assert(inf);
245 
246  std::string new_name = Utility::unzip_file(filename);
247 
248  inf->open(new_name.c_str(), std::ios::in);
249  file = std::move(inf);
250  }
251 
252  return file;
253 }
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)
std::string_view basename_of(const std::string &fullname)
Definition: utility.C:108

◆ 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:257
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:434
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 257 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().

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

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

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