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.
95 #todo this might be wrong
97 You will always needs to instances of this action set in a row, as the first
98 one might lift particles and put them into a sieve list. After that, the
99 subsequent grid sweep will drop the particles and sieve them in again. As
100 long as particles do not move, this variant becomes idempotent after two
106 Hanging vertices do never hold information and therefore are never assigned
110 ## Interpolay with particle storage
112 This sorting scheme should not be used if you use a particle memory pool,
113 i.e. if you try to store particles continuously - unless you insert
114 explicit gather/resort steps. Read through the @ref toolbox_particles_memorypool "memory implications for any particle sorting".
120 super(UpdateParticleGridAssociation_LiftDrop, self).
__init__(
124 _Template_Sieve = jinja2.Template(
126 // template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_LiftDrop.py
128 if ( vertexdata::{{PARTICLES_CONTAINER}}::hasParticlesToBeSievedIntoVertices() ) {
129 auto sievedParticles = vertexdata::{{PARTICLES_CONTAINER}}::getParticlesToBeSievedIntoVertex(
133 for (auto& newParticle: sievedParticles) {
134 _numberOfDropsFromSieveSet++;
135 fineGridVertex{{PARTICLES_CONTAINER}}.mergeWithParticle( newParticle, marker, _spacetreeId);
138 assertion1( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString() );
147 Takes those particles which are not within h/2 reach of a vertex and lift those.
149 This code snippet is used with touchVertexLastTime(). Therefore, the marker
152 @see toolbox::particles::updateContainedInAdjacentCellProperty()
155 __Template_LiftOrReassignParticles = jinja2.Template(
157 // template in python/peano4/toolbox/particles/api/UpdateParticleGridAssociation_LiftDrop.py
159 auto p = fineGridVertex{{PARTICLES_CONTAINER}}.begin();
160 while (p!=fineGridVertex{{PARTICLES_CONTAINER}}.end()) {
162 toolbox::particles::ParticleReassociationInstruction instruction = toolbox::particles::liftParticleAssociatedWithVertex(**p, marker);
165 int partID = (*p)->getPartid();
169 switch ( instruction ) {
170 case toolbox::particles::ParticleReassociationInstruction_Keep:
171 toolbox::particles::updateContainedInAdjacentCellProperty(
177 case toolbox::particles::ParticleReassociationInstruction_SieveGlobally:
178 _numberOfLiftsIntoSieveSet++;
179 logDebug( "touchVertexLastTime(...)", "have to lift particle " << (*p)->toString() << " on tree " << _spacetreeId << " globally. Previously assigned to " << marker.toString() );
181 toolbox::particles::assignmentchecks::detachParticleFromVertex(
185 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
189 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
191 toolbox::particles::assignmentchecks::assignParticleToSieveSet(
195 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
199 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
202 p = fineGridVertex{{PARTICLES_CONTAINER}}.particleCanNotBeLiftedLocally(p);
203 assertion1( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString() );
216 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() );
217 (*p)->setCellH(3.0 * marker.h());
218 toolbox::particles::updateContainedInAdjacentCellProperty(
219 peano4::datamanagement::reconstructXOfParentVertex(marker, instruction),
223 toolbox::particles::assignmentchecks::detachParticleFromVertex(
227 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
231 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles"
233 toolbox::particles::assignmentchecks::assignParticleToVertex(
237 (*p)->getParallelState()==globaldata::{{PARTICLE}}::ParallelState::Local,
238 peano4::datamanagement::reconstructXOfParentVertex(marker, instruction),
241 "UpdateParticleGridAssociation_LiftDrop::__Template_LiftOrReassignParticles",
245 p = coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).grabParticle( p, fineGridVertex{{PARTICLES_CONTAINER}} );
246 assertion2( fineGridVertex{{PARTICLES_CONTAINER}}.isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString(), coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).toString() );
247 assertion2( coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).isValid(), fineGridVertex{{PARTICLES_CONTAINER}}.toString(), coarseGridVertices{{PARTICLES_CONTAINER}}( instruction ).toString() );
250 assertionMsg( false, "value not implemented" );
262 Core algorithm. See class description.
266 if operation_name == ActionSet.OPERATION_BEGIN_TRAVERSAL:
268 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_FIRST_TIME:
271 if operation_name == ActionSet.OPERATION_TOUCH_VERTEX_LAST_TIME:
273 if operation_name == ActionSet.OPERATION_DESTROY_PERSISTENT_VERTEX:
275 if operation_name == ActionSet.OPERATION_END_TRAVERSAL:
280 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")