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