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 void operator()(Intern::EdgeKey key)
192 {
193 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
194 {
195 edges.push_back(key);
196 }
197 };
198 void operator()(Intern::FaceKey key)
199 {
200 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
201 {
202 faces.push_back(key);
203 }
204 };
205 void operator()(Intern::CellKey key)
206 {
207 if(storage[key].layer == layer || storage[key].type.is_zero_refinement())
208 {
209 cells.push_back(key);
210 }
211 };
212
213 const MeshStorage_& storage;
214 Layer layer;
215
216 std::vector<Intern::VertexKey> vertices;
217 std::vector<Intern::EdgeKey> edges;
218 std::vector<Intern::FaceKey> faces;
219 std::vector<Intern::CellKey> cells;
220 };
221
222#ifdef DOXYGEN
236 template<typename AdaptiveMesh_, typename TargetMeshType_, typename Shape_>
238 {
239 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
240 using Roots = typename AdaptiveMesh_::MeshRoots;
241 using Storage = typename AdaptiveMesh_::MeshStorage;
243
253 static void collect_keys(
254 Visitor& visitor,
255 const MeshPart<FoundationMesh>& source,
256 Layer layer,
257 const Roots& roots,
258 const Storage& storage)
259 {
260 }
261
269 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
270 {
271 }
272 };
273#else
274 template<typename AdaptiveMesh_, typename TargetMeshType_, typename Shape_>
275 struct MeshPartProjector;
276#endif
277
285 template<typename AdaptiveMesh_, typename TargetMeshType_>
286 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Vertex>
287 {
288 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
289 using Roots = typename AdaptiveMesh_::MeshRoots;
290 using Storage = typename AdaptiveMesh_::MeshStorage;
292
293 static void collect_keys(
294 Visitor& visitor,
295 const MeshPart<FoundationMesh>& source,
296 Layer layer,
297 const Roots& roots,
298 const Storage& storage)
299 {
300 auto& reg_vertices = source.template get_target_set<0>();
301 auto& root_vertices = roots.template by_dim<0>();
302 for(Index i(0); i < reg_vertices.get_num_entities(); ++i)
303 {
304 auto iter = root_vertices.find(reg_vertices[i]);
305 if(iter != root_vertices.end())
306 {
307 storage.walk_subtree(iter->second, visitor, layer);
308 }
309 }
310 }
311
312 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
313 {
314 auto& result_verts = target.template get_target_set<0>();
315 for(Index i(0); i < visitor.vertices.size(); ++i)
316 {
317 result_verts[i] = storage.get_index(visitor.vertices[i]);
318 }
319 }
320 };
321
329 template<typename AdaptiveMesh_, typename TargetMeshType_>
330 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<1>>
331 {
332 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
333 using Roots = typename AdaptiveMesh_::MeshRoots;
334 using Storage = typename AdaptiveMesh_::MeshStorage;
336
337 static void collect_keys(
338 Visitor& visitor,
339 const MeshPart<FoundationMesh>& source,
340 Layer layer,
341 const Roots& roots,
342 const Storage& storage)
343 {
345 visitor,
346 source,
347 layer,
348 roots,
349 storage);
350
351 auto& reg_edges = source.template get_target_set<1>();
352 auto& root_edges = roots.template by_dim<1>();
353 for(Index i(0); i < reg_edges.get_num_entities(); ++i)
354 {
355 auto iter = root_edges.find(reg_edges[i]);
356 if(iter != root_edges.end())
357 {
358 storage.walk_subtree(iter->second, visitor, layer);
359 }
360 }
361 }
362
363 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
364 {
366
367 auto& result_edges = target.template get_target_set<1>();
368 for(Index i(0); i < visitor.edges.size(); ++i)
369 {
370 result_edges[i] = storage.get_index(visitor.edges[i]);
371 }
372 }
373 };
374
382 template<typename AdaptiveMesh_, typename TargetMeshType_>
383 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<2>>
384 {
385 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
386 using Roots = typename AdaptiveMesh_::MeshRoots;
387 using Storage = typename AdaptiveMesh_::MeshStorage;
389
390 static void collect_keys(
391 Visitor& visitor,
392 const MeshPart<FoundationMesh>& source,
393 Layer layer,
394 const Roots& roots,
395 const Storage& storage)
396 {
398 visitor,
399 source,
400 layer,
401 roots,
402 storage);
403
404 auto& reg_faces = source.template get_target_set<2>();
405 auto& root_faces = roots.template by_dim<2>();
406 for(Index i(0); i < reg_faces.get_num_entities(); ++i)
407 {
408 auto iter = root_faces.find(reg_faces[i]);
409 if(iter != root_faces.end())
410 {
411 storage.walk_subtree(iter->second, visitor, layer);
412 }
413 }
414 }
415
416 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
417 {
419
420 auto& result_faces = target.template get_target_set<2>();
421 for(Index i(0); i < visitor.faces.size(); ++i)
422 {
423 result_faces[i] = storage.get_index(visitor.faces[i]);
424 }
425 }
426 };
427
435 template<typename AdaptiveMesh_, typename TargetMeshType_>
436 struct MeshPartProjector<AdaptiveMesh_, TargetMeshType_, Shape::Hypercube<3>>
437 {
438 using FoundationMesh = typename AdaptiveMesh_::FoundationMeshType;
439 using Roots = typename AdaptiveMesh_::MeshRoots;
440 using Storage = typename AdaptiveMesh_::MeshStorage;
442
443 static void collect_keys(
444 Visitor& visitor,
445 const MeshPart<FoundationMesh>& source,
446 Layer layer,
447 const Roots& roots,
448 const Storage& storage)
449 {
451 visitor,
452 source,
453 layer,
454 roots,
455 storage);
456
457 auto& reg_cells = source.template get_target_set<3>();
458 auto& root_cells = roots.template by_dim<3>();
459 for(Index i(0); i < reg_cells.get_num_entities(); ++i)
460 {
461 auto iter = root_cells.find(reg_cells[i]);
462 if(iter != root_cells.end())
463 {
464 storage.walk_subtree(iter->second, visitor, layer);
465 }
466 }
467 }
468
469 static void write_meshpart(Visitor& visitor, MeshPart<TargetMeshType_>& target, const Storage& storage)
470 {
472
473 auto& result_cells = target.template get_target_set<3>();
474 for(Index i(0); i < visitor.cells.size(); ++i)
475 {
476 result_cells[i] = storage.get_index(visitor.cells[i]);
477 }
478 }
479 };
480
487 {
488 std::set<Index> vertices;
489 std::set<Index> edges;
490 std::set<Index> faces;
491 std::set<Index> cells;
492
493 template<int dim_>
494 const std::set<Index>& by_dim() const
495 {
496 if constexpr(dim_ == 0)
497 {
498 return vertices;
499 }
500 else if constexpr(dim_ == 1)
501 {
502 return edges;
503 }
504 else if constexpr(dim_ == 2)
505 {
506 return faces;
507 }
508 else
509 {
510 return cells;
511 }
512 }
513 };
514
515#ifdef DOXYGEN
525 template<typename Shape_, typename TemplateSet, typename MeshType_>
527 {
536 static void collect(MeshIndexSet& set, const MeshType_& mesh, const SubdivisionLevels& levels, bool import_all)
537 {
538 }
539 };
540#else
541 template<typename Shape_, typename TemplateSet, typename MeshType_>
542 struct EntityCollector;
543#endif
544
552 template<typename TemplateSet, typename MeshType_>
553 struct EntityCollector<Shape::Quadrilateral, TemplateSet, MeshType_>
554 {
556 static void collect(MeshIndexSet& set, const MeshType_& mesh, const RefinementField<typename TemplateSet::VertexMarkerType>& levels, bool import_all)
557 {
558 auto& v_at_f = mesh.template get_index_set<2, 0>();
559 auto& e_at_f = mesh.template get_index_set<2, 1>();
560
561 // Collect either all faces (if import_all is true) or those faces with non-zero refinement type
562 // Also collects all their sub-entities, i.e. surrounding vertices, and edges.
563 for(Index face = 0; face < v_at_f.get_num_entities(); face++)
564 {
565 auto face_levels = levels.get_tuple(v_at_f[face]);
566
567 if(import_all || ! typename TemplateSet::template RefinementTypeByDim<2>(face_levels).is_zero_refinement())
568 {
569 set.faces.insert(face);
570
571 set.edges.insert(e_at_f[face][0]);
572 set.edges.insert(e_at_f[face][1]);
573 set.edges.insert(e_at_f[face][2]);
574 set.edges.insert(e_at_f[face][3]);
575
576 set.vertices.insert(v_at_f[face][0]);
577 set.vertices.insert(v_at_f[face][1]);
578 set.vertices.insert(v_at_f[face][2]);
579 set.vertices.insert(v_at_f[face][3]);
580 }
581 }
582 }
583 };
584
592 template<typename TemplateSet, typename MeshType_>
593 struct EntityCollector<Shape::Hexahedron, TemplateSet, MeshType_>
594 {
596 static void collect(MeshIndexSet& set, const MeshType_& mesh, const RefinementField<typename TemplateSet::VertexMarkerType>& levels, bool import_all)
597 {
598 auto& f_at_c = mesh.template get_index_set<3, 2>();
599 auto& e_at_c = mesh.template get_index_set<3, 1>();
600 auto& v_at_c = mesh.template get_index_set<3, 0>();
601
602 // Collect either all cells (if import_all is true) or those cells with non-zero refinement type
603 // Also collects all their sub-entities, i.e. surrounding vertices, edges, and faces.
604 for(Index cell = 0; cell < v_at_c.get_num_entities(); cell++)
605 {
606 auto cell_levels = levels.get_tuple(v_at_c[cell]);
607
608 if(import_all || ! typename TemplateSet::template RefinementTypeByDim<3>(cell_levels).is_zero_refinement())
609 {
610 set.cells.insert(cell);
611
612 for(int i = 0; i < f_at_c.num_indices; i++)
613 {
614 set.faces.insert(f_at_c[cell][i]);
615 }
616
617 for(int i = 0; i < e_at_c.num_indices; i++)
618 {
619 set.edges.insert(e_at_c[cell][i]);
620 }
621
622 for(int i = 0; i < v_at_c.num_indices; i++)
623 {
624 set.vertices.insert(v_at_c[cell][i]);
625 }
626 }
627 }
628 }
629 };
630
640 template<typename MeshType_, int cell_dim, int face_dim>
641 int congruency(const MeshType_& mesh, Index cell, int face)
642 {
643 using ShapeType = typename MeshType_::ShapeType;
644 using CellShape = typename Shape::FaceTraits<ShapeType, cell_dim>::ShapeType;
645 using FaceShape = typename Shape::FaceTraits<ShapeType, face_dim>::ShapeType;
646 using IndexMapping = Intern::FaceIndexMapping<CellShape, face_dim, 0>;
647 using Sampler = Intern::CongruencySampler<FaceShape>;
648
649 constexpr int face_verts = Shape::FaceTraits<FaceShape, 0>::count;
650
651 auto& face_at_cell = mesh.template get_index_set<cell_dim, face_dim>();
652 auto& v_at_face = mesh.template get_index_set<face_dim, 0>();
653 auto& v_at_cell = mesh.template get_index_set<cell_dim, 0>();
654
655 std::array<Index, face_verts> local;
656
657 for(int i = 0; i < face_verts; i++)
658 {
659 local[i] = v_at_cell[cell][IndexMapping::map(face, i)];
660 }
661 //return Sampler::compare(v_at_face[face_at_cell[cell][face]], local);
662 return Sampler::compare(local, v_at_face[face_at_cell(cell, face)]);
663 }
664
665#ifdef DOXYGEN
677 template<typename AdaptiveMeshType_, int topology_dim_, int collection_dim_>
679 {
680 };
681#else
682 template<typename AdaptiveMeshType_, int topology_dim_, int collection_dim_>
684#endif
685
693 template<typename AdaptiveMeshType_, int topology_dim_>
694 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 0>
695 {
696 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
698 static constexpr int num_vertices = Shape::FaceTraits<TopologyShape, 0>::count;
699
707 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
708 {
709 auto& foundation_entity_vertices = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 0>();
710
711 auto& topology_vertices = topology.template by_dim<0>();
712 auto& root_vertices = a_mesh._roots.template by_dim<0>();
713 for(int vert = 0; vert < num_vertices; vert++)
714 {
715 Index vertex_index = foundation_entity_vertices(entity, vert);
716 topology_vertices[vert] = Intern::OrientedElement<0>(0, root_vertices.at(vertex_index));
717 }
718 }
719 };
720
728 template<typename AdaptiveMeshType_, int topology_dim_>
729 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 1>
730 {
731 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
732 using ShapeType = typename AdaptiveMeshType_::ShapeType;
733 using TopologyShape = typename Shape::FaceTraits<ShapeType, topology_dim_>::ShapeType;
734 static constexpr int num_edges = Shape::FaceTraits<TopologyShape, 1>::count;
735
743 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
744 {
745 // Recursive call to lower dimension
747
748 using FoundationMeshType = typename AdaptiveMeshType_::FoundationMeshType;
749 auto& foundation_entity_edges = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 1>();
750
751 auto& topology_edges = topology.template by_dim<1>();
752 auto& root_edges = a_mesh._roots.template by_dim<1>();
753 for(int edge = 0; edge < num_edges; edge++)
754 {
755 int orientation = congruency<FoundationMeshType, topology_dim_, 1>(a_mesh._foundation_mesh, entity, edge);
756 Index edge_index = foundation_entity_edges(entity, (int)edge);
757 topology_edges[edge] = Intern::OrientedEdge(orientation, root_edges.at(edge_index));
758 }
759 }
760 };
761
769 template<typename AdaptiveMeshType_, int topology_dim_>
770 struct FoundationTopologyCollector<AdaptiveMeshType_, topology_dim_, 2>
771 {
772 using Topology = typename AdaptiveMeshType_::template ElementTopology<topology_dim_>;
773 using ShapeType = typename AdaptiveMeshType_::ShapeType;
774 using TopologyShape = typename Shape::FaceTraits<ShapeType, topology_dim_>::ShapeType;
775 static constexpr int num_faces = Shape::FaceTraits<TopologyShape, 2>::count;
776
784 static void collect(Topology& topology, Index entity, const AdaptiveMeshType_& a_mesh)
785 {
786 // Recursive call to lower dimension
788
789 using FoundationMeshType = typename AdaptiveMeshType_::FoundationMeshType;
790 auto& foundation_entity_faces = a_mesh._foundation_mesh.template get_index_set<topology_dim_, 2>();
791
792 auto& topology_faces = topology.template by_dim<2>();
793 auto& root_faces = a_mesh._roots.template by_dim<2>();
794 for(int face = 0; face < num_faces; face++)
795 {
796 int orientation = congruency<FoundationMeshType, topology_dim_, 2>(a_mesh._foundation_mesh, entity, face);
797 Index face_index = foundation_entity_faces(entity, face);
798 topology_faces[face] = Intern::OrientedFace(orientation, root_faces.at(face_index));
799 }
800 }
801 };
802} // 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