FEAT 3
Finite Element Analysis Toolbox
Loading...
Searching...
No Matches
template_sets.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/refinement_types.hpp>
9#include <kernel/shape.hpp>
10#include <kernel/geometry/template_builder.hpp>
11#include <kernel/geometry/subdivision_levels.hpp>
12#include <kernel/geometry/intern/refinement_field.hpp>
13
14namespace FEAT::Geometry
15{
16 namespace Intern
17 {
18 template<typename Templates_, typename MeshType_>
19 static RefinementField<std::uint64_t>
20 make_standard_refinement_field(const MeshType_& mesh, Templates_& templates, const Geometry::SubdivisionLevels& sdls)
21 {
22 using ShapeType = typename MeshType_::ShapeType;
23 static const constexpr int dim = MeshType_::shape_dim;
24 static const constexpr int num_vertices = Shape::FaceTraits<ShapeType, 0>::count;
25 //static const constexpr int num_neighbors = Shape::FaceTraits<ShapeType, dim - 1>::count;
26
27 // Copy SDLs into refinement field
28 RefinementField<std::uint64_t> result(sdls.size());
29 for(Index i(0); i < sdls.size(); ++i)
30 {
31 result[i] = sdls[i];
32 }
33
34 // We need to ensure the refinement field contains subdivision levels
35 // such that all cells (and their (grand-)children) have valid refinement
36 // types, for which templates exist. We treat the markings for a cells
37 // vertices as a series of refinement types and ensure that each type is
38 // valid. This is equivalent to assuming that each of these types will occur
39 // in some (grand-)child at least once. That is not necessarily the case, as
40 // refinement levels get spread during mesh adaptation, but is a safe
41 // assumption. As an example, consider a cell where two diagonally opposite
42 // vertices are marked. These vertices will not be shared by any child cell,
43 // and their levels could be adjusted individually after the first refinement.
44
45 // Grab necessary mesh and template info
46 const auto& v_at_c = mesh.template get_index_set<dim, 0>();
47 //const auto& neighbors = mesh.get_neighbors();
48
49 // The worklist indicates which cells still need to be checked. At the
50 // beginning all cells need to be checked. If a cells refinement types are
51 // all valid, it gets removed from the worklist. If a cells vertex markings
52 // needed to be adjusted, its neighboring cells get added to the worklist, as
53 // modifying the vertex markings changed those cells types as well.
54 std::vector<bool> worklist(mesh.get_num_elements(), true);
55
56 while(true)
57 {
58 // Find cell to check
59 auto it = std::find(worklist.begin(), worklist.end(), true);
60
61 // No remaining marked cells in worklist. We are done.
62 if(it == worklist.end())
63 {
64 break;
65 }
66
67 Index cell = std::distance(worklist.begin(), it);
68
69 RefinementFieldTuple<std::uint64_t, num_vertices> levels =
70 result.get_tuple(v_at_c[cell]);
71
72 StandardRefinementType<ShapeType> type(levels);
73
74 while(true)
75 {
76 // Strip away levels until type is no longer valid or type is zero type.
77 while(!type.is_zero_refinement() && templates.template has_template<dim>(type))
78 {
79 // Type is valid. Decrement markings to check next type.
80 for(Index i(0); i < num_vertices; i++)
81 {
82 levels[i] = levels[i] > 0 ? levels[i] - 1 : 0;
83 }
84 type = StandardRefinementType<ShapeType>(levels);
85 }
86
87 if(type.is_zero_refinement())
88 {
89 // No markings left. All types of the cell are valid.
90 worklist[cell] = false;
91 break;
92 }
93
94 // Invalid type found. Adjust levels
95 auto& adjustment = templates.template type_adjustment<dim>(type.to_number());
96 for(int i(0); i < num_vertices; i++)
97 {
98 result[v_at_c[cell][i]] += adjustment[i];
99 levels[i] += adjustment[i];
100 }
101 type = StandardRefinementType<ShapeType>(levels);
102
103 // We changed the cells vertex markings. This also changed the markings
104 // of its neighbors. We need to re-check those.
105 /*for(Index i(0); i < num_neighbors; i++)
106 {
107 if(neighbors(cell, i) != ~Index(0))
108 {
109 worklist[neighbors(cell, i)] = true;
110 }
111 }*/
112 for(Index idx = 0; idx < mesh.get_num_elements(); idx++)
113 {
114 worklist[idx] = true;
115 }
116 // Continue checking
117 }
118 }
119 return result;
120 }
121
122 template<typename Templates_, typename MeshType_>
123 static RefinementField<IsolatedPointVertexMarking>
124 make_isolated_point_refinement_field(const MeshType_& mesh, Templates_& templates, const Geometry::SubdivisionLevels& sdls)
125 {
126 using ShapeType = typename MeshType_::ShapeType;
127 static const constexpr int dim = MeshType_::shape_dim;
128 static const constexpr int num_vertices = Shape::FaceTraits<ShapeType, 0>::count;
129 //static const constexpr int num_neighbors = Shape::FaceTraits<ShapeType, dim - 1>::count;
130
131 // Copy SDLs into refinement field. We assume that all marked vertices
132 // are isolated.
133 RefinementField<IsolatedPointVertexMarking> result(sdls.size());
134 for(Index i(0); i < sdls.size(); ++i)
135 {
136 result[i] = IsolatedPointVertexMarking{sdls[i], sdls[i] > 0};
137 }
138
139 // We need to ensure the refinement field contains markings such that all
140 // cells (and their (grand-)children) have valid refinement types, for which
141 // templates exist. We treat the markings for a cells vertices as a series of
142 // refinement types and ensure that each type is valid. This is equivalent to
143 // assuming that each of these types will occur in some (grand-)child at
144 // least once. That is not necessarily the case, as refinement levels get
145 // spread during mesh adaptation, but is a safe assumption. As an example,
146 // consider a cell where two diagonally opposite vertices are marked. These
147 // vertices will not be shared by any child cell, and their levels could be
148 // adjusted individually after the first refinement.
149
150 // Grab necessary mesh and template info
151 const auto& v_at_c = mesh.template get_index_set<dim, 0>();
152 //const auto& neighbors = mesh.get_neighbors();
153
154 // The worklist indicates which cells still need to be checked. At the
155 // beginning all cells need to be checked. If a cells refinement types are
156 // all valid, it gets removed from the worklist. If a cells vertex markings
157 // needed to be adjusted, its neighboring cells get added to the worklist, as
158 // modifying the vertex markings changed those cells types as well.
159 std::vector<bool> worklist(mesh.get_num_elements(), true);
160
161 // Build accurate information about isolated points
162 auto determine_isolation = [&]()
163 {
164 // A vertex is not isolated, if it is marked together with another
165 // vertex in at least one cell
166 for(Index cell = 0; cell < mesh.get_num_elements(); cell++)
167 {
168 Index num_marked = 0;
169 for(int vertex(0); vertex < v_at_c.num_indices; vertex++)
170 {
171 num_marked += result[v_at_c(cell, vertex)].level > 0 ? 1 : 0;
172 }
173
174 if(num_marked != 1)
175 {
176 for(int vertex(0); vertex < v_at_c.num_indices; vertex++)
177 {
178 result[v_at_c(cell, vertex)].is_isolated = false;
179 }
180 }
181 }
182 };
183
184
185 while(true)
186 {
187 // (Re-)determine isolation of vertices. Adjustments might have caused
188 // previously isolated vertices to no longer be isolated.
189 determine_isolation();
190 // Find cell to check
191 auto it = std::find(worklist.begin(), worklist.end(), true);
192
193 // No remaining marked cells in worklist. We are done.
194 if(it == worklist.end())
195 {
196 break;
197 }
198
199 Index cell = std::distance(worklist.begin(), it);
200
201 RefinementFieldTuple<IsolatedPointVertexMarking, num_vertices> levels =
202 result.get_tuple(v_at_c[cell]);
203
204 IsolatedPointRefinementType<ShapeType> type(levels);
205
206 while(true)
207 {
208 // Strip away levels until type is no longer valid or type is zero type.
209 while(!type.is_zero_refinement() && templates.template has_template<dim>(type))
210 {
211 // Type is valid. Decrement markings to check next type.
212 for(Index i(0); i < num_vertices; i++)
213 {
214 levels[i].level = levels[i].level > 0 ? levels[i].level - 1 : 0;
215 }
216 type = IsolatedPointRefinementType<ShapeType>(levels);
217 }
218
219 if(type.is_zero_refinement())
220 {
221 // No markings left. All types of the cell are valid.
222 worklist[cell] = false;
223 break;
224 }
225
226 // Invalid type found. Adjust levels
227 // NOTE(mmuegge): We do not need to consider isolation here.
228 // levels contains either:
229 // * no marked vertices, in which case we do not hit this code path
230 // * a single isolated marked vertex, in which case all possible
231 // templates exist and we do not hit this code path
232 // * multiple marked vertices, in which case they aren't isolated per
233 // definition, and adding additional markings will not cause a previously
234 // isolated vertex (of this tuple) to become unisolated.
235 // Also note that this does not preclude some other vertex from no
236 // longer being isolated. We handle this by re-determining isolation at
237 // the start of checking each cell.
238 auto& adjustment = templates.template type_adjustment<dim>(type.to_number());
239 for(int i(0); i < num_vertices; i++)
240 {
241 result[v_at_c[cell][i]].level += adjustment[i];
242 levels[i].level += adjustment[i];
243 }
244 type = IsolatedPointRefinementType<ShapeType>(levels);
245
246 // We changed the cells vertex markings. This also changed the markings
247 // of its neighbors. We need to re-check those.
248 for(Index idx = 0; idx < mesh.get_num_elements(); idx++)
249 {
250 worklist[idx] = true;
251 }
252 /*for(Index i(0); i < num_neighbors; i++)
253 {
254 if(neighbors(cell, i) != ~Index(0))
255 {
256 worklist[neighbors(cell, i)] = true;
257 }
258 }*/
259 // Continue checking
260 }
261 }
262 return result;
263 }
264
265 template<typename Shape_>
266 std::uint64_t
267 spread_refinement_field(
268 const EntityReference& ref,
269 const Geometry::Intern::RefinementFieldTuple<std::uint64_t, Shape::FaceTraits<Shape_, 0>::count>& markings)
270 {
271 switch(ref.source)
272 {
273 case EntitySource::ParentTopology: return markings[ref.index] > 0 ? markings[ref.index] - 1 : 0;
275 {
276 std::uint64_t min = markings[0];
277 for(Index i(1); i < markings.size; ++i)
278 {
279 min = std::min(min, markings[i]);
280 }
281 return min > 0 ? min - 1 : 0;
282 }
284 {
285 if constexpr (Shape_::dimension >= 2)
286 {
287 using Mapping = Intern::FaceIndexMapping<Shape_, 1, 0>;
288
289 int face = ref.entity;
290
291 std::uint64_t min = markings[Mapping::map(face, 0)];
292 for(int i(1); i < 2; ++i)
293 {
294 min = std::min(min, markings[Mapping::map(face, i)]);
295 }
296 return min > 0 ? min - 1 : 0;
297 }
298 return 0;
299 }
301 {
302 if constexpr (Shape_::dimension >= 3)
303 {
304 using Mapping = Intern::FaceIndexMapping<Shape_, 2, 0>;
305
306 int face = ref.entity;
307
308 std::uint64_t min = markings[Mapping::map(face, 0)];
309 for(int i(1); i < 4; ++i)
310 {
311 min = std::min(min, markings[Mapping::map(face, i)]);
312 }
313 return min > 0 ? min - 1 : 0;
314 }
315 return 0;
316 }
317 default:
318 return 0;
319 }
320 }
321
322 template<typename Shape_>
323 IsolatedPointVertexMarking
324 spread_refinement_field(
325 const EntityReference& ref,
326 const Geometry::Intern::RefinementFieldTuple<IsolatedPointVertexMarking, Shape::FaceTraits<Shape_, 0>::count>& markings)
327 {
328 switch(ref.source)
329 {
330 case EntitySource::ParentTopology: return {
331 markings[ref.index].level > 0 ? markings[ref.index].level - 1 : 0,
332 markings[ref.index].is_isolated
333 };
335 {
336 std::uint64_t min = markings[0].level;
337 for(Index i(1); i < markings.size; ++i)
338 {
339 min = std::min(min, markings[i].level);
340 }
341 return {min > 0 ? min - 1 : 0, false};
342 }
344 {
345 if constexpr (Shape_::dimension >= 2)
346 {
347 using Mapping = Intern::FaceIndexMapping<Shape_, 1, 0>;
348
349 int face = ref.entity;
350
351 std::uint64_t min = markings[Mapping::map(face, 0)].level;
352 for(int i(1); i < 2; ++i)
353 {
354 min = std::min(min, markings[Mapping::map(face, i)].level);
355 }
356 return {min > 0 ? min - 1 : 0, false};
357 }
358 return {0, false};
359 }
361 {
362 if constexpr (Shape_::dimension >= 3)
363 {
364 using Mapping = Intern::FaceIndexMapping<Shape_, 2, 0>;
365
366 int face = ref.entity;
367
368 std::uint64_t min = markings[Mapping::map(face, 0)].level;
369 for(int i(1); i < 4; ++i)
370 {
371 min = std::min(min, markings[Mapping::map(face, i)].level);
372 }
373 return {min > 0 ? min - 1 : 0, false};
374 }
375 return {0, false};
376 }
377 default:
378 return {0, false};
379 }
380 }
381 } // namespace Intern
382
393 template<typename RawData_>
395 {
396 inline static TemplateBuilder<RawData_> _templates = {};
397
398 using MaxShape = typename RawData_::MaxShape;
399 public:
400 using VertexMarkerType = std::uint64_t;
401
402 template<int dim_>
404
405 template<typename Shape_>
407
415 template<typename Shape_>
416 static constexpr bool is_shape_compatible()
417 {
418 return RawData_::template is_shape_compatible<Shape_>();
419 }
420
421 static void stats()
422 {
423 _templates().stats();
424 }
425
432 template<int template_dim_, int child_dim_>
433 static constexpr int max_children()
434 {
435 return RawData_::template max_children<template_dim_, child_dim_>();
436 }
437
446 template<typename Mesh_>
448 {
449 return Intern::make_standard_refinement_field(mesh, _templates, sdls);
450 }
451
452 template<typename Shape_>
453 static VertexMarkerType spread_refinement_field(
454 const EntityReference& ref,
456 {
457 return Intern::spread_refinement_field<Shape_>(ref, levels);
458 }
459
460 template<typename Shape_>
461 static const RefinementTemplate<Shape_>& get_template(StandardRefinementType<Shape_> type)
462 {
463 return _templates.template get_template<Shape_::dimension>(type);
464 }
465
466 template<typename Shape_>
467 static bool has_template(StandardRefinementType<Shape_> type)
468 {
469 return _templates.template has_template<Shape_::dimension>(type);
470 }
471
472 template<typename Shape_, int dim_>
473 static std::pair<Index, int> correct_for_orientation(StandardRefinementType<Shape_> type, int orientation, Index idx)
474 {
475 return _templates.template correct_for_orientation<Shape_::dimension, dim_>(type, orientation, idx);
476 }
477
491 template<int template_dim_, int child_dim_>
493 {
494 return _templates.template get_template<template_dim_>(type).template num_entities<child_dim_>();
495 }
496 };
497
508 template<typename RawData_>
510 {
511 using MaxShape = typename RawData_::MaxShape;
512 public:
514
515 template<int dim_>
517
518 template<typename Shape_>
520
528 template<typename Shape_>
529 static constexpr bool is_shape_compatible()
530 {
531 return RawData_::template is_shape_compatible<Shape_>();
532 }
533
534 static void stats()
535 {
536 _templates().stats();
537 }
538
545 template<int template_dim_, int child_dim_>
546 static constexpr int max_children()
547 {
548 return RawData_::template max_children<template_dim_, child_dim_>();
549 }
550
559 template<typename Mesh_>
561 {
562 return Intern::make_isolated_point_refinement_field(mesh, _templates(), sdls);
563 }
564
565 template<typename Shape_>
566 static VertexMarkerType spread_refinement_field(
567 const EntityReference& ref,
569 {
570 return Intern::spread_refinement_field<Shape_>(ref, levels);
571 }
572
573 template<typename Shape_>
574 static const RefinementTemplate<Shape_>& get_template(IsolatedPointRefinementType<Shape_> type)
575 {
576 return _templates().template get_template<Shape_::dimension>(type);
577 }
578
579 template<typename Shape_>
580 static bool has_template(StandardRefinementType<Shape_> type)
581 {
582 return _templates().template has_template<Shape_::dimension>(type);
583 }
584
585 template<typename Shape_, int dim_>
586 static std::pair<Index, int> correct_for_orientation(IsolatedPointRefinementType<Shape_> type, int orientation, Index idx)
587 {
588 return _templates().template correct_for_orientation<Shape_::dimension, dim_>(type, orientation, idx);
589 }
590
604 template<int template_dim_, int child_dim_>
606 {
607 return _templates().template get_template<template_dim_>(type).template num_entities<child_dim_>();
608 }
609
610 private:
611 static TemplateBuilder<RawData_>& _templates()
612 {
613 static TemplateBuilder<RawData_> _static_templates = {};
614 return _static_templates;
615 }
616
617 };
618} // namespace FEAT::Geometry
Schneiders template set for adaptive mesh refinement.
static Intern::RefinementField< IsolatedPointVertexMarking > make_refinement_field(const Mesh_ &mesh, Geometry::SubdivisionLevels &sdls)
Adjusts SubdivisionLevels to match TemplateSet requirements.
static constexpr bool is_shape_compatible()
Shape compatability test.
static constexpr int max_children()
Returns maximum number of children a template produces.
static Index num_children(IsolatedPointRefinementType< typename Shape::FaceTraits< MaxShape, template_dim_ >::ShapeType > type)
Returns number of children a specific template produces.
Schneiders template set for adaptive mesh refinement.
static constexpr bool is_shape_compatible()
Shape compatability test.
static Index num_children(StandardRefinementType< typename Shape::FaceTraits< MaxShape, template_dim_ >::ShapeType > type)
Returns number of children a specific template produces.
static Intern::RefinementField< std::uint64_t > make_refinement_field(const Mesh_ &mesh, Geometry::SubdivisionLevels &sdls)
Adjusts SubdivisionLevels to match TemplateSet requirements.
static constexpr int max_children()
Returns maximum number of children a template produces.
Subdivision level markings for meshes.
Constructs RefinementTemplates from RawTemplates.
void stats()
print some stats about maximum children in the raw data
Geometry namespace.
@ BoundaryEdge
Entity is part of a boundary edge, i.e. a child of one of the parents edges.
@ ParentTopology
Entity is part of the parents topology.
@ BoundaryFace
Entity is part of a boundary face, i.e. a child of one of the parents faces.
@ Sibling
Entity is a sibling in the refinement tree.
T_ min(T_ a, T_ b)
Returns the minimum of two values.
Definition: math.hpp:123
std::uint64_t Index
Index data type.
Reference to another local mesh entity.
Face traits tag struct template.
Definition: shape.hpp:106