Peano
Loading...
Searching...
No Matches
UpdateParticleGridAssociation_Reassign.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
5
6from .AbstractUpdateParticleGridAssociation import AbstractUpdateParticleGridAssociation
7from .UpdateParticleGridAssociation_LiftDrop import (
8 UpdateParticleGridAssociation_LiftDrop,
9)
10
11import jinja2
12
13
15 """!
16
17 Associate particles to spacetree vertices
18
19 Sort particles into the respective levels and cells. This mapping should
20 be used every time you move particles around.
21
22 ## Algorithm
23
24 The re-association has different ingredients. We have two implementations
25 currently available. In this version, we try to minimise the particle
26 re-associations. For this, the algorithm realises the key checks within
27 the cells:
28
29 - Look at all the particles within a cell and check whether they are
30 still assigned to the closest of the @f$ 2^d @f$ vertices of this
31 cell. If not, reassign them.
32 - Identify particles that have moved by more than one mesh width since the
33 last update. If a particle travels fast, lift it to the next level. This
34 check happens recursively whenever we touch a cell for the last time.
35 - Drop particles down within the tree hierarchy such that they reside on
36 an as fine level as possible. This happens in touchVertexFirstTime(), i.e.
37 in-between two grid traversals, particles are distributed over all
38 resolutions, but we move them down in the hierarchy as kind of a preamble
39 of the subsequent grid sweep.
40
41 The persent code variant assumes that particles do not move after
42 touchVertexFirstTime(). So you can alter them in touchVertexFirstTime()
43 and then the code will sort them properly in this sweep, but if you change
44 their position again in touchCellLastTime() or touchVertexLastTime(), then
45 you will have an unsorted state by the end of the traversal.
46
47
48 ## Tunneling and horizontal data movements between trees
49
50 All cores run through their trees. On the finest mesh level, we have a
51 non-overlapping domain decomposition. Each cell has a unique owner tree.
52 On the coarser resolutions, the association is not unique anymore. We
53 make it unique, i.e. each cell on any level has a unique owner. The owners
54 (aka threads or ranks) run through their trees concurrently and exchange
55 their boundary data after the traversal. If particles are to be lifted, this
56 causes issues, as we cannot exchange them between two levels after the
57 traversal. We could, but then we can't lift them any further within the
58 first traversal, and we also cannot drop them into another rank at the
59 same time.
60
61 Therefore, I employ a mixture of the pidt technique from the paper and the
62 sieve approach also discussed there. Usually, I do all lifts and drops
63 right throughout the mesh traversal. If I'd lift into a cell/level which
64 is owned by another tree, I don't lift but instead dump the particle into
65 a rank-global list. These lists are then exchanged after each traversal
66 sweep. Drops now can either happen from the next coarser level or this
67 global list. I call the latter a sieve.
68
69 Due to this global list approach, I can support tunneling, i.e. particles
70 racing through multiple cells in one time step, and all of this works with
71 MPI, too.
72
73
74 ## Statistics
75
76 The mapping keeps some statistics on any state update. These statistics
77 however are not shared via MPI or synchronised between different threads.
78 It is the job of the ParticleSet to ensure that we have a proper global
79 bookkeeping.
80
81
82 ## Hanging vertices
83
84 Hanging vertices are assigned particles when they are created and their
85 particles are lifted again, when they are destroyed. You can disable to
86 drops in the constructor. This might reduce the number of overall drops.
87 However, you will always need the lift, as a cell might reassign a particle
88 to a hanging vertex at any time, and then this particle has to be lifted
89 before the vertex is destroyed.
90
91
92 ## Where and how to use
93
94 Within your algorithm step, this update action set should always be the
95 first or one of the first action sets before you add any other action set.
96 If you add it first, it ensures that the drop of particles is one of the
97 first things that happen, before any user code is triggered. As Peano
98 automatically inverts the action set order throughout the backtracking,
99 adding UpdateParticleGridAssociation as first action set ensures that the
100 lifts are basically the last thing you do. This is particular imporant if
101 your user code alters particle positions in touchVertexLastTime().
102
103 Your main code has to call finishedTraversal() on the tracer set after each
104 sweep on each rank. This important to roll those particles over that have
105 been sieved or have been lifted.
106
107 This action set has to be used in each and every grid traversal. In-between
108 time steps, it is idempotent if particles do not move or change their
109 search radius. However, as we have hanging vertices, it might move
110 particular up and down. So you have to insert it into each and every
111 mesh traversal.
112
113 If you disable drops, the action set becomes idempotent.
114
115
116 ## Interpolay with particle storage
117
118 This sorting scheme should not be used if you use a particle memory pool,
119 i.e. if you try to store particles continuously - unless you insert
120 explicit gather/resort steps. Read through the @ref toolbox_particles_memorypool "memory implications for any particle sorting".
121
122
123 ## Parameters
124
125 drop_into_hanging_vertices: Boolean
126
127 """
128
129 def __init__(self, particle_set, guard="true", drop_into_hanging_vertices=True):
130 super(UpdateParticleGridAssociation_Reassign, self).__init__(
131 particle_set, guard
132 )
133
134 self._drop_into_hanging_vertices = drop_into_hanging_vertices
135
136 _Template_Sieve = UpdateParticleGridAssociation_LiftDrop._Template_Sieve
137
138 """
139
140 @see toolbox::particles::updateContainedInAdjacentCellProperty()
141 @see toolbox::particles::getParticleReassociationInstructionWithinCellWithIntraCellReassignment()
142
143 """
144 __Template_ReassignAndLiftWithinCell = jinja2.Template(
145 """
146 // Start template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_Reassign.py
147
148 for (int i=0; i<TwoPowerD; i++) {
149 vertexdata::{{PARTICLES_CONTAINER}}::iterator p = fineGridVertices{{PARTICLES_CONTAINER}}(i).begin();
150 while ( p!=fineGridVertices{{PARTICLES_CONTAINER}}(i).end() ) {
151
152 toolbox::particles::ParticleReassociationInstruction instruction =
153 toolbox::particles::getParticleReassociationInstructionWithinCellWithIntraCellReassignment(
154 p, marker, i
155 );
156
157 #if PeanoDebug > 0
158 int partID = (*p)->getPartid();
159 #else
160 int partID = -1;
161 #endif
162
163 switch ( instruction ) {
164 case toolbox::particles::ParticleReassociationInstruction_Keep:
165 toolbox::particles::updateContainedInAdjacentCellProperty(
166 marker,
167 **p
168 );
169 p++;
170 break;
171 case toolbox::particles::ParticleReassociationInstruction_SieveGlobally:
172 logDebug( "touchVertexLastTime(...)", "particle " << (*p)->toString() << " has to be sieved globally. Current assocation=" << marker.toString() );
173 _numberOfLiftsIntoSieveSet++;
174 toolbox::particles::assignmentchecks::detachParticleFromVertex(
175 "{{PARTICLE}}",
176 (*p)->getX(),
177 partID,
178 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
179 marker.x(),
180 marker.h(),
181 _spacetreeId,
182 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
183 );
184 toolbox::particles::assignmentchecks::assignParticleToSieveSet(
185 "{{PARTICLE}}",
186 (*p)->getX(),
187 partID,
188 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
189 marker.x(),
190 marker.h(),
191 _spacetreeId,
192 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
193 );
194 p = fineGridVertex{{PARTICLES_CONTAINER}}.particleCanNotBeLiftedLocally(p);
195 break;
196 case 0:
197 case 1:
198 case 2:
199 case 3:
200 #if Dimensions==3
201 case 4:
202 case 5:
203 case 6:
204 case 7:
205 #endif
206 p = fineGridVertices{{PARTICLES_CONTAINER}}(instruction).move(p,fineGridVertices{{PARTICLES_CONTAINER}}(i));
207 tarch::la::Vector<Dimensions, double> newVertexPosition =
208 marker.x()
209 -
210 tarch::la::multiplyComponents(
211 tarch::la::convertScalar<double>(marker.getRelativePositionWithinFatherCell()),
212 marker.h()
213 )
214 +
215 tarch::la::multiplyComponents(
216 tarch::la::Vector<Dimensions,double>(target),
217 3.0*marker.h()
218 );
219 toolbox::particles::updateContainedInAdjacentCellProperty(newVertexPosition, marker.h()*3.0, *p );
220
221 toolbox::particles::assignmentchecks::detachParticleFromVertex(
222 "{{PARTICLE}}",
223 p->getX(),
224 partID,
225 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
226 marker.x(),
227 marker.h(),
228 _spacetreeId,
229 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
230 );
231 toolbox::particles::assignmentchecks::assignParticleToVertex(
232 "{{PARTICLE}}",
233 (*p)->getX(),
234 partID,
235 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
236 newVertexPosition,
237 3.0*marker.h(),
238 _spacetreeId,
239 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell",
240 marker.x(),
241 marker.h()
242 );
243 _numberOfParticleReassignmentsOnCurrentLevel++;
244 break;
245 case 0+TwoPowerD:
246 case 1+TwoPowerD:
247 case 2+TwoPowerD:
248 case 3+TwoPowerD:
249 #if Dimensions==3
250 case 4+TwoPowerD:
251 case 5+TwoPowerD:
252 case 6+TwoPowerD:
253 case 7+TwoPowerD:
254 #endif
255 (*p)->setCellH(3.0 * marker.h());
256 tarch::la::Vector<Dimensions, double> newVertexX =
257 marker.x()
258 -
259 tarch::la::multiplyComponents(
260 tarch::la::convertScalar<double>(marker.getRelativePositionWithinFatherCell()),
261 marker.h()
262 )
263 +
264 tarch::la::multiplyComponents(
265 tarch::la::Vector<Dimensions,double>( std::bitset<Dimensions>(instruction) ),
266 3.0*marker.h()
267 );
268 toolbox::particles::updateContainedInAdjacentCellProperty(newVertexX, marker.h()*3.0, *p );
269
270 toolbox::particles::assignmentchecks::detachParticleFromVertex(
271 "{{PARTICLE}}",
272 p->getX(),
273 partID,
274 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
275 marker.x(),
276 marker.h(),
277 _spacetreeId,
278 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
279 );
280 toolbox::particles::assignmentchecks::assignParticleToVertex(
281 "{{PARTICLE}}",
282 (*p)->getX(),
283 partID,
284 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
285 newVertexX,
286 3.0*marker.h(),
287 _spacetreeId,
288 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell",
289 marker.x(),
290 marker.h()
291 );
292 coarseGridVertices{{PARTICLES_CONTAINER}}(instruction-TwoPowerD).push_back(*p);
293 p = fineGridVertices{{PARTICLES_CONTAINER}}(i).erase(p);
294 _numberOfLifts ++;
295 break;
296 default:
297 assertionMsg( false, "value not implemented" );
298 break;
299 }
300 }
301 }
302
303 // End template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_Reassign.py]
304"""
305 )
306
307 def get_body_of_operation(self, operation_name):
308 """
309
310 Core algorithm. See class description.
311
312 """
313 result = "\n"
314 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
315 result = self._Template_BeginTraversal.render(**self.d)
316 if (
318 and operation_name == ActionSet.OPERATION_CREATE_HANGING_VERTEX
319 ):
320 result = self._Template_Drop.render(**self.d)
321 result += self._Template_Sieve.render(**self.d)
322 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
323 result = self.__Template_Drop.render(**self.d)
324 result += self.__Template_Sieve.render(**self.d)
325 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_LAST_TIME:
326 result = self.__Template_ValidateParticleLevelAssociation.render(**self.d)
327 if operation_name == ActionSet.OPERATION_TOUCH_CELL_LAST_TIME:
328 result = self.__Template_ReassignAndLiftWithinCell.render(**self.d)
329 if operation_name == ActionSet.OPERATION_DESTROY_PERSISTENT_VERTEX:
330 result = self._Template_LiftAllParticles.render(**self.d)
331 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
332 result = self._Template_EndTraversal.render(**self.d)
333 return result
334
336 return __name__.replace(".py", "").replace(".", "_")
Action set (reactions to events)
Definition ActionSet.py:6