Peano
Loading...
Searching...
No Matches
SPHLeapfrogFixedSearchRadius.py
Go to the documentation of this file.
1# This file is part of the SWIFT2 project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from swift2.particle.SPHParticle import SPHParticle
4from swift2.particle.AlgorithmStep import AlgorithmStep
5from swift2.particle.AlgorithmStepLibrary import get_algorithm_step_dict
6
7import peano4
8import dastgen2
10
11from abc import ABC
12import copy
13
14
15from enum import Enum
16
17
19 """!
20
21 SPH particle with fixed search radius
22
23 Same as LeapfrogFixedSearchRadius but augmented for full SPH.
24 Implements the Minimal SPH scheme.
25
26 Simple particle with a fixed search radius h which moves according
27 to leapfrog KDK scheme.
28 By default, it uses global time stepping,
29 i.e. the combination of maximum velocity and minimal mesh size determines
30 the time step size of the subsequent time step. Besides the default
31 variables x and h, the particle has the following properties:
32
33 - a vector a which is the acceleration;
34 - a vector v which is the velocity.
35
36 You can add further properties via
37
38 myparticle.data.add_attribute( peano4.dastgen2.Peano4DoubleArray("myFancyArray","Dimensions") )
39
40 in your code. Or you can create a subclass which adds additional fields
41 after it has called the baseline constructor.
42
43 You will need to add further properties for any SPH project.
44
45 ## Force calculation
46
47 particle_particle_interaction_over_particle_sets_kernel is a C++ string which defines a force between two
48 particles. It has access to three important objects:
49
50 - localParticles is a container (list) over pointers to local particles
51 - activeParticles is a container (list) over pointers to active particles
52 - marker is a cell marker which identifies the current cell.
53
54 Please consult the guidebook for a definition of local and active particles
55 but take into account that the local particles always are a subset of the
56 active particles.
57
58 Besides the actual particle-to-particle calculation, i.e. a force
59 calculation, users can also provide kernels that kick in when you touch
60 particles for the first time before you actually compute any
61 particle-particle interaction, and there is a plug-in point what you do
62 just once the particle-particle interaction has terminated. The latter
63 point is reached before we do the actual time stepping. In both plug-in
64 points, you have a vertex marker which gives you the position of the
65 vertex to which a particular is associated, and you have the localParticles.
66 This is a vector of pointers in this particular case.
67
68 The force calculation does exist in two variants: There's the default one
69 and then we have one that is aggressively optimised. The latter one requires
70 us to have properly sorted particle-mesh associations.
71
72 ## Precision
73
74 By default, all particle attributes are modelled as doubles or arrays of
75 doubles. This might be overly precise. You can alter the precision through
76 our LLVM compiler modifications if you invoke the following commands on a
77 particle species:
78
79 ~~~~~~~~~~~~~~~~~~~~~~~~~~
80 particle.mass.valid_mantissa_bits = args.mantissa_size
81 particle.velocity.valid_mantissa_bits = args.mantissa_size
82 particle.acceleration.valid_mantissa_bits = args.mantissa_size
83 particle.density.valid_mantissa_bits = args.mantissa_size
84 particle.pressure.valid_mantissa_bits = args.mantissa_size
85 particle.smoothL.valid_mantissa_bits = args.mantissa_size
86 particle.u.valid_mantissa_bits = args.mantissa_size
87 particle.uDot.valid_mantissa_bits = args.mantissa_size
88 particle.f.valid_mantissa_bits = args.mantissa_size
89 particle.wcount_dh.valid_mantissa_bits = args.mantissa_size
90 particle.rho_dh.valid_mantissa_bits = args.mantissa_size
91 particle.wcount.valid_mantissa_bits = args.mantissa_size
92 particle.hDot.valid_mantissa_bits = args.mantissa_size
93 particle.balsara.valid_mantissa_bits = args.mantissa_size
94 particle.rot_v.valid_mantissa_bits = args.mantissa_size
95 particle.div_v.valid_mantissa_bits = args.mantissa_size
96 particle.v_sig_AV.valid_mantissa_bits = args.mantissa_size
97 particle.soundSpeed.valid_mantissa_bits = args.mantissa_size
98 particle.v_full.valid_mantissa_bits = args.mantissa_size
99 particle.u_full.valid_mantissa_bits = args.mantissa_size
100 ~~~~~~~~~~~~~~~~~~~~~~~~~~
101
102 This is an example. You can also add ony a few of these fields, and picking
103 a value for args.mantissa_size is obviously up to you. We refrain from
104 illustrating that you can also alter the precision of the position and
105 maximum search radius of a particle this way. This is on purpose: We have
106 made bad experience with such modifications.
107
108 ## Boundary conditions
109
110 Boundary conditions for Swift are @ref swift_boundary_conditions "discussed on a separate page".
111 If you decide that you want to plug into the drift mechanism of
112 this SPH flavour, you typically add something similar to the
113 code snippet below to your code:
114
115 ~~~~~~~~~~~~~~~~~~~~~~
116 particle.algorithm_steps_dict["Drift"].touch_vertex_last_time_kernel += " " "
117 if (::swift2::boundaryconditions::isVertexOnGlobalBoundary(marker,DomainOffset,DomainSize)) {
118 ::swift2::kernels::forAllParticles<
119 [&](const peano4::datamanagement::VertexMarker& marker, globaldata::" " " + name + " " "& assignedParticle)->void {
120 ::swift2::boundaryconditions::applyFixedBoundaryCondition(
121 assignedParticle,
122 marker,
123 DomainOffset,
124 DomainSize,
125 0.1,
126 _spacetreeId
127 );
128 },
129 @todo Attribute missing
130 >(
131 marker,
132 assignedParticles,
133 numberOfCoalescedAssignedParticles
134 );
135 }
136 " " "
137 particle.algorithm_steps_dict["Drift"].includes += " " "
138 #include "swift2/boundaryconditions/FixedBoundary.h"
139 #include "swift2/boundaryconditions/Utils.h"
140 " " "
141 particle._setup_algorithm_steps()
142 particle._setup_initialisation_steps()
143 ~~~~~~~~~~~~~~~~~~~~~~
144
145 The spaced-out syntax is just there to ensure that the Python documentation
146 syntax is not broken.
147
148
149 ## Attributes
150
151 name: String
152 To be in line with other conventions, I recommend you start with an
153 uppercase letter. This has to be a valid C++ identifier, i.e. don't
154 use any special symbols besides an underscore.
155
156 ## Vectorisation
157
158 This type can be used with aggressively optimised kernels if you follow
159 @ref page_swift_performance_optimisation Performance optimisation and use
160 the map_particle_steps_onto_separate_mesh_traversals_insert_dummy_sweeps_for_coalesced_memory_access
161 graph compiler from the Sequential suite; or literally any other
162 flavour which yields coalesced memory.
163
164 @see peano4::datamanagement::CellMarker
165 @see peano4::datamanagement::VertexMarker
166
167 """
168
170 self,
171 name,
172 dimensions_hydro=2,
173 cfl_factor=0.1,
174 initial_time_step_size=1e-4,
175 constant_time_step_size=True,
176 swift_project_namespace="SPH",
177 particles_per_cell=0, # makes no sense, and should likely be forbidden
178 min_h=0.3,
179 max_h=0.3,
180 ):
181 super(SPHLeapfrogFixedSearchRadius, self).__init__(
182 name=name,
183 dimensions_hydro=dimensions_hydro,
184 cfl_factor=cfl_factor,
185 initial_time_step_size=initial_time_step_size,
186 constant_time_step_size=constant_time_step_size,
187 swift_project_namespace=swift_project_namespace,
188 particles_per_cell=particles_per_cell,
189 min_h=min_h,
190 max_h=max_h,
191 )
192
193 # Initialize default parameters.
194 # ---------------------------------------
195
196 # This is an SPH scheme.
197 # Hardcoded this for now until we can switch flavours.
198 self._sph_flavour = "Minimal"
199
200 # Minimal SPH parameters
201 self._alpha_av = 0.8
202 self._beta_av = 3.0
203
204 # now set these parameters as dastgen attributes.
205 # This needs to be done in a careful way so that
206 # changes to parameters outside of the initializer
207 # propagate into the generated c++ files.
208 self.set_parameters()
209
210 # Construct particle properties
211 # --------------------------------
212
213 # Artificial viscosity scheme --------------------------------------------------
215 if self._hydro_dimensions == 3:
216 self.rot_v = peano4.dastgen2.Peano4DoubleArray("rot_v", "Dimensions")
217 else: # Curl is a scalar in lower dimensions
219 "rot_v"
220 ) # In 2D sims it only has 1 component (z)
224 self.data.add_attribute(self.balsara)
225 self.data.add_attribute(self.rot_v)
226 self.data.add_attribute(self.div_v)
227 self.data.add_attribute(self.v_sig_AV)
228 self.data.add_attribute(self.soundSpeed)
229
230 # Algorithm Steps ---------------------------------------------------------------
231 # actual list containing the algorithm steps
233 # actual list containing the algorithm steps for initialization
235 # the dict containing all possible algorithm steps
236 self.algorithm_steps_dict = get_algorithm_step_dict(self)
237
238 # Now store an independent instance of the algorithm steps in the object
239 # We need an independent instance for situations where we modify the
240 # algorithm steps later. For example when we are adding debugging or
241 # dependence checks for each algorithm step.
243 # same for initialization steps
245
247
248 return
249
250 def set_parameters(self):
251 """
252 This function translates "global" particle parameters which are
253 constant throughout the simulation (like CFL factor, minimal time step
254 size, viscosity parameters...) into dastgen attributes of the C++
255 particle class.
256 If you modify any of the attributes manually outside of the particle
257 initialisation, e.g. by invoking
258
259 ```
260 particle = SPHLeapfrogFixedSearchRadius(initial_time_step_size=ABC, ...)
261 particle.initial_time_step_size = XYZ
262 ```
263
264 you need to call this function manually so your changes propagate
265 into the generated C++ files.
266 """
267
268 super(SPHLeapfrogFixedSearchRadius, self).set_parameters()
269
270 const_static = dastgen2.attributes.Attribute.Qualifier.CONST_STATIC
271
272 alpha_av_attr = dastgen2.attributes.Double(
273 "alphaAV", qualifier=const_static, initval=self._alpha_av
274 )
275 self.data.add_or_replace_attribute(alpha_av_attr)
276
277 beta_av_attr = dastgen2.attributes.Double(
278 "betaAV", qualifier=const_static, initval=self._beta_av
279 )
280 self.data.add_or_replace_attribute(beta_av_attr)
281
282 return
283
285 """!
286 Set up the internal list of algorithm steps for this particle.
287 We need to maintain an individual instance of this list for cases
288 where we modify the algorithm steps later on. This can happen for
289 example when adding debugging/dependency checks later on.
290
291
292 The algorithm steps shall be a list of AlgorithmStep objects to be
293 executed in that order.
294
295 Definitions of the algorithm steps stored in the algorithm_steps_dict are
296 placed in get_algorithm_steps_dict(self). The dict is set up during
297 instantiation of this class, and reads in all available algorithm steps
298 defined in AlgorithmStepLibrary.py.
299
300 Leapfrog consists basically of four steps per particle. We first
301 determine the force. Then we update the velocity by half a timestep and move
302 the particle by a full timestep. Then the force is re-computed and the
303 second half of the velocity update is done.
304 Some variations of this KDK form re-arrange the steps executed per timestep
305 to avoid a second force loop. We can't do this here because we're not planning
306 on running with fixed time step sizes throughout the run.
307 """
308
309 steps = [
310 self.algorithm_steps_dict["SPH_Drift"],
311 self.algorithm_steps_dict["PredictHydro"],
312 self.algorithm_steps_dict["SPH_Density"],
313 self.algorithm_steps_dict["SPH_Force"],
314 self.algorithm_steps_dict["SPH_Kick2"],
315 self.algorithm_steps_dict["SPH_Timestep"],
316 self.algorithm_steps_dict["SPH_ReduceGlobalQuantities"],
317 self.algorithm_steps_dict["SPH_Kick1"],
318 ]
319
320 # make a copy of the steps, so if you modify them later (e.g. by
321 # adding dependency checks), it won't modify the steps in the dict.
322 self._algorithm_steps = [copy.deepcopy(i) for i in steps]
323 return
324
326 """!
327 Define the algorithm steps to be taken during initialization here.
328 This follows the same logic as _setup_algorithm_steps. See documentation
329 there for more info.
330
331 Make sure get_algorithm_steps_dict(self) has been called before.
332 """
333 initsteps = [
334 self.algorithm_steps_dict["SPH_FirstInitParticle"],
335 self.algorithm_steps_dict["SPH_Density"],
336 self.algorithm_steps_dict["SPH_Force"],
337 self.algorithm_steps_dict["SPH_Timestep"],
338 # TODO for later: Call kick2 here. When a new simulation step
339 # begins, all particles need to have been kicked. This is necessary
340 # for individual particle timestepping.
341 # The difference between kick1 and kick2 is that we reset some
342 # additional quantities at the end. Since this is the first
343 # time we're calling it, it needs to be kick2.
344 self.algorithm_steps_dict["SPH_Kick2"],
345 ]
346
347 # return deep copies of algorithms steps. Otherwise,
348 # modifications down the line (like the dependency checks)
349 # will cause trouble.
350 self._initialisation_steps = [copy.deepcopy(i) for i in initsteps]
351
352 return
353
354 @property
355 def alpha_av(self):
356 """
357
358 Viscosity parameters of the Minimal SPH model. Default SWIFT values are
359 alpha_av=0.8 and beta_av=3.
360
361 """
362 return self._alpha_av
363
364 @alpha_av.setter
365 def alpha_av(self, alpha_av):
366 if alpha_av <= 0:
367 raise ValueError("Value for the alpha_av viscosiy parameter not valid.")
368 self._alpha_av = alpha_av
369
370 @property
371 def beta_av(self):
372 return self._alpha_av
373
374 @beta_av.setter
375 def beta_av(self, beta_av):
376 if beta_av <= 0:
377 raise ValueError("Value for the beta_av viscosiy parameter not valid.")
378 self._beta_av = beta_av
379
381 """
382
383 Transform namespace into cpp format. Could be used to append namespace to
384 constants in kernels (not used currently).
385
386 """
387 namespace = "::".join(self._swift_project_namespace) + "::"
388
389 print(namespace)
390
391 @property
393 return (
394 super(SPHLeapfrogFixedSearchRadius, self).readme_descriptor
395 + """
396
397 Time integrator: SPH Leapfrog
398
399 - search radius: fixed
400 - CFL factor: """
401 + str(self._cfl_factor)
402 + """
403 - dt_initial: """
405 + """
406
407 """
408 )
cardinality is a string (you can thus use symbols as well as long as they will be defined at compile ...
Definition Double.py:6
Specialisation of array using Peano's tarch.
_add_dependency_checks(self)
Add dependency (particle consistency) checks.
Definition Particle.py:482
__init__(self, name, dimensions_hydro=2, cfl_factor=0.1, initial_time_step_size=1e-4, constant_time_step_size=True, swift_project_namespace="SPH", particles_per_cell=0, min_h=0.3, max_h=0.3)
_setup_initialisation_steps(self)
Define the algorithm steps to be taken during initialization here.
_setup_algorithm_steps(self)
Set up the internal list of algorithm steps for this particle.
set_parameters(self)
This function translates "global" particle parameters which are constant throughout the simulation (l...
The SPH particle base class.