Peano
Loading...
Searching...
No Matches
SeparateSweeps.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
3from .CellCenteredFiniteDifferences import CellCenteredFiniteDifferences
4from exahype2.solvers.PDETerms import PDETerms
5
6import peano4
7import exahype2
8
9import jinja2
10
12 ReconstructPatchAndApplyFunctor,
13)
14
15from exahype2.solvers.ButcherTableau import ButcherTableau
16
17
19 r"""!
20
21 Update one cell, i.e. compute Runge-Kutta step on it
22
23 This routine is very similar to the Finite Volume step. The big difference in
24 the context of Runge-Kutta is that we always have to construct a linear
25 combination of the input data and then write the new estimate for the
26 right-hand side into the large estimate field.
27
28 So we operate in two steps: First, we let the default block-structured code
29 reconstruct the old time step data. After that, we add the rhs estimates
30 onto this reconstructed data. The latter can be read as a correction step
31 to the reconstructed values. It is correct if and only if the haloes are
32 properly initialised with a corrected value, as we cannot correct the halo
33 data at this point.
34
35
36 # Correction terms with Runge-Kutta trials
37
38 We current the values with a linear combination of all of the estimates according to the
39 Butcher Tableau.
40
41 The linear combination is a volumetric representation which includes both
42 the degrees of freedom and the auxiliary variables. However, the auxiliary
43 variables are not developing over time. In Runge-Kutta, I have estimates
44 for the right-hand side, i.e. for the derivatives
45
46 @f$ \partial _t Q = F(Q) @f$
47
48 This is the stuff stored in RhsEstimates. It does not comprise any auxiliary
49 variables. So I have to copy the auxiliary variables from the last valid
50 time step every time I reconstruct a new guess.
51
52
53
54 """
55
56 SolveRiemannProblemsOverPatch = jinja2.Template(
57 """
58 double timeStamp = fineGridCell{{SOLVER_NAME}}CellLabel.getTimeStamp();
59
60 // Set the variable
61 // double timeStepSize
62 {{COMPUTE_TIME_STEP_SIZE}}
63
64 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
65 if ({{PREDICATES[PREDICATE_NO]}}) {
66 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithAuxiliaryVariablesOnReconstructedPatch( 1, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, {{HALO_SIZE}}, {{NUMBER_OF_UNKNOWNS}}, {{NUMBER_OF_AUXILIARY_VARIABLES}});
67 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithoutAuxiliaryVariables( {{RK_STEPS}}, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, 0, {{NUMBER_OF_UNKNOWNS}}, 0 );
68 {% if RECONSTRUCTION_STAGES != 0 %}
69 {{PRIMARY_VARS_INDICES}}
70 {{AUXILIARY_VARS_INDICES}}
71 {% endif %}
72
73 dfor( dof, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} ) {
74 {% if RECONSTRUCTION_STAGES==0 %}
75 for (int unknown=0; unknown<{{NUMBER_OF_UNKNOWNS}}; unknown++) {
76 {% for WEIGHT_NO in range(0,BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO]|length) %}
77 {% if BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]!=0 %}
78 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] +=
79 timeStepSize * {{BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]}} *
80 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{WEIGHT_NO}},dof,unknown) ];
81 {% endif %}
82 {% endfor %}
83 }
84 {% else %}
85 for (int unknown : primaryVarsIndices) {
86 {% for WEIGHT_NO in range(0,BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO]|length) %}
87 {% if BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]!=0 %}
88 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] +=
89 timeStepSize * {{BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]}} *
90 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{WEIGHT_NO}},dof,unknown) ];
91 {% endif %}
92 {% endfor %}
93 }
94 for (int unknown : auxiliaryVarsIndices) {
95 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] = //abuse of RHS, auxiliary variables are stored there.
96 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{PREDICATE_NO}},dof,unknown) ];
97 }
98 {% endif %}
99
100 }
101
102 newQ = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + enumeratorWithoutAuxiliaryVariables({{PREDICATE_NO}},0,0);
103 }
104 {% endfor %}
105
106 {% for PREDICATE_NO in range(0,PREDICATES_RECONSTRUCTION|length) %}
107 if ({{PREDICATES_RECONSTRUCTION[PREDICATE_NO]}}) {
108 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithAuxiliaryVariablesOnReconstructedPatch( 1, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, {{HALO_SIZE}}, {{NUMBER_OF_UNKNOWNS}}, {{NUMBER_OF_AUXILIARY_VARIABLES}});
109 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithoutAuxiliaryVariables( {{RK_STEPS}}, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, 0, {{NUMBER_OF_UNKNOWNS}}, 0 );
110 {% if RECONSTRUCTION_STAGES != 0 %}
111 {{PRIMARY_VARS_INDICES}}
112 {{AUXILIARY_VARS_INDICES}}
113 {% endif %}
114
115 dfor( dof, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} ) {
116 for (int unknown : primaryVarsIndices) {
117 {% for WEIGHT_NO in range(0,BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO]|length) %}
118 {% if BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]!=0 %}
119 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] +=
120 timeStepSize * {{BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]}} *
121 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{WEIGHT_NO}},dof,unknown) ];
122 {% endif %}
123 {% endfor %}
124 }
125 for (int unknown : auxiliaryVarsIndices) {
126 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] = 0;
127 // actually no need for this initialization as we do overwritten in reconstruction, but we keep it for safety.
128 }
129
130 }
131
132 newQ = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + enumeratorWithoutAuxiliaryVariables({{PREDICATE_NO}},0,0);
133 }
134 {% endfor %}
135
136
137 {{PREPROCESS_RECONSTRUCTED_PATCH}}
138
139 assertion2( tarch::la::greaterEquals( timeStamp, 0.0 ), timeStamp, timeStepSize );
140 assertion2( tarch::la::greaterEquals( timeStepSize, 0.0 ), timeStamp, timeStepSize );
141
142 ::exahype2::fd::validatePatch(
143 oldQWithHalo,
144 {{NUMBER_OF_UNKNOWNS}},
145 {{NUMBER_OF_AUXILIARY_VARIABLES}},
146 {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}},
147 {{HALO_SIZE}}, // halo
148 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
149 ); // previous time step has to be valid
150
151 double subTimeStamp=timeStamp;
152 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
153 if ({{PREDICATES[PREDICATE_NO]}}) {
154 subTimeStamp += {{BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES[PREDICATE_NO]}}*timeStepSize;
155 }
156 {% endfor %}
157
158 ::exahype2::CellData patchData( oldQWithHalo, marker.x(), marker.h(), subTimeStamp, timeStepSize, newQ );
159
160 {% if RECONSTRUCTION_STAGES==0 %}
161 ::exahype2::fd::{{KERNEL_NAMESPACE}}::{{COMPUTE_KERNEL_CALL}}
162 {% else %}
163 if ({{IS_UNDER_RECONSTRUCTION}}) {
164 ::exahype2::fd::{{KERNEL_NAMESPACE}}::{{RECONSTRUCTION_KERNEL_CALL}}
165 } else if ({{IS_UNDER_RKSTEP}}) {
166 ::exahype2::fd::{{KERNEL_NAMESPACE}}::{{COMPUTE_KERNEL_CALL}}
167 }
168 {% endif %}
169
170 ::exahype2::fd::validatePatch(
171 newQ,
172 {{NUMBER_OF_UNKNOWNS}},
173 {{NUMBER_OF_AUXILIARY_VARIABLES}},
174 {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}},
175 0, // halo
176 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
177 ); // outcome has to be valid
178 """
179 )
180
181 def __init__(self, solver):
182 """ """
183 ReconstructPatchAndApplyFunctor.__init__(
184 self,
185 patch=solver._patch,
186 patch_overlap=solver._patch_overlap_new,
187 functor_implementation="""
188#error please switch to your Riemann solver of choice
189""",
190 reconstructed_array_memory_location=solver._reconstructed_array_memory_location,
191 guard="not marker.willBeRefined() and not marker.hasBeenRefined()",
192 add_assertions_to_halo_exchange=False,
193 )
194 self._solver = solver
195
197 """
198 fineGridCell"""
199 + solver._name
200 + """CellLabel.setHasUpdated(false);
201"""
203 )
204
206
208 """
209
210 This is our plug-in point to alter the underlying dictionary
211
212 """
213 super(UpdateCell, self)._add_action_set_entries_to_dictionary(d)
214
215 self._solver._init_dictionary_with_default_parameters(d)
216 self._solver.add_entries_to_text_replacement_dictionary(d)
217
218 d["PREDICATES"] = [
219 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(
220 self._solver._store_cell_data_default_guard(),
221 self._solver.get_name_of_global_instance(),
222 self._solver._name,
223 step,
224 )
225 for step in range(0, self._solver.number_of_Runge_Kutta_steps())
226 ]
227 if self._solver._reconstruction_stages != 0 :
228 d["PREDICATES_RECONSTRUCTION"] = [
229 "{} and repositories::{}.getSolverState()=={}::SolverState::ReconstructionSubStep{}".format(
230 self._solver._store_cell_data_default_guard(),
231 self._solver.get_name_of_global_instance(),
232 self._solver._name,
233 step,
234 )
235 for step in range(0, self._solver._reconstruction_stages)
236 ]
237
238 re_condition_text="repositories::{}.getSolverState()=={}::SolverState::ReconstructionSubStep{}".format(
239 self._solver.get_name_of_global_instance(),
240 self._solver._name,
241 0,
242 )
243 for step in range(1,self._solver._reconstruction_stages):
244 re_condition_text += " or repositories::{}.getSolverState()=={}::SolverState::ReconstructionSubStep{}".format(
245 self._solver.get_name_of_global_instance(),
246 self._solver._name,
247 step)
248
249 rk_condition_text="repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(
250 self._solver.get_name_of_global_instance(),
251 self._solver._name,
252 0,
253 )
254 for step in range(1,self._solver.number_of_Runge_Kutta_steps()):
255 rk_condition_text += " or repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(
256 self._solver.get_name_of_global_instance(),
257 self._solver._name,
258 step)
259
260 d["IS_UNDER_RECONSTRUCTION"] = re_condition_text
261 d["IS_UNDER_RKSTEP"] = rk_condition_text
262
263
264 d["BUTCHER_TABLEAU_WEIGHTS"] = self._butcher_tableau.weight_matrix()
265 d[
266 "BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES"
267 ] = self._butcher_tableau.time_step_sizes()
268
269 # Has to come after we've set the predicates, as we use these
270 # fields in here already
271 d["CELL_FUNCTOR_IMPLEMENTATION"] = self.SolveRiemannProblemsOverPatch.render(
272 **d
273 )
274
275 def get_includes(self):
276 return (
277 """
278#include "exahype2/enumerator/enumerator.h"
279#include "exahype2/fd/PatchUtils.h"
280#include "tarch/NonCriticalAssertions.h"
281"""
282 + self._solver._get_default_includes()
283 + self._solver.user_action_set_includes
284 )
285
287 """
288
289 You should replicate this function in each subclass, so you get
290 meaningful action set names (otherwise, it will be
291 AbstractRKFDActionSet0,1,2,...).
292
293 """
294 return __name__.replace(".py", "").replace(".", "_") + "_UpdateCell"
295
296
298 """
299 Probably the simplest solver you could think off.
300
301 This particular variant works only for Runge-Kutta order greater or equal
302 to two.
303
304
305 :: Write your own specialisation ::
306
307 self._preprocess_reconstructed_patch
308 Has to hold any preprocessing, but it also has to set the doubles
309 timeStepSize and timeStamp to valid data.
310
311 self._postprocess_updated_patch
312 You don't have to redefine this one, but if you want to alter the
313 time step size, then this is the right place to do so. If you don't
314 alter timeStepSize, the code will automatically continue with
315 the current one subject to a preprocessing in the next step.
316
317 """
318
320 self,
321 name,
322 patch_size,
323 overlap,
324 rk_order,
325 unknowns,
326 auxiliary_variables,
327 min_meshcell_h,
328 max_meshcell_h,
329 plot_grid_properties,
330 kernel_namespace,
331 ):
332 """
333
334 Instantiate a generic FV scheme with an overlap of 1.
335
336 """
337 self._rk_order_rk_order = rk_order
338
339 super(SeparateSweeps, self).__init__(
340 name,
341 patch_size,
342 overlap,
343 rk_order,
344 unknowns,
345 auxiliary_variables,
346 min_meshcell_h,
347 max_meshcell_h,
348 plot_grid_properties,
349 kernel_namespace,
350 )
351
352 if rk_order < 1:
353 raise Exception(
354 "Runge-Kutta order has to be at least 1 but was {}".format(rk_order)
355 )
356
358
359 self._flux_implementation = PDETerms.None_Implementation
360 self._ncp_implementation = PDETerms.None_Implementation
361 self._eigenvalues_implementation = PDETerms.None_Implementation
362 self._source_term_implementation = PDETerms.None_Implementation
363
365 """
366
367 Call the superclass' create_data_structures() to ensure that all the data
368 structures are in place, i.e. each cell can host a patch, that each face hosts
369 patch overlaps, and so forth. These quantities are all set to defaults. See
370 FV.create_data_structures().
371
372 After that, take the patch overlap (that's the data stored within the faces)
373 and ensure that these are sent and received via MPI whenever they are also
374 stored persistently. The default in FV is that no domain boundary data exchange
375 is active. Finally, ensure that the old data is only exchanged between the
376 initialisation sweep and the first first grid run-through.
377
378 """
379 super(SeparateSweeps, self).create_data_structures()
380
381 initialisation_sweep_guard = """(
382 repositories::{}.getSolverState()=={}::SolverState::GridInitialisation
383 )""".format(
385 )
386 first_iteration_after_initialisation_guard = """(
387 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep0AfterGridInitialisation or
388 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation
389 )""".format(
393 self._name_name,
394 )
395
396 self._patch_overlap_new.generator.send_condition = "true"
397 self._patch_overlap_new.generator.receive_and_merge_condition = "true"
398
399 self._patch_overlap_old.generator.send_condition = initialisation_sweep_guard
400 self._patch_overlap_old.generator.receive_and_merge_condition = (
401 first_iteration_after_initialisation_guard
402 )
403
404 if self._reconstruction_stages != 0 :
405 first_sweep_of_time_step_or_plotting_guard = """(
406 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep0AfterGridInitialisation or
407 repositories::{}.getSolverState()=={}::SolverState::ReconstructionSubStep0 or
408 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
409 repositories::{}.getSolverState()=={}::SolverState::Plotting or
410 repositories::{}.getSolverState()=={}::SolverState::Suspended
411 )""".format(
417 )
418 else:
419 first_sweep_of_time_step_or_plotting_guard = """(
420 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep0AfterGridInitialisation or
421 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep0 or
422 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
423 repositories::{}.getSolverState()=={}::SolverState::Plotting or
424 repositories::{}.getSolverState()=={}::SolverState::Suspended
425 )""".format(
431 )
432
433
434 last_sweep_of_time_step_or_plotting_initialisation = """(
435 repositories::{}.getSolverState()=={}::SolverState::GridInitialisation or
436 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{} or
437 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
438 repositories::{}.getSolverState()=={}::SolverState::Plotting or
439 repositories::{}.getSolverState()=={}::SolverState::Suspended
440 )""".format(
446 )
447
448 self._patch_estimates.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
451 + """
452 and not ("""
453 + first_sweep_of_time_step_or_plotting_guard
454 + ")",
456 + """
457 and not ("""
458 + last_sweep_of_time_step_or_plotting_initialisation
459 + ")",
460 )
461
463 """
464
465 Call superclass routine and then reconfigure the update cell call.
466 Only the UpdateCell action set is specific to a single sweep.
467
468 This operation is implicity called via the superconstructor.
469
470 Each guard here should combine the storage predicate with the
471 actual solver phase.
472
473 """
474 super(SeparateSweeps, self).create_action_sets()
477 self._action_set_compute_final_linear_combination.guard = self._store_cell_data_default_guard() + " and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(
479 self._name_name,
481 )
483 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(
486 self._name_name,
487 step,
488 )
489 for step in range(0, self.number_of_Runge_Kutta_steps())
490 ] + [
491 "{} and repositories::{}.getSolverState()=={}::SolverState::GridInitialisation".format(
494 self._name_name,
495 )
496 ]
497 if self._reconstruction_stages != 0 :
498 for step in range(0,self._reconstruction_stages):
499 self._action_set_project_patch_onto_faces.guards.append(
500 "{} and repositories::{}.getSolverState()=={}::SolverState::ReconstructionSubStep{}".format(
503 self._name_name,
504 step)
505 )
506
507
508
509 @property
511 return (
512 """
513#include "exahype2/CellData.h"
514"""
515 + super(SeparateSweeps, self).user_action_set_includes
516 )
517
519 self,
520 flux,
521 ncp,
522 source_term,
523 eigenvalues,
524 boundary_conditions,
525 refinement_criterion,
526 initial_conditions,
527 memory_location,
528 additional_action_set_includes,
529 additional_user_includes,
530 ):
531 """
532 If you pass in User_Defined, then the generator will create C++ stubs
533 that you have to befill manually. If you pass in None_Implementation, it
534 will create nop, i.e. no implementation or defaults. Any other string
535 is copied 1:1 into the implementation. If you pass in None, then the
536 set value so far won't be overwritten.
537 """
538 if boundary_conditions is not None:
540 if refinement_criterion is not None:
542 if initial_conditions is not None:
544 if memory_location is not None:
546
547 if refinement_criterion == exahype2.solvers.PDETerms.None_Implementation:
548 assert False, "refinement criterion cannot be none"
549 if initial_conditions == exahype2.solvers.PDETerms.None_Implementation:
550 assert False, "initial conditions cannot be none"
551
552 if flux is not None:
553 self._flux_implementation = flux
554 if ncp is not None:
555 self._ncp_implementation = ncp
556 if eigenvalues is not None:
557 self._eigenvalues_implementation = eigenvalues
558 if source_term is not None:
559 self._source_term_implementation = source_term
560
561 if (
563 == peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.HeapThroughTarchWithoutDelete
565 == peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.HeapWithoutDelete
567 == peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.ManagedSharedAcceleratorDeviceMemoryThroughTarchWithoutDelete
568 ):
569 raise Exception(
570 "memory mode without appropriate delete chosen, i.e. this will lead to a memory leak"
571 )
572
573 self._user_action_set_includes += additional_action_set_includes
574 self._user_solver_includes += additional_user_includes
575
577
579 """
580 d: Dictionary of string to string
581 in/out argument
582 """
583 pass
number_of_Runge_Kutta_steps(self)
Return number of steps required to realise the Runge-Kutta scheme.
Probably the simplest solver you could think off.
add_entries_to_text_replacement_dictionary(self, d)
d: Dictionary of string to string in/out argument
__init__(self, name, patch_size, overlap, rk_order, unknowns, auxiliary_variables, min_meshcell_h, max_meshcell_h, plot_grid_properties, kernel_namespace)
Instantiate a generic FV scheme with an overlap of 1.
set_implementation(self, flux, ncp, source_term, eigenvalues, boundary_conditions, refinement_criterion, initial_conditions, memory_location, additional_action_set_includes, additional_user_includes)
If you pass in User_Defined, then the generator will create C++ stubs that you have to befill manuall...
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
create_data_structures(self)
Call the superclass' create_data_structures() to ensure that all the data structures are in place,...
create_action_sets(self)
Call superclass routine and then reconfigure the update cell call.
get_action_set_name(self)
You should replicate this function in each subclass, so you get meaningful action set names (otherwis...
_add_action_set_entries_to_dictionary(self, d)
This is our plug-in point to alter the underlying dictionary.
get_includes(self)
Return include statements that you need.
__init__(self, solver)
patch: peano4.datamodel.Patch Patch which is to be used