Peano
Loading...
Searching...
No Matches
kernels.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 jinja2
4
5from enum import Enum
6import os
7import exahype2
8import exahype2.dslhype as DSL
9
10class SolverVariant(Enum):
11 WithVirtualFunctions = 0
12 Stateless = 1
13 Multicore = 2
14 Accelerator = 3
15
16class KernelVariant(Enum):
17 PatchWiseAoS = 10
18 PatchWiseAoSoA = 11
19 PatchWiseSoA = 12
20 BatchedAoS = 20
21 BatchedAoSoA = 21
22 BatchedSoA = 22
23 TaskGraphAoS = 30
24 TaskGraphAoSoA = 31
25 TaskGraphSoA = 32
26 VolumeWiseAoS = 40
27 VolumeWiseAoSoA = 41
28 VolumeWiseSoA = 42
29
30def create_rusanov_kernel_definitions(patch_size, unknowns, auxiliary_variables, flux_implementation, ncp_implementation, source_term_implementation, compute_max_eigenvalue_of_next_time_step):
31 if not os.path.exists("kernels"):
32 os.makedirs("kernels")
33
34 file = open("kernels/rusanov.h", "w")
35 file.write("""#if Dimensions == 2
36#include "rusanov2d.h"
37#elif Dimensions == 3
38#include "rusanov3d.h"
39#endif
40""")
41
42 create_rusanov_kernel_definitions_for_function(exahype2.solvers.fv.rusanov.timeStepWithRusanov2d, "rusanov2d", patch_size, unknowns, auxiliary_variables, flux_implementation, ncp_implementation, source_term_implementation, compute_max_eigenvalue_of_next_time_step)
43 create_rusanov_kernel_definitions_for_function(exahype2.solvers.fv.rusanov.timeStepWithRusanov3d, "rusanov3d", patch_size, unknowns, auxiliary_variables, flux_implementation, ncp_implementation, source_term_implementation, compute_max_eigenvalue_of_next_time_step)
44
45def create_rusanov_kernel_definitions_for_function(function, filename, patch_size, unknowns, auxiliary_variables, flux_implementation, ncp_implementation, source_term_implementation, compute_max_eigenvalue_of_next_time_step):
46 template_parameters = [DSL.SyntaxTree.Argument("NumberOfVolumesPerAxisInPatch", DSL.SyntaxTree.TInteger(), "applications::exahype2::ccz4::AbstractCCZ4"),
47 DSL.SyntaxTree.Argument("HaloSize", DSL.SyntaxTree.TInteger(), "applications::exahype2"),
48 DSL.SyntaxTree.Argument("NumberOfUnknowns", DSL.SyntaxTree.TInteger(), "applications::exahype2::ccz4::AbstractCCZ4"),
49 DSL.SyntaxTree.Argument("NumberOfAuxiliaryVariables", DSL.SyntaxTree.TInteger(), "applications::exahype2::ccz4::AbstractCCZ4"),
50 DSL.SyntaxTree.Argument("EvaluateFlux", DSL.SyntaxTree.TBoolean(), "applications::exahype2::ccz4"),
51 DSL.SyntaxTree.Argument("EvaluateNonconservativeProduct", DSL.SyntaxTree.TBoolean(), "applications::exahype2::ccz4"),
52 DSL.SyntaxTree.Argument("EvaluateSource", DSL.SyntaxTree.TBoolean(), "applications::exahype2::ccz4"),
53 DSL.SyntaxTree.Argument("EvaluateMaximumEigenvalueAfterTimeStep", DSL.SyntaxTree.TBoolean(), "applications::exahype2::ccz4")]
54
55
56 functor_arguments = [DSL.SyntaxTree.Argument("flux", DSL.SyntaxTree.TCustom("const FluxFunctor&"), "(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()", is_function=True),
57 DSL.SyntaxTree.Argument("nonconservativeProduct", DSL.SyntaxTree.TCustom("const NonconservativeProductFunctor&"), "(!llvm.ptr, !llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()", is_function=True),
58 DSL.SyntaxTree.Argument("sourceTerm", DSL.SyntaxTree.TCustom("const SourceFunctor&"), "(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, !llvm.ptr) -> ()", is_function=True),
59 DSL.SyntaxTree.Argument("maxEigenvalue", DSL.SyntaxTree.TCustom("const MaxEigenvalueFunctor&"), "(!llvm.ptr, !llvm.ptr, !llvm.ptr, f64, f64, i32, !llvm.ptr) -> ()", is_function=True)]
60
61 solver_includes = """#include "exahype2/CellData.h"
62#include "exahype2/VolumeIndex.h"
63#include "exahype2/fv/PatchUtils.h"
64#include "exahype2/fv/rusanov/Functors.h"
65#include "peano4/utils/Loop.h"
66#include "tarch/timing/Measurement.h"
67#include "tarch/timing/Watch.h"
68"""
69
70 d = {}
71 d["KERNEL_NAMESPACE"] = "exahype2::fv::rusanov"
72 d["SOLVER"] = "Rusanov"
73 d["SOLVER_CLASS"] = "FVRusanov"
74 d["KERNEL_NAME"] = "timeStepWithRusanov"
75 d["SOLVER_INCLUDES"] = solver_includes
76 d["SOLVER_CLASS_NAMESPACE"] = "benchmarks::exahype2::kernelbenchmarks"
77
78 d["PATCH_SIZE"] = patch_size
79 d["NUMBER_OF_UNKNOWNS"] = unknowns
80 d["NUMBER_OF_AUXILIARY_VARIABLES"] = auxiliary_variables
81 d["FLUX_IMPLEMENTATION"] = flux_implementation
82 d["NCP_IMPLEMENTATION"] = ncp_implementation
83 d["SOURCE_IMPLEMENTATION"] = source_term_implementation
84 d["COMPUTE_MAX_EIGENVALUE"] = compute_max_eigenvalue_of_next_time_step
85 d["HALO_SIZE"] = 1
86
87
88 template_call_jinja = """
89 {{SOLVER_CLASS_NAMESPACE}}::{{SOLVER_CLASS}},
90 {{PATCH_SIZE}},
91 {{HALO_SIZE}},
92 {{NUMBER_OF_UNKNOWNS}},
93 {{NUMBER_OF_AUXILIARY_VARIABLES}},
94 {% if FLUX_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
95 {% if NCP_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
96 {% if SOURCE_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
97 {% if COMPUTE_MAX_EIGENVALUE==False %} false {% else %} true {% endif %}
98 """
99 d["TEMPLATE_CALL"] = jinja2.Template(template_call_jinja).render(**d)
100
101 template_value_definitions_jinja = """
102 int NumberOfVolumesPerAxisInPatch = {{PATCH_SIZE}};
103 int NumberOfUnknowns = {{NUMBER_OF_UNKNOWNS}};
104 int NumberOfAuxiliaryVariables = {{NUMBER_OF_AUXILIARY_VARIABLES}};
105 int HaloSize = {{HALO_SIZE}};
106 bool EvaluateFlux = {% if FLUX_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %};
107 bool EvaluateNonconservativeProduct = {% if NCP_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %};
108 bool EvaluateSource = {% if SOURCE_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %};
109 bool EvaluateMaximumEigenvalueAfterTimeStep = {% if COMPUTE_MAX_EIGENVALUE==False %} false {% else %} true {% endif %};
110 """
111 d["TEMPLATE_VALUE_DEFINITIONS"] = jinja2.Template(template_value_definitions_jinja).render(**d)
112
113 bridge_functions_jinja = """
114 void flux_bridge(void* Q_ptr, void* x_ptr, void* h_ptr, double t, double dt, int normal, void* F_ptr) {
115 double* Q = static_cast<double*>(Q_ptr);
116 tarch::la::Vector<Dimensions, double>* x = static_cast<tarch::la::Vector<Dimensions, double>*>(x_ptr);
117 tarch::la::Vector<Dimensions, double>* h = static_cast<tarch::la::Vector<Dimensions, double>*>(h_ptr);
118 double* F = static_cast<double*>(F_ptr);
119 {{SOLVER_CLASS_NAMESPACE}}::Abstract{{SOLVER_CLASS}}::flux(Q, *x, *h, t, dt, normal, F, OffloadableType::Yes);
120 }
121
122 void nonconservativeProduct_bridge(void* Q_ptr, void* deltaQ_ptr, void* x_ptr, void* h_ptr, double t, double dt, int normal, void* result_ptr) {
123 double* Q = static_cast<double*>(Q_ptr);
124 double* deltaQ = static_cast<double*>(deltaQ_ptr);
125 tarch::la::Vector<Dimensions, double>* x = static_cast<tarch::la::Vector<Dimensions, double>*>(x_ptr);
126 tarch::la::Vector<Dimensions, double>* h = static_cast<tarch::la::Vector<Dimensions, double>*>(h_ptr);
127 double* result = static_cast<double*>(result_ptr);
128 {{SOLVER_CLASS_NAMESPACE}}::Abstract{{SOLVER_CLASS}}::nonconservativeProduct(Q, deltaQ, *x, *h, t, dt, normal, result, OffloadableType::Yes);
129 }
130
131 void sourceTerm_bridge(void* Q_ptr, void* x_ptr, void* h_ptr, double t, double dt, void* S_ptr) {
132 double* Q = static_cast<double*>(Q_ptr);
133 tarch::la::Vector<Dimensions, double>* x = static_cast<tarch::la::Vector<Dimensions, double>*>(x_ptr);
134 tarch::la::Vector<Dimensions, double>* h = static_cast<tarch::la::Vector<Dimensions, double>*>(h_ptr);
135 double* S = static_cast<double*>(S_ptr);
136 {{SOLVER_CLASS_NAMESPACE}}::Abstract{{SOLVER_CLASS}}::sourceTerm(Q, *x, *h, t, dt, S, OffloadableType::Yes);
137 }
138
139 void maxEigenvalue_bridge(void* Q_ptr, void* x_ptr, void* h_ptr, double t, double dt, int normal, void* result_ptr) {
140 double* Q = static_cast<double*>(Q_ptr);
141 tarch::la::Vector<Dimensions, double>* x = static_cast<tarch::la::Vector<Dimensions, double>*>(x_ptr);
142 tarch::la::Vector<Dimensions, double>* h = static_cast<tarch::la::Vector<Dimensions, double>*>(h_ptr);
143 double* result = static_cast<double*>(result_ptr);
144 {{SOLVER_CLASS_NAMESPACE}}::Abstract{{SOLVER_CLASS}}::maxEigenvalue(Q, *x, *h, t, dt, normal, result, OffloadableType::Yes);
145 }
146"""
147 d["BRIDGE_FUNCTIONS"] = jinja2.Template(bridge_functions_jinja).render(**d)
148
149 d["EXTERN_FUNCTION_ARGUMENT_DEFINITIONS"] = """
150 void (*flux_fn)(void*, void*, void*, double, double, int, void*),
151 void (*ncp_fn)(void*, void*, void*, void*, double, double, int, void*),
152 void (*source_fn)(void*, void*, void*, double, double, void*),
153 void (*maxeig_fn)(void*, void*, void*, double, double, int, void*)
154"""
155 enabled_pde_terms = []
156 if flux_implementation is not None and flux_implementation != exahype2.solvers.PDETerms.None_Implementation:
157 enabled_pde_terms.append("EvaluateFlux")
158 if source_term_implementation is not None and source_term_implementation != exahype2.solvers.PDETerms.None_Implementation:
159 enabled_pde_terms.append("EvaluateSource")
160 if ncp_implementation is not None and ncp_implementation != exahype2.solvers.PDETerms.None_Implementation:
161 enabled_pde_terms.append("EvaluateNonconservativeProduct")
162 if compute_max_eigenvalue_of_next_time_step:
163 enabled_pde_terms.append("EvaluateMaximumEigenvalueAfterTimeStep")
164
165 DSL.create_kernel_definitions(
166 function,
167 template_parameters,
168 functor_arguments,
169 filename,
170 solver_includes,
171 ["exahype2", "fv", "rusanov"],
172 d,
173 enabled_pde_terms
174 )
175
176def create_compute_Riemann_kernel_for_Rusanov_dsl(flux_implementation,
177 ncp_implementation,
178 source_implementation,
179 compute_max_eigenvalue_of_next_time_step,
180 solver_variant: SolverVariant,
181 kernel_variant: KernelVariant):
182 """
183 Return only the unqualified function call, i.e., without any namespaces.
184 So by setting the right namespace as prefix, you can direct it to particular
185 implementations.
186 """
187
188 template = "timeStepWithRusanov"
189
190 if solver_variant == SolverVariant.WithVirtualFunctions:
191 template += """<
192 {{NUMBER_OF_VOLUMES_PER_AXIS}},
193 {{HALO_SIZE}},
194 {{NUMBER_OF_UNKNOWNS}},
195 {{NUMBER_OF_AUXILIARY_VARIABLES}},
196 {% if FLUX_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
197 {% if NCP_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
198 {% if SOURCE_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
199 {% if COMPUTE_MAX_EIGENVALUE==False %} false {% else %} true {% endif %}
200 >(patchData,
201 [&](
202 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
203 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
204 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
205 [[maybe_unused]] double t,
206 [[maybe_unused]] double dt,
207 [[maybe_unused]] int normal,
208 [[maybe_unused]] double* __restrict__ F // F[{{NUMBER_OF_UNKNOWNS}}]
209 )->void {
210 {% if FLUX_IMPLEMENTATION!="<none>" %}
211 repositories::{{SOLVER_INSTANCE}}.flux(Q, faceCentre, volumeH, t, dt, normal, F);
212 {% endif %}
213 },
214 [&](
215 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
216 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
217 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
218 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
219 [[maybe_unused]] double t,
220 [[maybe_unused]] double dt,
221 [[maybe_unused]] int normal,
222 [[maybe_unused]] double* __restrict__ BTimesDeltaQ // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
223 )->void {
224 {% if NCP_IMPLEMENTATION!="<none>" %}
225 repositories::{{SOLVER_INSTANCE}}.nonconservativeProduct(Q, deltaQ, faceCentre, volumeH, t, dt, normal, BTimesDeltaQ);
226 {% endif %}
227 },
228 [&](
229 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
230 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeX,
231 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
232 [[maybe_unused]] double t,
233 [[maybe_unused]] double dt,
234 [[maybe_unused]] double* __restrict__ S // S[{{NUMBER_OF_UNKNOWNS}}]
235 )->void {
236 {% if SOURCE_IMPLEMENTATION!="<none>" %}
237 repositories::{{SOLVER_INSTANCE}}.sourceTerm(Q, volumeX, volumeH, t, dt, S);
238 {% endif %}
239 },
240 [&](
241 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
242 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
243 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
244 [[maybe_unused]] double t,
245 [[maybe_unused]] double dt,
246 [[maybe_unused]] int normal,
247 [[maybe_unused]] double* __restrict__ maxEigenvalue
248 )->void {
249 repositories::{{SOLVER_INSTANCE}}.maxEigenvalue(Q, faceCentre, volumeH, t, dt, normal, maxEigenvalue);
250 }
251);
252 """
253 elif solver_variant == SolverVariant.Stateless:
254 template += """Stateless<
255 {{SOLVER_NAME}},
256 {{NUMBER_OF_VOLUMES_PER_AXIS}},
257 {{HALO_SIZE}},
258 {{NUMBER_OF_UNKNOWNS}},
259 {{NUMBER_OF_AUXILIARY_VARIABLES}},
260 {% if FLUX_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
261 {% if NCP_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
262 {% if SOURCE_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
263 {% if COMPUTE_MAX_EIGENVALUE==False %} false {% else %} true {% endif %}
264 >(patchData);
265 """
266 elif solver_variant == SolverVariant.Accelerator:
267 template += """Stateless<
268 {{SOLVER_NAME}},
269 {{NUMBER_OF_VOLUMES_PER_AXIS}},
270 {{HALO_SIZE}},
271 {{NUMBER_OF_UNKNOWNS}},
272 {{NUMBER_OF_AUXILIARY_VARIABLES}},
273 {% if FLUX_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
274 {% if NCP_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
275 {% if SOURCE_IMPLEMENTATION=="<none>" %} false {% else %} true {% endif %},
276 {% if COMPUTE_MAX_EIGENVALUE==False %} false {% else %} true {% endif %}
277 >(gpuPatchData.targetDevice, gpuPatchData);
278"""
279 else:
280 assert False, "Not supported combination: {} x {}".format(solver_variant, kernel_variant)
281
282 result = jinja2.Template( template, undefined=jinja2.DebugUndefined)
283 d= {}
284 d["FLUX_IMPLEMENTATION"] = flux_implementation
285 d["NCP_IMPLEMENTATION"] = ncp_implementation
286 d["SOURCE_IMPLEMENTATION"] = source_implementation
287 d["COMPUTE_MAX_EIGENVALUE"] = compute_max_eigenvalue_of_next_time_step
288 return result.render(**d)
289
290
291def create_abstract_solver_declarations(flux_implementation,
292 ncp_implementation,
293 eigenvalues_implementation,
294 source_term_implementation,
295 pde_terms_without_state):
296 Template = jinja2.Template( """
297 public:
298 {% if EIGENVALUES_IMPLEMENTATION=="<none>" %}
299 #error eigenvalue implementation cannot be none
300 {% endif %}
301
302 {% if EIGENVALUES_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
303 /**
304 * Depending on the implementation, this variant might be slow as it
305 * lacks an inline define. Also, if you don't want to use ipo aggressively,
306 * it might be clever to put the implementation into the header.
307 *
308 * ## SYCL
309 *
310 * At the moment, SYCL seems to struggle with ipo, even if a function is
311 * never called. So I embed the (empty) implementation directly into the
312 * header.
313 */
314 #if defined(GPUOffloadingOMP)
315 #pragma omp declare target
316 #endif
317 static GPUCallableMethod void maxEigenvalue(
318 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
319 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
320 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
321 [[maybe_unused]] double t,
322 [[maybe_unused]] double dt,
323 [[maybe_unused]] int normal,
324 [[maybe_unused]] double* __restrict__ maxEigenvalue,
325 Offloadable
326 )
327 //#if defined(GPUOffloadingSYCL)
328 //{}
329 //#else
330 ;
331 //#endif
332 #if defined(GPUOffloadingOMP)
333 #pragma omp end declare target
334 #endif
335 {% endif %}
336
337 /**
338 * Determine max eigenvalue over Jacobian in a given point with solution values
339 * (states) Q. All parameters are in.
340 *
341 * @return Max eigenvalue. Result has to be positive, so we are actually speaking
342 * about the maximum absolute eigenvalue.
343 */
344 virtual void maxEigenvalue(
345 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
346 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
347 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
348 [[maybe_unused]] double t,
349 [[maybe_unused]] double dt,
350 [[maybe_unused]] int normal,
351 [[maybe_unused]] double* __restrict__ maxEigenvalue
352 ) {% if EIGENVALUES_IMPLEMENTATION=="<user-defined>" %}= 0{% else %} final{% endif %};
353
354 {% if FLUX_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
355 /**
356 * Depending on the implementation, this variant might be slow as it
357 * lacks an inline define. Also, if you don't want to use ipo aggressively,
358 * it might be clever to put the implementation into the header.
359 *
360 * ## SYCL
361 *
362 * At the moment, SYCL seems to struggle with ipo, even if a function is
363 * never called. So I embed the (empty) implementation directly into the
364 * header.
365 */
366 #if defined(GPUOffloadingOMP)
367 #pragma omp declare target
368 #endif
369 static GPUCallableMethod void flux(
370 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
371 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
372 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
373 [[maybe_unused]] double t,
374 [[maybe_unused]] double dt,
375 [[maybe_unused]] int normal,
376 [[maybe_unused]] double* __restrict__ F, // F[{{NUMBER_OF_UNKNOWNS}}]
377 Offloadable
378 );
379 #if defined(GPUOffloadingOMP)
380 #pragma omp end declare target
381 #endif
382 {% endif %}
383
384 {% if FLUX_IMPLEMENTATION!="<none>" %}
385 virtual void flux(
386 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
387 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
388 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
389 [[maybe_unused]] double t,
390 [[maybe_unused]] double dt,
391 [[maybe_unused]] int normal,
392 [[maybe_unused]] double* __restrict__ F // F[{{NUMBER_OF_UNKNOWNS}}]
393 ) {% if FLUX_IMPLEMENTATION=="<user-defined>" %}=0{% else %} final {% endif %};
394 {% endif %}
395
396 {% if NCP_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
397 /**
398 * Depending on the implementation, this variant might be slow as it
399 * lacks an inline define. Also, if you don't want to use ipo aggressively,
400 * it might be clever to put the implementation into the header.
401 *
402 * ## SYCL
403 *
404 * At the moment, SYCL seems to struggle with ipo, even if a function is
405 * never called. So I embed the (empty) implementation directly into the
406 * header.
407 */
408 #if defined(GPUOffloadingOMP)
409 #pragma omp declare target
410 #endif
411 static GPUCallableMethod void nonconservativeProduct(
412 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
413 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
414 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
415 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
416 [[maybe_unused]] double t,
417 [[maybe_unused]] double dt,
418 [[maybe_unused]] int normal,
419 [[maybe_unused]] double* __restrict__ BTimesDeltaQ, // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
420 Offloadable
421 );
422 #if defined(GPUOffloadingOMP)
423 #pragma omp end declare target
424 #endif
425 {% endif %}
426
427 {% if NCP_IMPLEMENTATION!="<none>" %}
428 virtual void nonconservativeProduct(
429 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
430 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
431 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
432 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
433 [[maybe_unused]] double t,
434 [[maybe_unused]] double dt,
435 [[maybe_unused]] int normal,
436 [[maybe_unused]] double* __restrict__ BTimesDeltaQ // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
437 ) {% if NCP_IMPLEMENTATION=="<user-defined>" %}=0{% endif %};
438 {% endif %}
439
440 {% if SOURCE_TERM_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
441 /**
442 * Depending on the implementation, this variant might be slow as it
443 * lacks an inline define. Also, if you don't want to use ipo aggressively,
444 * it might be clever to put the implementation into the header.
445 *
446 * ## SYCL
447 *
448 * At the moment, SYCL seems to struggle with ipo, even if a function is
449 * never called. So I embed the (empty) implementation directly into the
450 * header.
451 */
452 #if defined(GPUOffloadingOMP)
453 #pragma omp declare target
454 #endif
455 static GPUCallableMethod void sourceTerm(
456 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
457 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
458 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
459 [[maybe_unused]] double t,
460 [[maybe_unused]] double dt,
461 [[maybe_unused]] double* __restrict__ S, // S[{{NUMBER_OF_UNKNOWNS}}]
462 Offloadable
463 );
464 #if defined(GPUOffloadingOMP)
465 #pragma omp end declare target
466 #endif
467 {% endif %}
468
469 {% if SOURCE_TERM_IMPLEMENTATION!="<none>" %}
470 virtual void sourceTerm(
471 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
472 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
473 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
474 [[maybe_unused]] double t,
475 [[maybe_unused]] double dt,
476 [[maybe_unused]] double* __restrict__ S // S[{{NUMBER_OF_UNKNOWNS}}]
477 ) {% if SOURCE_TERM_IMPLEMENTATION=="<user-defined>" %}= 0{% else %} final {% endif %};
478 {% endif %}
479""", undefined=jinja2.DebugUndefined)
480
481 d= {}
482 d[ "FLUX_IMPLEMENTATION"] = flux_implementation
483 d[ "NCP_IMPLEMENTATION"] = ncp_implementation
484 d[ "EIGENVALUES_IMPLEMENTATION"] = eigenvalues_implementation
485 d[ "SOURCE_TERM_IMPLEMENTATION"] = source_term_implementation
486 d[ "STATELESS_PDE_TERMS"] = pde_terms_without_state
487 return Template.render(**d)
488
489def create_abstract_solver_definitions(flux_implementation, ncp_implementation, eigenvalues_implementation, source_term_implementation, pde_terms_without_state):
490 Template = jinja2.Template( """
491{% if EIGENVALUES_IMPLEMENTATION!="<user-defined>" and EIGENVALUES_IMPLEMENTATION!="<none>" %}
492void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::maxEigenvalue(
493 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
494 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
495 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
496 [[maybe_unused]] double t,
497 [[maybe_unused]] double dt,
498 [[maybe_unused]] int normal,
499 [[maybe_unused]] double* __restrict__ maxEigenvalue
500) {
501 {{EIGENVALUES_IMPLEMENTATION}}
502}
503{% endif %}
504
505{% if FLUX_IMPLEMENTATION!="<none>" and FLUX_IMPLEMENTATION!="<user-defined>" %}
506void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::flux(
507 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
508 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
509 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
510 [[maybe_unused]] double t,
511 [[maybe_unused]] double dt,
512 [[maybe_unused]] int normal,
513 [[maybe_unused]] double* __restrict__ F // F[{{NUMBER_OF_UNKNOWNS}}]
514) {
515 {{FLUX_IMPLEMENTATION}}
516}
517{% endif %}
518
519{% if NCP_IMPLEMENTATION!="<none>" and NCP_IMPLEMENTATION!="<user-defined>" %}
520void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::nonconservativeProduct(
521 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
522 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
523 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
524 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
525 [[maybe_unused]] double t,
526 [[maybe_unused]] double dt,
527 [[maybe_unused]] int normal,
528 [[maybe_unused]] double* __restrict__ BTimesDeltaQ // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
529) {
530 {{NCP_IMPLEMENTATION}}
531}
532{% endif %}
533
534{% if SOURCE_TERM_IMPLEMENTATION!="<user-defined>" and SOURCE_TERM_IMPLEMENTATION!="<none>" %}
535//#if !defined(GPUOffloadingSYCL)
536void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::sourceTerm(
537 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
538 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
539 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
540 [[maybe_unused]] double t,
541 [[maybe_unused]] double dt,
542 [[maybe_unused]] double* __restrict__ S // S[{{NUMBER_OF_UNKNOWNS}}]
543) {
544 {% if SOURCE_TERM_IMPLEMENTATION!="<empty>" %}
545 {{SOURCE_TERM_IMPLEMENTATION}}
546 {% else %}
547 std::fill_n(S,{{NUMBER_OF_UNKNOWNS}},0.0);
548 {% endif %}
549}
550//#endif
551{% endif %}
552
553{% if EIGENVALUES_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
554#if defined(GPUOffloadingOMP)
555#pragma omp declare target
556#endif
557//#if !defined(GPUOffloadingSYCL)
558GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::maxEigenvalue(
559 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
560 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
561 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
562 [[maybe_unused]] double t,
563 [[maybe_unused]] double dt,
564 [[maybe_unused]] int normal,
565 [[maybe_unused]] double* __restrict__ maxEigenvalue,
566 Offloadable
567) {
568 {{EIGENVALUES_IMPLEMENTATION}};
569}
570//#endif
571#if defined(GPUOffloadingOMP)
572#pragma omp end declare target
573#endif
574{% endif %}
575
576
577{% if FLUX_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
578#if defined(GPUOffloadingOMP)
579#pragma omp declare target
580#endif
581//#if !defined(GPUOffloadingSYCL)
582GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::flux(
583 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
584 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
585 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
586 [[maybe_unused]] double t,
587 [[maybe_unused]] double dt,
588 [[maybe_unused]] int normal,
589 [[maybe_unused]] double* __restrict__ F, // F[{{NUMBER_OF_UNKNOWNS}}]
590 Offloadable
591) {
592 {% if FLUX_IMPLEMENTATION=="<none>" %}
593 tarch::gpuAbort();
594 {% else %}
595 {{FLUX_IMPLEMENTATION}}
596 {% endif %}
597}
598//#endif
599#if defined(GPUOffloadingOMP)
600#pragma omp end declare target
601#endif
602{% endif %}
603
604{% if NCP_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
605#if defined(GPUOffloadingOMP)
606#pragma omp declare target
607#endif
608GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::nonconservativeProduct(
609 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
610 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
611 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
612 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
613 [[maybe_unused]] double t,
614 [[maybe_unused]] double dt,
615 [[maybe_unused]] int normal,
616 [[maybe_unused]] double* __restrict__ BTimesDeltaQ, // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
617 [[maybe_unused]] Offloadable
618) {
619 {% if NCP_IMPLEMENTATION=="<none>" %}
620 tarch::gpuAbort();
621 {% else %}
622 {{NCP_IMPLEMENTATION}}
623 {% endif %}
624}
625#if defined(GPUOffloadingOMP)
626#pragma omp end declare target
627#endif
628{% endif %}
629
630{% if SOURCE_TERM_IMPLEMENTATION!="<user-defined>" and STATELESS_PDE_TERMS %}
631#if defined(GPUOffloadingOMP)
632#pragma omp declare target
633#endif
634GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::sourceTerm(
635 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
636 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
637 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
638 [[maybe_unused]] double t,
639 [[maybe_unused]] double dt,
640 [[maybe_unused]] double* __restrict__ S, // S[{{NUMBER_OF_UNKNOWNS}}]
641 [[maybe_unused]] Offloadable
642) {
643 {% if SOURCE_TERM_IMPLEMENTATION=="<none>" %}
644 tarch::gpuAbort();
645 {% else %}
646 {{SOURCE_TERM_IMPLEMENTATION}}
647 {% endif %}
648}
649#if defined(GPUOffloadingOMP)
650#pragma omp end declare target
651#endif
652{% endif %}
653""", undefined=jinja2.DebugUndefined)
654
655 d= {}
656 d[ "FLUX_IMPLEMENTATION"] = flux_implementation
657 d[ "NCP_IMPLEMENTATION"] = ncp_implementation
658 d[ "EIGENVALUES_IMPLEMENTATION"] = eigenvalues_implementation
659 d[ "SOURCE_TERM_IMPLEMENTATION"] = source_term_implementation
660 d[ "STATELESS_PDE_TERMS"] = pde_terms_without_state
661 return Template.render(**d)
662
663def create_solver_declarations(flux_implementation, ncp_implementation, eigenvalues_implementation, source_term_implementation, pde_terms_without_state):
664 Template = jinja2.Template( """
665 public:
666 {% if SOURCE_TERM_IMPLEMENTATION=="<user-defined>" %}
667 virtual void sourceTerm(
668 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
669 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
670 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
671 [[maybe_unused]] double t,
672 [[maybe_unused]] double dt,
673 [[maybe_unused]] double* __restrict__ S // S[{{NUMBER_OF_UNKNOWNS}}]
674 ) override;
675 {% endif %}
676
677 {% if EIGENVALUES_IMPLEMENTATION=="<user-defined>" %}
678 /**
679 * Determine max eigenvalue over Jacobian in a given point with solution values
680 * (states) Q. All parameters are in.
681 *
682 * @return Max eigenvalue. Result has to be positive, so we are actually speaking
683 * about the maximum absolute eigenvalue.
684 */
685 virtual void maxEigenvalue(
686 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
687 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
688 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
689 [[maybe_unused]] double t,
690 [[maybe_unused]] double dt,
691 [[maybe_unused]] int normal,
692 [[maybe_unused]] double* __restrict__ maxEigenvalue
693 ) override;
694 {% endif %}
695
696 {% if FLUX_IMPLEMENTATION=="<user-defined>" %}
697 virtual void flux(
698 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
699 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
700 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
701 [[maybe_unused]] double t,
702 [[maybe_unused]] double dt,
703 [[maybe_unused]] int normal,
704 [[maybe_unused]] double* __restrict__ F // F[{{NUMBER_OF_UNKNOWNS}}]
705 ) override;
706 {% endif %}
707
708 {% if NCP_IMPLEMENTATION=="<user-defined>" %}
709 virtual void nonconservativeProduct(
710 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
711 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
712 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
713 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
714 [[maybe_unused]] double t,
715 [[maybe_unused]] double dt,
716 [[maybe_unused]] int normal,
717 [[maybe_unused]] double* __restrict__ BTimesDeltaQ // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
718 ) override;
719 {% endif %}
720
721 {% if STATELESS_PDE_TERMS and SOURCE_TERM_IMPLEMENTATION=="<user-defined>" %}
722 /**
723 * To obtain the best performance, I recommend to man inline command to
724 * this signature and to copy the implementation into the header. So it would
725 * read
726 *
727 * static inline void sourceTerm( ... ) {
728 * code here
729 * }
730 *
731 * The GPU offloading requires static functions. As we cannot overload the
732 * original (virtual) function with a static alternative, we do the
733 * TBB trick and overload by adding an additional enum. It has no semantics
734 * but helps the compiler to distinguish the different function variants.
735 */
736 #if defined(GPUOffloadingOMP)
737 #pragma omp declare target
738 #endif
739 static GPUCallableMethod void sourceTerm(
740 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
741 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
742 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
743 [[maybe_unused]] double t,
744 [[maybe_unused]] double dt,
745 [[maybe_unused]] double* __restrict__ S, // S[{{NUMBER_OF_UNKNOWNS}}]
746 [[maybe_unused]] Offloadable
747 );
748 #if defined(GPUOffloadingOMP)
749 #pragma omp end declare target
750 #endif
751 {% endif %}
752
753 {% if EIGENVALUES_IMPLEMENTATION=="<user-defined>" and STATELESS_PDE_TERMS %}
754 #if defined(GPUOffloadingOMP)
755 #pragma omp declare target
756 #endif
757 static GPUCallableMethod void maxEigenvalue(
758 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
759 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
760 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
761 [[maybe_unused]] double t,
762 [[maybe_unused]] double dt,
763 [[maybe_unused]] int normal,
764 [[maybe_unused]] double* __restrict__ maxEigenvalue,
765 [[maybe_unused]] Offloadable
766 );
767 #if defined(GPUOffloadingOMP)
768 #pragma omp end declare target
769 #endif
770 {% endif %}
771
772 {% if STATELESS_PDE_TERMS and FLUX_IMPLEMENTATION=="<user-defined>" %}
773 /**
774 * To obtain the best performance, I recommend to man inline command to
775 * this signature and to copy the implementation into the header. So it would
776 * read
777 *
778 * static inline void flux( ... ) {
779 * code here
780 * }
781 *
782 * The GPU offloading requires static functions. As we cannot overload the
783 * original (virtual) function with a static alternative, we do the
784 * TBB trick and overload by adding an additional enum. It has no semantics
785 * but helps the compiler to distinguish the different function variants.
786 */
787 #if defined(GPUOffloadingOMP)
788 #pragma omp declare target
789 #endif
790 static GPUCallableMethod void flux(
791 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
792 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
793 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
794 [[maybe_unused]] double t,
795 [[maybe_unused]] double dt,
796 [[maybe_unused]] int normal,
797 [[maybe_unused]] double* __restrict__ F, // F[{{NUMBER_OF_UNKNOWNS}}]
798 [[maybe_unused]] Offloadable
799 );
800 #if defined(GPUOffloadingOMP)
801 #pragma omp end declare target
802 #endif
803 {% endif %}
804
805 {% if STATELESS_PDE_TERMS and NCP_IMPLEMENTATION=="<user-defined>" %}
806 /**
807 * To obtain the best performance, I recommend to man inline command to
808 * this signature and to copy the implementation into the header. So it would
809 * read
810 *
811 * static inline void nonconservativeProduct( ... ) {
812 * code here
813 * }
814 *
815 * The GPU offloading requires static functions. As we cannot overload the
816 * original (virtual) function with a static alternative, we do the
817 * TBB trick and overload by adding an additional enum. It has no semantics
818 * but helps the compiler to distinguish the different function variants.
819 */
820 #if defined(GPUOffloadingOMP)
821 #pragma omp declare target
822 #endif
823 static GPUCallableMethod void nonconservativeProduct(
824 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
825 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
826 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
827 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
828 [[maybe_unused]] double t,
829 [[maybe_unused]] double dt,
830 [[maybe_unused]] int normal,
831 [[maybe_unused]] double* __restrict__ BTimesDeltaQ, // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
832 [[maybe_unused]] Offloadable
833 );
834 #if defined(GPUOffloadingOMP)
835 #pragma omp end declare target
836 #endif
837 {% endif %}
838""", undefined=jinja2.DebugUndefined)
839 d= {}
840 d[ "FLUX_IMPLEMENTATION"] = flux_implementation
841 d[ "NCP_IMPLEMENTATION"] = ncp_implementation
842 d[ "EIGENVALUES_IMPLEMENTATION"] = eigenvalues_implementation
843 d[ "SOURCE_TERM_IMPLEMENTATION"] = source_term_implementation
844 d[ "STATELESS_PDE_TERMS"] = pde_terms_without_state
845 return Template.render(**d)
846
847def create_solver_definitions(flux_implementation, ncp_implementation, eigenvalues_implementation, source_term_implementation, pde_terms_without_state):
848 Template = jinja2.Template( """
849{% if EIGENVALUES_IMPLEMENTATION=="<user-defined>" %}
850void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::maxEigenvalue(
851 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
852 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
853 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
854 [[maybe_unused]] double t,
855 [[maybe_unused]] double dt,
856 [[maybe_unused]] int normal,
857 [[maybe_unused]] double* __restrict__ maxEigenvalue
858) {
859 logTraceInWith4Arguments( "maxEigenvalue(...)", faceCentre, volumeH, t, normal );
860 // @todo implement
861 logTraceOut( "maxEigenvalue(...)" );
862}
863{% endif %}
864
865{% if FLUX_IMPLEMENTATION=="<user-defined>" %}
866void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::flux(
867 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
868 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
869 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
870 [[maybe_unused]] double t,
871 [[maybe_unused]] double dt,
872 [[maybe_unused]] int normal,
873 [[maybe_unused]] double* __restrict__ F // F[{{NUMBER_OF_UNKNOWNS}}]
874) {
875 logTraceInWith4Arguments("flux(...)", faceCentre, volumeH, t, normal);
876 // @todo Implement
877 logTraceOut("flux(...)");
878}
879{% endif %}
880
881{% if NCP_IMPLEMENTATION=="<user-defined>" %}
882void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::nonconservativeProduct(
883 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
884 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
885 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
886 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
887 [[maybe_unused]] double t,
888 [[maybe_unused]] double dt,
889 [[maybe_unused]] int normal,
890 [[maybe_unused]] double* __restrict__ BTimesDeltaQ // BTimesDeltaQQ[{{NUMBER_OF_UNKNOWNS}}]
891) {
892 logTraceInWith4Arguments("nonconservativeProduct(...)", faceCentre, volumeH, t, normal);
893 // @todo Implement
894 logTraceOut("nonconservativeProduct(...)");
895}
896{% endif %}
897
898{% if SOURCE_TERM_IMPLEMENTATION=="<user-defined>" %}
899void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::sourceTerm(
900 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
901 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeX,
902 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
903 [[maybe_unused]] double t,
904 [[maybe_unused]] double dt,
905 [[maybe_unused]] double* __restrict__ S // S[{{NUMBER_OF_UNKNOWNS}}]
906) {
907 logTraceInWith4Arguments("sourceTerm(...)", volumeX, volumeH, t, dt);
908
909 // @todo Implement and ensure that all entries of S are properly set
910 for (int i = 0; i < NumberOfUnknowns; i++) {
911 S[i] = 0.0;
912 }
913
914 logTraceOut("sourceTerm(...)");
915}
916{% endif %}
917
918
919{% if EIGENVALUES_IMPLEMENTATION=="<user-defined>" and STATELESS_PDE_TERMS %}
920#if defined(GPUOffloadingOMP)
921#pragma omp declare target
922#endif
923GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::maxEigenvalue(
924 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
925 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
926 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
927 [[maybe_unused]] double t,
928 [[maybe_unused]] double dt,
929 [[maybe_unused]] int normal,
930 [[maybe_unused]] double* __restrict__ maxEigenvalue,
931 Offloadable
932) {
933 // @todo implement
934}
935#if defined(GPUOffloadingOMP)
936#pragma omp end declare target
937#endif
938{% endif %}
939
940{% if FLUX_IMPLEMENTATION=="<user-defined>" and STATELESS_PDE_TERMS %}
941#if defined(GPUOffloadingOMP)
942#pragma omp declare target
943#endif
944GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::flux(
945 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
946 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
947 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
948 [[maybe_unused]] double t,
949 [[maybe_unused]] double dt,
950 [[maybe_unused]] int normal,
951 [[maybe_unused]] double* __restrict__ F, // F[{{NUMBER_OF_UNKNOWNS}}]
952 Offloadable
953) {
954 // @todo Implement
955}
956#if defined(GPUOffloadingOMP)
957#pragma omp end declare target
958#endif
959{% endif %}
960
961{% if NCP_IMPLEMENTATION=="<user-defined>" and STATELESS_PDE_TERMS %}
962#if defined(GPUOffloadingOMP)
963#pragma omp declare target
964#endif
965GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::nonconservativeProduct(
966 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
967 [[maybe_unused]] const double* __restrict__ deltaQ, // deltaQ[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
968 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& faceCentre,
969 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
970 [[maybe_unused]] double t,
971 [[maybe_unused]] double dt,
972 [[maybe_unused]] int normal,
973 [[maybe_unused]] double* __restrict__ BTimesDeltaQ, // BTimesDeltaQ[{{NUMBER_OF_UNKNOWNS}}]
974 [[maybe_unused]] Offloadable
975) {
976 // @todo Implement
977}
978#if defined(GPUOffloadingOMP)
979#pragma omp end declare target
980#endif
981{% endif %}
982
983{% if SOURCE_TERM_IMPLEMENTATION=="<user-defined>" and STATELESS_PDE_TERMS %}
984#if defined(GPUOffloadingOMP)
985#pragma omp declare target
986#endif
987GPUCallableMethod void {{FULL_QUALIFIED_NAMESPACE}}::{{CLASSNAME}}::sourceTerm(
988 [[maybe_unused]] const double* __restrict__ Q, // Q[{{NUMBER_OF_UNKNOWNS}}+{{NUMBER_OF_AUXILIARY_VARIABLES}}]
989 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeCentre,
990 [[maybe_unused]] const tarch::la::Vector<Dimensions, double>& volumeH,
991 [[maybe_unused]] double t,
992 [[maybe_unused]] double dt,
993 [[maybe_unused]] double* __restrict__ S, // S[{{NUMBER_OF_UNKNOWNS}}]
994 [[maybe_unused]] Offloadable
995) {
996 // @todo Implement but ensure that all entries of S are properly set
997 for (int i = 0; i < NumberOfUnknowns; i++) {
998 S[i] = 0.0;
999 }
1000}
1001#if defined(GPUOffloadingOMP)
1002#pragma omp end declare target
1003#endif
1004{% endif %}
1005
1006""", undefined=jinja2.DebugUndefined)
1007 d= {}
1008 d[ "FLUX_IMPLEMENTATION"] = flux_implementation
1009 d[ "NCP_IMPLEMENTATION"] = ncp_implementation
1010 d[ "EIGENVALUES_IMPLEMENTATION"] = eigenvalues_implementation
1011 d[ "SOURCE_TERM_IMPLEMENTATION"] = source_term_implementation
1012 d[ "STATELESS_PDE_TERMS"] = pde_terms_without_state
1013 return Template.render(**d)
create_rusanov_kernel_definitions_for_function(function, filename, patch_size, unknowns, auxiliary_variables, flux_implementation, ncp_implementation, source_term_implementation, compute_max_eigenvalue_of_next_time_step)
Definition kernels.py:45