8#include <range/v3/numeric/accumulate.hpp>
27 std::vector<GeoLib::Point*> points;
28 points.reserve(nodes.size());
29 std::transform(nodes.begin(), nodes.end(), std::back_inserter(points),
31 { return new GeoLib::Point(*node, node->getID()); });
38 std::ifstream poly_stream(geo_fname.c_str());
42 ERR(
"TetGenInterface::readTetGenGeometry() failed to open {:s}",
49 ERR(
"TetGenInterface::readTetGenGeometry() - unknown file type (only "
50 "*.smesh is supported).");
54 std::vector<MeshLib::Node*> nodes;
65 geo_objects.
addPointVec(std::move(points), geo_name);
66 const std::vector<std::size_t>& id_map(
69 std::vector<GeoLib::Surface*> surfaces;
87 std::getline(input, line);
90 ERR(
"TetGenInterface::getNFacets(): Error reading number of "
96 if (line.empty() || line.compare(0, 1,
"#") == 0)
102 auto it = fields.begin();
104 if (fields.size() > 1)
114 std::ifstream& input,
115 std::vector<GeoLib::Surface*>& surfaces,
116 const std::vector<GeoLib::Point*>& points,
117 const std::vector<std::size_t>& pnt_id_map)
119 const std::size_t nFacets(this->
getNFacets(input));
121 surfaces.reserve(nFacets);
122 std::list<std::string>::const_iterator it;
125 std::vector<std::size_t> idx_map;
128 while (k < nFacets && !input.fail())
130 std::getline(input, line);
133 ERR(
"TetGenInterface::parseFacets(): Error reading facet {:d}.", k);
138 if (line.empty() || line.compare(0, 1,
"#") == 0)
144 const std::list<std::string> point_fields =
146 it = point_fields.begin();
150 ERR(
"Smesh-files are currently only supported for triangle "
154 const std::size_t point_field_size =
156 if (point_fields.size() > point_field_size)
158 std::vector<std::size_t> point_ids;
159 for (std::size_t j(0); j < nPoints; ++j)
166 const std::size_t sfc_marker =
169 const std::size_t idx =
170 std::find(idx_map.begin(), idx_map.end(), sfc_marker) -
172 if (idx >= surfaces.size())
174 idx_map.push_back(sfc_marker);
177 surfaces[idx]->addTriangle(point_ids[0], point_ids[1],
182 ERR(
"TetGenInterface::parseFacets(): Error reading points for "
194 auto const nTotalTriangles = ranges::accumulate(
195 surfaces, std::size_t{0}, {},
196 [](
auto const* surface) {
return surface->getNumberOfTriangles(); });
197 if (nTotalTriangles == nFacets)
202 ERR(
"TetGenInterface::parseFacets(): Number of expected total triangles "
203 "({:d}) does not match number of found triangles ({:d}).",
210 std::string
const& ele_fname)
212 std::ifstream ins_nodes(nodes_fname.c_str());
213 std::ifstream ins_ele(ele_fname.c_str());
215 if (!ins_nodes || !ins_ele)
219 ERR(
"TetGenInterface::readTetGenMesh failed to open {:s}",
224 ERR(
"TetGenInterface::readTetGenMesh failed to open {:s}",
230 std::vector<MeshLib::Node*> nodes;
238 std::vector<MeshLib::Element*> elements;
239 std::vector<int> materials;
248 if (std::any_of(materials.cbegin(), materials.cend(),
249 [](
int m) { return m != 0; }))
253 mat_props->
assign(materials);
256 const std::string mesh_name(
263 std::vector<MeshLib::Node*>& nodes)
266 std::getline(ins, line);
269 std::size_t n_attributes;
270 bool boundary_markers;
275 if (line.empty() || line.compare(0, 1,
"#") == 0)
278 std::getline(ins, line);
283 n_attributes, boundary_markers);
298 std::size_t& n_nodes,
300 std::size_t& n_attributes,
301 bool& boundary_markers)
304 if (pnt_header.empty())
306 ERR(
"TetGenInterface::parseNodesFileHeader(): could not read number of "
307 "nodes specified in header.");
310 auto it = pnt_header.begin();
312 dim = (pnt_header.size() == 1) ? 3
315 if (pnt_header.size() < 4)
318 boundary_markers =
false;
323 boundary_markers = *(++it) ==
"1";
329 std::vector<MeshLib::Node*>& nodes,
334 nodes.reserve(n_nodes);
337 while (k < n_nodes && !ins.fail())
339 std::vector<double> coordinates(dim);
340 std::getline(ins, line);
343 ERR(
"TetGenInterface::parseNodes(): Error reading node {:d}.", k);
348 std::size_t pos_end = 0;
349 std::size_t pos_beg = line.find_first_not_of(
' ', pos_end);
350 pos_end = line.find_first_of(
" \n", pos_beg);
352 if (line.empty() || pos_beg == pos_end ||
353 line.compare(pos_beg, 1,
"#") == 0)
358 if (pos_beg != std::string::npos && pos_end != std::string::npos)
361 line.substr(pos_beg, pos_end - pos_beg));
362 if (k == 0 &&
id == 0)
369 ERR(
"TetGenInterface::parseNodes(): Error reading ID of node {:d}.",
375 for (std::size_t i(0); i < dim; i++)
377 pos_beg = line.find_first_not_of(
' ', pos_end);
378 pos_end = line.find_first_of(
" \n", pos_beg);
379 if (pos_end == std::string::npos)
381 pos_end = line.size();
383 if (pos_beg != std::string::npos)
386 line.substr(pos_beg, pos_end - pos_beg));
390 ERR(
"TetGenInterface::parseNodes(): error reading coordinate "
391 "{:d} of node {:d}.",
398 nodes.push_back(
new MeshLib::Node(coordinates.data(),
id - offset));
409 std::vector<MeshLib::Element*>& elements,
410 std::vector<int>& materials,
411 const std::vector<MeshLib::Node*>& nodes)
const
414 std::getline(ins, line);
416 std::size_t n_nodes_per_tet;
417 bool region_attributes;
422 if (line.empty() || line.compare(0, 1,
"#") == 0)
425 std::getline(ins, line);
431 line, n_tets, n_nodes_per_tet, region_attributes);
453 std::size_t& n_nodes_per_tet,
454 bool& region_attribute)
460 pos_beg = line.find_first_not_of(
' ');
461 pos_end = line.find_first_of(
' ', pos_beg);
462 if (pos_beg != std::string::npos && pos_end != std::string::npos)
465 line.substr(pos_beg, pos_end - pos_beg));
469 ERR(
"TetGenInterface::parseElementsFileHeader(): Could not read number "
470 "of tetrahedra specified in header.");
474 pos_beg = line.find_first_not_of(
" \t", pos_end);
475 pos_end = line.find_first_of(
" \t", pos_beg);
477 line.substr(pos_beg, pos_end - pos_beg));
479 pos_beg = line.find_first_not_of(
" \t", pos_end);
480 pos_end = line.find_first_of(
" \t\n", pos_beg);
481 if (pos_end == std::string::npos)
483 pos_end = line.size();
485 region_attribute = line.substr(pos_beg, pos_end - pos_beg) ==
"1";
491 std::vector<MeshLib::Element*>& elements,
492 std::vector<int>& materials,
493 const std::vector<MeshLib::Node*>& nodes,
495 std::size_t n_nodes_per_tet,
496 bool region_attribute)
const
499 std::vector<std::size_t> ids(n_nodes_per_tet);
501 elements.reserve(n_tets);
502 materials.reserve(n_tets);
505 for (std::size_t k(0); k < n_tets && !ins.fail(); k++)
507 std::getline(ins, line);
510 ERR(
"TetGenInterface::parseElements(): Error reading tetrahedron "
516 std::size_t pos_end = 0;
517 std::size_t pos_beg = line.find_first_not_of(
' ', pos_end);
518 pos_end = line.find_first_of(
" \n", pos_beg);
520 if (line.empty() || pos_beg == pos_end ||
521 line.compare(pos_beg, 1,
"#") == 0)
527 if (pos_beg == std::string::npos || pos_end == std::string::npos)
529 ERR(
"TetGenInterface::parseElements(): Error reading id of "
536 for (std::size_t i(0); i < n_nodes_per_tet; i++)
538 pos_beg = line.find_first_not_of(
' ', pos_end);
539 pos_end = line.find_first_of(
' ', pos_beg);
540 if (pos_end == std::string::npos)
542 pos_end = line.size();
544 if (pos_beg != std::string::npos && pos_end != std::string::npos)
547 line.substr(pos_beg, pos_end - pos_beg)) -
552 ERR(
"TetGenInterface::parseElements(): Error reading node {:d} "
553 "of tetrahedron {:d}.",
562 if (region_attribute)
564 pos_beg = line.find_first_not_of(
' ', pos_end);
565 pos_end = line.find_first_of(
' ', pos_beg);
566 if (pos_end == std::string::npos)
568 pos_end = line.size();
570 if (pos_beg != std::string::npos && pos_end != std::string::npos)
573 line.substr(pos_beg, pos_end - pos_beg));
577 ERR(
"TetGenInterface::parseElements(): Error reading region "
578 "attribute of tetrahedron {:d}.",
585 for (
int n = 0; n < 4; n++)
587 tet_nodes[n] = nodes[ids[n]];
590 materials.push_back(region);
597 const std::string& file_name,
599 const std::string& geo_name,
600 const std::vector<GeoLib::Point>& attribute_points)
602 std::vector<GeoLib::Point*>
const*
const points =
604 std::vector<GeoLib::Surface*>
const*
const surfaces =
607 if (points ==
nullptr)
609 ERR(
"Geometry {:s} not found.", geo_name);
612 if (surfaces ==
nullptr)
614 WARN(
"No surfaces found for geometry {:s}. Writing points only.",
618 std::ofstream out(file_name.c_str(), std::ios::out);
619 out.precision(std::numeric_limits<double>::max_digits10);
621 const std::size_t nPoints(points->size());
622 out << nPoints <<
" 3\n";
624 for (std::size_t i = 0; i < nPoints; ++i)
626 out << i <<
" " << (*(*points)[i])[0] <<
" " << (*(*points)[i])[1]
627 <<
" " << (*(*points)[i])[2] <<
"\n";
630 const std::size_t nSurfaces = (surfaces) ? surfaces->size() : 0;
631 std::size_t nTotalTriangles(0);
632 for (std::size_t i = 0; i < nSurfaces; ++i)
634 nTotalTriangles += (*surfaces)[i]->getNumberOfTriangles();
636 out << nTotalTriangles <<
" 1\n";
638 for (std::size_t i = 0; i < nSurfaces; ++i)
640 const std::size_t nTriangles((*surfaces)[i]->getNumberOfTriangles());
641 const std::size_t marker(i + 1);
643 for (std::size_t j = 0; j < nTriangles; ++j)
646 out <<
"3 " << tri[0] <<
" " << tri[1] <<
" " << tri[2] <<
" "
652 if (attribute_points.empty())
658 const std::size_t nAttributePoints(attribute_points.size());
659 out << nAttributePoints <<
"\n";
660 for (std::size_t i = 0; i < nAttributePoints; ++i)
662 out << i + 1 <<
" " << attribute_points[i][0] <<
" "
663 << attribute_points[i][1] <<
" " << attribute_points[i][2]
664 <<
" " << 10 * attribute_points[i].getID() <<
"\n";
668 "TetGenInterface::writeTetGenSmesh() - {:d} points and {:d} surfaces "
669 "successfully written.",
677 const std::string& file_name,
679 std::vector<MeshLib::Node>& attribute_points)
const
686 const std::vector<MeshLib::Node*>& nodes = mesh.
getNodes();
688 std::ofstream out(file_name.c_str(), std::ios::out);
689 out.precision(std::numeric_limits<double>::max_digits10);
691 const std::size_t nPoints(nodes.size());
692 out << nPoints <<
" 3\n";
694 for (std::size_t i = 0; i < nPoints; ++i)
696 out << i <<
" " << (*nodes[i])[0] <<
" " << (*nodes[i])[1] <<
" "
697 << (*nodes[i])[2] <<
"\n";
712 if (attribute_points.empty())
718 const std::size_t nAttributePoints(attribute_points.size());
719 out << nAttributePoints <<
"\n";
720 for (std::size_t i = 0; i < nAttributePoints; ++i)
722 out << i + 1 <<
" " << attribute_points[i][0] <<
" "
723 << attribute_points[i][1] <<
" " << attribute_points[i][2]
724 <<
" " << 10 * attribute_points[i].getID() <<
"\n";
729 "TetGenInterface::writeTetGenPoly() - {:d} points and {:d} surfaces "
730 "successfully written.",
743 std::size_t
const n_tri =
747 std::size_t
const n_quad =
751 unsigned const nTotalTriangles = n_tri + 2 * n_quad;
752 out << nTotalTriangles <<
" 1\n";
754 const std::vector<MeshLib::Element*>& elements = mesh.
getElements();
759 const std::size_t nElements(elements.size());
760 unsigned element_count(0);
761 for (std::size_t i = 0; i < nElements; ++i)
763 std::string
const matId = mat_ids ? std::to_string((*mat_ids)[i]) :
"";
771 std::vector<MeshLib::Node>& attribute_points)
const
773 const std::vector<MeshLib::Element*>& elements = mesh.
getElements();
774 const std::size_t nElements(elements.size());
775 if (!attribute_points.empty())
777 attribute_points.clear();
782 const std::streamoff before_elems_pos(out.tellp());
783 const unsigned n_spaces(
784 static_cast<unsigned>(std::floor(log(nElements * 8))) + 1);
785 out << std::string(n_spaces,
' ') <<
" 1\n";
786 auto const*
const materialIds =
788 unsigned element_count(0);
789 for (std::size_t i = 0; i < nElements; ++i)
791 if (elements[i]->getDimension() < 3)
796 const unsigned nFaces(elements[i]->getNumberOfNeighbors());
797 std::string
const mat_id_str =
798 materialIds ? std::to_string((*materialIds)[i]) :
"";
799 for (std::size_t j = 0; j < nFaces; ++j)
803 if (neighbor && materialIds &&
804 (*materialIds)[i] <= (*materialIds)[neighbor->
getID()])
809 std::unique_ptr<MeshLib::Element const>
const face(
810 elements[i]->getFace(j));
815 attribute_points.emplace_back(
821 const std::streamoff after_elems_pos(out.tellp());
822 out.seekp(before_elems_pos);
823 out << element_count;
824 out.seekp(after_elems_pos);
829 unsigned& element_count,
830 std::string
const& matId)
835 out <<
"3 " << getNodeIndex(element, 0) <<
" "
836 << getNodeIndex(element, 1) <<
" " << getNodeIndex(element, 2)
837 <<
" " << matId <<
" # " << element_count <<
"\n";
841 out <<
"3 " << getNodeIndex(element, 0) <<
" "
842 << getNodeIndex(element, 1) <<
" " << getNodeIndex(element, 2)
843 <<
" " << matId <<
" # " << element_count <<
"\n";
845 out <<
"3 " << getNodeIndex(element, 0) <<
" "
846 << getNodeIndex(element, 2) <<
" " << getNodeIndex(element, 3)
847 <<
" " << matId <<
" # " << element_count <<
"\n";
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
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 ®ion_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)
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.
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
A Surface is represented by Triangles. It consists of a reference to a vector of (pointers to) points...
std::map< std::string, std::size_t > NameIdMap
Class Triangle consists of a reference to a point vector and a vector that stores the indices in the ...
virtual MeshElemType getGeomType() const =0
std::size_t getID() const
Returns the ID of the element.
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Properties & getProperties()
std::size_t getNumberOfElements() const
Get the number of elements.
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
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
constexpr void assign(R &&r)
void simplify(std::string &str)
std::string getFileExtension(const std::string &path)
void cleanupVectorElements(std::vector< T * > &items)
std::string extractBaseNameWithoutExtension(std::string const &pathname)
std::vector< std::string > splitString(std::string const &str)
T str2number(const std::string &str)
auto constructPointsFromNodes(std::vector< MeshLib::Node * > nodes)
TemplateElement< MeshLib::TetRule4 > Tet
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.