Peano
Loading...
Searching...
No Matches
DynamicMeshRefinement.py
Go to the documentation of this file.
1# This file is part of the ExaHyPE2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3import jinja2
4
5import peano4.api
6from peano4.api.solversteps.ActionSet import ActionSet
7
9 """!
10
11 Evaluate the point-wise refinement criterion and collect the outcome as
12 refine and erase requests
13
14 The numerical schemes add this action set to the very last task of their
15 time step if the solver has an exahype2.api.RefineErasePointwisely PDE
16 term (@ref exahype2.api.blockstructured.create_dynamic_mesh_refinement_action_set.create_dynamic_mesh_refinement_action_set()). The action set
17 loops over all volumes of each patch and invokes the term per volume
18 centre. It initialises the term's output with Keep. From the outcomes of
19 all the volumes, it derives one command for the whole cell:
20
21 - If any volume says Refine, the cell asks for a refinement.
22 - If all volumes say Erase, the cell asks to be erased, i.e. coarsened.
23 - Otherwise, the cell is kept and does not issue any command.
24
25 The action set bounds the mesh size. Refine commands are dropped for
26 cells whose volumes are already smaller than min_volume_size. Erase
27 commands are dropped if the volumes of the coarsened cell would not be
28 smaller than max_volume_size. If a bound is None, the mesh size is not
29 constrained. As the action set drops these commands, it does not issue
30 requests which the mesh cannot realise anyway, and the mesh adaptation
31 phase is only triggered if the mesh actually can change. The numerical
32 schemes take the two bounds as constructor arguments and pass them
33 through.
34
35 Peano erases the children of a cell only if they all ask for it. Erase
36 commands therefore carry the cell's position within its parent, and the
37 refinement service keeps them only if all 3^d children of a parent have
38 asked to be erased within the same mesh sweep
39 (@ref exahype2::RefinementControlService::keepOnlyCompleteSiblingEraseEvents()).
40 Incomplete sets of erase requests are dropped right away, so they never
41 trigger the mesh adaptation phase.
42
43 The action set collects the commands of one tree within a local
44 ::exahype2::RefinementControl, merges it into the rank's
45 ::exahype2::RefinementControlService at the end of the traversal, and
46 commits the new events once per rank in unprepareTraversal(). By
47 default, it does not hand any event over to Peano, i.e. the time step
48 itself never changes the mesh. The mesh adaptation phase consumes the
49 requests (@ref exahype2::isMeshAdaptationRequired()). The setup's mesh
50 adaptation (@ref exahype2.api.fv.SetupSimulationWithUserCodedRefinementCriterion)
51 instead lets the action set hand the events over to Peano right away
52 (hand_events_to_peano). It also vetoes all erase commands (veto_erase):
53 The setup has no restriction which would hand the patches of erased
54 cells over to their parent, i.e. a parent would end up with an
55 uninitialised patch. The mesh adaptation phase of the time stepping
56 always restricts (@ref toolbox.blockstructured.api.InterpolateAndRestrictCells).
57
58 Subclasses which evaluate a different adaptivity criterion only replace
59 the per-volume evaluation (@ref exahype2.api.blockstructured.DynamicMeshRefinement.DynamicMeshRefinement.get_volume_evaluation()), e.g.
60 exahype2.api.blockstructured.DynamicMeshRefinementWithGradients.
61
62 The action set works for all block-structured schemes which hold their
63 unknowns as patch_size^d volumes (or grid cells) per mesh cell, i.e. for
64 exahype2.api.fv and exahype2.api.rkfd4.
65
66 """
67
69 self,
70 solver,
71 patch_size: int,
72 guard: str,
73 min_volume_size: float = None,
74 max_volume_size: float = None,
75 event_lifetime: int = 2,
76 hand_events_to_peano: bool = False,
77 veto_erase: bool = False,
78 ):
79 """!
80
81 @param solver: exahype2.api.Solver
82 The solver whose criterion is evaluated.
83
84 @param patch_size: int
85 Number of volumes per axis within one patch.
86
87 @param guard: str
88 C++ boolean expression, evaluated per cell, guarding whether the
89 criterion is evaluated for that cell.
90
91 @param min_volume_size: float
92 A cell asks for a refinement only if its volumes are at least of
93 this size. None does not bound the refinement.
94
95 @param max_volume_size: float
96 A cell asks to be erased only if the volumes of the coarser cell
97 are strictly smaller than this size. None does not bound the
98 coarsening.
99
100 @param event_lifetime: int
101 Number of mesh sweeps a refinement or erase event remains alive
102 within the refinement service (@ref exahype2::RefinementControl::addCommand()).
103
104 @param hand_events_to_peano: bool
105 Hand the refinement service's committed events over to Peano, so
106 Peano realises them in the subsequent mesh sweeps. The time step
107 leaves this off, the setup's mesh adaptation switches it on.
108
109 @param veto_erase: bool
110 Drop all erase commands, i.e. only ever refine. The time step
111 leaves this off, the setup's mesh adaptation switches it on.
112
113 """
114 super().__init__(descend_invocation_order=1, parallel=False)
115 self._solver = solver
116 self.patch_size = patch_size
117 self.guard = guard
118 self.event_lifetime = event_lifetime
119 self.min_volume_size = min_volume_size
120 self.max_volume_size = max_volume_size
121 self.hand_events_to_peano = hand_events_to_peano
122 self.veto_erase = veto_erase
123
124
125 TemplateEvaluateVolume = """
126 const int index = peano4::utils::dLinearised(volume,{{NUMBER_OF_VOLUMES_PER_AXIS}}) * ({{NUMBER_OF_UNKNOWNS}} + {{NUMBER_OF_AUXILIARY_VARIABLES}});
127 ::exahype2::RefinementCommand command = ::exahype2::RefinementCommand::Keep;
128 repositories::{{SOLVER_INSTANCE}}.refineErasePointwisely(
129 fineGridCell{{UNKNOWN_IDENTIFIER}}.value + index,
130 ::exahype2::fv::getVolumeCentre( marker.x(), marker.h(), {{NUMBER_OF_VOLUMES_PER_AXIS}}, volume),
131 repositories::{{SOLVER_INSTANCE}}.getMinTimeStamp(),
132 &command
133 );
134 anyVolumeWantsToRefine = anyVolumeWantsToRefine or command == ::exahype2::RefinementCommand::Refine;
135 allVolumesWantToErase = allVolumesWantToErase and command == ::exahype2::RefinementCommand::Erase;
136"""
137
138 def get_volume_evaluation(self) -> str:
139 """!
140
141 C++ Jinja2 template evaluating the criterion within one volume
142
143 The template runs within a loop over the volumes of the patch, i.e.
144 it has access to the volume's index volume. It has to update the
145 two flags anyVolumeWantsToRefine and allVolumesWantToErase.
146
147 """
148 return self.TemplateEvaluateVolume
149
150 TemplateEvaluateCriterion = """
151 logTraceIn( "touchCellFirstTime(...)---DynamicMeshRefinement" );
152 bool anyVolumeWantsToRefine = false;
153 bool allVolumesWantToErase = true;
154 dfor( volume, {{NUMBER_OF_VOLUMES_PER_AXIS}} ) {
155{{EVALUATE_VOLUME}}
156 }
157
158 if ( anyVolumeWantsToRefine {{REFINE_BOUND}}) {
159 _localRefinementControl.addCommand( marker.x(), marker.h(), ::exahype2::RefinementCommand::Refine, {{EVENT_LIFETIME}} );
160 }
161{%- if not VETO_ERASE %}
162 else if ( not anyVolumeWantsToRefine and allVolumesWantToErase {{ERASE_BOUND}}) {
163 _localRefinementControl.addCommand( marker.x(), marker.h(), ::exahype2::RefinementCommand::Erase, {{EVENT_LIFETIME}}, marker.getRelativePositionWithinFatherCell() );
164 }
165{%- endif %}
166 logTraceOut( "touchCellFirstTime(...)---DynamicMeshRefinement" );
167"""
168
169 def get_body_of_operation(self, operation_name):
170 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
171 return " _localRefinementControl.clear();\n"
172 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
173 return " ::exahype2::RefinementControlService::getInstance().merge( _localRefinementControl );\n"
174 if operation_name == ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
175 refine_bound = ""
176 if self.min_volume_size is not None:
177 min_cell_size = float(self.min_volume_size) * self.patch_size
178 refine_bound = f"and tarch::la::max( marker.h() ) >= {min_cell_size!r} "
179 erase_bound = ""
180 if self.max_volume_size is not None:
181 max_cell_size = float(self.max_volume_size) * self.patch_size
182 erase_bound = (
183 f"and 3.0 * tarch::la::max( marker.h() ) < {max_cell_size!r} "
184 )
185 d = {
186 "NUMBER_OF_VOLUMES_PER_AXIS": self.patch_size,
187 "NUMBER_OF_UNKNOWNS": self._solver.unknowns,
188 "NUMBER_OF_AUXILIARY_VARIABLES": self._solver.auxiliary_variables,
189 "UNKNOWN_IDENTIFIER": self._solver._unknown_identifier(),
190 "SOLVER_INSTANCE": self._solver.get_name_of_global_instance(),
191 "REFINE_BOUND": refine_bound,
192 "ERASE_BOUND": erase_bound,
193 "EVENT_LIFETIME": self.event_lifetime,
194 "VETO_ERASE": self.veto_erase,
195 }
196 template = self.TemplateEvaluateCriterion.replace(
197 "{{EVALUATE_VOLUME}}", self.get_volume_evaluation()
198 )
199 return jinja2.Template(template).render(**d)
200 return ""
201
202 def get_guard_of_operation(self, operation_name):
203 if operation_name == ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
204 return self.guard
205 return "true"
206
208 """!
209
210 Commit the new events once per rank and mesh sweep, after all trees
211 have merged their local events into the service
212
213 """
214 return " ::exahype2::RefinementControlService::getInstance().finishStep();\n"
215
217 if not self.hand_events_to_peano:
219 return " return ::exahype2::RefinementControlService::getInstance().createGridControlEventsForNextTraversal();\n"
220
221 def get_attributes(self):
222 return """
223 ::exahype2::RefinementControl _localRefinementControl;
224"""
225
227 return __name__.replace(".py", "").replace(".", "_")
228
230 return False
231
232 def get_includes(self):
233 return (
234 """
235#include "exahype2/RefinementControl.h"
236#include "exahype2/RefinementControlService.h"
237#include "exahype2/fv/PatchUtils.h"
238"""
239 + self._solver._get_default_includes()
240 + self._solver.user_solver_includes
241 )
Evaluate the point-wise refinement criterion and collect the outcome as refine and erase requests.
str get_volume_evaluation(self)
C++ Jinja2 template evaluating the criterion within one volume.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
__init__(self, solver, int patch_size, str guard, float min_volume_size=None, float max_volume_size=None, int event_lifetime=2, bool hand_events_to_peano=False, bool veto_erase=False)
get_guard_of_operation(self, operation_name)
Return the guard of an operation.
get_body_of_unprepareTraversal(self)
Commit the new events once per rank and mesh sweep, after all trees have merged their local events in...
get_body_of_createGridControlEventsForNextTraversal(self)
Return the grid control events that this action set wants to trigger.
str TemplateEvaluateVolume
Per-volume evaluation of the point-wise criterion.
get_attributes(self)
Return attributes as copied and pasted into the generated class.
Action set (reactions to events)
Definition ActionSet.py:6