OGS
MeshValidation.cpp
Go to the documentation of this file.
1
15#include "MeshValidation.h"
16
17#include <algorithm>
18#include <numeric>
19#include <stack>
20
21#include "BaseLib/Logging.h"
23#include "MeshLib/Mesh.h"
25#include "MeshLib/Node.h"
28
29namespace MeshToolsLib
30{
40static void trackSurface(MeshLib::Element const* const element,
41 std::vector<unsigned>& sfc_idx,
42 unsigned const current_index)
43{
44 std::stack<MeshLib::Element const*> elem_stack;
45 elem_stack.push(element);
46 while (!elem_stack.empty())
47 {
48 MeshLib::Element const* const elem = elem_stack.top();
49 elem_stack.pop();
50 sfc_idx[elem->getID()] = current_index;
51 std::size_t const n_neighbors(elem->getNumberOfNeighbors());
52 for (std::size_t i = 0; i < n_neighbors; ++i)
53 {
54 MeshLib::Element const* neighbor(elem->getNeighbor(i));
55 if (neighbor != nullptr && sfc_idx[neighbor->getID()] ==
56 std::numeric_limits<unsigned>::max())
57 {
58 elem_stack.push(neighbor);
59 }
60 }
61 }
62}
63
65{
66 INFO("Looking for unused nodes...");
67 MeshLib::NodeSearch ns(mesh);
68 ns.searchUnused();
69 if (!ns.getSearchedNodeIDs().empty())
70 {
71 INFO("{:d} unused mesh nodes found.", ns.getSearchedNodeIDs().size());
72 return false;
73 }
74 return true;
75}
76
78{
79 MeshRevision const rev(mesh);
80 INFO("Found {:d} potentially collapsible nodes.",
82 return (rev.getNumberOfCollapsibleNodes() > 0);
83}
84
86{
87 const std::vector<ElementErrorCode> codes(
89 std::array<std::string,
90 static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
92 for (auto& i : output_str)
93 {
94 INFO("{:s}", i);
95 }
96}
97
98std::vector<ElementErrorCode> MeshValidation::testElementGeometry(
99 const MeshLib::Mesh& mesh, double min_volume)
100{
101 INFO("Testing mesh element geometry:");
102 const auto nErrorCodes(
103 static_cast<std::size_t>(ElementErrorFlag::MaxValue));
104 unsigned error_count[nErrorCodes];
105 std::fill_n(error_count, 4, 0);
106 const std::size_t nElements(mesh.getNumberOfElements());
107 const std::vector<MeshLib::Element*>& elements(mesh.getElements());
108 std::vector<ElementErrorCode> error_code_vector;
109 error_code_vector.reserve(nElements);
110
111 for (std::size_t i = 0; i < nElements; ++i)
112 {
113 const ElementErrorCode e = elements[i]->validate();
114 error_code_vector.push_back(e);
115 if (e.none())
116 {
117 continue;
118 }
119
120 // increment error statistics
121 const std::bitset<static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
122 flags(static_cast<std::bitset<static_cast<std::size_t>(
124 for (unsigned j = 0; j < nErrorCodes; ++j)
125 {
126 error_count[j] += flags[j];
127 }
128 }
129
130 // if a larger volume threshold is given, evaluate elements again to add
131 // them even if they are formally okay
132 if (min_volume > std::numeric_limits<double>::epsilon())
133 {
134 for (std::size_t i = 0; i < nElements; ++i)
135 {
136 if (elements[i]->getContent() < min_volume)
137 {
138 error_code_vector[i].set(ElementErrorFlag::ZeroVolume);
139 }
140 }
141 }
142
143 // output
144 const auto error_sum(static_cast<unsigned>(
145 std::accumulate(error_count, error_count + nErrorCodes, 0.0)));
146 if (error_sum != 0)
147 {
148 ElementErrorFlag const flags[nErrorCodes] = {
151 for (std::size_t i = 0; i < nErrorCodes; ++i)
152 {
153 if (error_count[i])
154 {
155 INFO("{:d} elements found with {:s}.",
156 error_count[i],
158 }
159 }
160 }
161 else
162 {
163 INFO("No errors found.");
164 }
165 return error_code_vector;
166}
167
168std::array<std::string, static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
170 const std::vector<ElementErrorCode>& error_codes)
171{
172 const auto nErrorFlags(
173 static_cast<std::size_t>(ElementErrorFlag::MaxValue));
174 const ElementErrorFlag flags[nErrorFlags] = {
177 const std::size_t nElements(error_codes.size());
178 std::array<std::string,
179 static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
180 output;
181
182 for (std::size_t i = 0; i < nErrorFlags; ++i)
183 {
184 unsigned count(0);
185 std::string elementIdStr;
186
187 for (std::size_t j = 0; j < nElements; ++j)
188 {
189 if (error_codes[j][flags[i]])
190 {
191 elementIdStr += (std::to_string(j) + ", ");
192 count++;
193 }
194 }
195 const std::string nErrorsStr = (count) ? std::to_string(count) : "No";
196 output[i] = (nErrorsStr + " elements found with " +
197 ElementErrorCode::toString(flags[i]) + ".\n");
198
199 if (count)
200 {
201 output[i] += ("ElementIDs: " + elementIdStr + "\n");
202 }
203 }
204 return output;
205}
206
208{
209 if (mesh.getDimension() == 1)
210 {
211 return 0;
212 }
213
214 auto boundary_mesh =
216 mesh,
220 std::vector<MeshLib::Element*> const& elements(
221 boundary_mesh->getElements());
222
223 std::vector<unsigned> sfc_idx(elements.size(),
224 std::numeric_limits<unsigned>::max());
225 unsigned current_surface_id(0);
226 auto it = sfc_idx.cbegin();
227
228 while (it != sfc_idx.cend())
229 {
230 std::size_t const idx =
231 static_cast<std::size_t>(std::distance(sfc_idx.cbegin(), it));
232 trackSurface(elements[idx], sfc_idx, current_surface_id++);
233 it = std::find(sfc_idx.cbegin(),
234 sfc_idx.cend(),
235 std::numeric_limits<unsigned>::max());
236 }
237
238 // Subtract "1" from the number of surfaces found to get the number of
239 // holes.
240 return (--current_surface_id);
241}
242} // namespace MeshToolsLib
ElementErrorFlag
Possible error flags for mesh elements.
Definition of the Element class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
Definition of the MeshRevision class.
Definition of the MeshSurfaceExtraction class.
Definition of the MeshValidation class.
Definition of the Mesh class.
Definition of the Node class.
Collects error flags for mesh elements.
static std::string toString(const ElementErrorFlag e)
Returns a string output for a specific error flag.
virtual unsigned getNumberOfNeighbors() const =0
Get the number of neighbors for this element.
std::size_t getID() const
Returns the ID of the element.
Definition Element.h:89
virtual const Element * getNeighbor(unsigned i) const =0
Get the specified neighbor.
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition Mesh.h:109
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition Mesh.h:88
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
Node search class.
Definition NodeSearch.h:25
const std::vector< std::size_t > & getSearchedNodeIDs() const
return marked node IDs
Definition NodeSearch.h:30
std::size_t searchUnused()
Marks all unused nodes.
unsigned getNumberOfCollapsibleNodes(double eps=std::numeric_limits< double >::epsilon()) const
Returns the number of potentially collapsible nodes.
constexpr std::string_view getBulkIDString(MeshItemType mesh_item_type)
Definition Properties.h:188
std::unique_ptr< MeshLib::Mesh > getBoundaryElementsAsMesh(MeshLib::Mesh const &bulk_mesh, std::string_view subsfc_node_id_prop_name, std::string_view subsfc_element_id_prop_name, std::string_view face_id_prop_name)
static void trackSurface(MeshLib::Element const *const element, std::vector< unsigned > &sfc_idx, unsigned const current_index)
static bool existCollapsibleNodes(MeshLib::Mesh &mesh)
static unsigned detectHoles(MeshLib::Mesh const &mesh)
static std::array< std::string, static_cast< std::size_t >(ElementErrorFlag::MaxValue)> ElementErrorCodeOutput(const std::vector< ElementErrorCode > &error_codes)
static bool allNodesUsed(MeshLib::Mesh const &mesh)
static std::vector< ElementErrorCode > testElementGeometry(const MeshLib::Mesh &mesh, double min_volume=std::numeric_limits< double >::epsilon())
static void evaluateElementGeometry(MeshLib::Mesh const &mesh)