Peano
Loading...
Searching...
No Matches
UpdateParticle_SingleLevelInteraction.py
Go to the documentation of this file.
1# This file is part of the Peano project. For conditions of distribution and
2# use, please see the copyright notice at www.peano-framework.org
3from peano4.solversteps.ActionSet import ActionSet
4
5import jinja2
6
7
10 self,
11 particle_set,
12 particle_cell_update_kernel=None,
13 touch_vertex_first_time_compute_particle_update_kernel=None,
14 touch_vertex_last_time_compute_particle_update_kernel=None,
15 prepare_traversal_kernel="",
16 unprepare_traversal_kernel="",
17 additional_includes="",
18 active_particle_set=None,
19 ):
20 """!
21
22 Update particles on a single level
23
24 To be used if you want to update particles within their cell, while they
25 either
26
27 - do not interact at all; or
28 - interact only with particles on the same mesh level.
29
30 This code snippet creates a tree walker, i.e. an action set that runs
31 through the underlying spacetree top-down. Users can plug into what
32 happens per cell and what happens when we touch a set of particles for
33 the first and for the last time.
34
35 ## Per cell updates
36
37 Per tree node (cell) there are two different sets.
38 The set of local particles of a cell are all of the particles whose
39 centre is contained within the cell.
40 The set of active particles are all particles which are associated
41 with an adjacent vertex of the cell.
42 In line with @ref page_toolbox_particles_mesh_storage "Peano's particle storage scheme",
43 this effectively means that the active particles are those from the
44 cell plus its h/2 environment.
45
46 If the active_particle_set attribute is None, then
47 the active set and the local set are of the same type. They are
48 however not the same sets, as one contains only the particles held
49 within the cell.
50 You can set the active set to another species of particles
51 and thus couple two types of particles.
52
53 The local set is a strict subset of the active set per cell. The code has
54 not checked beforehand if its particles overlap with the current cell.
55
56
57 ## Per vertex updates
58
59 Besides the cell kernel which is there to realise per-cell updates,
60 we also have a vertex kernel which we call whenever a
61 vertex is loaded for the first time. That is, you can assume that the
62 vertex kernel has been launched for all 2^d vertices of a cell before
63 its cell kernel is triggered. The vertex kernel has access to a local
64 set: These sets contain all the particles
65 whose centre lies within the square/cube around the vertex with mesh size
66 2h. So this area goes h along each each coordinate axis into the
67 neighbouring cells. The vertex's local particles also have to reside
68 on the same resolution level.
69
70
71 ## Type of updates
72
73 - You can use this action set to realise particle updates without any
74 dependencies on other particles.
75 - You can use this action set to realise particle updates where the
76 particle depends on other particles which are stored on the same
77 level.
78
79 The following constraints apply:
80
81 - If you work with the local set within the cell, you are on the safe
82 side, though the association of particles to cells is not unique.
83 There is a tiny overlap between cells, i.e. particles on the face
84 between two cells might be associated to both cells. If you update
85 particles, you should employ a boolean flag to memorise if a particle
86 has been updated already or not.
87 - If you work with the local set within a vertex, this local set overlaps
88 with adjacent cells (see previous item), and it might even overlap with
89 a remote subdomain.
90 - If you change a particle position while the action set runs, you might
91 end up with inconsistent data view.
92
93
94 ## Validity if particles change their position of cut-off radius
95
96 This particular action set constructs its active and local sets totally
97 on-the-fly. It does not maintain any data while is marches through the
98 mesh. Consequently, it is robust w.r.t. particle position updates or
99 lift and drops and in general any resorting.
100
101
102 ## Arguments
103
104 @param particle_set: ParticleSet
105
106 @param particle_particle_interaction_kernel: String holding C++ code
107 This C++ code can access three different types of variables: There's
108 a list of particles called activeParticles, there's a list of particles
109 called localParticles, and there's the cell marker. See the guidebook
110 for further info. A typical kernel resembles
111
112 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
113 for (auto* localParticle: localParticles )
114 for (auto* activeParticle: activeParticles ) {
115 localParticle->doSomethingFancy( activeParticle );
116 }
117 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
118
119 @param active_particle_set: ParticleSet or None
120 You can compare different particles species with this argument. It
121 allows you to make the active particles stem from another species than
122 the local ones that you actually update. Pick None if both sets are of
123 the same type.
124
125 @param touch_vertex_first_time_compute_particle_update_kernel: String or None
126 Can be empty, but if you wanna move particles, then a minimal example
127 string passed equals
128
129 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
130 for (auto* localParticle: localParticles ) {
131 localParticle->setMoveState( globaldata::Particle::MoveState::NotMovedYet );
132 }
133 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134
135 i.e. you will have a variable localParticle available in this kernel
136 and it is a pointer. There is no notion of an active variable for
137 touch first or touch last.
138
139
140 """
141 super(UpdateParticle_SingleLevelInteraction, self).__init__(
142 descend_invocation_order=1, parallel=False
143 )
144
145 self._particle_set = particle_set
146 self.d = {}
147 self.d["LOCAL_PARTICLE"] = particle_set.particle_model.name
148 self.d["LOCAL_PARTICLES_CONTAINER"] = particle_set.name
149 if active_particle_set == None:
150 self.d["ACTIVE_PARTICLE"] = particle_set.particle_model.name
151 self.d["ACTIVE_PARTICLES_CONTAINER"] = particle_set.name
152 else:
153 self.d["ACTIVE_PARTICLE"] = active_particle_set.particle_model.name
154 self.d["ACTIVE_PARTICLES_CONTAINER"] = active_particle_set.name
155 self.d["PARTICLE_CELL_UPDATE_KERNEL"] = particle_cell_update_kernel
156 self.d[
157 "TOUCH_VERTEX_FIRST_COMPUTE_KERNEL"
158 ] = touch_vertex_first_time_compute_particle_update_kernel
159 self.d[
160 "TOUCH_VERTEX_LAST_COMPUTE_KERNEL"
161 ] = touch_vertex_last_time_compute_particle_update_kernel
162 self.d["ADDITIONAL_INCLUDES"] = additional_includes
163 self.d["PREPARE_TRAVERSAL_KERNEL"] = prepare_traversal_kernel
164 self.d["UNPREPARE_TRAVERSAL_KERNEL"] = unprepare_traversal_kernel
165
166 """!
167
168 The field numberOfCoalescedAssignedParticles is set to -1 to indicate that the
169 particles are not held in a continuous order.
170
171 Introducing this field makes all kernel signatures compatible with
172 UpdateParticle_SingleLevelInteraction_ContiguousParticles.
173
174 """
175 __Template_TouchVertexFirstTime = jinja2.Template(
176 """
177 {% if TOUCH_VERTEX_FIRST_COMPUTE_KERNEL!=None %}
178 auto& assignedParticles = fineGridVertex{{LOCAL_PARTICLES_CONTAINER}};
179 constexpr int numberOfCoalescedAssignedParticles = -1;
180
181 {{TOUCH_VERTEX_FIRST_COMPUTE_KERNEL}}
182 {% endif %}
183"""
184 )
185
186 """!
187
188 The field numberOfCoalescedAssignedParticles is set to -1 to indicate that the
189 particles are not held in a continuous order.
190
191 Introducing this field makes all kernel signatures compatible with
192 UpdateParticle_SingleLevelInteraction_ContiguousParticles.
193
194 """
195 __Template_TouchVertexLastTime = jinja2.Template(
196 """
197 {% if TOUCH_VERTEX_LAST_COMPUTE_KERNEL!=None %}
198 auto& assignedParticles = fineGridVertex{{LOCAL_PARTICLES_CONTAINER}};
199 constexpr int numberOfCoalescedAssignedParticles = -1;
200 {{TOUCH_VERTEX_LAST_COMPUTE_KERNEL}}
201 {% endif %}
202"""
203 )
204
205 __Template_TouchCellFirstTime = jinja2.Template(
206 """
207 {% if PARTICLE_CELL_UPDATE_KERNEL!=None %}
208 std::list< globaldata::{{LOCAL_PARTICLE}}* > localParticles;
209 std::list< globaldata::{{ACTIVE_PARTICLE}}* > _activeParticles;
210 std::vector< int > numberOfCoalescedLocalParticlesPerVertex( TwoPowerD );
211 std::vector< int > _numberOfActiveParticlesPerVertex( TwoPowerD ); // stay compatible with coalesced version
212 auto& numberOfCoalescedActiveParticlesPerVertex = _numberOfActiveParticlesPerVertex;
213 auto& activeParticles = _activeParticles;
214
215 for (int i=0; i<TwoPowerD; i++) {
216 numberOfCoalescedActiveParticlesPerVertex[i] = -1;
217 numberOfCoalescedLocalParticlesPerVertex[i] = -1;
218 for (auto* p: fineGridVertices{{ACTIVE_PARTICLES_CONTAINER}}(i) ) {
219 activeParticles.push_front( p );
220 }
221
222 for (auto* p: fineGridVertices{{LOCAL_PARTICLES_CONTAINER}}(i) ) {
223 localParticles.push_front( p );
224 }
225 }
226
227 {{PARTICLE_CELL_UPDATE_KERNEL}}
228 {% endif %}
229"""
230 )
231
232 def get_body_of_operation(self, operation_name):
233 result = "\n"
234 if operation_name == ActionSet.OPERATION_TOUCH_CELL_FIRST_TIME:
235 result = self.__Template_TouchCellFirstTime.render(**self.d)
236 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
237 result = self.__Template_TouchVertexFirstTime.render(**self.d)
238 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_LAST_TIME:
239 result = self.__Template_TouchVertexLastTime.render(**self.d)
240 return result
241
243 return " return std::vector< peano4::grid::GridControlEvent >();\n"
244
246 return self.d["PREPARE_TRAVERSAL_KERNEL"]
247
249 return self.d["UNPREPARE_TRAVERSAL_KERNEL"]
250
252 return __name__.replace(".py", "").replace(".", "_")
253
255 return False
256
257 def get_includes(self):
258 result = jinja2.Template(
259 """
260#include "toolbox/particles/particles.h"
261#include "vertexdata/{{LOCAL_PARTICLES_CONTAINER}}.h"
262#include "globaldata/{{LOCAL_PARTICLE}}.h"
263#include "vertexdata/{{ACTIVE_PARTICLES_CONTAINER}}.h"
264#include "globaldata/{{ACTIVE_PARTICLE}}.h"
265
266{{ADDITIONAL_INCLUDES}}
267
268#include <list>
269"""
270 )
271 return result.render(**self.d)
272
273 def get_attributes(self):
274 return """
275 int _spacetreeId;
276"""
277
279 return """
280 _spacetreeId = treeNumber;
281 """
Action set (reactions to events)
Definition ActionSet.py:6
get_body_of_operation(self, operation_name)
Return actual C++ code snippets to be inserted into C++ code.
__init__(self, particle_set, particle_cell_update_kernel=None, touch_vertex_first_time_compute_particle_update_kernel=None, touch_vertex_last_time_compute_particle_update_kernel=None, prepare_traversal_kernel="", unprepare_traversal_kernel="", additional_includes="", active_particle_set=None)
Update particles on a single level.