9from .AbstractUpdateParticleGridAssociation
import AbstractUpdateParticleGridAssociation
15 Associate particles to spacetree vertices
17 Sort particles into the respective levels and cells. This mapping should
18 be used every time you move particles around.
23 The re-association has different ingredients. We have two implementations
24 currently available. The present version does not touch any particle within
25 the cell events. It realises the following steps/checks:
27 - If I touch a vertex for the last time, I check if its particles are
28 within h/2 Manhattan distance. If not, I lift them to the next coarser
30 - Drop particles down within the tree hierarchy such that they reside on
31 an as fine level as possible. This happens in touchVertexFirstTime(), i.e.
32 in-between two grid traversals, particles are distributed over all
33 resolutions, but we move them down in the hierarchy as kind of a preamble
34 of the subsequent grid sweep.
36 This variant is algorithmically simpler than other ones, but it moves particles
37 around more often: If a particle moves closer to another vertex than the
38 one it is currently associated, we do not directly reassign it to a new
39 vertex. Instead, we move it one level up within the tree. Just before the
40 subsequent grid sweep, I sieve the particles all down again. So the move
41 from one vertex to the next is realised via a move through the next coarser
42 level. The first variant does not move particles up and down that often, but
43 it checks particles more often, as each particle is checked from up to 2^d
44 adjacent cells. So it is not clear which variant is superior.
47 ## Tunneling and horizontal data movements between trees
49 All cores run through their trees. On the finest mesh level, we have a
50 non-overlapping domain decomposition. Each cell has a unique owner tree.
51 On the coarser resolutions, the association is not unique anymore. We
52 make it unique, i.e. each cell on any level has a unique owner. The owners
53 (aka threads or ranks) run through their trees concurrently and exchange
54 their boundary data after the traversal. If particles are to be lifted, this
55 causes issues, as we cannot exchange them between two levels after the
56 traversal. We could, but then we can't lift them any further within the
57 first traversal, and we also cannot drop them into another rank at the
60 Therefore, I employ a mixture of the pidt technique from the paper and the
61 sieve approach also discussed there. Usually, I do all lifts and drops
62 right throughout the mesh traversal. If I'd lift into a cell/level which
63 is owned by another tree, I don't lift but instead dump the particle into
64 a rank-global list. These lists are then exchanged after each traversal
65 sweep. Drops now can either happen from the next coarser level or this
66 global list. I call the latter a sieve.
68 Due to this global list approach, I can support tunneling, i.e. particles
69 racing through multiple cells in one time step, and all of this works with
75 The mapping keeps some statistics on any state update. These statistics
76 however are not shared via MPI or synchronised between different threads.
77 It is the job of the ParticleSet to ensure that we have a proper global
81 ## Where and how to use
83 Within your algorithm step, this update action set should always be the
84 first or one of the first action sets before you add any other action set.
85 If you add it first, it ensures that the drop of particles is one of the
86 first things that happen, before any user code is triggered. As Peano
87 automatically inverts the action set order throughout the backtracking,
88 adding UpdateParticleGridAssociation as first action set ensures that the
89 lifts are basically the last thing you do. This is particular imporant if
90 your user code alters particle positions in touchVertexLastTime().
92 Your main code has to call finishedTraversal() on the tracer set after each
93 sweep on each rank. This important to roll those particles over that have
94 been sieved or have been lifted.
96 You will always needs to instances of this action set in a row, as the first
97 one might lift particles and put them into a sieve list. After that, the
98 subsequent grid sweep will drop the particles and sieve them in again. As
99 long as particles do not move, this variant becomes idempotent after two
105 Hanging vertices do never hold information and therefore are never assigned
109 ## Interpolay with particle storage
111 This sorting scheme should not be used if you use a particle memory pool,
112 i.e. if you try to store particles continuously - unless you insert
113 explicit gather/resort steps. Read through the @ref toolbox_particles_memorypool "memory implications for any particle sorting".
119 super(UpdateParticleGridAssociation_LiftDrop, self).
__init__(
123 _Template_Sieve = jinja2.Template(
125 // template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_LiftDrop.py
127 if ( vertexdata::{{PARTICLES_CONTAINER}}::hasParticlesToBeSievedIntoVertices() ) {
128 auto sievedParticles = vertexdata::{{PARTICLES_CONTAINER}}::getParticlesToBeSievedIntoVertex(
132 for (auto& newParticle: sievedParticles) {
133 _numberOfDropsFromSieveSet++;
134 fineGridVertex{{PARTICLES_CONTAINER}}.mergeWithParticle( newParticle, marker, _spacetreeId);
137 assertion1( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString() );
146 Takes those particles which are not within h/2 reach of a vertex and lift those.
148 This code snippet is used with touchVertexLastTime(). Therefore, the marker
151 @see toolbox::particles::updateContainedInAdjacentCellProperty()
154 __Template_LiftOrReassignParticles = jinja2.Template(
156 // template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_LiftDrop.py
158 auto p = fineGridVertex{{PARTICLES_CONTAINER}}.begin();
159 while (p!=fineGridVertex{{PARTICLES_CONTAINER}}.end()) {
161 toolbox::particles::ParticleReassociationInstruction instruction = toolbox::particles::liftParticleAssociatedWithVertex(**p, marker);
164 int partID = (*p)->getPartid();
168 switch ( instruction ) {
169 case toolbox::particles::ParticleReassociationInstruction_Keep:
170 toolbox::particles::updateContainedInAdjacentCellProperty(
176 case toolbox::particles::ParticleReassociationInstruction_SieveGlobally:
177 _numberOfLiftsIntoSieveSet++;
178 logDebug( "touchVertexLastTime(...)", "have to lift particle " << (*p)->toString() << " on tree " << _spacetreeId << " globally. Previously assigned to " << marker.toString() );
180 toolbox::particles::assignmentchecks::detachParticleFromVertex(
184 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
188 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
190 toolbox::particles::assignmentchecks::assignParticleToSieveSet(
194 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
198 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
201 p = fineGridVertex{{PARTICLES_CONTAINER}}.particleCanNotBeLiftedLocally(p);
202 assertion1( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString() );
215 logDebug( "touchVertexLastTime(...)", "have to lift particle " << (*p)->toString() << " to next coarser vertex " << instruction << ". Previously assigned to " << marker.toString() << ". Now lifted to " << coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).toString() );
216 (*p)->setCellH(3.0 * marker.h());
217 toolbox::particles::updateContainedInAdjacentCellProperty(
218 peano4::datamanagement::reconstructXOfParentVertex(marker, instruction),
222 toolbox::particles::assignmentchecks::detachParticleFromVertex(
226 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
230 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
232 toolbox::particles::assignmentchecks::assignParticleToVertex(
236 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
237 peano4::datamanagement::reconstructXOfParentVertex(marker, instruction),
240 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles",
244 p = coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).grabParticle( p, fineGridVertex{{PARTICLES_CONTAINER}} );
245 assertion2( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString(), coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).toString() );
246 assertion2( coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString(), coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).toString() );
249 assertionMsg( false, "value not implemented" );
261 Core algorithm. See class description.
265 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
267 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
270 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_LAST_TIME:
272 if operation_name == ActionSet.OPERATION_DESTROY_PERSISTENT_VERTEX:
274 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
279 return __name__.replace(
".py",
"").replace(
".",
"_")
Action set (reactions to events)
Associate particles to spacetree vertices.
_Template_LiftAllParticles
Associate particles to spacetree vertices.
get_action_set_name(self)
Return unique action set name.
__Template_LiftOrReassignParticles
get_body_of_operation(self, operation_name)
Core algorithm.
__init__(self, particle_set, guard="true")