Peano
Loading...
Searching...
No Matches
DynamicAMR.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 peano4
4import exahype2
5import jinja2
6
7
8from .AbstractRKFDActionSet import AbstractRKFDActionSet
9
10
12 """
13
14 The handling of (dynamically) adaptive meshes for finite differences
15
16 This class just invokes interpolation operators. Please consult the documentation
17 of the base class CellCenteredFiniteDifferences for a discussion of interpolation
18 and restriction operators. The class documentation also explains how you switch
19 to operators that you pass in manually.
20
21 """
22
23
24 def __init__(self,
25 solver,
26 interpolation,
27 restriction):
28 """
29 Construct object
30
31
32 :: Interpolation
33
34 Don't interpolate in initialisation. If you have a parallel run with AMR, then some
35 boundary data has not been received yet and your face data thus is not initialised
36 at all. Other than that, the interpolation is always on.
37
38
39 :: Restriction
40
41 In contrast to the interpolation, it is absolutely key that we restrict alreaday in
42 the initialisation. If we have a cell that is adjacent to a refined cell, then this
43 cell requires proper face data for the subsequent first time step. So we have to
44 restrict in the initialisation even if there's no update yet - just to get the
45 coarse representation of fine hanging faces initialised.
46
47
48 :: Restriction of destructed faces
49
50 A destructed face has to restrict its data: We've already restricted the cells,
51 but now we also have to restrict the faces, as faces span time spans. The cell
52 is only a snapshot, so we have to manually restrict.
53
54 It is important to also disable the projection in return. The projection onto the
55 faces happens in leaveCell. However, if you have a face in-between two 3x3 patches,
56 then you will have a destruction of the left patch (and a corresponding cell restriction),
57 the coarse cell will then project its data onto the face, you go down on the other
58 side and now the face will be destroyed. If you restrict now, you overwrite the
59 projected data with some (old) data, and you will get an inconsistent face data.
60 However, you always have to restrict both sides of persistent face when it is
61 destroyed. If you only restricted the inner part, you'd run into situations where
62 a 3x3 patch is coarsened, but its neighbour remains refined. That is, logically the
63 face transitions from a persistent one to a hanging face. When yo go through the
64 mesh next time, you'll need, on the coarse level, some valid data. So we have to
65 restrict both sides.
66
67 There's still a inconsistency here. To have really consistent data, we'd have to
68 average 3^{d-1} cells when we project them onto the face, such that the cell-restricted
69 data followed by a (single cell) projection gives the same result as a projection
70 first and then a face restriction. I neglect this fact here.
71
72
73 :: Interpolation throughout the grid initialisation
74
75 Throughout the grid initialisation, we cannot interpolate the halo layers reliably.
76 If we descend into a cell and want to initialise one of its hanging faces, we cannot
77 know, if the coarser cell on the other side has been initialised already. Therefore,
78 we cannot initialise the halo of a hanging face.
79
80 For persistent faces, this is something we don't bother about: We create both
81 adjacent cells of the respective face and then we will project this solution onto
82 the faces. Problem set, as all data is properly set.
83
84 For hanging faces, we will get the projection from the adjacent real cell. But
85 we cannot get a proper initialisation for the other half of the face data. These
86 data however is required for some restrictions. Even if we mask out the impact
87 of halo data on the restriction, it might, in the initialisation sweep, hold
88 nans, and 0 * nan = nan. So we will get garbage. In later time steps, this does
89 not hold, as we have properly initialised coarse grid data then on all sides.
90
91 To solve this issue, we initialise the hanging face data properly using the user's
92 callbacks. These data will later be overwritten with (coarser) data which is
93 interpolated. For the initialisation, it provides us with proper initial guesses.
94
95
96 """
97 super( DynamicAMR, self ).__init__(
98 patch = solver._patch,
99 patch_overlap_interpolation = solver._patch_overlap_old,
100 patch_overlap_restriction = solver._patch_overlap_update,
101 interpolation_scheme = interpolation,
102 restriction_scheme = restriction,
103 clear_guard = solver._provide_face_data_to_compute_kernels_default_guard(),
104 interpolate_guard = solver._provide_face_data_to_compute_kernels_default_guard() + """ and
105 repositories::""" + solver.get_name_of_global_instance() + """.getSolverState()!=""" + solver._name + """::SolverState::GridInitialisation
106""",
107 restrict_guard = solver._provide_face_data_to_compute_kernels_default_guard(),
108 additional_includes = """
109#include "../repositories/SolverRepository.h"
110"""
111)
112
113 self.d[ "SOLVER_INSTANCE" ] = solver.get_name_of_global_instance()
114 self.d[ "FINE_GRID_FACE_ACCESSOR_INTERPOLATION" ] = "fineGridFace" + solver._name
115 self.d[ "FINE_GRID_FACE_ACCESSOR_INTERPOLATION" ] = "fineGridFace" + solver._name
116 self.d[ "COARSE_GRID_FACE_ACCESSOR_INTERPOLATION" ] = "coarseGridFaces" + solver._name
117 self.d[ "FINE_GRID_FACE_ACCESSOR_RESTRICTION" ] = "fineGridFace" + solver._name
118 self.d[ "COARSE_GRID_FACE_ACCESSOR_RESTRICTION" ] = "coarseGridFaces" + solver._name
119
120 """
121
122 Touch first time does nothing proper. It simply clears the halo
123 layer.
124
125 """
127 if ( {{CLEAR_GUARD}} ) {
128 logTraceInWith2Arguments( "touchFaceFirstTime(...)", marker.toString(), "clear halo layer {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}" );
129
130 ::toolbox::blockstructured::clearHaloLayerAoS(
131 marker,
132 {{DOFS_PER_AXIS}},
133 {{OVERLAP}},
134 {{UNKNOWNS}},
135 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value
136 );
137
138 logTraceOut( "touchFaceFirstTime(...)" );
139 }
140"""
141
142 """
143
144 Very similar to original toolbox's routine, but this one restricts
145 into QUpdate, and leaves QOld and QNew unchanged. Furthermore to the
146 actual data restriction, we also restrict the updated flag and the
147 time face's time stamp.
148
149 """
151 if ( {{RESTRICT_GUARD}} ) {
152 logTraceInWith4Arguments( "destroyHangingFace(...)", "{{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}", "{{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}", marker.getSelectedFaceNumber(), marker.toString() );
153
154 ::toolbox::blockstructured::restrictInnerHalfOfHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
155 marker,
156 {{DOFS_PER_AXIS}},
157 {{OVERLAP}},
158 {{UNKNOWNS}},
159 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value,
160 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate(marker.getSelectedFaceNumber()).value
161 );
162
163 bool isLeftEntryOnCoarseFaceLabel = marker.getSelectedFaceNumber() >= Dimensions;
164 double newTimeStamp = std::max( coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getUpdatedTimeStamp( isLeftEntryOnCoarseFaceLabel ? 0 : 1 ), fineGridFace""" + solver._face_label.name + """.getUpdatedTimeStamp( isLeftEntryOnCoarseFaceLabel ? 0 : 1 ));
165 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setUpdated( isLeftEntryOnCoarseFaceLabel ? 0 : 1,true);
166 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setUpdatedTimeStamp( isLeftEntryOnCoarseFaceLabel ? 0 : 1,newTimeStamp);
167
168 logTraceOut( "destroyHangingFace(...)" );
169 }
170"""
171
173 if ( not marker.isInteriorFaceWithinPatch() ) {
174 logTraceIn( "destroyPersistentFace(...)" );
175
176 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
177 marker,
178 {{DOFS_PER_AXIS}},
179 {{OVERLAP}},
180 {{UNKNOWNS}},
181 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value,
182 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate(marker.getSelectedFaceNumber()).value
183 );
184
185 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
186 marker,
187 {{DOFS_PER_AXIS}},
188 {{OVERLAP}},
189 {{UNKNOWNS}},
190 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QNew.value,
191 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QNew(marker.getSelectedFaceNumber()).value
192 );
193
194 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
195 marker,
196 {{DOFS_PER_AXIS}},
197 {{OVERLAP}},
198 {{UNKNOWNS}},
199 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QOld.value,
200 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QOld(marker.getSelectedFaceNumber()).value
201 );
202
203 // A coarse face might have been non-persistent before. So it might
204 // not carry a valid boundary flag, and we have to re-analyse it and
205 // set it accordingly.
206 tarch::la::Vector<Dimensions, double> offset(DomainOffset);
207 tarch::la::Vector<Dimensions, double> size(DomainSize);
208 bool isBoundary = false;
209 for (int d=0; d<Dimensions; d++) {
210 isBoundary |= tarch::la::equals( marker.x()(d), offset(d) );
211 isBoundary |= tarch::la::equals( marker.x()(d), offset(d) + size(d) );
212 }
213 coarseGridFaces""" + exahype2.grid.UpdateFaceLabel.get_attribute_name(solver._name) + """(marker.getSelectedFaceNumber()).setBoundary( isBoundary );
214
215 // left and right
216 for (int i=0; i<2; i++) {
217 double newTimeStamp = std::max( coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getNewTimeStamp( i ), fineGridFace""" + solver._face_label.name + """.getNewTimeStamp( i ));
218 double oldTimeStamp = std::max( coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getOldTimeStamp( i ), fineGridFace""" + solver._face_label.name + """.getOldTimeStamp( i ));
219 double updatedTimeStamp = std::max( coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getUpdatedTimeStamp( i ), fineGridFace""" + solver._face_label.name + """.getUpdatedTimeStamp( i ));
220 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setUpdated( i,true);
221 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setNewTimeStamp( i,newTimeStamp);
222 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setOldTimeStamp( i,oldTimeStamp);
223 coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).setUpdatedTimeStamp(i,updatedTimeStamp);
224 }
225
226 logTraceOut( "destroyPersistentFace(...)" );
227 }
228"""
229
230 """
231
232 Again, a 1:1 extension of the toolbox routine which interpolates both QOld
233 and QNew. The clue here is that we treat the solution initialisation
234 separately: Here, we do not interpolate. We initialise using the solver's
235 callback themselves.
236
237 """
239 if ( {{INTERPOLATE_GUARD}} ) {
240 logTraceInWith1Argument( "createHangingFace(...)", marker.toString() );
241
242 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
243 marker,
244 {{DOFS_PER_AXIS}},
245 {{OVERLAP}},
246 {{UNKNOWNS}},
247 {{COARSE_GRID_FACE_ACCESSOR_INTERPOLATION}}QNew(marker.getSelectedFaceNumber()).value,
248 {{FINE_GRID_FACE_ACCESSOR_INTERPOLATION}}QNew.value
249 );
250 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
251 marker,
252 {{DOFS_PER_AXIS}},
253 {{OVERLAP}},
254 {{UNKNOWNS}},
255 coarseGridFaces""" + solver._name + """QOld(marker.getSelectedFaceNumber()).value,
256 fineGridFace""" + solver._name + """QOld.value
257 );
258 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
259 marker,
260 {{DOFS_PER_AXIS}},
261 {{OVERLAP}},
262 {{UNKNOWNS}},
263 coarseGridFaces""" + solver._name + """QNew(marker.getSelectedFaceNumber()).value,
264 fineGridFace""" + solver._name + """QNew.value
265 );
266
267 // It is important that we clear the halo layer. If we have two layers of
268 // AMR, the finest one will restrict into QUpdate (so it has to be properly
269 // initialised as 0).
270 ::toolbox::blockstructured::clearHaloLayerAoS(
271 marker,
272 {{DOFS_PER_AXIS}},
273 {{OVERLAP}},
274 {{UNKNOWNS}},
275 fineGridFace""" + solver._name + """QUpdate.value
276 );
277 const int leftRightEntry = marker.getSelectedFaceNumber()<Dimensions ? 0 : 1;
278 fineGridFace""" + solver._face_label.name + """.setNewTimeStamp(leftRightEntry,coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getNewTimeStamp(leftRightEntry));
279 fineGridFace""" + solver._face_label.name + """.setOldTimeStamp(leftRightEntry,coarseGridFaces""" + solver._face_label.name + """(marker.getSelectedFaceNumber()).getOldTimeStamp(leftRightEntry));
280
281 logTraceOut( "createHangingFace(...)" );
282 }
283 else if ( repositories::""" + solver.get_name_of_global_instance() + """.getSolverState()==""" + solver._name + """::SolverState::GridInitialisation ) {
284 logTraceInWith1Argument( "createHangingFace(...)", marker.toString() );
285
286 int normal = marker.getSelectedFaceNumber() % Dimensions;
287 dfore(i, {{DOFS_PER_AXIS}}, normal, 0) {
288 for( int j=0; j<2*{{OVERLAP}}; j++) {
289 tarch::la::Vector<Dimensions, int> dof = i;
290 dof(normal) = j;
291
292 int serialisedDoF = ::toolbox::blockstructured::serialiseVoxelIndexInOverlap(
293 dof,
294 {{DOFS_PER_AXIS}},
295 {{OVERLAP}},
296 normal
297 );
298
299 repositories::{{SOLVER_INSTANCE}}.initialCondition(
300 fineGridFace""" + solver._name + """QNew.value + serialisedDoF * {{UNKNOWNS}},
301 ::exahype2::fd::getGridFaceCentre( marker.x(), marker.h(), {{DOFS_PER_AXIS}}, {{OVERLAP}}, normal, dof),
302 ::exahype2::fd::getGridFaceSize( marker.h(), {{DOFS_PER_AXIS}} ),
303 true // grid grid is constructed
304 );
305 repositories::{{SOLVER_INSTANCE}}.initialCondition(
306 fineGridFace""" + solver._name + """QOld.value + serialisedDoF * {{UNKNOWNS}},
307 ::exahype2::fd::getGridFaceCentre( marker.x(), marker.h(), {{DOFS_PER_AXIS}}, {{OVERLAP}}, normal, dof),
308 ::exahype2::fd::getGridFaceSize( marker.h(), {{DOFS_PER_AXIS}} ),
309 true // grid grid is constructed
310 );
311 repositories::{{SOLVER_INSTANCE}}.initialCondition(
312 fineGridFace""" + solver._name + """QUpdate.value + serialisedDoF * {{UNKNOWNS}},
313 ::exahype2::fd::getGridFaceCentre( marker.x(), marker.h(), {{DOFS_PER_AXIS}}, {{OVERLAP}}, normal, dof),
314 ::exahype2::fd::getGridFaceSize( marker.h(), {{DOFS_PER_AXIS}} ),
315 true // grid grid is constructed
316 );
317 }
318 }
319
320 logTraceOut( "createHangingFace(...)" );
321 }
322"""
323
324 """
325
326 Very similar to default version, but this time we interpolate QOld and
327 QNew. We also clear the update field via clearHaloLayerAoS(). It is
328 important that we initialise the time step sizes properly. As we deal
329 with a persistent face, we set both the left and right time stamp from
330 the coarse face.
331
332 """
334 logTraceInWith1Argument( "createPersistentFace(...)", marker.toString() );
335
336 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
337 marker,
338 {{DOFS_PER_AXIS}},
339 {{OVERLAP}},
340 {{UNKNOWNS}},
341 coarseGridCell""" + solver._name + """Q.value,
342 coarseGridFaces""" + solver._name + """QOld(marker.getSelectedFaceNumber()).value,
343 fineGridFace""" + solver._name + """QOld.value
344 );
345 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
346 marker,
347 {{DOFS_PER_AXIS}},
348 {{OVERLAP}},
349 {{UNKNOWNS}},
350 coarseGridCell""" + solver._name + """Q.value,
351 coarseGridFaces""" + solver._name + """QNew(marker.getSelectedFaceNumber()).value,
352 fineGridFace""" + solver._name + """QNew.value
353 );
354
355 // It is important that we clear the halo layer. If we have two layers of
356 // AMR, the finest one will restrict into QUpdate (so it has to be properly
357 // initialised as 0).
358 ::toolbox::blockstructured::clearHaloLayerAoS(
359 marker,
360 {{DOFS_PER_AXIS}},
361 {{OVERLAP}},
362 {{UNKNOWNS}},
363 fineGridFace""" + solver._name + """QUpdate.value
364 );
365 fineGridFace""" + solver._face_label.name + """.setNewTimeStamp(coarseGridCell""" + solver._cell_label.name + """.getTimeStamp());
366 fineGridFace""" + solver._face_label.name + """.setOldTimeStamp(coarseGridCell""" + solver._cell_label.name + """.getTimeStamp());
367
368 logTraceOutWith1Argument( "createPersistentFace(...)", marker.toString() );
369"""
370
372 logTraceIn( "createCell(...)" );
373
374 ::toolbox::blockstructured::interpolateCell_AoS_{{INTERPOLATION_SCHEME}}(
375 marker,
376 {{DOFS_PER_AXIS}},
377 {{UNKNOWNS}},
378 {{COARSE_GRID_CELL}}.value,
379 {{FINE_GRID_CELL}}.value
380 );
381
382 ::exahype2::fv::validatePatch(
383 {{FINE_GRID_CELL}}.value,
384 {{UNKNOWNS}},
385 0, // auxiliary values. Not known here
386 {{DOFS_PER_AXIS}},
387 0, // no halo
388 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
389 );
390
391 fineGridCell""" + solver._cell_label.name + """.setTimeStamp( coarseGridCell""" + solver._cell_label.name + """.getTimeStamp() );
392 fineGridCell""" + solver._cell_label.name + """.setTimeStepSize( coarseGridCell""" + solver._cell_label.name + """.getTimeStepSize() );
393
394 logTraceOut( "createCell(...)" );
395"""
396
398 logTraceInWith1Argument( "destroyCell(...)", marker.toString() );
399
400 ::toolbox::blockstructured::restrictCell_AoS_{{RESTRICTION_SCHEME}}(
401 marker,
402 {{DOFS_PER_AXIS}},
403 {{UNKNOWNS}},
404 {{FINE_GRID_CELL}}.value,
405 {{COARSE_GRID_CELL}}.value
406 );
407
408 // exploit the fact that we can "reuse" some FV utils here
409 ::exahype2::fv::validatePatch(
410 {{FINE_GRID_CELL}}.value,
411 {{UNKNOWNS}},
412 0, // auxiliary values. Not known here
413 {{DOFS_PER_AXIS}},
414 0, // no halo
415 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
416 );
417
418 coarseGridCell""" + solver._cell_label.name + """.setTimeStamp( fineGridCell""" + solver._cell_label.name + """.getTimeStamp() );
419 coarseGridCell""" + solver._cell_label.name + """.setTimeStepSize( fineGridCell""" + solver._cell_label.name + """.getTimeStepSize() );
420
421 logTraceOut( "destroyCell(...)" );
422"""
423
424
425
427 return __name__.replace(".py", "").replace(".", "_")
428
429
430 def get_includes(self):
431 return super(DynamicAMR,self).get_includes() + """
432#include <cstring>
433#include "exahype2/fd/PatchUtils.h"
434#include "exahype2/fv/InterpolationRestriction.h"
435"""
The handling of (dynamically) adaptive meshes for finite differences.
Definition DynamicAMR.py:11
get_includes(self)
Return include statements that you need.
get_action_set_name(self)
Return unique action set name.
__init__(self, solver, interpolation, restriction)
Construct object.
Definition DynamicAMR.py:27
This class assumes that you have an 2MxNxN patch on your faces.
Definition DynamicAMR.py:9