OGS
TetGenInterface.cpp
Go to the documentation of this file.
1 
15 #include "TetGenInterface.h"
16 
17 #include <cstddef>
18 #include <fstream>
19 #include <string>
20 
21 #include "BaseLib/FileTools.h"
22 #include "BaseLib/Logging.h"
23 #include "BaseLib/StringTools.h"
24 #include "GeoLib/Triangle.h"
26 #include "MeshLib/Elements/Tet.h"
27 #include "MeshLib/Mesh.h"
29 #include "MeshLib/Node.h"
30 
31 namespace FileIO
32 {
34 
35 bool TetGenInterface::readTetGenGeometry(std::string const& geo_fname,
36  GeoLib::GEOObjects& geo_objects)
37 {
38  std::ifstream poly_stream(geo_fname.c_str());
39 
40  if (!poly_stream)
41  {
42  ERR("TetGenInterface::readTetGenGeometry() failed to open {:s}",
43  geo_fname);
44  return false;
45  }
46  std::string ext(BaseLib::getFileExtension(geo_fname));
47  if (ext != ".smesh")
48  {
49  ERR("TetGenInterface::readTetGenGeometry() - unknown file type (only "
50  "*.smesh is supported).");
51  return false;
52  }
53 
54  std::vector<MeshLib::Node*> nodes;
55  if (!readNodesFromStream(poly_stream, nodes))
56  {
57  // remove nodes read until now
58  for (auto& node : nodes)
59  {
60  delete node;
61  }
62  return false;
63  }
64  const std::size_t nNodes(nodes.size());
65  auto points = std::make_unique<std::vector<GeoLib::Point*>>();
66  points->reserve(nNodes);
67  for (std::size_t k(0); k < nNodes; ++k)
68  {
69  points->push_back(new GeoLib::Point(*(nodes[k]), nodes[k]->getID()));
70  delete nodes[k];
71  }
72  std::string geo_name(BaseLib::extractBaseNameWithoutExtension(geo_fname));
73  geo_objects.addPointVec(std::move(points), geo_name);
74  const std::vector<std::size_t>& id_map(
75  geo_objects.getPointVecObj(geo_name)->getIDMap());
76 
77  auto surfaces = std::make_unique<std::vector<GeoLib::Surface*>>();
78  if (!parseSmeshFacets(
79  poly_stream, *surfaces, *geo_objects.getPointVec(geo_name), id_map))
80  {
81  // remove surfaces read until now but keep the points
82  for (std::size_t k = 0; k < surfaces->size(); k++)
83  {
84  delete (*surfaces)[k];
85  }
86  }
87  geo_objects.addSurfaceVec(std::move(surfaces), geo_name);
88 
89  return true;
90 }
91 
92 std::size_t TetGenInterface::getNFacets(std::ifstream& input)
93 {
94  std::string line;
95  while (!input.fail())
96  {
97  getline(input, line);
98  if (input.fail())
99  {
100  ERR("TetGenInterface::getNFacets(): Error reading number of "
101  "facets.");
102  return 0;
103  }
104 
105  BaseLib::simplify(line);
106  if (line.empty() || line.compare(0, 1, "#") == 0)
107  {
108  continue;
109  }
110 
111  const std::list<std::string> fields = BaseLib::splitString(line, ' ');
112  auto it = fields.begin();
113  const auto nFacets(BaseLib::str2number<std::size_t>(*it));
114  if (fields.size() > 1)
115  {
116  _boundary_markers = BaseLib::str2number<std::size_t>(*(++it)) != 0;
117  }
118  return nFacets;
119  }
120  return 0;
121 }
122 
124  std::ifstream& input,
125  std::vector<GeoLib::Surface*>& surfaces,
126  const std::vector<GeoLib::Point*>& points,
127  const std::vector<std::size_t>& pnt_id_map)
128 {
129  const std::size_t nFacets(this->getNFacets(input));
130  std::string line;
131  surfaces.reserve(nFacets);
132  std::list<std::string>::const_iterator it;
133 
134  const unsigned offset = (_zero_based_idx) ? 0 : 1;
135  std::vector<std::size_t> idx_map;
136 
137  std::size_t k(0);
138  while (k < nFacets && !input.fail())
139  {
140  getline(input, line);
141  if (input.fail())
142  {
143  ERR("TetGenInterface::parseFacets(): Error reading facet {:d}.", k);
144  return false;
145  }
146 
147  BaseLib::simplify(line);
148  if (line.empty() || line.compare(0, 1, "#") == 0)
149  {
150  continue;
151  }
152 
153  // read facets
154  const std::list<std::string> point_fields =
155  BaseLib::splitString(line, ' ');
156  it = point_fields.begin();
157  const auto nPoints = BaseLib::str2number<std::size_t>(*it);
158  if (nPoints != 3)
159  {
160  ERR("Smesh-files are currently only supported for triangle "
161  "meshes.");
162  return false;
163  }
164  std::vector<std::size_t> point_ids;
165  const std::size_t point_field_size =
166  (_boundary_markers) ? nPoints + 1 : nPoints;
167  if (point_fields.size() > point_field_size)
168  {
169  for (std::size_t j(0); j < nPoints; ++j)
170  {
171  point_ids.push_back(
172  pnt_id_map[BaseLib::str2number<std::size_t>(*(++it)) -
173  offset]);
174  }
175 
176  const std::size_t sfc_marker =
177  (_boundary_markers) ? BaseLib::str2number<std::size_t>(*(++it))
178  : 0;
179  const std::size_t idx =
180  std::find(idx_map.begin(), idx_map.end(), sfc_marker) -
181  idx_map.begin();
182  if (idx >= surfaces.size())
183  {
184  idx_map.push_back(sfc_marker);
185  surfaces.push_back(new GeoLib::Surface(points));
186  }
187  surfaces[idx]->addTriangle(
188  point_ids[0], point_ids[1], point_ids[2]);
189  }
190  else
191  {
192  ERR("TetGenInterface::parseFacets(): Error reading points for "
193  "facet {:d}.",
194  k);
195  return false;
196  }
197  ++k;
198  }
199  // here the poly-file potentially defines a number of points to mark holes
200  // within the volumes defined by the facets, these are ignored for now here
201  // the poly-file potentially defines a number of region attributes, these
202  // are ignored for now
203 
204  std::size_t nTotalTriangles(0);
205  for (auto& surface : surfaces)
206  {
207  nTotalTriangles += surface->getNumberOfTriangles();
208  }
209  if (nTotalTriangles == nFacets)
210  {
211  return true;
212  }
213 
214  ERR("TetGenInterface::parseFacets(): Number of expected total triangles "
215  "({:d}) does not match number of found triangles ({:d}).",
216  surfaces.size(),
217  nTotalTriangles);
218  return false;
219 }
220 
221 MeshLib::Mesh* TetGenInterface::readTetGenMesh(std::string const& nodes_fname,
222  std::string const& ele_fname)
223 {
224  std::ifstream ins_nodes(nodes_fname.c_str());
225  std::ifstream ins_ele(ele_fname.c_str());
226 
227  if (!ins_nodes || !ins_ele)
228  {
229  if (!ins_nodes)
230  {
231  ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
232  nodes_fname);
233  }
234  if (!ins_ele)
235  {
236  ERR("TetGenInterface::readTetGenMesh failed to open {:s}",
237  ele_fname);
238  }
239  return nullptr;
240  }
241 
242  std::vector<MeshLib::Node*> nodes;
243  if (!readNodesFromStream(ins_nodes, nodes))
244  {
245  // remove nodes read until now
246  for (auto& node : nodes)
247  {
248  delete node;
249  }
250  return nullptr;
251  }
252 
253  std::vector<MeshLib::Element*> elements;
254  std::vector<int> materials;
255  if (!readElementsFromStream(ins_ele, elements, materials, nodes))
256  {
257  BaseLib::cleanupVectorElements(nodes, elements);
258  return nullptr;
259  }
260 
261  MeshLib::Properties properties;
262  // Transmit material values if there is any material value != 0
263  if (std::any_of(
264  materials.cbegin(), materials.cend(), [](int m) { return m != 0; }))
265  {
266  auto* const mat_props = properties.createNewPropertyVector<int>(
267  "MaterialIDs", MeshLib::MeshItemType::Cell);
268  mat_props->reserve(elements.size());
269  std::copy(materials.cbegin(),
270  materials.cend(),
271  std::back_inserter(*mat_props));
272  }
273 
274  const std::string mesh_name(
276  return new MeshLib::Mesh(mesh_name, nodes, elements, properties);
277 }
278 
279 bool TetGenInterface::readNodesFromStream(std::ifstream& ins,
280  std::vector<MeshLib::Node*>& nodes)
281 {
282  std::string line;
283  getline(ins, line);
284  std::size_t n_nodes;
285  std::size_t dim;
286  std::size_t n_attributes;
287  bool boundary_markers;
288 
289  while (!ins.fail())
290  {
291  BaseLib::simplify(line);
292  if (line.empty() || line.compare(0, 1, "#") == 0)
293  {
294  // this line is a comment - skip
295  getline(ins, line);
296  continue;
297  }
298  // read header line
299  bool header_okay = parseNodesFileHeader(
300  line, n_nodes, dim, n_attributes, boundary_markers);
301  if (!header_okay)
302  {
303  return false;
304  }
305  if (!parseNodes(ins, nodes, n_nodes, dim))
306  {
307  return false;
308  }
309  return true;
310  }
311  return false;
312 }
313 
314 bool TetGenInterface::parseNodesFileHeader(std::string const& line,
315  std::size_t& n_nodes,
316  std::size_t& dim,
317  std::size_t& n_attributes,
318  bool& boundary_markers)
319 {
320  std::list<std::string> pnt_header = BaseLib::splitString(line, ' ');
321  if (pnt_header.empty())
322  {
323  ERR("TetGenInterface::parseNodesFileHeader(): could not read number of "
324  "nodes specified in header.");
325  return false;
326  }
327  auto it = pnt_header.begin();
328  n_nodes = BaseLib::str2number<std::size_t>(*it);
329  dim = (pnt_header.size() == 1) ? 3
330  : BaseLib::str2number<std::size_t>(*(++it));
331 
332  if (pnt_header.size() < 4)
333  {
334  n_attributes = 0;
335  boundary_markers = false;
336  return true;
337  }
338 
339  n_attributes = BaseLib::str2number<std::size_t>(*(++it));
340  boundary_markers = *(++it) == "1";
341 
342  return true;
343 }
344 
345 bool TetGenInterface::parseNodes(std::ifstream& ins,
346  std::vector<MeshLib::Node*>& nodes,
347  std::size_t n_nodes,
348  std::size_t dim)
349 {
350  std::string line;
351  nodes.reserve(n_nodes);
352 
353  std::size_t k(0);
354  while (k < n_nodes && !ins.fail())
355  {
356  std::vector<double> coordinates(dim);
357  std::getline(ins, line);
358  if (ins.fail())
359  {
360  ERR("TetGenInterface::parseNodes(): Error reading node {:d}.", k);
361  return false;
362  }
363 
364  std::size_t id;
365  std::size_t pos_end = 0;
366  std::size_t pos_beg = line.find_first_not_of(' ', pos_end);
367  pos_end = line.find_first_of(" \n", pos_beg);
368 
369  if (line.empty() || pos_beg == pos_end ||
370  line.compare(pos_beg, 1, "#") == 0)
371  {
372  continue;
373  }
374 
375  if (pos_beg != std::string::npos && pos_end != std::string::npos)
376  {
377  id = BaseLib::str2number<std::size_t>(
378  line.substr(pos_beg, pos_end - pos_beg));
379  if (k == 0 && id == 0)
380  {
381  _zero_based_idx = true;
382  }
383  }
384  else
385  {
386  ERR("TetGenInterface::parseNodes(): Error reading ID of node {:d}.",
387  k);
388  return false;
389  }
390  // read coordinates
391  const unsigned offset = (_zero_based_idx) ? 0 : 1;
392  for (std::size_t i(0); i < dim; i++)
393  {
394  pos_beg = line.find_first_not_of(' ', pos_end);
395  pos_end = line.find_first_of(" \n", pos_beg);
396  if (pos_end == std::string::npos)
397  {
398  pos_end = line.size();
399  }
400  if (pos_beg != std::string::npos)
401  {
402  coordinates[i] = BaseLib::str2number<double>(
403  line.substr(pos_beg, pos_end - pos_beg));
404  }
405  else
406  {
407  ERR("TetGenInterface::parseNodes(): error reading coordinate "
408  "{:d} of node {:d}.",
409  i,
410  k);
411  return false;
412  }
413  }
414 
415  nodes.push_back(new MeshLib::Node(coordinates.data(), id - offset));
416  // read attributes and boundary markers ... - at the moment we do not
417  // use this information
418  ++k;
419  }
420 
421  return true;
422 }
423 
425  std::ifstream& ins,
426  std::vector<MeshLib::Element*>& elements,
427  std::vector<int>& materials,
428  const std::vector<MeshLib::Node*>& nodes) const
429 {
430  std::string line;
431  std::getline(ins, line);
432  std::size_t n_tets;
433  std::size_t n_nodes_per_tet;
434  bool region_attributes;
435 
436  while (!ins.fail())
437  {
438  BaseLib::simplify(line);
439  if (line.empty() || line.compare(0, 1, "#") == 0)
440  {
441  // this line is a comment - skip
442  std::getline(ins, line);
443  continue;
444  }
445 
446  // read header line
447  bool header_okay = parseElementsFileHeader(
448  line, n_tets, n_nodes_per_tet, region_attributes);
449  if (!header_okay)
450  {
451  return false;
452  }
453  if (!parseElements(ins,
454  elements,
455  materials,
456  nodes,
457  n_tets,
458  n_nodes_per_tet,
459  region_attributes))
460  {
461  return false;
462  }
463  return true;
464  }
465  return false;
466 }
467 
469  std::size_t& n_tets,
470  std::size_t& n_nodes_per_tet,
471  bool& region_attribute)
472 {
473  std::size_t pos_beg;
474  std::size_t pos_end;
475 
476  // number of tetrahedras
477  pos_beg = line.find_first_not_of(' ');
478  pos_end = line.find_first_of(' ', pos_beg);
479  if (pos_beg != std::string::npos && pos_end != std::string::npos)
480  {
481  n_tets = BaseLib::str2number<std::size_t>(
482  line.substr(pos_beg, pos_end - pos_beg));
483  }
484  else
485  {
486  ERR("TetGenInterface::parseElementsFileHeader(): Could not read number "
487  "of tetrahedra specified in header.");
488  return false;
489  }
490  // nodes per tet - either 4 or 10
491  pos_beg = line.find_first_not_of(" \t", pos_end);
492  pos_end = line.find_first_of(" \t", pos_beg);
493  n_nodes_per_tet = BaseLib::str2number<std::size_t>(
494  line.substr(pos_beg, pos_end - pos_beg));
495  // region attribute at tetrahedra?
496  pos_beg = line.find_first_not_of(" \t", pos_end);
497  pos_end = line.find_first_of(" \t\n", pos_beg);
498  if (pos_end == std::string::npos)
499  {
500  pos_end = line.size();
501  }
502  region_attribute = line.substr(pos_beg, pos_end - pos_beg) == "1";
503 
504  return true;
505 }
506 
507 bool TetGenInterface::parseElements(std::ifstream& ins,
508  std::vector<MeshLib::Element*>& elements,
509  std::vector<int>& materials,
510  const std::vector<MeshLib::Node*>& nodes,
511  std::size_t n_tets,
512  std::size_t n_nodes_per_tet,
513  bool region_attribute) const
514 {
515  std::string line;
516  std::vector<std::size_t> ids(n_nodes_per_tet);
517 
518  elements.reserve(n_tets);
519  materials.reserve(n_tets);
520 
521  const unsigned offset = (_zero_based_idx) ? 0 : 1;
522  for (std::size_t k(0); k < n_tets && !ins.fail(); k++)
523  {
524  getline(ins, line);
525  if (ins.fail())
526  {
527  ERR("TetGenInterface::parseElements(): Error reading tetrahedron "
528  "{:d}.",
529  k);
530  return false;
531  }
532 
533  std::size_t pos_end = 0;
534  std::size_t pos_beg = line.find_first_not_of(' ', pos_end);
535  pos_end = line.find_first_of(" \n", pos_beg);
536 
537  if (line.empty() || pos_beg == pos_end ||
538  line.compare(pos_beg, 1, "#") == 0)
539  {
540  k--;
541  continue;
542  }
543 
544  if (pos_beg == std::string::npos || pos_end == std::string::npos)
545  {
546  ERR("TetGenInterface::parseElements(): Error reading id of "
547  "tetrahedron {:d}.",
548  k);
549  return false;
550  }
551 
552  // read node ids
553  for (std::size_t i(0); i < n_nodes_per_tet; i++)
554  {
555  pos_beg = line.find_first_not_of(' ', pos_end);
556  pos_end = line.find_first_of(' ', pos_beg);
557  if (pos_end == std::string::npos)
558  {
559  pos_end = line.size();
560  }
561  if (pos_beg != std::string::npos && pos_end != std::string::npos)
562  {
563  ids[i] = BaseLib::str2number<std::size_t>(
564  line.substr(pos_beg, pos_end - pos_beg)) -
565  offset;
566  }
567  else
568  {
569  ERR("TetGenInterface::parseElements(): Error reading node {:d} "
570  "of tetrahedron {:d}.",
571  i,
572  k);
573  return false;
574  }
575  }
576 
577  // read region attribute - this is something like material group
578  int region(0);
579  if (region_attribute)
580  {
581  pos_beg = line.find_first_not_of(' ', pos_end);
582  pos_end = line.find_first_of(' ', pos_beg);
583  if (pos_end == std::string::npos)
584  {
585  pos_end = line.size();
586  }
587  if (pos_beg != std::string::npos && pos_end != std::string::npos)
588  {
589  region = BaseLib::str2number<int>(
590  line.substr(pos_beg, pos_end - pos_beg));
591  }
592  else
593  {
594  ERR("TetGenInterface::parseElements(): Error reading region "
595  "attribute of tetrahedron {:d}.",
596  k);
597  return false;
598  }
599  }
600  // insert new element into vector
601  auto** tet_nodes = new MeshLib::Node*[4];
602  for (int n = 0; n < 4; n++)
603  {
604  tet_nodes[n] = nodes[ids[n]];
605  }
606  elements.push_back(new MeshLib::Tet(tet_nodes));
607  materials.push_back(region);
608  }
609 
610  return true;
611 }
612 
614  const std::string& file_name,
615  const GeoLib::GEOObjects& geo_objects,
616  const std::string& geo_name,
617  const std::vector<GeoLib::Point>& attribute_points)
618 {
619  std::vector<GeoLib::Point*> const* const points =
620  geo_objects.getPointVec(geo_name);
621  std::vector<GeoLib::Surface*> const* const surfaces =
622  geo_objects.getSurfaceVec(geo_name);
623 
624  if (points == nullptr)
625  {
626  ERR("Geometry {:s} not found.", geo_name);
627  return false;
628  }
629  if (surfaces == nullptr)
630  {
631  WARN("No surfaces found for geometry {:s}. Writing points only.",
632  geo_name);
633  }
634 
635  std::ofstream out(file_name.c_str(), std::ios::out);
636  out.precision(std::numeric_limits<double>::digits10);
637  // the points header
638  const std::size_t nPoints(points->size());
639  out << nPoints << " 3\n";
640  // the point list
641  for (std::size_t i = 0; i < nPoints; ++i)
642  {
643  out << i << " " << (*(*points)[i])[0] << " " << (*(*points)[i])[1]
644  << " " << (*(*points)[i])[2] << "\n";
645  }
646  // the surfaces header
647  const std::size_t nSurfaces = (surfaces) ? surfaces->size() : 0;
648  std::size_t nTotalTriangles(0);
649  for (std::size_t i = 0; i < nSurfaces; ++i)
650  {
651  nTotalTriangles += (*surfaces)[i]->getNumberOfTriangles();
652  }
653  out << nTotalTriangles << " 1\n";
654 
655  for (std::size_t i = 0; i < nSurfaces; ++i)
656  {
657  const std::size_t nTriangles((*surfaces)[i]->getNumberOfTriangles());
658  const std::size_t marker(i + 1); // must NOT be 0!
659  // the poly list
660  for (std::size_t j = 0; j < nTriangles; ++j)
661  {
662  const GeoLib::Triangle& tri = *(*(*surfaces)[i])[j];
663  out << "3 " << tri[0] << " " << tri[1] << " " << tri[2] << " "
664  << marker << "\n";
665  }
666  }
667  out << "0\n"; // the polygon holes list
668  // the region attributes list
669  if (attribute_points.empty())
670  {
671  out << "0\n";
672  }
673  else
674  {
675  const std::size_t nAttributePoints(attribute_points.size());
676  out << nAttributePoints << "\n";
677  for (std::size_t i = 0; i < nAttributePoints; ++i)
678  {
679  out << i + 1 << " " << attribute_points[i][0] << " "
680  << attribute_points[i][1] << " " << attribute_points[i][2]
681  << " " << 10 * attribute_points[i].getID() << "\n";
682  }
683  }
684  INFO(
685  "TetGenInterface::writeTetGenSmesh() - {:d} points and {:d} surfaces "
686  "successfully written.",
687  nPoints,
688  nSurfaces);
689  out.close();
690  return true;
691 }
692 
694  const std::string& file_name,
695  const MeshLib::Mesh& mesh,
696  std::vector<MeshLib::Node>& attribute_points) const
697 {
698  if (mesh.getDimension() == 1)
699  {
700  return false;
701  }
702 
703  const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
704 
705  std::ofstream out(file_name.c_str(), std::ios::out);
706  out.precision(std::numeric_limits<double>::digits10);
707  // the points header
708  const std::size_t nPoints(nodes.size());
709  out << nPoints << " 3\n";
710  // the point list
711  for (std::size_t i = 0; i < nPoints; ++i)
712  {
713  out << i << " " << (*nodes[i])[0] << " " << (*nodes[i])[1] << " "
714  << (*nodes[i])[2] << "\n";
715  }
716 
717  if (mesh.getDimension() == 2)
718  {
719  write2dElements(out, mesh);
720  }
721  else
722  {
723  write3dElements(out, mesh, attribute_points);
724  }
725 
726  out << "0\n"; // the polygon holes list
727 
728  // the region attributes list
729  if (attribute_points.empty())
730  {
731  out << "0\n";
732  }
733  else
734  {
735  const std::size_t nAttributePoints(attribute_points.size());
736  out << nAttributePoints << "\n";
737  for (std::size_t i = 0; i < nAttributePoints; ++i)
738  {
739  out << i + 1 << " " << attribute_points[i][0] << " "
740  << attribute_points[i][1] << " " << attribute_points[i][2]
741  << " " << 10 * attribute_points[i].getID() << "\n";
742  }
743  }
744 
745  INFO(
746  "TetGenInterface::writeTetGenPoly() - {:d} points and {:d} surfaces "
747  "successfully written.",
748  nPoints,
749  mesh.getNumberOfElements());
750  out.close();
751  return true;
752 }
753 
754 void TetGenInterface::write2dElements(std::ofstream& out,
755  const MeshLib::Mesh& mesh) const
756 {
757  // the surfaces header
758  auto const& types = MeshLib::MeshInformation::getNumberOfElementTypes(mesh);
759  std::size_t const n_tri =
760  (types.find(MeshLib::MeshElemType::TRIANGLE) != types.end())
762  : 0;
763  std::size_t const n_quad =
764  (types.find(MeshLib::MeshElemType::QUAD) != types.end())
765  ? types.at(MeshLib::MeshElemType::QUAD)
766  : 0;
767  unsigned const nTotalTriangles = n_tri + 2 * n_quad;
768  out << nTotalTriangles << " 1\n";
769 
770  const std::vector<MeshLib::Element*>& elements = mesh.getElements();
771  MeshLib::PropertyVector<int> const* const mat_ids =
772  mesh.getProperties().existsPropertyVector<int>("MaterialIDs")
773  ? mesh.getProperties().getPropertyVector<int>("MaterialIDs")
774  : nullptr;
775  const std::size_t nElements(elements.size());
776  unsigned element_count(0);
777  for (std::size_t i = 0; i < nElements; ++i)
778  {
779  std::string const matId = mat_ids ? std::to_string((*mat_ids)[i]) : "";
780  this->writeElementToFacets(out, *elements[i], element_count, matId);
781  }
782 }
783 
785  std::ofstream& out,
786  const MeshLib::Mesh& mesh,
787  std::vector<MeshLib::Node>& attribute_points) const
788 {
789  const std::vector<MeshLib::Element*>& elements = mesh.getElements();
790  const std::size_t nElements(elements.size());
791  if (!attribute_points.empty())
792  {
793  attribute_points.clear();
794  }
795 
796  // get position where number of facets need to be written and figure out
797  // worst case of chars that are needed
798  const std::streamoff before_elems_pos(out.tellp());
799  const unsigned n_spaces(
800  static_cast<unsigned>(std::floor(log(nElements * 8))) + 1);
801  out << std::string(n_spaces, ' ') << " 1\n";
802  auto const* const materialIds =
803  mesh.getProperties().getPropertyVector<int>("MaterialIDs");
804  unsigned element_count(0);
805  for (std::size_t i = 0; i < nElements; ++i)
806  {
807  if (elements[i]->getDimension() < 3)
808  {
809  continue;
810  }
811 
812  const unsigned nFaces(elements[i]->getNumberOfNeighbors());
813  std::string const mat_id_str =
814  materialIds ? std::to_string((*materialIds)[i]) : "";
815  for (std::size_t j = 0; j < nFaces; ++j)
816  {
817  MeshLib::Element const* const neighbor(elements[i]->getNeighbor(j));
818 
819  if (neighbor && materialIds &&
820  (*materialIds)[i] <= (*materialIds)[neighbor->getID()])
821  {
822  continue;
823  }
824 
825  std::unique_ptr<MeshLib::Element const> const face(
826  elements[i]->getFace(j));
827  this->writeElementToFacets(out, *face, element_count, mat_id_str);
828  }
829  if (materialIds)
830  {
831  attribute_points.emplace_back(
832  MeshLib::getCenterOfGravity(*elements[i]).getCoords(),
833  (*materialIds)[i]);
834  }
835  }
836  // add number of facets at correct position and jump back
837  const std::streamoff after_elems_pos(out.tellp());
838  out.seekp(before_elems_pos);
839  out << element_count;
840  out.seekp(after_elems_pos);
841 }
842 
844  const MeshLib::Element& element,
845  unsigned& element_count,
846  std::string const& matId)
847 {
848  element_count++;
850  {
851  out << "3 " << getNodeIndex(element, 0) << " "
852  << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
853  << " " << matId << " # " << element_count << "\n";
854  }
855  else if (element.getGeomType() == MeshLib::MeshElemType::QUAD)
856  {
857  out << "3 " << getNodeIndex(element, 0) << " "
858  << getNodeIndex(element, 1) << " " << getNodeIndex(element, 2)
859  << " " << matId << " # " << element_count << "\n";
860  element_count++;
861  out << "3 " << getNodeIndex(element, 0) << " "
862  << getNodeIndex(element, 2) << " " << getNodeIndex(element, 3)
863  << " " << matId << " # " << element_count << "\n";
864  }
865 }
866 
867 } // end namespace FileIO
Definition of the Element class.
Filename manipulation routines.
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:32
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
void WARN(char const *fmt, Args const &... args)
Definition: Logging.h:37
Definition of the MeshInformation class.
Definition of the Mesh class.
Definition of the Node class.
Definition of string helper functions.
Definition of the TetGenInterface class.
Definition of the Tet class.
bool readElementsFromStream(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes) const
bool _boundary_markers
true if boundary markers are set, false otherwise
MeshLib::Mesh * readTetGenMesh(std::string const &nodes_fname, std::string const &ele_fname)
bool parseNodes(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes, std::size_t n_nodes, std::size_t dim)
static bool parseElementsFileHeader(std::string &line, std::size_t &n_tets, std::size_t &n_nodes_per_tet, bool &region_attribute)
void write3dElements(std::ofstream &out, const MeshLib::Mesh &mesh, std::vector< MeshLib::Node > &attribute_points) const
bool readNodesFromStream(std::ifstream &ins, std::vector< MeshLib::Node * > &nodes)
static bool parseNodesFileHeader(std::string const &line, std::size_t &n_nodes, std::size_t &dim, std::size_t &n_attributes, bool &boundary_markers)
bool _zero_based_idx
the value is true if the indexing is zero based, else false
bool readTetGenGeometry(std::string const &geo_fname, GeoLib::GEOObjects &geo_objects)
void write2dElements(std::ofstream &out, const MeshLib::Mesh &mesh) const
bool parseElements(std::ifstream &ins, std::vector< MeshLib::Element * > &elements, std::vector< int > &materials, const std::vector< MeshLib::Node * > &nodes, std::size_t n_tets, std::size_t n_nodes_per_tet, bool region_attribute) const
static bool writeTetGenSmesh(const std::string &file_name, const GeoLib::GEOObjects &geo_objects, const std::string &geo_name, const std::vector< GeoLib::Point > &attribute_points)
static void writeElementToFacets(std::ofstream &out, const MeshLib::Element &element, unsigned &element_count, std::string const &matId)
Writes facet information from a 2D element to the stream and increments the total element count accor...
bool parseSmeshFacets(std::ifstream &input, std::vector< GeoLib::Surface * > &surfaces, const std::vector< GeoLib::Point * > &points, const std::vector< std::size_t > &pnt_id_map)
std::size_t getNFacets(std::ifstream &input)
Returns the declared number of facets in the poly file.
Container class for geometric objects.
Definition: GEOObjects.h:61
void addSurfaceVec(std::unique_ptr< std::vector< Surface * >> sfc, const std::string &name, std::unique_ptr< std::map< std::string, std::size_t >> sfc_names=nullptr)
Definition: GEOObjects.cpp:261
const std::vector< Point * > * getPointVec(const std::string &name) const
Definition: GEOObjects.cpp:71
const PointVec * getPointVecObj(const std::string &name) const
Definition: GEOObjects.cpp:84
void addPointVec(std::unique_ptr< std::vector< Point * >> points, std::string &name, std::unique_ptr< std::map< std::string, std::size_t >> pnt_id_name_map=nullptr, double eps=std::sqrt(std::numeric_limits< double >::epsilon()))
Definition: GEOObjects.cpp:51
const std::vector< Surface * > * getSurfaceVec(const std::string &name) const
Returns the surface vector with the given name as a const.
Definition: GEOObjects.cpp:307
const std::vector< std::size_t > & getIDMap() const
Definition: PointVec.h:97
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
Definition: Surface.h:34
Class Triangle consists of a reference to a point vector and a vector that stores the indices in the ...
Definition: Triangle.h:26
virtual MeshElemType getGeomType() const =0
virtual std::size_t getID() const final
Returns the ID of the element.
Definition: Element.h:82
static std::map< MeshElemType, unsigned > getNumberOfElementTypes(const MeshLib::Mesh &mesh)
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition: Mesh.h:95
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition: Mesh.h:71
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:98
Properties & getProperties()
Definition: Mesh.h:123
std::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:86
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition: Properties.h:36
PropertyVector< T > const * getPropertyVector(std::string const &name) const
bool existsPropertyVector(std::string const &name) const
PropertyVector< T > * createNewPropertyVector(std::string const &name, MeshItemType mesh_item_type, std::size_t n_components=1)
void simplify(std::string &str)
Definition: StringTools.cpp:76
std::string getFileExtension(const std::string &path)
Definition: FileTools.cpp:186
std::string extractBaseNameWithoutExtension(std::string const &pathname)
Definition: FileTools.cpp:180
std::vector< std::string > splitString(std::string const &str)
Definition: StringTools.cpp:28
void cleanupVectorElements(std::vector< T1 * > const &items, std::vector< T2 * > const &dependent_items)
Definition: Algorithm.h:300
void copy(PETScVector const &x, PETScVector &y)
Definition: LinAlg.cpp:37
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition: Element.cpp:225
MeshLib::Node getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.
Definition: Element.cpp:126
unsigned getDimension(MeshLib::MeshElemType eleType)