Peano
Loading...
Searching...
No Matches
SeparateSweepsWithEnclaveTasking.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 .SeparateSweeps import SeparateSweeps
4from exahype2.solvers.PDETerms import PDETerms
5from exahype2.solvers.rkfd.actionsets.AbstractRKFDActionSet import AbstractRKFDActionSet
6
7import peano4
8import exahype2
9import jinja2
10
11
12import os
13
15 ReconstructPatchAndApplyFunctor,
16)
17
18from exahype2.solvers.ButcherTableau import ButcherTableau
19from exahype2.solvers.Storage import Storage
20
21
23 """!
24
25 Update one cell that is compute Runge-Kutta step on it
26
27 This routine is significantly simpler than its counterpart in SeparateSweeps,
28 as we basically check if a cell is an enclave cell or not. If it is one, we
29 spawn a task. If not, we call the static routine from the task class which
30 updates the patch. All the computations thus are removed.
31
32 """
33
34 SolveRiemannProblemsOverPatch = jinja2.Template(
35 """
36 double timeStamp = fineGridCell{{SOLVER_NAME}}CellLabel.getTimeStamp();
37
38 // Set the variable
39 // double timeStepSize
40 {{COMPUTE_TIME_STEP_SIZE}}
41
42 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
43 if ({{PREDICATES[PREDICATE_NO]}}) {
44 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithAuxiliaryVariablesOnReconstructedPatch( 1, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, {{HALO_SIZE}}, {{NUMBER_OF_UNKNOWNS}}, {{NUMBER_OF_AUXILIARY_VARIABLES}});
45 ::exahype2::enumerator::AoSLexicographicEnumerator enumeratorWithoutAuxiliaryVariables( {{RK_STEPS}}, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}}, 0, {{NUMBER_OF_UNKNOWNS}}, 0 );
46
47 dfor( dof, {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} ) {
48 for (int unknown=0; unknown<{{NUMBER_OF_UNKNOWNS}}; unknown++) {
49 {% for WEIGHT_NO in range(0,BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO]|length) %}
50 {% if BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]!=0 %}
51 oldQWithHalo[ enumeratorWithAuxiliaryVariablesOnReconstructedPatch(0,dof,unknown) ] +=
52 timeStepSize * {{BUTCHER_TABLEAU_WEIGHTS[PREDICATE_NO][WEIGHT_NO]}} *
53 fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value[ enumeratorWithoutAuxiliaryVariables({{WEIGHT_NO}},dof,unknown) ];
54 {% endif %}
55 {% endfor %}
56 }
57 }
58
59 newQ = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + enumeratorWithoutAuxiliaryVariables({{PREDICATE_NO}},0,0);
60 }
61 {% endfor %}
62
63 {{PREPROCESS_RECONSTRUCTED_PATCH}}
64
65 assertion2( tarch::la::greaterEquals( timeStamp, 0.0 ), timeStamp, timeStepSize );
66 assertion2( tarch::la::greaterEquals( timeStepSize, 0.0 ), timeStamp, timeStepSize );
67
68 ::exahype2::fd::validatePatch(
69 oldQWithHalo,
70 {{NUMBER_OF_UNKNOWNS}},
71 {{NUMBER_OF_AUXILIARY_VARIABLES}},
72 {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}},
73 {{HALO_SIZE}}, // halo
74 std::string(__FILE__) + "(" + std::to_string(__LINE__) + "): " + marker.toString()
75 ); // previous time step has to be valid
76
77 double subTimeStamp=timeStamp;
78 {% for PREDICATE_NO in range(0,PREDICATES|length-1) %}
79 if ({{PREDICATES[PREDICATE_NO]}}) {
80 subTimeStamp += {{BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES[PREDICATE_NO]}}*timeStepSize;
81 }
82 {% endfor %}
83
84 if ( marker.willBeSkeletonCell() ) {
85 tasks::{{SOLVER_NAME}}EnclaveTask::applyKernelToCell(
86 marker,
87 subTimeStamp,
88 timeStepSize,
89 oldQWithHalo,
90 newQ
91 );
92
93 fineGridCell{{SEMAPHORE_LABEL}}.setSemaphoreNumber( ::exahype2::EnclaveBookkeeping::SkeletonTask );
94 }
95 else {
96 assertion( marker.willBeEnclaveCell() );
97 assertion( not marker.willBeRefined() );
98 auto newEnclaveTask = new tasks::{{SOLVER_NAME}}EnclaveTask(
99 marker,
100 subTimeStamp,
101 timeStepSize,
102 oldQWithHalo,
103 {% if MAKE_COPY_OF_ENCLAVE_TASK_DATA %}
104 nullptr
105 {% else %}
106 newQ
107 {% endif %}
108 );
109
110 int predecessorEnclaveTaskNumber = fineGridCell{{SEMAPHORE_LABEL}}.getSemaphoreNumber();
111
112 tarch::multicore::spawnTask(
113 newEnclaveTask,
114 predecessorEnclaveTaskNumber>=0 ? std::set<int>{predecessorEnclaveTaskNumber} : tarch::multicore::NoInDependencies,
115 newEnclaveTask->getTaskId()
116 );
117
118 if (predecessorEnclaveTaskNumber>=0) {
119 ::exahype2::EnclaveTask::releaseTaskNumber(predecessorEnclaveTaskNumber);
120 }
121
122 fineGridCell{{SEMAPHORE_LABEL}}.setSemaphoreNumber( newEnclaveTask->getTaskId() );
123
124 // Time stamp is not updated, as this will be done by final linear combination
125 // fineGridCell{{SOLVER_NAME}}CellLabel.setTimeStamp(timeStamp + timeStepSize);
126
127 }
128 """
129 )
130
131 def __init__(self, solver):
132 """ """
133 one_huge_boolean_guard_expression = "false"
134 for expr in solver._primary_sweeps_of_Runge_Kutta_step_on_cell:
135 one_huge_boolean_guard_expression += " or (" + expr + ")"
136
137 super(UpdateCell, self).__init__(
138 patch=solver._patch,
139 patch_overlap=solver._patch_overlap_new,
140 functor_implementation="""
141#error please switch to your Riemann solver of choice
142""",
143 reconstructed_array_memory_location=peano4.toolbox.blockstructured.ReconstructedArrayMemoryLocation.ManagedSharedAcceleratorDeviceMemoryThroughTarchWithoutDelete,
144 guard=one_huge_boolean_guard_expression,
145 add_assertions_to_halo_exchange=False,
146 )
147 self._solver = solver
148
150 """
151 fineGridCell"""
152 + solver._name
153 + """CellLabel.setHasUpdated(false);
154"""
156 )
157
159
161 """!
162
163 This is our plug-in point to alter the underlying dictionary
164
165 """
166 super(UpdateCell, self)._add_action_set_entries_to_dictionary(d)
167
168 self._solver._init_dictionary_with_default_parameters(d)
169 self._solver.add_entries_to_text_replacement_dictionary(d)
170
171 d["PREDICATES"] = self._solver._primary_sweeps_of_Runge_Kutta_step_on_cell
172 d["BUTCHER_TABLEAU_WEIGHTS"] = self._butcher_tableau.weight_matrix()
173 d[
174 "BUTCHER_TABLEAU_RELATIVE_TIME_STEP_SIZES"
175 ] = self._butcher_tableau.time_step_sizes()
176
177 # Has to come after we've set the predicates, as we use these
178 # fields in here already
179 d["CELL_FUNCTOR_IMPLEMENTATION"] = self.SolveRiemannProblemsOverPatch.render(
180 **d
181 )
182
183 def get_includes(self):
184 return (
185 """
186#include "tarch/NonCriticalAssertions.h"
187#include "exahype2/enumerator/enumerator.h"
188#include "exahype2/fd/PatchUtils.h"
189#include "exahype2/EnclaveBookkeeping.h"
190#include "tarch/multicore/Task.h"
191"""
192 + self._solver._get_default_includes()
193 + self._solver.user_action_set_includes
194 + """
195#include "tasks/{}.h"
196""".format(
197 self._solver._enclave_task_name()
198 )
199 )
200
202 return __name__.replace(".py", "").replace(".", "_") + "_UpdateCell"
203
204
206 Template = """
207 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
208 if (
209 not marker.hasBeenRefined()
210 and
211 marker.hasBeenEnclaveCell()
212 and
213 {{PREDICATES[PREDICATE_NO]}}
214 ) {
215 #if Dimensions==2
216 constexpr int NumberOfDoFsPerCell = {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}} * {{NUMBER_OF_GRID_CELLS_PER_PATCH_PER_AXIS}};
217 double* QOut = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * NumberOfDoFsPerCell * {{NUMBER_OF_UNKNOWNS}};
218 #elif Dimensions==3
219 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}};
220 double* QOut = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * NumberOfDoFsPerCell * {{NUMBER_OF_UNKNOWNS}};
221 #endif
222
223 const int taskNumber = fineGridCell{{LABEL_NAME}}.getSemaphoreNumber();
224 if ( taskNumber>=0 ) {
225 double maxEigenvalue; // not used here
226 ::exahype2::EnclaveBookkeeping::getInstance().waitForTaskToTerminateAndCopyResultOver( taskNumber, QOut, maxEigenvalue );
227 fineGridCell{{LABEL_NAME}}.setSemaphoreNumber( ::exahype2::EnclaveBookkeeping::NoEnclaveTaskNumber );
228 }
229 }
230 {% endfor %}
231"""
232
233 def __init__(self, solver):
234 super(MergeEnclaveTaskOutcome, self).__init__(solver)
236 self.label_name = exahype2.grid.UpdateCellLabel.get_attribute_name(solver._name)
237
238 def get_body_of_operation(self, operation_name):
239 result = ""
240 if (
241 operation_name
242 == peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
243 ):
244 d = {}
245 self._solver._init_dictionary_with_default_parameters(d)
246 self._solver.add_entries_to_text_replacement_dictionary(d)
247 d["LABEL_NAME"] = self.label_name
248 d["PREDICATES"] = self._solver._secondary_sweeps_of_Runge_Kutta_step_on_cell
249 result = jinja2.Template(self.Template).render(**d)
250 pass
251 return result
252
254 return (
255 __name__.replace(".py", "").replace(".", "_") + "_MergeEnclaveTaskOutcome"
256 )
257
258 def get_includes(self):
259 return (
260 super(MergeEnclaveTaskOutcome, self).get_includes()
261 + """
262#include "exahype2/EnclaveBookkeeping.h"
263"""
264 )
265
266
268 """!
269
270 Enclave variant of the solver where we still run through mesh once per Runge-Kutta sweep
271
272 The concept of (enclave) tasking within ExaHyPE solvers is described in
273 detail in the @ref page_exahype_solvers_enclave_solvers "generic enclave discussion of ExaHyPE".
274 This class is a prototype realisation of this concept which other solvers
275 then specialise for particular numerical schemes.
276
277 The class basically replaces the standard "update a cell" action set with an
278 action set that might or might not spawn a task. In return, it adds a further
279 action set which merges the arising task outcomes into the actual mesh
280 structure. By default, we use peano4::datamanagement::CellMarker::willBeEnclaveCell()
281 and peano4::datamanagement::CellMarker::hasBeenEnclaveCell() to guide the
282 decision whether to spawn a task or not. You can overwrite this decision
283 by redefining the corresponding entry in the dictionary befilled by
284 add_entries_to_text_replacement_dictionary().
285
286 ## Task priorities
287
288 Use the attributes self.enclave_task_priority to change the priority of the
289 task. This value can either be a string that C++ can evaluate into a
290 priority or a plain numerical value. I set it to
291
292 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
293
294 by default.
295
296
297 """
298
300 self,
301 name,
302 patch_size,
303 overlap,
304 rk_order,
305 unknowns,
306 auxiliary_variables,
307 min_meshcell_h,
308 max_meshcell_h,
309 plot_grid_properties,
310 kernel_namespace,
311 pde_terms_without_state,
312 ):
313 """ """
314 self._name_name_name = name
316
318 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep{}".format(
321 self._name_name_name,
322 step,
323 )
324 for step in range(0, self.number_of_Runge_Kutta_steps())
325 ] + [
326 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep0AfterGridInitialisation".format(
329 self._name_name_name,
330 )
331 ]
333 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSecondarySubStep{}".format(
336 self._name_name_name,
337 step,
338 )
339 for step in range(0, self.number_of_Runge_Kutta_steps())
340 ]
341 self._last_secondary_sweep_of_Runge_Kutta_step_on_cell = "repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSecondarySubStep{}".format(
343 self._name_name_name,
345 )
346
348 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep{}".format(
351 self._name_name_name,
352 step,
353 )
354 for step in range(0, self.number_of_Runge_Kutta_steps())
355 ] + [
356 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep0AfterGridInitialisation".format(
359 self._name_name_name,
360 )
361 ]
363 "{} and repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSecondarySubStep{}".format(
366 self._name_name_name,
367 step,
368 )
369 for step in range(0, self.number_of_Runge_Kutta_steps())
370 ]
371
373 "("
374 + "repositories::"
376 + ".getSolverState()=="
377 + self._name_name_name
378 + "::SolverState::RungeKuttaPrimarySubStep0AfterGridInitialisation "
379 )
380 for step in range(0, self.number_of_Runge_Kutta_steps()):
381 self._primary_sweep_guard += " or repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep{}".format(
383 )
384 self._primary_sweep_guard += ")"
385
387 repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep0AfterGridInitialisation
388 or repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation
389 or repositories::{}.getSolverState()=={}::SolverState::Plotting
390 or repositories::{}.getSolverState()=={}::SolverState::Suspended
391 )""".format(
396 )
397
398
399 for step in range(0, self.number_of_Runge_Kutta_steps()):
400 self._primary_sweep_or_plot_guard += " or repositories::{}.getSolverState()=={}::SolverState::RungeKuttaPrimarySubStep{}".format(
402 )
404
405 self._secondary_sweep_guard = "( false"
406 for step in range(0, self.number_of_Runge_Kutta_steps()):
407 self._secondary_sweep_guard += " or repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSecondarySubStep{}".format(
409 )
410 self._secondary_sweep_guard += ")"
411
413 repositories::{}.getSolverState()=={}::SolverState::GridInitialisation""".format(
415 )
416 for step in range(0, self.number_of_Runge_Kutta_steps()):
417 self._secondary_sweep_or_initialisation_guard += " or repositories::{}.getSolverState()=={}::SolverState::RungeKuttaSecondarySubStep{}".format(
419 )
421
422 super(SeparateSweepsWithEnclaveTasking, self).__init__(
423 name,
424 patch_size,
425 overlap,
426 rk_order,
427 unknowns,
428 auxiliary_variables,
429 min_meshcell_h,
430 max_meshcell_h,
431 plot_grid_properties,
432 kernel_namespace,
433 )
434
436
438 "#error Not yet defined. Set in your Python solver class."
439 )
441 "#error Not yet defined. Set in your Python solver class."
442 )
443 self._pde_terms_without_state = pde_terms_without_state
444
445 self._fused_volumetric_kernel_call_cpu = "#error Not yet defined. Set self._fused_volumetric_kernel_call_cpu in your Python solver class."
446 self._fused_volumetric_kernel_call_gpu = "#error Not yet defined. Set self._fused_volumetric_kernel_call_gpu in your Python solver class."
447
448 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
449
452
454 """
455
456 Call the superclass' create_data_structures() to ensure that all the data
457 structures are in place, i.e. each cell can host a patch, that each face hosts
458 patch overlaps, and so forth. These quantities are all set to defaults. See
459 FV.create_data_structures().
460
461 After that, take the patch overlap (that's the data stored within the faces)
462 and ensure that these are sent and received via MPI whenever they are also
463 stored persistently. The default in FV is that no domain boundary data exchange
464 is active. Finally, ensure that the old data is only exchanged between the
465 initialisation sweep and the first first grid run-through.
466
467 """
468 super(SeparateSweepsWithEnclaveTasking, self).create_data_structures()
469
470 initialisation_sweep_guard = (
471 "("
472 + "repositories::"
474 + ".getSolverState()=="
475 + self._name_name_name
476 + "::SolverState::GridInitialisation"
477 + ")"
478 )
479 first_iteration_after_initialisation_guard = (
480 "("
481 + "repositories::"
483 + ".getSolverState()=="
484 + self._name_name_name
485 + "::SolverState::RungeKuttaPrimarySubStep0AfterGridInitialisation or "
486 + "repositories::"
488 + ".getSolverState()=="
489 + self._name_name_name
490 + "::SolverState::PlottingAfterGridInitialisation"
491 + ")"
492 )
493
494 self._patch_overlap_old.generator.send_condition = initialisation_sweep_guard
495 self._patch_overlap_old.generator.receive_and_merge_condition = (
496 first_iteration_after_initialisation_guard
497 )
498
499 secondary_sweep_or_initialisation_or_plotting_guard = """(
500 repositories::{}.getSolverState()=={}::SolverState::GridInitialisation or
501 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
502 repositories::{}.getSolverState()=={}::SolverState::Plotting or
503 repositories::{}.getSolverState()=={}::SolverState::Suspended or
504 repositories::{}.isLastGridSweepOfTimeStep()
505 )""".format(
511 )
512
513 primary_sweep_or_plotting = """(
514 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
515 repositories::{}.getSolverState()=={}::SolverState::Plotting or
516 repositories::{}.getSolverState()=={}::SolverState::Suspended or
517 repositories::{}.isFirstGridSweepOfTimeStep()
518 )""".format(
523 )
524
525 self._patch_overlap_new.generator.send_condition = (
526 secondary_sweep_or_initialisation_or_plotting_guard
527 )
528 self._patch_overlap_new.generator.receive_and_merge_condition = (
529 primary_sweep_or_plotting
530 )
531
532 first_sweep_of_time_step_or_plotting_guard = """(
533 repositories::{}.isFirstGridSweepOfTimeStep() or
534 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
535 repositories::{}.getSolverState()=={}::SolverState::Plotting or
536 repositories::{}.getSolverState()=={}::SolverState::Suspended
537 )""".format(
542 )
543
544 last_sweep_of_time_step_or_plotting_or_initialisation = """(
545 repositories::{}.getSolverState()=={}::SolverState::GridInitialisation or
546 repositories::{}.getSolverState()=={}::SolverState::PlottingAfterGridInitialisation or
547 repositories::{}.getSolverState()=={}::SolverState::Plotting or
548 repositories::{}.getSolverState()=={}::SolverState::Suspended or
549 repositories::{}.isLastGridSweepOfTimeStep()
550 )""".format(
556 )
557
558 self._patch_estimates.generator.load_store_compute_flag = "::peano4::grid::constructLoadStoreComputeFlag({},{},{})".format(
561 + """
562 and not ("""
563 + first_sweep_of_time_step_or_plotting_guard
564 + ")",
566 + """
567 and not ("""
568 + last_sweep_of_time_step_or_plotting_or_initialisation
569 + ")",
570 )
571
573 """
574
575 Call superclass routine and then reconfigure the update cell call.
576 Only the UpdateCell action set is specific to a single sweep.
577
578 This operation is implicity called via the superconstructor.
579
580 ## Guard construction
581
582 We note that the guard sets all contain the storage predicate already,
583 i.e. they combine the logic state analysis with an evaluation of
584 _load_cell_data_default_guard() and _store_cell_data_default_guard().
585 The singular strings like _primary_sweep_guard do not have this check
586 built in. We have to add it here.
587
588 """
589 super(SeparateSweepsWithEnclaveTasking, self).create_action_sets()
590
593
595 self._action_set_merge_enclave_task_outcome.descend_invocation_order = (
597 )
598 #
599 # have a single guard (technically)
600 #
603 + " and ("
605 + ")"
606 )
607 self._action_set_handle_boundary.guard = (
609 + " and ("
611 + ")"
612 )
615 + " and ("
617 + ")"
618 )
619
620 #
621 # the following mappings have guards, i.e. a whole set of guards
622 #
624 "{} and repositories::{}.getSolverState()=={}::SolverState::GridInitialisation".format(
627 self._name_name_name,
628 )
629 ]
630
631 #
632 # this one is fine, as it only is used in the initialisation
633 #
634 # self._action_set_copy_new_faces_onto_old_faces.guard = self._secondary_sweeps_of_Runge_Kutta_step_on_face
635
636 # last_sweep_of_time_step_or_plotting_or_initialisation
639 )
640
641 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
642 """
643
644 Add the enclave task for the GPU
645
646 See superclass for further information.
647
648 """
649 super(
650 SeparateSweepsWithEnclaveTasking, self
651 ).add_implementation_files_to_project(namespace, output, dimensions, subdirectory)
652 templatefile_prefix = os.path.join(
653 os.path.dirname(os.path.realpath(__file__)),
654 "SeparateSweeps.EnclaveTask.template",
655 )
656
657 if(subdirectory):
658 subdirectory += "/"
659
660 implementationDictionary = {}
661 self._init_dictionary_with_default_parameters(implementationDictionary)
663
664 # Some includes might logically belong into the action sets, but now they are
665 # 'outsourced' into the enclave task. So we manually add it here.
666 implementationDictionary["SOLVER_INCLUDES"] += self.user_solver_includes
667 implementationDictionary["SOLVER_INCLUDES"] += self.user_action_set_includesuser_action_set_includesuser_action_set_includes
668
669 task_name = self._enclave_task_name()
670 generated_solver_files = (
672 "{}.h".format(templatefile_prefix),
673 "{}.cpp".format(templatefile_prefix),
674 task_name,
675 namespace + ["tasks"],
676 subdirectory + "tasks",
677 implementationDictionary,
678 True,
679 )
680 )
681
682 output.add(generated_solver_files)
683 output.makefile.add_cpp_file(subdirectory + "tasks/" + task_name + ".cpp", generated=True)
684
685
687 """!
688
689 Add enclave aspect
690
691 Add enclave aspect to time stepping. If you study the superclass'
692 routine add_actions_to_perform_time_step() and consider that this action
693 set is invoked in the secondary grid sweep, then it becomes clear that
694 this merger has to come first, i.e. we first add the action set and then
695 we call the superclass' add_action_set().
696
697 We need the result of the volumetric operation before we sum up this
698 volumetric solution and the Riemann solution.
699
700 """
701 super(SeparateSweepsWithEnclaveTasking, self).add_actions_to_perform_time_step(
702 step
703 )
704 step.add_action_set(self._action_set_merge_enclave_task_outcome)
705
707 super(
708 SeparateSweepsWithEnclaveTasking, self
710
711 d["FUSED_COMPUTE_KERNEL_CALL_CPU"] = jinja2.Template(
712 self._fused_compute_kernel_call_cpu, undefined=jinja2.DebugUndefined
713 ).render(**d)
714 d["FUSED_COMPUTE_KERNEL_CALL_GPU"] = jinja2.Template(
715 self._fused_compute_kernel_call_gpu, undefined=jinja2.DebugUndefined
716 ).render(**d)
717
718 d["SEMAPHORE_LABEL"] = exahype2.grid.UpdateCellLabel.get_attribute_name(
719 self._name_name_name
720 )
721 d["STATELESS_PDE_TERMS"] = self._pde_terms_without_state
722 d["ENCLAVE_TASK_PRIORITY"] = self.enclave_task_priority
723 d["MAKE_COPY_OF_ENCLAVE_TASK_DATA"] = self.make_copy_of_enclave_task_data
724
725
726 @property
728 return (
729 """
730#include "exahype2/CellData.h"
731"""
732 + super(SeparateSweeps, self).user_action_set_includes
733 )
734
736 return "{}EnclaveTask".format(self._name_name_name)
737
739 self,
740 cell_data_storage: Storage,
741 face_data_storage: Storage,
742 ):
743 if cell_data_storage == Storage.SmartPointers:
745 else:
747
748 super(SeparateSweepsWithEnclaveTasking, self).switch_storage_scheme(
749 cell_data_storage,
750 face_data_storage
751 )
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
number_of_Runge_Kutta_steps(self)
Return number of steps required to realise the Runge-Kutta scheme.
user_solver_includes(self)
Add further includes to this property, if your solver requires some additional routines from other he...
_init_dictionary_with_default_parameters(self, d)
This one is called by all algorithmic steps before I invoke add_entries_to_text_replacement_dictionar...
create_data_structures(self)
Recall in subclasses if you wanna change the number of unknowns or auxiliary variables.
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
get_action_set_name(self)
You should replicate this function in each subclass, so you get meaningful action set names (otherwis...
Enclave variant of the solver where we still run through mesh once per Runge-Kutta sweep.
switch_storage_scheme(self, Storage cell_data_storage, Storage face_data_storage)
By default, we hold all data on the call stacks.
__init__(self, name, patch_size, overlap, rk_order, unknowns, auxiliary_variables, min_meshcell_h, max_meshcell_h, plot_grid_properties, kernel_namespace, pde_terms_without_state)
Instantiate a generic FV scheme with an overlap of 1.
create_data_structures(self)
Call the superclass' create_data_structures() to ensure that all the data structures are in place,...
add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory="")
Add the enclave task for the GPU.
create_action_sets(self)
Call superclass routine and then reconfigure the update cell call.
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
__init__(self, solver)
patch: peano4.datamodel.Patch Patch which is to be used
_add_action_set_entries_to_dictionary(self, d)
This is our plug-in point to alter the underlying dictionary.
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
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.