7#include <range/v3/algorithm/copy.hpp>
8#include <range/v3/algorithm/transform.hpp>
9#include <range/v3/range/conversion.hpp>
10#include <range/v3/view/filter.hpp>
11#include <range/v3/view/iota.hpp>
12#include <range/v3/view/transform.hpp>
29 if ((id1 == 0 && id2 == 1) || (id1 == 1 && id2 == 0))
33 if ((id1 == 1 && id2 == 2) || (id1 == 2 && id2 == 1))
37 if ((id1 == 0 && id2 == 2) || (id1 == 2 && id2 == 0))
41 if ((id1 == 3 && id2 == 4) || (id1 == 4 && id2 == 3))
45 if ((id1 == 4 && id2 == 5) || (id1 == 5 && id2 == 4))
49 if ((id1 == 3 && id2 == 5) || (id1 == 5 && id2 == 3))
53 return std::numeric_limits<unsigned>::max();
59template <
typename ElementType>
61 std::span<MeshLib::Node* const>
const element_nodes,
62 std::vector<MeshLib::Node*>
const& nodes,
63 std::array<std::size_t, ElementType::n_all_nodes>
const local_ids)
66 auto lookup_in = [](
auto const& values)
68 return ranges::views::transform([&values](std::size_t
const n)
69 {
return values[n]; });
72 std::array<MeshLib::Node*, ElementType::n_all_nodes> new_nodes{};
73 ranges::copy(local_ids | lookup_in(element_nodes) |
ids | lookup_in(nodes),
76 return std::make_unique<ElementType>(new_nodes);
81 std::vector<MeshLib::Node*>
const& nodes,
82 std::vector<MeshLib::Element*>& new_elements)
84 std::array<std::size_t, 3>
const tri1_node_ids{0, 1, 2};
85 new_elements.push_back(
89 std::array<std::size_t, 3>
const tri2_node_ids{0, 2, 3};
90 new_elements.push_back(
99 std::vector<MeshLib::Node*>
const& nodes,
100 std::vector<MeshLib::Element*>& new_elements)
102 auto addTetrahedron =
103 [&prism, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
105 new_elements.push_back(
109 addTetrahedron({0, 1, 2, 3});
110 addTetrahedron({3, 2, 4, 5});
111 addTetrahedron({2, 1, 3, 4});
118 std::vector<MeshLib::Node*>
const& nodes,
119 std::vector<MeshLib::Element*>& new_elements)
134 std::vector<MeshLib::Node*>
const& nodes,
135 std::vector<MeshLib::Element*>& new_elements)
137 auto addTetrahedron =
138 [&pyramid, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
140 new_elements.push_back(
145 addTetrahedron({0, 1, 2, 4});
146 addTetrahedron({0, 2, 3, 4});
154 const std::vector<MeshLib::Node*>& nodes)
156 std::array<std::size_t, 2> line_node_ids = {0, 0};
161 line_node_ids[1] = i;
165 assert(line_node_ids[1] != 0);
173 const std::vector<MeshLib::Node*>& nodes)
179 std::array<MeshLib::Node*, 3> tri_nodes{};
181 tri_nodes[2] =
nullptr;
184 if (element->
getNode(i)->
getID() != tri_nodes[0]->getID())
189 if (element->
getNode(j)->
getID() != tri_nodes[1]->getID())
201 assert(tri_nodes[2] !=
nullptr);
209 std::vector<MeshLib::Node*>
const& nodes,
210 unsigned const min_elem_dim = 1)
212 std::array<MeshLib::Node*, 4> new_nodes{};
214 new_nodes[count++] = nodes[element->
getNode(0)->
getID()];
221 bool unique_node(
true);
222 for (
unsigned j = 0; j < i; ++j)
232 new_nodes[count++] = nodes[element->
getNode(i)->
getID()];
238 *new_nodes[2], *new_nodes[3]));
239 if (isQuad && min_elem_dim < 3)
242 for (
unsigned i = 1; i < 3; ++i)
251 new_nodes[i + 1] = new_nodes[i];
268 unsigned const n_unique_nodes,
269 std::vector<MeshLib::Node*>
const& nodes,
270 std::vector<MeshLib::Element*>& new_elements,
271 unsigned const min_elem_dim)
273 if (n_unique_nodes == 4)
279 new_elements.push_back(elem);
282 else if (n_unique_nodes == 3 && min_elem_dim < 3)
286 else if (n_unique_nodes == 2 && min_elem_dim == 1)
296 unsigned const n_unique_nodes,
297 std::vector<MeshLib::Node*>
const& nodes,
298 std::vector<MeshLib::Element*>& new_elements,
299 unsigned const min_elem_dim)
301 auto addTetrahedron =
302 [&org_elem, &nodes, &new_elements](std::array<std::size_t, 4>
const ids)
304 new_elements.push_back(
316 if (n_unique_nodes == 5)
318 for (
unsigned i = 0; i < 5; ++i)
320 for (
unsigned j = i + 1; j < 6; ++j)
329 {(i + 1) % 3, (i + 2) % 3, i, (i + 1) % 3 + 3});
331 {(i + 1) % 3 + 3, (i + 2) % 3, i, (i + 2) % 3 + 3});
336 const unsigned i_offset = (i > 2) ? i - 3 : i + 3;
337 const unsigned j_offset = (i > 2) ? j - 3 : j + 3;
339 if (k == std::numeric_limits<unsigned>::max())
341 ERR(
"Unexpected error during prism reduction.");
344 const unsigned k_offset = (i > 2) ? k - 3 : k + 3;
346 addTetrahedron({i_offset, j_offset, k_offset, i});
355 const unsigned l_offset = (i > 2) ? l - 3 : l + 3;
356 addTetrahedron({l_offset, k_offset, i, k});
362 else if (n_unique_nodes == 4)
368 new_elements.push_back(elem);
371 else if (n_unique_nodes == 3 && min_elem_dim < 3)
375 else if (n_unique_nodes == 2 && min_elem_dim == 1)
386 if (id1 == 0 && id2 == 1)
390 if (id1 == 1 && id2 == 2)
394 if (id1 == 2 && id2 == 3)
398 if (id1 == 3 && id2 == 0)
402 if (id1 == 4 && id2 == 5)
406 if (id1 == 5 && id2 == 6)
410 if (id1 == 6 && id2 == 7)
414 if (id1 == 7 && id2 == 4)
418 if (id1 == 0 && id2 == 4)
422 if (id1 == 1 && id2 == 5)
426 if (id1 == 2 && id2 == 6)
430 if (id1 == 3 && id2 == 7)
434 if (id1 == 1 && id2 == 0)
438 if (id1 == 2 && id2 == 1)
442 if (id1 == 3 && id2 == 2)
446 if (id1 == 0 && id2 == 3)
450 if (id1 == 5 && id2 == 4)
454 if (id1 == 6 && id2 == 5)
458 if (id1 == 7 && id2 == 6)
462 if (id1 == 4 && id2 == 7)
466 if (id1 == 4 && id2 == 0)
470 if (id1 == 5 && id2 == 1)
474 if (id1 == 6 && id2 == 2)
478 if (id1 == 7 && id2 == 3)
484 "lutHexCuttingQuadNodes() for nodes {} and {} does not have a valid "
493 constexpr std::array<unsigned, 8> hex_diametral_node_ids = {
494 {6, 7, 4, 5, 2, 3, 0, 1}};
496 return hex_diametral_node_ids[id];
542 return {std::numeric_limits<unsigned>::max(),
543 std::numeric_limits<unsigned>::max()};
549 std::array<std::size_t, 4>
const& base_node_ids)
552 for (std::size_t i = 0; i < nNodes; ++i)
554 bool top_node =
true;
555 for (
unsigned j = 0; j < 4; ++j)
567 return std::numeric_limits<unsigned>::max();
575 unsigned const n_unique_nodes,
576 std::vector<MeshLib::Node*>
const& nodes,
577 std::vector<MeshLib::Element*>& new_elements,
578 unsigned const min_elem_dim)
584 if (n_unique_nodes == 7)
587 for (
unsigned i = 0; i < 7; ++i)
589 for (
unsigned j = i + 1; j < 8; ++j)
594 const std::array<unsigned, 4> base_node_ids(
596 std::array<std::size_t, 5>
const pyr_node_ids = {
597 base_node_ids[0], base_node_ids[1], base_node_ids[2],
598 base_node_ids[3], i};
599 new_elements.push_back(
608 std::array<std::size_t, 6>
const prism_node_ids{
609 base_node_ids[0], base_node_ids[3],
612 new_elements.push_back(
621 else if (n_unique_nodes == 6)
624 for (
unsigned i = 0; i < 6; ++i)
630 std::array<std::size_t, 6>
const prism_node_ids{
642 new_elements.push_back(
652 std::array<std::size_t, 6>
const prism_node_ids{
663 new_elements.push_back(
674 for (
unsigned i = 0; i < 7; ++i)
676 for (
unsigned j = i + 1; j < 8; ++j)
681 for (
unsigned k = i; k < 7; ++k)
683 for (
unsigned l = k + 1; l < 8; ++l)
685 if ((i != k || j != l) && org_elem->
isEdge(i, j) &&
690 const std::pair<unsigned, unsigned> back(
693 std::numeric_limits<unsigned>::max() ||
695 std::numeric_limits<unsigned>::max())
697 ERR(
"Unexpected error during Hex "
702 std::array<unsigned, 4>
const cutting_plane(
705 std::array<std::size_t, 6>
const pris1_node_ids{
706 back.first, cutting_plane[0],
707 cutting_plane[3], back.second,
708 cutting_plane[1], cutting_plane[2]};
710 org_elem->
nodes(), nodes, pris1_node_ids);
711 unsigned nNewElements =
713 new_elements, min_elem_dim);
715 std::array<std::size_t, 6>
const pris2_node_ids{
723 org_elem->
nodes(), nodes, pris2_node_ids);
726 new_elements, min_elem_dim);
735 else if (n_unique_nodes == 5)
738 std::array<std::size_t, 4>
const first_four_node_ids = {
741 unsigned const fifth_node =
744 bool tet_changed(
false);
749 std::array
const tet1_nodes = {
750 nodes[first_four_node_ids[0]], nodes[first_four_node_ids[1]],
751 nodes[first_four_node_ids[2]],
757 new_elements.push_back(tet1);
760 std::array
const tet2_nodes = {
761 (tet_changed) ? nodes[first_four_node_ids[0]]
762 : nodes[first_four_node_ids[1]],
763 nodes[first_four_node_ids[2]], nodes[first_four_node_ids[3]],
768 else if (n_unique_nodes == 4)
774 new_elements.push_back(elem);
778 else if (n_unique_nodes == 3 && min_elem_dim < 3)
783 else if (min_elem_dim == 1)
799 std::vector<MeshLib::Node*>
const& nodes,
800 std::vector<MeshLib::Element*>& elements)
824 unsigned const n_unique_nodes,
825 std::vector<MeshLib::Node*>
const& nodes,
826 std::vector<MeshLib::Element*>& elements,
827 unsigned const min_elem_dim)
841 if (n_unique_nodes == 3 && min_elem_dim < 3)
845 else if (min_elem_dim == 1)
853 return reduceHex(element, n_unique_nodes, nodes, elements,
858 reducePyramid(element, n_unique_nodes, nodes, elements, min_elem_dim);
863 return reducePrism(element, n_unique_nodes, nodes, elements,
867 ERR(
"Unknown element type.");
875 unsigned count(nNodes);
877 for (
unsigned i = 0; i < nNodes - 1; ++i)
879 for (
unsigned j = i + 1; j < nNodes; ++j)
894 std::vector<std::size_t>
const& node_ids)
896 return ranges::views::iota(std::size_t{0}, node_ids.size()) |
897 ranges::views::filter([&node_ids](std::size_t
const i)
898 {
return node_ids[i] == i; }) |
899 ranges::to<std::vector>;
909 std::string
const& name,
911 std::vector<std::size_t>
const& source_ids)
919 name, item_type, source_ids.size(), 1);
920 if (new_prop ==
nullptr)
926 "Could not create the property vector '{:s}' in the revised mesh.",
929 ranges::transform(source_ids, new_prop->begin(),
930 [&old_prop](std::size_t
const i) { return old_prop[i]; });
937template <
typename... Ts>
940 std::string
const& name,
942 std::vector<std::size_t>
const& source_ids)
954 std::vector<std::size_t>
const& node_ids,
955 std::vector<std::size_t>
const& elem_ids)
961 for (
auto const& name : prop_names)
965 surviving_node_ids) &&
970 WARN(
"PropertyVector {:s} not being converted.", name);
973 return new_properties;
984 std::size_t
const nNodes = id_map.size();
986 for (std::size_t i = 0; i < nNodes; ++i)
998 unsigned const min_elem_dim)
const
1000 if (this->
_mesh.getNumberOfElements() == 0)
1005 std::vector<MeshLib::Element*>
const& elements(this->
_mesh.getElements());
1007 std::vector<MeshLib::Node*> new_nodes =
1009 std::vector<MeshLib::Element*> new_elements;
1010 std::vector<std::size_t> element_ids;
1012 for (std::size_t k(0); k < elements.size(); ++k)
1015 unsigned const n_unique_nodes(getNumberOfUniqueNodes(elem));
1022 std::size_t
const n_new_elements(
1023 subdivideElement(elem, new_nodes, new_elements));
1024 if (n_new_elements == 0)
1026 ERR(
"Element {:d} has unknown element type.", k);
1027 _mesh.resetNodeIDs();
1031 element_ids.insert(element_ids.end(), n_new_elements, k);
1036 element_ids.push_back(k);
1039 else if (n_unique_nodes < elem->getNumberOfBaseNodes() &&
1042 std::size_t
const n_new_elements(reduceElement(
1043 elem, n_unique_nodes, new_nodes, new_elements, min_elem_dim));
1044 element_ids.insert(element_ids.end(), n_new_elements, k);
1048 ERR(
"Something is wrong, more unique nodes than actual nodes");
1052 auto const& props =
_mesh.getProperties();
1054 copyProperties(props, node_ids, element_ids);
1056 _mesh.resetNodeIDs();
1057 if (!new_elements.empty())
1059 return new MeshLib::Mesh(new_mesh_name, new_nodes, new_elements,
1069 double const eps)
const
1071 const std::vector<MeshLib::Node*>& nodes(
_mesh.getNodes());
1072 const std::size_t nNodes(
_mesh.getNumberOfNodes());
1073 std::vector<std::size_t> id_map(nNodes);
1074 const double half_eps(eps / 2.0);
1075 const double sqr_eps(eps * eps);
1076 std::iota(id_map.begin(), id_map.end(), 0);
1080 for (std::size_t k = 0; k < nNodes; ++k)
1083 if (node->
getID() != k)
1087 std::vector<std::vector<MeshLib::Node*>
const*>
const node_vectors(
1090 const std::size_t nVectors(node_vectors.size());
1091 for (std::size_t i = 0; i < nVectors; ++i)
1093 const std::vector<MeshLib::Node*>& cell_vector(*node_vectors[i]);
1094 const std::size_t nGridCellNodes(cell_vector.size());
1095 for (std::size_t j = 0; j < nGridCellNodes; ++j)
1100 if (id_map[node->
getID()] == id_map[test_node->
getID()])
1108 if (test_node->
getID() != id_map[test_node->
getID()])
1116 WARN(
"nodes {} and {} can be collapsed", *node, *test_node);
1126 const std::vector<std::size_t>& id_map)
const
1128 const std::vector<MeshLib::Node*>& nodes(
_mesh.getNodes());
1129 const std::size_t nNodes(nodes.size());
1130 std::vector<MeshLib::Node*> new_nodes;
1131 new_nodes.reserve(nNodes);
1132 for (std::size_t k = 0; k < nNodes; ++k)
1136 if (nodes[k]->getID() == id_map[k])
1138 std::size_t
const id(new_nodes.size());
1140 (*nodes[k])[0], (*nodes[k])[1], (*nodes[k])[2],
id));
1141 nodes[k]->setID(
id);
1148 nodes[k]->setID(nodes[id_map[k]]->getID());
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
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.
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.
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
TemplateElement< MeshLib::TetRule4 > Tet
TemplateElement< MeshLib::QuadRule4 > Quad
TemplateElement< MeshLib::TriRule3 > Tri
unsigned getNodeIDinElement(Element const &element, const MeshLib::Node *node)
Returns the position of the given node in the node array of this element.
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)
bool copyPropertyOfAnyValueType(MeshLib::Properties const &props, MeshLib::Properties &new_properties, std::string const &name, MeshLib::MeshItemType const item_type, std::vector< std::size_t > const &source_ids)
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)
bool copyProperty(MeshLib::Properties const &props, MeshLib::Properties &new_properties, std::string const &name, MeshLib::MeshItemType const item_type, std::vector< std::size_t > const &source_ids)
std::vector< std::size_t > getSurvivingNodeIds(std::vector< std::size_t > const &node_ids)
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.