6from .AbstractUpdateParticleGridAssociation
import AbstractUpdateParticleGridAssociation
7from .UpdateParticleGridAssociation_LiftDrop
import (
8 UpdateParticleGridAssociation_LiftDrop,
17 Associate particles to spacetree vertices
19 Sort particles into the respective levels and cells. This mapping should
20 be used every time you move particles around.
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
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.
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.
48 ## Tunneling and horizontal data movements between trees
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
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.
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
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
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.
92 ## Where and how to use
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().
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.
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
113 If you disable drops, the action set becomes idempotent.
116 ## Interpolay with particle storage
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".
125 drop_into_hanging_vertices: Boolean
129 def __init__(self, particle_set, guard="true", drop_into_hanging_vertices=True):
130 super(UpdateParticleGridAssociation_Reassign, self).
__init__(
136 _Template_Sieve = UpdateParticleGridAssociation_LiftDrop._Template_Sieve
140 @see toolbox::particles::updateContainedInAdjacentCellProperty()
141 @see toolbox::particles::getParticleReassociationInstructionWithinCellWithIntraCellReassignment()
144 __Template_ReassignAndLiftWithinCell = jinja2.Template(
146 // Start template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_Reassign.py
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() ) {
152 toolbox::particles::ParticleReassociationInstruction instruction =
153 toolbox::particles::getParticleReassociationInstructionWithinCellWithIntraCellReassignment(
158 int partID = (*p)->getPartid();
163 switch ( instruction ) {
164 case toolbox::particles::ParticleReassociationInstruction_Keep:
165 toolbox::particles::updateContainedInAdjacentCellProperty(
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(
178 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
182 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
184 toolbox::particles::assignmentchecks::assignParticleToSieveSet(
188 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
192 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
194 p = fineGridVertex{{PARTICLES_CONTAINER}}.particleCanNotBeLiftedLocally(p);
206 p = fineGridVertices{{PARTICLES_CONTAINER}}(instruction).move(p,fineGridVertices{{PARTICLES_CONTAINER}}(i));
207 tarch::la::Vector<Dimensions, double> newVertexPosition =
210 tarch::la::multiplyComponents(
211 tarch::la::convertScalar<double>(marker.getRelativePositionWithinFatherCell()),
215 tarch::la::multiplyComponents(
216 tarch::la::Vector<Dimensions,double>(target),
219 toolbox::particles::updateContainedInAdjacentCellProperty(newVertexPosition, marker.h()*3.0, *p );
221 toolbox::particles::assignmentchecks::detachParticleFromVertex(
225 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
229 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
231 toolbox::particles::assignmentchecks::assignParticleToVertex(
235 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
239 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell",
243 _numberOfParticleReassignmentsOnCurrentLevel++;
255 (*p)->setCellH(3.0 * marker.h());
256 tarch::la::Vector<Dimensions, double> newVertexX =
259 tarch::la::multiplyComponents(
260 tarch::la::convertScalar<double>(marker.getRelativePositionWithinFatherCell()),
264 tarch::la::multiplyComponents(
265 tarch::la::Vector<Dimensions,double>( std::bitset<Dimensions>(instruction) ),
268 toolbox::particles::updateContainedInAdjacentCellProperty(newVertexX, marker.h()*3.0, *p );
270 toolbox::particles::assignmentchecks::detachParticleFromVertex(
274 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
278 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell"
280 toolbox::particles::assignmentchecks::assignParticleToVertex(
284 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
288 "UpdateParticleGridAssociation_Reassign::__Template_ReassignAndLiftWithinCell",
292 coarseGridVertices{{PARTICLES_CONTAINER}}(instruction-TwoPowerD).push_back(*p);
293 p = fineGridVertices{{PARTICLES_CONTAINER}}(i).erase(p);
297 assertionMsg( false, "value not implemented" );
303 // End template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_Reassign.py]
310 Core algorithm. See class description.
314 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
318 and operation_name == ActionSet.OPERATION_CREATE_HANGING_VERTEX
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:
329 if operation_name == ActionSet.OPERATION_DESTROY_PERSISTENT_VERTEX:
331 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
336 return __name__.replace(
".py",
"").replace(
".",
"_")
Action set (reactions to events)
Associate particles to spacetree vertices.
_Template_LiftAllParticles
Associate particles to spacetree vertices.
_drop_into_hanging_vertices
get_action_set_name(self)
Return unique action set name.
__Template_ReassignAndLiftWithinCell
get_body_of_operation(self, operation_name)
Core algorithm.
__init__(self, particle_set, guard="true", drop_into_hanging_vertices=True)