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 
29 namespace MeshLib
30 {
40 static 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("Mesh Quality Control:");
67  INFO("Looking for unused nodes...");
68  NodeSearch ns(mesh);
69  ns.searchUnused();
70  if (!ns.getSearchedNodeIDs().empty())
71  {
72  INFO("{:d} unused mesh nodes found.", ns.getSearchedNodeIDs().size());
73  }
74  MeshRevision rev(mesh);
75  INFO("Found {:d} potentially collapsible nodes.",
77 
78  const std::vector<ElementErrorCode> codes(
80  std::array<std::string,
81  static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
83  for (auto& i : output_str)
84  {
85  INFO("{:s}", i);
86  }
87 }
88 
89 std::vector<ElementErrorCode> MeshValidation::testElementGeometry(
90  const MeshLib::Mesh& mesh, double min_volume)
91 {
92  INFO("Testing mesh element geometry:");
93  const auto nErrorCodes(
94  static_cast<std::size_t>(ElementErrorFlag::MaxValue));
95  unsigned error_count[nErrorCodes];
96  std::fill_n(error_count, 4, 0);
97  const std::size_t nElements(mesh.getNumberOfElements());
98  const std::vector<MeshLib::Element*>& elements(mesh.getElements());
99  std::vector<ElementErrorCode> error_code_vector;
100  error_code_vector.reserve(nElements);
101 
102  for (std::size_t i = 0; i < nElements; ++i)
103  {
104  const ElementErrorCode e = elements[i]->validate();
105  error_code_vector.push_back(e);
106  if (e.none())
107  {
108  continue;
109  }
110 
111  // increment error statistics
112  const std::bitset<static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
113  flags(static_cast<std::bitset<static_cast<std::size_t>(
115  for (unsigned j = 0; j < nErrorCodes; ++j)
116  {
117  error_count[j] += flags[j];
118  }
119  }
120 
121  // if a larger volume threshold is given, evaluate elements again to add
122  // them even if they are formally okay
123  if (min_volume > std::numeric_limits<double>::epsilon())
124  {
125  for (std::size_t i = 0; i < nElements; ++i)
126  {
127  if (elements[i]->getContent() < min_volume)
128  {
129  error_code_vector[i].set(ElementErrorFlag::ZeroVolume);
130  }
131  }
132  }
133 
134  // output
135  const auto error_sum(static_cast<unsigned>(
136  std::accumulate(error_count, error_count + nErrorCodes, 0.0)));
137  if (error_sum != 0)
138  {
139  ElementErrorFlag flags[nErrorCodes] = {
142  for (std::size_t i = 0; i < nErrorCodes; ++i)
143  {
144  if (error_count[i])
145  {
146  INFO("{:d} elements found with {:s}.",
147  error_count[i],
148  ElementErrorCode::toString(flags[i]));
149  }
150  }
151  }
152  else
153  {
154  INFO("No errors found.");
155  }
156  return error_code_vector;
157 }
158 
159 std::array<std::string, static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
161  const std::vector<ElementErrorCode>& error_codes)
162 {
163  const auto nErrorFlags(
164  static_cast<std::size_t>(ElementErrorFlag::MaxValue));
165  ElementErrorFlag flags[nErrorFlags] = {
168  const std::size_t nElements(error_codes.size());
169  std::array<std::string,
170  static_cast<std::size_t>(ElementErrorFlag::MaxValue)>
171  output;
172 
173  for (std::size_t i = 0; i < nErrorFlags; ++i)
174  {
175  unsigned count(0);
176  std::string elementIdStr;
177 
178  for (std::size_t j = 0; j < nElements; ++j)
179  {
180  if (error_codes[j][flags[i]])
181  {
182  elementIdStr += (std::to_string(j) + ", ");
183  count++;
184  }
185  }
186  const std::string nErrorsStr = (count) ? std::to_string(count) : "No";
187  output[i] = (nErrorsStr + " elements found with " +
188  ElementErrorCode::toString(flags[i]) + ".\n");
189 
190  if (count)
191  {
192  output[i] += ("ElementIDs: " + elementIdStr + "\n");
193  }
194  }
195  return output;
196 }
197 
199 {
200  if (mesh.getDimension() == 1)
201  {
202  return 0;
203  }
204 
206  mesh, "bulk_node_ids", "bulk_element_ids", "bulk_face_ids");
207  std::vector<MeshLib::Element*> const& elements(
208  boundary_mesh->getElements());
209 
210  std::vector<unsigned> sfc_idx(elements.size(),
211  std::numeric_limits<unsigned>::max());
212  unsigned current_surface_id(0);
213  auto it = sfc_idx.cbegin();
214 
215  while (it != sfc_idx.cend())
216  {
217  std::size_t const idx =
218  static_cast<std::size_t>(std::distance(sfc_idx.cbegin(), it));
219  trackSurface(elements[idx], sfc_idx, current_surface_id++);
220  it = std::find(sfc_idx.cbegin(),
221  sfc_idx.cend(),
222  std::numeric_limits<unsigned>::max());
223  }
224 
225  // Subtract "1" from the number of surfaces found to get the number of
226  // holes.
227  return (--current_surface_id);
228 }
229 } // 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:32
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 const Element * getNeighbor(unsigned i) const =0
Get the specified neighbor.
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:82
unsigned getNumberOfCollapsableNodes(double eps=std::numeric_limits< double >::epsilon()) const
Returns the number of potentially collapsible nodes.
unsigned getDimension() const
Returns the dimension of the mesh (determined by the maximum dimension over all elements).
Definition: Mesh.h:71
std::vector< Element * > const & getElements() const
Get the element-vector for the mesh.
Definition: Mesh.h:98
std::size_t getNumberOfElements() const
Get the number of elements.
Definition: Mesh.h:86
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())
MeshValidation(MeshLib::Mesh &mesh)
static std::array< std::string, static_cast< std::size_t >ElementErrorFlag::MaxValue)> ElementErrorCodeOutput(const std::vector< ElementErrorCode > &error_codes)
static unsigned detectHoles(MeshLib::Mesh const &mesh)