Peano
Loading...
Searching...
No Matches
AlgorithmStepLibrary.py
Go to the documentation of this file.
1from exaparty.api.particle.AlgorithmStep import AlgorithmStep
2from exaparty.api.particle.SPHParticle import SPHParticle
3
4
5DefaultIncludes = """
6#include "exaparty/CellMetaData.h"
7"""
8
9
11 """!
12 A mini-wrapper around a string for particle iterator.
13 Exists for convenience: adds self.insert() method,
14 which inserts the function which the iterators are supposed to call
15 on a particle or particle pair.
16
17 The function insertion works via string replacement. It will
18 look for the string '*FUNCTION*' to be replaced.
19 """
20
21 def __init__(self, template):
22 """!
23 template: str
24 the string containing the particle interacion iterator template
25 """
26 self.template = template
27 return
28
29 def insert(self, function):
30 """!
31 insert a function into the template string.
32
33 Returns the particle iterator template with the function inserted.
34 """
35 return self.template.replace("*FUNCTION*", function)
36
37
39 """!
40
41 Counterpart of ParticleVertexIteratorTemplate for cells.
42
43 """
44
45 def __init__(self, template):
46 """!
47 template: str
48 the string containing the particle interacion iterator template
49 """
50 self.template = template
51 return
52
53 def insert(self, function):
54 """!
55 insert a function into the template string.
56
57 Returns the particle iterator template with the function inserted.
58 """
59
60 return """
61 ::exaparty::CellMetaData cellMetaData(
62 marker,
63 numberOfCoalescedLocalParticlesPerVertex,
64 numberOfCoalescedActiveParticlesPerVertex,
65 localParticleIsContainedInCell
66 );
67""" + self.template.replace(
68 "*FUNCTION*", function
69 )
70
71
73 """!
74 Construct particle interaction iterator call templates given the
75 desired particle interaction kernel realisation. These signature
76 templates are strings containing c++ code snippets of the correct
77 iterator call signature.
78
79 In total, there are four types of iterators. The essential two are:
80
81 - The one that's used to run over all particle assigned to a vertex. It
82 is called iterate_over_particles_assigned_to_vertex.
83 - There is one to iterate over all particle pairs associated with a
84 cell. This one is called iterate_over_particles_assigned_to_cell.
85
86 From hereon, we can define some "derived" iterators:
87
88 - One special iterator runs over all particles associated with a vertex
89 and allows them to move. This one is titled
90 iterate_over_particles_assigned_to_vertex_for_move and equals
91 iterate_over_particles_assigned_to_vertex. However, it embeds the
92 latter into some bookkeeping for the validation of the
93 vertex-particle assocation.
94 - Another special iterator runs over all particles but allows them to
95 reduce into some global space. If you use vectorisation, this one
96 cannot be vectorised by definition.
97
98 Both special iterators are constructed to default values unless you
99 explicitly set them beforehand.
100
101 The iterators require a function to be passed as an argument to
102 act on the particles. In the template snippets being generated here,
103 the functions shall be replaced by a placeholder string '*FUNCTION*'.
104
105 Finally, the code snippets being returned are stored as a
106 ParticleVertexIteratorTemplate object.
107
108 @param particle_name: str
109 the particle class name.
110
111
112 4 ParticleVertexIteratorTemplate objects containing particle iterator code snippets.
113
114 @return vertex_for_move: snippet (in a ParticleVertexIteratorTemplate object) to
115 use for particle interactons which will move assigned to a vertex
116 @return cell: snippet (in a ParticleVertexIteratorTemplate object) to use for
117 particle-particle interactions assigned to a cell
118 @return vertex: snippet (in a ParticleVertexIteratorTemplate object) to use for
119 particle interactions assigned to a vertex
120 @return vertex_with_global_reduction: snippet (in a ParticleVertexIteratorTemplate
121 object) to use for particle interactions assigned to a vertex which also
122 contain a global reduction
123 """
124
125 PARTICLE = particle_name
126
127 iterate_over_particles_assigned_to_vertex_for_move = None
128 iterate_over_particles_assigned_to_vertex = f"""
129 // Template in src/exaparty/api/particle/AlgorithmStepLibrary.py
130 // iterate_over_particles_assigned_to_vertex
131
132 ::exaparty::kernels::forAllParticles(*FUNCTION*<globaldata::{PARTICLE}>,
133 numberOfCoalescedAssignedParticles,
134 *FUNCTION*UpdateParticlePredicate<globaldata::{PARTICLE}>
135 );
136 // end template
137 """
138 iterate_over_particles_assigned_to_cell = f"""
139 // Template in src/exaparty/api/particle/AlgorithmStepLibrary.py
140 // iterate_over_particles_assigned_to_cell
141
142 ::exaparty::kernels::forAllParticlePairs<*FUNCTION*<globaldata::{PARTICLE}>, *FUNCTION*UpdateParticlePredicate<globaldata::{PARTICLE}>, *FUNCTION*EvaluatePairInteractionPredicate<globaldata::{PARTICLE}>>(
143 cellMetaData,
144 localParticles,
145 activeParticles,
146 ::exaparty::kernels::kernelrealisation::Generic
147 );
148 // end template
149"""
150 iterate_over_particles_assigned_to_vertex_with_global_reduction = f"""
151 // Template in src/exaparty/api/particle/AlgorithmStepLibrary.py
152 // iterate_over_particles_assigned_to_vertex_with_global_reduction
153
154 ::exaparty::kernels::forAllParticles<*FUNCTION*<globaldata::{PARTICLE}>, *FUNCTION*UpdateParticlePredicate<globaldata::{PARTICLE}>>(marker,
155 assignedParticles,
156 numberOfCoalescedAssignedParticles,
157 ::exaparty::kernels::kernelrealisation::Generic
158 );
159 // end template
160 """
161
162 # Set defaults or raise error if there shouldn't be defaults and we missed something.
163
164 if iterate_over_particles_assigned_to_vertex_for_move is None:
165 iterate_over_particles_assigned_to_vertex_for_move = f"""
166 // Template in src/exaparty/api/particle/AlgorithmStepLibrary.py
167 // iterate_over_particles_assigned_to_vertex_for_move
168
169 auto oldParticlePositions = ::toolbox::particles::assignmentchecks::recordParticlePositions(assignedParticles);
170 ::exaparty::kernels::forAllParticles<*FUNCTION*<globaldata::{PARTICLE}>, *FUNCTION*ParticleUpdatePredicate<globaldata::{PARTICLE}>>(marker,
171 assignedParticles,
172 numberOfCoalescedAssignedParticles,
173 ::exaparty::kernels::kernelrealisation::Generic
174 );
175 ::toolbox::particles::assignmentchecks::traceParticleMovements(assignedParticles,
176 oldParticlePositions,
177 marker.x(),
178 marker.h(),
179 _spacetreeId);
180 // end template
181 """
182
183
184 if iterate_over_particles_assigned_to_cell is None:
185 raise ValueError("We shouldn't be here.")
186
187 if iterate_over_particles_assigned_to_vertex is None:
188 raise ValueError("We shouldn't be here.")
189
190 if iterate_over_particles_assigned_to_vertex_with_global_reduction is None:
191 iterate_over_particles_assigned_to_vertex_with_global_reduction = f"""
192 // Template in src/exaparty/api/particle/AlgorithmStepLibrary.py,
193 // iterate_over_particles_assigned_to_vertex_with_global_reduction
194 ::exaparty::kernels::forAllParticles<*FUNCTION*<globaldata::{PARTICLE}>,
195 ::exaparty::kernels::alwaysUpdateInVertexKernel<globaldata::{PARTICLE}>>(marker,
196 assignedParticles,
197 ::exaparty::kernels::kernelrealisation::Generic
198 );
199 // end template
200 """
201
202 # finally, wrap the templates into ParticleVertexIteratorTemplate objects
203 vertex_for_move = ParticleVertexIteratorTemplate(
204 iterate_over_particles_assigned_to_vertex_for_move
205 )
206 cell = ParticleCellIteratorTemplate(iterate_over_particles_assigned_to_cell)
208 iterate_over_particles_assigned_to_vertex_with_global_reduction
209 )
210 vertex_with_global_reduction = ParticleVertexIteratorTemplate(
211 iterate_over_particles_assigned_to_vertex_with_global_reduction
212 )
213
214 return vertex_for_move, cell, vertex, vertex_with_global_reduction
215
216
217def get_algorithm_step_dict(particle):
218 """!
219
220 Sets up a dict of the algorithm steps for this scheme so they can be accessed
221 at various points and by various models.
222
223 """
224
225 algorithm_steps_dict = {}
226
227 project_namespace = particle._exaparty_project_namespace
228
229 PARTICLE = particle.name
230 NAMESPACE = "::".join(project_namespace)
231
232 (
233 v_iter_for_move,
234 c_iter,
235 v_iter,
236 v_iter_with_global_reduction,
238
239 # --------------------------------------------------------------------------
240 # --------------------------------------------------------------------------
241 sph_kick1 = AlgorithmStep(
242 name="SPH_Kick1",
243 dependencies=AlgorithmStep.Dependencies.SELF,
244 effect=AlgorithmStep.Effect.ALTER_LOCAL_STATE,
245 touch_vertex_last_time_kernel=v_iter.insert(
246 "::exaparty::kernels::legacy::leapfrogKickWithGlobalTimeStepSize"
247 ),
248 includes=DefaultIncludes
249 + """
250 #include "exaparty/kernels/legacy/Leapfrog.h"
251 """,
252 )
253 algorithm_steps_dict["SPH_Kick1"] = sph_kick1
254
255 # --------------------------------------------------------------------------
256 #
257 #
258 # Correctness: Whenever we drift a particle, we might subsequently have to
259 # resort it. That is, we assign it to another vertex. Therefore, it can
260 # happen that another cell checks a particle again and that we notably call
261 # touchVertexLastTime() with one particle twice. Therefore, we only know
262 # that we touch a particle at least once in touchVertexLastTime, that cell
263 # updates can be done multiple times (subsequent cell and vertex updates
264 # will mask out any changes to the particle as the moved flag is set, but
265 # they check), and that a cell update can follow a touchVertexLastTime()
266 # (on a finer level if we move particles from fine to coarse).
267 # --------------------------------------------------------------------------
268 sph_drift = AlgorithmStep(
269 name="SPH_Drift",
270 dependencies=AlgorithmStep.Dependencies.SELF,
271 effect=AlgorithmStep.Effect.CHANGE_POSITION_OR_INTERACTION_RADIUS,
272 touch_vertex_first_time_kernel=v_iter.insert(
273 "::exaparty::timestepping::resetMovedParticleMarker"
274 ),
275 touch_vertex_last_time_kernel=v_iter_for_move.insert(
276 "::exaparty::kernels::legacy::leapfrogDriftWithGlobalTimeStepSize"
277 ),
278 includes=DefaultIncludes
279 + """
280 #include "Constants.h"
281 #include "exaparty/kernels/legacy/Leapfrog.h"
282 #include "exaparty/timestepping/GlobalTimeStepping.h"
283 #include "exaparty/timestepping/TimeStepping.h"
284 """,
285 cell_kernel_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce_MayOverwritePreviousCellUpdatesFromSameSweep",
286 touch_vertex_first_time_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce",
287 touch_vertex_last_time_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce",
288 )
289 algorithm_steps_dict["SPH_Drift"] = sph_drift
290
291 # --------------------------------------------------------------------------
292 # --------------------------------------------------------------------------
293 # From the SPH side of things, this doesn't need to be an AlgorithmStep
294 # on its own. We could merge it together with the drifts. However, in order
295 # to ensure that the particles which have just been moved in the preceeding
296 # drift sweep are sorted correctly into the cells and vertices, we need an
297 # extra sweep.
298 predictHydro = AlgorithmStep(
299 name="PredictHydro",
300 dependencies=AlgorithmStep.Dependencies.SELF,
301 effect=AlgorithmStep.Effect.ALTER_LOCAL_STATE,
302 touch_vertex_first_time_kernel=v_iter.insert(
303 "::exaparty::timestepping::resetMovedParticleMarker"
304 )
305 + v_iter.insert("::exaparty::kernels::legacy::hydroPredictExtra"),
306 includes=DefaultIncludes
307 + """
308 #include "Constants.h"
309 #include "exaparty/kernels/legacy/Leapfrog.h"
310 #include "exaparty/timestepping/TimeStepping.h"
311 """,
312 touch_vertex_first_time_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce_MayOverwritePreviousCellUpdatesFromSameSweep",
313 cell_kernel_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce_MayOverwritePreviousCellUpdatesFromSameSweep",
314 )
315 algorithm_steps_dict["PredictHydro"] = predictHydro
316
317 # --------------------------------------------------------------------------
318 # --------------------------------------------------------------------------
319 sph_densityWithConstantSearchRadius = AlgorithmStep(
320 name="SPH_DensityLoopWithConstantSearchRadius",
321 dependencies=AlgorithmStep.Dependencies.NEIGHBOURS,
322 effect=AlgorithmStep.Effect.ALTER_LOCAL_STATE_AND_MIGHT_RERUN,
323 prepare_traversal_kernel=f"""globaldata::{PARTICLE}::getSpecies().clearRerunPreviousGridSweepFlag();""",
324 touch_vertex_first_time_kernel=v_iter.insert(
325 "::exaparty::kernels::legacy::prepareDensity"
326 ),
327 cell_kernel=c_iter.insert("::exaparty::kernels::legacy::densityKernel"),
328 touch_vertex_last_time_kernel=(
329 v_iter.insert("::exaparty::kernels::legacy::endDensityCalculation")
330 + v_iter_with_global_reduction.insert(
331 "::exaparty::kernels::legacy::updateSmoothingLengthAndRerunIfRequired"
332 )
333 ),
334 includes=DefaultIncludes
335 + """
336 #include "exaparty/kernels/legacy/SmoothingLength.h"
337 #include "exaparty/kernels/legacy/Density.h"
338 """,
339 )
340 algorithm_steps_dict["SPH_Density"] = sph_densityWithConstantSearchRadius
341
342 # --------------------------------------------------------------------------
343 # --------------------------------------------------------------------------
344 sph_force = AlgorithmStep(
345 name="SPH_ForceLoop",
346 dependencies=AlgorithmStep.Dependencies.NEIGHBOURS,
347 effect=AlgorithmStep.Effect.ALTER_LOCAL_STATE,
348 touch_vertex_first_time_kernel=(
349 v_iter.insert(
350 "::exaparty::kernels::legacy::resetSmoothingLengthIterationCounter"
351 )
352 + v_iter.insert("::exaparty::kernels::legacy::prepareHydroForce")
353 + v_iter.insert("::exaparty::kernels::legacy::resetAcceleration")
354 ),
355 cell_kernel=c_iter.insert("::exaparty::kernels::legacy::forceKernel"),
356 touch_vertex_last_time_kernel=v_iter.insert(
357 "::exaparty::kernels::legacy::endHydroForceCalculation"
358 ),
359 includes=DefaultIncludes
360 + """
361 #include "exaparty/kernels/legacy/SmoothingLength.h"
362 #include "exaparty/kernels/legacy/HydroForce.h"
363 """,
364 )
365 algorithm_steps_dict["SPH_Force"] = sph_force
366
367 # --------------------------------------------------------------------------
368 # --------------------------------------------------------------------------
369 sph_kick2 = AlgorithmStep(
370 name="SPH_Kick2",
371 dependencies=AlgorithmStep.Dependencies.SELF,
372 effect=AlgorithmStep.Effect.ALTER_LOCAL_STATE,
373 touch_vertex_last_time_kernel=(
374 v_iter.insert(
375 "::exaparty::kernels::legacy::leapfrogKickWithGlobalTimeStepSize"
376 )
377 + v_iter.insert("::exaparty::kernels::legacy::resetPredictedValues")
378 ),
379 includes=DefaultIncludes
380 + """
381 #include "Constants.h"
382 #include "exaparty/kernels/legacy/Leapfrog.h"
383 """,
384 )
385 algorithm_steps_dict["SPH_Kick2"] = sph_kick2
386
387 # --------------------------------------------------------------------------
388 # --------------------------------------------------------------------------
389 timestep = AlgorithmStep(
390 name="SPH_Timestep",
391 dependencies=AlgorithmStep.Dependencies.SELF,
392 effect=AlgorithmStep.Effect.ALTER_GLOBAL_STATE,
393 touch_vertex_last_time_kernel="::exaparty::kernels::legacy::computeNextTimestep(marker, assignedParticles);",
394 includes=DefaultIncludes
395 + """
396 #include "Constants.h"
397 #include "exaparty/kernels/legacy/Timestep.h"
398 """,
399 )
400 algorithm_steps_dict["SPH_Timestep"] = timestep
401
402 # --------------------------------------------------------------------------
403 # --------------------------------------------------------------------------
404 sph_reduceGlobals = AlgorithmStep(
405 name="SPH_ReduceGlobalQuantities",
406 dependencies=AlgorithmStep.Dependencies.SELF,
407 effect=AlgorithmStep.Effect.ALTER_GLOBAL_STATE,
408 touch_vertex_last_time_kernel=v_iter_with_global_reduction.insert(
409 "::exaparty::statistics::reduceVelocityAndSearchRadius"
410 ),
411 prepare_traversal_kernel=f"""
412 globaldata::{PARTICLE}::getSpecies().clearSearchRadius();
413 globaldata::{PARTICLE}::getSpecies().clearVelocity();
414 """,
415 unprepare_traversal_kernel=f"""
416 globaldata::{PARTICLE}::getSpecies().setTimeStamp( globaldata::{PARTICLE}::getSpecies().getMinTimeStamp() + globaldata::{PARTICLE}::getSpecies().getMinTimeStepSize(), false );
417 ::exaparty::statistics::reportSearchRadiusVTDt<globaldata::{PARTICLE}>( "{PARTICLE}" );
418 """,
419 includes=DefaultIncludes
420 + """
421 #include "Constants.h"
422 #include "exaparty/statistics/Reports.h"
423 #include "exaparty/statistics/Statistics.h"
424 """,
425 )
426 algorithm_steps_dict["SPH_ReduceGlobalQuantities"] = sph_reduceGlobals
427
428 # --------------------------------------------------------------------------
429 # --------------------------------------------------------------------------
430 # The firstInitParticle step may adapt a particle's search radius to fit
431 # globally set limits. If the radius changes, and since this is the first
432 # step in the run, a particle may be passed further down the tree, in which
433 # case the dependency checks fail unless you permit the
434 # `_MayOverwritePreviousCellUpdatesFromSameSweep` dependency policy.
435 firstInit = AlgorithmStep(
436 name="SPH_FirstInitParticle",
437 dependencies=AlgorithmStep.Dependencies.SELF,
438 effect=AlgorithmStep.Effect.CHANGE_POSITION_OR_INTERACTION_RADIUS,
439 touch_vertex_last_time_kernel=v_iter_for_move.insert(
440 "::exaparty::kernels::legacy::firstInitParticle"
441 ),
442 includes=DefaultIncludes
443 + """
444 #include "Constants.h"
445 #include "exaparty/kernels/legacy/Swift.h"
446 """,
447 cell_kernel_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce_MayOverwritePreviousCellUpdatesFromSameSweep",
448 touch_vertex_first_time_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce",
449 touch_vertex_last_time_dependency_policy="TouchAtLeastOnce_AllPreviousStepsUpdateAtLeastOnce",
450 )
451 algorithm_steps_dict["SPH_FirstInitParticle"] = firstInit
452
453 return algorithm_steps_dict
Counterpart of ParticleVertexIteratorTemplate for cells.
insert(self, function)
insert a function into the template string.
__init__(self, template)
template: str the string containing the particle interacion iterator template
__init__(self, template)
template: str the string containing the particle interacion iterator template
insert(self, function)
insert a function into the template string.
Defines the meta data around one algorithmic step per particle.
_get_particle_iterator_templates(particle_name)
Construct particle interaction iterator call templates given the desired particle interaction kernel ...