OGS
AngleSkewMetric.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4#include "AngleSkewMetric.h"
5
6#include <cmath>
7#include <numbers>
8
9#include "MathLib/MathTools.h"
10#include "MeshLib/Node.h"
11
12namespace MeshToolsLib
13{
14namespace
15{
16template <unsigned long N>
17std::tuple<double, double> getMinMaxAngle(
18 std::array<MeshLib::Node, N> const& nodes)
19{
20 double min_angle(2 * std::numbers::pi);
21 double max_angle(0.0);
22
23 for (decltype(N) i = 0; i < N; ++i)
24 {
25 const double angle(MathLib::getAngle(nodes[i], nodes[(i + 1) % N],
26 nodes[(i + 2) % N]));
27 min_angle = std::min(angle, min_angle);
28 max_angle = std::max(angle, max_angle);
29 }
30 return {min_angle, max_angle};
31}
32
34{
35 using namespace std::numbers;
36 std::array const nodes = {*elem.getNode(0), *elem.getNode(1),
37 *elem.getNode(2)};
38 auto const& [min_angle, max_angle] = getMinMaxAngle(nodes);
39 return std::max((max_angle - pi / 3) / 2, (pi / 3 - min_angle)) * 3 / pi;
40}
41
42double checkQuad(MeshLib::Element const& elem)
43{
44 std::array const nodes = {*elem.getNode(0), *elem.getNode(1),
45 *elem.getNode(2), *elem.getNode(3)};
46 auto const& [min_angle, max_angle] = getMinMaxAngle(nodes);
47
48 using namespace std::numbers;
49 return std::max((max_angle - pi / 2), (pi / 2 - min_angle)) * 2 / pi;
50}
51
53{
54 std::array<double, 4> min;
55 std::array<double, 4> max;
56 for (auto face_number = 0; face_number < 4; ++face_number)
57 {
58 std::unique_ptr<MeshLib::Element const> face{elem.getFace(face_number)};
59 std::array const nodes = {*face->getNode(0), *face->getNode(1),
60 *face->getNode(2)};
61 std::tie(min[face_number], max[face_number]) = getMinMaxAngle(nodes);
62 }
63
64 double const min_angle = *std::min_element(min.begin(), min.end());
65 double const max_angle = *std::max_element(max.begin(), max.end());
66
67 using namespace std::numbers;
68 return std::max((max_angle - pi / 3) / 2, (pi / 3 - min_angle)) * 3 / pi;
69}
70
72{
73 std::array<double, 6> min;
74 std::array<double, 6> max;
75 for (auto face_number = 0; face_number < 6; ++face_number)
76 {
77 std::unique_ptr<MeshLib::Element const> face{elem.getFace(face_number)};
78 std::array const nodes = {*face->getNode(0), *face->getNode(1),
79 *face->getNode(2), *face->getNode(3)};
80 std::tie(min[face_number], max[face_number]) = getMinMaxAngle(nodes);
81 }
82
83 double const min_angle = *std::min_element(min.begin(), min.end());
84 double const max_angle = *std::max_element(max.begin(), max.end());
85
86 using namespace std::numbers;
87 return std::max((max_angle - pi / 2), (pi / 2 - min_angle)) * 2 / pi;
88}
89
90double checkPrism(MeshLib::Element const& elem)
91{
92 // face 0: triangle (0,1,2)
93 std::unique_ptr<MeshLib::Element const> f0{elem.getFace(0)};
94 std::array const nodes_f0 = {*f0->getNode(0), *f0->getNode(1),
95 *f0->getNode(2)};
96 auto const& [min_angle_tri0, max_angle_tri0] = getMinMaxAngle(nodes_f0);
97
98 // face 4: triangle (3,4,5)
99 std::unique_ptr<MeshLib::Element const> f4{elem.getFace(4)};
100 std::array const nodes_f4 = {*f4->getNode(0), *f4->getNode(1),
101 *f4->getNode(2)};
102 auto const& [min_angle_tri1, max_angle_tri1] = getMinMaxAngle(nodes_f4);
103
104 auto const min_angle_tri = std::min(min_angle_tri0, min_angle_tri1);
105 auto const max_angle_tri = std::max(max_angle_tri0, max_angle_tri1);
106
107 using namespace std::numbers;
108 double const tri_criterion =
109 std::max((max_angle_tri - pi / 3) / 2, (pi / 3 - min_angle_tri)) * 3 /
110 pi;
111
112 std::array<double, 3> min;
113 std::array<double, 3> max;
114 for (int i = 1; i < 4; ++i)
115 {
116 std::unique_ptr<MeshLib::Element const> f{elem.getFace(i)};
117 std::array const nodes = {*f->getNode(0), *f->getNode(1),
118 *f->getNode(2), *f->getNode(3)};
119 std::tie(min[i - 1], max[i - 1]) = getMinMaxAngle(nodes);
120 }
121
122 double const min_angle_quad = *std::min_element(min.begin(), min.end());
123 double const max_angle_quad = *std::max_element(max.begin(), max.end());
124
125 using namespace std::numbers;
126 double const quad_criterion =
127 std::max((max_angle_quad - pi / 2), (pi / 2 - min_angle_quad)) * 2 / pi;
128
129 return std::min(tri_criterion, quad_criterion);
130}
131
132} // end unnamed namespace
133
135{
136 for (auto const e : _mesh.getElements())
137 {
138 switch (e->getGeomType())
139 {
141 _element_quality_metric[e->getID()] = -1.0;
142 break;
144 _element_quality_metric[e->getID()] = checkTriangle(*e);
145 break;
147 _element_quality_metric[e->getID()] = checkQuad(*e);
148 break;
150 _element_quality_metric[e->getID()] = checkTetrahedron(*e);
151 break;
153 _element_quality_metric[e->getID()] = checkHexahedron(*e);
154 break;
156 _element_quality_metric[e->getID()] = checkPrism(*e);
157 break;
158 default:
159 break;
160 }
161 }
162}
163
164} // namespace MeshToolsLib
virtual const Element * getFace(unsigned i) const =0
Returns the i-th face of the element.
virtual const Node * getNode(unsigned idx) const =0
std::vector< double > _element_quality_metric
double getAngle(Point3d const &p0, Point3d const &p1, Point3d const &p2)
Definition MathTools.cpp:36
double checkTriangle(MeshLib::Element const &elem)
std::tuple< double, double > getMinMaxAngle(std::array< MeshLib::Node, N > const &nodes)
double checkHexahedron(MeshLib::Element const &elem)
double checkTetrahedron(MeshLib::Element const &elem)
void calculateQuality() override
Calculates the quality metric for each element of the mesh.