libMesh
tetgen_io.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 // Local includes
20 #include "libmesh/tetgen_io.h"
21 #include "libmesh/mesh_base.h"
22 #include "libmesh/cell_tet4.h"
23 #include "libmesh/cell_tet10.h"
24 
25 // C++ includes
26 #include <array>
27 #include <fstream>
28 
29 namespace libMesh
30 {
31 
32 // ------------------------------------------------------------
33 // TetgenIO class members
34 void TetGenIO::read (const std::string & name)
35 {
36  // This is a serial-only process for now;
37  // the Mesh should be read on processor 0 and
38  // broadcast later
39  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().processor_id(), 0);
40 
41  std::string name_node, name_ele, dummy;
42 
43  // tetgen only works in 3D
44  MeshInput<MeshBase>::mesh().set_mesh_dimension(3);
45 
46 #if LIBMESH_DIM < 3
47  libmesh_error_msg("Cannot open dimension 3 mesh file when configured without 3D support.");
48 #endif
49 
50  // Check name for *.node or *.ele extension.
51  // Set std::istream for node_stream and ele_stream.
52  //
53  if (name.rfind(".node") < name.size())
54  {
55  name_node = name;
56  dummy = name;
57  std::size_t position = dummy.rfind(".node");
58  name_ele = dummy.replace(position, 5, ".ele");
59  }
60  else if (name.rfind(".ele") < name.size())
61  {
62  name_ele = name;
63  dummy = name;
64  std::size_t position = dummy.rfind(".ele");
65  name_node = dummy.replace(position, 4, ".node");
66  }
67  else
68  libmesh_error_msg("ERROR: Unrecognized file name: " << name);
69 
70 
71 
72  // Set the streams from which to read in
73  std::ifstream node_stream (name_node.c_str());
74  std::ifstream ele_stream (name_ele.c_str());
75 
76  if (!node_stream.good() || !ele_stream.good())
77  libmesh_error_msg("Error while opening either " \
78  << name_node \
79  << " or " \
80  << name_ele);
81 
82  libMesh::out<< "TetGenIO found the tetgen files to read " <<std::endl;
83 
84  // Skip the comment lines at the beginning
85  this->skip_comment_lines (node_stream, '#');
86  this->skip_comment_lines (ele_stream, '#');
87 
88  // Read the nodes and elements from the streams
89  this->read_nodes_and_elem (node_stream, ele_stream);
90  libMesh::out<< "TetGenIO read in nodes and elements " <<std::endl;
91 }
92 
93 
94 
95 void TetGenIO::read_nodes_and_elem (std::istream & node_stream,
96  std::istream & ele_stream)
97 {
98  _num_nodes = 0;
99  _num_elements = 0;
100 
101  // Read all the datasets.
102  this->node_in (node_stream);
103  this->element_in (ele_stream);
104 
105  // some more clean-up
106  _assign_nodes.clear();
107 }
108 
109 
110 
111 //----------------------------------------------------------------------
112 // Function to read in the node table.
113 void TetGenIO::node_in (std::istream & node_stream)
114 {
115  // Check input buffer
116  libmesh_assert (node_stream.good());
117 
118  // Get a reference to the mesh
120 
121  unsigned int dimension=0, nAttributes=0, BoundaryMarkers=0;
122 
123  node_stream >> _num_nodes // Read the number of nodes from the stream
124  >> dimension // Read the dimension from the stream
125  >> nAttributes // Read the number of attributes from stream
126  >> BoundaryMarkers; // Read if or not boundary markers are included in *.node (0 or 1)
127 
128  // Read the nodal coordinates from the node_stream (*.node file).
129  unsigned int node_lab=0;
130  Real dummy;
131 
132  // If present, make room for node attributes to be stored.
133  this->node_attributes.resize(nAttributes);
134  for (unsigned i=0; i<nAttributes; ++i)
135  this->node_attributes[i].resize(_num_nodes);
136 
137 
138  for (unsigned int i=0; i<_num_nodes; i++)
139  {
140  // Check input buffer
141  libmesh_assert (node_stream.good());
142 
143  std::array<Real, 3> xyz;
144 
145  node_stream >> node_lab // node number
146  >> xyz[0] // x-coordinate value
147  >> xyz[1] // y-coordinate value
148  >> xyz[2]; // z-coordinate value
149 
150  // Read and store attributes from the stream.
151  for (unsigned int j=0; j<nAttributes; j++)
152  node_stream >> node_attributes[j][i];
153 
154  // Read (and discard) boundary marker if BoundaryMarker=1.
155  // TODO: should we store this somehow?
156  if (BoundaryMarkers == 1)
157  node_stream >> dummy;
158 
159  // Store the new position of the node under its label.
160  //_assign_nodes.insert (std::make_pair(node_lab,i));
161  _assign_nodes[node_lab] = i;
162 
163  Point p(xyz[0]);
164 #if LIBMESH_DIM > 1
165  p(1) = xyz[1];
166 #else
167  libmesh_assert_equal_to(xyz[1], 0);
168 #endif
169 #if LIBMESH_DIM > 2
170  p(2) = xyz[2];
171 #else
172  libmesh_assert_equal_to(xyz[2], 0);
173 #endif
174 
175  // Add this point to the Mesh.
176  mesh.add_point(p, i);
177  }
178 }
179 
180 
181 
182 //----------------------------------------------------------------------
183 // Function to read in the element table.
184 void TetGenIO::element_in (std::istream & ele_stream)
185 {
186  // Check input buffer
187  libmesh_assert (ele_stream.good());
188 
189  // Get a reference to the mesh
191 
192  // Read the elements from the ele_stream (*.ele file).
193  unsigned int element_lab=0, n_nodes=0, region_attribute=0;
194 
195  ele_stream >> _num_elements // Read the number of tetrahedrons from the stream.
196  >> n_nodes // Read the number of nodes per tetrahedron from the stream (defaults to 4).
197  >> region_attribute; // Read the number of attributes from stream.
198 
199  // According to the Tetgen docs for .ele files:
200  // http://wias-berlin.de/software/tetgen/1.5/doc/manual/manual006.html#ff_ele
201  // region_attribute can either 0 or 1, and specifies whether, for
202  // each tetrahedron, there is an extra integer specifying which
203  // region it belongs to. Normally, this id matches a value in a
204  // corresponding .poly or .smesh file, but here we simply use it to
205  // set the subdomain_id of the element in question.
206  if (region_attribute > 1)
207  libmesh_error_msg("Invalid region_attribute " << region_attribute << " specified in .ele file.");
208 
209  // Vector that assigns element nodes to their correct position.
210  // TetGen is normally 0-based
211  // (right now this is strictly not necessary since it is the identity map,
212  // but in the future TetGen could change their numbering scheme.)
213  static const unsigned int assign_elm_nodes[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
214 
215  for (dof_id_type i=0; i<_num_elements; i++)
216  {
217  libmesh_assert (ele_stream.good());
218 
219  // TetGen only supports Tet4 and Tet10 elements.
220  Elem * elem;
221 
222  if (n_nodes==4)
223  elem = new Tet4;
224 
225  else if (n_nodes==10)
226  elem = new Tet10;
227 
228  else
229  libmesh_error_msg("Elements with " << n_nodes << " nodes are not supported in the LibMesh tetgen module.");
230 
231  elem->set_id(i);
232 
233  mesh.add_elem (elem);
234 
235  libmesh_assert(elem);
236  libmesh_assert_equal_to (elem->n_nodes(), n_nodes);
237 
238  // The first number on the line is the tetrahedron number. We
239  // have previously ignored this, preferring to set our own ids,
240  // but this could be changed to respect the Tetgen numbering if
241  // desired.
242  ele_stream >> element_lab;
243 
244  // Read node labels
245  for (dof_id_type j=0; j<n_nodes; j++)
246  {
247  dof_id_type node_label;
248  ele_stream >> node_label;
249 
250  // Assign node to element
251  elem->set_node(assign_elm_nodes[j]) =
252  mesh.node_ptr(_assign_nodes[node_label]);
253  }
254 
255  // Read the region attribute (if present) and use it to set the subdomain id.
256  if (region_attribute)
257  {
258  unsigned int region;
259  ele_stream >> region;
260 
261  // Make sure that the id we read can be successfully cast to
262  // an integral value of type subdomain_id_type.
263  elem->subdomain_id() = cast_int<subdomain_id_type>(region);
264  }
265  }
266 }
267 
268 
273 void TetGenIO::write (const std::string & fname)
274 {
275  // libmesh_assert three dimensions (should be extended later)
276  libmesh_assert_equal_to (MeshOutput<MeshBase>::mesh().mesh_dimension(), 3);
277 
278  if (!(fname.rfind(".poly") < fname.size()))
279  libmesh_error_msg("ERROR: Unrecognized file name: " << fname);
280 
281  // Open the output file stream
282  std::ofstream out_stream (fname.c_str());
283 
284  // Make sure it opened correctly
285  if (!out_stream.good())
286  libmesh_file_error(fname.c_str());
287 
288  // Get a reference to the mesh
290 
291  // Begin interfacing with the .poly file
292  {
293  // header:
294  out_stream << "# poly file output generated by libmesh\n"
295  << mesh.n_nodes() << " 3 0 0\n";
296 
297  // write the nodes:
298  for (auto v : IntRange<dof_id_type>(0, mesh.n_nodes()))
299  out_stream << v << " "
300  << mesh.point(v)(0) << " "
301  << mesh.point(v)(1) << " "
302  << mesh.point(v)(2) << "\n";
303  }
304 
305  {
306  // write the connectivity:
307  out_stream << "# Facets:\n"
308  << mesh.n_elem() << " 0\n";
309 
310  for (const auto & elem : mesh.active_element_ptr_range())
311  out_stream << "1\n3 " // no. of facet polygons
312  // << elem->n_nodes() << " "
313  << elem->node_id(0) << " "
314  << elem->node_id(1) << " "
315  << elem->node_id(2) << "\n";
316  }
317 
318  // end of the file
319  out_stream << "0\n"; // no holes output!
320  out_stream << "\n\n# end of file\n";
321 }
322 
323 } // namespace libMesh
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::MeshBase::point
virtual const Point & point(const dof_id_type i) const =0
libMesh::MeshInput< MeshBase >::skip_comment_lines
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.
Definition: mesh_input.h:179
libMesh::MeshBase::active_element_ptr_range
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
libMesh::MeshBase::n_elem
virtual dof_id_type n_elem() const =0
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::TetGenIO::read
virtual void read(const std::string &) override
This method implements reading a mesh from a specified file in TetGen format.
Definition: tetgen_io.C:34
libMesh::TetGenIO::write
virtual void write(const std::string &) override
This method implements writing a mesh to a specified ".poly" file.
Definition: tetgen_io.C:273
libMesh::MeshBase::node_ptr
virtual const Node * node_ptr(const dof_id_type i) const =0
libMesh::TetGenIO::node_attributes
std::vector< std::vector< Real > > node_attributes
Data structure to hold node attributes read in from file.
Definition: tetgen_io.h:82
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::IntRange
The IntRange templated class is intended to make it easy to loop over integers which are indices of a...
Definition: int_range.h:53
libMesh::MeshBase
This is the MeshBase class.
Definition: mesh_base.h:78
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::TetGenIO::_assign_nodes
std::map< dof_id_type, dof_id_type > _assign_nodes
stores new positions of nodes.
Definition: tetgen_io.h:133
libMesh::Tet4
The Tet4 is an element in 3D composed of 4 nodes.
Definition: cell_tet4.h:53
n_nodes
const dof_id_type n_nodes
Definition: tecplot_io.C:68
libMesh::TetGenIO::element_in
void element_in(std::istream &ele_stream)
Method reads elements and stores them in vector<Elem *> elements in the same order as they come in.
Definition: tetgen_io.C:184
libMesh::MeshBase::n_nodes
virtual dof_id_type n_nodes() const =0
libMesh::MeshOutput
This class defines an abstract interface for Mesh output.
Definition: mesh_output.h:53
libMesh::MeshOutput::mesh
const MT & mesh() const
Definition: mesh_output.h:247
libMesh::Tet10
The Tet10 is an element in 3D composed of 10 nodes.
Definition: cell_tet10.h:60
libMesh::MeshBase::add_elem
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
libMesh::TetGenIO::node_in
void node_in(std::istream &node_stream)
Method reads nodes from node_stream and stores them in vector<Node *> nodes in the order they come in...
Definition: tetgen_io.C:113
libMesh::Elem
This is the base class from which all geometric element types are derived.
Definition: elem.h:100
libMesh::TetGenIO::_num_nodes
dof_id_type _num_nodes
total number of nodes.
Definition: tetgen_io.h:138
libMesh::MeshInput::mesh
MT & mesh()
Definition: mesh_input.h:169
libMesh::MeshBase::add_point
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.
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::out
OStreamProxy out
libMesh::TetGenIO::read_nodes_and_elem
void read_nodes_and_elem(std::istream &node_stream, std::istream &ele_stream)
Reads a mesh (nodes & elements) from the file provided through node_stream and ele_stream.
Definition: tetgen_io.C:95
libMesh::TetGenIO::_num_elements
dof_id_type _num_elements
total number of elements.
Definition: tetgen_io.h:143
libMesh::Quality::name
std::string name(const ElemQuality q)
This function returns a string containing some name for q.
Definition: elem_quality.C:42