19#include <range/v3/numeric/accumulate.hpp>
38 std::vector<GeoLib::Point*> points;
39 points.reserve(nodes.size());
40 std::transform(nodes.begin(), nodes.end(), std::back_inserter(points),
42 { return new GeoLib::Point(*node, node->getID()); });
49 std::ifstream poly_stream(geo_fname.c_str());
53 ERR(
"TetGenInterface::readTetGenGeometry() failed to open {:s}",
60 ERR(
"TetGenInterface::readTetGenGeometry() - unknown file type (only "
61 "*.smesh is supported).");
65 std::vector<MeshLib::Node*> nodes;
76 geo_objects.
addPointVec(std::move(points), geo_name);
77 const std::vector<std::size_t>& id_map(
80 std::vector<GeoLib::Surface*> surfaces;
98 std::getline(input, line);
101 ERR(
"TetGenInterface::getNFacets(): Error reading number of "
107 if (line.empty() || line.compare(0, 1,
"#") == 0)
113 auto it = fields.begin();
115 if (fields.size() > 1)
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)
130 const std::size_t nFacets(this->
getNFacets(input));
132 surfaces.reserve(nFacets);
133 std::list<std::string>::const_iterator it;
136 std::vector<std::size_t> idx_map;
139 while (k < nFacets && !input.fail())
141 std::getline(input, line);
144 ERR(
"TetGenInterface::parseFacets(): Error reading facet {:d}.", k);
149 if (line.empty() || line.compare(0, 1,
"#") == 0)
155 const std::list<std::string> point_fields =
157 it = point_fields.begin();
161 ERR(
"Smesh-files are currently only supported for triangle "
165 const std::size_t point_field_size =
167 if (point_fields.size() > point_field_size)
169 std::vector<std::size_t> point_ids;
170 for (std::size_t j(0); j < nPoints; ++j)
177 const std::size_t sfc_marker =
180 const std::size_t idx =
181 std::find(idx_map.begin(), idx_map.end(), sfc_marker) -
183 if (idx >= surfaces.size())
185 idx_map.push_back(sfc_marker);
188 surfaces[idx]->addTriangle(point_ids[0], point_ids[1],
193 ERR(
"TetGenInterface::parseFacets(): Error reading points for "
205 auto const nTotalTriangles = ranges::accumulate(
206 surfaces, std::size_t{0}, {},
207 [](
auto const* surface) {
return surface->getNumberOfTriangles(); });
208 if (nTotalTriangles == nFacets)
213 ERR(
"TetGenInterface::parseFacets(): Number of expected total triangles "
214 "({:d}) does not match number of found triangles ({:d}).",
221 std::string
const& ele_fname)
223 std::ifstream ins_nodes(nodes_fname.c_str());
224 std::ifstream ins_ele(ele_fname.c_str());
226 if (!ins_nodes || !ins_ele)
230 ERR(
"TetGenInterface::readTetGenMesh failed to open {:s}",
235 ERR(
"TetGenInterface::readTetGenMesh failed to open {:s}",
241 std::vector<MeshLib::Node*> nodes;
249 std::vector<MeshLib::Element*> elements;
250 std::vector<int> materials;
259 if (std::any_of(materials.cbegin(), materials.cend(),
260 [](
int m) { return m != 0; }))
264 mat_props->reserve(elements.size());
265 std::copy(materials.cbegin(),
267 std::back_inserter(*mat_props));
270 const std::string mesh_name(
277 std::vector<MeshLib::Node*>& nodes)
280 std::getline(ins, line);
283 std::size_t n_attributes;
284 bool boundary_markers;
289 if (line.empty() || line.compare(0, 1,
"#") == 0)
292 std::getline(ins, line);
297 n_attributes, boundary_markers);
312 std::size_t& n_nodes,
314 std::size_t& n_attributes,
315 bool& boundary_markers)
318 if (pnt_header.empty())
320 ERR(
"TetGenInterface::parseNodesFileHeader(): could not read number of "
321 "nodes specified in header.");
324 auto it = pnt_header.begin();
326 dim = (pnt_header.size() == 1) ? 3
329 if (pnt_header.size() < 4)
332 boundary_markers =
false;
337 boundary_markers = *(++it) ==
"1";
343 std::vector<MeshLib::Node*>& nodes,
348 nodes.reserve(n_nodes);
351 while (k < n_nodes && !ins.fail())
353 std::vector<double> coordinates(dim);
354 std::getline(ins, line);
357 ERR(
"TetGenInterface::parseNodes(): Error reading node {:d}.", k);
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);
366 if (line.empty() || pos_beg == pos_end ||
367 line.compare(pos_beg, 1,
"#") == 0)
372 if (pos_beg != std::string::npos && pos_end != std::string::npos)
375 line.substr(pos_beg, pos_end - pos_beg));
376 if (k == 0 &&
id == 0)
383 ERR(
"TetGenInterface::parseNodes(): Error reading ID of node {:d}.",
389 for (std::size_t i(0); i < dim; i++)
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)
395 pos_end = line.size();
397 if (pos_beg != std::string::npos)
400 line.substr(pos_beg, pos_end - pos_beg));
404 ERR(
"TetGenInterface::parseNodes(): error reading coordinate "
405 "{:d} of node {:d}.",
412 nodes.push_back(
new MeshLib::Node(coordinates.data(),
id - offset));
423 std::vector<MeshLib::Element*>& elements,
424 std::vector<int>& materials,
425 const std::vector<MeshLib::Node*>& nodes)
const
428 std::getline(ins, line);
430 std::size_t n_nodes_per_tet;
431 bool region_attributes;
436 if (line.empty() || line.compare(0, 1,
"#") == 0)
439 std::getline(ins, line);
445 line, n_tets, n_nodes_per_tet, region_attributes);
467 std::size_t& n_nodes_per_tet,
468 bool& region_attribute)
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)
479 line.substr(pos_beg, pos_end - pos_beg));
483 ERR(
"TetGenInterface::parseElementsFileHeader(): Could not read number "
484 "of tetrahedra specified in header.");
488 pos_beg = line.find_first_not_of(
" \t", pos_end);
489 pos_end = line.find_first_of(
" \t", pos_beg);
491 line.substr(pos_beg, pos_end - pos_beg));
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)
497 pos_end = line.size();
499 region_attribute = line.substr(pos_beg, pos_end - pos_beg) ==
"1";
505 std::vector<MeshLib::Element*>& elements,
506 std::vector<int>& materials,
507 const std::vector<MeshLib::Node*>& nodes,
509 std::size_t n_nodes_per_tet,
510 bool region_attribute)
const
513 std::vector<std::size_t> ids(n_nodes_per_tet);
515 elements.reserve(n_tets);
516 materials.reserve(n_tets);
519 for (std::size_t k(0); k < n_tets && !ins.fail(); k++)
521 std::getline(ins, line);
524 ERR(
"TetGenInterface::parseElements(): Error reading tetrahedron "
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);
534 if (line.empty() || pos_beg == pos_end ||
535 line.compare(pos_beg, 1,
"#") == 0)
541 if (pos_beg == std::string::npos || pos_end == std::string::npos)
543 ERR(
"TetGenInterface::parseElements(): Error reading id of "
550 for (std::size_t i(0); i < n_nodes_per_tet; i++)
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)
556 pos_end = line.size();
558 if (pos_beg != std::string::npos && pos_end != std::string::npos)
561 line.substr(pos_beg, pos_end - pos_beg)) -
566 ERR(
"TetGenInterface::parseElements(): Error reading node {:d} "
567 "of tetrahedron {:d}.",
576 if (region_attribute)
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)
582 pos_end = line.size();
584 if (pos_beg != std::string::npos && pos_end != std::string::npos)
587 line.substr(pos_beg, pos_end - pos_beg));
591 ERR(
"TetGenInterface::parseElements(): Error reading region "
592 "attribute of tetrahedron {:d}.",
599 for (
int n = 0; n < 4; n++)
601 tet_nodes[n] = nodes[ids[n]];
604 materials.push_back(region);
611 const std::string& file_name,
613 const std::string& geo_name,
614 const std::vector<GeoLib::Point>& attribute_points)
616 std::vector<GeoLib::Point*>
const*
const points =
618 std::vector<GeoLib::Surface*>
const*
const surfaces =
621 if (points ==
nullptr)
623 ERR(
"Geometry {:s} not found.", geo_name);
626 if (surfaces ==
nullptr)
628 WARN(
"No surfaces found for geometry {:s}. Writing points only.",
632 std::ofstream out(file_name.c_str(), std::ios::out);
633 out.precision(std::numeric_limits<double>::max_digits10);
635 const std::size_t nPoints(points->size());
636 out << nPoints <<
" 3\n";
638 for (std::size_t i = 0; i < nPoints; ++i)
640 out << i <<
" " << (*(*points)[i])[0] <<
" " << (*(*points)[i])[1]
641 <<
" " << (*(*points)[i])[2] <<
"\n";
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)
648 nTotalTriangles += (*surfaces)[i]->getNumberOfTriangles();
650 out << nTotalTriangles <<
" 1\n";
652 for (std::size_t i = 0; i < nSurfaces; ++i)
654 const std::size_t nTriangles((*surfaces)[i]->getNumberOfTriangles());
655 const std::size_t marker(i + 1);
657 for (std::size_t j = 0; j < nTriangles; ++j)
660 out <<
"3 " << tri[0] <<
" " << tri[1] <<
" " << tri[2] <<
" "
666 if (attribute_points.empty())
672 const std::size_t nAttributePoints(attribute_points.size());
673 out << nAttributePoints <<
"\n";
674 for (std::size_t i = 0; i < nAttributePoints; ++i)
676 out << i + 1 <<
" " << attribute_points[i][0] <<
" "
677 << attribute_points[i][1] <<
" " << attribute_points[i][2]
678 <<
" " << 10 * attribute_points[i].getID() <<
"\n";
682 "TetGenInterface::writeTetGenSmesh() - {:d} points and {:d} surfaces "
683 "successfully written.",
691 const std::string& file_name,
693 std::vector<MeshLib::Node>& attribute_points)
const
700 const std::vector<MeshLib::Node*>& nodes = mesh.
getNodes();
702 std::ofstream out(file_name.c_str(), std::ios::out);
703 out.precision(std::numeric_limits<double>::max_digits10);
705 const std::size_t nPoints(nodes.size());
706 out << nPoints <<
" 3\n";
708 for (std::size_t i = 0; i < nPoints; ++i)
710 out << i <<
" " << (*nodes[i])[0] <<
" " << (*nodes[i])[1] <<
" "
711 << (*nodes[i])[2] <<
"\n";
726 if (attribute_points.empty())
732 const std::size_t nAttributePoints(attribute_points.size());
733 out << nAttributePoints <<
"\n";
734 for (std::size_t i = 0; i < nAttributePoints; ++i)
736 out << i + 1 <<
" " << attribute_points[i][0] <<
" "
737 << attribute_points[i][1] <<
" " << attribute_points[i][2]
738 <<
" " << 10 * attribute_points[i].getID() <<
"\n";
743 "TetGenInterface::writeTetGenPoly() - {:d} points and {:d} surfaces "
744 "successfully written.",
757 std::size_t
const n_tri =
761 std::size_t
const n_quad =
765 unsigned const nTotalTriangles = n_tri + 2 * n_quad;
766 out << nTotalTriangles <<
" 1\n";
768 const std::vector<MeshLib::Element*>& elements = mesh.
getElements();
773 const std::size_t nElements(elements.size());
774 unsigned element_count(0);
775 for (std::size_t i = 0; i < nElements; ++i)
777 std::string
const matId = mat_ids ? std::to_string((*mat_ids)[i]) :
"";
785 std::vector<MeshLib::Node>& attribute_points)
const
787 const std::vector<MeshLib::Element*>& elements = mesh.
getElements();
788 const std::size_t nElements(elements.size());
789 if (!attribute_points.empty())
791 attribute_points.clear();
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 =
802 unsigned element_count(0);
803 for (std::size_t i = 0; i < nElements; ++i)
805 if (elements[i]->getDimension() < 3)
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)
817 if (neighbor && materialIds &&
818 (*materialIds)[i] <= (*materialIds)[neighbor->
getID()])
823 std::unique_ptr<MeshLib::Element const>
const face(
824 elements[i]->getFace(j));
829 attribute_points.emplace_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);
843 unsigned& element_count,
844 std::string
const& matId)
849 out <<
"3 " << getNodeIndex(element, 0) <<
" "
850 << getNodeIndex(element, 1) <<
" " << getNodeIndex(element, 2)
851 <<
" " << matId <<
" # " << element_count <<
"\n";
855 out <<
"3 " << getNodeIndex(element, 0) <<
" "
856 << getNodeIndex(element, 1) <<
" " << getNodeIndex(element, 2)
857 <<
" " << matId <<
" # " << element_count <<
"\n";
859 out <<
"3 " << getNodeIndex(element, 0) <<
" "
860 << getNodeIndex(element, 2) <<
" " << getNodeIndex(element, 3)
861 <<
" " << matId <<
" # " << element_count <<
"\n";
Definition of the Element class.
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)
Definition of the Mesh class.
Definition of the Node class.
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 ®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)
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.
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
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)
MathLib::Point3d getCenterOfGravity(Element const &element)
Calculates the center of gravity for the mesh element.