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 marker,
120 assignedParticles,
121 numberOfCoalescedAssignedParticles,
122 [&](const peano4::datamanagement::VertexMarker& marker, globaldata::" " " + name + " " "& assignedParticle)->void {
123 ::swift2::boundaryconditions::applyFixedBoundaryCondition(
124 assignedParticle,
125 marker,
126 DomainOffset,
127 DomainSize,
128 0.1,
129 _spacetreeId
130 );
131 }
132 );
133 }
134 " " "
135 particle.algorithm_steps_dict["Drift"].includes += " " "
136 #include "swift2/boundaryconditions/FixedBoundary.h"
137 #include "swift2/boundaryconditions/Utils.h"
138 " " "
139 particle._setup_algorithm_steps()
140 particle._setup_initialisation_steps()
141 ~~~~~~~~~~~~~~~~~~~~~~
142
143 The spaced-out syntax is just there to ensure that the Python documentation
144 syntax is not broken.
145
146
147 ## Attributes
148
149 name: String
150 To be in line with other conventions, I recommend you start with an
151 uppercase letter. This has to be a valid C++ identifier, i.e. don't
152 use any special symbols besides an underscore.
153
154 ## Vectorisation
155
156 This type can be used with aggressively optimised kernels if you follow
157 @ref page_swift_performance_optimisation Performance optimisation and use
158 the map_particle_steps_onto_separate_mesh_traversals_insert_dummy_sweeps_for_coalesced_memory_access
159 graph compiler from the Sequential suite; or literally any other
160 flavour which yields coalesced memory.
161
162 @see peano4::datamanagement::CellMarker
163 @see peano4::datamanagement::VertexMarker
164
165 """
166
168 self,
169 name,
170 dimensions_hydro=2,
171 cfl_factor=0.1,
172 initial_time_step_size=1e-4,
173 constant_time_step_size=True,
174 swift_project_namespace="SPH",
175 particles_per_cell=0, # makes no sense, and should likely be forbidden
176 min_h=0.3,
177 max_h=0.3,
178 ):
179 super(SPHLeapfrogFixedSearchRadius, self).__init__(
180 name=name,
181 dimensions_hydro=dimensions_hydro,
182 cfl_factor=cfl_factor,
183 initial_time_step_size=initial_time_step_size,
184 constant_time_step_size=constant_time_step_size,
185 swift_project_namespace=swift_project_namespace,
186 particles_per_cell=particles_per_cell,
187 min_h=min_h,
188 max_h=max_h,
189 )
190
191 # Initialize default parameters.
192 # ---------------------------------------
193
194 # This is an SPH scheme.
195 # Hardcoded this for now until we can switch flavours.
197
198 # Minimal SPH parameters
199 self._alpha_av = 0.8
200 self._beta_av = 3.0
201
202 # now set these parameters as dastgen attributes.
203 # This needs to be done in a careful way so that
204 # changes to parameters outside of the initializer
205 # propagate into the generated c++ files.
207
208 # Construct particle properties
209 # --------------------------------
210
211 # Artificial viscosity scheme --------------------------------------------------
214 self.rot_v = peano4.dastgen2.Peano4DoubleArray("rot_v", "Dimensions")
215 else: # Curl is a scalar in lower dimensions
217 "rot_v"
218 ) # In 2D sims it only has 1 component (z)
222 self.data.add_attribute(self.balsara)
223 self.data.add_attribute(self.rot_v)
224 self.data.add_attribute(self.div_v)
225 self.data.add_attribute(self.v_sig_AV)
226 self.data.add_attribute(self.soundSpeed)
227
228 # Algorithm Steps ---------------------------------------------------------------
229 # actual list containing the algorithm steps
231 # actual list containing the algorithm steps for initialization
233 # the dict containing all possible algorithm steps
234 self.algorithm_steps_dict = get_algorithm_step_dict(self)
235
236 # Now store an independent instance of the algorithm steps in the object
237 # We need an independent instance for situations where we modify the
238 # algorithm steps later. For example when we are adding debugging or
239 # dependence checks for each algorithm step.
241 # same for initialization steps
243
245
246 return
247
248 def set_parameters(self):
249 """
250 This function translates "global" particle parameters which are
251 constant throughout the simulation (like CFL factor, minimal time step
252 size, viscosity parameters...) into dastgen attributes of the C++
253 particle class.
254 If you modify any of the attributes manually outside of the particle
255 initialisation, e.g. by invoking
256
257 ```
258 particle = SPHLeapfrogFixedSearchRadius(initial_time_step_size=ABC, ...)
259 particle.initial_time_step_size = XYZ
260 ```
261
262 you need to call this function manually so your changes propagate
263 into the generated C++ files.
264 """
265
266 super(SPHLeapfrogFixedSearchRadius, self).set_parameters()
267
268 const_static = dastgen2.attributes.Attribute.Qualifier.CONST_STATIC
269
270 alpha_av_attr = dastgen2.attributes.Double(
271 "alphaAV", qualifier=const_static, initval=self._alpha_av
272 )
273 self.data.add_or_replace_attribute(alpha_av_attr)
274
275 beta_av_attr = dastgen2.attributes.Double(
276 "betaAV", qualifier=const_static, initval=self._beta_av
277 )
278 self.data.add_or_replace_attribute(beta_av_attr)
279
280 return
281
283 """!
284 Set up the internal list of algorithm steps for this particle.
285 We need to maintain an individual instance of this list for cases
286 where we modify the algorithm steps later on. This can happen for
287 example when adding debugging/dependency checks later on.
288
289
290 The algorithm steps shall be a list of AlgorithmStep objects to be
291 executed in that order.
292
293 Definitions of the algorithm steps stored in the algorithm_steps_dict are
294 placed in get_algorithm_steps_dict(self). The dict is set up during
295 instantiation of this class, and reads in all available algorithm steps
296 defined in AlgorithmStepLibrary.py.
297
298 Leapfrog consists basically of four steps per particle. We first
299 determine the force. Then we update the velocity by half a timestep and move
300 the particle by a full timestep. Then the force is re-computed and the
301 second half of the velocity update is done.
302 Some variations of this KDK form re-arrange the steps executed per timestep
303 to avoid a second force loop. We can't do this here because we're not planning
304 on running with fixed time step sizes throughout the run.
305 """
306
307 steps = [
308 self.algorithm_steps_dict["SPH_Drift"],
309 self.algorithm_steps_dict["PredictHydro"],
310 self.algorithm_steps_dict["SPH_Density"],
311 self.algorithm_steps_dict["SPH_Force"],
312 self.algorithm_steps_dict["SPH_Kick2"],
313 self.algorithm_steps_dict["SPH_Timestep"],
314 self.algorithm_steps_dict["SPH_ReduceGlobalQuantities"],
315 self.algorithm_steps_dict["SPH_Kick1"],
316 ]
317
318 # make a copy of the steps, so if you modify them later (e.g. by
319 # adding dependency checks), it won't modify the steps in the dict.
320 self._algorithm_steps_algorithm_steps = [copy.deepcopy(i) for i in steps]
321 return
322
324 """!
325 Define the algorithm steps to be taken during initialization here.
326 This follows the same logic as _setup_algorithm_steps. See documentation
327 there for more info.
328
329 Make sure get_algorithm_steps_dict(self) has been called before.
330 """
331 initsteps = [
332 self.algorithm_steps_dict["SPH_FirstInitParticle"],
333 self.algorithm_steps_dict["SPH_Density"],
334 self.algorithm_steps_dict["SPH_Force"],
335 self.algorithm_steps_dict["SPH_Timestep"],
336 # TODO for later: Call kick2 here. When a new simulation step
337 # begins, all particles need to have been kicked. This is necessary
338 # for individual particle timestepping.
339 # The difference between kick1 and kick2 is that we reset some
340 # additional quantities at the end. Since this is the first
341 # time we're calling it, it needs to be kick2.
342 # self.algorithm_steps_dict["SPH_Kick2"],
343 ]
344
345 # return deep copies of algorithms steps. Otherwise,
346 # modifications down the line (like the dependency checks)
347 # will cause trouble.
348 self._initialisation_steps_initialisation_steps = [copy.deepcopy(i) for i in initsteps]
349
350 return
351
352 @property
353 def alpha_av(self):
354 """
355
356 Viscosity parameters of the Minimal SPH model. Default SWIFT values are
357 alpha_av=0.8 and beta_av=3.
358
359 """
360 return self._alpha_av
361
362 @alpha_av.setter
363 def alpha_av(self, alpha_av):
364 if alpha_av <= 0:
365 raise ValueError("Value for the alpha_av viscosiy parameter not valid.")
366 self._alpha_av = alpha_av
367
368 @property
369 def beta_av(self):
370 return self._alpha_av
371
372 @beta_av.setter
373 def beta_av(self, beta_av):
374 if beta_av <= 0:
375 raise ValueError("Value for the beta_av viscosiy parameter not valid.")
376 self._beta_av = beta_av
377
379 """
380
381 Transform namespace into cpp format. Could be used to append namespace to
382 constants in kernels (not used currently).
383
384 """
385 namespace = "::".join(self._swift_project_namespace) + "::"
386
387 print(namespace)
388
389 @property
391 return (
392 super(SPHLeapfrogFixedSearchRadius, self).readme_descriptor
393 + """
394
395 Time integrator: SPH Leapfrog
396
397 - search radius: fixed
398 - CFL factor: """
400 + """
401 - dt_initial: """
403 + """
404
405 """
406 )
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 dastgen2.attributes.DoubleArray which relies on 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)
Initialise the particle.
_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.
_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...