Peano
Loading...
Searching...
No Matches
Prediction.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 .AbstractADERDGActionSet import AbstractADERDGActionSet
4from exahype2.solvers.PDETerms import PDETerms
5
6import jinja2
7import peano4.solversteps
8
9
11 """
12 The extrapolated solution from the space-time predictor has to be projected onto
13 the faces, so we can then solve the Riemann problems. So the projection
14 happens in one grid sweep, the corresponding Riemann solve in the next one.
15 """
16
17 _Template_TouchCellFirstTime_Preamble = """
18 bool isHangingCell = false;
19 for (int d = 0; d < 2 * Dimensions; d++) {
20 if (fineGridFaces{{SOLVER_NAME}}FaceLabel(d).getIsHanging()) {
21 isHangingCell = true;
22 break;
23 }
24 }
25
26 if ({{PREDICATE}}) {
27 const double timeStamp = fineGridCell{{SOLVER_NAME}}CellLabel.getTimeStamp();
28 // Needs to declare and define timeStepSize
29 {{COMPUTE_TIME_STEP_SIZE}}
30
31 #if Dimensions == 2
32 constexpr int SpaceFaceSize = {{ORDER}} + 1;
33 constexpr int SpaceBasisSize = ({{ORDER}} + 1) * ({{ORDER}} + 1);
34 #else
35 constexpr int SpaceFaceSize = ({{ORDER}} + 1) * ({{ORDER}} + 1);
36 constexpr int SpaceBasisSize = ({{ORDER}} + 1) * ({{ORDER}} + 1) * ({{ORDER}} + 1);
37 #endif
38
39 constexpr int SpaceTimeBasisSize = SpaceBasisSize * ({{ORDER}} + 1);
40 constexpr int BasisElementsPerFace = kernels::{{SOLVER_NAME}}::getBndFaceSize();
41 constexpr int FluxElementsPerFace = kernels::{{SOLVER_NAME}}::getBndFluxSize();
42
43 auto* Q = fineGridCell{{UNKNOWN_IDENTIFIER}}.value;
44 auto* oldQ = fineGridCell{{UNKNOWN_IDENTIFIER}}_old.value;
45
46 {{PREPROCESS_RECONSTRUCTED_PATCH}}
47
48 {{CREATE_PREDICTOR_ALLOCATIONS}}
49
50 std::copy_n(Q, SpaceBasisSize * ({{NUMBER_OF_UNKNOWNS}} + {{NUMBER_OF_AUXILIARY_VARIABLES}}), oldQ);
51"""
52
53 _Template_TouchCellFirstTime_Core = """
54 {{FUSED_PREDICTOR_VOLUME_INTEGRAL}}
55 {{PROJECT_SOLUTION_TO_FACES}}
56"""
57
58 _Template_TouchCellFirstTime_Epilogue = """
59 fineGridCell{{SOLVER_NAME}}CellLabel.setTimeStepSize(timeStepSize);
60
61 repositories::{{SOLVER_INSTANCE}}.update(timeStepSize, timeStamp, marker.h()(0));
62 }
63"""
64
65 _Template_PredictorAllocations = """
66 {{CORRECTOR_COMPUTATION_PRECISION}}* lQhbnd[2*Dimensions] = {
67 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(0).value + BasisElementsPerFace,
68 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(1).value + BasisElementsPerFace,
69#if Dimensions==3
70 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(2).value + BasisElementsPerFace,
71#endif
72 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(0+Dimensions).value,
73 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(1+Dimensions).value,
74#if Dimensions==3
75 fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(2+Dimensions).value
76#endif
77 };
78
79 {{CORRECTOR_COMPUTATION_PRECISION}}* lFhbnd[2*Dimensions] = {
80 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(0).value + FluxElementsPerFace,
81 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(1).value + FluxElementsPerFace,
82#if Dimensions==3
83 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(2).value + FluxElementsPerFace,
84#endif
85 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(0+Dimensions).value,
86 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(1+Dimensions).value,
87#if Dimensions==3
88 fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(2+Dimensions).value
89#endif
90 };
91
92 ::exahype2::CellData<{{SOLUTION_STORAGE_PRECISION}}, {{CORRECTOR_COMPUTATION_PRECISION}}> cellData(
93 fineGridCell{{UNKNOWN_IDENTIFIER}}.value,
94 marker.x(),
95 marker.h(),
96 timeStamp,
97 timeStepSize,
98 nullptr
99 );
100"""
101
102 _Template_FSTPVI_Linear_Without_PS = """
103 // Linear, without point sources
104 int numberOfIterations = kernels::{{SOLVER_NAME}}::fusedSpaceTimePredictorVolumeIntegral<{{SOLUTION_STORAGE_PRECISION}}, {{PREDICTOR_COMPUTATION_PRECISIONS[PRECISION_NUM]}}, {{CORRECTOR_COMPUTATION_PRECISION}}>(
105 repositories::{{SOLVER_INSTANCE}},
106 lQhbnd, lFhbnd, cellData.QIn[0],
107 marker.x(), marker.h(), timeStamp, timeStepSize,
108 std::vector<int>() // Empty vector
109 );
110"""
111
112 _Template_FSTPVI_Linear_With_PS = """
113 const auto pointSources = kernels::{{SOLVER_NAME}}::pointSources(
114 repositories::{{SOLVER_INSTANCE}},
115 marker.x(),
116 marker.h()
117 );
118
119 if (!pointSources.empty()) {
120 // Linear, with point sources
121 int numberOfIterations = kernels::{{SOLVER_NAME}}::fusedSpaceTimePredictorVolumeIntegral<{{SOLUTION_STORAGE_PRECISION}}, {{PREDICTOR_COMPUTATION_PRECISIONS[PRECISION_NUM]}}, {{CORRECTOR_COMPUTATION_PRECISION}}>(
122 repositories::{{SOLVER_INSTANCE}},
123 lQhbnd, lFhbnd, cellData.QIn[0],
124 marker.x(), marker.h(), timeStamp, timeStepSize,
125 pointSources
126 );
127 } else {
128 // Linear, without point sources
129 int numberOfIterations = kernels::{{SOLVER_NAME}}::fusedSpaceTimePredictorVolumeIntegralWithoutPointSources<{{SOLUTION_STORAGE_PRECISION}}, {{PREDICTOR_COMPUTATION_PRECISIONS[PRECISION_NUM]}}, {{CORRECTOR_COMPUTATION_PRECISION}}>(
130 repositories::{{SOLVER_INSTANCE}},
131 lQhbnd, lFhbnd, cellData.QIn[0],
132 marker.x(), marker.h(), timeStamp, timeStepSize,
133 pointSources
134 );
135 }
136"""
137
138 _Template_FSTPVI_Nonlinear = """
139 // Nonlinear, without point sources
140 int numberOfIterations = kernels::{{SOLVER_NAME}}::fusedSpaceTimePredictorVolumeIntegral<{{SOLUTION_STORAGE_PRECISION}}, {{PREDICTOR_COMPUTATION_PRECISIONS[PRECISION_NUM]}}, {{CORRECTOR_COMPUTATION_PRECISION}}>(
141 repositories::{{SOLVER_INSTANCE}},
142 lQhbnd, lFhbnd, cellData.QIn[0],
143 marker.x(), marker.h(), timeStamp, timeStepSize
144 );
145"""
146
147 _Template_SetFaceTimeStamps = """
148 /**
149 * Copy the estimates into the face data containers. Note that Peano uses a different ordering of
150 * the faces that the kernels, so these are reordered somewhat.
151 * The kernels order by dimension, then side of the face whereas Peano orders by
152 * side, then dimension.
153 * E.g., in 2d the kernels have the order left, right, lower face, upper face
154 * whereas Peano orders: left, lower, right, upper.
155 *
156 * 2d: 0,1,2,3 -> 0,2,1,3
157 * 3d: 0,1,2,3,4,5 -> 0,3,1,4,2,5
158 */
159
160 for (int d = 0; d < Dimensions; d++) {
161 // Timestamp information for boundary handling
162 fineGridFaces{{SOLVER_NAME}}FaceLabel(d).setNewTimeStamp(1, timeStamp);
163 fineGridFaces{{SOLVER_NAME}}FaceLabel(d + Dimensions).setNewTimeStamp(0, timeStamp);
164 }
165"""
166
167 _Template_NumberOfPrecisionsIterator = """
168 ::exahype2::PrecisionCommand myPrecision = repositories::{{SOLVER_INSTANCE}}.precisionCriterion(
169 cellData.QIn[0],
170 marker.x(),
171 marker.h(),
172 timeStepSize,
173 repositories::{{SOLVER_INSTANCE}}.getSolverState()
174 );
175
176 switch (myPrecision) {
177 {% for PRECISION_NUM in range(0,PREDICTOR_COMPUTATION_PRECISIONS|length) %}
178 case ::exahype2::PrecisionCommand::{{PRECISIONS_CAPITALIZED[PRECISION_NUM]}}:
179 {{ITERATION_CONTENT}}
180 break;
181 {% endfor %}
182 default:
183 assertion1WithExplanation(
184 false, myPrecision, "chosen precision was not in the previously specified options, as such there are no compiled kernels for this option."
185 );
186 }
187"""
188
189 _Template_PerformRiemannSolutionOnHangingFacesAndSetFaceTimeStamps = """
190 /**
191 * Copy the estimates into the face data containers. Note that Peano uses a different ordering of
192 * the faces that the kernels, so these are reordered somewhat.
193 * The kernels order by dimension, then side of the face whereas Peano orders by
194 * side, then dimension.
195 * E.g., in 2d the kernels have the order left, right, lower face, upper face
196 * whereas Peano orders: left, lower, right, upper.
197 *
198 * 2d: 0,1,2,3 -> 0,2,1,3
199 * 3d: 0,1,2,3,4,5 -> 0,3,1,4,2,5
200 *
201 * On hanging faces, this instead computes the Riemann solution and face integral, then
202 * stores the solution of this into the face. The reason for this is that performing the
203 * Riemann solution on the hanging cell and restricting these is much more accurate than
204 * performing them on the coarse faces and projecting those to the fine faces, to the
205 * degree that the later breaks many simulations.
206 */
207
208 for (int d = 0; d < Dimensions; d++) {
209 int direction = d;
210
211 // Left values
212 if (fineGridFaces{{SOLVER_NAME}}FaceLabel(d).getIsHanging()) {
213 {{CORRECTOR_COMPUTATION_PRECISION}}* FL = fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(d).value;
214 {{CORRECTOR_COMPUTATION_PRECISION}}* FR = fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(d).value + FluxElementsPerFace;
215 {{CORRECTOR_COMPUTATION_PRECISION}}* QL = fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(d).value;
216 {{CORRECTOR_COMPUTATION_PRECISION}}* QR = fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(d).value + BasisElementsPerFace;
217 int orientation = 0;
218 int faceNumber = d;
219 bool isBoundary = false;
220 tarch::la::Vector<Dimensions, double> faceCentre = marker.x();
221 faceCentre[d] -= 0.5 * marker.h()[d];
222 {{RIEMANN_SOLVER}}
223 {{CORRECTOR_COMPUTATION_PRECISION}}* FIn = FR;
224 {{FACE_INTEGRAL}}
225 }
226
227 // Right values
228 if (fineGridFaces{{SOLVER_NAME}}FaceLabel(d+Dimensions).getIsHanging()) {
229 {{CORRECTOR_COMPUTATION_PRECISION}}* FL = fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(d + Dimensions).value;
230 {{CORRECTOR_COMPUTATION_PRECISION}}* FR = fineGridFaces{{UNKNOWN_IDENTIFIER}}FluxEstimates(d + Dimensions).value + FluxElementsPerFace;
231 {{CORRECTOR_COMPUTATION_PRECISION}}* QL = fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(d + Dimensions).value;
232 {{CORRECTOR_COMPUTATION_PRECISION}}* QR = fineGridFaces{{UNKNOWN_IDENTIFIER}}Estimates(d + Dimensions).value + BasisElementsPerFace;
233 int orientation = 1;
234 int faceNumber = d + Dimensions;
235 bool isBoundary = false;
236 tarch::la::Vector<Dimensions, double> faceCentre = marker.x();
237 faceCentre[d] += 0.5 * marker.h()[d];
238 {{RIEMANN_SOLVER}}
239 {{CORRECTOR_COMPUTATION_PRECISION}}* FIn = FL;
240 {{FACE_INTEGRAL}}
241 }
242 }
243"""
244
245 _Template_RiemannSolver = """
246 kernels::{{SOLVER_NAME}}::riemannSolver<{{CORRECTOR_COMPUTATION_PRECISION}}>(
247 repositories::{{SOLVER_INSTANCE}},
248 FL,
249 FR,
250 QL,
251 QR,
252 timeStamp,
253 timeStepSize,
254 faceCentre,
255 marker.h(),
256 direction
257 );
258"""
259
260 _Template_CustomRiemannSolver = """
261 repositories::{{SOLVER_INSTANCE}}.riemannSolver(
262 FL,
263 FR,
264 QL,
265 QR,
266 timeStamp,
267 timeStepSize,
268 marker.x(),
269 faceCentre,
270 direction,
271 isBoundary,
272 faceNumber
273 );
274"""
275
276 _Template_FaceIntegral = """
277 const double inverseDxDirection = 1.0 / marker.h()[d];
278 kernels::{{SOLVER_NAME}}::faceIntegral(
279 cellData.QIn[0],
280 FIn,
281 direction,
282 orientation,
283 inverseDxDirection,
284 timeStepSize
285 );
286"""
287
288 def __init__(self, solver, guard, on_hanging_cells=False):
289 """
290 guard: String (C++ code)
291 Predicate which controls whether this action set should run
292 on_hanging_cells: bool
293 Determines whether this is running on hanging cells or not,
294 the actions on both differ
295 """
296 super(Prediction, self).__init__(solver)
297 self._guard = guard
298 self._on_hanging_cells = on_hanging_cells
299 self._is_linear = solver._is_linear
301 solver._riemann_solver_implementation != PDETerms.None_Implementation
302 )
304 solver._point_sources_implementation != PDETerms.None_Implementation
305 )
306 self._multiple_precisions = len(solver._predictor_computation_precisions) > 1
307
308 def get_body_of_operation(self, operation_name):
309 result = ""
310 if (
311 operation_name
312 == peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
313 ):
314 d = {}
315 self._solver._init_dictionary_with_default_parameters(d)
316 self._solver.add_entries_to_text_replacement_dictionary(d)
317 d[
318 "PREDICATE"
319 ] = self.guard # self._guard TODO: Why does self._guard not work?
320 d["PRECISIONS_CAPITALIZED"] = [
321 x.replace(" ", "_").replace("std::", "").capitalize()
322 for x in d["PREDICTOR_COMPUTATION_PRECISIONS"]
323 ]
324 d["CREATE_PREDICTOR_ALLOCATIONS"] = self._Template_PredictorAllocations
325 if self._is_linear:
326 if self._use_point_source:
327 d[
328 "FUSED_PREDICTOR_VOLUME_INTEGRAL"
330 else:
331 d[
332 "FUSED_PREDICTOR_VOLUME_INTEGRAL"
334 else:
335 d["FUSED_PREDICTOR_VOLUME_INTEGRAL"] = self._Template_FSTPVI_Nonlinear
336 if self._on_hanging_cells:
338 d["RIEMANN_SOLVER"] = jinja2.Template(
340 ).render(**d)
341 else:
342 d["RIEMANN_SOLVER"] = jinja2.Template(
344 ).render(**d)
345 d["FACE_INTEGRAL"] = jinja2.Template(
347 ).render(**d)
348 d[
349 "PROJECT_SOLUTION_TO_FACES"
351 else:
352 d["PROJECT_SOLUTION_TO_FACES"] = self._Template_SetFaceTimeStamps
353
354 result = jinja2.Template(self._Template_TouchCellFirstTime_Preamble).render(
355 **d
356 )
357 if self._multiple_precisions:
358 d["ITERATION_CONTENT"] = jinja2.Template(
360 ).render(**d)
361 result += jinja2.Template(
363 ).render(**d)
364 else:
365 d["PRECISION_NUM"] = 0
366 result += jinja2.Template(
368 ).render(**d)
369 result += jinja2.Template(
371 ).render(**d)
372
373 result = jinja2.Template(result).render(**d)
374 return result
375
377 return (
378 (__name__ + ("OnHangingCells" if self._on_hanging_cells else ""))
379 .replace(".py", "")
380 .replace(".", "_")
381 )
382
383 def get_includes(self):
384 includes = (
385 super(Prediction, self).get_includes()
386 + """
387#include "exahype2/CellData.h"
388#include "kernels/"""
389 + self._solver._name
390 + """/CellData.h"
391#include "kernels/"""
392 + self._solver._name
393 + """/FaceIntegral.h"
394#include "kernels/"""
395 + self._solver._name
396 + """/RiemannSolver.h"
397#include "kernels/"""
398 + self._solver._name
399 + """/FusedSpaceTimePredictorVolumeIntegral.h"
400"""
401 )
402 if self._use_point_source:
403 includes += (
404 """
405#include "kernels/"""
406 + self._solver._name
407 + """/PointSources.h"
408#include "kernels/"""
409 + self._solver._name
410 + """/FusedSpaceTimePredictorVolumeIntegralWithoutPointSources.h"
411"""
412 )
413 return includes
The extrapolated solution from the space-time predictor has to be projected onto the faces,...
Definition Prediction.py:10
get_action_set_name(self)
You should replicate this function in each subclass, so you get meaningful action set names (otherwis...
get_includes(self)
Return include statements that you need.
__init__(self, solver, guard, on_hanging_cells=False)
guard: String (C++ code) Predicate which controls whether this action set should run on_hanging_cells...
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.