OpenLB 1.7
Loading...
Searching...
No Matches
Classes | Functions
olb::particles::contact Namespace Reference

Classes

struct  ContactContainer
 
struct  ContactProperties
 Object that stores properties which are necessary for the computation of contact forces N = number of different materials The material here is an identifier of a solid material with certain (mechanical) properties This material is something completely different from the lattice's material number, which is used to assign boundary conditions and dynamics. More...
 
struct  ContactProperty
 
struct  MaterialProperties
 Class storing properties that are necessary for the computation of the contact orce N = number of different materials [0]: modulus of elasticity [1]: Poisson's ratio. More...
 
struct  particle_particle
 
struct  particle_particle< T, PARTICLETYPE, ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX >, WALLCONTACTTYPE, BBCORRECTIONMETHOD, CONVEX, useSDF >
 
struct  particle_wall
 
struct  particle_wall< T, PARTICLETYPE, PARTICLECONTACTTYPE, WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX >, BBCORRECTIONMETHOD, CONVEX, useSDF >
 
struct  ParticleContact
 
struct  ParticleContactArbitraryFromOverlapVolume
 An object holding data for a contact which is described analog to Nassauer and Kuna (2013) More...
 
struct  WallContact
 
struct  WallContactArbitraryFromOverlapVolume
 

Functions

template<typename T >
constexpr T evalEffectiveYoungModulus (T E1, T E2, T nu1, T nu2)
 
template<typename T >
constexpr T evalDampingFactor (const T coefficientOfRestitution, const T initialRelativeVelocityMagnitude)
 Calculates the damping factor according to Carvalho & Martins (2019) (10.1016/j.mechmachtheory.2019.03.028)
 
template<typename T , typename PARTICLETYPE >
evalContactDetectionDistance (Particle< T, PARTICLETYPE > &particle, T const physDeltaX)
 
template<typename T >
evalCircumRadius (T const contactDetectionDistance, T const circumRadius, T const epsilon)
 
template<typename T , typename PARTICLETYPE >
evalCircumRadius (Particle< T, PARTICLETYPE > &particle, T const physDeltaX, T const circumRadius, T const epsilon)
 
template<typename T , typename PARTICLETYPE >
evalCircumRadius (Particle< T, PARTICLETYPE > &particle, T const physDeltaX)
 
template<typename CONTACTTYPE >
void cleanContacts (std::vector< CONTACTTYPE > &contacts)
 
template<typename CONTACTTYPE >
void resetResponsibleRank (CONTACTTYPE &contact)
 
template<typename CONTACTTYPE >
bool isResponsibleRankSet (CONTACTTYPE &contact)
 
template<typename T , unsigned D>
void updateMinMax (PhysR< T, D > &min, PhysR< T, D > &max, const PhysR< T, D > &pos)
 
template<typename T , unsigned D>
unsigned short domainDimension (PhysR< T, D > &min, PhysR< T, D > &max)
 
template<typename T , unsigned N, typename F >
constexpr ContactProperties< T, N > createContactProperties (F f)
 
template<typename T , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void communicateContacts (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void accountForPeriodicParticleBoundary (SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, F getSetupPeriodicity)
 update positions in contact to account for periodic boundaries
 
template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > evalDestRanksForDetectionCommunication (ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
 evaluate responsible ranks for particle-particle contact
 
template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > evalDestRanksForDetectionCommunication (WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
 evaluate responsible rank for solid boundary contact
 
template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > evalDestRanksForPostContactTreatmentCommunication (ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
 evaluate ranks that touch both particles of a particle-particle contact
 
template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > evalDestRanksForPostContactTreatmentCommunication (WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
 evaluate ranks that touch the particle of a particle-wall contact
 
template<typename T , typename PARTICLETYPE , typename CONTACTTYPE , bool CONVEX, bool SANITYCHECK = false>
void receiveContact (ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &newcontact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< CONTACTTYPE > &contacts, int rankOrig)
 
template<typename T , typename PARTICLETYPE , typename CONTACTTYPE , bool CONVEX, bool SANITYCHECK = false>
void receiveContact (WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &newcontact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< CONTACTTYPE > &contacts, int rankOrig)
 
template<typename T , typename PARTICLETYPE , typename CONTACTTYPE >
void communicateParallelContacts (std::vector< CONTACTTYPE > &contacts, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm contactDetectionComm, const Vector< bool, PARTICLETYPE::d > &periodicity)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void communicateContactsParallel (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm particleContactDetectionComm, MPI_Comm wallContactDetectionComm, const Vector< bool, PARTICLETYPE::d > &periodicity)
 
template<typename T , typename PARTICLETYPE , typename CONTACTTYPE >
void communicatePostContactTreatmentContacts (std::vector< CONTACTTYPE > &contacts, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm postContactTreatmentComm, const Vector< bool, PARTICLETYPE::d > &periodicity)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void communicatePostContactTreatmentContacts (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm particlePostContactTreatmentComm, MPI_Comm wallPostContactTreatmentComm, const Vector< bool, PARTICLETYPE::d > &periodicity)
 It is necessary to communicate contacts so that no information is lost.
 
template<typename T , unsigned D>
int getContactTreatmentResultsSerialSize ()
 
template<typename T , unsigned D>
void extendContactTreatmentResultsDataMap (const std::size_t &globalParticleID, Vector< T, D > &force, Vector< T, utilities::dimensions::convert< D >::rotation > &torque, const int destRank, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap)
 
template<typename T , typename PARTICLETYPE >
void receiveContactTreatmentResults (SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, MPI_Comm contactTreatmentComm, singleton::MpiNonBlockingHelper &mpiNbHelper)
 
template<typename T , typename PARTICLETYPE >
void communicateContactTreatmentResults (SuperParticleSystem< T, PARTICLETYPE > &particleSystem, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, MPI_Comm contactTreatmentComm)
 
template<typename CONTACTTYPE >
auto getContactIterator (std::vector< CONTACTTYPE > &contacts, const std::function< bool(const CONTACTTYPE &)> condition)
 
std::array< std::size_t, 2 > sortParticleIDs (const std::array< std::size_t, 2 > &ids)
 
template<typename T , typename PARTICLETYPE , typename F >
void unifyPositions (Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, std::array< PhysR< T, PARTICLETYPE::d >, 2 > &positions, T deltaX)
 
template<typename T , typename PARTICLETYPE , typename F >
PhysR< T, PARTICLETYPE::d > unifyPosition (Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename T , typename PARTICLETYPE , typename F >
PhysR< T, PARTICLETYPE::d > evalContactPosition (Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &particlePos, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename PARTICLECONTACTTYPE , bool IS_INPUT_SORTED = false>
bool particleContactConsistsOfIDs (PARTICLECONTACTTYPE &particleContact, const std::array< size_t, 2 > &ids)
 
template<typename T , typename PARTICLETYPE , bool CONVEX, typename F >
void updateContact (ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename T , typename PARTICLETYPE , bool CONVEX, typename F >
void updateContact (WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void updateContacts (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, std::array< std::size_t, 2 > &&ids, const PhysR< T, PARTICLETYPE::d > &pos, Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void updateContacts (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, size_t particleID, unsigned wallID, const PhysR< T, PARTICLETYPE::d > &pos, Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
 
template<typename T , unsigned D, typename CONTACTTYPE >
constexpr T evalCurrentDampingFactor (CONTACTTYPE &contact, const T coefficientOfRestitution, const Vector< T, D > &initialRelativeNormalVelocity)
 
template<typename T , typename PARTICLETYPE >
constexpr Vector< T, PARTICLETYPE::d > evalRelativeVelocity (Particle< T, PARTICLETYPE > &particleA, Particle< T, PARTICLETYPE > &particleB, const Vector< T, PARTICLETYPE::d > &position)
 Returns the relative velocity of two particles at a defined position.
 
template<typename T , typename PARTICLETYPE >
constexpr Vector< T, PARTICLETYPE::d > evalRelativeVelocity (Particle< T, PARTICLETYPE > &particle, const Vector< T, PARTICLETYPE::d > &position)
 
template<typename T , unsigned D>
constexpr Vector< T, D > evalRelativeNormalVelocity (const Vector< T, D > &contactNormal, const Vector< T, D > &relVel)
 
template<typename T , typename F >
constexpr void forEachPosition (Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
 
template<typename T , typename F >
constexpr void forEachPosition (Vector< T, 2 > startPos, Vector< T, 2 > endPos, F f)
 
template<typename T , typename F >
constexpr void forEachPositionWithBreak (Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
 
template<typename T , typename F >
constexpr void forEachPositionWithBreak (Vector< T, 2 > startPos, Vector< T, 2 > endPos, F f)
 
template<typename T , unsigned D>
constexpr Vector< T, D > evalContactDeltaX (const Vector< T, D > &min, const Vector< T, D > &max, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , bool CONVEX>
void prepareForceCalculation (ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer)
 
template<typename T , unsigned D>
Vector< T, D > calcElasticAndViscousForce (T effectiveE, T k, T overlapVolume, T indentation, T dampingFactor, const Vector< T, D > &relVelNormal, const Vector< T, D > &contactNormal)
 Elastic and viscous force from overlap volume according to Nassauer & Kuna (2013)
 
template<typename T , unsigned D>
evalApproxSurface (const Vector< T, D > &normalizedNormal, const PhysR< T, D > &contactPhysDeltaX)
 Takes a normalized normal and the voxel sizes and approximates the corresponding surface.
 
template<typename T , unsigned D>
Vector< T, D > getTangentialForceFromOverlapVolume (const Vector< T, D > &contactNormal, const T coefficientStaticFriction, const T coefficientKineticFriction, const T staticKineticTransitionVelocity, const T k, const Vector< T, D > &relVel, const Vector< T, D > &normalForce)
 
template<typename T , unsigned D>
Vector< T, D > getNormalForceFromOverlapVolume (const Vector< T, D > &contactNormal, const T indentation, const T overlapVolume, const T effectiveE, const T dampingFactor, const T k, const Vector< T, D > &relVel)
 
template<typename T , typename PARTICLETYPE >
void applyForceOnParticle (std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, Particle< T, PARTICLETYPE > &particle, XParticleSystem< T, PARTICLETYPE > &particleSystem, const Vector< T, PARTICLETYPE::d > &contactPoint, const Vector< T, PARTICLETYPE::d > &normalForce, const Vector< T, PARTICLETYPE::d > &tangentialForce)
 
template<typename T , typename PARTICLETYPE , typename CONTACTPROPERTIES , typename F = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void applyForceFromOverlapVolume (std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, Particle< T, PARTICLETYPE > &particleA, Particle< T, PARTICLETYPE > &particleB, XParticleSystem< T, PARTICLETYPE > &particleSystem, const PhysR< T, PARTICLETYPE::d > &contactPoint, const Vector< T, PARTICLETYPE::d > &contactNormal, const T indentation, const T overlapVolume, const Vector< T, PARTICLETYPE::d > &relVel, const T dampingFactor, const CONTACTPROPERTIES &contactProperties, T k, const std::size_t &particleAID, const std::size_t &particleBID, F processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
 
template<typename T , typename PARTICLETYPE , typename CONTACTPROPERTIES , typename F = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void applyForceFromOverlapVolume (std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap, Particle< T, PARTICLETYPE > &particle, XParticleSystem< T, PARTICLETYPE > &particleSystem, SolidBoundary< T, PARTICLETYPE::d > &solidBoundary, const PhysR< T, PARTICLETYPE::d > &contactPoint, const Vector< T, PARTICLETYPE::d > &contactNormal, const T indentation, const T overlapVolume, const Vector< T, PARTICLETYPE::d > &relVel, const T dampingFactor, const CONTACTPROPERTIES &contactProperties, T k, const std::size_t &particleID, const std::size_t &wallID, F processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
 
template<typename T , unsigned D>
void evalStartAndEndPos (Vector< long, D > &startPos, Vector< long, D > &endPos, const PhysR< T, D > &max, const PhysR< T, D > &min, const PhysR< T, D > &contactPhysDeltaX)
 
template<typename T , unsigned D>
evalForceViaVolumeCoefficient (const Vector< T, D > &min, const Vector< T, D > &max, T overlapVolume)
 
template<typename T >
constexpr T evalForceViaVolumeCoefficient (const T contactVolume, const T contactSurface, const T indentationDepth)
 
template<typename T , unsigned D, typename F1 , typename F2 , typename F3 , typename F4 , typename F5 >
void processCell (const PhysR< T, D > &pos, const PhysR< T, D > &contactPhysDeltaX, PhysR< T, D > &center, Vector< T, D > &contactNormal, unsigned &volumeCellCount, T &surfaceCellCount, F1 isInside, F2 isOnSurface, F3 calcNormalA, F4 calcNormalB, F5 updateMinMax)
 
template<typename T , unsigned D, typename F1 , typename F2 , typename F3 , typename F4 >
void processContactViaVolume (const Vector< T, D > &min, const Vector< T, D > &max, T physDeltaX, unsigned contactBoxResolutionPerDirection, F1 resetContactBox, F2 processCellWrapped, F3 calculateIndentation, F4 applyForce)
 
template<typename T , unsigned D, typename F1 >
bool evalStartingPoint (const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, Vector< long, D > &currPos, F1 isInsideContact)
 
template<typename T , unsigned D, typename F1 , typename F2 >
void evalBoundingBoxRecursive (const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, const Vector< long, D > &currPos, const Vector< short, D > &dirIn, F1 isInsideContact, F2 updateMinMax)
 
template<typename T , unsigned D, typename F1 , typename F2 , typename F3 >
void correctBoundingBox (const PhysR< T, D > &min, const PhysR< T, D > &max, const T physDeltaX, const unsigned contactBoxResolutionPerDirection, F1 isInsideContact, F2 resetContactBox, F3 updateMinMax)
 
template<typename T , unsigned D, typename F1 , typename F2 , typename F3 >
void correctBoundingBoxNewContact (PhysR< T, D > min, PhysR< T, D > max, T physDeltaX, unsigned contactBoxResolutionPerDirection, F1 signedDistanceToIntersection, F2 resetContactBox, F3 updateMinMax)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename CONTACTPROPERTIES , unsigned BBCORRECTIONMETHOD = 0, typename F1 = decltype(defaults::periodicity<PARTICLETYPE::d>), typename F2 = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void processContacts (SuperParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, const CONTACTPROPERTIES &contactProperties, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, MPI_Comm contactTreatmentComm, const unsigned contactBoxResolutionPerDirection=8, const T k=static_cast< T >(4./(3 *util::sqrt(M_PI))), F1 getSetupPeriodicity=defaults::periodicity< PARTICLETYPE::d >, F2 processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
 
template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename CONTACTPROPERTIES , unsigned BBCORRECTIONMETHOD = 0, typename F1 = decltype(defaults::periodicity<PARTICLETYPE::d>), typename F2 = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void processContacts (ParticleSystem< T, PARTICLETYPE > &particleSystem, std::vector< SolidBoundary< T, PARTICLETYPE::d > > &solidBoundaries, ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer, const CONTACTPROPERTIES &contactProperties, const SuperGeometry< T, PARTICLETYPE::d > &sGeometry, const unsigned contactBoxResolutionPerDirection=8, const T k=static_cast< T >(4./(3 *util::sqrt(M_PI))), F1 getSetupPeriodicity=defaults::periodicity< PARTICLETYPE::d >, F2 processContactForce=defaults::processContactForce< T, PARTICLETYPE::d >)
 

Function Documentation

◆ accountForPeriodicParticleBoundary()

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void olb::particles::contact::accountForPeriodicParticleBoundary ( SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
const SuperGeometry< T, PARTICLETYPE::d > & sGeometry,
F getSetupPeriodicity )

update positions in contact to account for periodic boundaries

Definition at line 176 of file particleContactCommunicationFunctions.h.

181{
182 using namespace descriptors;
183
184 // if a periodic setup is used, we have to update min and max in rare occasions
185 // i.e. when the first/only particle "jumps" from the end to the beginning
186 // because then the min and max from the step before isn't valid anymore
187 const T physDeltaX =
188 sGeometry.getCuboidGeometry().getMotherCuboid().getDeltaR();
189 const PhysR<T, PARTICLETYPE::d> cellMin =
190 particles::communication::getCuboidMin<T, PARTICLETYPE::d>(
191 sGeometry.getCuboidGeometry());
192 const PhysR<T, PARTICLETYPE::d> cellMax =
193 particles::communication::getCuboidMax<T, PARTICLETYPE::d>(
194 sGeometry.getCuboidGeometry(), cellMin);
195
196 communication::forParticlesInSuperParticleSystem(
197 sParticleSystem,
198 [&](Particle<T, PARTICLETYPE>& particle,
199 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
200 const std::size_t currentGlobalParticleID =
201 particle.template getField<PARALLELIZATION, ID>();
202
203 for (WALLCONTACTTYPE& wallContact : contactContainer.wallContacts) {
204 if (!wallContact.isEmpty() && !wallContact.isNew() &&
205 wallContact.getParticleID() == currentGlobalParticleID &&
206 wallContact.getResponsibleRank() == singleton::mpi().getRank()) {
207 const PhysR<T, PARTICLETYPE::d> min = wallContact.getMin();
208 const PhysR<T, PARTICLETYPE::d> max = wallContact.getMax();
209 wallContact.resetMinMax();
210 const PhysR<T, PARTICLETYPE::d> unifiedPos = contact::unifyPosition(
211 particle, cellMin, cellMax, getSetupPeriodicity, physDeltaX);
212 wallContact.setParticlePosition(unifiedPos);
213 const PhysR<T, PARTICLETYPE::d> newMin =
214 contact::evalContactPosition(
215 particle, wallContact.getParticlePosition(), min, cellMin,
216 cellMax, getSetupPeriodicity, physDeltaX);
217 const PhysR<T, PARTICLETYPE::d> newMax =
218 contact::evalContactPosition(
219 particle, wallContact.getParticlePosition(), max, cellMin,
220 cellMax, getSetupPeriodicity, physDeltaX);
221 wallContact.updateMinMax(newMin);
222 wallContact.updateMinMax(newMax);
223 }
224 }
225 for (PARTICLECONTACTTYPE& particleContact :
226 contactContainer.particleContacts) {
227 if (!particleContact.isEmpty() && !particleContact.isNew() &&
228 particleContact.getIDs()[0] == currentGlobalParticleID &&
229 particleContact.getResponsibleRank() ==
230 singleton::mpi().getRank()) {
231 const PhysR<T, PARTICLETYPE::d> min = particleContact.getMin();
232 const PhysR<T, PARTICLETYPE::d> max = particleContact.getMax();
233 particleContact.resetMinMax();
234 std::array<PhysR<T, PARTICLETYPE::d>, 2> unifiedPos;
235 auto particleB = sParticleSystem.get(particleContact.getIDs()[1]);
236 contact::unifyPositions(particle, particleB, cellMin, cellMax,
237 getSetupPeriodicity, unifiedPos,
238 physDeltaX);
239 particleContact.setParticlePositions(unifiedPos);
240 const PhysR<T, PARTICLETYPE::d> newMin =
241 contact::evalContactPosition(
242 particle, particleContact.getParticlePositions()[0], min,
243 cellMin, cellMax, getSetupPeriodicity, physDeltaX);
244 const PhysR<T, PARTICLETYPE::d> newMax =
245 contact::evalContactPosition(
246 particle, particleContact.getParticlePositions()[0], max,
247 cellMin, cellMax, getSetupPeriodicity, physDeltaX);
248 particleContact.updateMinMax(newMin);
249 particleContact.updateMinMax(newMax);
250 }
251 }
252 });
253}
CuboidGeometry< T, D > & getCuboidGeometry()
Read and write access to cuboid geometry.
Plain old scalar vector.
Definition vector.h:47
Particle< T, PARTICLETYPE > get(std::size_t globalParticleID)

References evalContactPosition(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::get(), olb::SuperStructure< T, D >::getCuboidGeometry(), olb::singleton::MpiManager::getRank(), olb::singleton::mpi(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::particleContacts, unifyPosition(), unifyPositions(), and olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::wallContacts.

+ Here is the call graph for this function:

◆ applyForceFromOverlapVolume() [1/2]

template<typename T , typename PARTICLETYPE , typename CONTACTPROPERTIES , typename F = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void olb::particles::contact::applyForceFromOverlapVolume ( std::multimap< int, std::unique_ptr< std::uint8_t[]> > & dataMap,
Particle< T, PARTICLETYPE > & particle,
XParticleSystem< T, PARTICLETYPE > & particleSystem,
SolidBoundary< T, PARTICLETYPE::d > & solidBoundary,
const PhysR< T, PARTICLETYPE::d > & contactPoint,
const Vector< T, PARTICLETYPE::d > & contactNormal,
const T indentation,
const T overlapVolume,
const Vector< T, PARTICLETYPE::d > & relVel,
const T dampingFactor,
const CONTACTPROPERTIES & contactProperties,
T k,
const std::size_t & particleID,
const std::size_t & wallID,
F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d> )

Definition at line 448 of file particleContactForceFunctions.h.

459{
460 using namespace descriptors;
461 constexpr unsigned D = PARTICLETYPE::d;
462
463 const unsigned particleMaterial =
464 particle.template getField<MECHPROPERTIES, MATERIAL>();
465 const unsigned wallMaterial = solidBoundary.getContactMaterial();
466
467 // Calculation of contact force
469 contactNormal, indentation, overlapVolume,
470 contactProperties.getEffectiveYoungsModulus(particleMaterial,
471 wallMaterial),
472 dampingFactor, k, relVel);
474 contactNormal,
475 contactProperties.getStaticFrictionCoefficient(particleMaterial,
476 wallMaterial),
477 contactProperties.getKineticFrictionCoefficient(particleMaterial,
478 wallMaterial),
479 contactProperties.getStaticKineticTransitionVelocity(particleMaterial,
480 wallMaterial),
481 k, relVel, normalForce);
482
483 processContactForce(contactPoint, contactNormal, normalForce, tangentialForce,
484 std::array<std::size_t, 2>({particleID, wallID}),
485 overlapVolume, indentation, true);
486
487 // Applying contact forces on the particle
488 applyForceOnParticle(dataMap, particle, particleSystem, contactPoint,
489 normalForce, tangentialForce);
490}
Vector< T, D > getNormalForceFromOverlapVolume(const Vector< T, D > &contactNormal, const T indentation, const T overlapVolume, const T effectiveE, const T dampingFactor, const T k, const Vector< T, D > &relVel)
Vector< T, D > getTangentialForceFromOverlapVolume(const Vector< T, D > &contactNormal, const T coefficientStaticFriction, const T coefficientKineticFriction, const T staticKineticTransitionVelocity, const T k, const Vector< T, D > &relVel, const Vector< T, D > &normalForce)
constexpr unsigned getContactMaterial() const
Definition wall.hh:54

References applyForceOnParticle(), olb::SolidBoundary< T, D >::getContactMaterial(), getNormalForceFromOverlapVolume(), and getTangentialForceFromOverlapVolume().

+ Here is the call graph for this function:

◆ applyForceFromOverlapVolume() [2/2]

template<typename T , typename PARTICLETYPE , typename CONTACTPROPERTIES , typename F = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void olb::particles::contact::applyForceFromOverlapVolume ( std::multimap< int, std::unique_ptr< std::uint8_t[]> > & dataMap,
Particle< T, PARTICLETYPE > & particleA,
Particle< T, PARTICLETYPE > & particleB,
XParticleSystem< T, PARTICLETYPE > & particleSystem,
const PhysR< T, PARTICLETYPE::d > & contactPoint,
const Vector< T, PARTICLETYPE::d > & contactNormal,
const T indentation,
const T overlapVolume,
const Vector< T, PARTICLETYPE::d > & relVel,
const T dampingFactor,
const CONTACTPROPERTIES & contactProperties,
T k,
const std::size_t & particleAID,
const std::size_t & particleBID,
F processContactForce = defaults::processContactForce<T, PARTICLETYPE::d> )

Definition at line 403 of file particleContactForceFunctions.h.

413{
414 using namespace descriptors;
415 constexpr unsigned D = PARTICLETYPE::d;
416
417 const unsigned materialA =
418 particleA.template getField<MECHPROPERTIES, MATERIAL>();
419 const unsigned materialB =
420 particleB.template getField<MECHPROPERTIES, MATERIAL>();
421
422 // Calculation of contact force
424 contactNormal, indentation, overlapVolume,
425 contactProperties.getEffectiveYoungsModulus(materialA, materialB),
426 dampingFactor, k, relVel);
428 contactNormal,
429 contactProperties.getStaticFrictionCoefficient(materialA, materialB),
430 contactProperties.getKineticFrictionCoefficient(materialA, materialB),
431 contactProperties.getStaticFrictionCoefficient(materialA, materialB), k,
432 relVel, normalForce);
433
434 processContactForce(contactPoint, contactNormal, normalForce, tangentialForce,
435 std::array<std::size_t, 2>({particleAID, particleBID}),
436 overlapVolume, indentation, false);
437
438 // Applying forces on the particle
439 applyForceOnParticle(dataMap, particleA, particleSystem, contactPoint,
440 normalForce, tangentialForce);
441 applyForceOnParticle(dataMap, particleB, particleSystem, contactPoint,
442 -1 * normalForce, -1 * tangentialForce);
443}

References applyForceOnParticle(), getNormalForceFromOverlapVolume(), and getTangentialForceFromOverlapVolume().

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

◆ applyForceOnParticle()

template<typename T , typename PARTICLETYPE >
void olb::particles::contact::applyForceOnParticle ( std::multimap< int, std::unique_ptr< std::uint8_t[]> > & dataMap,
Particle< T, PARTICLETYPE > & particle,
XParticleSystem< T, PARTICLETYPE > & particleSystem,
const Vector< T, PARTICLETYPE::d > & contactPoint,
const Vector< T, PARTICLETYPE::d > & normalForce,
const Vector< T, PARTICLETYPE::d > & tangentialForce )

Definition at line 310 of file particleContactForceFunctions.h.

317{
318 using namespace descriptors;
319 constexpr unsigned D = PARTICLETYPE::d;
320 constexpr unsigned Drot = utilities::dimensions::convert<D>::rotation;
321 Vector<T, D> contactForce = normalForce + tangentialForce;
322 const PhysR<T, D> position = particle.template getField<GENERAL, POSITION>();
323 const PhysR<T, D> contactPointDistance = contactPoint - position;
324 Vector<T, Drot> torqueFromContact(
326 contactForce, contactPointDistance));
327
328 if (access::isContactComputationEnabled(particle)) {
329 bool applyNow = true;
330
331 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
332 auto& loadBalancer = particleSystem.getSuperStructure().getLoadBalancer();
333 const std::size_t globalParticleIC =
334 particle.template getField<PARALLELIZATION, IC>();
335 int responsibleRank = loadBalancer.rank(globalParticleIC);
336 if (responsibleRank != singleton::mpi().getRank()) {
337 applyNow = false;
338 const std::size_t globalParticleID =
339 particle.template getField<PARALLELIZATION, ID>();
340 extendContactTreatmentResultsDataMap(globalParticleID, contactForce,
341 torqueFromContact, responsibleRank,
342 dataMap);
343 }
344 }
345
346 if (applyNow) {
347 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
348 // Apply force only to the main particle
349 const std::size_t globalParticleID =
350 particle.template getField<PARALLELIZATION, ID>();
351 particles::communication::forParticlesInSuperParticleSystem<
352 T, PARTICLETYPE, conditions::valid_particles>(
353 particleSystem,
354 [&](Particle<T, PARTICLETYPE>& particle,
355 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
356 const int globalParticleIC =
357 particle.template getField<PARALLELIZATION, IC>();
358 const std::size_t currGlobalParticleID =
359 particle.template getField<PARALLELIZATION, ID>();
360 if (currGlobalParticleID == globalParticleID &&
361 globiC == globalParticleIC) {
362 // Applying contact force on the particle
363 const Vector<T, D> force =
364 particle.template getField<FORCING, FORCE>();
365 particle.template setField<FORCING, FORCE>(force +
366 contactForce);
367
368 // Torque calculation and application
369 const Vector<T, Drot> torque(
370 particle.template getField<FORCING, TORQUE>());
371 particle.template setField<FORCING, TORQUE>(
373 torque + torqueFromContact));
374#ifdef VERBOSE_CONTACT_COMMUNICATION
375 std::cout << "Rank " << singleton::mpi().getRank()
376 << " procsses data of particle " << globalParticleID
377 << " (contactForce = " << contactForce + force
378 << "; torque = " << torqueFromContact + torque << ")"
379 << std::endl;
380#endif
381 }
382 });
383 }
384 else {
385 // Applying contact force on the particle
386 const Vector<T, D> force = particle.template getField<FORCING, FORCE>();
387 particle.template setField<FORCING, FORCE>(force + contactForce);
388
389 // Torque calculation and application
390 const Vector<T, Drot> torque(
391 particle.template getField<FORCING, TORQUE>());
392 particle.template setField<FORCING, TORQUE>(
393 utilities::dimensions::convert<D>::serialize_rotation(
394 torque + torqueFromContact));
395 }
396 }
397 }
398}
void extendContactTreatmentResultsDataMap(const std::size_t &globalParticleID, Vector< T, D > &force, Vector< T, utilities::dimensions::convert< D >::rotation > &torque, const int destRank, std::multimap< int, std::unique_ptr< std::uint8_t[]> > &dataMap)
Converts dimensions by deriving from given cartesian dimension D.

References extendContactTreatmentResultsDataMap(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::singleton::MpiManager::getRank(), olb::particles::access::isContactComputationEnabled(), and olb::singleton::mpi().

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

◆ calcElasticAndViscousForce()

template<typename T , unsigned D>
Vector< T, D > olb::particles::contact::calcElasticAndViscousForce ( T effectiveE,
T k,
T overlapVolume,
T indentation,
T dampingFactor,
const Vector< T, D > & relVelNormal,
const Vector< T, D > & contactNormal )

Elastic and viscous force from overlap volume according to Nassauer & Kuna (2013)

Definition at line 208 of file particleContactForceFunctions.h.

212{
213 // Sum is necessary to get the sign of the damping since velocity and normal have the exact same/opposite direction
214 T sum = relVelNormal[0] * contactNormal[0];
215 for (unsigned iD = 1; iD < D; ++iD) {
216 sum += relVelNormal[iD] * contactNormal[iD];
217 }
218
219 const T forceMagnitude =
220 effectiveE * k * util::sqrt(overlapVolume * indentation) *
221 (1 + dampingFactor * util::sign(-sum) * norm(relVelNormal));
222 return util::max(forceMagnitude, T {0}) * contactNormal;
223}
constexpr T norm(const ScalarVector< T, D, IMPL > &a)
Euclidean vector norm.

References olb::util::max(), olb::norm(), olb::util::sign(), and olb::util::sqrt().

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

◆ cleanContacts()

template<typename CONTACTTYPE >
void olb::particles::contact::cleanContacts ( std::vector< CONTACTTYPE > & contacts)

Definition at line 107 of file contactFunctions.h.

108{
109 contacts.erase(std::remove_if(contacts.begin(), contacts.end(),
110 [](const CONTACTTYPE& contact) {
111 return contact.isEmpty();
112 }),
113 contacts.end());
114}
+ Here is the caller graph for this function:

◆ communicateContacts()

template<typename T , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void olb::particles::contact::communicateContacts ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer)

Definition at line 38 of file particleContactCommunicationFunctions.h.

40{
41#ifdef PARALLEL_MODE_MPI
42 OstreamManager clout(std::cout, "contactCommunication");
43
44 if (singleton::mpi().getSize() > 1) {
45 int sumParticleContact = 0;
46 int sumWallContact = 0;
47 int countParticleContactsPerRank[singleton::mpi().getSize()];
48 int countWallContactsPerRank[singleton::mpi().getSize()];
49 int localCountParticleContacts = 0;
50 int localCountWallContacts = 0;
51
52 //clout << "communicate number of contacts ..." << std::endl;
53 if (singleton::mpi().isMainProcessor()) {
54 countParticleContactsPerRank[singleton::mpi().bossId()] =
55 contactContainer.particleContacts.size();
56 sumParticleContact +=
57 countParticleContactsPerRank[singleton::mpi().bossId()];
58 countWallContactsPerRank[singleton::mpi().bossId()] =
59 contactContainer.wallContacts.size();
60 sumWallContact += countWallContactsPerRank[singleton::mpi().bossId()];
61 for (int rank = 0; rank < singleton::mpi().getSize(); ++rank) {
62 if (rank != singleton::mpi().bossId()) {
63 singleton::mpi().receive(&countParticleContactsPerRank[rank], 1,
64 rank);
65 sumParticleContact += countParticleContactsPerRank[rank];
66 singleton::mpi().receive(&countWallContactsPerRank[rank], 1, rank);
67 sumWallContact += countWallContactsPerRank[rank];
68 }
69 }
70 }
71 else {
72 localCountParticleContacts =
73 contactContainer.particleContacts
74 .size(); // size of std::vector (called contacts in container)
75 singleton::mpi().send(&localCountParticleContacts, 1,
76 singleton::mpi().bossId()); // 0 is rank of master
77 localCountWallContacts = contactContainer.wallContacts.size();
78 singleton::mpi().send(&localCountWallContacts, 1,
79 singleton::mpi().bossId());
80 }
81 //clout << "communicate number of contacts ... OK" << std::endl;
82
83 //clout << "broadcasting number of contacts ..." << std::endl;
84 singleton::mpi().bCast(&sumParticleContact, 1, singleton::mpi().bossId());
85 singleton::mpi().bCast(&sumWallContact, 1, singleton::mpi().bossId());
86 //std::cout << sumParticleContact << std::endl;
87 //singleton::mpi().barrier();
88 //clout << "broadcasting number of contacts ... OK" << std::endl;
89
90 if (sumParticleContact > 0 || sumWallContact > 0) {
91 ContactContainer<T, PARTICLECONTACTTYPE, WALLCONTACTTYPE> container(
92 sumParticleContact, sumWallContact);
93 int particleContactObjSize = sizeof(PARTICLECONTACTTYPE);
94 int wallContactObjSize = sizeof(WALLCONTACTTYPE);
95
96 //clout << "Bundling contact objects ..." << std::endl;
97 if (singleton::mpi().isMainProcessor()) {
98 PARTICLECONTACTTYPE* currParticle = container.particleContacts.data();
99 WALLCONTACTTYPE* currWall = container.wallContacts.data();
100 for (int rank = 0; rank < singleton::mpi().getSize(); ++rank) {
101 std::uint8_t* bytesParticle = (std::uint8_t*)currParticle;
102 std::uint8_t* bytesWall = (std::uint8_t*)currWall;
103 if (rank != singleton::mpi().bossId()) {
104 singleton::mpi().receive(bytesParticle,
105 countParticleContactsPerRank[rank] *
106 particleContactObjSize,
107 rank);
108 singleton::mpi().receive(
109 bytesWall, countWallContactsPerRank[rank] * wallContactObjSize,
110 rank);
111 }
112 else {
113 std::memcpy(
114 bytesParticle,
115 (std::uint8_t*)contactContainer.particleContacts.data(),
116 countParticleContactsPerRank[singleton::mpi().bossId()] *
117 particleContactObjSize);
118 std::memcpy(bytesWall,
119 (std::uint8_t*)contactContainer.wallContacts.data(),
120 countWallContactsPerRank[singleton::mpi().bossId()] *
121 wallContactObjSize);
122 }
123 currParticle += countParticleContactsPerRank[rank];
124 currWall += countWallContactsPerRank[rank];
125 }
126 }
127 else {
128 PARTICLECONTACTTYPE* currParticle =
129 contactContainer.particleContacts.data();
130 WALLCONTACTTYPE* currWall = contactContainer.wallContacts.data();
131 std::uint8_t* bytesParticle = (std::uint8_t*)currParticle;
132 std::uint8_t* bytesWall = (std::uint8_t*)currWall;
133 singleton::mpi().send(
134 bytesParticle, localCountParticleContacts * particleContactObjSize,
135 singleton::mpi().bossId());
136 singleton::mpi().send(bytesWall,
137 localCountWallContacts * wallContactObjSize,
138 singleton::mpi().bossId());
139 }
140 //clout << "Bundling contact objects ... OK" << std::endl;
141
142 if (singleton::mpi().isMainProcessor()) {
143 container.combineContacts();
144 }
145
146 //clout << "Broadcasting contact objects ..." << std::endl;
147 std::uint8_t* containerParticlesBytes =
148 (std::uint8_t*)container.particleContacts.data();
149 singleton::mpi().bCast(containerParticlesBytes,
150 sumParticleContact * particleContactObjSize,
151 singleton::mpi().bossId());
152 std::uint8_t* containerWallBytes =
153 (std::uint8_t*)container.wallContacts.data();
154 singleton::mpi().bCast(containerWallBytes,
155 sumWallContact * wallContactObjSize,
156 singleton::mpi().bossId());
157 //singleton::mpi().barrier();
158 //clout << "Broadcasting contact objects ... OK" << std::endl;
159 /*
160 clout << "#######" << std::endl;
161 clout << "id: " << container.wallContacts[3].id << std::endl;
162 clout << "#######" << std::endl;
163 */
164 //std::cout << "size before: " << container.particleContacts.size() << std::endl;
165 container.cleanContacts();
166 //std::cout << "size after: " << container.particleContacts.size() << std::endl;
167 contactContainer = container;
168 }
169 }
170#endif
171}
class for marking output with some text
std::vector< PARTICLECONTACTTYPE > particleContacts
resizeable vector containing all particle-particle contacts
std::vector< WALLCONTACTTYPE > wallContacts
resizeable vector containg all particle-wall contacts

References olb::singleton::MpiManager::bCast(), olb::singleton::MpiManager::bossId(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::cleanContacts(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::combineContacts(), olb::singleton::MpiManager::getSize(), olb::singleton::MpiManager::isMainProcessor(), olb::singleton::mpi(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::particleContacts, olb::singleton::MpiManager::receive(), olb::singleton::MpiManager::send(), and olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::wallContacts.

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

◆ communicateContactsParallel()

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void olb::particles::contact::communicateContactsParallel ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
MPI_Comm particleContactDetectionComm,
MPI_Comm wallContactDetectionComm,
const Vector< bool, PARTICLETYPE::d > & periodicity )

Definition at line 743 of file particleContactCommunicationFunctions.h.

750{
751#ifdef PARALLEL_MODE_MPI
752 OstreamManager clout(std::cout, "contactCommunication");
753
754 communicateParallelContacts(contactContainer.wallContacts, sParticleSystem,
755 deltaX, wallContactDetectionComm, periodicity);
756
758 sParticleSystem, deltaX,
759 particleContactDetectionComm, periodicity);
760#endif
761}
void communicateParallelContacts(std::vector< CONTACTTYPE > &contacts, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm contactDetectionComm, const Vector< bool, PARTICLETYPE::d > &periodicity)

References communicateParallelContacts(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::particleContacts, and olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::wallContacts.

+ Here is the call graph for this function:

◆ communicateContactTreatmentResults()

template<typename T , typename PARTICLETYPE >
void olb::particles::contact::communicateContactTreatmentResults ( SuperParticleSystem< T, PARTICLETYPE > & particleSystem,
std::multimap< int, std::unique_ptr< std::uint8_t[]> > & dataMap,
MPI_Comm contactTreatmentComm )

Definition at line 1052 of file particleContactCommunicationFunctions.h.

1060{
1061#ifdef PARALLEL_MODE_MPI
1062 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
1063
1064 std::size_t serialSize =
1065 getContactTreatmentResultsSerialSize<T, PARTICLETYPE::d>();
1066
1067 //Create non blocking mpi helper
1069
1070 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
1071 communication::fillSendBuffer(dataMap, rankDataMapSorted, serialSize);
1072
1073 // Send mapped data
1074 communication::sendMappedData(
1075 rankDataMapSorted, particleSystem.getNeighbourRanks(), serialSize,
1076 contactTreatmentComm, mpiNbHelper);
1077
1078 receiveContactTreatmentResults(particleSystem, contactTreatmentComm,
1079 mpiNbHelper);
1080 }
1081#endif
1082}
const std::unordered_set< int > & getNeighbourRanks()
Helper class for non blocking MPI communication.
Definition mpiManager.h:51
void receiveContactTreatmentResults(SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, MPI_Comm contactTreatmentComm, singleton::MpiNonBlockingHelper &mpiNbHelper)

References olb::particles::communication::fillSendBuffer(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getNeighbourRanks(), receiveContactTreatmentResults(), and olb::particles::communication::sendMappedData().

+ Here is the call graph for this function:

◆ communicateParallelContacts()

template<typename T , typename PARTICLETYPE , typename CONTACTTYPE >
void olb::particles::contact::communicateParallelContacts ( std::vector< CONTACTTYPE > & contacts,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
MPI_Comm contactDetectionComm,
const Vector< bool, PARTICLETYPE::d > & periodicity )

Definition at line 667 of file particleContactCommunicationFunctions.h.

674{
675#ifdef PARALLEL_MODE_MPI
676 OstreamManager clout(std::cout, "contactCommunication");
677
678 // Retrieve rank of direct neighbours
679 auto& listNeighbourRanks = sParticleSystem.getNeighbourRanks();
680 constexpr std::size_t serialSize = CONTACTTYPE::getSerialSize();
681
682 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
683
684 for (CONTACTTYPE& contact : contacts) {
685 // Reset responsible rank because we evaluate the new one in the next step
686 resetResponsibleRank(contact);
687
688 if (!contact.isEmpty()) {
689 std::unordered_set<int> destRanks {evalDestRanksForDetectionCommunication(
690 contact, sParticleSystem, deltaX, periodicity)};
691
692 // Only new contacts need communication because they originate from the on-lattice
693 // contact detection. Known contacts are not updated during that step.
694 if (particles::contact::isResponsibleRankSet(contact)
695 // not new contacts need to be communicated as the responsible processors for each particle must know the responsible rank for contact treatment, which is evaluated above
696 && (contact.isNew() ||
697 contact.getResponsibleRank() == singleton::mpi().getRank())) {
698 for (const int destRank : destRanks) {
699 if (destRank != singleton::mpi().getRank()) {
700 std::unique_ptr<std::uint8_t[]> buffer(
701 new std::uint8_t[serialSize] {});
702 contact.serialize(buffer.get());
703 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
704 }
705 }
706 }
707
708 // Reset contact on other ranks to avoid unnecessary communication
709 //if (destRanks.find(singleton::mpi().getRank()) == destRanks.end()) {
710 // contact.resetMinMax();
711 //}
712 }
713 }
714
715 //Create non blocking mpi helper
716 singleton::MpiNonBlockingHelper mpiNbHelper;
717
718 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
719 communication::fillSendBuffer(dataMap, rankDataMapSorted, serialSize);
720
721 //Send mapped data
722 communication::sendMappedData(rankDataMapSorted, listNeighbourRanks,
723 serialSize, contactDetectionComm, mpiNbHelper);
724
725 //Receive data and iterate buffer
726 communication::receiveAndExecuteForData(
727 listNeighbourRanks, serialSize, contactDetectionComm, mpiNbHelper,
728 [&](int rankOrig, std::uint8_t* buffer) {
729 CONTACTTYPE newcontact;
730 newcontact.deserialize(buffer);
731
732#ifdef VERBOSE_CONTACT_COMMUNICATION
733 std::cout << "From Rank " << rankOrig << ": ";
734#endif
735
736 receiveContact(newcontact, sParticleSystem, contacts, rankOrig);
737 });
738#endif
739}
void resetResponsibleRank(CONTACTTYPE &contact)
void receiveContact(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &newcontact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, std::vector< CONTACTTYPE > &contacts, int rankOrig)
std::unordered_set< int > evalDestRanksForDetectionCommunication(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
evaluate responsible ranks for particle-particle contact

References evalDestRanksForDetectionCommunication(), olb::particles::communication::fillSendBuffer(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getNeighbourRanks(), olb::singleton::MpiManager::getRank(), isResponsibleRankSet(), olb::singleton::mpi(), olb::particles::communication::receiveAndExecuteForData(), receiveContact(), resetResponsibleRank(), and olb::particles::communication::sendMappedData().

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

◆ communicatePostContactTreatmentContacts() [1/2]

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE >
void olb::particles::contact::communicatePostContactTreatmentContacts ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
MPI_Comm particlePostContactTreatmentComm,
MPI_Comm wallPostContactTreatmentComm,
const Vector< bool, PARTICLETYPE::d > & periodicity )

It is necessary to communicate contacts so that no information is lost.

Definition at line 832 of file particleContactCommunicationFunctions.h.

840{
841#ifdef PARALLEL_MODE_MPI
842 OstreamManager clout(std::cout, "postContactTreatmentCommunication");
843
845 contactContainer.wallContacts, sParticleSystem, deltaX,
846 wallPostContactTreatmentComm, periodicity);
847
849 contactContainer.particleContacts, sParticleSystem, deltaX,
850 particlePostContactTreatmentComm, periodicity);
851#endif
852}
void communicatePostContactTreatmentContacts(std::vector< CONTACTTYPE > &contacts, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, MPI_Comm postContactTreatmentComm, const Vector< bool, PARTICLETYPE::d > &periodicity)

References communicatePostContactTreatmentContacts(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::particleContacts, and olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::wallContacts.

+ Here is the call graph for this function:

◆ communicatePostContactTreatmentContacts() [2/2]

template<typename T , typename PARTICLETYPE , typename CONTACTTYPE >
void olb::particles::contact::communicatePostContactTreatmentContacts ( std::vector< CONTACTTYPE > & contacts,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
MPI_Comm postContactTreatmentComm,
const Vector< bool, PARTICLETYPE::d > & periodicity )

Definition at line 764 of file particleContactCommunicationFunctions.h.

771{
772#ifdef PARALLEL_MODE_MPI
773 OstreamManager clout(std::cout, "postContactTreatmentCommunication");
774
775 // Retrieve rank of direct neighbours
776 auto& listNeighbourRanks = sParticleSystem.getNeighbourRanks();
777 constexpr std::size_t serialSize = CONTACTTYPE::getSerialSize();
778
779 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
780
781 for (CONTACTTYPE& contact : contacts) {
782 if (contact.getResponsibleRank() == singleton::mpi().getRank()) {
783 if (!contact.isEmpty()) {
784 std::unordered_set<int> destRanks {
786 contact, sParticleSystem, deltaX, periodicity)};
787 resetResponsibleRank(contact);
788 for (const int destRank : destRanks) {
789 if (destRank != singleton::mpi().getRank()) {
790 std::unique_ptr<std::uint8_t[]> buffer(
791 new std::uint8_t[serialSize] {});
792 contact.serialize(buffer.get());
793 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
794 }
795 }
796 }
797 }
798 // Otherwise reset min and max as they are not accurate anymore
799 else {
800 contact.resetMinMax();
801 }
802 }
803
804 //Create non blocking mpi helper
805 singleton::MpiNonBlockingHelper mpiNbHelper;
806
807 std::map<int, std::vector<std::uint8_t>> rankDataMapSorted;
808 communication::fillSendBuffer(dataMap, rankDataMapSorted, serialSize);
809
810 //Send mapped data
811 communication::sendMappedData(rankDataMapSorted, listNeighbourRanks,
812 serialSize, postContactTreatmentComm,
813 mpiNbHelper);
814
815 // Remove all empty contacts (= all contacts that were empty and all contacts where the process wasn't responsible) to ensure that 100% of the data send by the responsible rank is used
816 cleanContacts(contacts);
817
818 //Receive data and iterate buffer
819 communication::receiveAndExecuteForData(
820 listNeighbourRanks, serialSize, postContactTreatmentComm, mpiNbHelper,
821 [&](int rankOrig, std::uint8_t* buffer) {
822 CONTACTTYPE newcontact;
823 newcontact.deserialize(buffer);
824 receiveContact(newcontact, sParticleSystem, contacts, rankOrig);
825 });
826#endif
827}
void cleanContacts(std::vector< CONTACTTYPE > &contacts)
std::unordered_set< int > evalDestRanksForPostContactTreatmentCommunication(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, SuperParticleSystem< T, PARTICLETYPE > &sParticleSystem, const T deltaX, const Vector< bool, PARTICLETYPE::d > &periodicity)
evaluate ranks that touch both particles of a particle-particle contact

References cleanContacts(), evalDestRanksForPostContactTreatmentCommunication(), olb::particles::communication::fillSendBuffer(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getNeighbourRanks(), olb::singleton::MpiManager::getRank(), olb::singleton::mpi(), olb::particles::communication::receiveAndExecuteForData(), receiveContact(), resetResponsibleRank(), and olb::particles::communication::sendMappedData().

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

◆ correctBoundingBox()

template<typename T , unsigned D, typename F1 , typename F2 , typename F3 >
void olb::particles::contact::correctBoundingBox ( const PhysR< T, D > & min,
const PhysR< T, D > & max,
const T physDeltaX,
const unsigned contactBoxResolutionPerDirection,
F1 isInsideContact,
F2 resetContactBox,
F3 updateMinMax )

Definition at line 731 of file particleContactForceFunctions.h.

735{
736 const Vector<T, D> contactPhysDeltaX =
737 evalContactDeltaX(min, max, physDeltaX, contactBoxResolutionPerDirection);
738 Vector<long, D> startPos;
739 Vector<long, D> endPos;
740 evalStartAndEndPos(startPos, endPos, max, min, contactPhysDeltaX);
741 resetContactBox();
742
743 Vector<long, D> origin;
744 const bool originFound = evalStartingPoint(
745 startPos, endPos, contactPhysDeltaX, origin, isInsideContact);
746
747 if (originFound) {
748 PhysR<T, D> physOrigin;
749 for (unsigned iD = 0; iD < D; ++iD) {
750 physOrigin[iD] = contactPhysDeltaX[iD] * origin[iD];
751 }
752 updateMinMax(physOrigin);
753
754 for (unsigned i = 0; i < utilities::dimensions::convert<D>::neighborsCount;
755 ++i) {
756 const Vector<short, D> direction =
758 evalBoundingBoxRecursive(startPos, endPos, contactPhysDeltaX,
759 origin + direction, direction, isInsideContact,
760 updateMinMax);
761 }
762 }
763}
void evalStartAndEndPos(Vector< long, D > &startPos, Vector< long, D > &endPos, const PhysR< T, D > &max, const PhysR< T, D > &min, const PhysR< T, D > &contactPhysDeltaX)
constexpr Vector< T, D > evalContactDeltaX(const Vector< T, D > &min, const Vector< T, D > &max, const T physDeltaX, const unsigned contactBoxResolutionPerDirection)
bool evalStartingPoint(const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, Vector< long, D > &currPos, F1 isInsideContact)

References evalBoundingBoxRecursive(), evalContactDeltaX(), evalStartAndEndPos(), evalStartingPoint(), and updateMinMax().

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

◆ correctBoundingBoxNewContact()

template<typename T , unsigned D, typename F1 , typename F2 , typename F3 >
void olb::particles::contact::correctBoundingBoxNewContact ( PhysR< T, D > min,
PhysR< T, D > max,
T physDeltaX,
unsigned contactBoxResolutionPerDirection,
F1 signedDistanceToIntersection,
F2 resetContactBox,
F3 updateMinMax )

Definition at line 766 of file particleContactForceFunctions.h.

771{
772 Vector<T, D> contactPhysDeltaX =
773 evalContactDeltaX(min, max, physDeltaX, contactBoxResolutionPerDirection);
774
775 for (unsigned iD = 0; iD < D; ++iD) {
776 if (util::nearZero(min[iD] - max[iD])) {
777 min[iD] -= contactPhysDeltaX[iD];
778 /* T {0.5} * contactBoxResolutionPerDirection * contactPhysDeltaX[iD]; */
779 max[iD] += contactPhysDeltaX[iD];
780 /* T {0.5} * contactBoxResolutionPerDirection * contactPhysDeltaX[iD]; */
781 }
782 }
783
784 Vector<long, D> startPos;
785 Vector<long, D> endPos;
786 evalStartAndEndPos(startPos, endPos, max, min, contactPhysDeltaX);
787 resetContactBox();
788
789 forEachPosition(startPos, endPos, [&](const Vector<long, D>& pos) {
790 bool isOnContactSurface = false;
791 for (unsigned iD = 0; iD < D; ++iD) {
792 if (pos[iD] == startPos[iD] || pos[iD] == endPos[iD]) {
793 isOnContactSurface = true;
794 break;
795 }
796 }
797
798 if (isOnContactSurface) {
799 // Determine physical position
800 PhysR<T, D> physPos;
801 for (unsigned iD = 0; iD < D; ++iD) {
802 physPos[iD] = pos[iD] * contactPhysDeltaX[iD];
803 }
804
805 for (unsigned i = 0;
806 i < utilities::dimensions::convert<D>::neighborsCount; ++i) {
807 // do not regard direction if the neighbor is also on the surface
808 bool regardDirection = true;
809 //const Vector<long,D> neighborPos = pos + direction;
810 const Vector<long, D> neighborPos =
811 pos + Vector<long, D>(
812 utilities::dimensions::convert<D>::neighborDirections[i]);
813 for (unsigned iD = 0; iD < D; ++iD) {
814 if (neighborPos[iD] <= startPos[iD] ||
815 neighborPos[iD] >= endPos[iD]) {
816 regardDirection = false;
817 break;
818 }
819 }
820
821 if (regardDirection) {
822 const PhysR<T, D> normalizedDirection =
823 PhysR<T, D>(utilities::dimensions::convert<
824 D>::template normalizedNeighborDirections<T>[i]);
825 T distance;
826
827 // TODO: the sdf from intersections is not exact - replace with another option
828 // Only change min & max if boundary was found
829 /* if (util::distance( */
830 /* distance, physPos, direction, physDeltaX * T {1e-2}, */
831 /* [&](const Vector<T, D>& pos) { */
832 /* return signedDistanceToIntersection(pos); */
833 /* }, */
834 /* [&](const Vector<T, D>& pos) { */
835 /* return signedDistanceToIntersection(pos) < physDeltaX; */
836 /* })) { */
837 if (util::distance<T, D, false>(
838 distance, physPos, normalizedDirection, physDeltaX * T {1e-2},
839 [&](const Vector<T, D>& pos) {
840 return signedDistanceToIntersection(pos);
841 },
842 physDeltaX)) {
843 // Determine position of boundary in given direction
844 const PhysR<T, D> posOnBoundary =
845 physPos + distance * normalizedDirection;
846
847 // Attempt to update min and max with found position on contact boundary
848 updateMinMax(posOnBoundary);
849 }
850 }
851 }
852 }
853 });
854}
void updateMinMax(PhysR< T, D > &min, PhysR< T, D > &max, const PhysR< T, D > &pos)
bool distance(S &distance, const Vector< S, D > &origin, const Vector< S, D > &direction, S precision, S pitch, F1 isInside, F2 isInsideBoundingBox)

References evalContactDeltaX(), evalStartAndEndPos(), forEachPosition(), olb::util::nearZero(), and updateMinMax().

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

◆ createContactProperties()

template<typename T , unsigned N, typename F >
constexpr ContactProperties< T, N > olb::particles::contact::createContactProperties ( F f)
constexpr

Definition at line 98 of file contactProperties.h.

99{
100 ContactProperties<T, N> contactProperties {};
101 f(contactProperties);
102 return contactProperties;
103}
Object that stores properties which are necessary for the computation of contact forces N = number of...

◆ domainDimension()

template<typename T , unsigned D>
unsigned short olb::particles::contact::domainDimension ( PhysR< T, D > & min,
PhysR< T, D > & max )

Definition at line 44 of file contactHelpers.h.

45{
46 unsigned short dimension=0;
47 for (unsigned iD = 0; iD < D; ++iD) {
48 if(max[iD]>min[iD]){
49 dimension+=1;
50 }
51 }
52 return dimension;
53}

◆ evalApproxSurface()

template<typename T , unsigned D>
T olb::particles::contact::evalApproxSurface ( const Vector< T, D > & normalizedNormal,
const PhysR< T, D > & contactPhysDeltaX )

Takes a normalized normal and the voxel sizes and approximates the corresponding surface.

Definition at line 227 of file particleContactForceFunctions.h.

229{
230 T approxSurface;
231 if constexpr (D == 3) {
232 approxSurface =
233 contactPhysDeltaX[1] * contactPhysDeltaX[2] *
234 /* util::abs(normalizedNormal[0]); // * normalizedNormal[0]; */
235 normalizedNormal[0] * normalizedNormal[0];
236 approxSurface +=
237 contactPhysDeltaX[0] * contactPhysDeltaX[2] *
238 /* util::abs(normalizedNormal[1]); // * normalizedNormal[1]; */
239 normalizedNormal[1] * normalizedNormal[1];
240 approxSurface +=
241 contactPhysDeltaX[0] * contactPhysDeltaX[1] *
242 /* util::abs(normalizedNormal[2]); // * normalizedNormal[2]; */
243 normalizedNormal[2] * normalizedNormal[2];
244 }
245 else {
246 approxSurface =
247 contactPhysDeltaX[0] *
248 /* util::abs(normalizedNormal[1]); // * normalizedNormal[1]; */
249 normalizedNormal[1] * normalizedNormal[1];
250 approxSurface +=
251 contactPhysDeltaX[1] *
252 /* util::abs(normalizedNormal[0]); // * normalizedNormal[0]; */
253 normalizedNormal[0] * normalizedNormal[0];
254 }
255 return approxSurface;
256 /* return approxSurface / norm(contactPhysDeltaX); */
257}
+ Here is the caller graph for this function:

◆ evalBoundingBoxRecursive()

template<typename T , unsigned D, typename F1 , typename F2 >
void olb::particles::contact::evalBoundingBoxRecursive ( const Vector< long, D > & startPos,
const Vector< long, D > & endPos,
const Vector< T, D > & contactPhysDeltaX,
const Vector< long, D > & currPos,
const Vector< short, D > & dirIn,
F1 isInsideContact,
F2 updateMinMax )

Definition at line 687 of file particleContactForceFunctions.h.

693{
694 PhysR<T, D> currPhysPos;
695 for (unsigned iD = 0; iD < D; ++iD) {
696 currPhysPos[iD] = contactPhysDeltaX[iD] * currPos[iD];
697 }
698 bool isInside = isInsideContact(currPhysPos);
699 bool isInsideBB = true;
700 for (unsigned iD = 0; iD < D; ++iD) {
701 if (currPos[iD] < startPos[iD] || currPos[iD] > endPos[iD]) {
702 isInsideBB = false;
703 break;
704 }
705 }
706
707 // if point is inside, then we check the neighboring points too, otherwise they cannot be inside for convex shapes
708 if (isInside || isInsideBB) {
709 if (isInside) {
710 updateMinMax(currPhysPos);
711 }
712
713 forEachPosition(Vector<unsigned short, D>(0),
714 Vector<unsigned short, D>(abs(dirIn)),
715 [&](const Vector<unsigned short, D>& dirOut) {
716 if (norm(dirOut) >= 1) {
717 Vector<short, D> signedDirOut;
718 for (unsigned iD = 0; iD < D; ++iD) {
719 signedDirOut[iD] = dirOut[iD] * dirIn[iD];
720 }
721 const Vector<long, D> nextPos = signedDirOut + currPos;
723 startPos, endPos, contactPhysDeltaX, nextPos,
724 signedDirOut, isInsideContact, updateMinMax);
725 }
726 });
727 }
728}
constexpr void forEachPosition(Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)
void evalBoundingBoxRecursive(const Vector< long, D > &startPos, const Vector< long, D > &endPos, const Vector< T, D > &contactPhysDeltaX, const Vector< long, D > &currPos, const Vector< short, D > &dirIn, F1 isInsideContact, F2 updateMinMax)
std::enable_if_t< std::is_arithmetic< T >::type::value, T > abs(T x)
Definition util.h:396

References olb::abs(), evalBoundingBoxRecursive(), forEachPosition(), olb::norm(), and updateMinMax().

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

◆ evalCircumRadius() [1/3]

template<typename T , typename PARTICLETYPE >
T olb::particles::contact::evalCircumRadius ( Particle< T, PARTICLETYPE > & particle,
T const physDeltaX )

Definition at line 98 of file contactFunctions.h.

99{
100 using namespace descriptors;
101 auto sIndicator = particle.template getField<SURFACE, SINDICATOR>();
102 return evalCircumRadius(particle, physDeltaX, sIndicator->getCircumRadius(),
103 sIndicator->getEpsilon());
104}
T evalCircumRadius(T const contactDetectionDistance, T const circumRadius, T const epsilon)

References evalCircumRadius().

+ Here is the call graph for this function:

◆ evalCircumRadius() [2/3]

template<typename T , typename PARTICLETYPE >
T olb::particles::contact::evalCircumRadius ( Particle< T, PARTICLETYPE > & particle,
T const physDeltaX,
T const circumRadius,
T const epsilon )

Definition at line 89 of file contactFunctions.h.

91{
92 const T contactDetectionDistance =
93 evalContactDetectionDistance(particle, physDeltaX);
94 return evalCircumRadius(contactDetectionDistance, circumRadius, epsilon);
95}
T evalContactDetectionDistance(Particle< T, PARTICLETYPE > &particle, T const physDeltaX)

References evalCircumRadius(), and evalContactDetectionDistance().

+ Here is the call graph for this function:

◆ evalCircumRadius() [3/3]

template<typename T >
T olb::particles::contact::evalCircumRadius ( T const contactDetectionDistance,
T const circumRadius,
T const epsilon )

Definition at line 82 of file contactFunctions.h.

84{
85 return circumRadius - epsilon + util::max(epsilon, contactDetectionDistance);
86}

References olb::util::max().

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

◆ evalContactDeltaX()

template<typename T , unsigned D>
constexpr Vector< T, D > olb::particles::contact::evalContactDeltaX ( const Vector< T, D > & min,
const Vector< T, D > & max,
const T physDeltaX,
const unsigned contactBoxResolutionPerDirection )
constexpr

Definition at line 148 of file particleContactForceFunctions.h.

151{
152 // Adaptiv resolution of found contact
153 const Vector<T, D> boxSize = max - min;
154 Vector<T, D> contactPhysDeltaX = boxSize;
155 std::array<bool, D> fallbackUsed {[]() {
156 static_assert(D == 2 || D == 3, "Only D=2 and D=3 are supported");
157 if constexpr (D == 3) {
158 return std::array<bool, D> {false, false, false};
159 }
160 else {
161 return std::array<bool, D> {false, false};
162 }
163 }()};
164
165 for (unsigned iD = 0; iD < D; ++iD) {
166 contactPhysDeltaX[iD] /= contactBoxResolutionPerDirection;
167 if (util::nearZero(contactPhysDeltaX[iD])) {
168 contactPhysDeltaX[iD] = physDeltaX / contactBoxResolutionPerDirection;
169 fallbackUsed[iD] = true;
170 }
171 }
172
173 // If fallback was used, check if in another dimension the deltaX is known.
174 // If yes, then use the smallest known deltaX. Otherwise, keep the fallback.
175 // This is possible because any dimenison for which we cannot find a proper deltaX has probably even smaller lenghts than the others.
176 for (unsigned iD = 0; iD < D; ++iD) {
177 if (fallbackUsed[iD]) {
178 for (unsigned iD2 = 0; iD2 < D; ++iD2) {
179 if (iD != iD2) {
180 contactPhysDeltaX[iD] =
181 util::min(contactPhysDeltaX[iD], contactPhysDeltaX[iD2]);
182 }
183 }
184 }
185 }
186
187 return contactPhysDeltaX;
188}

References olb::util::min(), and olb::util::nearZero().

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

◆ evalContactDetectionDistance()

template<typename T , typename PARTICLETYPE >
T olb::particles::contact::evalContactDetectionDistance ( Particle< T, PARTICLETYPE > & particle,
T const physDeltaX )

Definition at line 59 of file contactFunctions.h.

61{
62 constexpr unsigned D = PARTICLETYPE::d;
63
64 if constexpr (particles::access::providesContactMaterial<PARTICLETYPE>()) {
65 constexpr T factor = []() {
66 static_assert(D == 2 || D == 3, "Only D=2 and D=3 are supported");
67 // TODO: Use with c++20
68 //return T{0.5} * (D == 3 ? std::numbers::sqrt3_v<T> : std::numbers::sqrt2_v<T>);
69 return T {0.5} * (D == 3 ? 1.7320508075688772935 : 1.4142135623730950488);
70 }();
71 return factor * physDeltaX +
72 particles::access::getEnlargementForContact(particle);
73 }
74 else {
75 return T {0};
76 }
77
78 __builtin_unreachable();
79}

References olb::particles::access::getEnlargementForContact().

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

◆ evalContactPosition()

template<typename T , typename PARTICLETYPE , typename F >
PhysR< T, PARTICLETYPE::d > olb::particles::contact::evalContactPosition ( Particle< T, PARTICLETYPE > & particle,
const PhysR< T, PARTICLETYPE::d > & particlePos,
const PhysR< T, PARTICLETYPE::d > & contactPos,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 162 of file particleContactDetectionFunctions.h.

168{
169 using namespace descriptors;
170
171 if constexpr (!(isPeriodic(getSetupPeriodicity()))) {
172 return contactPos;
173 }
174 else {
175 auto sIndicator = particle.template getField<SURFACE, SINDICATOR>();
176 const T circumRadius = sIndicator->getCircumRadius() -
177 sIndicator->getEpsilon() +
178 util::max(sIndicator->getEpsilon(), 0.5 * deltaX);
179
180 PhysR<T, PARTICLETYPE::d> ghostPos = contactPos;
181 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
182 T const particleMin = particlePos[i] - circumRadius;
183 T const particleMax = particlePos[i] + circumRadius;
184 if (particleMin > contactPos[i] && getSetupPeriodicity()[i]) {
185 ghostPos[i] = communication::movePositionToEnd(
186 contactPos[i], cellMax[i], cellMin[i]);
187 }
188 else if (particleMax < contactPos[i] && getSetupPeriodicity()[i]) {
189 ghostPos[i] = communication::movePositionToStart(
190 contactPos[i], cellMax[i], cellMin[i]);
191 }
192 }
193 return ghostPos;
194 }
195}
constexpr bool isPeriodic(const Vector< bool, D > &periodic)

References olb::particles::isPeriodic(), olb::util::max(), olb::particles::communication::movePositionToEnd(), and olb::particles::communication::movePositionToStart().

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

◆ evalCurrentDampingFactor()

template<typename T , unsigned D, typename CONTACTTYPE >
constexpr T olb::particles::contact::evalCurrentDampingFactor ( CONTACTTYPE & contact,
const T coefficientOfRestitution,
const Vector< T, D > & initialRelativeNormalVelocity )
constexpr

Definition at line 52 of file particleContactForceFunctions.h.

54{
55 if (contact.getDampingFactor() < 0) {
56 contact.setDampingFactorFromInitialVelocity(
57 coefficientOfRestitution, norm(initialRelativeNormalVelocity));
58 }
59 return contact.getDampingFactor();
60}

References olb::norm().

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

◆ evalDampingFactor()

template<typename T >
constexpr T olb::particles::contact::evalDampingFactor ( const T coefficientOfRestitution,
const T initialRelativeVelocityMagnitude )
constexpr

Calculates the damping factor according to Carvalho & Martins (2019) (10.1016/j.mechmachtheory.2019.03.028)

Definition at line 46 of file contactFunctions.h.

48{
49 // This case should never happen, but could for example due to initial conditions
50 if (initialRelativeVelocityMagnitude <= 0) {
51 return 0;
52 }
53 return 1.5 * (1 - coefficientOfRestitution) *
54 (11 - coefficientOfRestitution) / (1 + 9 * coefficientOfRestitution) /
55 initialRelativeVelocityMagnitude;
56}
+ Here is the caller graph for this function:

◆ evalDestRanksForDetectionCommunication() [1/2]

template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > olb::particles::contact::evalDestRanksForDetectionCommunication ( ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
const Vector< bool, PARTICLETYPE::d > & periodicity )

evaluate responsible ranks for particle-particle contact

Definition at line 257 of file particleContactCommunicationFunctions.h.

262{
263 using namespace descriptors;
264 auto& superStructure = sParticleSystem.getSuperStructure();
265 auto& loadBalancer = superStructure.getLoadBalancer();
266 /* auto& cuboidGeometry = superStructure.getCuboidGeometry(); */
267
268 // Set instead of unordered_set so that it's sorted
269 // Therefore, it is easier to find the the rank with smallest ID
270 std::set<int> intersectingRanks {};
271 std::array<int, 2> responsibleRank = {-1, -1};
272 std::array<std::set<int>, 2> touchedRanks {};
273 std::unordered_set<int> destRanks {};
274
275 // Function that is called on failure
276 const auto errorTreatment = [&contact, &destRanks]() {
277 contact.resetMinMax();
278 resetResponsibleRank(contact);
279 destRanks.clear();
280 };
281
282 // Iterate over all particles to populate responsible and touched ranks of each particle in the contact
283 communication::forParticlesInSuperParticleSystem<T, PARTICLETYPE,
284 conditions::valid_particles>(
285 sParticleSystem,
286 [&](Particle<T, PARTICLETYPE>& particle,
287 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
288 const std::size_t globalParticleID =
289 particle.template getField<PARALLELIZATION, ID>();
290
291 for (unsigned short index = 0; index < 2; ++index) {
292 if (globalParticleID == contact.getIDs()[index]) {
293 const int globiCcenter =
294 particle.template getField<PARALLELIZATION, IC>();
295 responsibleRank[index] = loadBalancer.rank(globiCcenter);
296 touchedRanks[index].insert(responsibleRank[index]);
297
298 const PhysR<T, PARTICLETYPE::d> position =
299 access::getPosition(particle);
300 const T circumRadius = evalCircumRadius(particle, deltaX);
301 communication::getSurfaceTouchingICs(
302 sParticleSystem, position, circumRadius, periodicity,
303 globiCcenter, [&](const int iC) {
304 touchedRanks[index].insert(loadBalancer.rank(iC));
305 });
306 }
307 }
308 });
309
310 // If at least one particle has no touched cuboids then cancel function call
311 // (this should be caused by an invalid particle that somehow still has an existing contact)
312 if (touchedRanks[0].empty() || touchedRanks[1].empty() ||
313 responsibleRank[0] < 0 || responsibleRank[1] < 0) {
314 errorTreatment();
315 }
316 // If both particles have the same responsible rank then let that rank take care of the contact
317 else if (responsibleRank[0] == responsibleRank[1]) {
318 destRanks.insert(responsibleRank[0]);
319 contact.setResponsibleRank(responsibleRank[0]);
320 }
321 // If not, then determine treatment rank from intersection of ranks that touch the particles
322 else {
323 std::set_intersection(
324 touchedRanks[0].begin(), touchedRanks[0].end(), touchedRanks[1].begin(),
325 touchedRanks[1].end(),
326 std::inserter(intersectingRanks, intersectingRanks.begin()));
327
328 /*
329 * It's possible that no intersection is found, if a rank loses responsibility
330 * for the contact, but still holds the old information. At the same time,
331 * the contact of both particles breaks, and they are also on different ranks,
332 * without any processor that knows both. This is very unlikely, but it can
333 * happen.
334 * However, the following simple if-condition shouldn't be expensive as it is
335 * almost always true.
336 */
337 if (!intersectingRanks.empty()) {
338 destRanks.insert(responsibleRank[0]);
339 destRanks.insert(responsibleRank[1]);
340
341 // Sort responsible ranks so that the following is consistent
342 if (responsibleRank[0] > responsibleRank[1]) {
343 std::swap(responsibleRank[0], responsibleRank[1]);
344 }
345
346 // First use one of the responsible ranks if they know both particles
347 if (intersectingRanks.find(responsibleRank[0]) !=
348 intersectingRanks.end()) {
349 contact.setResponsibleRank(responsibleRank[0]);
350 }
351 else if (intersectingRanks.find(responsibleRank[1]) !=
352 intersectingRanks.end()) {
353 contact.setResponsibleRank(responsibleRank[1]);
354 }
355 // Otherwise use smallest rank of intersection
356 else {
357 const int responsibleRankContact = *intersectingRanks.begin();
358 contact.setResponsibleRank(responsibleRankContact);
359 destRanks.insert(responsibleRankContact);
360 }
361 }
362 else {
363 errorTreatment();
364 }
365 }
366
367#ifdef VERBOSE_CONTACT_COMMUNICATION
368 std::cout << "Contact of ids " << contact.getIDs()[0] << " & "
369 << contact.getIDs()[1] << " goes to " << destRanks << " and "
370 << contact.getResponsibleRank()
371 << " is responsible for the calculation (Rank "
372 << singleton::mpi().getRank() << ")"
373 << " the intersection was " << intersectingRanks
374 << " from touched ranks " << touchedRanks[0] << " and "
375 << touchedRanks[1] << std::endl;
376#endif
377
378 return destRanks;
379}
LoadBalancer< T > & getLoadBalancer()
Read and write access to the load balancer.
SuperStructure< T, PARTICLETYPE::d > & getSuperStructure()
constexpr const std::array< std::size_t, 2 > & getIDs() const
Read access to particle IDs.
constexpr const int & getResponsibleRank() const
Read access to the responsible rank.
constexpr void resetMinMax()
Reset min and max to default values.
constexpr void setResponsibleRank(const int &rank)
Set processor that is responsible for contact treatment.

References evalCircumRadius(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getIDs(), olb::SuperStructure< T, D >::getLoadBalancer(), olb::particles::access::getPosition(), olb::singleton::MpiManager::getRank(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getResponsibleRank(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getSuperStructure(), olb::particles::communication::getSurfaceTouchingICs(), olb::singleton::mpi(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::resetMinMax(), resetResponsibleRank(), and olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::setResponsibleRank().

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

◆ evalDestRanksForDetectionCommunication() [2/2]

template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > olb::particles::contact::evalDestRanksForDetectionCommunication ( WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
const Vector< bool, PARTICLETYPE::d > & periodicity )

evaluate responsible rank for solid boundary contact

Definition at line 383 of file particleContactCommunicationFunctions.h.

387{
388 using namespace descriptors;
389 auto& superStructure = sParticleSystem.getSuperStructure();
390 auto& loadBalancer = superStructure.getLoadBalancer();
391
392 bool isSuccessful = false;
393 std::unordered_set<int> destRanks {};
394 int destRank;
395 // Find responsible rank
396 communication::forParticlesInSuperParticleSystem<T, PARTICLETYPE,
398 sParticleSystem,
399 [&](Particle<T, PARTICLETYPE>& particle,
400 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
401 const std::size_t globalParticleID =
402 particle.template getField<PARALLELIZATION, ID>();
403 if (globalParticleID == contact.getParticleID()) {
404 std::size_t globiCcenter =
405 particle.template getField<PARALLELIZATION, IC>();
406 destRank = loadBalancer.rank(globiCcenter);
407 isSuccessful = true;
408 }
409 });
410
411 if (isSuccessful) {
412 contact.setResponsibleRank(destRank);
413 if (destRank != singleton::mpi().getRank()) {
414 destRanks.insert(destRank);
415 }
416
417#ifdef VERBOSE_CONTACT_COMMUNICATION
418 std::cout << "Contact of id " << contact.getParticleID()
419 << " & solid boundary " << contact.getWallID() << " goes to "
420 << destRanks << std::endl;
421#endif
422 }
423
424 return destRanks;
425}
constexpr void setResponsibleRank(const int &rank)
Set processor that is responsible for contact treatment.
constexpr const std::size_t & getParticleID() const
Read access to particle ID.
constexpr unsigned getWallID() const
Read access to wall matreial.

References olb::particles::communication::forParticlesInSuperParticleSystem(), olb::SuperStructure< T, D >::getLoadBalancer(), olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::getParticleID(), olb::singleton::MpiManager::getRank(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getSuperStructure(), olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::getWallID(), olb::singleton::mpi(), and olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::setResponsibleRank().

+ Here is the call graph for this function:

◆ evalDestRanksForPostContactTreatmentCommunication() [1/2]

template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > olb::particles::contact::evalDestRanksForPostContactTreatmentCommunication ( ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
const Vector< bool, PARTICLETYPE::d > & periodicity )

evaluate ranks that touch both particles of a particle-particle contact

Definition at line 429 of file particleContactCommunicationFunctions.h.

434{
435 using namespace descriptors;
436 auto& superStructure = sParticleSystem.getSuperStructure();
437 auto& loadBalancer = superStructure.getLoadBalancer();
438 auto& cuboidGeometry = superStructure.getCuboidGeometry();
439
440 std::unordered_set<int> destRanks;
441 std::array<std::set<int>, 2> touchedRanks;
442
443 // Iterate over all particles to populate touched ranks of each particle in the contact
444 communication::forParticlesInSuperParticleSystem<T, PARTICLETYPE,
446 sParticleSystem,
447 [&](Particle<T, PARTICLETYPE>& particle,
448 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
449 const std::size_t globalParticleID =
450 particle.template getField<PARALLELIZATION, ID>();
451
452 for (unsigned short index = 0; index < 2; ++index) {
453 if (globalParticleID == contact.getIDs()[index]) {
454 const PhysR<T, PARTICLETYPE::d> position =
455 access::getPosition(particle);
456 // the particle moved, therefore, the iC may have changed
457 int globiCcenter;
458 const bool cuboidFound = communication::getCuboid(
459 cuboidGeometry, periodicity, position, globiCcenter);
460 if (cuboidFound) {
461 touchedRanks[index].insert(loadBalancer.rank(globiCcenter));
462
463 const T circumRadius = evalCircumRadius(particle, deltaX);
464 communication::getSurfaceTouchingICs(
465 sParticleSystem, position, circumRadius, periodicity,
466 globiCcenter, [&](const int iC) {
467 touchedRanks[index].insert(loadBalancer.rank(iC));
468 });
469 }
470 }
471 }
472 });
473
474 std::set_intersection(touchedRanks[0].begin(), touchedRanks[0].end(),
475 touchedRanks[1].begin(), touchedRanks[1].end(),
476 std::inserter(destRanks, destRanks.begin()));
477
478#ifdef VERBOSE_CONTACT_COMMUNICATION
479 std::cout << "Contact of ids " << contact.getIDs()[0] << " & "
480 << contact.getIDs()[1] << " goes to " << destRanks << " and "
481 << contact.getResponsibleRank()
482 << " is responsible for the calculation (Rank "
483 << singleton::mpi().getRank() << ")" << '\n'
484 << "Touched ranks of 1. particle: " << touchedRanks[0]
485 << " and touched ranks of 2. particle: " << touchedRanks[1]
486 << std::endl;
487#endif
488
489 return destRanks;
490}

References evalCircumRadius(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::particles::communication::getCuboid(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getIDs(), olb::SuperStructure< T, D >::getLoadBalancer(), olb::particles::access::getPosition(), olb::singleton::MpiManager::getRank(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getResponsibleRank(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getSuperStructure(), olb::particles::communication::getSurfaceTouchingICs(), and olb::singleton::mpi().

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

◆ evalDestRanksForPostContactTreatmentCommunication() [2/2]

template<typename T , typename PARTICLETYPE , bool CONVEX>
std::unordered_set< int > olb::particles::contact::evalDestRanksForPostContactTreatmentCommunication ( WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
const T deltaX,
const Vector< bool, PARTICLETYPE::d > & periodicity )

evaluate ranks that touch the particle of a particle-wall contact

Definition at line 494 of file particleContactCommunicationFunctions.h.

498{
499 using namespace descriptors;
500 auto& superStructure = sParticleSystem.getSuperStructure();
501 auto& loadBalancer = superStructure.getLoadBalancer();
502 auto& cuboidGeometry = superStructure.getCuboidGeometry();
503
504 std::unordered_set<int> destRanks;
505
506 // Find responsible rank
507 communication::forParticlesInSuperParticleSystem<T, PARTICLETYPE,
509 sParticleSystem,
510 [&](Particle<T, PARTICLETYPE>& particle,
511 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
512 const std::size_t globalParticleID =
513 particle.template getField<PARALLELIZATION, ID>();
514 if (globalParticleID == contact.getParticleID()) {
515 const PhysR<T, PARTICLETYPE::d> position =
516 access::getPosition(particle);
517 // the particle moved, therefore, the iC may have changed
518 int globiCcenter;
519 const bool cuboidFound = communication::getCuboid(
520 cuboidGeometry, periodicity, position, globiCcenter);
521 if (cuboidFound) {
522 destRanks.insert(loadBalancer.rank(globiCcenter));
523
524 const T circumRadius {evalCircumRadius(particle, deltaX)};
525 communication::getSurfaceTouchingICs(
526 sParticleSystem, position, circumRadius, periodicity,
527 globiCcenter, [&](const int iC) {
528 destRanks.insert(loadBalancer.rank(iC));
529 });
530 }
531 }
532 });
533
534#ifdef VERBOSE_CONTACT_COMMUNICATION
535 std::cout << "Contact of id " << contact.getParticleID()
536 << " & solid boundary " << contact.getWallID() << " goes to "
537 << destRanks << " and rank " << contact.getResponsibleRank()
538 << " is responsible for the calculation" << std::endl;
539#endif
540
541 return destRanks;
542}
constexpr const int & getResponsibleRank() const
Read access to the responsible rank.

References evalCircumRadius(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::particles::communication::getCuboid(), olb::SuperStructure< T, D >::getLoadBalancer(), olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::getParticleID(), olb::particles::access::getPosition(), olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::getResponsibleRank(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getSuperStructure(), olb::particles::communication::getSurfaceTouchingICs(), and olb::particles::contact::WallContactArbitraryFromOverlapVolume< T, D, CONVEX >::getWallID().

+ Here is the call graph for this function:

◆ evalEffectiveYoungModulus()

template<typename T >
constexpr T olb::particles::contact::evalEffectiveYoungModulus ( T E1,
T E2,
T nu1,
T nu2 )
constexpr

Definition at line 38 of file contactFunctions.h.

39{
40 const T denominator = (1 - nu1 * nu1) / E1 + (1 - nu2 * nu2) / E2;
41 return T {1} / denominator;
42}

◆ evalForceViaVolumeCoefficient() [1/2]

template<typename T >
constexpr T olb::particles::contact::evalForceViaVolumeCoefficient ( const T contactVolume,
const T contactSurface,
const T indentationDepth )
constexpr

Definition at line 522 of file particleContactForceFunctions.h.

525{
526 constexpr T a = 0.6118229;
527 constexpr T b = 1.900093;
528 constexpr T c = 0.651237;
529
530 const T x = indentationDepth * contactSurface / contactVolume;
531 const T k = a + b * util::exp(-c * x);
532 return k;
533}

References olb::util::exp().

+ Here is the call graph for this function:

◆ evalForceViaVolumeCoefficient() [2/2]

template<typename T , unsigned D>
T olb::particles::contact::evalForceViaVolumeCoefficient ( const Vector< T, D > & min,
const Vector< T, D > & max,
T overlapVolume )

Definition at line 504 of file particleContactForceFunctions.h.

506{
507 const T a = util::log(2. / 3.) / util::log(2.);
508 const T m = 2. / util::sqrt(M_PI) * util::pow(4. / M_PI, -a);
509
510 Vector<T, D> length = max - min;
511 T boundingBoxVolume = 1;
512 for (unsigned iD = 0; iD < D; ++iD) {
513 boundingBoxVolume *= length[iD];
514 }
515
516 const T k =
517 m * util::pow(util::max(boundingBoxVolume / overlapVolume, T {1}), a);
518 return k;
519}
#define M_PI

References olb::util::log(), M_PI, olb::util::max(), olb::util::pow(), and olb::util::sqrt().

+ Here is the call graph for this function:

◆ evalRelativeNormalVelocity()

template<typename T , unsigned D>
constexpr Vector< T, D > olb::particles::contact::evalRelativeNormalVelocity ( const Vector< T, D > & contactNormal,
const Vector< T, D > & relVel )
constexpr

Definition at line 83 of file particleContactForceFunctions.h.

85{
86 return Vector<T, D>((relVel * contactNormal) * contactNormal);
87}
+ Here is the caller graph for this function:

◆ evalRelativeVelocity() [1/2]

template<typename T , typename PARTICLETYPE >
constexpr Vector< T, PARTICLETYPE::d > olb::particles::contact::evalRelativeVelocity ( Particle< T, PARTICLETYPE > & particle,
const Vector< T, PARTICLETYPE::d > & position )
constexpr

Definition at line 75 of file particleContactForceFunctions.h.

77{
78 return particles::dynamics::calculateLocalVelocity(particle, position);
79}

References olb::particles::dynamics::calculateLocalVelocity().

+ Here is the call graph for this function:

◆ evalRelativeVelocity() [2/2]

template<typename T , typename PARTICLETYPE >
constexpr Vector< T, PARTICLETYPE::d > olb::particles::contact::evalRelativeVelocity ( Particle< T, PARTICLETYPE > & particleA,
Particle< T, PARTICLETYPE > & particleB,
const Vector< T, PARTICLETYPE::d > & position )
constexpr

Returns the relative velocity of two particles at a defined position.

Definition at line 65 of file particleContactForceFunctions.h.

68{
69 return particles::dynamics::calculateLocalVelocity(particleA, position) -
70 particles::dynamics::calculateLocalVelocity(particleB, position);
71}

References olb::particles::dynamics::calculateLocalVelocity().

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

◆ evalStartAndEndPos()

template<typename T , unsigned D>
void olb::particles::contact::evalStartAndEndPos ( Vector< long, D > & startPos,
Vector< long, D > & endPos,
const PhysR< T, D > & max,
const PhysR< T, D > & min,
const PhysR< T, D > & contactPhysDeltaX )

Definition at line 493 of file particleContactForceFunctions.h.

496{
497 for (unsigned iD = 0; iD < D; ++iD) {
498 startPos[iD] = util::floor(min[iD] / contactPhysDeltaX[iD]);
499 endPos[iD] = util::ceil(max[iD] / contactPhysDeltaX[iD]);
500 }
501}

References olb::util::ceil(), and olb::util::floor().

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

◆ evalStartingPoint()

template<typename T , unsigned D, typename F1 >
bool olb::particles::contact::evalStartingPoint ( const Vector< long, D > & startPos,
const Vector< long, D > & endPos,
const Vector< T, D > & contactPhysDeltaX,
Vector< long, D > & currPos,
F1 isInsideContact )

Definition at line 663 of file particleContactForceFunctions.h.

667{
668 bool pointFound = false;
669
670 forEachPositionWithBreak(startPos, endPos,
671 [&](const Vector<long, D>& pos, bool& breakLoops) {
672 PhysR<T, D> physPos;
673 for (unsigned iD = 0; iD < D; ++iD) {
674 physPos[iD] = contactPhysDeltaX[iD] * pos[iD];
675 }
676 if (isInsideContact(physPos)) {
677 currPos = pos;
678 pointFound = true;
679 breakLoops = true;
680 }
681 });
682
683 return pointFound;
684}
constexpr void forEachPositionWithBreak(Vector< T, 3 > startPos, Vector< T, 3 > endPos, F f)

References forEachPositionWithBreak().

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

◆ extendContactTreatmentResultsDataMap()

template<typename T , unsigned D>
void olb::particles::contact::extendContactTreatmentResultsDataMap ( const std::size_t & globalParticleID,
Vector< T, D > & force,
Vector< T, utilities::dimensions::convert< D >::rotation > & torque,
const int destRank,
std::multimap< int, std::unique_ptr< std::uint8_t[]> > & dataMap )

Definition at line 897 of file particleContactCommunicationFunctions.h.

902{
903#ifdef PARALLEL_MODE_MPI
904 // Create communicatables
905 std::array<std::size_t, 1> commGlobalParticleID {globalParticleID};
906 ConcreteCommunicatable communicatableID =
907 ConcreteCommunicatable(commGlobalParticleID);
908 ConcreteCommunicatable communicatableForce = ConcreteCommunicatable(force);
909 ConcreteCommunicatable communicatableTorque = ConcreteCommunicatable(torque);
910
911 // Setting dimension dependent indices
912 const std::vector<unsigned> indicesID {0};
913 std::vector<unsigned> indicesForce;
914 if constexpr (D == 3) {
915 indicesForce = std::vector<unsigned> {0, 1, 2};
916 }
917 else {
918 indicesForce = std::vector<unsigned> {0, 1};
919 }
920 std::vector<unsigned> indicesTorque;
921 if constexpr (D == 3) {
922 indicesTorque = indicesForce;
923 }
924 else {
925 indicesTorque = std::vector<unsigned> {0};
926 }
927
928 // Retrieve serial size
929 const std::size_t serialSize = communicatableID.size(indicesID) +
930 communicatableForce.size(indicesForce) +
931 communicatableTorque.size(indicesTorque);
932
933 std::unique_ptr<std::uint8_t[]> buffer(new std::uint8_t[serialSize] {});
934 std::uint8_t* bufferRaw = buffer.get();
935 std::size_t serialIdx = communicatableID.serialize(indicesID, bufferRaw);
936 serialIdx +=
937 communicatableForce.serialize(indicesForce, &bufferRaw[serialIdx]);
938 serialIdx +=
939 communicatableTorque.serialize(indicesTorque, &bufferRaw[serialIdx]);
940
941 dataMap.insert(std::make_pair(destRank, std::move(buffer)));
942#ifdef VERBOSE_CONTACT_COMMUNICATION
943 std::cout << "Rank " << singleton::mpi().getRank()
944 << " sends contact treatment results of particle "
945 << globalParticleID << " to " << destRank << std::endl;
946#endif
947#endif
948}
std::size_t serialize(ConstSpan< CellID > indices, std::uint8_t *buffer) const override
Serialize data at locations indices to buffer
std::size_t size(ConstSpan< CellID > indices) const override
Get serialized size for data at locations indices

References olb::singleton::MpiManager::getRank(), olb::singleton::mpi(), olb::ConcreteCommunicatable< COMMUNICATEE >::serialize(), and olb::ConcreteCommunicatable< COMMUNICATEE >::size().

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

◆ forEachPosition() [1/2]

template<typename T , typename F >
constexpr void olb::particles::contact::forEachPosition ( Vector< T, 2 > startPos,
Vector< T, 2 > endPos,
F f )
constexpr

Definition at line 103 of file particleContactForceFunctions.h.

104{
105 Vector<T, 2> pos;
106 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
107 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
108 f(pos);
109 }
110 }
111}

◆ forEachPosition() [2/2]

template<typename T , typename F >
constexpr void olb::particles::contact::forEachPosition ( Vector< T, 3 > startPos,
Vector< T, 3 > endPos,
F f )
constexpr

Definition at line 90 of file particleContactForceFunctions.h.

91{
92 Vector<T, 3> pos;
93 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
94 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
95 for (pos[2] = startPos[2]; pos[2] <= endPos[2]; ++pos[2]) {
96 f(pos);
97 }
98 }
99 }
100}
+ Here is the caller graph for this function:

◆ forEachPositionWithBreak() [1/2]

template<typename T , typename F >
constexpr void olb::particles::contact::forEachPositionWithBreak ( Vector< T, 2 > startPos,
Vector< T, 2 > endPos,
F f )
constexpr

Definition at line 132 of file particleContactForceFunctions.h.

134{
135 bool breakLoops = false;
136 Vector<T, 2> pos;
137 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
138 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
139 f(pos, breakLoops);
140 if (breakLoops) {
141 return;
142 }
143 }
144 }
145}

◆ forEachPositionWithBreak() [2/2]

template<typename T , typename F >
constexpr void olb::particles::contact::forEachPositionWithBreak ( Vector< T, 3 > startPos,
Vector< T, 3 > endPos,
F f )
constexpr

Definition at line 114 of file particleContactForceFunctions.h.

116{
117 bool breakLoops = false;
118 Vector<T, 3> pos;
119 for (pos[0] = startPos[0]; pos[0] <= endPos[0]; ++pos[0]) {
120 for (pos[1] = startPos[1]; pos[1] <= endPos[1]; ++pos[1]) {
121 for (pos[2] = startPos[2]; pos[2] <= endPos[2]; ++pos[2]) {
122 f(pos, breakLoops);
123 if (breakLoops) {
124 return;
125 }
126 }
127 }
128 }
129}
+ Here is the caller graph for this function:

◆ getContactIterator()

template<typename CONTACTTYPE >
auto olb::particles::contact::getContactIterator ( std::vector< CONTACTTYPE > & contacts,
const std::function< bool(const CONTACTTYPE &)> condition )

Definition at line 38 of file particleContactDetectionFunctions.h.

40{
41 auto contactIt = std::find_if(contacts.begin(), contacts.end(),
42 [&condition](const auto& contact) -> bool {
43 return condition(contact);
44 });
45 return contactIt;
46}
+ Here is the caller graph for this function:

◆ getContactTreatmentResultsSerialSize()

template<typename T , unsigned D>
int olb::particles::contact::getContactTreatmentResultsSerialSize ( )

Definition at line 857 of file particleContactCommunicationFunctions.h.

858{
859 constexpr unsigned Drot = utilities::dimensions::convert<D>::rotation;
860
861 // Create communicatables
862 std::array<std::size_t, 1> commGlobalParticleID {1};
863 ConcreteCommunicatable communicatableID =
864 ConcreteCommunicatable(commGlobalParticleID);
865 Vector<T, D> forceDummy(1);
866 ConcreteCommunicatable communicatableForce =
867 ConcreteCommunicatable(forceDummy);
868 Vector<T, Drot> torqueDummy(1);
869 ConcreteCommunicatable communicatableTorque =
870 ConcreteCommunicatable(torqueDummy);
871
872 // Setting dimension dependent indices
873 const std::vector<unsigned> indicesID {0};
874 std::vector<unsigned> indicesForce;
875 if constexpr (D == 3) {
876 indicesForce = std::vector<unsigned> {0, 1, 2};
877 }
878 else {
879 indicesForce = std::vector<unsigned> {0, 1};
880 }
881 std::vector<unsigned> indicesTorque;
882 if constexpr (D == 3) {
883 indicesTorque = indicesForce;
884 }
885 else {
886 indicesTorque = std::vector<unsigned> {0};
887 }
888
889 // Retrieve serial size
890 return communicatableID.size(indicesID) +
891 communicatableForce.size(indicesForce) +
892 communicatableTorque.size(indicesTorque);
893}

References olb::ConcreteCommunicatable< COMMUNICATEE >::size().

+ Here is the call graph for this function:

◆ getNormalForceFromOverlapVolume()

template<typename T , unsigned D>
Vector< T, D > olb::particles::contact::getNormalForceFromOverlapVolume ( const Vector< T, D > & contactNormal,
const T indentation,
const T overlapVolume,
const T effectiveE,
const T dampingFactor,
const T k,
const Vector< T, D > & relVel )

Definition at line 298 of file particleContactForceFunctions.h.

302{
303 const Vector<T, D> relVelNormal =
304 evalRelativeNormalVelocity(contactNormal, relVel);
305 return calcElasticAndViscousForce(effectiveE, k, overlapVolume, indentation,
306 dampingFactor, relVelNormal, contactNormal);
307}
Vector< T, D > calcElasticAndViscousForce(T effectiveE, T k, T overlapVolume, T indentation, T dampingFactor, const Vector< T, D > &relVelNormal, const Vector< T, D > &contactNormal)
Elastic and viscous force from overlap volume according to Nassauer & Kuna (2013)
constexpr Vector< T, D > evalRelativeNormalVelocity(const Vector< T, D > &contactNormal, const Vector< T, D > &relVel)

References calcElasticAndViscousForce(), and evalRelativeNormalVelocity().

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

◆ getTangentialForceFromOverlapVolume()

template<typename T , unsigned D>
Vector< T, D > olb::particles::contact::getTangentialForceFromOverlapVolume ( const Vector< T, D > & contactNormal,
const T coefficientStaticFriction,
const T coefficientKineticFriction,
const T staticKineticTransitionVelocity,
const T k,
const Vector< T, D > & relVel,
const Vector< T, D > & normalForce )

Definition at line 260 of file particleContactForceFunctions.h.

264{
265 // Only regard if static friction is > 0, because we obtain nan otherwise
266 if (coefficientStaticFriction > T {0.}) {
267 const Vector<T, D> relVelNormal =
268 evalRelativeNormalVelocity(contactNormal, relVel);
269 const Vector<T, D> relVelTangential(relVel - relVelNormal);
270 T const magnitudeTangentialVelocity = norm(relVelTangential);
271 if (magnitudeTangentialVelocity != T {0}) {
272 T const velocityQuotient =
273 magnitudeTangentialVelocity / staticKineticTransitionVelocity;
274
275 T magnitudeTangentialForce =
276 2 * coefficientStaticFriction *
277 (1 - T {0.09} * util::pow(coefficientKineticFriction /
278 coefficientStaticFriction,
279 4));
280 magnitudeTangentialForce -= coefficientKineticFriction;
281 magnitudeTangentialForce *= velocityQuotient * velocityQuotient /
282 (util::pow(velocityQuotient, 4) + 1);
283 magnitudeTangentialForce += coefficientKineticFriction;
284 magnitudeTangentialForce -= coefficientKineticFriction /
285 (velocityQuotient * velocityQuotient + 1);
286 magnitudeTangentialForce *= norm(normalForce);
287
288 return -magnitudeTangentialForce * relVelTangential /
289 magnitudeTangentialVelocity;
290 }
291 }
292
293 return Vector<T, D>(T {0.});
294}

References evalRelativeNormalVelocity(), olb::norm(), and olb::util::pow().

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

◆ isResponsibleRankSet()

template<typename CONTACTTYPE >
bool olb::particles::contact::isResponsibleRankSet ( CONTACTTYPE & contact)

Definition at line 123 of file contactFunctions.h.

124{
125 return contact.getResponsibleRank() < std::numeric_limits<int>::max();
126}
+ Here is the caller graph for this function:

◆ particleContactConsistsOfIDs()

template<typename PARTICLECONTACTTYPE , bool IS_INPUT_SORTED = false>
bool olb::particles::contact::particleContactConsistsOfIDs ( PARTICLECONTACTTYPE & particleContact,
const std::array< size_t, 2 > & ids )

Definition at line 198 of file particleContactDetectionFunctions.h.

200{
201 if constexpr (!IS_INPUT_SORTED) {
202 return (particleContact.getIDs()[0] == ids[0] &&
203 particleContact.getIDs()[1] == ids[1]) ||
204 (particleContact.getIDs()[0] == ids[1] &&
205 particleContact.getIDs()[1] == ids[0]);
206 }
207 else {
208 return particleContact.getIDs()[0] == ids[0] &&
209 particleContact.getIDs()[1] == ids[1];
210 }
211 __builtin_unreachable();
212}
+ Here is the caller graph for this function:

◆ prepareForceCalculation()

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , bool CONVEX>
void olb::particles::contact::prepareForceCalculation ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer)

Definition at line 192 of file particleContactForceFunctions.h.

194{
195
196 communicateContacts(contactContainer);
197
198 if constexpr (!CONVEX) {
199 OstreamManager clout(std::cout, "forceCalcPrep");
200 // TODO: Split contacts if the points are not connected
201 // How to remember properties then? Store old min and max (maybe with a little extra) and then check for to which contact a position belongs?
202 clout << "WARNING: Concave particles aren't supported." << std::endl;
203 }
204}
void communicateContacts(ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > &contactContainer)

References communicateContacts().

+ Here is the call graph for this function:

◆ processCell()

template<typename T , unsigned D, typename F1 , typename F2 , typename F3 , typename F4 , typename F5 >
void olb::particles::contact::processCell ( const PhysR< T, D > & pos,
const PhysR< T, D > & contactPhysDeltaX,
PhysR< T, D > & center,
Vector< T, D > & contactNormal,
unsigned & volumeCellCount,
T & surfaceCellCount,
F1 isInside,
F2 isOnSurface,
F3 calcNormalA,
F4 calcNormalB,
F5 updateMinMax )

Definition at line 537 of file particleContactForceFunctions.h.

542{
543 // outside for normal calculation
544 if (!isInside(pos)) {
545 bool onSurfaceA = false, onSurfaceB = false;
546 // calc normals
547 Vector<T, D> normalA, normalB;
548 // TODO: Improve mesh size
549 T const meshSize = 1e-8 * util::average(contactPhysDeltaX);
550 normalA = calcNormalA(pos, meshSize);
551 normalB = calcNormalB(pos, meshSize);
552 if (!util::nearZero(norm(normalA))) {
553 normalA = normalize(normalA);
554 }
555 if (!util::nearZero(norm(normalB))) {
556 normalB = normalize(normalB);
557 }
558
559 if (isOnSurface(pos, contactPhysDeltaX, onSurfaceA, onSurfaceB, normalA,
560 normalB)) {
561 T approxSurface;
562 if (!util::nearZero(norm(normalA)) && onSurfaceA) {
563 approxSurface = evalApproxSurface(normalA, contactPhysDeltaX);
564 surfaceCellCount += approxSurface;
565 contactNormal += normalA * approxSurface;
566 }
567 if (!util::nearZero(norm(normalB)) && onSurfaceB) {
568 approxSurface = evalApproxSurface(normalB, contactPhysDeltaX);
569 surfaceCellCount += approxSurface;
570 contactNormal -= normalB * approxSurface;
571 }
572 }
573 }
574 // inside volume calculation
575 else {
576 ++volumeCellCount;
577
578 for (unsigned iD = 0; iD < D; ++iD) {
579 center[iD] += pos[iD];
580 }
581 // Updating min and max for next sub-timestep
582 updateMinMax(pos);
583 }
584}
constexpr Vector< T, D > normalize(const ScalarVector< T, D, IMPL > &a, T scale=T{1})
Definition vector.h:245

References olb::util::average(), evalApproxSurface(), olb::util::nearZero(), olb::norm(), olb::normalize(), and updateMinMax().

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

◆ processContacts() [1/2]

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename CONTACTPROPERTIES , unsigned BBCORRECTIONMETHOD = 0, typename F1 = decltype(defaults::periodicity<PARTICLETYPE::d>), typename F2 = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void olb::particles::contact::processContacts ( ParticleSystem< T, PARTICLETYPE > & particleSystem,
std::vector< SolidBoundary< T, PARTICLETYPE::d > > & solidBoundaries,
ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
const CONTACTPROPERTIES & contactProperties,
const SuperGeometry< T, PARTICLETYPE::d > & sGeometry,
const unsigned contactBoxResolutionPerDirection = 8,
const T k = static_cast<T>(4. / (3 * util::sqrt(M_PI))),
F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
F2 processContactForce = defaults::processContactForce<T, PARTICLETYPE::d> )

Definition at line 1657 of file particleContactForceFunctions.h.

1668{
1669 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
1670
1671 particle_particle<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1672 BBCORRECTIONMETHOD>::apply(particleSystem, contactContainer,
1673 contactProperties, sGeometry,
1674 dataMap,
1675 contactBoxResolutionPerDirection,
1676 k, getSetupPeriodicity,
1677 processContactForce);
1678
1679 particle_wall<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1680 BBCORRECTIONMETHOD>::apply(particleSystem, solidBoundaries,
1681 contactContainer, contactProperties,
1682 sGeometry, dataMap,
1683 contactBoxResolutionPerDirection, k,
1684 getSetupPeriodicity,
1685 processContactForce);
1686}

◆ processContacts() [2/2]

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename CONTACTPROPERTIES , unsigned BBCORRECTIONMETHOD = 0, typename F1 = decltype(defaults::periodicity<PARTICLETYPE::d>), typename F2 = decltype(defaults::processContactForce<T, PARTICLETYPE::d>)>
void olb::particles::contact::processContacts ( SuperParticleSystem< T, PARTICLETYPE > & particleSystem,
std::vector< SolidBoundary< T, PARTICLETYPE::d > > & solidBoundaries,
ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
const CONTACTPROPERTIES & contactProperties,
const SuperGeometry< T, PARTICLETYPE::d > & sGeometry,
MPI_Comm contactTreatmentComm,
const unsigned contactBoxResolutionPerDirection = 8,
const T k = static_cast<T>(4. / (3 * util::sqrt(M_PI))),
F1 getSetupPeriodicity = defaults::periodicity<PARTICLETYPE::d>,
F2 processContactForce = defaults::processContactForce<T, PARTICLETYPE::d> )

Definition at line 1609 of file particleContactForceFunctions.h.

1623{
1624 std::multimap<int, std::unique_ptr<std::uint8_t[]>> dataMap;
1625
1626 particle_particle<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1627 BBCORRECTIONMETHOD>::apply(particleSystem, contactContainer,
1628 contactProperties, sGeometry,
1629 dataMap,
1630 contactBoxResolutionPerDirection,
1631 k, getSetupPeriodicity,
1632 processContactForce);
1633
1634 particle_wall<T, PARTICLETYPE, PARTICLECONTACTTYPE, WALLCONTACTTYPE,
1635 BBCORRECTIONMETHOD>::apply(particleSystem, solidBoundaries,
1636 contactContainer, contactProperties,
1637 sGeometry, dataMap,
1638 contactBoxResolutionPerDirection, k,
1639 getSetupPeriodicity,
1640 processContactForce);
1641 if constexpr (access::providesParallelization<PARTICLETYPE>()) {
1642 communicateContactTreatmentResults<T, PARTICLETYPE>(particleSystem, dataMap
1643#ifdef PARALLEL_MODE_MPI
1644 ,
1645 contactTreatmentComm
1646#endif
1647 );
1648 }
1649}

◆ processContactViaVolume()

template<typename T , unsigned D, typename F1 , typename F2 , typename F3 , typename F4 >
void olb::particles::contact::processContactViaVolume ( const Vector< T, D > & min,
const Vector< T, D > & max,
T physDeltaX,
unsigned contactBoxResolutionPerDirection,
F1 resetContactBox,
F2 processCellWrapped,
F3 calculateIndentation,
F4 applyForce )

Definition at line 588 of file particleContactForceFunctions.h.

593{
594 Vector<T, D> contactPhysDeltaX =
595 evalContactDeltaX(min, max, physDeltaX, contactBoxResolutionPerDirection);
596
597 // direction of force
598 Vector<T, D> contactNormal(T(0.));
599 // contact point
600 Vector<T, D> center(T(0.));
601 // number of cells in contact volume
602 unsigned volumeCellCount = 0;
603 // number of cells in contact surface
604 T surfaceCellCount = 0.;
605 // volume of cell describing the contact
606 T infinitesimalVolume = contactPhysDeltaX[0] * contactPhysDeltaX[1];
607 if constexpr (D == 3) {
608 infinitesimalVolume *= contactPhysDeltaX[2];
609 }
610
611 Vector<long, D> startPos;
612 Vector<long, D> endPos;
613 evalStartAndEndPos(startPos, endPos, max, min, contactPhysDeltaX);
614 // Increase the box 2*deltaX in each direction
615 startPos -= Vector<long, D>(1);
616 endPos += Vector<long, D>(1);
617
618 resetContactBox();
619
620 forEachPosition(startPos, endPos, [&](const Vector<long, D>& pos) {
621 Vector<T, D> physPos;
622 for (unsigned iD = 0; iD < D; ++iD) {
623 physPos[iD] = pos[iD] * contactPhysDeltaX[iD];
624 }
625 processCellWrapped(contactNormal, center, volumeCellCount, surfaceCellCount,
626 physPos, contactPhysDeltaX);
627 });
628
629 if (!util::nearZero(norm(contactNormal))) {
630 if (volumeCellCount > 0 && surfaceCellCount > 0) {
631 // finishing center calculation
632 center /= volumeCellCount;
633 // finishing normal calculation
634 contactNormal = normalize(contactNormal);
635 // calculate precision depending on the size of the overlap
636 T precision {0};
637 for (unsigned iD = 0; iD < D; ++iD) {
638 precision += util::pow(contactNormal[iD] * contactPhysDeltaX[iD], 2);
639 }
640 precision = T {1e-2} * util::sqrt(precision / D);
641 const T indentation =
642 calculateIndentation(center, contactNormal, precision);
643 // currently, the normal points outside the particle (because we use SDF), but the force acts in the opposite way
644 contactNormal *= -1;
645 // Avoid indentation < 0
646 if (indentation > 0) {
647 applyForce(center, contactNormal, util::max(indentation, T {0}),
648 volumeCellCount * infinitesimalVolume);
649 }
650 }
651 }
652#ifdef OLB_DEBUG
653 else {
654 OstreamManager clout(std::cout, "contactProcessing");
655 clout << "WARNING: The contact normal's norm is zero. Therefore, the "
656 "detected contact is ignored."
657 << std::endl;
658 }
659#endif
660}

References evalContactDeltaX(), evalStartAndEndPos(), forEachPosition(), olb::util::max(), olb::util::nearZero(), olb::norm(), olb::normalize(), olb::util::pow(), and olb::util::sqrt().

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

◆ receiveContact() [1/2]

template<typename T , typename PARTICLETYPE , typename CONTACTTYPE , bool CONVEX, bool SANITYCHECK = false>
void olb::particles::contact::receiveContact ( ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & newcontact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
std::vector< CONTACTTYPE > & contacts,
int rankOrig )

Definition at line 546 of file particleContactCommunicationFunctions.h.

551{
552 using namespace descriptors;
553
554 bool addNewContact = true;
555
556 // Optional sanity check
557 if constexpr (SANITYCHECK) {
558 if (newcontact.getResponsibleRank() == singleton::mpi().getRank()) {
559 bool isParticleDataAvailable[2] = {false, false};
560 // Iterate over all particles to check for errors
561 communication::forParticlesInSuperParticleSystem(
562 sParticleSystem,
563 [&](Particle<T, PARTICLETYPE>& particle,
564 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
565 for (unsigned short i = 0; i < 2; ++i) {
566 if (particle.template getField<PARALLELIZATION, ID>() ==
567 newcontact.getIDs()[i]) {
568 isParticleDataAvailable[i] = true;
569 }
570 }
571 });
572 if (!isParticleDataAvailable[0] || !isParticleDataAvailable[1]) {
573 addNewContact = false;
574 std::cout << "WARNING: rank " << singleton::mpi().getRank()
575 << " received a contact of particles with the global ids "
576 << newcontact.getIDs()[0] << " and " << newcontact.getIDs()[1]
577 << " from rank " << rankOrig
578 << " for which no particle data are available." << std::endl;
579 }
580 }
581 }
582
583 if (addNewContact) {
584 const std::array<std::size_t, 2> particleIDs = newcontact.getIDs();
585
586 const std::function<bool(const CONTACTTYPE&)> condition =
587 [&particleIDs](const CONTACTTYPE& contact) {
588 return particleContactConsistsOfIDs(contact, particleIDs);
589 };
590
591 auto contactIt = getContactIterator(contacts, condition);
592
593 if (contactIt != std::end(contacts)) {
594 contactIt->combineWith(newcontact);
595 }
596 else {
597 contacts.push_back(newcontact);
598 }
599
600#ifdef VERBOSE_CONTACT_COMMUNICATION
601 std::cout << "Rank " << singleton::mpi().getRank()
602 << " received contact of ids " << newcontact.getIDs()[0] << " & "
603 << newcontact.getIDs()[1] << ". Rank "
604 << newcontact.getResponsibleRank()
605 << " is responsible for the calculation." << std::endl;
606#endif
607 }
608}
bool particleContactConsistsOfIDs(PARTICLECONTACTTYPE &particleContact, const std::array< size_t, 2 > &ids)
auto getContactIterator(std::vector< CONTACTTYPE > &contacts, const std::function< bool(const CONTACTTYPE &)> condition)

References olb::particles::communication::forParticlesInSuperParticleSystem(), getContactIterator(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getIDs(), olb::singleton::MpiManager::getRank(), olb::particles::contact::ParticleContactArbitraryFromOverlapVolume< T, D, CONVEX >::getResponsibleRank(), olb::singleton::mpi(), and particleContactConsistsOfIDs().

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

◆ receiveContact() [2/2]

template<typename T , typename PARTICLETYPE , typename CONTACTTYPE , bool CONVEX, bool SANITYCHECK = false>
void olb::particles::contact::receiveContact ( WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & newcontact,
SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
std::vector< CONTACTTYPE > & contacts,
int rankOrig )

Definition at line 612 of file particleContactCommunicationFunctions.h.

617{
618 using namespace descriptors;
619
620 bool addNewContact = true;
621
622 if constexpr (SANITYCHECK) {
623 if (newcontact.getResponsibleRank() == singleton::mpi().getRank()) {
624 bool isParticleDataAvailable = false;
625 // Iterate over all particles to check for errors
626 communication::forParticlesInSuperParticleSystem(
627 sParticleSystem,
628 [&](Particle<T, PARTICLETYPE>& particle,
629 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
630 if (particle.template getField<PARALLELIZATION, ID>() ==
631 newcontact.getParticleID()) {
632 isParticleDataAvailable = true;
633 }
634 });
635 if (!isParticleDataAvailable) {
636 addNewContact = false;
637 std::cout << "WARNING: rank " << singleton::mpi().getRank()
638 << " received a contact of particle with the global id "
639 << newcontact.getParticleID() << " from rank " << rankOrig
640 << " for which no particle data is available." << std::endl;
641 }
642 }
643 }
644
645 if (addNewContact) {
646 const std::size_t particleID = newcontact.getParticleID();
647 const std::size_t solidBoundaryMaterial = newcontact.getWallID();
648
649 const std::function<bool(const CONTACTTYPE&)> condition =
650 [&particleID, &solidBoundaryMaterial](const CONTACTTYPE& contact) {
651 return particleID == contact.getParticleID() &&
652 solidBoundaryMaterial == contact.getWallID();
653 };
654
655 auto contactIt = getContactIterator(contacts, condition);
656
657 if (contactIt != std::end(contacts)) {
658 contactIt->combineWith(newcontact);
659 }
660 else {
661 contacts.push_back(newcontact);
662 }
663 }
664}

References olb::particles::communication::forParticlesInSuperParticleSystem(), getContactIterator(), olb::singleton::MpiManager::getRank(), and olb::singleton::mpi().

+ Here is the call graph for this function:

◆ receiveContactTreatmentResults()

template<typename T , typename PARTICLETYPE >
void olb::particles::contact::receiveContactTreatmentResults ( SuperParticleSystem< T, PARTICLETYPE > & sParticleSystem,
MPI_Comm contactTreatmentComm,
singleton::MpiNonBlockingHelper & mpiNbHelper )

Definition at line 952 of file particleContactCommunicationFunctions.h.

955{
956 using namespace descriptors;
957
958 // Retrieve dimensions
959 constexpr unsigned D = PARTICLETYPE::d;
960 constexpr unsigned Drot = utilities::dimensions::convert<D>::rotation;
961
962 // Retrieve rank of direct neighbours
963 auto& listNeighbourRanks = sParticleSystem.getNeighbourRanks();
964
965#ifdef VERBOSE_CONTACT_COMMUNICATION
966 std::cout << "Rank " << singleton::mpi().getRank() << " has the neighbours: ";
967 for (auto& neighbourRank : listNeighbourRanks) {
968 std::cout << neighbourRank << " ";
969 }
970 std::cout << std::endl;
971#endif
972
973 // Setting dimension dependent indices
974 const std::vector<unsigned> indicesID {0};
975 std::vector<unsigned> indicesForce;
976 if constexpr (D == 3) {
977 indicesForce = std::vector<unsigned> {0, 1, 2};
978 }
979 else {
980 indicesForce = std::vector<unsigned> {0, 1};
981 }
982 std::vector<unsigned> indicesTorque;
983 if constexpr (D == 3) {
984 indicesTorque = indicesForce;
985 }
986 else {
987 indicesTorque = std::vector<unsigned> {0};
988 }
989
990 std::array<std::size_t, 1> commGlobalParticleID;
991 Vector<T, D> contactForce;
992 Vector<T, Drot> contactTorque;
993
994 // Create communicatables
995 ConcreteCommunicatable communicatableID =
996 ConcreteCommunicatable(commGlobalParticleID);
997 ConcreteCommunicatable communicatableForce =
998 ConcreteCommunicatable(contactForce);
999 ConcreteCommunicatable communicatableTorque =
1000 ConcreteCommunicatable(contactTorque);
1001
1002 // Retrieve serial size
1003 const std::size_t serialSize = communicatableID.size(indicesID) +
1004 communicatableForce.size(indicesForce) +
1005 communicatableTorque.size(indicesTorque);
1006
1007 // Receive data and iterate buffer
1008 // TODO: Improve processing of data, do not iterate through the all particles every time (maybe also add main iC to the communicated data to reduce processed particles)
1009 communication::receiveAndExecuteForData(
1010 listNeighbourRanks, serialSize, contactTreatmentComm, mpiNbHelper,
1011 [&](int rankOrig, std::uint8_t* buffer) {
1012 std::size_t serialIdx = communicatableID.deserialize(indicesID, buffer);
1013 serialIdx +=
1014 communicatableForce.deserialize(indicesForce, &buffer[serialIdx]);
1015 serialIdx +=
1016 communicatableTorque.deserialize(indicesTorque, &buffer[serialIdx]);
1017
1018#ifdef VERBOSE_CONTACT_COMMUNICATION
1019 std::cout << "Rank " << singleton::mpi().getRank()
1020 << " received contact treatment results for particle "
1021 << commGlobalParticleID[0] << " (force = " << contactForce
1022 << "; torque = " << contactTorque << ") from rank "
1023 << rankOrig << std::endl;
1024#endif
1025
1026 communication::forParticlesInSuperParticleSystem<
1027 T, PARTICLETYPE, conditions::valid_particles>(
1028 sParticleSystem,
1029 [&](Particle<T, PARTICLETYPE>& particle,
1030 ParticleSystem<T, PARTICLETYPE>& particleSystem, int globiC) {
1031 const std::size_t currentGlobalParticleID =
1032 particle.template getField<PARALLELIZATION, ID>();
1033 if (commGlobalParticleID[0] == currentGlobalParticleID) {
1034 // Process contact force
1035 const Vector<T, D> force =
1036 particle.template getField<FORCING, FORCE>();
1037 particle.template setField<FORCING, FORCE>(force +
1038 contactForce);
1039 // Process torque from contact
1040 const Vector<T, Drot> torque(
1041 particle.template getField<FORCING, TORQUE>());
1042 particle.template setField<FORCING, TORQUE>(
1043 utilities::dimensions::convert<D>::serialize_rotation(
1044 torque + contactTorque));
1045 }
1046 });
1047 });
1048}

References olb::ConcreteCommunicatable< COMMUNICATEE >::deserialize(), olb::particles::communication::forParticlesInSuperParticleSystem(), olb::particles::SuperParticleSystem< T, PARTICLETYPE >::getNeighbourRanks(), olb::singleton::MpiManager::getRank(), olb::singleton::mpi(), olb::particles::communication::receiveAndExecuteForData(), and olb::ConcreteCommunicatable< COMMUNICATEE >::size().

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

◆ resetResponsibleRank()

template<typename CONTACTTYPE >
void olb::particles::contact::resetResponsibleRank ( CONTACTTYPE & contact)

Definition at line 117 of file contactFunctions.h.

118{
119 contact.setResponsibleRank(std::numeric_limits<int>::max());
120}
+ Here is the caller graph for this function:

◆ sortParticleIDs()

std::array< std::size_t, 2 > olb::particles::contact::sortParticleIDs ( const std::array< std::size_t, 2 > & ids)

Definition at line 49 of file particleContactDetectionFunctions.h.

50{
51 return std::array<std::size_t, 2>(
52 {util::min(ids[0], ids[1]), util::max(ids[0], ids[1])});
53}

References olb::util::max(), and olb::util::min().

+ Here is the call graph for this function:

◆ unifyPosition()

template<typename T , typename PARTICLETYPE , typename F >
PhysR< T, PARTICLETYPE::d > olb::particles::contact::unifyPosition ( Particle< T, PARTICLETYPE > & particle,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 124 of file particleContactDetectionFunctions.h.

128{
129 using namespace descriptors;
130 const PhysR<T, PARTICLETYPE::d> pos =
131 particles::access::getPosition(particle);
132 PhysR<T, PARTICLETYPE::d> unifiedPosition(pos);
133
134 if constexpr (isPeriodic(getSetupPeriodicity())) {
135 constexpr Vector<bool, PARTICLETYPE::d> isPeriodic(getSetupPeriodicity());
136
137 auto sIndicator = particle.template getField<SURFACE, SINDICATOR>();
138 const T circumRadius = sIndicator->getCircumRadius() -
139 sIndicator->getEpsilon() +
140 util::max(sIndicator->getEpsilon(), 0.5 * deltaX);
141
142 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
143 T const particleMax = pos[i] + circumRadius;
144 //T const particleMin = pos[i] - circumRadius;
145
146 if (particleMax > cellMax[i] && isPeriodic[i]) {
147 unifiedPosition[i] = communication::movePositionToStart(
148 pos[i], cellMax[i], cellMin[i]);
149 }
150 /*
151 else if (particleMin < cellMin[i] && isPeriodic[i]) {
152 unifiedPosition[i] = cellMax[i] - (cellMin[i] - pos[i]);
153 }
154 */
155 }
156 }
157 return unifiedPosition;
158}

References olb::particles::access::getPosition(), olb::particles::isPeriodic(), olb::util::max(), and olb::particles::communication::movePositionToStart().

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

◆ unifyPositions()

template<typename T , typename PARTICLETYPE , typename F >
void olb::particles::contact::unifyPositions ( Particle< T, PARTICLETYPE > & particle1,
Particle< T, PARTICLETYPE > & particle2,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
std::array< PhysR< T, PARTICLETYPE::d >, 2 > & positions,
T deltaX )

Definition at line 56 of file particleContactDetectionFunctions.h.

63{
64 using namespace descriptors;
65
66 const PhysR<T, PARTICLETYPE::d> pos1 =
67 particles::access::getPosition(particle1);
68 const PhysR<T, PARTICLETYPE::d> pos2 =
69 particles::access::getPosition(particle2);
70 positions[0] = pos1;
71 positions[1] = pos2;
72
73 if constexpr (isPeriodic(getSetupPeriodicity())) {
74 constexpr Vector<bool, PARTICLETYPE::d> isPeriodic(getSetupPeriodicity());
75
76 auto sIndicator1 = particle1.template getField<SURFACE, SINDICATOR>();
77 const T circumRadius1 = sIndicator1->getCircumRadius() -
78 sIndicator1->getEpsilon() +
79 util::max(sIndicator1->getEpsilon(), 0.5 * deltaX);
80 auto sIndicator2 = particle2.template getField<SURFACE, SINDICATOR>();
81 const T circumRadius2 = sIndicator2->getCircumRadius() -
82 sIndicator2->getEpsilon() +
83 util::max(sIndicator2->getEpsilon(), 0.5 * deltaX);
84
85 const PhysR<T, PARTICLETYPE::d> middle = 0.5 * (cellMin + cellMax);
86
87 for (unsigned i = 0; i < PARTICLETYPE::d; ++i) {
88 T const particleMin1 = pos1[i] - circumRadius1;
89 T const particleMax1 = pos1[i] + circumRadius1;
90 T const particleMin2 = pos2[i] - circumRadius2;
91 T const particleMax2 = pos2[i] + circumRadius2;
92
93 // Always solely "move" the second particle
94 if (particleMin1 < cellMin[i] && isPeriodic[i]) {
95 if (pos2[i] > middle[i]) {
96 positions[1][i] = communication::movePositionToStart(
97 pos2[i], cellMax[i], cellMin[i]);
98 }
99 }
100 else if (particleMax1 > cellMax[i] && isPeriodic[i]) {
101 if (pos2[i] < middle[i]) {
102 positions[1][i] = communication::movePositionToEnd(
103 pos2[i], cellMax[i], cellMin[i]);
104 }
105 }
106 else if (particleMin2 < cellMin[i] && isPeriodic[i]) {
107 if (pos1[i] > middle[i]) {
108 positions[1][i] = communication::movePositionToEnd(
109 pos2[i], cellMax[i], cellMin[i]);
110 }
111 }
112 else if (particleMax2 > cellMax[i] && isPeriodic[i]) {
113 if (pos1[i] < middle[i]) {
114 positions[1][i] = communication::movePositionToStart(
115 pos2[i], cellMax[i], cellMin[i]);
116 }
117 }
118 }
119 }
120}

References olb::particles::access::getPosition(), olb::particles::isPeriodic(), olb::util::max(), olb::particles::communication::movePositionToEnd(), and olb::particles::communication::movePositionToStart().

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

◆ updateContact() [1/2]

template<typename T , typename PARTICLETYPE , bool CONVEX, typename F >
void olb::particles::contact::updateContact ( ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
Particle< T, PARTICLETYPE > & particle1,
Particle< T, PARTICLETYPE > & particle2,
const PhysR< T, PARTICLETYPE::d > & contactPos,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 215 of file particleContactDetectionFunctions.h.

223{
224 if (!contact.isParticlePositionUpdated()) {
225 std::array<PhysR<T, PARTICLETYPE::d>, 2> positions;
226 unifyPositions(particle1, particle2, cellMin, cellMax, getSetupPeriodicity,
227 positions, deltaX);
228 contact.setParticlePositions(positions);
229 }
230 // It doesn't matter which particle is used, since the contact must be in both
231 contact.updateMinMax(evalContactPosition(
232 particle1, contact.getParticlePosition(contact.getIDs()[0]),
233 contactPos, cellMin, cellMax, getSetupPeriodicity, deltaX));
234}
void unifyPositions(Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, std::array< PhysR< T, PARTICLETYPE::d >, 2 > &positions, T deltaX)
constexpr const PhysR< T, D > & getParticlePosition(const std::size_t &id) const
Return particle position.
constexpr void setParticlePositions(const std::array< PhysR< T, D >, 2 > &positions)
Set particle positions.
constexpr void updateMinMax(const PhysR< T, D > &positionInsideTheContact)
Update min and max with given position inside the contact.
constexpr bool isParticlePositionUpdated() const
Returns if the particle position is up-to-date.

References evalContactPosition(), and unifyPositions().

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

◆ updateContact() [2/2]

template<typename T , typename PARTICLETYPE , bool CONVEX, typename F >
void olb::particles::contact::updateContact ( WallContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > & contact,
Particle< T, PARTICLETYPE > & particle,
const PhysR< T, PARTICLETYPE::d > & contactPos,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 237 of file particleContactDetectionFunctions.h.

244{
245 if (!contact.isParticlePositionUpdated()) {
246 contact.setParticlePosition(
247 unifyPosition(particle, cellMin, cellMax, getSetupPeriodicity, deltaX));
248 }
249 contact.updateMinMax(
250 evalContactPosition(particle, contact.getParticlePosition(), contactPos,
251 cellMin, cellMax, getSetupPeriodicity, deltaX));
252}
PhysR< T, PARTICLETYPE::d > unifyPosition(Particle< T, PARTICLETYPE > &particle, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)
constexpr bool isParticlePositionUpdated() const
Returns if the particle position is up-to-date.
constexpr void setParticlePosition(const PhysR< T, D > &particlePosition)
Set particle position.
constexpr const PhysR< T, D > & getParticlePosition() const
Return particle position.
constexpr void updateMinMax(const PhysR< T, D > &positionInsideTheContact)
Update min and max with given position inside the contact.

References evalContactPosition(), and unifyPosition().

+ Here is the call graph for this function:

◆ updateContacts() [1/2]

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void olb::particles::contact::updateContacts ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
size_t particleID,
unsigned wallID,
const PhysR< T, PARTICLETYPE::d > & pos,
Particle< T, PARTICLETYPE > & particle,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 304 of file particleContactDetectionFunctions.h.

310{
311 // find the contact by checking ids
312 const std::function<bool(const WALLCONTACTTYPE&)> condition =
313 [&particleID, &wallID](const WALLCONTACTTYPE& contact) {
314 return particleID == contact.getParticleID() &&
315 wallID == contact.getWallID();
316 };
317 auto contactIt =
318 getContactIterator(contactContainer.wallContacts, condition);
319
320 if (contactIt != std::end(contactContainer.wallContacts)) {
321 if (contactIt->isNew()) {
322 updateContact(*contactIt, particle, pos, cellMin, cellMax,
323 getSetupPeriodicity, deltaX);
324 }
325 }
326 else {
327 contactContainer.wallContacts.push_back(
328 WALLCONTACTTYPE(particleID, wallID));
329 updateContact(*(contactContainer.wallContacts.end() - 1), particle, pos,
330 cellMin, cellMax, getSetupPeriodicity, deltaX);
331 }
332}

References getContactIterator(), updateContact(), and olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::wallContacts.

+ Here is the call graph for this function:

◆ updateContacts() [2/2]

template<typename T , typename PARTICLETYPE , typename PARTICLECONTACTTYPE , typename WALLCONTACTTYPE , typename F >
void olb::particles::contact::updateContacts ( ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE > & contactContainer,
std::array< std::size_t, 2 > && ids,
const PhysR< T, PARTICLETYPE::d > & pos,
Particle< T, PARTICLETYPE > & particle1,
Particle< T, PARTICLETYPE > & particle2,
const PhysR< T, PARTICLETYPE::d > & cellMin,
const PhysR< T, PARTICLETYPE::d > & cellMax,
F getSetupPeriodicity,
T deltaX )

Definition at line 256 of file particleContactDetectionFunctions.h.

263{
264 // find the contact by checking particle ids
265 const std::function<bool(const PARTICLECONTACTTYPE&)> condition =
266 [&ids](const PARTICLECONTACTTYPE& contact) {
267 // we assume that ids aren't sorted
268 return particleContactConsistsOfIDs(contact, ids);
269 };
270 auto contactIt =
271 getContactIterator(contactContainer.particleContacts, condition);
272
273 if (contactIt != std::end(contactContainer.particleContacts)) {
274 if (contactIt->isNew()) {
275 if (particleContactConsistsOfIDs<PARTICLECONTACTTYPE, true>(
276 *contactIt, ids)) {
277 updateContact(*contactIt, particle1, particle2, pos, cellMin, cellMax,
278 getSetupPeriodicity, deltaX);
279 }
280 else {
281 updateContact(*contactIt, particle2, particle1, pos, cellMin, cellMax,
282 getSetupPeriodicity, deltaX);
283 }
284 }
285 }
286 else {
287 contactContainer.particleContacts.push_back(PARTICLECONTACTTYPE(ids));
288 if (particleContactConsistsOfIDs<PARTICLECONTACTTYPE, true>(
289 *(contactContainer.particleContacts.end() - 1), ids)) {
290 updateContact(*(contactContainer.particleContacts.end() - 1), particle1,
291 particle2, pos, cellMin, cellMax, getSetupPeriodicity,
292 deltaX);
293 }
294 else {
295 updateContact(*(contactContainer.particleContacts.end() - 1), particle2,
296 particle1, pos, cellMin, cellMax, getSetupPeriodicity,
297 deltaX);
298 }
299 }
300}
void updateContact(ParticleContactArbitraryFromOverlapVolume< T, PARTICLETYPE::d, CONVEX > &contact, Particle< T, PARTICLETYPE > &particle1, Particle< T, PARTICLETYPE > &particle2, const PhysR< T, PARTICLETYPE::d > &contactPos, const PhysR< T, PARTICLETYPE::d > &cellMin, const PhysR< T, PARTICLETYPE::d > &cellMax, F getSetupPeriodicity, T deltaX)

References getContactIterator(), particleContactConsistsOfIDs(), olb::particles::contact::ContactContainer< T, PARTICLECONTACTTYPE, WALLCONTACTTYPE >::particleContacts, and updateContact().

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

◆ updateMinMax()

template<typename T , unsigned D>
void olb::particles::contact::updateMinMax ( PhysR< T, D > & min,
PhysR< T, D > & max,
const PhysR< T, D > & pos )

Definition at line 34 of file contactHelpers.h.

35{
36 for (unsigned iD = 0; iD < D; ++iD) {
37 min[iD] = util::min(min[iD], pos[iD]);
38 max[iD] = util::max(max[iD], pos[iD]);
39 }
40}

References olb::util::max(), and olb::util::min().

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