OGS
MeshSurfaceExtraction.cpp
Go to the documentation of this file.
1
16
17#include <boost/math/constants/constants.hpp>
18#include <memory>
19
20#include "BaseLib/Logging.h"
25#include "MeshLib/Mesh.h"
31
32namespace MeshToolsLib
33{
34template <typename T>
36 std::vector<std::size_t> const& id_map,
37 MeshLib::Mesh& sfc_mesh)
38{
39 auto const number_of_components = property.getNumberOfGlobalComponents();
40
41 auto sfc_prop = MeshLib::getOrCreateMeshProperty<T>(
42 sfc_mesh, property.getPropertyName(), property.getMeshItemType(),
43 number_of_components);
44 sfc_prop->clear();
45 sfc_prop->reserve(id_map.size());
46
47 for (auto bulk_id : id_map)
48 {
49 std::copy_n(&property.getComponent(bulk_id, 0 /*component_id*/),
50 number_of_components, back_inserter(*sfc_prop));
51 }
52}
53
55 MeshLib::Properties const& properties,
56 std::vector<std::size_t> const& node_ids_map,
57 std::vector<std::size_t> const& element_ids_map)
58{
59 std::size_t const n_elems(sfc_mesh.getNumberOfElements());
60 std::size_t const n_nodes(sfc_mesh.getNumberOfNodes());
61 if (node_ids_map.size() != n_nodes)
62 {
63 ERR("createSfcMeshProperties() - Incorrect number of node IDs ({:d}) "
64 "compared to actual number of surface nodes ({:d}).",
65 node_ids_map.size(), n_nodes);
66 return false;
67 }
68
69 if (element_ids_map.size() != n_elems)
70 {
71 ERR("createSfcMeshProperties() - Incorrect number of element IDs "
72 "({:d}) compared to actual number of surface elements ({:d}).",
73 element_ids_map.size(), n_elems);
74 return false;
75 }
76 std::map<MeshLib::MeshItemType, std::vector<std::size_t> const*> const
77 id_maps = {{MeshLib::MeshItemType::Cell, &element_ids_map},
78 {MeshLib::MeshItemType::Node, &node_ids_map}};
79
80 std::size_t vectors_copied(0);
81 std::size_t vectors_skipped(0);
82 for (auto [name, property] : properties)
83 {
84 if (property->getMeshItemType() != MeshLib::MeshItemType::Cell &&
85 property->getMeshItemType() != MeshLib::MeshItemType::Node)
86 {
87 WARN(
88 "Skipping property vector '{:s}' - not defined on cells or "
89 "nodes.",
90 name);
91 vectors_skipped++;
92 continue;
93 }
94
95 auto const& id_map = *id_maps.at(property->getMeshItemType());
96 if (auto const* p =
97 dynamic_cast<MeshLib::PropertyVector<double>*>(property))
98 {
99 processPropertyVector(*p, id_map, sfc_mesh);
100 vectors_copied++;
101 }
102 else if (auto const* p =
103 dynamic_cast<MeshLib::PropertyVector<float>*>(property))
104 {
105 processPropertyVector(*p, id_map, sfc_mesh);
106 vectors_copied++;
107 }
108 else if (auto const* p =
109 dynamic_cast<MeshLib::PropertyVector<int>*>(property))
110 {
111 processPropertyVector(*p, id_map, sfc_mesh);
112 vectors_copied++;
113 }
114 else if (auto const* p =
115 dynamic_cast<MeshLib::PropertyVector<unsigned>*>(property))
116 {
117 processPropertyVector(*p, id_map, sfc_mesh);
118 vectors_copied++;
119 }
120 else if (auto const* p =
121 dynamic_cast<MeshLib::PropertyVector<long>*>(property))
122 {
123 processPropertyVector(*p, id_map, sfc_mesh);
124 vectors_copied++;
125 }
126 else if (auto const* p =
128 property))
129 {
130 processPropertyVector(*p, id_map, sfc_mesh);
131 vectors_copied++;
132 }
133 else if (auto const* p =
135 property))
136 {
137 processPropertyVector(*p, id_map, sfc_mesh);
138 vectors_copied++;
139 }
140 else if (auto const* p =
142 property))
143 {
144 processPropertyVector(*p, id_map, sfc_mesh);
145 vectors_copied++;
146 }
147 else if (auto const* p =
149 property))
150 {
151 processPropertyVector(*p, id_map, sfc_mesh);
152 vectors_copied++;
153 }
154 else if (auto const* p =
155 dynamic_cast<MeshLib::PropertyVector<char>*>(property))
156 {
157 processPropertyVector(*p, id_map, sfc_mesh);
158 vectors_copied++;
159 }
160 else
161 {
162 WARN(
163 "Skipping property vector '{:s}' - no matching data type "
164 "'{:s}' found.",
165 name, typeid(*property).name());
166 vectors_skipped++;
167 }
168 }
169 INFO("{:d} property vectors copied, {:d} vectors skipped.", vectors_copied,
170 vectors_skipped);
171 return true;
172}
173
174std::tuple<std::vector<MeshLib::Node*>, std::vector<std::size_t>>
175createNodesAndIDMapFromElements(std::vector<MeshLib::Element*> const& elements,
176 std::size_t const n_all_nodes)
177{
178 std::vector<MeshLib::Node const*> tmp_nodes(n_all_nodes, nullptr);
179 for (auto const* elem : elements)
180 {
181 auto const n_nodes = elem->getNumberOfNodes();
182 for (unsigned j = 0; j < n_nodes; ++j)
183 {
184 const MeshLib::Node* node(elem->getNode(j));
185 tmp_nodes[node->getID()] = node;
186 }
187 }
188
189 std::vector<MeshLib::Node*> nodes;
190 std::vector<std::size_t> node_id_map(n_all_nodes);
191 for (unsigned i = 0; i < n_all_nodes; ++i)
192 {
193 if (tmp_nodes[i])
194 {
195 node_id_map[i] = nodes.size();
196 nodes.push_back(new MeshLib::Node(*tmp_nodes[i]));
197 }
198 }
199 return {nodes, node_id_map};
200}
201
203 const MeshLib::Mesh& mesh)
204{
205 std::vector<double> node_area_vec;
206 if (mesh.getDimension() != 2)
207 {
208 ERR("Error in MeshSurfaceExtraction::getSurfaceAreaForNodes() - Given "
209 "mesh is no surface mesh (dimension != 2).");
210 return node_area_vec;
211 }
212
213 double total_area(0);
214
215 // for each node, a vector containing all the element idget every element
216 const std::vector<MeshLib::Node*>& nodes = mesh.getNodes();
217 const std::size_t nNodes(mesh.getNumberOfNodes());
218 for (std::size_t n = 0; n < nNodes; ++n)
219 {
220 double node_area(0);
221
222 auto const conn_elems = mesh.getElementsConnectedToNode(*nodes[n]);
223 const std::size_t nConnElems(conn_elems.size());
224
225 for (std::size_t i = 0; i < nConnElems; ++i)
226 {
227 const MeshLib::Element* elem(conn_elems[i]);
228 const unsigned nElemParts =
230 : 4;
231 const double area = conn_elems[i]->getContent() / nElemParts;
232 node_area += area;
233 total_area += area;
234 }
235
236 node_area_vec.push_back(node_area);
237 }
238
239 INFO("Total surface Area: {:f}", total_area);
240
241 return node_area_vec;
242}
243
245 const MeshLib::Mesh& subsfc_mesh, Eigen::Vector3d const& dir, double angle,
246 std::string_view subsfc_node_id_prop_name,
247 std::string_view subsfc_element_id_prop_name,
248 std::string_view face_id_prop_name)
249{
250 // allow slightly greater angles than 90 degrees for numerical errors
251 if (angle < 0 || angle > 91)
252 {
253 ERR("Supported angle between 0 and 90 degrees only.");
254 return nullptr;
255 }
256
257 INFO("Extracting mesh surface...");
258 std::vector<MeshLib::Element*> sfc_elements;
259 std::vector<std::size_t> element_ids_map;
260 std::vector<std::size_t> face_ids_map;
261 get2DSurfaceElements(subsfc_mesh.getElements(), sfc_elements,
262 element_ids_map, face_ids_map, dir, angle,
263 subsfc_mesh.getDimension());
264
265 if (sfc_elements.empty())
266 {
267 return nullptr;
268 }
269
270 auto [sfc_nodes, node_id_map] = createNodesAndIDMapFromElements(
271 sfc_elements, subsfc_mesh.getNumberOfNodes());
272
273 // create new elements vector with newly created nodes (and delete
274 // temp-elements)
275 auto new_elements =
276 MeshLib::copyElementVector(sfc_elements, sfc_nodes, &node_id_map);
277 std::for_each(sfc_elements.begin(), sfc_elements.end(),
278 [](MeshLib::Element* e) { delete e; });
279
280 auto sfc_node_ids = sfc_nodes | MeshLib::views::ids;
281 std::vector<std::size_t> const id_map(sfc_node_ids.begin(),
282 sfc_node_ids.end());
283
284 MeshLib::Mesh* result(
285 new MeshLib::Mesh(subsfc_mesh.getName() + "-Surface", sfc_nodes,
286 new_elements, true /* compute_element_neighbors */));
287
288 addBulkIDPropertiesToMesh(*result, subsfc_node_id_prop_name, id_map,
289 subsfc_element_id_prop_name, element_ids_map,
290 face_id_prop_name, face_ids_map);
291
292 if (!createSfcMeshProperties(*result, subsfc_mesh.getProperties(), id_map,
293 element_ids_map))
294 {
295 ERR("Transferring subsurface properties failed.");
296 }
297 return result;
298}
299
301 const std::vector<MeshLib::Element*>& all_elements,
302 std::vector<MeshLib::Element*>& sfc_elements,
303 std::vector<std::size_t>& element_to_bulk_element_id_map,
304 std::vector<std::size_t>& element_to_bulk_face_id_map,
305 Eigen::Vector3d const& dir, double angle, unsigned mesh_dimension)
306{
307 if (mesh_dimension < 2 || mesh_dimension > 3)
308 {
309 ERR("Cannot handle meshes of dimension {}", mesh_dimension);
310 }
311
312 bool const complete_surface = (dir.dot(dir) == 0);
313
314 double const pi(boost::math::constants::pi<double>());
315 double const cos_theta(std::cos(angle * pi / 180.0));
316 Eigen::Vector3d const norm_dir(dir.normalized());
317
318 for (auto const* elem : all_elements)
319 {
320 const unsigned element_dimension(elem->getDimension());
321 if (element_dimension < mesh_dimension)
322 {
323 continue;
324 }
325
326 if (element_dimension == 2)
327 {
328 if (!complete_surface)
329 {
330 if (MeshLib::FaceRule::getSurfaceNormal(*elem).normalized().dot(
331 norm_dir) > cos_theta)
332 {
333 continue;
334 }
335 }
336 sfc_elements.push_back(elem->clone());
337 element_to_bulk_element_id_map.push_back(elem->getID());
338 element_to_bulk_face_id_map.push_back(0);
339 }
340 else
341 {
342 if (!elem->isBoundaryElement())
343 {
344 continue;
345 }
346 const unsigned nFaces(elem->getNumberOfFaces());
347 for (unsigned j = 0; j < nFaces; ++j)
348 {
349 if (elem->getNeighbor(j) != nullptr)
350 {
351 continue;
352 }
353
354 auto const face =
355 std::unique_ptr<MeshLib::Element const>{elem->getFace(j)};
356 if (!complete_surface)
357 {
359 .normalized()
360 .dot(norm_dir) < cos_theta)
361 {
362 continue;
363 }
364 }
365 switch (face->getCellType())
366 {
368 sfc_elements.push_back(new MeshLib::Tri(
369 *static_cast<const MeshLib::Tri*>(face.get())));
370 break;
372 sfc_elements.push_back(new MeshLib::Tri6(
373 *static_cast<const MeshLib::Tri6*>(face.get())));
374 break;
376 sfc_elements.push_back(new MeshLib::Quad(
377 *static_cast<const MeshLib::Quad*>(face.get())));
378 break;
380 sfc_elements.push_back(new MeshLib::Quad8(
381 *static_cast<const MeshLib::Quad8*>(face.get())));
382 break;
384 sfc_elements.push_back(new MeshLib::Quad9(
385 *static_cast<const MeshLib::Quad9*>(face.get())));
386 break;
387 default:
388 DBUG("unknown cell type");
389 }
390 element_to_bulk_element_id_map.push_back(elem->getID());
391 element_to_bulk_face_id_map.push_back(j);
392 }
393 }
394 }
395}
396
397std::vector<MeshLib::Node*> MeshSurfaceExtraction::getSurfaceNodes(
398 const MeshLib::Mesh& mesh, Eigen::Vector3d const& dir, double angle)
399{
400 INFO("Extracting surface nodes...");
401 std::vector<MeshLib::Element*> sfc_elements;
402 std::vector<std::size_t> element_to_bulk_element_id_map;
403 std::vector<std::size_t> element_to_bulk_face_id_map;
404
406 mesh.getElements(), sfc_elements, element_to_bulk_element_id_map,
407 element_to_bulk_face_id_map, dir, angle, mesh.getDimension());
408
409 std::vector<MeshLib::Node*> surface_nodes;
410 std::tie(surface_nodes, std::ignore) =
412
413 for (auto e : sfc_elements)
414 {
415 delete e;
416 }
417
418 return surface_nodes;
419}
420
422 MeshLib::Element const& surface_element,
423 std::vector<MeshLib::Element*>& surface_elements,
424 std::vector<std::size_t>& element_to_bulk_element_id_map,
425 std::vector<std::size_t>& element_to_bulk_face_id_map)
426{
427 const unsigned n_faces(surface_element.getNumberOfBoundaries());
428 for (unsigned j = 0; j < n_faces; ++j)
429 {
430 if (surface_element.getNeighbor(j) != nullptr)
431 {
432 continue;
433 }
434
435 surface_elements.push_back(
436 const_cast<MeshLib::Element*>(surface_element.getBoundary(j)));
437 element_to_bulk_face_id_map.push_back(j);
438 element_to_bulk_element_id_map.push_back(surface_element.getID());
439 }
440}
441
442std::tuple<std::vector<MeshLib::Element*>, std::vector<std::size_t>,
443 std::vector<std::size_t>>
445{
446 std::vector<std::size_t> element_to_bulk_element_id_map;
447 std::vector<std::size_t> element_to_bulk_face_id_map;
448 std::vector<MeshLib::Element*> surface_elements;
449
450 auto const& bulk_elements = bulk_mesh.getElements();
451 auto const mesh_dimension = bulk_mesh.getDimension();
452
453 for (auto const* elem : bulk_elements)
454 {
455 const unsigned element_dimension(elem->getDimension());
456 if (element_dimension < mesh_dimension)
457 {
458 continue;
459 }
460
461 if (!elem->isBoundaryElement())
462 {
463 continue;
464 }
465 createSurfaceElementsFromElement(*elem, surface_elements,
466 element_to_bulk_element_id_map,
467 element_to_bulk_face_id_map);
468 }
469 return {surface_elements, element_to_bulk_element_id_map,
470 element_to_bulk_face_id_map};
471}
472
473namespace BoundaryExtraction
474{
475std::unique_ptr<MeshLib::Mesh> getBoundaryElementsAsMesh(
476 MeshLib::Mesh const& bulk_mesh,
477 std::string_view subsfc_node_id_prop_name,
478 std::string_view subsfc_element_id_prop_name,
479 std::string_view face_id_prop_name)
480{
481 auto const mesh_dimension = bulk_mesh.getDimension();
482 if (mesh_dimension < 2 || mesh_dimension > 3)
483 {
484 ERR("Cannot handle meshes of dimension {}", mesh_dimension);
485 }
486
487 // create boundary elements based on the subsurface nodes
488 auto [boundary_elements, element_to_bulk_element_id_map,
489 element_to_bulk_face_id_map] = createBoundaryElements(bulk_mesh);
490
491 // create new nodes needed for the new surface elements
492 auto [boundary_nodes, node_id_map] = createNodesAndIDMapFromElements(
493 boundary_elements, bulk_mesh.getNumberOfNodes());
494
495 // create new elements using newly created nodes and delete temp-elements
496 auto new_elements = MeshLib::copyElementVector(
497 boundary_elements, boundary_nodes, &node_id_map);
498 for (auto* e : boundary_elements)
499 {
500 delete e;
501 }
502
503 auto boundary_node_ids = boundary_nodes | MeshLib::views::ids;
504
505 std::vector<std::size_t> const nodes_to_bulk_nodes_id_map(
506 boundary_node_ids.begin(), boundary_node_ids.end());
507
508 std::unique_ptr<MeshLib::Mesh> boundary_mesh(
509 new MeshLib::Mesh(bulk_mesh.getName() + "-boundary", boundary_nodes,
510 new_elements, true /* compute_element_neighbors */));
511
513 *boundary_mesh, subsfc_node_id_prop_name, nodes_to_bulk_nodes_id_map,
514 subsfc_element_id_prop_name, element_to_bulk_element_id_map,
515 face_id_prop_name, element_to_bulk_face_id_map);
516
518 if (!createSfcMeshProperties(*boundary_mesh, bulk_mesh.getProperties(),
519 nodes_to_bulk_nodes_id_map,
520 element_to_bulk_element_id_map))
521 {
522 ERR("Transferring subsurface properties failed.");
523 }
524 return boundary_mesh;
525}
526
527} // namespace BoundaryExtraction
528
530 MeshLib::Mesh& surface_mesh,
531 std::string_view node_to_bulk_node_id_map_name,
532 std::vector<std::size_t> const& node_to_bulk_node_id_map,
533 std::string_view element_to_bulk_element_id_map_name,
534 std::vector<std::size_t> const& element_to_bulk_element_id_map,
535 std::string_view element_to_bulk_face_id_map_name,
536 std::vector<std::size_t> const& element_to_bulk_face_id_map)
537{
538 // transmit the original node ids of the bulk mesh as a property
539 if (!node_to_bulk_node_id_map_name.empty())
540 {
541 MeshLib::addPropertyToMesh(surface_mesh, node_to_bulk_node_id_map_name,
543 node_to_bulk_node_id_map);
544 }
545
546 // transmit the original bulk element ids as a property
547 if (!element_to_bulk_element_id_map_name.empty())
548 {
550 surface_mesh, element_to_bulk_element_id_map_name,
551 MeshLib::MeshItemType::Cell, 1, element_to_bulk_element_id_map);
552 }
553
554 // transmit the face id of the original bulk element as a property
555 if (!element_to_bulk_face_id_map_name.empty())
556 {
558 surface_mesh, element_to_bulk_face_id_map_name,
559 MeshLib::MeshItemType::Cell, 1, element_to_bulk_face_id_map);
560 }
561}
562
563} // namespace MeshToolsLib
Definition of Duplicate functions.
Definition of the Line class.
void INFO(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:35
void DBUG(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:30
void ERR(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:45
void WARN(fmt::format_string< Args... > fmt, Args &&... args)
Definition Logging.h:40
Definition of the MeshSurfaceExtraction class.
Definition of the Mesh class.
Definition of the Quad class.
Definition of the Tri class.
std::size_t getID() const
virtual MeshElemType getGeomType() const =0
virtual unsigned getNumberOfBoundaries() const =0
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.
virtual const Element * getBoundary(unsigned i) const =0
static Eigen::Vector3d getSurfaceNormal(Element const &e)
Returns the surface normal of a 2D element.
Definition FaceRule.cpp:40
std::vector< Node * > const & getNodes() const
Get the nodes-vector for the mesh.
Definition Mesh.h:106
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
Properties & getProperties()
Definition Mesh.h:134
const std::string getName() const
Get name of the mesh.
Definition Mesh.h:103
std::size_t getNumberOfNodes() const
Get the number of nodes.
Definition Mesh.h:100
std::vector< Element const * > const & getElementsConnectedToNode(std::size_t node_id) const
Definition Mesh.cpp:256
std::size_t getNumberOfElements() const
Get the number of elements.
Definition Mesh.h:97
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition Properties.h:36
MeshItemType getMeshItemType() const
std::string const & getPropertyName() const
PROP_VAL_TYPE & getComponent(std::size_t tuple_index, int component)
Returns the value for the given component stored in the given tuple.
static std::vector< double > getSurfaceAreaForNodes(const MeshLib::Mesh &mesh)
Returns a vector of the areas assigned to each node on a surface mesh.
static void get2DSurfaceElements(const std::vector< MeshLib::Element * > &all_elements, std::vector< MeshLib::Element * > &sfc_elements, std::vector< std::size_t > &element_to_bulk_element_id_map, std::vector< std::size_t > &element_to_bulk_face_id_map, Eigen::Vector3d const &dir, double angle, unsigned mesh_dimension)
Functionality needed for getSurfaceNodes() and getMeshSurface()
static MeshLib::Mesh * getMeshSurface(const MeshLib::Mesh &subsfc_mesh, Eigen::Vector3d const &dir, double angle, std::string_view subsfc_node_id_prop_name="", std::string_view subsfc_element_id_prop_name="", std::string_view face_id_prop_name="")
static std::vector< MeshLib::Node * > getSurfaceNodes(const MeshLib::Mesh &mesh, Eigen::Vector3d const &dir, double angle)
Returns the surface nodes of a mesh.
constexpr ranges::views::view_closure ids
For an element of a range view return its id.
Definition Mesh.h:225
std::vector< Element * > copyElementVector(std::vector< Element * > const &elements, std::vector< Node * > const &new_nodes, std::vector< std::size_t > const *const node_id_map)
void addPropertyToMesh(Mesh &mesh, std::string_view name, MeshItemType item_type, std::size_t number_of_components, std::vector< T > const &values)
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)
std::tuple< std::vector< MeshLib::Node * >, std::vector< std::size_t > > createNodesAndIDMapFromElements(std::vector< MeshLib::Element * > const &elements, std::size_t const n_all_nodes)
void processPropertyVector(MeshLib::PropertyVector< T > const &property, std::vector< std::size_t > const &id_map, MeshLib::Mesh &sfc_mesh)
std::tuple< std::vector< MeshLib::Element * >, std::vector< std::size_t >, std::vector< std::size_t > > createBoundaryElements(MeshLib::Mesh const &bulk_mesh)
void createSurfaceElementsFromElement(MeshLib::Element const &surface_element, std::vector< MeshLib::Element * > &surface_elements, std::vector< std::size_t > &element_to_bulk_element_id_map, std::vector< std::size_t > &element_to_bulk_face_id_map)
bool createSfcMeshProperties(MeshLib::Mesh &sfc_mesh, MeshLib::Properties const &properties, std::vector< std::size_t > const &node_ids_map, std::vector< std::size_t > const &element_ids_map)
void addBulkIDPropertiesToMesh(MeshLib::Mesh &surface_mesh, std::string_view node_to_bulk_node_id_map_name, std::vector< std::size_t > const &node_to_bulk_node_id_map, std::string_view element_to_bulk_element_id_map_name, std::vector< std::size_t > const &element_to_bulk_element_id_map, std::string_view element_to_bulk_face_id_map_name, std::vector< std::size_t > const &element_to_bulk_face_id_map)