FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
adaptive_mesh_algorithms.hpp
1// FEAT3: Finite Element Analysis Toolbox, Version 3
2// Copyright (C) 2010 by Stefan Turek & the FEAT group
3// FEAT3 is released under the GNU General Public License version 3,
4// see the file 'copyright.txt' in the top level directory for details.
5
6#pragma once
7
8#include <kernel/geometry/intern/refinement_field.hpp>
9#include <kernel/geometry/mesh_part.hpp>
11#include <kernel/geometry/intern/adaptive_mesh_storage.hpp>
12#include <kernel/geometry/subdivision_levels.hpp>
13#include <kernel/shape.hpp>
14
15namespace FEAT::Geometry::Intern
16{
17#ifdef DOXYGEN
27 template<typename AdaptiveMesh_, typename ConformalMesh_, typename Shape_>
29 {
37 static void write_to_mesh(ConformalMesh_& target, AdaptiveMesh_& source, Index layer)
38 {
39 }
40 };
41#else
42 template<typename AdaptiveMesh_, typename ConformalMesh_, typename Shape_>
43 struct ConformalMeshWriter;
44#endif
45
53 template<typename AdaptiveMesh_, typename ConformalMesh_>
54 struct ConformalMeshWriter<AdaptiveMesh_, ConformalMesh_, Shape::Vertex>
55 {
57 static void write_to_mesh(ConformalMesh_& target, const AdaptiveMesh_& source, Layer layer)
58 {
59 auto& vertices = target.get_vertex_set();
60
61 Index num_vertices = source.get_num_entities(layer, 0);
62 for(Index i = 0; i < num_vertices; i++)
63 {
64 vertices[i] = source.vertex(layer, i);
65 }
66 }
67 };
68
76 template<typename AdaptiveMesh_, typename ConformalMesh_>
77 struct ConformalMeshWriter<AdaptiveMesh_, ConformalMesh_, Shape::Hypercube<1>>
78 {
80 static void write_to_mesh(ConformalMesh_& target, const AdaptiveMesh_& source, Layer layer)
81 {
82 // Write vertices
84
85 auto& v_at_e = target.template get_index_set<1, 0>();
86
87 Index num_edges = source.get_num_entities(layer, 1);
88 for(Index i = 0; i < num_edges; i++)
89 {
90 v_at_e[i][0] = source.template get_face_index<1, 0>(layer, i, 0);
91 v_at_e[i][1] = source.template get_face_index<1, 0>(layer, i, 1);
92 }
93 }
94 };
95
103 template<typename AdaptiveMesh_, typename ConformalMesh_>
104 struct ConformalMeshWriter<AdaptiveMesh_, ConformalMesh_, Shape::Hypercube<2>>
105 {
107 static void write_to_mesh(ConformalMesh_& target, const AdaptiveMesh_& source, Layer layer)
108 {
109 // Write edges
111
112 auto& v_at_f = target.template get_index_set<2, 0>();
113 auto& e_at_f = target.template get_index_set<2, 1>();
114
115 Index num_faces = source.get_num_entities(layer, 2);
116 for(Index i = 0; i < num_faces; i++)
117 {
118 for(int j = 0; j < v_at_f.get_num_indices(); j++)
119 {
120 v_at_f[i][j] = source.template get_face_index<2, 0>(layer, i, j);
121 }
122
123 for(int j = 0; j < e_at_f.get_num_indices(); j++)
124 {
125 e_at_f[i][j] = source.template get_face_index<2, 1>(layer, i, j);
126 }
127 }
128 }
129 };
130
138 template<typename AdaptiveMesh_, typename ConformalMesh_>
139 struct ConformalMeshWriter<AdaptiveMesh_, ConformalMesh_, Shape::Hypercube<3>>
140 {
142 static void write_to_mesh(ConformalMesh_& target, const AdaptiveMesh_& source, Layer layer)
143 {
144 // Write faces
146
147 auto& v_at_c = target.template get_index_set<3, 0>();
148 auto& e_at_c = target.template get_index_set<3, 1>();
149 auto& f_at_c = target.template get_index_set<3, 2>();
150
151 Index num_cells = source.get_num_entities(layer, 3);
152 for(Index i = 0; i < num_cells; i++)
153 {
154 for(int j = 0; j < v_at_c.get_num_indices(); j++)
155 {
156 v_at_c[i][j] = source.template get_face_index<3, 0>(layer, i, j);
157 }
158 for(int j = 0; j < e_at_c.get_num_indices(); j++)
159 {
160 e_at_c[i][j] = source.template get_face_index<3, 1>(layer, i, j);
161 }
162 for(int j = 0; j < f_at_c.get_num_indices(); j++)
163 {
164 f_at_c[i][j] = source.template get_face_index<3, 2>(layer, i, j);
165 }
166 }
167 }
168 };
169
177 template<typename MeshStorage_>
179 {
180 MeshPartProjectorVisitor(const MeshStorage_& s, Layer l) : storage(s), layer(l)
181 {
182 }
183
184 void operator()(Intern::VertexKey key)
185 {
186 if(storage[key].layer <= layer)
187 {
188 vertices.push_back(key);
189 }
190 }
191
192 void operator()(Intern::EdgeKey key)
193 {
194 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
195 {
196 edges.push_back(key);
197 }
198 }
199
200 void operator()(Intern::FaceKey key)
201 {
202 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
203 {
204 faces.push_back(key);
205 }
206 }
207
208 void operator()(Intern::CellKey key)
209 {
210 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
211 {
212 cells.push_back(key);
213 }
214 }
215
216 const MeshStorage_& storage;
217 Layer layer;
218
219 std::vector<Intern::VertexKey> vertices;
220 std::vector<Intern::EdgeKey> edges;
221 std::vector<Intern::FaceKey> faces;
222 std::vector<Intern::CellKey> cells;
223 };
224
225#ifdef DOXYGEN
239 template<typename AdaptiveMesh_, typename TargetMeshType_, typename Shape_>
241 {
242 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
243 using Roots = typename AdaptiveMesh_::MeshRoots;
244 using Storage = typename AdaptiveMesh_::MeshStorage;
246
256 static void collect_keys(
257 Visitor& visitor,
258 const MeshPart<FoundationMesh>& source,
259 Layer layer,
260 const Roots& roots,
261 const Storage& storage)
262 {
263 }
264
272 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
273 {
274 }
275 };
276#else
277 template<typename AdaptiveMesh_, typename TargetMeshType_, typename Shape_>
278 struct MeshPartProjector;
279#endif
280
288 template<typename AdaptiveMesh_, typename TargetMeshType_>
289 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Vertex>
290 {
291 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
292 using Roots = typename AdaptiveMesh_::MeshRoots;
293 using Storage = typename AdaptiveMesh_::MeshStorage;
295
296 static void collect_keys(
297 Visitor& visitor,
298 const MeshPart<FoundationMesh>& source,
299 Layer layer,
300 const Roots& roots,
301 const Storage& storage)
302 {
303 auto& reg_vertices = source.template get_target_set<0>();
304 auto& root_vertices = roots.template by_dim<0>();
305 for(Index i(0); i < reg_vertices.get_num_entities(); ++i)
306 {
307 auto iter = root_vertices.find(reg_vertices[i]);
308 if(iter != root_vertices.end())
309 {
310 storage.walk_subtree(iter->second, visitor, layer);
311 }
312 }
313 }
314
315 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
316 {
317 auto& result_verts = target.template get_target_set<0>();
318 for(Index i(0); i < visitor.vertices.size(); ++i)
319 {
320 result_verts[i] = storage.get_index(visitor.vertices[i]);
321 }
322 }
323 };
324
332 template<typename AdaptiveMesh_, typename TargetMeshType_>
333 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<1>>
334 {
335 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
336 using Roots = typename AdaptiveMesh_::MeshRoots;
337 using Storage = typename AdaptiveMesh_::MeshStorage;
339
340 static void collect_keys(
341 Visitor& visitor,
342 const MeshPart<FoundationMesh>& source,
343 Layer layer,
344 const Roots& roots,
345 const Storage& storage)
346 {
348 visitor,
349 source,
350 layer,
351 roots,
352 storage);
353
354 auto& reg_edges = source.template get_target_set<1>();
355 auto& root_edges = roots.template by_dim<1>();
356 for(Index i(0); i < reg_edges.get_num_entities(); ++i)
357 {
358 auto iter = root_edges.find(reg_edges[i]);
359 if(iter != root_edges.end())
360 {
361 storage.walk_subtree(iter->second, visitor, layer);
362 }
363 }
364 }
365
366 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
367 {
369
370 auto& result_edges = target.template get_target_set<1>();
371 for(Index i(0); i < visitor.edges.size(); ++i)
372 {
373 result_edges[i] = storage.get_index(visitor.edges[i]);
374 }
375 }
376 };
377
385 template<typename AdaptiveMesh_, typename TargetMeshType_>
386 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<2>>
387 {
388 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
389 using Roots = typename AdaptiveMesh_::MeshRoots;
390 using Storage = typename AdaptiveMesh_::MeshStorage;
392
393 static void collect_keys(
394 Visitor& visitor,
395 const MeshPart<FoundationMesh>& source,
396 Layer layer,
397 const Roots& roots,
398 const Storage& storage)
399 {
401 visitor,
402 source,
403 layer,
404 roots,
405 storage);
406
407 auto& reg_faces = source.template get_target_set<2>();
408 auto& root_faces = roots.template by_dim<2>();
409 for(Index i(0); i < reg_faces.get_num_entities(); ++i)
410 {
411 auto iter = root_faces.find(reg_faces[i]);
412 if(iter != root_faces.end())
413 {
414 storage.walk_subtree(iter->second, visitor, layer);
415 }
416 }
417 }
418
419 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
420 {
422
423 auto& result_faces = target.template get_target_set<2>();
424 for(Index i(0); i < visitor.faces.size(); ++i)
425 {
426 result_faces[i] = storage.get_index(visitor.faces[i]);
427 }
428 }
429 };
430
438 template<typename AdaptiveMesh_, typename TargetMeshType_>
439 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<3>>
440 {
441 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
442 using Roots = typename AdaptiveMesh_::MeshRoots;
443 using Storage = typename AdaptiveMesh_::MeshStorage;
445
446 static void collect_keys(
447 Visitor& visitor,
448 const MeshPart<FoundationMesh>& source,
449 Layer layer,
450 const Roots& roots,
451 const Storage& storage)
452 {
454 visitor,
455 source,
456 layer,
457 roots,
458 storage);
459
460 auto& reg_cells = source.template get_target_set<3>();
461 auto& root_cells = roots.template by_dim<3>();
462 for(Index i(0); i < reg_cells.get_num_entities(); ++i)
463 {
464 auto iter = root_cells.find(reg_cells[i]);
465 if(iter != root_cells.end())
466 {
467 storage.walk_subtree(iter->second, visitor, layer);
468 }
469 }
470 }
471
472 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
473 {
475
476 auto& result_cells = target.template get_target_set<3>();
477 for(Index i(0); i < visitor.cells.size(); ++i)
478 {
479 result_cells[i] = storage.get_index(visitor.cells[i]);
480 }
481 }
482 };
483
490 {
491 std::set<Index> vertices;
492 std::set<Index> edges;
493 std::set<Index> faces;
494 std::set<Index> cells;
495
496 template<int dim_>
497 const std::set<Index>& by_dim() const
498 {
499 if constexpr(dim_ == 0)
500 {
501 return vertices;
502 }
503 else if constexpr(dim_ == 1)
504 {
505 return edges;
506 }
507 else if constexpr(dim_ == 2)
508 {
509 return faces;
510 }
511 else
512 {
513 return cells;
514 }
515 }
516 };
517
518#ifdef DOXYGEN
528 template<typename Shape_, typename TemplateSet, typename MeshType_>
530 {
539 static void collect(MeshIndexSet& set, const MeshType_& mesh, const SubdivisionLevels& levels, bool import_all)
540 {
541 }
542 };
543#else
544 template<typename Shape_, typename TemplateSet, typename MeshType_>
545 struct EntityCollector;
546#endif
547
555 template<typename TemplateSet, typename MeshType_>
556 struct EntityCollector<Shape::Quadrilateral, TemplateSet, MeshType_>
557 {
559 static void collect(MeshIndexSet& set, const MeshType_& mesh, const RefinementField<typename TemplateSet::VertexMarkerType>& levels, bool import_all)
560 {
561 auto& v_at_f = mesh.template get_index_set<2, 0>();
562 auto& e_at_f = mesh.template get_index_set<2, 1>();
563
564 // Collect either all faces (if import_all is true) or those faces with non-zero refinement type
565 // Also collects all their sub-entities, i.e. surrounding vertices, and edges.
566 for(Index face = 0; face < v_at_f.get_num_entities(); face++)
567 {
568 auto face_levels = levels.get_tuple(v_at_f[face]);
569
570 if(import_all || ! typename TemplateSet::template RefinementTypeByDim<2>(face_levels).is_zero_refinement())
571 {
572 set.faces.insert(face);
573
574 set.edges.insert(e_at_f[face][0]);
575 set.edges.insert(e_at_f[face][1]);
576 set.edges.insert(e_at_f[face][2]);
577 set.edges.insert(e_at_f[face][3]);
578
579 set.vertices.insert(v_at_f[face][0]);
580 set.vertices.insert(v_at_f[face][1]);
581 set.vertices.insert(v_at_f[face][2]);
582 set.vertices.insert(v_at_f[face][3]);
583 }
584 }
585 }
586 };
587
595 template<typename TemplateSet, typename MeshType_>
596 struct EntityCollector<Shape::Hexahedron, TemplateSet, MeshType_>
597 {
599 static void collect(MeshIndexSet& set, const MeshType_& mesh, const RefinementField<typename TemplateSet::VertexMarkerType>& levels, bool import_all)
600 {
601 auto& f_at_c = mesh.template get_index_set<3, 2>();
602 auto& e_at_c = mesh.template get_index_set<3, 1>();
603 auto& v_at_c = mesh.template get_index_set<3, 0>();
604
605 // Collect either all cells (if import_all is true) or those cells with non-zero refinement type
606 // Also collects all their sub-entities, i.e. surrounding vertices, edges, and faces.
607 for(Index cell = 0; cell < v_at_c.get_num_entities(); cell++)
608 {
609 auto cell_levels = levels.get_tuple(v_at_c[cell]);
610
611 if(import_all || ! typename TemplateSet::template RefinementTypeByDim<3>(cell_levels).is_zero_refinement())
612 {
613 set.cells.insert(cell);
614
615 for(int i = 0; i < f_at_c.num_indices; i++)
616 {
617 set.faces.insert(f_at_c[cell][i]);
618 }
619
620 for(int i = 0; i < e_at_c.num_indices; i++)
621 {
622 set.edges.insert(e_at_c[cell][i]);
623 }
624
625 for(int i = 0; i < v_at_c.num_indices; i++)
626 {
627 set.vertices.insert(v_at_c[cell][i]);
628 }
629 }
630 }
631 }
632 };
633
643 template<typename MeshType_, int cell_dim, int face_dim>
644 int congruency(const MeshType_& mesh, Index cell, int face)
645 {
646 using ShapeType = typename MeshType_::ShapeType;
647 using CellShape = typename Shape::FaceTraits<ShapeType, cell_dim>::ShapeType;
648 using FaceShape = typename Shape::FaceTraits<ShapeType, face_dim>::ShapeType;
649 using IndexMapping = Intern::FaceIndexMapping<CellShape, face_dim, 0>;
650 using Sampler = Intern::CongruencySampler<FaceShape>;
651
652 constexpr int face_verts = Shape::FaceTraits<FaceShape, 0>::count;
653
654 auto& face_at_cell = mesh.template get_index_set<cell_dim, face_dim>();
655 auto& v_at_face = mesh.template get_index_set<face_dim, 0>();
656 auto& v_at_cell = mesh.template get_index_set<cell_dim, 0>();
657
658 std::array<Index, face_verts> local;
659
660 for(int i = 0; i < face_verts; i++)
661 {
662 local[std::size_t(i)] = v_at_cell[cell][IndexMapping::map(face, i)];
663 }
664 //return Sampler::compare(v_at_face[face_at_cell[cell][face]], local);
665 return Sampler::compare(local, v_at_face[face_at_cell(cell, face)]);
666 }
667
668#ifdef DOXYGEN
680 template<typename AdaptiveMeshType_, int topology_dim_, int collection_dim_>
682 {
683 };
684#else
685 template<typename AdaptiveMeshType_, int topology_dim_, int collection_dim_>
687#endif
688
696 template<typename AdaptiveMeshType_, int topology_dim_>
697 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 0>
698 {
699 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
701 static constexpr int num_vertices = Shape::FaceTraits<TopologyShape, 0>::count;
702
710 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
711 {
712 auto& foundation_entity_vertices = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 0>();
713
714 auto& topology_vertices = topology.template by_dim<0>();
715 auto& root_vertices = a_mesh._roots.template by_dim<0>();
716 for(int vert = 0; vert < num_vertices; vert++)
717 {
718 Index vertex_index = foundation_entity_vertices(entity, vert);
719 topology_vertices[std::size_t(vert)] = Intern::OrientedElement<0>(0, root_vertices.at(vertex_index));
720 }
721 }
722 };
723
731 template<typename AdaptiveMeshType_, int topology_dim_>
732 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 1>
733 {
734 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
735 using ShapeType = typename AdaptiveMeshType_::ShapeType;
736 using TopologyShape = typename Shape::FaceTraits<ShapeType, topology_dim_>::ShapeType;
737 static constexpr int num_edges = Shape::FaceTraits<TopologyShape, 1>::count;
738
746 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
747 {
748 // Recursive call to lower dimension
750
751 using FoundationMeshType = typename AdaptiveMeshType_::FoundationMeshType;
752 auto& foundation_entity_edges = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 1>();
753
754 auto& topology_edges = topology.template by_dim<1>();
755 auto& root_edges = a_mesh._roots.template by_dim<1>();
756 for(int edge = 0; edge < num_edges; edge++)
757 {
758 int orientation = congruency<FoundationMeshType, topology_dim_, 1>(a_mesh._foundation_mesh, entity, edge);
759 Index edge_index = foundation_entity_edges(entity, edge);
760 topology_edges[std::size_t(edge)] = Intern::OrientedEdge(orientation, root_edges.at(edge_index));
761 }
762 }
763 };
764
772 template<typename AdaptiveMeshType_, int topology_dim_>
773 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 2>
774 {
775 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
776 using ShapeType = typename AdaptiveMeshType_::ShapeType;
777 using TopologyShape = typename Shape::FaceTraits<ShapeType, topology_dim_>::ShapeType;
778 static constexpr int num_faces = Shape::FaceTraits<TopologyShape, 2>::count;
779
787 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
788 {
789 // Recursive call to lower dimension
791
792 using FoundationMeshType = typename AdaptiveMeshType_::FoundationMeshType;
793 auto& foundation_entity_faces = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 2>();
794
795 auto& topology_faces = topology.template by_dim<2>();
796 auto& root_faces = a_mesh._roots.template by_dim<2>();
797 for(int face = 0; face < num_faces; face++)
798 {
799 int orientation = congruency<FoundationMeshType, topology_dim_, 2>(a_mesh._foundation_mesh, entity, face);
800 Index face_index = foundation_entity_faces(entity, face);
801 topology_faces[std::size_t(face)] = Intern::OrientedFace(orientation, root_faces.at(face_index));
802 }
803 }
804 };
805} // namespace FEAT::Geometry::Intern
FEAT Kernel base header.
Class template for partial meshes.
Definition: mesh_part.hpp:90
Subdivision level markings for meshes.
std::uint64_t Index
Index data type.
static void write_to_mesh(ConformalMesh_ &target, const AdaptiveMesh_ &source, Layer layer)
\copdydoc ConformalMeshWriter::write_to_mesh
static void write_to_mesh(ConformalMesh_ &target, const AdaptiveMesh_ &source, Layer layer)
\copdydoc ConformalMeshWriter::write_to_mesh
static void write_to_mesh(ConformalMesh_ &target, const AdaptiveMesh_ &source, Layer layer)
\copdydoc ConformalMeshWriter::write_to_mesh
static void write_to_mesh(ConformalMesh_ &target, const AdaptiveMesh_ &source, Layer layer)
\copdydoc ConformalMeshWriter::write_to_mesh
Algorithm for exporting a layer of an AdaptiveMesh to a ConformalMesh.
static void write_to_mesh(ConformalMesh_ &target, AdaptiveMesh_ &source, Index layer)
Write entites of the current shape into the target ConformalMesh.
SlotMap key for use by the AdaptiveMeshStorage class.
Surrounding elements of a mesh element.
static void collect(MeshIndexSet &set, const MeshType_ &mesh, const RefinementField< typename TemplateSet::VertexMarkerType > &levels, bool import_all)
Collect all entities of current dimension with non zero refinement type.
static void collect(MeshIndexSet &set, const MeshType_ &mesh, const RefinementField< typename TemplateSet::VertexMarkerType > &levels, bool import_all)
Collect all entities of current dimension with non zero refinement type.
Alorithm for collecting mesh entities that must be adaptively refined.
static void collect(MeshIndexSet &set, const MeshType_ &mesh, const SubdivisionLevels &levels, bool import_all)
Collect all entities of current dimension with non zero refinement type.
static void collect(Topology &topology, Index entity, const AdaptiveMeshType_ &a_mesh)
Collect vertices of foundation mesh for topologies.
static void collect(Topology &topology, Index entity, const AdaptiveMeshType_ &a_mesh)
Collect edges of foundation mesh for topologies.
static void collect(Topology &topology, Index entity, const AdaptiveMeshType_ &a_mesh)
Collect faces of foundation mesh for topologies.
Algorithm for collecting topologies from the foundation mesh.
Newtype wrapper for mesh layers.
Algorithm for projecting MeshParts of an underlying mesh onto its adaptive mesh.
static void collect_keys(Visitor &visitor, const MeshPart< FoundationMesh > &source, Layer layer, const Roots &roots, const Storage &storage)
Collect mesh entities stemming from one of the entities in the source meshpart.
static void write_meshpart(Visitor &visitor, MeshPart< TargetMeshType_ > &target, const Storage &storage)
Write collected references into a new target meshpart.
Orientation-aware reference to another mesh element.
Face traits tag struct template.
Definition: shape.hpp:106