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.
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.
48 :: Restriction of destructed faces
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.
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
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.
73 :: Interpolation throughout the grid initialisation
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.
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.
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.
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.
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
107 restrict_guard = solver._provide_face_data_to_compute_kernels_default_guard(),
108 additional_includes =
"""
109#include "../repositories/SolverRepository.h"
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
122 Touch first time does nothing proper. It simply clears the halo
127 if ( {{CLEAR_GUARD}} ) {
128 logTraceInWith2Arguments( "touchFaceFirstTime(...)", marker.toString(), "clear halo layer {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}" );
130 ::toolbox::blockstructured::clearHaloLayerAoS(
135 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value
138 logTraceOut( "touchFaceFirstTime(...)" );
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.
151 if ( {{RESTRICT_GUARD}} ) {
152 logTraceInWith4Arguments( "destroyHangingFace(...)", "{{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}", "{{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}", marker.getSelectedFaceNumber(), marker.toString() );
154 ::toolbox::blockstructured::restrictInnerHalfOfHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
159 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value,
160 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate(marker.getSelectedFaceNumber()).value
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);
168 logTraceOut( "destroyHangingFace(...)" );
173 if ( not marker.isInteriorFaceWithinPatch() ) {
174 logTraceIn( "destroyPersistentFace(...)" );
176 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
181 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate.value,
182 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QUpdate(marker.getSelectedFaceNumber()).value
185 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
190 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QNew.value,
191 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QNew(marker.getSelectedFaceNumber()).value
194 ::toolbox::blockstructured::restrictHaloLayer_AoS_{{RESTRICTION_SCHEME}}(
199 {{FINE_GRID_FACE_ACCESSOR_RESTRICTION}}QOld.value,
200 {{COARSE_GRID_FACE_ACCESSOR_RESTRICTION}}QOld(marker.getSelectedFaceNumber()).value
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) );
213 coarseGridFaces""" + exahype2.grid.UpdateFaceLabel.get_attribute_name(solver._name) +
"""(marker.getSelectedFaceNumber()).setBoundary( isBoundary );
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);
226 logTraceOut( "destroyPersistentFace(...)" );
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
239 if ( {{INTERPOLATE_GUARD}} ) {
240 logTraceInWith1Argument( "createHangingFace(...)", marker.toString() );
242 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
247 {{COARSE_GRID_FACE_ACCESSOR_INTERPOLATION}}QNew(marker.getSelectedFaceNumber()).value,
248 {{FINE_GRID_FACE_ACCESSOR_INTERPOLATION}}QNew.value
250 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
255 coarseGridFaces""" + solver._name +
"""QOld(marker.getSelectedFaceNumber()).value,
256 fineGridFace""" + solver._name +
"""QOld.value
258 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
263 coarseGridFaces""" + solver._name +
"""QNew(marker.getSelectedFaceNumber()).value,
264 fineGridFace""" + solver._name +
"""QNew.value
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(
275 fineGridFace""" + solver._name +
"""QUpdate.value
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));
281 logTraceOut( "createHangingFace(...)" );
283 else if ( repositories::""" + solver.get_name_of_global_instance() +
""".getSolverState()==""" + solver._name +
"""::SolverState::GridInitialisation ) {
284 logTraceInWith1Argument( "createHangingFace(...)", marker.toString() );
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;
292 int serialisedDoF = ::toolbox::blockstructured::serialiseVoxelIndexInOverlap(
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
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
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
320 logTraceOut( "createHangingFace(...)" );
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
334 logTraceInWith1Argument( "createPersistentFace(...)", marker.toString() );
336 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
341 coarseGridCell""" + solver._name +
"""Q.value,
342 coarseGridFaces""" + solver._name +
"""QOld(marker.getSelectedFaceNumber()).value,
343 fineGridFace""" + solver._name +
"""QOld.value
345 ::toolbox::blockstructured::interpolateHaloLayer_AoS_{{INTERPOLATION_SCHEME}}(
350 coarseGridCell""" + solver._name +
"""Q.value,
351 coarseGridFaces""" + solver._name +
"""QNew(marker.getSelectedFaceNumber()).value,
352 fineGridFace""" + solver._name +
"""QNew.value
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(
363 fineGridFace""" + solver._name +
"""QUpdate.value
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());
368 logTraceOutWith1Argument( "createPersistentFace(...)", marker.toString() );
372 logTraceIn( "createCell(...)" );
374 ::toolbox::blockstructured::interpolateCell_AoS_{{INTERPOLATION_SCHEME}}(
378 {{COARSE_GRID_CELL}}.value,
379 {{FINE_GRID_CELL}}.value
382 ::exahype2::fv::validatePatch(
383 {{FINE_GRID_CELL}}.value,
385 0, // auxiliary values. Not known here
388 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
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() );
394 logTraceOut( "createCell(...)" );
398 logTraceInWith1Argument( "destroyCell(...)", marker.toString() );
400 ::toolbox::blockstructured::restrictCell_AoS_{{RESTRICTION_SCHEME}}(
404 {{FINE_GRID_CELL}}.value,
405 {{COARSE_GRID_CELL}}.value
408 // exploit the fact that we can "reuse" some FV utils here
409 ::exahype2::fv::validatePatch(
410 {{FINE_GRID_CELL}}.value,
412 0, // auxiliary values. Not known here
415 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
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() );
421 logTraceOut( "destroyCell(...)" );