Peano
Loading...
Searching...
No Matches
OneSweepPerRungeKuttaStep.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
11from peano4.toolbox.blockstructured.ReconstructPatchAndApplyFunctor import ReconstructPatchAndApplyFunctor
12
13from exahype2.solvers.ButcherTableau import ButcherTableau
14
15
16ComputeNewQPointer = """
17 #if Dimensions==2
18 constexpr int NumberOfDoFsPerCell = {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} * {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}};
19 newQ = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * NumberOfDoFsPerCell * {{NUMBER_OF_UNKNOWNS}};
20 #elif Dimensions==3
21 constexpr int NumberOfDoFsPerCell = {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} * {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} * {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}};
22 newQ = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * NumberOfDoFsPerCell * {{NUMBER_OF_UNKNOWNS}};
23 #endif
24"""
25
26
27ReconstructLinearCombination = """
28 double timeStamp = fineGridCell{{SOLVER_NAME}}CellLabel.getTimeStamp();
29
30 // Set the variable
31 // double timeStepSize
32 {{COMPUTE_TIME_STEP_SIZE}}
33
34 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
35 if ({{PREDICATES[PREDICATE_NO]}}) {
36 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithAuxiliaryVariablesOnReconstructedPatch( 1, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, {{HALO_SIZE}}, {{NUMBER_OF_UNKNOWNS}}, {{NUMBER_OF_AUXILIARY_VARIABLES}});
37 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithoutAuxiliaryVariables( {{RK_STEPS}}, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, 0, {{NUMBER_OF_UNKNOWNS}}, 0 );
38
39 // Add rhs estimates to oldQ (if RK order>1)
40 dfor( dof, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} ) {
41 for (int unknown=0; unknown<{{NUMBER_OF_UNKNOWNS}}; unknown++) {
42 {% for WEIGHT_NO in range(0,BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO]|length) %}
43 {% if BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]!=0 %}
44 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] +=
45 timeStepSize * {{BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]}} *
46 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{WEIGHT_NO}},dof,unknown) ];
47 {% endif %}
48 {% endfor %}
49 }
50 }
51 """ + ComputeNewQPointer + """
52 }
53 {% endfor %}
54
55 {{PREPROCESS_RECONSTRUCTED_PATCH}}
56
57 assertion2( tarch::la::greaterEquals( timeStamp, 0.0 ), timeStamp, timeStepSize );
58 assertion2( tarch::la::greaterEquals( timeStepSize, 0.0 ), timeStamp, timeStepSize );
59
60 ::exahype2::fd::validatePatch(
61 oldQWithHalo,
62 {{NUMBER_OF_UNKNOWNS}},
63 {{NUMBER_OF_AUXILIARY_VARIABLES}},
64 {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}},
65 {{HALO_SIZE}}, // halo
66 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
67 ); // previous time step has to be valid
68 """
69
70
71
73 """
74
75 Update one cell, i.e. compute Runge-Kutta step on it
76
77 This routine is very similar to the Finite Volume step. The big difference in
78 the context of Runge-Kutta is that we always have to construct a linear
79 combination of the input data and then write the new estimate for the
80 right-hand side into the large estimate field.
81
82 So we operate in two steps: First, we let the default block-structured code
83 reconstruct the old time step data. After that, we add the rhs estimates
84 onto this reconstructed data. The latter can be read as a correction step
85 to the reconstructed values. It is correct if and only if the haloes are
86 properly initialised with a corrected value, as we cannot correct the halo
87 data at this point.
88
89
90 # Correction terms with Runge-Kutta trials
91
92 We current the values with a linear combination of all of the estimates according to the
93 Butcher Tableau.
94
95 The linear combination is a volumetric representation which includes both
96 the degrees of freedom and the auxiliary variables. However, the auxiliary
97 variables are not developing over time. In Runge-Kutta, I have estimates
98 for the right-hand side, i.e. for the derivatives
99
100 @f$ \partial _t Q = F(Q) @f$
101
102 This is the stuff stored in RhsEstimates. It does not comprise any auxiliary
103 variables. So I have to copy the auxiliary variables from the last valid
104 time step every time I reconstruct a new guess.
105
106
107
108 """
109
110 SolveRiemannProblemsOverPatch = jinja2.Template( ReconstructLinearCombination + """
111 double subTimeStamp=timeStamp;
112 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
113 if ({{PREDICATES[PREDICATE_NO]}}) {
114 subTimeStamp += {{BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES[PREDICATE_NO]}}*timeStepSize;
115 }
116 {% endfor %}
117
118 ::exahype2::CellData patchData( oldQWithHalo, marker.x(), marker.h(), subTimeStamp, timeStepSize, newQ );
119
120 ::exahype2::fd::{{KERNEL_NAMESPACE}}::{{COMPUTE_KERNEL_CALL}}
121
122 ::exahype2::fd::validatePatch(
123 newQ,
124 {{NUMBER_OF_UNKNOWNS}},
125 {{NUMBER_OF_AUXILIARY_VARIABLES}},
126 {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}},
127 0, // halo
128 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
129 ); // outcome has to be valid
130 """ )
131
132
133 def __init__(self, solver):
134 """
135
136
137 """
138 ReconstructPatchAndApplyFunctor.__init__(self,
139 patch = solver._patch,
140 patch_overlap = solver._patch_overlap_new,
141 functor_implementation = """
142#error please switch to your Riemann solver of choice
143""",
144 reconstructed_array_memory_location = solver._reconstructed_array_memory_location,
145 guard = "not marker.willBeRefined() and not marker.hasBeenRefined()",
146 add_assertions_to_halo_exchange = False
147 )
148 self._solver = solver
149
151 fineGridCell""" + solver._name + """CellLabel.setHasUpdated(false);
153
155
156
158 """
159
160 This is our plug-in point to alter the underlying dictionary
161
162 """
163 super(UpdateCell,self)._add_action_set_entries_to_dictionary(d)
164
165 self._solver._init_dictionary_with_default_parameters(d)
166 self._solver.add_entries_to_text_replacement_dictionary(d)
167
168 d[ "PREDICATES" ] = [
169 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(self._solver._store_cell_data_default_guard(),self._solver.get_name_of_global_instance(),self._solver._name,step) for step in range(0,self._solver.number_of_Runge_Kutta_steps())
170 ]
171 d[ "BUTCHER_TABLEAU_WEIGHTS" ] = self._butcher_tableau.weight_matrix()
172 d[ "BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES" ] = self._butcher_tableau.time_step_sizes()
173
174 # Has to come after we've set the predicates, as we use these
175 # fields in here already
176 d[ "CELL_FUNCTOR_IMPLEMENTATION" ] = self.SolveRiemannProblemsOverPatch.render(**d)
177
178
179 def get_includes(self):
180 return """
181#include "exahype2/enumerator/enumerator.h"
182#include "exahype2/fd/PatchUtils.h"
183#include "tarch/NonCriticalAssertions.h"
184""" + self._solver._get_default_includes() + self._solver.user_action_set_includes
185
186
187
188
189
191 """
192 Probably the simplest solver you could think off.
193
194 This particular variant works only for Runge-Kutta order greater or equal
195 to two.
196
197
198 :: Write your own specialisation ::
199
200 self._preprocess_reconstructed_patch
201 Has to hold any preprocessing, but it also has to set the doubles
202 timeStepSize and timeStamp to valid data.
203
204 self._postprocess_updated_patch
205 You don't have to redefine this one, but if you want to alter the
206 time step size, then this is the right place to do so. If you don't
207 alter timeStepSize, the code will automatically continue with
208 the current one subject to a preprocessing in the next step.
209
210 """
211
212
213 def __init__(self, name, patch_size, overlap, rk_order, unknowns, auxiliary_variables, min_meshcell_h, max_meshcell_h, plot_grid_properties, kernel_namespace):
214 """
215
216 Instantiate a generic FV scheme with an overlap of 1.
217
218 """
219 super(OneSweepPerRungeKuttaStep, self).__init__(name, patch_size, overlap, rk_order, unknowns, auxiliary_variables, min_meshcell_h, max_meshcell_h, plot_grid_properties, kernel_namespace)
220
221 if rk_order<1:
222 raise Exception( "Runge-Kutta order has to be at least 1 but was {}".format(rk_order) )
223
225
226 self._flux_implementation = PDETerms.None_Implementation
227 self._ncp_implementation = PDETerms.None_Implementation
228 self._eigenvalues_implementation = PDETerms.None_Implementation
229 self._source_term_implementation = PDETerms.None_Implementation
230
231
232
234 """
235
236 Call the superclass' create_data_structures() to ensure that all the data
237 structures are in place, i.e. each cell can host a patch, that each face hosts
238 patch overlaps, and so forth. These quantities are all set to defaults. See
239 FV.create_data_structures().
240
241 After that, take the patch overlap (that's the data stored within the faces)
242 and ensure that these are sent and received via MPI whenever they are also
243 stored persistently. The default in FV is that no domain boundary data exchange
244 is active. Finally, ensure that the old data is only exchanged between the
245 initialisation sweep and the first first grid run-through.
246
247 """
248 super(OneSweepPerRungeKuttaStep, self).create_data_structures()
249
250 initialisation_sweep_guard = "(" + \
251 "repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name_name + "::SolverState::GridInitialisation" + \
252 ")"
253 first_iteration_after_initialisation_guard = "(" + \
254 "repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name_name + "::SolverState::RungeKuttaSubStep0AfterGridInitialisation or " + \
255 "repositories::" + self.get_name_of_global_instance() + ".getSolverState()==" + self._name_name + "::SolverState::PlottingAfterGridInitialisation" + \
256 ")"
257
258 self._patch_overlap_new.generator.send_condition = "true"
259 self._patch_overlap_new.generator.receive_and_merge_condition = "true"
260
261 self._patch_overlap_old.generator.send_condition = initialisation_sweep_guard
262 self._patch_overlap_old.generator.receive_and_merge_condition = first_iteration_after_initialisation_guard
263
264
266 """
267
268 Call superclass routine and then reconfigure the update cell call.
269 Only the UpdateCell action set is specific to a single sweep.
270
271 This operation is implicity called via the superconstructor.
272
273 """
274 super(OneSweepPerRungeKuttaStep, self).create_action_sets()
276 self._action_set_compute_final_linear_combination.guard = self._store_cell_data_default_guard() + " and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(self.get_name_of_global_instance(),self._name_name,self.number_of_Runge_Kutta_steps()-1)
278 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSubStep{}".format(self._store_cell_data_default_guard(),self.get_name_of_global_instance(),self._name_name,step) for step in range(0,self.number_of_Runge_Kutta_steps())
279 ] + [ "{} and repositories::{}.getSolverState()=={}::SolverState::GridInitialisation".format(self._store_cell_data_default_guard(),self.get_name_of_global_instance(),self._name_name) ]
280
281
282 @property
284 return """
285#include "exahype2/CellData.h"
286""" + super(OneSweepPerRungeKuttaStep, self).user_action_set_includes
287
288
290 flux, ncp, source_term, eigenvalues,
291 boundary_conditions, refinement_criterion, initial_conditions,
292 memory_location,
293 additional_action_set_includes,
294 additional_user_includes
295 ):
296 """
297 If you pass in User_Defined, then the generator will create C++ stubs
298 that you have to befill manually. If you pass in None_Implementation, it
299 will create nop, i.e. no implementation or defaults. Any other string
300 is copied 1:1 into the implementation. If you pass in None, then the
301 set value so far won't be overwritten.
302 """
303 if boundary_conditions is not None: self._boundary_conditions_implementation_boundary_conditions_implementation = boundary_conditions
304 if refinement_criterion is not None: self._refinement_criterion_implementation_refinement_criterion_implementation = refinement_criterion
305 if initial_conditions is not None: self._initial_conditions_implementation_initial_conditions_implementation = initial_conditions
306 if memory_location is not None: self._reconstructed_array_memory_location_reconstructed_array_memory_location = memory_location
307
308 if refinement_criterion==exahype2.solvers.PDETerms.None_Implementation:
309 assert False, "refinement criterion cannot be none"
310 if initial_conditions==exahype2.solvers.PDETerms.None_Implementation:
311 assert False, "initial conditions cannot be none"
312
313 if flux is not None: self._flux_implementation = flux
314 if ncp is not None: self._ncp_implementation = ncp
315 if eigenvalues is not None: self._eigenvalues_implementation = eigenvalues
316 if source_term is not None: self._source_term_implementation = source_term
317
318 if self._reconstructed_array_memory_location_reconstructed_array_memory_location==peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.HeapThroughTarchWithoutDelete or \
319 self._reconstructed_array_memory_location_reconstructed_array_memory_location==peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.HeapWithoutDelete or \
320 self._reconstructed_array_memory_location_reconstructed_array_memory_location==peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.AcceleratorWithoutDelete:
321 raise Exception( "memory mode without appropriate delete chosen, i.e. this will lead to a memory leak" )
322
323 self._user_action_set_includes += additional_action_set_includes
324 self._user_solver_includes += additional_user_includes
325
327
328
330 """
331 d: Dictionary of string to string
332 in/out argument
333 """
334 pass
335
number_of_Runge_Kutta_steps(self)
Return number of steps required to realise the Runge-Kutta scheme.
create_action_sets(self)
Call superclass routine and then reconfigure the update cell call.
create_data_structures(self)
Call the superclass' create_data_structures() to ensure that all the data structures are in place,...
__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...
add_entries_to_text_replacement_dictionary(self, d)
d: Dictionary of string to string in/out argument
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
_add_action_set_entries_to_dictionary(self, d)
This is our plug-in point to alter the underlying dictionary.
__init__(self, solver)
patch: peano4.datamodel.Patch Patch which is to be used
get_includes(self)
Return include statements that you need.