18#include <range/v3/algorithm/copy.hpp>
19#include <range/v3/range/conversion.hpp>
20#include <range/v3/view/transform.hpp>
37 if ((id1 == 0 && id2 == 1) || (id1 == 1 && id2 == 0))
41 if ((id1 == 1 && id2 == 2) || (id1 == 2 && id2 == 1))
45 if ((id1 == 0 && id2 == 2) || (id1 == 2 && id2 == 0))
49 if ((id1 == 3 && id2 == 4) || (id1 == 4 && id2 == 3))
53 if ((id1 == 4 && id2 == 5) || (id1 == 5 && id2 == 4))
57 if ((id1 == 3 && id2 == 5) || (id1 == 5 && id2 == 3))
61 return std::numeric_limits<unsigned>::max();
67template <
typename ElementType>
69 std::span<MeshLib::Node* const>
const element_nodes,
70 std::vector<MeshLib::Node*>
const& nodes,
71 std::array<std::size_t, ElementType::n_all_nodes>
const local_ids)
74 auto lookup_in = [](
auto const& values)
76 return ranges::views::transform([&values](std::size_t
const n)
77 {
return values[n]; });
80 std::array<MeshLib::Node*, ElementType::n_all_nodes> new_nodes;
81 ranges::copy(local_ids | lookup_in(element_nodes) | ids | lookup_in(nodes),
84 return std::make_unique<ElementType>(new_nodes);
89 std::vector<MeshLib::Node*>
const& nodes,
90 std::vector<MeshLib::Element*>& new_elements)
92 std::array<std::size_t, 3>
const tri1_node_ids{0, 1, 2};
93 new_elements.push_back(
94 createElement<MeshLib::Tri>(quad->
nodes(), nodes, tri1_node_ids)
97 std::array<std::size_t, 3>
const tri2_node_ids{0, 2, 3};
98 new_elements.push_back(
99 createElement<MeshLib::Tri>(quad->
nodes(), nodes, tri2_node_ids)
107 std::vector<MeshLib::Node*>
const& nodes,
108 std::vector<MeshLib::Element*>& new_elements)
110 auto addTetrahedron =
111 [&prism, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
113 new_elements.push_back(
117 addTetrahedron({0, 1, 2, 3});
118 addTetrahedron({3, 2, 4, 5});
119 addTetrahedron({2, 1, 3, 4});
126 std::vector<MeshLib::Node*>
const& nodes,
127 std::vector<MeshLib::Element*>& new_elements)
142 std::vector<MeshLib::Node*>
const& nodes,
143 std::vector<MeshLib::Element*>& new_elements)
145 auto addTetrahedron =
146 [&pyramid, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
148 new_elements.push_back(
153 addTetrahedron({0, 1, 2, 4});
154 addTetrahedron({0, 2, 3, 4});
162 const std::vector<MeshLib::Node*>& nodes)
164 std::array<std::size_t, 2> line_node_ids = {0, 0};
169 line_node_ids[1] = i;
173 assert(line_node_ids[1] != 0);
181 const std::vector<MeshLib::Node*>& nodes)
187 std::array<MeshLib::Node*, 3> tri_nodes;
189 tri_nodes[2] =
nullptr;
192 if (element->
getNode(i)->
getID() != tri_nodes[0]->getID())
197 if (element->
getNode(j)->
getID() != tri_nodes[1]->getID())
209 assert(tri_nodes[2] !=
nullptr);
217 std::vector<MeshLib::Node*>
const& nodes,
218 unsigned const min_elem_dim = 1)
220 std::array<MeshLib::Node*, 4> new_nodes;
222 new_nodes[count++] = nodes[element->
getNode(0)->
getID()];
229 bool unique_node(
true);
230 for (
unsigned j = 0; j < i; ++j)
240 new_nodes[count++] = nodes[element->
getNode(i)->
getID()];
246 *new_nodes[2], *new_nodes[3]));
247 if (isQuad && min_elem_dim < 3)
250 for (
unsigned i = 1; i < 3; ++i)
259 new_nodes[i + 1] = new_nodes[i];
276 unsigned const n_unique_nodes,
277 std::vector<MeshLib::Node*>
const& nodes,
278 std::vector<MeshLib::Element*>& new_elements,
279 unsigned const min_elem_dim)
281 if (n_unique_nodes == 4)
287 new_elements.push_back(elem);
290 else if (n_unique_nodes == 3 && min_elem_dim < 3)
294 else if (n_unique_nodes == 2 && min_elem_dim == 1)
304 unsigned const n_unique_nodes,
305 std::vector<MeshLib::Node*>
const& nodes,
306 std::vector<MeshLib::Element*>& new_elements,
307 unsigned const min_elem_dim)
309 auto addTetrahedron =
310 [&org_elem, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
312 new_elements.push_back(
324 if (n_unique_nodes == 5)
326 for (
unsigned i = 0; i < 5; ++i)
328 for (
unsigned j = i + 1; j < 6; ++j)
337 {(i + 1) % 3, (i + 2) % 3, i, (i + 1) % 3 + 3});
339 {(i + 1) % 3 + 3, (i + 2) % 3, i, (i + 2) % 3 + 3});
344 const unsigned i_offset = (i > 2) ? i - 3 : i + 3;
345 const unsigned j_offset = (i > 2) ? j - 3 : j + 3;
347 if (k == std::numeric_limits<unsigned>::max())
349 ERR(
"Unexpected error during prism reduction.");
352 const unsigned k_offset = (i > 2) ? k - 3 : k + 3;
354 addTetrahedron({i_offset, j_offset, k_offset, i});
363 const unsigned l_offset = (i > 2) ? l - 3 : l + 3;
364 addTetrahedron({l_offset, k_offset, i, k});
370 else if (n_unique_nodes == 4)
376 new_elements.push_back(elem);
379 else if (n_unique_nodes == 3 && min_elem_dim < 3)
383 else if (n_unique_nodes == 2 && min_elem_dim == 1)
394 if (id1 == 0 && id2 == 1)
398 if (id1 == 1 && id2 == 2)
402 if (id1 == 2 && id2 == 3)
406 if (id1 == 3 && id2 == 0)
410 if (id1 == 4 && id2 == 5)
414 if (id1 == 5 && id2 == 6)
418 if (id1 == 6 && id2 == 7)
422 if (id1 == 7 && id2 == 4)
426 if (id1 == 0 && id2 == 4)
430 if (id1 == 1 && id2 == 5)
434 if (id1 == 2 && id2 == 6)
438 if (id1 == 3 && id2 == 7)
442 if (id1 == 1 && id2 == 0)
446 if (id1 == 2 && id2 == 1)
450 if (id1 == 3 && id2 == 2)
454 if (id1 == 0 && id2 == 3)
458 if (id1 == 5 && id2 == 4)
462 if (id1 == 6 && id2 == 5)
466 if (id1 == 7 && id2 == 6)
470 if (id1 == 4 && id2 == 7)
474 if (id1 == 4 && id2 == 0)
478 if (id1 == 5 && id2 == 1)
482 if (id1 == 6 && id2 == 2)
486 if (id1 == 7 && id2 == 3)
492 "lutHexCuttingQuadNodes() for nodes {} and {} does not have a valid "
501 constexpr std::array<unsigned, 8> hex_diametral_node_ids = {
502 {6, 7, 4, 5, 2, 3, 0, 1}};
504 return hex_diametral_node_ids[id];
550 return {std::numeric_limits<unsigned>::max(),
551 std::numeric_limits<unsigned>::max()};
557 std::array<std::size_t, 4>
const& base_node_ids)
560 for (std::size_t i = 0; i < nNodes; ++i)
562 bool top_node =
true;
563 for (
unsigned j = 0; j < 4; ++j)
575 return std::numeric_limits<unsigned>::max();
583 unsigned const n_unique_nodes,
584 std::vector<MeshLib::Node*>
const& nodes,
585 std::vector<MeshLib::Element*>& new_elements,
586 unsigned const min_elem_dim)
592 if (n_unique_nodes == 7)
595 for (
unsigned i = 0; i < 7; ++i)
597 for (
unsigned j = i + 1; j < 8; ++j)
602 const std::array<unsigned, 4> base_node_ids(
604 std::array<std::size_t, 5>
const pyr_node_ids = {
605 base_node_ids[0], base_node_ids[1], base_node_ids[2],
606 base_node_ids[3], i};
607 new_elements.push_back(
616 std::array<std::size_t, 6>
const prism_node_ids{
617 base_node_ids[0], base_node_ids[3],
620 new_elements.push_back(
629 else if (n_unique_nodes == 6)
632 for (
unsigned i = 0; i < 6; ++i)
638 std::array<std::size_t, 6>
const prism_node_ids{
640 getNodeIDinElement(*org_elem, face->
getNode(0))),
642 getNodeIDinElement(*org_elem, face->
getNode(1))),
643 getNodeIDinElement(*org_elem, face->
getNode(2)),
645 getNodeIDinElement(*org_elem, face->
getNode(2))),
647 getNodeIDinElement(*org_elem, face->
getNode(3))),
648 getNodeIDinElement(*org_elem, face->
getNode(0))};
650 new_elements.push_back(
660 std::array<std::size_t, 6>
const prism_node_ids{
662 getNodeIDinElement(*org_elem, face->
getNode(0))),
664 getNodeIDinElement(*org_elem, face->
getNode(3))),
665 getNodeIDinElement(*org_elem, face->
getNode(2)),
667 getNodeIDinElement(*org_elem, face->
getNode(1))),
669 getNodeIDinElement(*org_elem, face->
getNode(2))),
670 getNodeIDinElement(*org_elem, face->
getNode(0))};
671 new_elements.push_back(
682 for (
unsigned i = 0; i < 7; ++i)
684 for (
unsigned j = i + 1; j < 8; ++j)
689 for (
unsigned k = i; k < 7; ++k)
691 for (
unsigned l = k + 1; l < 8; ++l)
693 if (!(i == k && j == l) && org_elem->
isEdge(i, j) &&
698 const std::pair<unsigned, unsigned> back(
701 std::numeric_limits<unsigned>::max() ||
703 std::numeric_limits<unsigned>::max())
705 ERR(
"Unexpected error during Hex "
710 std::array<unsigned, 4>
const cutting_plane(
713 std::array<std::size_t, 6>
const pris1_node_ids{
714 back.first, cutting_plane[0],
715 cutting_plane[3], back.second,
716 cutting_plane[1], cutting_plane[2]};
718 org_elem->
nodes(), nodes, pris1_node_ids);
719 unsigned nNewElements =
721 new_elements, min_elem_dim);
723 std::array<std::size_t, 6>
const pris2_node_ids{
731 org_elem->
nodes(), nodes, pris2_node_ids);
734 new_elements, min_elem_dim);
743 else if (n_unique_nodes == 5)
746 std::array<std::size_t, 4>
const first_four_node_ids = {
749 unsigned const fifth_node =
752 bool tet_changed(
false);
757 std::array
const tet1_nodes = {
758 nodes[first_four_node_ids[0]], nodes[first_four_node_ids[1]],
759 nodes[first_four_node_ids[2]],
765 new_elements.push_back(tet1);
768 std::array
const tet2_nodes = {
769 (tet_changed) ? nodes[first_four_node_ids[0]]
770 : nodes[first_four_node_ids[1]],
771 nodes[first_four_node_ids[2]], nodes[first_four_node_ids[3]],
776 else if (n_unique_nodes == 4)
782 new_elements.push_back(elem);
786 else if (n_unique_nodes == 3 && min_elem_dim < 3)
791 else if (min_elem_dim == 1)
807 std::vector<MeshLib::Node*>
const& nodes,
808 std::vector<MeshLib::Element*>& elements)
832 unsigned const n_unique_nodes,
833 std::vector<MeshLib::Node*>
const& nodes,
834 std::vector<MeshLib::Element*>& elements,
835 unsigned const min_elem_dim)
849 if (n_unique_nodes == 3 && min_elem_dim < 3)
853 else if (min_elem_dim == 1)
861 return reduceHex(element, n_unique_nodes, nodes, elements,
866 reducePyramid(element, n_unique_nodes, nodes, elements, min_elem_dim);
871 return reducePrism(element, n_unique_nodes, nodes, elements,
875 ERR(
"Unknown element type.");
883 unsigned count(nNodes);
885 for (
unsigned i = 0; i < nNodes - 1; ++i)
887 for (
unsigned j = i + 1; j < nNodes; ++j)
901 std::vector<T>
const& old_prop,
902 std::vector<size_t>
const& node_ids)
904 std::size_t
const n_nodes = node_ids.size();
905 for (std::size_t i = 0; i < n_nodes; ++i)
907 if (node_ids[i] != i)
911 new_prop.push_back(old_prop[i]);
917 std::vector<T>
const& old_prop,
918 std::vector<size_t>
const& elem_ids)
920 std::transform(elem_ids.cbegin(), elem_ids.cend(),
921 std::back_inserter(new_prop),
922 [&](std::size_t
const i) { return old_prop[i]; });
929 std::vector<std::size_t>
const& node_ids,
930 std::vector<std::size_t>
const& elem_ids)
935 for (
auto name : prop_names)
997 WARN(
"PropertyVector {:s} not being converted.", name);
999 return new_properties;
1010 std::size_t
const nNodes = id_map.size();
1012 for (std::size_t i = 0; i < nNodes; ++i)
1024 unsigned const min_elem_dim)
const
1033 std::vector<MeshLib::Node*> new_nodes =
1035 std::vector<MeshLib::Element*> new_elements;
1036 std::vector<std::size_t> element_ids;
1038 for (std::size_t k(0); k < elements.size(); ++k)
1041 unsigned const n_unique_nodes(getNumberOfUniqueNodes(elem));
1048 std::size_t
const n_new_elements(
1049 subdivideElement(elem, new_nodes, new_elements));
1050 if (n_new_elements == 0)
1052 ERR(
"Element {:d} has unknown element type.", k);
1057 element_ids.insert(element_ids.end(), n_new_elements, k);
1062 element_ids.push_back(k);
1065 else if (n_unique_nodes < elem->getNumberOfBaseNodes() &&
1068 std::size_t
const n_new_elements(reduceElement(
1069 elem, n_unique_nodes, new_nodes, new_elements, min_elem_dim));
1070 element_ids.insert(element_ids.end(), n_new_elements, k);
1074 ERR(
"Something is wrong, more unique nodes than actual nodes");
1080 copyProperties(props, node_ids, element_ids);
1083 if (!new_elements.empty())
1085 return new MeshLib::Mesh(new_mesh_name, new_nodes, new_elements,
1095 double const eps)
const
1099 std::vector<std::size_t> id_map(nNodes);
1100 const double half_eps(eps / 2.0);
1101 const double sqr_eps(eps * eps);
1102 std::iota(id_map.begin(), id_map.end(), 0);
1106 for (std::size_t k = 0; k < nNodes; ++k)
1109 if (node->
getID() != k)
1113 std::vector<std::vector<MeshLib::Node*>
const*>
const node_vectors(
1116 const std::size_t nVectors(node_vectors.size());
1117 for (std::size_t i = 0; i < nVectors; ++i)
1119 const std::vector<MeshLib::Node*>& cell_vector(*node_vectors[i]);
1120 const std::size_t nGridCellNodes(cell_vector.size());
1121 for (std::size_t j = 0; j < nGridCellNodes; ++j)
1126 if (id_map[node->
getID()] == id_map[test_node->
getID()])
1134 if (test_node->
getID() != id_map[test_node->
getID()])
1151 const std::vector<std::size_t>& id_map)
const
1154 const std::size_t nNodes(nodes.size());
1155 std::vector<MeshLib::Node*> new_nodes;
1156 new_nodes.reserve(nNodes);
1157 for (std::size_t k = 0; k < nNodes; ++k)
1161 if (nodes[k]->getID() == id_map[k])
1163 std::size_t
const id(new_nodes.size());
1165 (*nodes[k])[0], (*nodes[k])[1], (*nodes[k])[2],
id));
1166 nodes[k]->setID(
id);
1173 nodes[k]->setID(nodes[id_map[k]]->getID());
Definition of Duplicate functions.
Definition of the Grid class.
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition of the class Properties that implements a container of properties.
Definition of the MeshRevision class.
Definition of the Mesh class.
Collects error flags for mesh elements.
std::vector< std::vector< POINT * > const * > getPntVecsOfGridCellsIntersectingCube(P const ¢er, double half_len) const
std::size_t getID() const
virtual MeshElemType getGeomType() const =0
virtual ElementErrorCode validate() const =0
virtual const Element * getFace(unsigned i) const =0
Returns the i-th face of the element.
virtual unsigned getNumberOfBaseNodes() const =0
virtual const Node * getNode(unsigned idx) const =0
virtual bool isEdge(unsigned i, unsigned j) const =0
Returns true if these two indices form an edge and false otherwise.
virtual constexpr unsigned getDimension() const =0
Get dimension of the mesh element.
constexpr std::span< Node *const > nodes() const
Span of element's nodes, their pointers actually.
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.
void resetNodeIDs()
Resets the IDs of all mesh-nodes to their position in the node vector.
Properties & getProperties()
std::size_t getNumberOfNodes() const
Get the number of nodes.
std::size_t getNumberOfElements() const
Get the number of elements.
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
std::vector< std::string > getPropertyVectorNames() const
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 cleanupVectorElements(std::vector< T * > &items)
bool isCoplanar(const MathLib::Point3d &a, const MathLib::Point3d &b, const MathLib::Point3d &c, const MathLib::Point3d &d)
Checks if the four given points are located on a plane.
double sqrDist(MathLib::Point3d const &p0, MathLib::Point3d const &p1)
MeshLib specific, lazy, non-owning, non-mutating, composable range views.
TemplateElement< MeshLib::TetRule4 > Tet
TemplateElement< MeshLib::TriRule3 > Tri
Element * copyElement(Element const *const element, const std::vector< Node * > &nodes, std::vector< std::size_t > const *const id_map)
std::size_t reduceElement(MeshLib::Element const *const element, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elements, unsigned const min_elem_dim)
unsigned lutHexDiametralNode(unsigned const id)
MeshLib::Element * constructTri(MeshLib::Element const *const element, const std::vector< MeshLib::Node * > &nodes)
MeshLib::Element * constructLine(MeshLib::Element const *const element, const std::vector< MeshLib::Node * > &nodes)
unsigned reduceHex(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
unsigned reducePrism(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
unsigned getNumberOfUniqueNodes(MeshLib::Element const *const element)
unsigned subdivideHex(MeshLib::Element const *const hex, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a Hex with nonplanar faces into tets.
std::unique_ptr< MeshLib::Element > createElement(std::span< MeshLib::Node *const > const element_nodes, std::vector< MeshLib::Node * > const &nodes, std::array< std::size_t, ElementType::n_all_nodes > const local_ids)
std::size_t subdivideElement(MeshLib::Element const *const element, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &elements)
void reducePyramid(MeshLib::Element const *const org_elem, unsigned const n_unique_nodes, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements, unsigned const min_elem_dim)
MeshLib::Properties copyProperties(MeshLib::Properties const &props, std::vector< std::size_t > const &node_ids, std::vector< std::size_t > const &elem_ids)
unsigned subdividePrism(MeshLib::Element const *const prism, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a prism with nonplanar quad faces into two tets.
std::array< unsigned, 4 > lutHexCuttingQuadNodes(unsigned id1, unsigned id2)
std::pair< unsigned, unsigned > lutHexBackNodes(unsigned const i, unsigned const j, unsigned const k, unsigned const l)
unsigned subdividePyramid(MeshLib::Element const *const pyramid, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a pyramid with a nonplanar base into two tets.
unsigned findPyramidTopNode(MeshLib::Element const &element, std::array< std::size_t, 4 > const &base_node_ids)
MeshLib::Element * constructFourNodeElement(MeshLib::Element const *const element, std::vector< MeshLib::Node * > const &nodes, unsigned const min_elem_dim=1)
unsigned subdivideQuad(MeshLib::Element const *const quad, std::vector< MeshLib::Node * > const &nodes, std::vector< MeshLib::Element * > &new_elements)
Subdivides a nonplanar quad into two triangles.
void fillElemProperty(std::vector< T > &new_prop, std::vector< T > const &old_prop, std::vector< size_t > const &elem_ids)
void fillNodeProperty(std::vector< T > &new_prop, std::vector< T > const &old_prop, std::vector< size_t > const &node_ids)