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"
27#include "MeshLib/Node.h"
28
29namespace MeshLib
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 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 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 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
215 mesh, "bulk_node_ids", "bulk_element_ids", "bulk_face_ids");
216 std::vector<MeshLib::Element*> const& elements(
217 boundary_mesh->getElements());
218
219 std::vector<unsigned> sfc_idx(elements.size(),
220 std::numeric_limits<unsigned>::max());
221 unsigned current_surface_id(0);
222 auto it = sfc_idx.cbegin();
223
224 while (it != sfc_idx.cend())
225 {
226 std::size_t const idx =
227 static_cast<std::size_t>(std::distance(sfc_idx.cbegin(), it));
228 trackSurface(elements[idx], sfc_idx, current_surface_id++);
229 it = std::find(sfc_idx.cbegin(),
230 sfc_idx.cend(),
231 std::numeric_limits<unsigned>::max());
232 }
233
234 // Subtract "1" from the number of surfaces found to get the number of
235 // holes.
236 return (--current_surface_id);
237}
238} // end namespace MeshLib
ElementErrorFlag
Possible error flags for mesh elements.
Definition of the Element class.
void INFO(char const *fmt, Args const &... args)
Definition: Logging.h:34
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.
virtual std::size_t getID() const final
Returns the ID of the element.
Definition: Element.h:89
virtual const Element * getNeighbor(unsigned i) const =0
Get the specified neighbor.
unsigned getNumberOfCollapsibleNodes(double eps=std::numeric_limits< double >::epsilon()) const
Returns the number of potentially collapsible nodes.
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:103
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition: Mesh.h:76
std::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:91
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.
Definition: NodeSearch.cpp:58
std::unique_ptr< MeshLib::Mesh > getBoundaryElementsAsMesh(MeshLib::Mesh const &bulk_mesh, std::string const &subsfc_node_id_prop_name, std::string const &subsfc_element_id_prop_name, std::string const &face_id_prop_name)
static void trackSurface(MeshLib::Element const *const element, std::vector< unsigned > &sfc_idx, unsigned const current_index)
static std::vector< ElementErrorCode > testElementGeometry(const MeshLib::Mesh &mesh, double min_volume=std::numeric_limits< double >::epsilon())
static bool existCollapsibleNodes(MeshLib::Mesh &mesh)
static bool allNodesUsed(MeshLib::Mesh const &mesh)
static std::array< std::string, static_cast< std::size_t >(ElementErrorFlag::MaxValue)> ElementErrorCodeOutput(const std::vector< ElementErrorCode > &error_codes)
static void evaluateElementGeometry(MeshLib::Mesh const &mesh)
static unsigned detectHoles(MeshLib::Mesh const &mesh)