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 .RungeKuttaDG import RungeKuttaDG
4from .SeparateSweeps import SeparateSweeps
5from exahype2.solvers.PDETerms import PDETerms
6
7import peano4
8import exahype2
9
10import jinja2
11
12import os
13
14from exahype2.solvers.fv.actionsets.AbstractFVActionSet import AbstractFVActionSet
15
16from peano4.toolbox.blockstructured.ReconstructPatchAndApplyFunctor import ReconstructPatchAndApplyFunctor
17from exahype2.solvers.Storage import Storage
18
19
21 Template = """
22 {% for PREDICATE_NO in range(0,PREDICATES|length) %}
23 if (
24 not marker.hasBeenRefined()
25 and
26 marker.hasBeenEnclaveCell()
27 and
28 {{PREDICATES[PREDICATE_NO]}}
29 ) {
30#if Dimensions==2
31 double* QOut = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * {{NUMBER_OF_DOFS_PER_CELL_2D}} * {{NUMBER_OF_UNKNOWNS}};
32#elif Dimensions==3
33 double* QOut = fineGridCell{{UNKNOWN_IDENTIFIER}}RhsEstimates.value + {{PREDICATE_NO}} * {{NUMBER_OF_DOFS_PER_CELL_3D}} * {{NUMBER_OF_UNKNOWNS}};
34#endif
35
36 const int taskNumber = fineGridCell{{LABEL_NAME}}.getSemaphoreNumber();
37 if ( taskNumber>=0 ) {
38 double maxEigenvalue; // not used here
39 ::exahype2::EnclaveBookkeeping::getInstance().waitForTaskToTerminateAndCopyResultOver( taskNumber, QOut, maxEigenvalue );
40 fineGridCell{{LABEL_NAME}}.setSemaphoreNumber( ::exahype2::EnclaveBookkeeping::NoEnclaveTaskNumber );
41 }
42 }
43 {% endfor %}
44"""
45
46
47 def __init__(self, solver):
48 super(MergeEnclaveTaskOutcome, self).__init__(solver)
49 self.label_name = exahype2.grid.UpdateCellLabel.get_attribute_name(solver._name)
50
51
52 def get_body_of_operation(self, operation_name):
53 result = ""
54 if (
55 operation_name
56 == peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
57 ):
58 d = {}
59 self._solver._init_dictionary_with_default_parameters(d)
60 self._solver.add_entries_to_text_replacement_dictionary(d)
61 d["LABEL_NAME"] = self.label_name
62 d["PREDICATES"] = self._solver._secondary_sweeps_of_Runge_Kutta_step_on_cell
63 result = jinja2.Template(self.Template).render(**d)
64 pass
65 return result
66
67
69 return (
70 __name__.replace(".py", "").replace(".", "_") + "_MergeEnclaveTaskOutcome"
71 )
72
73
74 def get_includes(self):
75 return (
76 super(MergeEnclaveTaskOutcome, self).get_includes()
77 + """
78#include "exahype2/EnclaveBookkeeping.h"
79"""
80 )
81
82
84 """
85 Two separate sweeps per Runge-Kutta sweep where volumetric operations
86 are outsourced into dedicated tasks.
87
88
89 ## Task priorities
90
91 Use the attributes self.enclave_task_priority to change the priority of the
92 task. This value can either be a string that C++ can evaluate into a
93 priority or a plain numerical value. I set it to
94
95 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
96
97 by default.
98 """
99
100
102 self,
103 name,
104 rk_order,
105 polynomial_basis,
106 number_of_face_projections,
107 unknowns,
108 auxiliary_variables,
109 min_cell_h,
110 max_cell_h,
111 plot_grid_properties,
112 pde_terms_without_state,
113 ):
114 """
115 See superclass constructor for all the interesting info.
116
117 It is important to notice that we still use the separate sweep template classes
118 here.
119 """
120 super(SeparateSweepsWithEnclaveTasking, self).__init__(
121 name,
122 rk_order,
123 polynomial_basis,
124 number_of_face_projections,
125 unknowns,
126 auxiliary_variables,
127 min_cell_h,
128 max_cell_h,
129 plot_grid_properties,
130 pde_terms_without_state,
131 )
132
135
136 self._fused_volumetric_compute_kernel_call_stateless_cpu = "#error Not yet defined. Set self._fused_volumetric_compute_kernel_call_stateless_cpu in your Python solver class."
137 self._fused_volumetric_compute_kernel_call_stateless_gpu = "#error Not yet defined. Set self._fused_volumetric_compute_kernel_call_stateless_gpu in your Python solver class."
138 self._fused_Riemann_compute_kernel_call_stateless_cpu = "#error Not yet defined. Set self._fused_Riemann_compute_kernel_call_stateless_cpu in your Python solver class."
139 self._fused_Riemann_compute_kernel_call_stateless_gpu = "#error Not yet defined. Set self._fused_Riemann_compute_kernel_call_stateless_gpu in your Python solver class."
140
141 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
142
145
146
148 """
149 First, call the superclass' create_data_structures() to ensure that all
150 the data structures are in place.
151
152 The linear combination is to be computed if and only if
153 """
154 super(SeparateSweepsWithEnclaveTasking, self).create_data_structures()
155
156
158 """
159 Call superclass routine and then reconfigure the update cell call.
160 Only the UpdateCell action set is specific to an enclave solver.
161
162 This operation is implicitly called via the superconstructor.
163
164 It is important that we add the action set at the right point. See
165 add_actions_to_perform_time_step() for a discussion.
166 """
167 super(SeparateSweepsWithEnclaveTasking, self).create_action_sets()
168
169 self._action_set_solve_volume_integral.spawn_volume_kernel_as_task = True
170
172 self._action_set_merge_enclave_task_outcome.descend_invocation_order = (
174 )
175
176
177 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
178 super(
179 SeparateSweepsWithEnclaveTasking, self
180 ).add_implementation_files_to_project(namespace, output, dimensions)
181 templatefile_prefix = os.path.join(
182 os.path.dirname(os.path.realpath(__file__)),
183 "SolveVolumeIntegral.EnclaveTask.template",
184 )
185
186 if(subdirectory):
187 subdirectory += "/"
188
189 implementationDictionary = {}
190 self._init_dictionary_with_default_parameters(implementationDictionary)
192
193 # Some includes might logically belong into the action sets, but now they are
194 # 'outsourced' into the enclave task. So we manually add it here.
195 implementationDictionary["SOLVER_INCLUDES"] += self.user_solver_includes
196 implementationDictionary["SOLVER_INCLUDES"] += self.user_action_set_includes
197
198 task_name = self._volumetric_solver_enclave_task_name()
199 generated_solver_files = (
201 "{}.h".format(templatefile_prefix),
202 "{}.cpp".format(templatefile_prefix),
203 task_name,
204 namespace + ["tasks"],
205 subdirectory + "tasks",
206 implementationDictionary,
207 True,
208 )
209 )
210
211 output.add(generated_solver_files)
212 output.makefile.add_cpp_file(subdirectory + "tasks/" + task_name + ".cpp", generated=True)
213
214
216 return "{}_VolumetricSolverEnclaveTask".format(self._name_name_name)
217
218
220 """
221 Add enclave aspect to time stepping. If you study the superclass'
222 routine add_actions_to_perform_time_step() and consider that this action
223 set is invoked in the secondary grid sweep, then it becomes clear that
224 this merger has to come first, i.e. we first add the action set and then
225 we call the superclass' add_action_set().
226
227 We need the result of the volumetric operation before we sum up this
228 volumetric solution and the Riemann solution.
229 """
230 super(SeparateSweepsWithEnclaveTasking, self).add_actions_to_perform_time_step(
231 step
232 )
233 step.add_action_set(self._action_set_merge_enclave_task_outcome)
234
235
237 super(SeparateSweepsWithEnclaveTasking, self).add_entries_to_text_replacement_dictionary(d)
238
239 d["FUSED_VOLUMETRIC_COMPUTE_KERNEL_CALL_STATELESS_CPU"] = jinja2.Template(
240 self._fused_volumetric_compute_kernel_call_stateless_cpu, undefined=jinja2.DebugUndefined
241 ).render(**d)
242 d["FUSED_VOLUMETRIC_COMPUTE_KERNEL_CALL_STATELESS_GPU"] = jinja2.Template(
243 self._fused_volumetric_compute_kernel_call_stateless_gpu, undefined=jinja2.DebugUndefined
244 ).render(**d)
245 d["FUSED_RIEMANN_COMPUTE_KERNEL_CALL_STATELESS_CPU"] = jinja2.Template(
246 self._fused_Riemann_compute_kernel_call_stateless_cpu, undefined=jinja2.DebugUndefined
247 ).render(**d)
248 d["FUSED_RIEMANN_COMPUTE_KERNEL_CALL_STATELESS_GPU"] = jinja2.Template(
249 self._fused_Riemann_compute_kernel_call_stateless_gpu, undefined=jinja2.DebugUndefined
250 ).render(**d)
251
252 d["SEMAPHORE_LABEL"] = exahype2.grid.UpdateCellLabel.get_attribute_name(
253 self._name_name_name
254 )
255 d["ENCLAVE_TASK_PRIORITY"] = self.enclave_task_priority
256 d["MAKE_COPY_OF_ENCLAVE_TASK_DATA"] = self.make_copy_of_enclave_task_data
257
258
260 self,
261 cell_data_storage: Storage,
262 face_data_storage: Storage,
263 ):
264 if cell_data_storage == Storage.SmartPointers:
266 else:
268
269 super(SeparateSweepsWithEnclaveTasking, self).switch_storage_scheme(
270 cell_data_storage,
271 face_data_storage
272 )
create_data_structures(self)
Recall in subclasses if you wanna change the number of unknowns or auxiliary variables.
create_action_sets(self)
Overwrite in subclasses if you wanna create different action sets.
user_action_set_includes(self)
Add further includes to this property, if your action sets require some additional routines from othe...
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...
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...
Two separate sweeps per Runge-Kutta sweep where volumetric operations are outsourced into dedicated t...
switch_storage_scheme(self, Storage cell_data_storage, Storage face_data_storage)
By default, we hold all data on the call stacks.
add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory="")
The ExaHyPE project will call this operation when it sets up the overall environment.
__init__(self, name, rk_order, polynomial_basis, number_of_face_projections, unknowns, auxiliary_variables, min_cell_h, max_cell_h, plot_grid_properties, pde_terms_without_state)
See superclass constructor for all the interesting info.
create_data_structures(self)
First, call the superclass' create_data_structures() to ensure that all the data structures are in pl...
create_action_sets(self)
Call superclass routine and then reconfigure the update cell call.
Probably the simplest solver you could think off.
create_data_structures(self)
First, call the superclass' create_data_structures() to ensure that all the data structures are in pl...
create_action_sets(self)
We invoke the superclass which creates all the action sets, and then we set the appropriate guards.