Peano
Loading...
Searching...
No Matches
swift2::kernels Namespace Reference

Namespaces

namespace  gravity
 
namespace  internal
 
namespace  kernelrealisation
 Different (generic) kernel realisations.
 
namespace  legacy
 Legacy SPH implementation.
 

Concepts

concept  ParticleUnaryOperatorOnVertex
 Definition of particle update (unary operation)
 
concept  ParticleUnaryOperatorOnCell
 
concept  ParticleBinaryOperator
 Definition of particle-particle interaction.
 

Typedefs

template<typename ParticleContainer >
using PCParticle = typename std::remove_pointer<typename ParticleContainer::value_type>::type
 
template<typename Particle >
using UpdateParticlePairWithinCellPredicate
 
template<typename Particle >
using UpdateParticleAssignedToCellPredicate
 
template<typename Particle >
using UpdateParticleAssignedToVertexPredicate
 

Functions

template<typename ParticleA , typename ParticleB = ParticleA>
bool forceKernelDistanceCheck (ParticleA &__restrict__ localParticle, const ParticleB &__restrict__ activeParticle)
 
template<typename Particle >
void adoptInteractionRadiusAndTriggerRerun (const std::list< Particle * > &localParticles, const std::list< Particle * > &activeParticles, int targetNumberOfNeighbourParticles, double maxGrowthPerSweep=2.0, double shrinkingFactor=0.8)
 This routine runs over all the local particles and tries to ensure that the number of particles equals roughly targetNumberOfNeighbourParticles.
 
template<typename ParticleContainer >
void flagBoundaryParticles (const ParticleContainer &localParticles, const double nparts)
 Flag boundary particles.
 
template<typename ParticleContainer >
void flagBoundaryParticles (const ParticleContainer &localParticles, const double nparts, const tarch::la::Vector< Dimensions, double > &domainSize, const tarch::la::Vector< Dimensions, double > &domainOffset)
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::VertexMarker &marker, auto &assignedParticles, int numberOfCoalescedAssignedParticles, ::swift2::kernels::kernelrealisation::GenericRealisation realisation)
 Run over all particles and update them independent of each other.
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::VertexMarker &marker, auto &assignedParticles, int numberOfCoalescedAssignedParticles, ::swift2::kernels::kernelrealisation::GenericOffloadRealisation)
 Exactly the same version as the generic variant, but we use the offload attribute.
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::GenericRealisation realisation)
 Run over all local particle-active particle combinations.
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::GenericOffloadRealisation)
 Exactly the same version as the generic variant, but with an additional offload annotation.
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::VertexMarker &marker, auto &assignedParticles, int numberOfAssignedParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryRealisation realisation)
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::CellMarker &marker, auto &localParticles, const std::vector< int > &numberOfLocalParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryRealisation realisation)
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::VertexMarker &marker, auto &assignedParticles, int numberOfAssignedParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryOffloadRealisation realisation)
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::CellMarker &marker, auto &localParticles, const std::vector< int > &numberOfLocalParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryOffloadRealisation realisation)
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryActiveLocalRealisation realisation)
 Alternative implementation of CoalescedMemoryActiveLocalRealisation.
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryActiveLocalOffloadRealisation realisation)
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueActiveLocalRealisation realisation)
 
template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueLocalActiveRealisation realisation)
 
template<auto ParticlePairOp, auto LocalPredicateOp, auto ParticlePairPredicateOp>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryLocalActiveRealisation realisation)
 
template<auto ParticlePairOp, auto LocalPredicateOp, auto ParticlePairPredicateOp>
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::CoalescedMemoryLocalActiveOffloadRealisation realisation)
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::VertexMarker &marker, auto &assignedParticles, int numberOfCoalescedAssignedParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueRealisation)
 We split up the loop into two loops: The first one runs over the predicates and collects all the results in one large bit field.
 
template<auto ParticleOp, auto PredicateOp>
void forAllParticles (const peano4::datamanagement::CellMarker &marker, auto &localParticles, const std::vector< int > &numberOfCoalescedLocalParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueRealisation)
 
template<typename LocalParticleContainer , typename ActiveParticleContainer >
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueActiveLocalRealisation realisation)
 Move all the predicate evaluations into dedicated prologue.
 
template<typename LocalParticleContainer , typename ActiveParticleContainer >
void forAllParticlePairs (const swift2::CellMetaData &cellMetaData, auto &localParticles, auto &activeParticles, ::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueLocalActiveRealisation realisation)
 
template<typename Particle >
bool alwaysUpdateInVertexKernel (const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
 Degenerated predicate which always allows for an update.
 
template<typename Particle >
bool alwaysUpdateInCellKernel (const peano4::datamanagement::CellMarker &marker, const bool &localParticleIsContainedInCell, const Particle &localParticle)
 Degenerated update in cell predicate.
 
template<typename ParticleA , typename ParticleB = ParticleA>
bool alwaysUpdateParticlePairs (const peano4::datamanagement::CellMarker &marker, const ParticleA &localParticle, const ParticleB &activeParticle)
 Degenerated update in cell predicate.
 
template<typename Particle >
bool particleIsLocal (const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
 Is a particle local.
 
template<typename Particle >
bool localParticleCanBeUpdatedAndMovedInVertexKernel (const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
 Can we move (drift) this particle?
 
template<typename ParticleA , typename ParticleB = ParticleA>
bool localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle (const peano4::datamanagement::CellMarker &marker, const ParticleA &localParticle, const ParticleB &activeParticle)
 Can we do work on this particle during a cell kernel sweep stage?
 
template<typename ParticleA , typename ParticleB = ParticleA>
bool updateFromAnyOtherParticle (const peano4::datamanagement::CellMarker &marker, const ParticleA &localParticle, const ParticleB &activeParticle)
 
template<typename ParticleA , typename ParticleB = ParticleA>
bool localParticleCanBeUpdatedInCellKernelFromAnyOtherParticleWithinIterationRange (const peano4::datamanagement::CellMarker &marker, const ParticleA &localParticle, const ParticleB &activeParticle)
 
template<typename Particle >
bool localParticleCanBeUpdatedInCellKernel (const peano4::datamanagement::CellMarker &marker, const bool &localParticleIsContainedInCell, const Particle &localParticle)
 
template<typename Particle >
bool localParticleCanBeUpdatedInVertexKernel (const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
 Can we do work on this particle during a vertex kernel sweep stage?
 

Typedef Documentation

◆ PCParticle

template<typename ParticleContainer >
using swift2::kernels::PCParticle = typename std::remove_pointer<typename ParticleContainer::value_type>::type

Definition at line 17 of file ParticleSetIterators.h.

◆ UpdateParticleAssignedToCellPredicate

template<typename Particle >
using swift2::kernels::UpdateParticleAssignedToCellPredicate
Initial value:
std::function<bool(
const bool& localParticleIsContainedInCell,
const Particle& localParticle
)>

Definition at line 17 of file ParticleUpdatePredicates.h.

◆ UpdateParticleAssignedToVertexPredicate

Initial value:
std::function<bool(
const Particle& localParticle
)>
Vertex marker to provide information about selected vertex.

Definition at line 24 of file ParticleUpdatePredicates.h.

◆ UpdateParticlePairWithinCellPredicate

template<typename Particle >
using swift2::kernels::UpdateParticlePairWithinCellPredicate
Initial value:
std::function<bool(
const Particle& localParticle,
const Particle& activeParticle
)>

Definition at line 10 of file ParticleUpdatePredicates.h.

Function Documentation

◆ adoptInteractionRadiusAndTriggerRerun()

template<typename Particle >
void swift2::kernels::adoptInteractionRadiusAndTriggerRerun ( const std::list< Particle * > & localParticles,
const std::list< Particle * > & activeParticles,
int targetNumberOfNeighbourParticles,
double maxGrowthPerSweep = 2.0,
double shrinkingFactor = 0.8 )

This routine runs over all the local particles and tries to ensure that the number of particles equals roughly targetNumberOfNeighbourParticles.

The algorithm is fairly simple:

  • Find out how many other particles are currently within the search radius.
  • If this number is bigger than the target value, decrease the search radius slightly. Count again. If we are still above the target value, accept the slightly reduced search. Otherwise, undo the alteration.
  • If the number of interaction partners is too small, increase it and study the effect:
    • If we meet the target neighbour count now, we are happy.
    • If we have increased the number of neighbours but are not there yet, we keep this increase, but ask Peano/Swift to run this analysis again.
    • If the increase has not paid off, we keep the old search radius. It means that likely the interaction radii overall all are too small or the particle density is just not there.

The reduction starts from the assumption that we should be careful with reducing the search radii. So we only slightly decrease the search radius. If we could have reduced it more aggressively, we accept that and hope that subsequent time steps or sweeps will eventually bring the search radius down. But we do not enforce it here, which might mean that we work with too big interaction sets.

The increase is different: If we

If an interaction radius has to be increased, the code sets the flag setRerunPreviousGridSweep() on the underlying particle species.

In prin

◆ alwaysUpdateInCellKernel()

template<typename Particle >
bool swift2::kernels::alwaysUpdateInCellKernel ( const peano4::datamanagement::CellMarker & marker,
const bool & localParticleIsContainedInCell,
const Particle & localParticle )

Degenerated update in cell predicate.

See comment on alwaysUpdateInVertexKernel(), which also holds for this predicate.

Definition at line 55 of file ParticleUpdatePredicates.h.

◆ alwaysUpdateInVertexKernel()

template<typename Particle >
bool swift2::kernels::alwaysUpdateInVertexKernel ( const peano4::datamanagement::VertexMarker & marker,
const Particle & localParticle )

Degenerated predicate which always allows for an update.

This predicate is a prototype of what predicated look like. It rarely is used directly as it is. Typically, you have a kernel called ABC and then you write ABCUpdateParticlePredicate() with the same signature as alwaysUpdateInVertexKernel() aka UpdateParticleAssignedToVertexPredicate().

Definition at line 40 of file ParticleUpdatePredicates.h.

◆ alwaysUpdateParticlePairs()

template<typename ParticleA , typename ParticleB = ParticleA>
bool swift2::kernels::alwaysUpdateParticlePairs ( const peano4::datamanagement::CellMarker & marker,
const ParticleA & localParticle,
const ParticleB & activeParticle )

Degenerated update in cell predicate.

See comment on alwaysUpdateInVertexKernel(), which also holds for this predicate.

Definition at line 71 of file ParticleUpdatePredicates.h.

◆ flagBoundaryParticles() [1/2]

template<typename ParticleContainer >
void swift2::kernels::flagBoundaryParticles ( const ParticleContainer & localParticles,
const double nparts )

Flag boundary particles.

These particles we will not be updated by any algorithmic step.

Parameters
ParticleContainerTypicaly either std::list<Particle *> or std::unordered_set<Particle *>

◆ flagBoundaryParticles() [2/2]

template<typename ParticleContainer >
void swift2::kernels::flagBoundaryParticles ( const ParticleContainer & localParticles,
const double nparts,
const tarch::la::Vector< Dimensions, double > & domainSize,
const tarch::la::Vector< Dimensions, double > & domainOffset )

◆ forAllParticlePairs() [1/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryActiveLocalOffloadRealisation realisation )

◆ forAllParticlePairs() [2/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryActiveLocalRealisation realisation )

Alternative implementation of CoalescedMemoryActiveLocalRealisation.

  Simple version of pair-wise comparison exploiting coalesced memory

  Please consult the generic cousin (with a generic template argument)
  for an explanation of the semantics.

  @image html coalesced-memory.png

  Before you continue to read, please read also the documentation
  of forAllParticles() that accepts

swift2::kernels::kernelrealisation::CoalescedMemoryRealisation as argument. This routine mirrors all ideas described there. The only "difference" is that both the local and active particle sets are clustered, i.e. we get sequences of pointers, but we know that these sequences are split into chunks with consecutive memory regions.

Concept

We know in this case that activeParticles is clustered into chunks described by numberOfCoalescedActiveParticlesPerVertex. The same reasoning holds for localParticles. Per local particles it has to loop over all active particles. We employ exactly the techniques described for forAllParticles(), but we run over the active/local particle set chunk-wisely. Per chunk, we exploit the fact that particles are stored continuously.

Ordering

In principle, the counters over active and local particles run independent of each other, while the active set always contains the local set. If we assume that the update function can be vectorised, we see that the active set has to be the outer loop: We fix the particle that works on a chunk of local particles. If we made the active set the inner loop, i.e. evaluated all the impacts of a set of active particles onto one local particle, we would have a write conflict if vectorised.

Loop fusion vs separation

We have to check if a particle is to be updated. If so, we also have to check if the symmetric evaluation has to be performed: By default, we do not exploit any force symmetry on one level, as it makes bookkeeping more complicated. However, coarser active particles act on finer particles and immediately receive their update back, i.e. between scales we exploit the symmetry.

The generic implementation does these checks within one loop, i.e. once we have found an active particle excerting a force onto a local one, we immediately check if they reside on different levels and, if so, do the symmetric calculation. We may assume that such multiscale relations are rare. Furthermore, they have the potential to stop vectorisation as we have concurrent writes to an active particle. Therefore, we could split the check into two separate loops, where the second will rarely ever trigger any calculation.

While a valid rationale, we found the split version to perform significantly slower than a fused one.

Implementation

The outer loop is kind of trivial:

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ int firstActiveParticleOfCurrentChunk = 0; for (auto& activeParticleChunk: numberOfActiveParticlesPerVertex) { typename ActiveParticleContainer::value_type pFirstActiveParticleOfCurrentChunk = *activeParticles.begin() + firstActiveParticleOfCurrentChunk; firstActiveParticleOfCurrentChunk += activeParticleChunk; for (int iActiveParticle=0; iActiveParticle<activeParticleChunk; iActiveParticle++) { ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

iterates over the chunks within the active sets. Per chunk, it creates a pointer to the first active particles within this chunk. From hereon, we know that the particles are stored continuously (in this chunk) and hence can use

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PCParticle<ActiveParticleContainer>& activeParticle = *(pFirstActiveParticleOfCurrentChunk+iActiveParticle); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

later on the reconstruct the correct active particle.

In the variant with CoalescedMemoryActiveLocalRealisation, the outer loop runs over the active particles, while the inner loop runs over the local ones. Here, we invert these two loops.

◆ forAllParticlePairs() [3/10]

template<auto ParticlePairOp, auto LocalPredicateOp, auto ParticlePairPredicateOp>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryLocalActiveOffloadRealisation realisation )

◆ forAllParticlePairs() [4/10]

template<auto ParticlePairOp, auto LocalPredicateOp, auto ParticlePairPredicateOp>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryLocalActiveRealisation realisation )

◆ forAllParticlePairs() [5/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueActiveLocalRealisation realisation )

◆ forAllParticlePairs() [6/10]

template<typename LocalParticleContainer , typename ActiveParticleContainer >
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueActiveLocalRealisation realisation )

Move all the predicate evaluations into dedicated prologue.

Alternative implementation to the one with swift2::kernels::kernelrealisation::CoalescedMemoryRealisation. We run over the particles and first

◆ forAllParticlePairs() [7/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueLocalActiveRealisation realisation )

◆ forAllParticlePairs() [8/10]

template<typename LocalParticleContainer , typename ActiveParticleContainer >
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueLocalActiveRealisation realisation )

◆ forAllParticlePairs() [9/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::GenericOffloadRealisation  )

Exactly the same version as the generic variant, but with an additional offload annotation.

◆ forAllParticlePairs() [10/10]

template<auto PairOperator, auto LocalPredicate, auto PairPredicate>
void swift2::kernels::forAllParticlePairs ( const swift2::CellMetaData & cellMetaData,
auto & localParticles,
auto & activeParticles,
::swift2::kernels::kernelrealisation::GenericRealisation realisation )

Run over all local particle-active particle combinations.

The generic implementation realises a nested loop: We call interaction per pair of local and active particles. The interaction functor may modify the local particle. It is the responsibility of the update predicate to ensure that no particle is updated twice: For example, most users will look whether a particle is contained within the local cell, so we do not update it when actually the neighbour should do that job, but if it is sitting right at the face in-between two cells, then we also have to check a boolean that tells us where we are regarding updates. The predicate also should check if there's a self-interaction and mask it out if appropriate.

In Swift's terminology, we rely on a non-symmetric XXX calculation where XXX is the compute kernel (such as density): Our implementations loops over all local particles (outer loop) and, per local particle then over all active particles (inner loop). Inside this second loop, we compute a force acting from the active particle onto the local particle, but if and only if the PairPredicate holds. But this knowledge is not used to update the active particle in an way.

This might seem to be a missed tuning opportunity: If a local and an active particle reside on the same level, we know that the symmetric force component will be computed later on, i.e. either in a subsequent step of the present loop or later on when the other cell hosting the other particle invokes the update kernel.

Let L be the local one and A the active one, we have

\( f(L,A) = -f(A,L). \)

Following the description above, this antisymmetry is not exploited in the kernel. We know that there will be another loop iteration or cell interaction kernel call which takes care of the negative complementary force.

It is subject (and possible) to inject the antisymmetry optimisation later in the user kernel, but that's beyond scope here.

Multiscale interactions

If A resides on a coarser level than L, then we have to exploit the antisymmetry. We need to add the force explicitly as discussed in Mesh traversal.

This routine follows Peano's generic multiscale discussion, where we point out that we have correctly take particles into account which reside on coarser levels. This is necessary if some particles have larger cut-off radii than the others or if we work with adaptive meshes.

Signatures and internal types

The routine accepts a container over particle pointers. The functor f however accepts references. It is the responsibility of this routine to map pointers onto references. We use

for (auto& localParticle : localParticles) {
f(*localParticle);
}

Predicates

This would be the generic predicates as most kernels require it:

localParticlePredicate =
::swift2::kernels::alwaysUpdateInCellKernel<PCParticle<LocalParticleContainer>>,
particlePairPredicate =
::swift2::kernels::localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle<PCParticle<LocalParticleContainer>>
std::function< bool( const peano4::datamanagement::CellMarker &marker, const bool & localParticleIsContainedInCell, const Particle & localParticle)> UpdateParticleAssignedToCellPredicate
std::function< bool( const peano4::datamanagement::CellMarker &marker, const Particle & localParticle, const Particle & activeParticle)> UpdateParticlePairWithinCellPredicate

However, you can use a more bespoke version as follows:

localParticlePredicate =
::swift2::kernels::localParticleCanBeUpdatedInCellKernel<PCParticle<LocalParticleContainer>>,
particlePairPredicate =
::swift2::kernels::localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle<PCParticle<LocalParticleContainer>>
Parameters
LocalParticleContainerA subtype of std::list<Particle *>. You have no guarantee of the pointers in the list, i.e. that they are in any way consecutive.
ActiveParticleContainerA subtype of std::list<Particle *>. You have no guarantee of the pointers in the list, i.e. that they are in any way consecutive.
See also
Variant accepting swift2::kernels::kernelrealisation::CoalescedMemoryRealisation for a discussion of memory ordering optimisation.

◆ forAllParticles() [1/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::CellMarker & marker,
auto & localParticles,
const std::vector< int > & numberOfCoalescedLocalParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueRealisation  )

◆ forAllParticles() [2/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::CellMarker & marker,
auto & localParticles,
const std::vector< int > & numberOfLocalParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryOffloadRealisation realisation )

◆ forAllParticles() [3/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::CellMarker & marker,
auto & localParticles,
const std::vector< int > & numberOfLocalParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryRealisation realisation )

◆ forAllParticles() [4/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::VertexMarker & marker,
auto & assignedParticles,
int numberOfAssignedParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryOffloadRealisation realisation )

◆ forAllParticles() [5/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::VertexMarker & marker,
auto & assignedParticles,
int numberOfAssignedParticles,
::swift2::kernels::kernelrealisation::CoalescedMemoryRealisation realisation )

◆ forAllParticles() [6/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::VertexMarker & marker,
auto & assignedParticles,
int numberOfCoalescedAssignedParticles,
::swift2::kernels::kernelrealisation::EvaluatePredicateInPrologueRealisation  )

We split up the loop into two loops: The first one runs over the predicates and collects all the results in one large bit field.

The idea/hope is that this part vectorises. After that, we run over the particle set again, but only evaluate those guys where the bitfield is actually set.

◆ forAllParticles() [7/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::VertexMarker & marker,
auto & assignedParticles,
int numberOfCoalescedAssignedParticles,
::swift2::kernels::kernelrealisation::GenericOffloadRealisation  )

Exactly the same version as the generic variant, but we use the offload attribute.

◆ forAllParticles() [8/8]

template<auto ParticleOp, auto PredicateOp>
void swift2::kernels::forAllParticles ( const peano4::datamanagement::VertexMarker & marker,
auto & assignedParticles,
int numberOfCoalescedAssignedParticles,
::swift2::kernels::kernelrealisation::GenericRealisation realisation )

Run over all particles and update them independent of each other.

The routine accepts a container over particle pointers, but the functor f actually accepts references. It is the responsibility of this routine to map pointers onto references.

Predicate

The predicate can be used to mask out certain updates.

We distinguish two use cases for the particle self-interactions:

  1. We want to execute a stand-alone computation over the particle, e.g. the kick step, which is does not require any particle-particle contribution.
  2. We want to execute computations after and before the particle-particle interactions kernels, e.g. to 'prepare' or 'end' a given calculation in SPH loops (e.g. density).

The most popular predicates therefore are:

ParticleContainer::DoFType>
bool localParticleCanBeUpdatedInVertexKernel(const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
Can we do work on this particle during a vertex kernel sweep stage?

and

ParticleContainer::DoFType>
bool alwaysUpdateInVertexKernel(const peano4::datamanagement::VertexMarker &marker, const Particle &localParticle)
Degenerated predicate which always allows for an update.

Consistency remarks

In order to ensure the self-interaction kernels execute consistently during the mesh traversals for these type of operations, the user should bear in mind the difference between these two cases:

  • The 'prepare' case should be mapped into touchVertexFirstTime(). Peano internally ensures that CellHasUpdatedParticle is false in this situation.
  • The 'end' case should be mapped into touchVertexLastTime. Peano internally ensures that CellHasUpdatedParticle is true in this situation.

This routine does not vectorise over the particles. If any vectorisation is used, you'll see the vector instructions arise from the actual compute kernel.

Parameters
ParticleContainerA subtype of std::list<Particle *>

◆ forceKernelDistanceCheck()

template<typename ParticleA , typename ParticleB = ParticleA>
bool swift2::kernels::forceKernelDistanceCheck ( ParticleA &__restrict__ localParticle,
const ParticleB &__restrict__ activeParticle )

◆ localParticleCanBeUpdatedAndMovedInVertexKernel()

template<typename Particle >
bool swift2::kernels::localParticleCanBeUpdatedAndMovedInVertexKernel ( const peano4::datamanagement::VertexMarker & marker,
const Particle & localParticle )

Can we move (drift) this particle?

This is a more restrictive version compared to localParticleCanBeUpdatedInVertexKernel(), as it allows the underlying kernel to move a particle, too. Hence, the particle has to be local, and we have to check if it has not been moved yet. It is important that we distinguish this more restrictive version from its counterpart, as not each and every mesh traversal might reset the moved marker.

Parameters
localParticleParticle to check for
markerIdentifier for this vertex

Definition at line 113 of file ParticleUpdatePredicates.h.

References particleIsLocal().

Here is the call graph for this function:

◆ localParticleCanBeUpdatedInCellKernel()

template<typename Particle >
bool swift2::kernels::localParticleCanBeUpdatedInCellKernel ( const peano4::datamanagement::CellMarker & marker,
const bool & localParticleIsContainedInCell,
const Particle & localParticle )

◆ localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle()

template<typename ParticleA , typename ParticleB = ParticleA>
bool swift2::kernels::localParticleCanBeUpdatedInCellKernelFromAnyOtherParticle ( const peano4::datamanagement::CellMarker & marker,
const ParticleA & localParticle,
const ParticleB & activeParticle )

Can we do work on this particle during a cell kernel sweep stage?

A particle is to be updated if and only if

  • it is located within the cell of interest;
  • it has not yet been updated by a cell;
  • the particle interaction triggering the update is not a self-interaction.

The second point is important. A particle might be located right at the face in-between two cells. In this case, it is not clear to which cell is actually belong to. So we are fine if either cell updates it, but it should be only one cel at a time.

Further remarks

I originally thought that this predicate should resemble

return (
not localParticle->getCellHasUpdatedParticle()
and
marker.isContained(localParticle->getX())
and
marker)
);
bool particleWillBeDroppedFurther(const Particle &particle, const peano4::datamanagement::CellMarker &marker)
Will the particle be dropped further throughout the traversal.

However, that's a poor idea, as it does not work along AMR boundaries for particles which reside in a refined cell yet would be dropped into a hanging vertex (which we don't). The file peano4.toolbox.particles.api.AbstractParticleGridAssociation provides some examples on this.

Optimisation

This routine looks if a particle is contained in a cell. This is slow. Usually, you would do this check once in an outer loop via the is local flag, and then you can skip it here.

Usage

Usually, it is a poor idea to use this routine. It is brutally slow to check a local particle whether it is really contained within a cell per particle-particle interaction. I rather prefer to use

   ::swift2::kernels::localParticleCanBeUpdatedInCellKernel<globaldata::HydroPart>,

once in an outer loop and then to apply

    updateFromAnyOtherParticle

as predicate (or something more restrictive such as densityKernelEvaluatePairInteractionPredicate but never this one).

Parameters
localParticleparticle to check for
markerthe cell's CellMarker

Definition at line 188 of file ParticleUpdatePredicates.h.

References tarch::la::NUMERICAL_ZERO_DIFFERENCE, and toolbox::particles::internal::relativeGrabOwnershipSpatialSortingTolerance().

Here is the call graph for this function:

◆ localParticleCanBeUpdatedInCellKernelFromAnyOtherParticleWithinIterationRange()

template<typename ParticleA , typename ParticleB = ParticleA>
bool swift2::kernels::localParticleCanBeUpdatedInCellKernelFromAnyOtherParticleWithinIterationRange ( const peano4::datamanagement::CellMarker & marker,
const ParticleA & localParticle,
const ParticleB & activeParticle )

◆ localParticleCanBeUpdatedInVertexKernel()

template<typename Particle >
bool swift2::kernels::localParticleCanBeUpdatedInVertexKernel ( const peano4::datamanagement::VertexMarker & marker,
const Particle & localParticle )

Can we do work on this particle during a vertex kernel sweep stage?

This predicate filters out all halo (virtual) particle. It implicitly assumes that the particle-vertex association is correct. Therefore, we really only have to mask out virtual particles. The predicate breaks down if the association is not correct, which means it does not work if particles move.

Parameters
localParticleParticle to check for
markerIdentifier for this vertex

Definition at line 270 of file ParticleUpdatePredicates.h.

References particleIsLocal().

Referenced by swift2::kernels::legacy::firstInitParticleParticleUpdatePredicate().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ particleIsLocal()

template<typename Particle >
bool swift2::kernels::particleIsLocal ( const peano4::datamanagement::VertexMarker & marker,
const Particle & localParticle )

Is a particle local.

is this localParticle a local particle (in the ParallelState sense)?

Helper routine which is used by a lot of predicates in their decision making process. Is usually not used directly and hence could be moved into an "internal" namespace as well.

Definition at line 91 of file ParticleUpdatePredicates.h.

Referenced by localParticleCanBeUpdatedAndMovedInVertexKernel(), and localParticleCanBeUpdatedInVertexKernel().

Here is the caller graph for this function:

◆ updateFromAnyOtherParticle()

template<typename ParticleA , typename ParticleB = ParticleA>
bool swift2::kernels::updateFromAnyOtherParticle ( const peano4::datamanagement::CellMarker & marker,
const ParticleA & localParticle,
const ParticleB & activeParticle )

Definition at line 206 of file ParticleUpdatePredicates.h.