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(
40 taskNumber,
41 QOut,
42 maxEigenvalue,
43 marker.x(),
44 marker.h()
45 );
46 fineGridCell{{LABEL_NAME}}.setSemaphoreNumber( ::exahype2::EnclaveBookkeeping::NoEnclaveTaskNumber );
47 }
48 }
49 {% endfor %}
50"""
51
52
53 def __init__(self, solver):
54 super(MergeEnclaveTaskOutcome, self).__init__(solver)
55 self.label_name = exahype2.grid.UpdateCellLabel.get_attribute_name(solver._name)
56
57
58 def get_body_of_operation(self, operation_name):
59 result = ""
60 if (
61 operation_name
62 == peano4.solversteps.ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME
63 ):
64 d = {}
65 self._solver._init_dictionary_with_default_parameters(d)
66 self._solver.add_entries_to_text_replacement_dictionary(d)
67 d["LABEL_NAME"] = self.label_name
68 d["PREDICATES"] = self._solver._secondary_sweeps_of_Runge_Kutta_step_on_cell
69 result = jinja2.Template(self.Template).render(**d)
70 pass
71 return result
72
73
75 return (
76 __name__.replace(".py", "").replace(".", "_") + "_MergeEnclaveTaskOutcome"
77 )
78
79
80 def get_includes(self):
81 return (
82 super(MergeEnclaveTaskOutcome, self).get_includes()
83 + """
84#include "exahype2/EnclaveBookkeeping.h"
85"""
86 )
87
88
90 """
91 Two separate sweeps per Runge-Kutta sweep where volumetric operations
92 are outsourced into dedicated tasks.
93
94
95 ## Task priorities
96
97 Use the attributes self.enclave_task_priority to change the priority of the
98 task. This value can either be a string that C++ can evaluate into a
99 priority or a plain numerical value. I set it to
100
101 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
102
103 by default.
104 """
105
106
108 self,
109 name,
110 rk_order,
111 polynomial_basis,
112 number_of_face_projections,
113 unknowns,
114 auxiliary_variables,
115 min_cell_h,
116 max_cell_h,
117 plot_grid_properties,
118 pde_terms_without_state,
119 ):
120 """
121 See superclass constructor for all the interesting info.
122
123 It is important to notice that we still use the separate sweep template classes
124 here.
125 """
126 super(SeparateSweepsWithEnclaveTasking, self).__init__(
127 name,
128 rk_order,
129 polynomial_basis,
130 number_of_face_projections,
131 unknowns,
132 auxiliary_variables,
133 min_cell_h,
134 max_cell_h,
135 plot_grid_properties,
136 pde_terms_without_state,
137 )
138
139 self._solver_template_file_class_name = "SeparateSweeps"
140 self._pde_terms_without_state = pde_terms_without_state
141
142 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."
143 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."
144 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."
145 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."
146
147 self.enclave_task_priority = "tarch::multicore::Task::DefaultPriority-1"
148
149 self.create_action_sets()
151
152
154 """
155 First, call the superclass' create_data_structures() to ensure that all
156 the data structures are in place.
157
158 The linear combination is to be computed if and only if
159 """
160 super(SeparateSweepsWithEnclaveTasking, self).create_data_structures()
161
162
164 """
165 Call superclass routine and then reconfigure the update cell call.
166 Only the UpdateCell action set is specific to an enclave solver.
167
168 This operation is implicitly called via the superconstructor.
169
170 It is important that we add the action set at the right point. See
171 add_actions_to_perform_time_step() for a discussion.
172 """
173 super(SeparateSweepsWithEnclaveTasking, self).create_action_sets()
174
175 self._action_set_solve_volume_integral.spawn_volume_kernel_as_task = True
176
178 self._action_set_merge_enclave_task_outcome.descend_invocation_order = (
180 )
181
182
183 def add_implementation_files_to_project(self, namespace, output, dimensions, subdirectory=""):
184 super(
185 SeparateSweepsWithEnclaveTasking, self
186 ).add_implementation_files_to_project(namespace, output, dimensions)
187 templatefile_prefix = os.path.join(
188 os.path.dirname(os.path.realpath(__file__)),
189 "SolveVolumeIntegral.EnclaveTask.template",
190 )
191
192 if(subdirectory):
193 subdirectory += "/"
194
195 implementationDictionary = {}
196 self._init_dictionary_with_default_parameters(implementationDictionary)
197 self.add_entries_to_text_replacement_dictionary(implementationDictionary)
198
199 # Some includes might logically belong into the action sets, but now they are
200 # 'outsourced' into the enclave task. So we manually add it here.
201 implementationDictionary["SOLVER_INCLUDES"] += self.user_solver_includes
202 implementationDictionary["SOLVER_INCLUDES"] += self.user_action_set_includes
203
204 task_name = self._volumetric_solver_enclave_task_name()
205 generated_solver_files = (
207 "{}.h".format(templatefile_prefix),
208 "{}.cpp".format(templatefile_prefix),
209 task_name,
210 namespace + ["tasks"],
211 subdirectory + "tasks",
212 implementationDictionary,
213 True,
214 )
215 )
216
217 output.add(generated_solver_files)
218 output.makefile.add_cpp_file(subdirectory + "tasks/" + task_name + ".cpp", generated=True)
219
220
222 return "{}_VolumetricSolverEnclaveTask".format(self._name)
223
224
226 """
227 Add enclave aspect to time stepping. If you study the superclass'
228 routine add_actions_to_perform_time_step() and consider that this action
229 set is invoked in the secondary grid sweep, then it becomes clear that
230 this merger has to come first, i.e. we first add the action set and then
231 we call the superclass' add_action_set().
232
233 We need the result of the volumetric operation before we sum up this
234 volumetric solution and the Riemann solution.
235 """
236 super(SeparateSweepsWithEnclaveTasking, self).add_actions_to_perform_time_step(
237 step
238 )
239 step.add_action_set(self._action_set_merge_enclave_task_outcome)
240
241
243 super(SeparateSweepsWithEnclaveTasking, self).add_entries_to_text_replacement_dictionary(d)
244
245 d["FUSED_VOLUMETRIC_COMPUTE_KERNEL_CALL_STATELESS_CPU"] = jinja2.Template(
246 self._fused_volumetric_compute_kernel_call_stateless_cpu, undefined=jinja2.DebugUndefined
247 ).render(**d)
248 d["FUSED_VOLUMETRIC_COMPUTE_KERNEL_CALL_STATELESS_GPU"] = jinja2.Template(
249 self._fused_volumetric_compute_kernel_call_stateless_gpu, undefined=jinja2.DebugUndefined
250 ).render(**d)
251 d["FUSED_RIEMANN_COMPUTE_KERNEL_CALL_STATELESS_CPU"] = jinja2.Template(
252 self._fused_Riemann_compute_kernel_call_stateless_cpu, undefined=jinja2.DebugUndefined
253 ).render(**d)
254 d["FUSED_RIEMANN_COMPUTE_KERNEL_CALL_STATELESS_GPU"] = jinja2.Template(
255 self._fused_Riemann_compute_kernel_call_stateless_gpu, undefined=jinja2.DebugUndefined
256 ).render(**d)
257
258 d["SEMAPHORE_LABEL"] = exahype2.grid.UpdateCellLabel.get_attribute_name(
259 self._name
260 )
261 d["ENCLAVE_TASK_PRIORITY"] = self.enclave_task_priority
262 d["MAKE_COPY_OF_ENCLAVE_TASK_DATA"] = self.make_copy_of_enclave_task_data
263
264
266 self,
267 cell_data_storage: Storage,
268 face_data_storage: Storage,
269 ):
270 if cell_data_storage == Storage.SmartPointers:
272 else:
274
275 super(SeparateSweepsWithEnclaveTasking, self).switch_storage_scheme(
276 cell_data_storage,
277 face_data_storage
278 )
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.