MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
ParticleCollision< nDim > Class Template Reference

#include <lptcollision.h>

Collaboration diagram for ParticleCollision< nDim >:
[legend]

Classes

struct  collQueueElem
 
struct  collQueueElemEllipsoid
 

Public Member Functions

 ParticleCollision (LPT< nDim > *lptSolver, MInt collisionModel, const MInt solverId, const MInt domainId, const MInt noDomains, const MPI_Comm comm)
 Constructor of the ParticleCollision class. More...
 
void init ()
 Initialisation of collision model. More...
 
void detectPartColl (std::vector< LPTSpherical< nDim > > &partList, std::vector< LPTEllipsoidal< nDim > > &partListEllipsoid, const MFloat timeStep, const MFloat time)
 Disables the following warnings with gcc: -Warray-bounds. More...
 
void geometryInteraction ()
 
void writeCollData ()
 write collision data queue to Netcdf file (using parallel output) More...
 

Private Types

using GridProxy = typename maia::grid::Proxy< nDim >
 
using lptParticleI = typename maia::lpt::partListIteratorConst< nDim >
 
using lptEllipticleI = typename maia::lpt::ellipsListIteratorConst< nDim >
 

Private Member Functions

MInt domainId () const
 
MInt solverId () const
 
MInt noDomains () const
 
MPI_Comm mpiComm () const
 
MFloat collisionCheck (lptParticleI, lptParticleI, MFloat)
 Checks whether particles i and j collide after currCollTime, and returns collision time. More...
 
void collisionCheckSphereEllipsoid (lptParticleI, lptEllipticleI)
 Collision check for ellipsoids i2 and i3 calls the corresponding proactive or retroactive method. More...
 
void collisionCheckEllipsoidEllipsoid (lptEllipticleI, lptEllipticleI)
 Collision check for ellipsoids i2 and i3 calls the corresponding proactive or retroactive method. More...
 
void collisionCheckSEP (lptParticleI, lptEllipticleI)
 Collision check for sphere i1 and ellipsoid i2, specialized version of ellips ellips checks and stores collision event this method works proactive, but assumes that the closet distance between the centroids corresponds to the closest distance betweeen the two particles. More...
 
void collisionCheckSERetroActive (lptParticleI, lptEllipticleI)
 Collision check for sphere i1 and ellipsoid i2 based on overlap criterion, and store collision event when found. More...
 
void collisionCheckEEProActive (lptEllipticleI, lptEllipticleI)
 Collision check for ellipsoids i2 and i3 checks and stores collision event this method works proactive, but assumes that the closet distance between the centroids corresponds to the closest distance betweeen the two ellipsoids. More...
 
void collisionCheckEERetroActive (lptEllipticleI, lptEllipticleI)
 Collision check for ellipsoids i2 and i3 based on overlap criterion, and store collision event when found. More...
 
void collisionCheckEECCD (lptEllipticleI, lptEllipticleI)
 checks continuously for the overlaps of the two ellipsoids i2 and i3 assuming that they do not rotate during the timestep after Choi et al., IEEE TRANSACTIONS ON VISUALIZATION AND COMPUTER GRAPHICS, VOL. 15, NO. 2, MARCH/APRIL 2009, 311 Continuous Collision Detection for Ellipsoids More...
 
void collisionCheckSECCD (lptParticleI, lptEllipticleI)
 checks continuously for the overlaps of the sphere i2 and the ellipsoid i3 assuming that they do not rotate during two timesteps after Choi et al., IEEE TRANSACTIONS ON VISUALIZATION AND COMPUTER GRAPHICS, VOL. 15, NO. 2, MARCH/APRIL 2009, 311 Continuous Collision Detection for Ellipsoids More...
 
MFloat checkBndryCross (MInt, lptParticleI, MFloat)
 Checks crossing of boundary surface of the boundary cell. More...
 
void createMatrix_CCD (const MFloat(&MA)[16], const MFloat(&u1)[3], const MFloat(&invMB)[16], const MFloat(&u2)[3], const MFloat &a_2, const MFloat &c_2, MFloat(&n)[16], MFloat(&m)[5])
 calculates M_A^T*(M_B^(-1))^T*B*(M_B^(-1))*M_A, write it the part independent of t in n and the other values in m More...
 
MFloat checkStaticOverlap_CCD (const MFloat(&b_Matrix)[16], const MFloat(&A)[16], const MFloat(&m)[5], const MFloat &detMinusB, MFloat &t1)
 calculates if there is a local maximum of det(A*(u-1)-u*B) in u for a fixed value of t and if the value there is above zero since this necessary for separation returns this value otherwise -1. b_Matrix is the build matrix by createMatrix_CCD independent of t m are the values build by createMatrix_CCD dependent of t A is the matrix of Ellpsoid2 detMinusB is det(-B) where B is the matrix of Ellipsoid3 More...
 
MBool checkCSI_CCD (const MFloat(&A)[16], const MFloat(&b_Matrix)[16], const MFloat(&m)[5], const MFloat &detMinusB, MFloat &t1, MFloat &t2, MFloat &positive1, MFloat &positive2, MInt &iteration)
 checks recursively if the ellipsoids are separated by subdividing the time intervals in smaller CSIs. returns false if separated, otherwise returns true More...
 
MFloat testU_CCD (const MFloat &u, const MFloat &t4, const MFloat &t3, const MFloat &t2, const MFloat &t1, const MFloat &t0)
 calculates the value of the forth order polynomial and returns it if positive other returns -1 More...
 
MFloat checkDynamicOverlap_CCD (const MFloat(&n)[16], const MFloat(&m)[5], MFloat t1, MFloat t2)
 Performes BezierShot from "side", returns the first zero-crossing results in finding the roots of the determinate of the Matrix for fixed "u" value, which is a quadratic equation in t. returns the t value of the root if one exists between 0 and 1 otherwise returns side. "n" is the symmetric matrix containing the values independent of t, "m" are the coefficients t is multiplied to "side" is -1 or 1 depending on the direction of the BezierShot. More...
 
void writeCollEvent (MFloat collisionTime, MInt particle0, MInt particle1, MFloat diam0, MFloat diam1, MFloat dens0, MFloat dens1, MFloat relVel, MFloat meanVel, MFloat *x)
 Add collision data to queue which is to be written. More...
 

Private Attributes

MInt m_collisionModel = -1
 
LPT< nDim > * m_lpt = nullptr
 
MInt m_solverId = -1
 
MInt m_domainId = -1
 
MInt m_noDomains = -1
 
MPI_Comm m_mpiComm
 
std::list< collStruct< nDim > > collList
 
MInt m_noOfSubDomains [3] {}
 
MFloat m_subDomainCoordOffset [3] {}
 
MFloat m_subDomainSize [3] {}
 
MInt m_totalSubDomains = 1
 
maia::lpt::subDomainCollector< nDim > * subDomainContent
 
maia::lpt::subDomainCollectorEllipsoid< nDim > * subDomainContentEllipsoid
 
MInt m_outputStep = 50
 
MFloat m_offset = -1000.0
 
MInt m_ellipsoidCCD = 1
 
MBool m_includeEllipsoids = false
 
MFloat m_timeStep = -1
 
std::queue< collQueueElemcollQueue
 
std::queue< collQueueElemEllipsoidcollQueueEllipsoid
 

Friends

class LPT< nDim >
 

Detailed Description

template<MInt nDim>
class ParticleCollision< nDim >

Definition at line 16 of file lptcollision.h.

Member Typedef Documentation

◆ GridProxy

template<MInt nDim>
using ParticleCollision< nDim >::GridProxy = typename maia::grid::Proxy<nDim>
private

Definition at line 18 of file lptcollision.h.

◆ lptEllipticleI

template<MInt nDim>
using ParticleCollision< nDim >::lptEllipticleI = typename maia::lpt::ellipsListIteratorConst<nDim>
private

Definition at line 21 of file lptcollision.h.

◆ lptParticleI

template<MInt nDim>
using ParticleCollision< nDim >::lptParticleI = typename maia::lpt::partListIteratorConst<nDim>
private

Definition at line 20 of file lptcollision.h.

Constructor & Destructor Documentation

◆ ParticleCollision()

template<MInt nDim>
ParticleCollision< nDim >::ParticleCollision ( LPT< nDim > *  lptSolver,
MInt  collisionModel,
const MInt  solverId,
const MInt  domainId,
const MInt  noDomains,
const MPI_Comm  comm 
)
Author
Sven Berger, Tim Wegmann
Date
June 2016
Parameters
[in]collisionModelCollision model to use.
[in]lptSolverPointer to LPT solver.
[in]fvSolverPointer to matching FV solver.

Definition at line 28 of file lptcollision.cpp.

30 : m_collisionModel(collisionModel),
31 m_lpt(lptSolver),
35 m_mpiComm(comm) {
36 init();
37}
MInt solverId() const
Definition: lptcollision.h:47
LPT< nDim > * m_lpt
Definition: lptcollision.h:39
MInt domainId() const
Definition: lptcollision.h:46
MPI_Comm m_mpiComm
Definition: lptcollision.h:44
void init()
Initialisation of collision model.
MInt noDomains() const
Definition: lptcollision.h:48

Member Function Documentation

◆ checkBndryCross()

template<MInt nDim>
MFloat ParticleCollision< nDim >::checkBndryCross ( MInt  ,
lptParticleI  ,
MFloat   
)
private

MFloat LPT::checkBndryCross(MInt bndryId, MInt vectorId, MFloat particleDiameter)

The current cell in which the particle resides, is a boundary cell. It is checked whether the particle crossed the boundary surface of that cell in the last time step using the new and old particle positions.

Author
Martin Brinks

Definition at line 2521 of file lptcollision.cpp.

2522 {
2523 TRACE();
2524
2525 MFloat nx0 = 0.0, na = 0.0, nb = 0.0;
2526
2527 for(MInt i = 0; i < nDim; i++) {
2528 nx0 += m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i]
2529 * m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[0][i];
2530 na += m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i] * (*vectorId).m_oldPos[i];
2531 nb +=
2532 m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i] * ((*vectorId).m_position[i] - (*vectorId).m_oldPos[i]);
2533 }
2534
2535 return (nx0 - na + (0.5 * particleDiameter)) / nb;
2536}
int32_t MInt
Definition: maiatypes.h:62
double MFloat
Definition: maiatypes.h:52

◆ checkCSI_CCD()

template<MInt nDim>
MBool ParticleCollision< nDim >::checkCSI_CCD ( const MFloat(&)  A[16],
const MFloat(&)  b_Matrix[16],
const MFloat(&)  m[5],
const MFloat detMinusB,
MFloat t1,
MFloat t2,
MFloat positive1,
MFloat positive2,
MInt iteration 
)
private

MBool LPT::checkCSI_CCD(const MFloat (&A)[16], const MFloat (&b_Matrix)[16], const MFloat (&m)[5], const MFloat& detMinusB, MFloat& t1, MFloat& t2, MFloat& positive1, MFloat& positive2, MInt& iteration)

      A is the matrix of Ellpsoid2
      b_Matrix is the build matrix by createMatrix_CCD independent of t
      m are the values build by createMatrix_CCD dependent of t
      detMinusB is det(-B) where B is the matrix of Ellipsoid3
      t1 is the beginning time
      t2 is the ending time
      positive1 is the u value of the local maximum for t1
      positive2 is the u value of the local maximum for t2
      iteration is the number of recursive calls

Aug-2013

Author
Christoph Siewert

Definition at line 2814 of file lptcollision.cpp.

2816 {
2817 TRACE();
2818
2819 if(t2 - t1 < 1.0E-13) {
2820 return false;
2821 } else {
2822 iteration++;
2823
2824 MFloat b_A[16];
2825 for(MInt q0 = 0; q0 < 16; q0++) {
2826 b_A[q0] = A[q0] * (positive1 - 1.0) - positive1 * b_Matrix[q0];
2827 }
2828
2829 MFloat b_positive1[5];
2830 for(MInt q0 = 0; q0 < 5; q0++) {
2831 b_positive1[q0] = -positive1 * m[q0];
2832 }
2833
2834 t1 = checkDynamicOverlap_CCD(b_A, b_positive1, t1, t2);
2835 if(t1 >= t2) {
2836 return false;
2837 } else {
2838 for(MInt q0 = 0; q0 < 16; q0++) {
2839 b_A[q0] = A[q0] * (positive2 - 1.0) - positive2 * b_Matrix[q0];
2840 }
2841
2842 for(MInt q0 = 0; q0 < 5; q0++) {
2843 b_positive1[q0] = -positive2 * m[q0];
2844 }
2845
2846 t2 = checkDynamicOverlap_CCD(b_A, b_positive1, t2, t1);
2847 if(t1 >= t2) {
2848 return false;
2849 } else {
2850 MFloat t_neu = (t1 + t2) / 2.0;
2851 MFloat positive_neu = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t_neu);
2852 if(positive_neu < 0.0) {
2853 return true;
2854 } else {
2855 positive1 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t1);
2856 MBool value = checkCSI_CCD(A, b_Matrix, m, detMinusB, t1, t_neu, positive1, positive_neu, iteration);
2857 if(value) {
2858 return true;
2859 } else {
2860 positive2 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t2);
2861 if(positive2 < 0.0) {
2862 return true;
2863 } else {
2864 return checkCSI_CCD(A, b_Matrix, m, detMinusB, t_neu, t2, positive_neu, positive2, iteration);
2865 }
2866 }
2867 }
2868 }
2869 }
2870 }
2871}
MFloat checkStaticOverlap_CCD(const MFloat(&b_Matrix)[16], const MFloat(&A)[16], const MFloat(&m)[5], const MFloat &detMinusB, MFloat &t1)
calculates if there is a local maximum of det(A*(u-1)-u*B) in u for a fixed value of t and if the val...
MFloat checkDynamicOverlap_CCD(const MFloat(&n)[16], const MFloat(&m)[5], MFloat t1, MFloat t2)
Performes BezierShot from "side", returns the first zero-crossing results in finding the roots of the...
MBool checkCSI_CCD(const MFloat(&A)[16], const MFloat(&b_Matrix)[16], const MFloat(&m)[5], const MFloat &detMinusB, MFloat &t1, MFloat &t2, MFloat &positive1, MFloat &positive2, MInt &iteration)
checks recursively if the ellipsoids are separated by subdividing the time intervals in smaller CSIs....
bool MBool
Definition: maiatypes.h:58

◆ checkDynamicOverlap_CCD()

template<MInt nDim>
MFloat ParticleCollision< nDim >::checkDynamicOverlap_CCD ( const MFloat(&)  n[16],
const MFloat(&)  m[5],
MFloat  t1,
MFloat  t2 
)
private

MFloat LPT::checkDynamicOverlap_CCD(const MFloat (&n)[16], const MFloat (&m)[5], const MInt& side)

Aug-2013

Author
Christoph Siewert

Definition at line 2909 of file lptcollision.cpp.

2910 {
2911 TRACE();
2912
2913 MInt side = 1;
2914 if(t2 < t1) {
2915 side = -1;
2916 MInt temp = (MInt)t2;
2917 t2 = t1;
2918 t1 = temp;
2919 }
2920
2921 MFloat t;
2922 MFloat AA;
2923 MFloat BB;
2924 MFloat CC;
2925 MFloat p_2;
2926 AA = (((((((((((((((m[0] * m[0] * (n[9] * n[9]) - n[5] * n[10] * (m[0] * m[0])) + 2.0 * n[10] * m[0] * m[1] * n[4])
2927 - 2.0 * m[0] * m[1] * n[8] * n[9])
2928 - 2.0 * m[0] * m[2] * n[4] * n[9])
2929 + 2.0 * n[5] * m[0] * m[2] * n[8])
2930 + m[1] * m[1] * (n[8] * n[8]))
2931 - n[0] * n[10] * (m[1] * m[1]))
2932 - 2.0 * m[1] * m[2] * n[4] * n[8])
2933 + 2.0 * n[0] * m[1] * m[2] * n[9])
2934 + m[2] * m[2] * (n[4] * n[4]))
2935 - n[0] * n[5] * (m[2] * m[2]))
2936 - m[4] * n[10] * (n[4] * n[4]))
2937 + 2.0 * m[4] * n[4] * n[8] * n[9])
2938 - m[4] * n[5] * (n[8] * n[8]))
2939 - m[4] * n[0] * (n[9] * n[9]))
2940 + m[4] * n[0] * n[5] * n[10];
2941 BB = (((((((((((((((((((((2.0 * n[13] * m[1] * (n[8] * n[8]) + 2.0 * n[14] * m[2] * (n[4] * n[4]))
2942 + 2.0 * n[12] * m[0] * (n[9] * n[9]))
2943 - m[3] * n[0] * (n[9] * n[9]))
2944 - m[3] * (n[8] * n[8]) * n[5])
2945 - m[3] * (n[4] * n[4]) * n[10])
2946 - 2.0 * n[13] * m[2] * n[4] * n[8])
2947 - 2.0 * m[1] * n[14] * n[4] * n[8])
2948 - 2.0 * n[12] * m[1] * n[8] * n[9])
2949 - 2.0 * m[0] * n[13] * n[8] * n[9])
2950 - 2.0 * n[12] * m[2] * n[4] * n[9])
2951 + 2.0 * n[12] * m[2] * n[8] * n[5])
2952 - 2.0 * m[0] * n[14] * n[4] * n[9])
2953 + 2.0 * m[0] * n[14] * n[8] * n[5])
2954 + 2.0 * n[13] * m[2] * n[0] * n[9])
2955 + 2.0 * m[1] * n[14] * n[0] * n[9])
2956 - 2.0 * n[14] * m[2] * n[0] * n[5])
2957 + 2.0 * n[12] * m[1] * n[4] * n[10])
2958 + 2.0 * m[0] * n[13] * n[4] * n[10])
2959 - 2.0 * n[13] * m[1] * n[0] * n[10])
2960 - 2.0 * n[12] * m[0] * n[5] * n[10])
2961 + 2.0 * m[3] * n[4] * n[8] * n[9])
2962 + m[3] * n[0] * n[5] * n[10];
2963 CC = (((((((((((((((n[12] * n[12] * (n[9] * n[9]) - n[5] * n[10] * (n[12] * n[12]))
2964 + 2.0 * n[10] * n[12] * n[13] * n[4])
2965 - 2.0 * n[12] * n[13] * n[8] * n[9])
2966 - 2.0 * n[12] * n[14] * n[4] * n[9])
2967 + 2.0 * n[5] * n[12] * n[14] * n[8])
2968 + n[13] * n[13] * (n[8] * n[8]))
2969 - n[0] * n[10] * (n[13] * n[13]))
2970 - 2.0 * n[13] * n[14] * n[4] * n[8])
2971 + 2.0 * n[0] * n[13] * n[14] * n[9])
2972 + n[14] * n[14] * (n[4] * n[4]))
2973 - n[0] * n[5] * (n[14] * n[14]))
2974 - n[15] * n[10] * (n[4] * n[4]))
2975 + 2.0 * n[15] * n[4] * n[8] * n[9])
2976 - n[15] * n[5] * (n[8] * n[8]))
2977 - n[15] * n[0] * (n[9] * n[9]))
2978 + n[15] * n[0] * n[5] * n[10];
2979 if(fabs(AA) > 1.0E-13) {
2980 p_2 = BB / (2.0 * AA);
2981 BB = p_2 * p_2 - CC / AA;
2982 if(BB > 0.0) {
2983 BB = side * sqrt(BB);
2984 t = -p_2 - BB;
2985 if((t >= t1) && (t <= t2)) {
2986 } else {
2987 t = -p_2 + BB;
2988 if((t >= t1) && (t <= t2)) {
2989 } else {
2990 t = side;
2991 }
2992 }
2993 } else {
2994 t = side;
2995 }
2996 } else if(fabs(BB) > 1.0E-13) {
2997 t = CC / BB;
2998 if((t >= t1) && (t <= t2)) {
2999 } else {
3000 t = side;
3001 }
3002 } else {
3003 t = side;
3004 }
3005
3006 return t;
3007}

◆ checkStaticOverlap_CCD()

template<MInt nDim>
MFloat ParticleCollision< nDim >::checkStaticOverlap_CCD ( const MFloat(&)  b_Matrix[16],
const MFloat(&)  A[16],
const MFloat(&)  m[5],
const MFloat detMinusB,
MFloat t 
)
private

MFloat LPT::checkStaticOverlap_CCD(const MFloat (&b_Matrix)[16], const MFloat (&A)[16], const MFloat (&m)[5], const MFloat& detMinusB, MFloat& t)

Aug-2013

Author
Christoph Siewert

Definition at line 2684 of file lptcollision.cpp.

2685 {
2686 TRACE();
2687
2688
2689 const MFloat eps = 1.0E-13;
2690
2691 MFloat b[16];
2692 copy(b_Matrix, b_Matrix + 16, b);
2693 b[12] = b[12] + m[0] * t;
2694 b[13] = b[13] + m[1] * t;
2695 b[14] = b[14] + m[2] * t;
2696 b[15] = b[15] + m[3] * t + m[4] * t * t;
2697
2698 MFloat b12s = b[4] * b[4];
2699 MFloat b13s = b[8] * b[8];
2700 MFloat b14s = b[12] * b[12];
2701 MFloat b23s = b[9] * b[9];
2702 MFloat b24s = b[13] * b[13];
2703 MFloat b34s = b[14] * b[14];
2704 MFloat b2233 = b[5] * b[10];
2705 MFloat termA = (b[0] * A[5] * A[10] + b[5] * A[0] * A[10]) + b[10] * A[0] * A[5];
2706 MFloat termB = ((b2233 - b23s) * A[0] + (b[0] * b[10] - b13s) * A[5]) + (b[0] * b[5] - b12s) * A[10];
2707
2708 MFloat T4 = -A[0] * A[5] * A[10];
2709 MFloat T3 = termA + b[15] * T4;
2710 MFloat T2 = (((termA * b[15] - termB) - b34s * A[0] * A[5]) - b14s * A[5] * A[10]) - b24s * A[0] * A[10];
2711 MFloat tmp1 = termB * b[15];
2712 MFloat tmp2 = b[0] * (b2233 + A[5] * b34s + A[10] * b24s - b23s);
2713 MFloat tmp3 = b[5] * (A[0] * b34s + A[10] * b14s - b13s);
2714 MFloat tmp4 = b[10] * (A[0] * b24s + A[5] * b14s - b12s);
2715 MFloat tmp5 = b[14] * (A[0] * b[9] * b[13] + A[5] * b[8] * b[12]) + b[4] * (A[10] * b[12] * b[13] - b[8] * b[9]);
2716 tmp5 = tmp5 + tmp5;
2717 MFloat T1 = -tmp1 + tmp2 + tmp3 + tmp4 - tmp5;
2718 MFloat T0 = detMinusB;
2719
2720 MFloat t4 = (T0 + T1 + T2 + T3 + T4);
2721 MFloat t3 = (-T1 - 2 * T2 - 3 * T3 - 4 * T4);
2722 MFloat t2 = (T2 + 3 * T3 + 6 * T4);
2723 MFloat t1 = (-T3 - 4 * T4);
2724 MFloat t0 = T4;
2725
2726 MFloat a = 4 * t4;
2727 MFloat bb = 3 * t3;
2728 MFloat c = 2 * t2;
2729 MFloat d = 1 * t1;
2730 if(fabs(a) > eps) {
2731 MFloat p = (3 * a * c - bb * bb) / (3 * a * a);
2732 MFloat q = (2 * bb * bb * bb - 9 * a * bb * c + 27 * a * a * d) / (27 * a * a * a);
2733 if(fabs(p) > eps) {
2734 if(p > 0) {
2735 MFloat term = sqrt(p / 3.0);
2736 MFloat u = -2 * term * sinh((1.0 / 3.0) * asinh((3 * q / (2 * p)) / term)) - bb / (3 * a);
2737 return testU_CCD(u, t4, t3, t2, t1, t0);
2738 } else {
2739 MFloat test = 4 * p * p * p + 27 * q * q;
2740 MFloat term = sqrt(-p / 3.0);
2741 if(test > 0) {
2742 MFloat u =
2743 -2 * fabs(q) / q * term * cosh((1.0 / 3.0) * acosh((-3 * fabs(q) / (2 * p)) / term)) - bb / (3 * a);
2744 return testU_CCD(u, t4, t3, t2, t1, t0);
2745 } else {
2746 for(MInt that = 0; that < 3; that++) {
2747 MFloat u =
2748 2 * term * cos((1.0 / 3.0) * acos((3 * q / (2 * p)) / term) - that * 2 * PI / 3.0) - bb / (3 * a);
2749 MFloat positive = testU_CCD(u, t4, t3, t2, t1, t0);
2750 if(positive > -1) {
2751 return positive;
2752 }
2753 }
2754 }
2755 }
2756 } else {
2757 if(fabs(q) > eps) {
2758 MFloat u = pow(-q, (1.0 / 3.0)) - bb / (3 * a);
2759 return testU_CCD(u, t4, t3, t2, t1, t0);
2760 } else {
2761 MFloat u = -bb / (3 * a);
2762 return testU_CCD(u, t4, t3, t2, t1, t0);
2763 }
2764 }
2765 } else {
2766 if(fabs(bb) > eps) {
2767 MFloat p_2 = c / bb / 2.0;
2768 MFloat q = d / bb;
2769 MFloat temp = p_2 * p_2 - q;
2770 if(temp >= 0) {
2771 temp = sqrt(temp);
2772 MFloat u = p_2 + temp;
2773 MFloat positive = testU_CCD(u, t4, t3, t2, t1, t0);
2774 if(positive > -1) {
2775 return positive;
2776 }
2777 u = p_2 - temp;
2778 return testU_CCD(u, t4, t3, t2, t1, t0);
2779 } else {
2780 return -F1;
2781 }
2782 } else {
2783 if(fabs(c) > eps) {
2784 MFloat u = d / c;
2785 return testU_CCD(u, t4, t3, t2, t1, t0);
2786 } else {
2787 return -F1;
2788 }
2789 }
2790 }
2791
2792 return -F1;
2793}
MFloat testU_CCD(const MFloat &u, const MFloat &t4, const MFloat &t3, const MFloat &t2, const MFloat &t1, const MFloat &t0)
calculates the value of the forth order polynomial and returns it if positive other returns -1
constexpr std::underlying_type< FcCell >::type p(const FcCell property)
Converts property name to underlying integer value.
T cos(const T a, const T b, const T x)
Cosine slope filter.
Definition: filter.h:125
Definition: contexttypes.h:19

◆ collisionCheck()

template<MInt nDim>
MFloat ParticleCollision< nDim >::collisionCheck ( lptParticleI  ,
lptParticleI  ,
MFloat   
)
private

MFloat LPT::collisionCheck(MInt i, MInt j, MFloat currCollTime)

version: December-09

Author
Rudie Kunnen

Definition at line 1184 of file lptcollision.cpp.

1185 {
1186 // TRACE();
1187
1188 MFloat collTime = -1.0;
1189
1190 switch(m_collisionModel) {
1191 case 1:
1192 case 3:
1193 case 5: { // retroactive collision detection: search for overlap between particles
1194 MFloat currDist, collDist, squaredw = 0.0, squaredr0 = 0.0;
1195 MFloat wdotr0 = 0.0, tempa, tempb;
1196 // currDist = squared distance between centres of particles i and j
1197 // collDist = squared distance between centres of particles i and j
1198 // at collision, i.e. the square of the sum of radii
1199 currDist = distance(i, j);
1200 collDist = POW2(0.5 * ((*i).m_diameter + (*j).m_diameter));
1201
1202 // collision condition: particles overlap
1203 if(currDist < collDist) {
1204 // calculation of collision time, uses square of vector w,
1205 // square of vector r0, and inner product (w.r0)
1206 for(MInt k = 0; k < nDim; k++) {
1207 tempa = (((*i).m_position[k] - (*i).m_oldPos[k]) - ((*j).m_position[k] - (*j).m_oldPos[k])) / m_timeStep;
1208 tempb = (*i).m_oldPos[k] - (*j).m_oldPos[k];
1209 squaredw += POW2(tempa);
1210 squaredr0 += POW2(tempb);
1211 wdotr0 += tempa * tempb;
1212 }
1213 collTime = -(wdotr0 / squaredw) * (1.0 - sqrt(1.0 - squaredw * (squaredr0 - collDist) / POW2(wdotr0)));
1214 }
1215 } break;
1216
1217 case 2:
1218 case 4:
1219 case 6: { // proactive collision detection: calculate time of collision and
1220 // compare with the particle time step
1221 MFloat bigK, squaredw = 0.0, squaredr0 = 0.0, wdotr0 = 0.0;
1222 MFloat tempa, tempb;
1223
1224 for(MInt k = 0; k < nDim; k++) {
1225 tempa = (((*i).m_position[k] - (*i).m_oldPos[k]) - ((*j).m_position[k] - (*j).m_oldPos[k])) / m_timeStep;
1226 tempb = (*i).m_oldPos[k] - (*j).m_oldPos[k];
1227 squaredw += POW2(tempa);
1228 squaredr0 += POW2(tempb);
1229 wdotr0 += tempa * tempb;
1230 }
1231
1232 // tempb holds the square of the separation distance upon collision
1233 // (sum of radii, squared)
1234 tempb = POW2(0.5 * ((*i).m_diameter + (*j).m_diameter));
1235 bigK = squaredw * (squaredr0 - tempb) / POW2(wdotr0);
1236
1237 if(bigK <= 1.0) {
1238 // There are real solutions to the equation that gives the particle
1239 // collision times, i.e. there will be a collision given the current
1240 // particle paths.
1241 // tempa holds the time of minimal separation
1242 // squaredw and squaredr0 hold the two collision times
1243 bigK = sqrt(1.0 - bigK);
1244 tempa = -wdotr0 / squaredw;
1245 squaredw = tempa * (1.0 - bigK);
1246 squaredr0 = tempa * (1.0 + bigK);
1247 tempb = (squaredw < squaredr0) ? squaredw : squaredr0;
1248 // tempb holds the smaller of the two times
1249 if((tempb < m_timeStep) && (tempb >= currCollTime)) {
1250 collTime = tempb;
1251 }
1252 } // when bigK > 1.0 there are no real solutions: particles move without
1253 // (ever) touching (based on current velocity & position)
1254 } break;
1255
1256 default: {
1257 mTerm(1, AT_, "Unknown particle collision type");
1258 }
1259 }
1260
1261 // schedule the collision only when both particles are still valid and present within the domain
1262 if(!(*i).toBeDeleted() && !(*j).toBeDeleted()) {
1263 return collTime;
1264 } else {
1265 return -1.0;
1266 }
1267}
void mTerm(const MInt errorCode, const MString &location, const MString &message)
Definition: functions.cpp:29
constexpr Real POW2(const Real x)
Definition: functions.h:119
MFloat distance(const MFloat *a, const MFloat *b)
Definition: maiamath.h:249

◆ collisionCheckEECCD()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckEECCD ( lptEllipticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckSECCD(partListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Aug-2013

Author
Christoph Siewert

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

Definition at line 2129 of file lptcollision.cpp.

2129 {
2130 TRACE();
2131
2132 const MInt dim3 = 3;
2133
2134 MFloat deltaXSq = F0;
2135 MFloat deltaVSq = F0;
2136 MFloat deltaVdeltaX = F0;
2137 MFloat dist[dim3];
2138 for(MInt d = 0; d < dim3; ++d) {
2139 dist[d] = i2->m_oldPos[d] - i3->m_oldPos[d];
2140 MFloat deltaV = ((i2->m_position[d] - i2->m_oldPos[d]) - (i3->m_position[d] - i3->m_oldPos[d])) / m_timeStep;
2141 deltaXSq += POW2(dist[d]);
2142 deltaVSq += POW2(deltaV);
2143 deltaVdeltaX += dist[d] * deltaV;
2144 }
2145 if(approx(deltaVSq, F0, MFloatEps)) { // no relative velocity, check for overlap only
2147 return;
2148 }
2149
2150 MFloat i2minR = min(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
2151 MFloat i2maxR = max(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
2152 MFloat i3minR = min(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
2153 MFloat i3maxR = max(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
2154 MFloat RminSq = POW2(i2minR + i3minR);
2155 MFloat RmaxSq = POW2(i2maxR + i3maxR);
2156
2157 // as a first rough criterion, check the distance between the centroids
2158 // if larger than the sum of major axes, then
2159 // for sure there is no collision between the two
2160 MFloat bigKmax = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RmaxSq);
2161 if(bigKmax < F0) {
2162 return; // only complex solutions, no collision on current route
2163 }
2164 bigKmax = sqrt(bigKmax);
2165 MFloat tempt1 = (-deltaVdeltaX - bigKmax) / deltaVSq;
2166 MFloat tempt2 = (-deltaVdeltaX + bigKmax) / deltaVSq;
2167 MFloat t1max = min(tempt1, tempt2);
2168 MFloat t2max = max(tempt1, tempt2);
2169 if(t1max > m_timeStep) {
2170 return; // collision begin in the future
2171 }
2172 if(t2max < F0) {
2173 return; // collision end in the past
2174 }
2175
2176 // if smaller than the sum of the minor axis, then
2177 // a collision between the two is certain
2178 MFloat bigKmin = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RminSq);
2179 if(bigKmin >= F0) {
2180 bigKmin = sqrt(bigKmin);
2181 tempt1 = (-deltaVdeltaX - bigKmin) / deltaVSq;
2182 tempt2 = (-deltaVdeltaX + bigKmin) / deltaVSq;
2183 MFloat t1min = min(tempt1, tempt2);
2184 MFloat t2min = max(tempt1, tempt2);
2185 if((t1min <= m_timeStep) && (t2min >= F0)) {
2186 collQueueElemEllipsoid thisColl;
2187 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + t1min;
2188 thisColl.part0 = (*i2).m_partId;
2189 thisColl.part1 = (*i3).m_partId;
2190 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
2191 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
2192 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
2193 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
2194 thisColl.dens0 = (*i2).m_densityRatio;
2195 thisColl.dens1 = (*i3).m_densityRatio;
2196 thisColl.collPosX = i2->m_oldPos[0] + (i2->m_position[0] - i2->m_oldPos[0]) * t1min / m_timeStep;
2197 thisColl.collPosY = i2->m_oldPos[1] + (i2->m_position[1] - i2->m_oldPos[1]) * t1min / m_timeStep;
2198 thisColl.collPosZ = i2->m_oldPos[2] + (i2->m_position[2] - i2->m_oldPos[2]) * t1min / m_timeStep;
2199 collQueueEllipsoid.push(thisColl);
2200 return;
2201 }
2202 }
2203
2204 // distance is smaller than maximal distance but larger than minimal distance
2205 // so collision may occur
2206
2207
2208 MFloat e0_1 = i2->m_quaternion[0];
2209 MFloat e1_1 = i2->m_quaternion[1];
2210 MFloat e2_1 = i2->m_quaternion[2];
2211 MFloat e3_1 = i2->m_quaternion[3];
2212
2213 MFloat e0_2 = i3->m_quaternion[0];
2214 MFloat e1_2 = i3->m_quaternion[1];
2215 MFloat e2_2 = i3->m_quaternion[2];
2216 MFloat e3_2 = i3->m_quaternion[3];
2217
2218 MFloat MA[16];
2219 MA[0] = ((e0_1 * e0_1 + e1_1 * e1_1) - e2_1 * e2_1) - e3_1 * e3_1;
2220 MA[4] = 2.0 * e1_1 * e2_1 - 2.0 * e0_1 * e3_1;
2221 MA[8] = 2.0 * e0_1 * e2_1 + 2.0 * e1_1 * e3_1;
2222 MA[12] = i2->m_oldPos[0];
2223 MA[1] = 2.0 * e0_1 * e3_1 + 2.0 * e1_1 * e2_1;
2224 MA[5] = ((e0_1 * e0_1 - e1_1 * e1_1) + e2_1 * e2_1) - e3_1 * e3_1;
2225 MA[9] = 2.0 * e2_1 * e3_1 - 2.0 * e0_1 * e1_1;
2226 MA[13] = i2->m_oldPos[1];
2227 MA[2] = 2.0 * e1_1 * e3_1 - 2.0 * e0_1 * e2_1;
2228 MA[6] = 2.0 * e0_1 * e1_1 + 2.0 * e2_1 * e3_1;
2229 MA[10] = ((e0_1 * e0_1 - e1_1 * e1_1) - e2_1 * e2_1) + e3_1 * e3_1;
2230 MA[14] = i2->m_oldPos[2];
2231 MA[3] = F0;
2232 MA[7] = F0;
2233 MA[11] = F0;
2234 MA[15] = F1;
2235
2236 MFloat invMB[16];
2237 invMB[0] = ((e0_2 * e0_2 + e1_2 * e1_2) - e2_2 * e2_2) - e3_2 * e3_2;
2238 invMB[4] = 2.0 * e0_2 * e3_2 + 2.0 * e1_2 * e2_2;
2239 invMB[8] = 2.0 * e1_2 * e3_2 - 2.0 * e0_2 * e2_2;
2240 invMB[12] = -(invMB[0] * i3->m_oldPos[0] + invMB[4] * i3->m_oldPos[1] + invMB[8] * i3->m_oldPos[2]);
2241 invMB[1] = 2.0 * e1_2 * e2_2 - 2.0 * e0_2 * e3_2;
2242 invMB[5] = ((e0_2 * e0_2 - e1_2 * e1_2) + e2_2 * e2_2) - e3_2 * e3_2;
2243 invMB[9] = 2.0 * e0_2 * e1_2 + 2.0 * e2_2 * e3_2;
2244 invMB[13] = -(invMB[1] * i3->m_oldPos[0] + invMB[5] * i3->m_oldPos[1] + invMB[9] * i3->m_oldPos[2]);
2245 invMB[2] = 2.0 * e0_2 * e2_2 + 2.0 * e1_2 * e3_2;
2246 invMB[6] = 2.0 * e2_2 * e3_2 - 2.0 * e0_2 * e1_2;
2247 invMB[10] = ((e0_2 * e0_2 - e1_2 * e1_2) - e2_2 * e2_2) + e3_2 * e3_2;
2248 invMB[14] = -(invMB[2] * i3->m_oldPos[0] + invMB[6] * i3->m_oldPos[1] + invMB[10] * i3->m_oldPos[2]);
2249 invMB[3] = F0;
2250 invMB[7] = F0;
2251 invMB[11] = F0;
2252 invMB[15] = F1;
2253
2254 MFloat v_1[3];
2255 v_1[0] = (i2->m_position[0] - i2->m_oldPos[0]);
2256 v_1[1] = (i2->m_position[1] - i2->m_oldPos[1]);
2257 v_1[2] = (i2->m_position[2] - i2->m_oldPos[2]);
2258
2259 MFloat v_2[3];
2260 v_2[0] = (i3->m_position[0] - i3->m_oldPos[0]);
2261 v_2[1] = (i3->m_position[1] - i3->m_oldPos[1]);
2262 v_2[2] = (i3->m_position[2] - i3->m_oldPos[2]);
2263
2264 MFloat A[16] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0};
2265 A[0] = 1 / (i2->m_semiMinorAxis * i2->m_semiMinorAxis);
2266 A[5] = A[0];
2267 A[10] = 1 / (i2->m_semiMinorAxis * i2->m_semiMinorAxis * i2->m_aspectRatio * i2->m_aspectRatio);
2268
2269 MFloat detMinusB = -1
2270 / (i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_semiMinorAxis
2271 * i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_aspectRatio * i3->m_aspectRatio);
2272
2273 MFloat m[5];
2274 MFloat b_Matrix[16];
2275 createMatrix_CCD(MA, v_1, invMB, v_2, i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio, b_Matrix, m);
2276 MInt iteration = 0;
2277 MFloat t1 = 0.0;
2278 MFloat t2 = 1.0;
2279 /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
2280 /* setup until here */
2281
2282 MBool collision;
2283 MFloat positive1 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t1);
2284 if(positive1 < 0.0) {
2285 collision = true;
2286 } else {
2287 MFloat positive2 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t2);
2288 if(positive2 < 0.0) {
2289 collision = true;
2290 } else {
2291 collision = checkCSI_CCD(A, b_Matrix, m, detMinusB, t1, t2, positive1, positive2, iteration);
2292 }
2293 }
2294 /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
2295 /* collision detection until here */
2296 if(collision) {
2297 collQueueElemEllipsoid thisColl;
2298 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time;
2299 thisColl.part0 = (*i2).m_partId;
2300 thisColl.part1 = (*i3).m_partId;
2301 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
2302 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
2303 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
2304 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
2305 thisColl.dens0 = (*i2).m_densityRatio;
2306 thisColl.dens1 = (*i3).m_densityRatio;
2307 thisColl.collPosX = i2->m_position[0];
2308 thisColl.collPosY = i2->m_position[1];
2309 thisColl.collPosZ = i2->m_position[2];
2310 collQueueEllipsoid.push(thisColl);
2311 }
2312}
void collisionCheckEERetroActive(lptEllipticleI, lptEllipticleI)
Collision check for ellipsoids i2 and i3 based on overlap criterion, and store collision event when f...
void createMatrix_CCD(const MFloat(&MA)[16], const MFloat(&u1)[3], const MFloat(&invMB)[16], const MFloat(&u2)[3], const MFloat &a_2, const MFloat &c_2, MFloat(&n)[16], MFloat(&m)[5])
calculates M_A^T*(M_B^(-1))^T*B*(M_B^(-1))*M_A, write it the part independent of t in n and the other...
std::queue< collQueueElemEllipsoid > collQueueEllipsoid
Definition: lptcollision.h:139
MBool approx(const T &, const U &, const T)
Definition: functions.h:272
MInt globalTimeStep
MFloat dist(const Point< DIM > &p, const Point< DIM > &q)
Definition: pointbox.h:54

◆ collisionCheckEEProActive()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckEEProActive ( lptEllipticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckEEProActive(ellipsListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Author
Christoph Siewert May-2013

Definition at line 1698 of file lptcollision.cpp.

1699 {
1700 TRACE();
1701
1702
1703 MFloat deltaXSq = F0;
1704 MFloat deltaVSq = F0;
1705 MFloat deltaVdeltaX = F0;
1706 MFloat dist[nDim];
1707 for(MInt d = 0; d < nDim; ++d) {
1708 dist[d] = i2->m_oldPos[d] - i3->m_oldPos[d];
1709 MFloat deltaV = ((i2->m_position[d] - i2->m_oldPos[d]) - (i3->m_position[d] - i3->m_oldPos[d])) / m_timeStep;
1710 deltaXSq += POW2(dist[d]);
1711 deltaVSq += POW2(deltaV);
1712 deltaVdeltaX += dist[d] * deltaV;
1713 }
1714 if(approx(deltaVSq, F0, MFloatEps)) { // no relative velocity, check for overlap only
1716 return;
1717 }
1718
1719 MFloat i2minR = min(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
1720 MFloat i2maxR = max(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
1721 MFloat i3minR = min(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
1722 MFloat i3maxR = max(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
1723 MFloat RminSq = POW2(i2minR + i3minR);
1724 MFloat RmaxSq = POW2(i2maxR + i3maxR);
1725
1726 // as a first rough criterion, check the distance between the centroids
1727 // if larger than the sum of major axes, then
1728 // for sure there is no collision between the two
1729 MFloat bigKmax = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RmaxSq);
1730 if(bigKmax < F0) {
1731 return; // only complex solutions, no collision on current route
1732 }
1733 bigKmax = sqrt(bigKmax);
1734 MFloat tempt1 = (-deltaVdeltaX - bigKmax) / deltaVSq;
1735 MFloat tempt2 = (-deltaVdeltaX + bigKmax) / deltaVSq;
1736 MFloat t1max = min(tempt1, tempt2);
1737 MFloat t2max = max(tempt1, tempt2);
1738 if(t1max > m_timeStep) {
1739 return; // collision begin in the future
1740 }
1741 if(t2max < F0) {
1742 return; // collision end in the past
1743 }
1744
1745 // if smaller than the sum of the minor axis, then
1746 // a collision between the two is certain
1747 MFloat bigKmin = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RminSq);
1748 if(bigKmin >= F0) {
1749 bigKmin = sqrt(bigKmin);
1750 tempt1 = (-deltaVdeltaX - bigKmin) / deltaVSq;
1751 tempt2 = (-deltaVdeltaX + bigKmin) / deltaVSq;
1752 MFloat t1min = min(tempt1, tempt2);
1753 MFloat t2min = max(tempt1, tempt2);
1754 if((t1min <= m_timeStep) && (t2min >= F0)) {
1755 collQueueElemEllipsoid thisColl;
1756 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + t1min;
1757 thisColl.part0 = (*i2).m_partId;
1758 thisColl.part1 = (*i3).m_partId;
1759 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1760 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
1761 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1762 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
1763 thisColl.dens0 = (*i2).m_densityRatio;
1764 thisColl.dens1 = (*i3).m_densityRatio;
1765 thisColl.collPosX = i2->m_oldPos[0] + (i2->m_position[0] - i2->m_oldPos[0]) * t1min / m_timeStep;
1766 thisColl.collPosY = i2->m_oldPos[1] + (i2->m_position[1] - i2->m_oldPos[1]) * t1min / m_timeStep;
1767 thisColl.collPosZ = i2->m_oldPos[2] + (i2->m_position[2] - i2->m_oldPos[2]) * t1min / m_timeStep;
1768 collQueueEllipsoid.push(thisColl);
1769 return;
1770 }
1771 }
1772
1773 // distance is smaller than maximal distance but larger than minimal distance
1774 // so collision may occur
1775 // consider distance between the bodies with the orientation at the closet distance
1776 // between the two centroids (might not be a good choose with the ellipsoids rotate very fast
1777 // while tranlate very slowly
1778 MFloat a1[3], b1[3], c1[3];
1779 MFloat a2[3], b2[3], c2[3];
1780 MFloat distTminSq;
1781 MFloat tmin = (-deltaVdeltaX / deltaVSq) / m_timeStep;
1782 if((tmin < F0) || (tmin > F1)) {
1783 MFloat partQuatA[4], partQuatB[4];
1784 if(tmin < F0) {
1785 for(MInt i = 0; i < 4; ++i) {
1786 partQuatA[i] = i2->m_oldQuaternion[i];
1787 partQuatB[i] = i3->m_oldQuaternion[i];
1788 }
1789 distTminSq = deltaXSq;
1790 } else {
1791 for(MInt i = 0; i < 4; ++i) {
1792 partQuatA[i] = i2->m_quaternion[i];
1793 partQuatB[i] = i3->m_quaternion[i];
1794 }
1795 distTminSq = F0;
1796 for(MInt i = 0; i < nDim; ++i) {
1797 distTminSq += POW2(i2->m_position[i] - i3->m_position[i]);
1798 }
1799 }
1800 // Calculate the transformation matrix A of orientation of ellipsoid i2
1801 a1[0] = 1.0 - 2.0 * (partQuatA[2] * partQuatA[2] + partQuatA[3] * partQuatA[3]);
1802 a1[1] = 2.0 * (partQuatA[1] * partQuatA[2] + partQuatA[0] * partQuatA[3]);
1803 a1[2] = 2.0 * (partQuatA[1] * partQuatA[3] - partQuatA[0] * partQuatA[2]);
1804 b1[0] = 2.0 * (partQuatA[1] * partQuatA[2] - partQuatA[0] * partQuatA[3]);
1805 b1[1] = 1.0 - 2.0 * (partQuatA[1] * partQuatA[1] + partQuatA[3] * partQuatA[3]);
1806 b1[2] = 2.0 * (partQuatA[2] * partQuatA[3] + partQuatA[0] * partQuatA[1]);
1807 c1[0] = 2.0 * (partQuatA[1] * partQuatA[3] + partQuatA[0] * partQuatA[2]);
1808 c1[1] = 2.0 * (partQuatA[2] * partQuatA[3] - partQuatA[0] * partQuatA[1]);
1809 c1[2] = 1.0 - 2.0 * (partQuatA[1] * partQuatA[1] + partQuatA[2] * partQuatA[2]);
1810
1811 // Calculate the transformation matrix B of orientation of ellipsoid i3
1812 a2[0] = 1.0 - 2.0 * (partQuatB[2] * partQuatB[2] + partQuatB[3] * partQuatB[3]);
1813 a2[1] = 2.0 * (partQuatB[1] * partQuatB[2] + partQuatB[0] * partQuatB[3]);
1814 a2[2] = 2.0 * (partQuatB[1] * partQuatB[3] - partQuatB[0] * partQuatB[2]);
1815 b2[0] = 2.0 * (partQuatB[1] * partQuatB[2] - partQuatB[0] * partQuatB[3]);
1816 b2[1] = 1.0 - 2.0 * (partQuatB[1] * partQuatB[1] + partQuatB[3] * partQuatB[3]);
1817 b2[2] = 2.0 * (partQuatB[2] * partQuatB[3] + partQuatB[0] * partQuatB[1]);
1818 c2[0] = 2.0 * (partQuatB[1] * partQuatB[3] + partQuatB[0] * partQuatB[2]);
1819 c2[1] = 2.0 * (partQuatB[2] * partQuatB[3] - partQuatB[0] * partQuatB[1]);
1820 c2[2] = 1.0 - 2.0 * (partQuatB[1] * partQuatB[1] + partQuatB[2] * partQuatB[2]);
1821 } else {
1822 // slerp(i2->m_oldQuaternion, i2->m_quaternion, tmin, partQuatA, 4);
1823 // slerp(i3->m_oldQuaternion, i3->m_quaternion, tmin, partQuatB, 4);
1824 const MFloat* e;
1825 e = i2->m_oldQuaternion.data();
1826 a1[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1827 a1[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1828 a1[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1829 e = i2->m_quaternion.data();
1830 b1[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1831 b1[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1832 b1[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1833 slerp(a1, b1, tmin, c1, 3);
1834
1835 // generate orthonormal basis using Gram-Schmidt and cross-product
1836 for(MInt dim = 0; dim < 3; ++dim) {
1837 a1[dim] = c1[dim];
1838 }
1839 a1[0] -= F1;
1840 normalize(a1, 3);
1841 MFloat innerProd = F0;
1842 for(MInt dim = 0; dim < 3; ++dim) {
1843 innerProd += c1[dim] * a1[dim];
1844 }
1845 for(MInt dim = 0; dim < 3; ++dim) {
1846 b1[dim] = a1[dim] - innerProd * c1[dim];
1847 }
1848 normalize(b1, 3);
1849 a1[0] = b1[1] * c1[2] - b1[2] * c1[1];
1850 a1[1] = b1[2] * c1[0] - b1[0] * c1[2];
1851 a1[2] = b1[0] * c1[1] - b1[1] * c1[0];
1852 normalize(a1, 3);
1853 // second ellipsoid
1854 e = i3->m_oldQuaternion.data();
1855 a2[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1856 a2[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1857 a2[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1858 e = i3->m_quaternion.data();
1859 b2[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1860 b2[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1861 b2[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1862 slerp(a2, b2, tmin, c2, 3);
1863
1864 // generate orthonormal basis using Gram-Schmidt and cross-product
1865 for(MInt dim = 0; dim < nDim; ++dim) {
1866 a2[dim] = c2[dim];
1867 }
1868 a2[0] -= F1;
1869 normalize(a2, 3);
1870 innerProd = F0;
1871 for(MInt dim = 0; dim < nDim; ++dim) {
1872 innerProd += c2[dim] * a2[dim];
1873 }
1874 for(MInt dim = 0; dim < nDim; ++dim) {
1875 b2[dim] = a2[dim] - innerProd * c2[dim];
1876 }
1877 normalize(b2, 3);
1878 a2[0] = b2[1] * c2[2] - b2[2] * c2[1];
1879 a2[1] = b2[2] * c2[0] - b2[0] * c2[2];
1880 a2[2] = b2[0] * c2[1] - b2[1] * c2[0];
1881 normalize(a2, 3);
1882
1883 distTminSq = F0;
1884 for(MInt dim = 0; dim < nDim; ++dim) {
1885 distTminSq += POW2((i2->m_position[dim] - i3->m_position[dim]) * tmin
1886 + (i2->m_oldPos[dim] - i3->m_oldPos[dim]) * (1 - tmin));
1887 }
1888 }
1889
1890 // next, apply the method proposed by Zheng et al., Phys. Rev. E 79, 057702 (2009)
1891 // to determine the minimal distance between the two bodies
1892 // at the current orientation/separation
1893
1894 // determine minimal distance at contact between the particles
1895 // distance = separation vector of midpoints
1896 // l1, m1, n1 = principal orientation vectors of ellipsoid i2
1897 // l2, m2, n2 = principal orientation vectors of ellipsoid i3
1898 // store the minimal distance in largestCollDistSquared
1899 EllipsoidDistance theDistance(dist, a1, b1, c1, a2, b2, c2, (*i2).m_semiMinorAxis, (*i2).m_semiMinorAxis,
1900 (*i2).m_semiMinorAxis * (*i2).m_aspectRatio, (*i3).m_semiMinorAxis,
1901 (*i3).m_semiMinorAxis, (*i3).m_semiMinorAxis * (*i3).m_aspectRatio);
1902 MFloat largestCollDistSquared = theDistance.ellipsoids();
1903 largestCollDistSquared = POW2(largestCollDistSquared);
1904
1905 if(distTminSq < largestCollDistSquared) {
1906 collQueueElemEllipsoid thisColl;
1907 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + tmin*m_particleTimeStep;
1908 thisColl.part0 = (*i2).m_partId;
1909 thisColl.part1 = (*i3).m_partId;
1910 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1911 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
1912 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1913 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
1914 thisColl.dens0 = (*i2).m_densityRatio;
1915 thisColl.dens1 = (*i3).m_densityRatio;
1916 thisColl.collPosX = i2->m_oldPos[0] + (i2->m_position[0] - i2->m_oldPos[0]) * tmin;
1917 thisColl.collPosY = i2->m_oldPos[1] + (i2->m_position[1] - i2->m_oldPos[1]) * tmin;
1918 thisColl.collPosZ = i2->m_oldPos[2] + (i2->m_position[2] - i2->m_oldPos[2]) * tmin;
1919 collQueueEllipsoid.push(thisColl);
1920 }
1921}
void slerp(const MFloat *before, const MFloat *now, const MFloat time, MFloat *result, const MInt length)
Definition: lptlib.h:157
void normalize(std::array< T, N > &u)
Definition: maiamath.h:191

◆ collisionCheckEERetroActive()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckEERetroActive ( lptEllipticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckEERetroActive( ellipsListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Author
Rudie Kunnen, Feb-2011

Definition at line 1931 of file lptcollision.cpp.

1932 {
1933 TRACE();
1934
1935 MFloat dist[nDim];
1936 MFloat totalDistanceSquared = 0.0;
1937
1938 // check offset
1939 // particles before the plane x = m_particleCollOffset are not considered
1940 if((*i2).m_position[0] < m_offset) {
1941 return;
1942 }
1943 if((*i3).m_position[0] < m_offset) {
1944 return;
1945 }
1946
1947 for(MInt i = 0; i < nDim; i++) {
1948 dist[i] = (*i3).m_position[i] - (*i2).m_position[i];
1949 totalDistanceSquared += POW2(dist[i]);
1950 }
1951
1952 MFloat minLength2, maxLength2, minLength3, maxLength3;
1953 minLength2 = (*i2).m_semiMinorAxis * (*i2).m_aspectRatio;
1954 if(minLength2 < (*i2).m_semiMinorAxis) {
1955 maxLength2 = (*i2).m_semiMinorAxis;
1956 } else {
1957 maxLength2 = minLength2;
1958 minLength2 = (*i2).m_semiMinorAxis;
1959 }
1960 minLength3 = (*i3).m_semiMinorAxis * (*i3).m_aspectRatio;
1961 if(minLength3 < (*i3).m_semiMinorAxis) {
1962 maxLength3 = (*i3).m_semiMinorAxis;
1963 } else {
1964 maxLength3 = minLength3;
1965 minLength3 = (*i3).m_semiMinorAxis;
1966 }
1967
1968 // as a first rough criterion, check the distance between the centroids
1969 // if larger than the sum of major axes, then
1970 // for sure there is no collision between the two
1971 MFloat largestCollDistSquared = POW2(maxLength2 + maxLength3);
1972 if(totalDistanceSquared > largestCollDistSquared) {
1973 return;
1974 }
1975 // if smaller than the sum of the minor axis, then
1976 // for sure there is a collision between the two
1977 MFloat smallestCollDistSquared = POW2(minLength2 + minLength3);
1978 if(totalDistanceSquared < smallestCollDistSquared) {
1979 collQueueElemEllipsoid thisColl;
1980 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time;
1981 thisColl.part0 = (*i2).m_partId;
1982 thisColl.part1 = (*i3).m_partId;
1983 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1984 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
1985 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1986 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
1987 thisColl.dens0 = (*i2).m_densityRatio;
1988 thisColl.dens1 = (*i3).m_densityRatio;
1989 thisColl.collPosX = i2->m_position[0];
1990 thisColl.collPosY = i2->m_position[1];
1991 thisColl.collPosZ = i2->m_position[2];
1992 collQueueEllipsoid.push(thisColl);
1993 return;
1994 }
1995
1996 // distance is smaller than maximal distance but larger than minimal distance
1997 // so collision may occur
1998 // consider distace between the bodies
1999 MFloat A[3][3], B[3][3];
2000 // MFloat invA[3][3], invB[3][3];
2001
2002 // Calculate the transformation matrix A of orientation of ellipsoid i2
2003 A[0][0] = 1.0 - 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[2] + (*i2).m_quaternion[3] * (*i2).m_quaternion[3]);
2004 A[0][1] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[2] + (*i2).m_quaternion[0] * (*i2).m_quaternion[3]);
2005 A[0][2] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[3] - (*i2).m_quaternion[0] * (*i2).m_quaternion[2]);
2006 A[1][0] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[2] - (*i2).m_quaternion[0] * (*i2).m_quaternion[3]);
2007 A[1][1] = 1.0 - 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[1] + (*i2).m_quaternion[3] * (*i2).m_quaternion[3]);
2008 A[1][2] = 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[3] + (*i2).m_quaternion[0] * (*i2).m_quaternion[1]);
2009 A[2][0] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[3] + (*i2).m_quaternion[0] * (*i2).m_quaternion[2]);
2010 A[2][1] = 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[3] - (*i2).m_quaternion[0] * (*i2).m_quaternion[1]);
2011 A[2][2] = 1.0 - 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[1] + (*i2).m_quaternion[2] * (*i2).m_quaternion[2]);
2012 // and its inverse (inverse == transpose for rotation matrix!)
2013 // for (MInt i = 0; i < 3; i++)
2014 // for (MInt j = 0; j < 3; j++)
2015 // invA[i][j] = A[j][i];
2016
2017 // Calculate the transformation matrix B of orientation of ellipsoid i3
2018 B[0][0] = 1.0 - 2.0 * ((*i3).m_quaternion[2] * (*i3).m_quaternion[2] + (*i3).m_quaternion[3] * (*i3).m_quaternion[3]);
2019 B[0][1] = 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[2] + (*i3).m_quaternion[0] * (*i3).m_quaternion[3]);
2020 B[0][2] = 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[3] - (*i3).m_quaternion[0] * (*i3).m_quaternion[2]);
2021 B[1][0] = 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[2] - (*i3).m_quaternion[0] * (*i3).m_quaternion[3]);
2022 B[1][1] = 1.0 - 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[1] + (*i3).m_quaternion[3] * (*i3).m_quaternion[3]);
2023 B[1][2] = 2.0 * ((*i3).m_quaternion[2] * (*i3).m_quaternion[3] + (*i3).m_quaternion[0] * (*i3).m_quaternion[1]);
2024 B[2][0] = 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[3] + (*i3).m_quaternion[0] * (*i3).m_quaternion[2]);
2025 B[2][1] = 2.0 * ((*i3).m_quaternion[2] * (*i3).m_quaternion[3] - (*i3).m_quaternion[0] * (*i3).m_quaternion[1]);
2026 B[2][2] = 1.0 - 2.0 * ((*i3).m_quaternion[1] * (*i3).m_quaternion[1] + (*i3).m_quaternion[2] * (*i3).m_quaternion[2]);
2027 // and its inverse (inverse == transpose for rotation matrix!)
2028 // for (MInt i = 0; i < 3; i++)
2029 // for (MInt j = 0; j < 3; j++)
2030 // invB[i][j] = B[j][i];
2031
2032 // // calculate the matrix product invA * X_A * A, is stored in A
2033 // // [X_A is a diagonal matrix with elements: semi_axis_length^2]
2034 // MFloat minorAxis2 = POW2(minLength2);
2035 // MFloat majorAxis2 = POW2(maxLength3);
2036 // for (MInt i = 0; i < 3; i++)
2037 // { // this is the right-hand side of the product: X_A * A
2038 // // stored in A
2039 // A[0][i] *= minorAxis2;
2040 // A[1][i] *= minorAxis2;
2041 // A[2][i] *= majorAxis2;
2042 // }
2043 // // left-hand-side part, again stored in A
2044 // matrixMultiplyLeft(invA, A);
2045 //
2046 // // calculate the matrix product invB * X_B * B, is stored in B
2047 // // [X_B is a diagonal matrix with elements: semi_axis_length^2]
2048 // minorAxis2 = POW2(minLength3);
2049 // majorAxis2 = POW2(maxLength3);
2050 // for (MInt i = 0; i < 3; i++)
2051 // { // this is the right-hand side of the product: X_B * B
2052 // // stored in B
2053 // B[0][i] *= minorAxis2;
2054 // B[1][i] *= minorAxis2;
2055 // B[2][i] *= majorAxis2;
2056 // }
2057 // // left-hand-side part, again stored in B
2058 // matrixMultiplyLeft(invB, B);
2059 //
2060 // // next, apply the method proposed by Zheng et al., Phys. Rev. E 79, 057702 (2009)
2061 // // to determine the minimal distance between the two bodies
2062 // // at the current orientation/separation
2063 //
2064 // // prepare input vectors
2065 // MFloat l1[3], m1[3], n1[3];
2066 // MFloat l2[3], m2[3], n2[3];
2067 // for (MInt i = 0; i < 3; i++)
2068 // {
2069 // l1[i] = A[i][0];
2070 // m1[i] = A[i][1];
2071 // n1[i] = A[i][2];
2072 // l2[i] = B[i][0];
2073 // m2[i] = B[i][1];
2074 // n2[i] = B[i][2];
2075 // }
2076
2077 // next, apply the method proposed by Zheng et al., Phys. Rev. E 79, 057702 (2009)
2078 // to determine the minimal distance between the two bodies
2079 // at the current orientation/separation
2080 MFloat l1[3], m1[3], n1[3];
2081 MFloat l2[3], m2[3], n2[3];
2082 for(MInt i = 0; i < 3; i++) {
2083 l1[i] = A[0][i];
2084 m1[i] = A[1][i];
2085 n1[i] = A[2][i];
2086 l2[i] = B[0][i];
2087 m2[i] = B[1][i];
2088 n2[i] = B[2][i];
2089 }
2090
2091 // determine minimal distance at contact between the particles
2092 // distance = separation vector of midpoints
2093 // l1, m1, n1 = principal orientation vectors of ellipsoid i2
2094 // l2, m2, n2 = principal orientation vectors of ellipsoid i3
2095 // store the minimal distance in largestCollDistSquared
2096 EllipsoidDistance theDistance(dist, l1, m1, n1, l2, m2, n2, (*i2).m_semiMinorAxis, (*i2).m_semiMinorAxis,
2097 (*i2).m_semiMinorAxis * (*i2).m_aspectRatio, (*i3).m_semiMinorAxis,
2098 (*i3).m_semiMinorAxis, (*i3).m_semiMinorAxis * (*i3).m_aspectRatio);
2099 largestCollDistSquared = theDistance.ellipsoids();
2100 largestCollDistSquared = POW2(largestCollDistSquared);
2101
2102 if(totalDistanceSquared < largestCollDistSquared) {
2103 collQueueElemEllipsoid thisColl;
2104 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time;
2105 thisColl.part0 = (*i2).m_partId;
2106 thisColl.part1 = (*i3).m_partId;
2107 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
2108 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
2109 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
2110 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
2111 thisColl.dens0 = (*i2).m_densityRatio;
2112 thisColl.dens1 = (*i3).m_densityRatio;
2113 thisColl.collPosX = i2->m_position[0];
2114 thisColl.collPosY = i2->m_position[1];
2115 thisColl.collPosZ = i2->m_position[2];
2116 collQueueEllipsoid.push(thisColl);
2117 }
2118}

◆ collisionCheckEllipsoidEllipsoid()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckEllipsoidEllipsoid ( lptEllipticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckEllipsoidEllipsoid(ellipsListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Author
Christoph Siewert May-2013

Definition at line 1321 of file lptcollision.cpp.

1322 {
1323 TRACE();
1324
1325 // check offset
1326 // particles before the plane x = m_particleCollOffset are not considered
1327 if((*i2).m_position[0] < m_offset) {
1328 return;
1329 }
1330 if((*i3).m_position[0] < m_offset) {
1331 return;
1332 }
1333
1334 switch(m_collisionModel) {
1335 case 1:
1336 case 3:
1337 case 5: { // retroactive collision detection: search for overlap between particles
1338 // collisionCheckEERetroActive(i2,i3);
1340 } break;
1341
1342 case 2:
1343 case 4:
1344 case 6: { // proactive collision detection: calculate time of collision and
1345 // compare with the particle time step
1346 if(m_ellipsoidCCD) {
1347 collisionCheckEECCD(i2, i3);
1348 } else {
1350 }
1351 } break;
1352
1353 default: {
1354 mTerm(1, AT_, "Unknown particle collision type");
1355 }
1356 }
1357}
void collisionCheckEECCD(lptEllipticleI, lptEllipticleI)
checks continuously for the overlaps of the two ellipsoids i2 and i3 assuming that they do not rotate...
void collisionCheckEEProActive(lptEllipticleI, lptEllipticleI)
Collision check for ellipsoids i2 and i3 checks and stores collision event this method works proactiv...

◆ collisionCheckSECCD()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckSECCD ( lptParticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckSECCD(partListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Aug-2013

Author
Christoph Siewert

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

m_particleTimeStep;

Definition at line 2323 of file lptcollision.cpp.

2323 {
2324 TRACE();
2325
2326 const MInt dim3 = 3;
2327
2328 MFloat deltaXSq = F0;
2329 MFloat deltaVSq = F0;
2330 MFloat deltaVdeltaX = F0;
2331 MFloat dist[dim3];
2332 for(MInt d = 0; d < dim3; ++d) {
2333 dist[d] = i2->m_oldPos[d] - i3->m_oldPos[d];
2334 MFloat deltaV = ((i2->m_position[d] - i2->m_oldPos[d]) - (i3->m_position[d] - i3->m_oldPos[d])) / m_timeStep;
2335 deltaXSq += POW2(dist[d]);
2336 deltaVSq += POW2(deltaV);
2337 deltaVdeltaX += dist[d] * deltaV;
2338 }
2339 if(approx(deltaVSq, F0, MFloatEps)) { // no relative velocity, check for overlap only
2341 return;
2342 }
2343
2344 MFloat i1minR = i2->m_diameter / F2;
2345 MFloat& i1maxR = i1minR;
2346 MFloat i2minR = min(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
2347 MFloat i2maxR = max(i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio);
2348 MFloat RminSq = POW2(i1minR + i2minR);
2349 MFloat RmaxSq = POW2(i1maxR + i2maxR);
2350
2351 // as a first rough criterion, check the distance between the centroids
2352 // if larger than the sum of major axes, then
2353 // for sure there is no collision between the two
2354 MFloat bigKmax = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RmaxSq);
2355 if(bigKmax < F0) {
2356 return; // only complex solutions, no collision on current route
2357 }
2358 bigKmax = sqrt(bigKmax);
2359 MFloat tempt1 = (-deltaVdeltaX - bigKmax) / deltaVSq;
2360 MFloat tempt2 = (-deltaVdeltaX + bigKmax) / deltaVSq;
2361 MFloat t1max = min(tempt1, tempt2);
2362 MFloat t2max = max(tempt1, tempt2);
2363 if(t1max > m_timeStep) {
2364 return; // collision begin in the future
2365 }
2366 if(t2max < F0) {
2367 return; // collision end in the past
2368 }
2369
2370 // if smaller than the sum of the minor axis, then
2371 // a collision between the two is certain
2372 MFloat bigKmin = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RminSq);
2373 if(bigKmin >= F0) {
2374 bigKmin = sqrt(bigKmin);
2375 tempt1 = (-deltaVdeltaX - bigKmin) / deltaVSq;
2376 tempt2 = (-deltaVdeltaX + bigKmin) / deltaVSq;
2377 MFloat t1min = min(tempt1, tempt2);
2378 MFloat t2min = max(tempt1, tempt2);
2379 if((t1min <= m_timeStep) && (t2min >= F0)) {
2380 collQueueElemEllipsoid thisColl;
2381 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + t1min;
2382 thisColl.part0 = (*i3).m_partId;
2383 thisColl.part1 = (*i2).m_partId;
2384 thisColl.semiMinorAxis0 = (*i3).m_semiMinorAxis;
2385 thisColl.semiMinorAxis1 = i1minR;
2386 thisColl.aspectRatio0 = (*i3).m_aspectRatio;
2387 thisColl.aspectRatio1 = -1.0;
2388 thisColl.dens0 = (*i3).m_densityRatio;
2389 thisColl.dens1 = (*i2).m_densityRatio;
2390 thisColl.collPosX = i2->m_oldPos[0] + (i2->m_position[0] - i2->m_oldPos[0]) * t1min / m_timeStep;
2391 thisColl.collPosY = i2->m_oldPos[1] + (i2->m_position[1] - i2->m_oldPos[1]) * t1min / m_timeStep;
2392 thisColl.collPosZ = i2->m_oldPos[2] + (i2->m_position[2] - i2->m_oldPos[2]) * t1min / m_timeStep;
2393 collQueueEllipsoid.push(thisColl);
2394 return;
2395 }
2396 }
2397
2398 // distance is smaller than maximal distance but larger than minimal distance
2399 // so collision may occur
2400
2401
2402 // MFloat e0_1 = 0.5;
2403 // MFloat e1_1 = 0.5;
2404 // MFloat e2_1 = 0.5;
2405 // MFloat e3_1 = 0.5;
2406
2407 MFloat e0_2 = i3->m_quaternion[0];
2408 MFloat e1_2 = i3->m_quaternion[1];
2409 MFloat e2_2 = i3->m_quaternion[2];
2410 MFloat e3_2 = i3->m_quaternion[3];
2411
2412 MFloat MA[16];
2413 MA[0] = 1.0;
2414 MA[4] = 0.0;
2415 MA[8] = 0.0;
2416 MA[12] = i2->m_oldPos[0];
2417 MA[1] = 0.0;
2418 MA[5] = 1.0;
2419 MA[9] = 0.0;
2420 MA[13] = i2->m_oldPos[1];
2421 MA[2] = 0.0;
2422 MA[6] = 0.0;
2423 MA[10] = 1.0;
2424 MA[14] = i2->m_oldPos[2];
2425 MA[3] = F0;
2426 MA[7] = F0;
2427 MA[11] = F0;
2428 MA[15] = F1;
2429
2430 MFloat invMB[16];
2431 invMB[0] = ((e0_2 * e0_2 + e1_2 * e1_2) - e2_2 * e2_2) - e3_2 * e3_2;
2432 invMB[4] = 2.0 * e0_2 * e3_2 + 2.0 * e1_2 * e2_2;
2433 invMB[8] = 2.0 * e1_2 * e3_2 - 2.0 * e0_2 * e2_2;
2434 invMB[12] = -(invMB[0] * i3->m_oldPos[0] + invMB[4] * i3->m_oldPos[1] + invMB[8] * i3->m_oldPos[2]);
2435 invMB[1] = 2.0 * e1_2 * e2_2 - 2.0 * e0_2 * e3_2;
2436 invMB[5] = ((e0_2 * e0_2 - e1_2 * e1_2) + e2_2 * e2_2) - e3_2 * e3_2;
2437 invMB[9] = 2.0 * e0_2 * e1_2 + 2.0 * e2_2 * e3_2;
2438 invMB[13] = -(invMB[1] * i3->m_oldPos[0] + invMB[5] * i3->m_oldPos[1] + invMB[9] * i3->m_oldPos[2]);
2439 invMB[2] = 2.0 * e0_2 * e2_2 + 2.0 * e1_2 * e3_2;
2440 invMB[6] = 2.0 * e2_2 * e3_2 - 2.0 * e0_2 * e1_2;
2441 invMB[10] = ((e0_2 * e0_2 - e1_2 * e1_2) - e2_2 * e2_2) + e3_2 * e3_2;
2442 invMB[14] = -(invMB[2] * i3->m_oldPos[0] + invMB[6] * i3->m_oldPos[1] + invMB[10] * i3->m_oldPos[2]);
2443 invMB[3] = F0;
2444 invMB[7] = F0;
2445 invMB[11] = F0;
2446 invMB[15] = F1;
2447
2448 MFloat v_1[3];
2449 v_1[0] = (i2->m_position[0] - i2->m_oldPos[0]);
2450 v_1[1] = (i2->m_position[1] - i2->m_oldPos[1]);
2451 v_1[2] = (i2->m_position[2] - i2->m_oldPos[2]);
2452
2453 MFloat v_2[3];
2454 v_2[0] = (i3->m_position[0] - i3->m_oldPos[0]);
2455 v_2[1] = (i3->m_position[1] - i3->m_oldPos[1]);
2456 v_2[2] = (i3->m_position[2] - i3->m_oldPos[2]);
2457
2458 MFloat A[16] = {1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, -1.0};
2459 A[0] = 4.0 / (i2->m_diameter * i2->m_diameter);
2460 A[5] = A[0];
2461 A[10] = A[0];
2462
2463 MFloat detMinusB = -1
2464 / (i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_semiMinorAxis
2465 * i3->m_semiMinorAxis * i3->m_semiMinorAxis * i3->m_aspectRatio * i3->m_aspectRatio);
2466
2467 MFloat m[5];
2468 MFloat b_Matrix[16];
2469 createMatrix_CCD(MA, v_1, invMB, v_2, i3->m_semiMinorAxis, i3->m_semiMinorAxis * i3->m_aspectRatio, b_Matrix, m);
2470 MInt iteration = 0;
2471 MFloat t1 = 0.0;
2472 MFloat t2 = 1.0;
2473 /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
2474 /* setup until here */
2475
2476 MBool collision;
2477 MFloat positive1 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t1);
2478 if(positive1 < 0.0) {
2479 collision = true;
2480 } else {
2481 MFloat positive2 = checkStaticOverlap_CCD(b_Matrix, A, m, detMinusB, t2);
2482 if(positive2 < 0.0) {
2483 collision = true;
2484 } else {
2485 collision = checkCSI_CCD(A, b_Matrix, m, detMinusB, t1, t2, positive1, positive2, iteration);
2486 }
2487 }
2488
2489 /* %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% */
2490 /* collision detection until here */
2491 if(collision) {
2492 collQueueElemEllipsoid thisColl;
2493 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + tmin*m_particleTimeStep;
2494 thisColl.part0 = (*i2).m_partId;
2495 thisColl.part1 = (*i3).m_partId;
2496 thisColl.semiMinorAxis1 = (*i3).m_semiMinorAxis;
2497 thisColl.semiMinorAxis0 = i2->m_diameter / 2.0;
2498 thisColl.aspectRatio1 = (*i3).m_aspectRatio;
2499 thisColl.aspectRatio0 = -1.0;
2500 thisColl.dens0 = (*i2).m_densityRatio;
2501 thisColl.dens1 = (*i3).m_densityRatio;
2502 thisColl.collPosX = i2->m_oldPos[0];
2503 thisColl.collPosY = i2->m_oldPos[1];
2504 thisColl.collPosZ = i2->m_oldPos[2];
2505 collQueueEllipsoid.push(thisColl);
2506 }
2507}
void collisionCheckSERetroActive(lptParticleI, lptEllipticleI)
Collision check for sphere i1 and ellipsoid i2 based on overlap criterion, and store collision event ...

◆ collisionCheckSEP()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckSEP ( lptParticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckSEP((partListIteratorConst<nDim> i1, ellipsListIteratorConst<nDim> i2)

Author
Christoph Siewert May-2013

Definition at line 1368 of file lptcollision.cpp.

1368 {
1369 TRACE();
1370
1371 MFloat deltaXSq = F0;
1372 MFloat deltaVSq = F0;
1373 MFloat deltaVdeltaX = F0;
1374 MFloat dist[nDim];
1375 for(MInt d = 0; d < nDim; ++d) {
1376 dist[d] = i1->m_oldPos[d] - i2->m_oldPos[d];
1377 MFloat deltaV = ((i1->m_position[d] - i1->m_oldPos[d]) - (i2->m_position[d] - i2->m_oldPos[d])) / m_timeStep;
1378 deltaXSq += POW2(dist[d]);
1379 deltaVSq += POW2(deltaV);
1380 deltaVdeltaX += dist[d] * deltaV;
1381 }
1382 if(approx(deltaVSq, F0, MFloatEps)) { // no relative velocity, check for overlap only
1384 return;
1385 }
1386
1387 MFloat i1minR = i1->m_diameter / F2;
1388 MFloat& i1maxR = i1minR;
1389 MFloat i2minR = min(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
1390 MFloat i2maxR = max(i2->m_semiMinorAxis, i2->m_semiMinorAxis * i2->m_aspectRatio);
1391 MFloat RminSq = POW2(i1minR + i2minR);
1392 MFloat RmaxSq = POW2(i1maxR + i2maxR);
1393
1394 // as a first rough criterion, check the distance between the centroids
1395 // if larger than the sum of major axes, then
1396 // for sure there is no collision between the two
1397 MFloat bigKmax = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RmaxSq);
1398 if(bigKmax < F0) {
1399 return; // only complex solutions, no collision on current route
1400 }
1401 bigKmax = sqrt(bigKmax);
1402 MFloat tempt1 = (-deltaVdeltaX - bigKmax) / deltaVSq;
1403 MFloat tempt2 = (-deltaVdeltaX + bigKmax) / deltaVSq;
1404 MFloat t1max = min(tempt1, tempt2);
1405 MFloat t2max = max(tempt1, tempt2);
1406 if(t1max > m_timeStep) {
1407 return; // collision begin in the future
1408 }
1409 if(t2max < F0) {
1410 return; // collision end in the past
1411 }
1412
1413 // if smaller than the sum of the minor axis, then
1414 // a collision between the two is certain
1415 MFloat bigKmin = POW2(deltaVdeltaX) - deltaVSq * (deltaXSq - RminSq);
1416 if(bigKmin >= F0) {
1417 bigKmin = sqrt(bigKmin);
1418 tempt1 = (-deltaVdeltaX - bigKmin) / deltaVSq;
1419 tempt2 = (-deltaVdeltaX + bigKmin) / deltaVSq;
1420 MFloat t1min = min(tempt1, tempt2);
1421 MFloat t2min = max(tempt1, tempt2);
1422 if((t1min <= m_timeStep) && (t2min >= F0)) {
1423 collQueueElemEllipsoid thisColl;
1424 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + t1min;
1425 thisColl.part0 = (*i2).m_partId;
1426 thisColl.part1 = (*i1).m_partId;
1427 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1428 thisColl.semiMinorAxis1 = i1minR;
1429 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1430 thisColl.aspectRatio1 = -1.0;
1431 thisColl.dens0 = (*i2).m_densityRatio;
1432 thisColl.dens1 = (*i1).m_densityRatio;
1433 thisColl.collPosX = i1->m_oldPos[0] + (i1->m_position[0] - i1->m_oldPos[0]) * t1min / m_timeStep;
1434 thisColl.collPosY = i1->m_oldPos[1] + (i1->m_position[1] - i1->m_oldPos[1]) * t1min / m_timeStep;
1435 thisColl.collPosZ = i1->m_oldPos[2] + (i1->m_position[2] - i1->m_oldPos[2]) * t1min / m_timeStep;
1436 collQueueEllipsoid.push(thisColl);
1437 return;
1438 }
1439 }
1440
1441 // distance is smaller than maximal distance but larger than minimal distance
1442 // so collision may occur
1443 // consider distance between the bodies with the orientation at the closet distance
1444 // between the two centroids (might not be a good choose with the ellipsoids rotate very fast
1445 // while tranlate very slowly
1446 MFloat distTminSq = F0;
1447 MFloat a[3], b[3], c[3];
1448 MFloat l2[3] = {1.0, 0.0, 0.0}, m2[3] = {0.0, 1.0, 0.0}, n2[3] = {0.0, 0.0, 1.0};
1449 MFloat tmin = (-deltaVdeltaX / deltaVSq) / m_timeStep;
1450 if((tmin < F0) || (tmin > F1)) {
1451 MFloat partQuatA[4];
1452 if(tmin < F0) {
1453 for(MInt i = 0; i < 4; ++i) {
1454 partQuatA[i] = i2->m_oldQuaternion[i];
1455 }
1456 distTminSq = deltaXSq;
1457 } else {
1458 for(MInt i = 0; i < 4; ++i) {
1459 partQuatA[i] = i2->m_quaternion[i];
1460 }
1461 for(MInt i = 0; i < nDim; ++i) {
1462 distTminSq += POW2(i1->m_position[i] - i2->m_position[i]);
1463 }
1464 }
1465 // Calculate the transformation matrix A of orientation of ellipsoid i2
1466 a[0] = 1.0 - 2.0 * (partQuatA[2] * partQuatA[2] + partQuatA[3] * partQuatA[3]);
1467 a[1] = 2.0 * (partQuatA[1] * partQuatA[2] + partQuatA[0] * partQuatA[3]);
1468 a[2] = 2.0 * (partQuatA[1] * partQuatA[3] - partQuatA[0] * partQuatA[2]);
1469 b[0] = 2.0 * (partQuatA[1] * partQuatA[2] - partQuatA[0] * partQuatA[3]);
1470 b[1] = 1.0 - 2.0 * (partQuatA[1] * partQuatA[1] + partQuatA[3] * partQuatA[3]);
1471 b[2] = 2.0 * (partQuatA[2] * partQuatA[3] + partQuatA[0] * partQuatA[1]);
1472 c[0] = 2.0 * (partQuatA[1] * partQuatA[3] + partQuatA[0] * partQuatA[2]);
1473 c[1] = 2.0 * (partQuatA[2] * partQuatA[3] - partQuatA[0] * partQuatA[1]);
1474 c[2] = 1.0 - 2.0 * (partQuatA[1] * partQuatA[1] + partQuatA[2] * partQuatA[2]);
1475 } else {
1476 // slerp(i2->m_oldQuaternion, i2->m_quaternion, tmin, partQuatA, 4);
1477 // slerp between old and new orientation;
1478 const MFloat* e;
1479 e = i2->m_oldQuaternion.data();
1480 a[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1481 a[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1482 a[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1483 e = i2->m_quaternion.data();
1484 b[0] = 2.0 * (e[1] * e[3] + e[0] * e[2]);
1485 b[1] = 2.0 * (e[2] * e[3] - e[0] * e[1]);
1486 b[2] = 1.0 - 2.0 * (e[1] * e[1] + e[2] * e[2]);
1487 slerp(a, b, tmin, c, 3);
1488
1489 // generate orthonormal basis using Gram-Schmidt and cross-product
1490 for(MInt dim = 0; dim < 3; ++dim) {
1491 a[dim] = c[dim];
1492 }
1493 a[0] -= F1;
1494 normalize(a, 3);
1495 MFloat innerProd = F0;
1496 for(MInt dim = 0; dim < 3; ++dim) {
1497 innerProd += c[dim] * a[dim];
1498 }
1499 for(MInt dim = 0; dim < 3; ++dim) {
1500 b[dim] = a[dim] - innerProd * c[dim];
1501 }
1502 normalize(b, 3);
1503 a[0] = b[1] * c[2] - b[2] * c[1];
1504 a[1] = b[2] * c[0] - b[0] * c[2];
1505 a[2] = b[0] * c[1] - b[1] * c[0];
1506 normalize(a, 3);
1507
1508 for(MInt dim = 0; dim < nDim; ++dim) {
1509 distTminSq += POW2((i1->m_position[dim] - i2->m_position[dim]) * tmin
1510 + (i1->m_oldPos[dim] - i2->m_oldPos[dim]) * (1 - tmin));
1511 }
1512 }
1513
1514 // next, apply the method proposed by Zheng et al., Phys. Rev. E 79, 057702 (2009)
1515 // to determine the minimal distance between the two bodies
1516 // at the current orientation/separation
1517
1518 // determine minimal distance at contact between the particles
1519 // distance = separation vector of midpoints
1520 // l1, m1, n1 = principal orientation vectors of ellipsoid i2
1521 // l2, m2, n2 = principal orientation vectors of ellipsoid i3
1522 // store the minimal distance in largestCollDistSquared
1523 EllipsoidDistance theDistance(dist, a, b, c, l2, m2, n2, (*i2).m_semiMinorAxis, (*i2).m_semiMinorAxis,
1524 (*i2).m_semiMinorAxis * (*i2).m_aspectRatio, i1minR, i1minR, i1minR);
1525 MFloat largestCollDistSquared = theDistance.ellipsoids();
1526 largestCollDistSquared = POW2(largestCollDistSquared);
1527
1528 if(distTminSq < largestCollDistSquared) {
1529 collQueueElemEllipsoid thisColl;
1530 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time - m_particleTimeStep + tmin*m_particleTimeStep;
1531 thisColl.part0 = (*i2).m_partId;
1532 thisColl.part1 = (*i1).m_partId;
1533 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1534 thisColl.semiMinorAxis1 = i1minR;
1535 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1536 thisColl.aspectRatio1 = -1.0;
1537 thisColl.dens0 = (*i2).m_densityRatio;
1538 thisColl.dens1 = (*i1).m_densityRatio;
1539 thisColl.collPosX = i1->m_oldPos[0] + (i1->m_position[0] - i1->m_oldPos[0]) * tmin;
1540 thisColl.collPosY = i1->m_oldPos[1] + (i1->m_position[1] - i1->m_oldPos[1]) * tmin;
1541 thisColl.collPosZ = i1->m_oldPos[2] + (i1->m_position[2] - i1->m_oldPos[2]) * tmin;
1542 collQueueEllipsoid.push(thisColl);
1543 }
1544}

◆ collisionCheckSERetroActive()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckSERetroActive ( lptParticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckSERetroActive(partListIteratorConst<nDim> i1, ellipsListIteratorConst<nDim> i2)

Author
Rudie Kunnen, Feb-2011

Definition at line 1554 of file lptcollision.cpp.

1555 {
1556 TRACE();
1557
1558 MFloat dist[nDim];
1559 MFloat totalDistanceSquared = 0.0;
1560
1561 for(MInt i = 0; i < nDim; i++) {
1562 dist[i] = (*i2).m_position[i] - (*i1).m_position[i];
1563 totalDistanceSquared += POW2(dist[i]);
1564 }
1565
1566 MFloat Length1 = 0.5 * (*i1).m_diameter;
1567 MFloat minLength2, maxLength2;
1568 minLength2 = (*i2).m_semiMinorAxis * (*i2).m_aspectRatio;
1569 if(minLength2 < (*i2).m_semiMinorAxis) {
1570 maxLength2 = (*i2).m_semiMinorAxis;
1571 } else {
1572 maxLength2 = minLength2;
1573 minLength2 = (*i2).m_semiMinorAxis;
1574 }
1575
1576 // as a first rough criterion, check the distance between the centroids
1577 // if larger than radius_sphere + semi_major_axis_ellipsoid, then
1578 // for sure there is no collision between the two
1579 MFloat largestCollDistSquared = POW2(Length1 + maxLength2);
1580 if(totalDistanceSquared > largestCollDistSquared) {
1581 return;
1582 }
1583 MFloat smallestCollDistSquared = POW2(Length1 + minLength2);
1584 if(totalDistanceSquared < smallestCollDistSquared) {
1585 collQueueElemEllipsoid thisColl;
1586 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time;
1587 thisColl.part0 = (*i2).m_partId;
1588 thisColl.part1 = (*i1).m_partId;
1589 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1590 thisColl.semiMinorAxis1 = Length1;
1591 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1592 thisColl.aspectRatio1 = -1.0;
1593 thisColl.dens0 = (*i2).m_densityRatio;
1594 thisColl.dens1 = (*i1).m_densityRatio;
1595 thisColl.collPosX = i1->m_position[0];
1596 thisColl.collPosY = i1->m_position[1];
1597 thisColl.collPosZ = i1->m_position[2];
1598 collQueueEllipsoid.push(thisColl);
1599 return;
1600 }
1601
1602 // distance is smaller than maximal distance but larger than minimal distance
1603 // so collision may occur
1604 // consider distace between the bodies
1605
1606 MFloat A[3][3];
1607 // MFloat invA[3][3];
1608
1609 // Calculate the transformation matrix A of the ellipsoid orientation
1610 A[0][0] = 1.0 - 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[2] + (*i2).m_quaternion[3] * (*i2).m_quaternion[3]);
1611 A[0][1] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[2] + (*i2).m_quaternion[0] * (*i2).m_quaternion[3]);
1612 A[0][2] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[3] - (*i2).m_quaternion[0] * (*i2).m_quaternion[2]);
1613 A[1][0] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[2] - (*i2).m_quaternion[0] * (*i2).m_quaternion[3]);
1614 A[1][1] = 1.0 - 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[1] + (*i2).m_quaternion[3] * (*i2).m_quaternion[3]);
1615 A[1][2] = 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[3] + (*i2).m_quaternion[0] * (*i2).m_quaternion[1]);
1616 A[2][0] = 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[3] + (*i2).m_quaternion[0] * (*i2).m_quaternion[2]);
1617 A[2][1] = 2.0 * ((*i2).m_quaternion[2] * (*i2).m_quaternion[3] - (*i2).m_quaternion[0] * (*i2).m_quaternion[1]);
1618 A[2][2] = 1.0 - 2.0 * ((*i2).m_quaternion[1] * (*i2).m_quaternion[1] + (*i2).m_quaternion[2] * (*i2).m_quaternion[2]);
1619 // and its inverse (inverse == transpose for rotation matrix!)
1620 // for (MInt i = 0; i < 3; i++)
1621 // for (MInt j = 0; j < 3; j++)
1622 // invA[i][j] = A[j][i];
1623 //
1624 // // calculate the matrix product invA * X_A * A, is stored in A
1625 // // [X_A is a diagonal matrix with elements: semi_axis_length^2]
1626 // MFloat minorAxis2 = POW2(minLength2);
1627 // MFloat majorAxis2 = POW2(maxLength2);
1628 // for (MInt i = 0; i < 3; i++)
1629 // { // this is the right-hand side of the product: X_A * A
1630 // // stored in A
1631 // A[0][i] *= minorAxis2;
1632 // A[1][i] *= minorAxis2;
1633 // A[2][i] *= majorAxis2;
1634 // }
1635 // // left-hand-side part, again stored in A
1636 // matrixMultiplyLeft(invA, A);
1637 //
1638 // // prepare input vectors
1639 // MFloat l1[3], m1[3], n1[3];
1640 // MFloat l2[3] = {1.0, 0.0, 0.0}, m2[3] = {0.0, 1.0, 0.0}, n2[3] = {0.0, 0.0, 1.0};
1641 // for (MInt i = 0; i < 3; i++)
1642 // {
1643 // l1[i] = A[i][0];
1644 // m1[i] = A[i][1];
1645 // n1[i] = A[i][2];
1646 // }
1647
1648 // next, apply the method proposed by Zheng et al., Phys. Rev. E 79, 057702 (2009)
1649 // to determine the minimal distance between the two bodies
1650 // at the current orientation/separation
1651
1652 // prepare input vectors
1653 MFloat l1[3], m1[3], n1[3];
1654 MFloat l2[3] = {1.0, 0.0, 0.0}, m2[3] = {0.0, 1.0, 0.0}, n2[3] = {0.0, 0.0, 1.0};
1655 for(MInt i = 0; i < 3; i++) {
1656 l1[i] = A[0][i];
1657 m1[i] = A[1][i];
1658 n1[i] = A[2][i];
1659 }
1660
1661 // determine minimal distance at contact between the particles
1662 // distance = separation vector of midpoints
1663 // l1, m1, n1 = principal orientation vectors of ellipsoid
1664 // l2, m2, n2 = orientation vectors of sphere (consider sphere as an ellipsoid with AR = 1)
1665 // store the minimal distance in largestCollDistSquared
1666 EllipsoidDistance theDistance(dist, l1, m1, n1, l2, m2, n2, (*i2).m_semiMinorAxis, (*i2).m_semiMinorAxis,
1667 (*i2).m_semiMinorAxis * (*i2).m_aspectRatio, Length1, Length1, Length1);
1668 largestCollDistSquared = theDistance.ellipsoids();
1669 largestCollDistSquared = POW2(largestCollDistSquared);
1670
1671 if(totalDistanceSquared < largestCollDistSquared) {
1672 collQueueElemEllipsoid thisColl;
1673 thisColl.collTimeStep = globalTimeStep; // solverPtr->m_time;
1674 thisColl.part0 = (*i2).m_partId;
1675 thisColl.part1 = (*i1).m_partId;
1676 thisColl.semiMinorAxis0 = (*i2).m_semiMinorAxis;
1677 thisColl.semiMinorAxis1 = Length1;
1678 thisColl.aspectRatio0 = (*i2).m_aspectRatio;
1679 thisColl.aspectRatio1 = -1.0;
1680 thisColl.dens0 = (*i2).m_densityRatio;
1681 thisColl.dens1 = (*i1).m_densityRatio;
1682 thisColl.collPosX = i1->m_position[0];
1683 thisColl.collPosY = i1->m_position[1];
1684 thisColl.collPosZ = i1->m_position[2];
1685 collQueueEllipsoid.push(thisColl);
1686 }
1687}

◆ collisionCheckSphereEllipsoid()

template<MInt nDim>
void ParticleCollision< nDim >::collisionCheckSphereEllipsoid ( lptParticleI  ,
lptEllipticleI   
)
private

void LPT::collisionCheckSphereEllipsoid(ellipsListIteratorConst<nDim> i2, ellipsListIteratorConst<nDim> i3)

Author
Christoph Siewert May-2013

Definition at line 1276 of file lptcollision.cpp.

1277 {
1278 TRACE();
1279
1280 // check offset
1281 // particles before the plane x = m_particleCollOffset are not considered
1282 if((*i1).m_position[0] < m_offset) {
1283 return;
1284 }
1285 if((*i2).m_position[0] < m_offset) {
1286 return;
1287 }
1288
1289 switch(m_collisionModel) {
1290 case 1:
1291 case 3:
1292 case 5: { // retroactive collision detection: search for overlap between particles
1293 // collisionCheckSERetroActive(i1,i2);
1294 collisionCheckSEP(i1, i2);
1295 } break;
1296
1297 case 2:
1298 case 4:
1299 case 6: { // proactive collision detection: calculate time of collision and
1300 // compare with the particle time step
1301 if(m_ellipsoidCCD) {
1302 collisionCheckSECCD(i1, i2);
1303 } else {
1304 collisionCheckSEP(i1, i2);
1305 }
1306 } break;
1307
1308 default: {
1309 mTerm(1, AT_, "Unknown particle collision type");
1310 }
1311 }
1312}
void collisionCheckSECCD(lptParticleI, lptEllipticleI)
checks continuously for the overlaps of the sphere i2 and the ellipsoid i3 assuming that they do not ...
void collisionCheckSEP(lptParticleI, lptEllipticleI)
Collision check for sphere i1 and ellipsoid i2, specialized version of ellips ellips checks and store...

◆ createMatrix_CCD()

template<MInt nDim>
void ParticleCollision< nDim >::createMatrix_CCD ( const MFloat(&)  MA[16],
const MFloat(&)  u1[3],
const MFloat(&)  invMB[16],
const MFloat(&)  u2[3],
const MFloat a_2,
const MFloat c_2,
MFloat(&)  n[16],
MFloat(&)  m[5] 
)
private

void LPT::createMatrix_CCD(const MFloat (&MA)[16], const MFloat (&u1)[3], const MFloat (&invMB)[16], const MFloat (&u2)[3], const MFloat& a_2, const MFloat& c_2, MFloat (&n)[16], MFloat (&m)[5])

      M_A is the matrix of Ellipsoid2
      u1 are the time-dependent values of M_A
      invM_B is the matrix of Ellipsoid3
      u2 are the time-dependent values of M_B
      a_2 is the semiAxis of Ellipsoid3
      c_2 is the semiAxis*aspectRatio of Ellipsoid3

Aug-2013

Author
Christoph Siewert

Definition at line 2592 of file lptcollision.cpp.

2594 {
2595 TRACE();
2596
2597 MFloat b_j1;
2598 MFloat k1, l1;
2599 MFloat d1, d2, d3;
2600 MFloat bla1, bla2, bla3;
2601 MFloat y;
2602 MFloat b_y, c_y, d_y, e_y, f_y;
2603 b_j1 = (-invMB[0] * u2[0] - invMB[4] * u2[1]) - invMB[8] * u2[2];
2604 k1 = (-invMB[1] * u2[0] - invMB[5] * u2[1]) - invMB[9] * u2[2];
2605 l1 = (-invMB[2] * u2[0] - invMB[6] * u2[1]) - invMB[10] * u2[2];
2606 d1 = (MA[0] * invMB[2] + MA[1] * invMB[6]) + MA[2] * invMB[10];
2607 d2 = (MA[0] * invMB[1] + MA[1] * invMB[5]) + MA[2] * invMB[9];
2608 d3 = (MA[0] * invMB[0] + MA[1] * invMB[4]) + MA[2] * invMB[8];
2609 bla1 = (invMB[8] * d3 / (a_2 * a_2) + invMB[9] * d2 / (a_2 * a_2)) + invMB[10] * d1 / (c_2 * c_2);
2610 bla2 = (invMB[4] * d3 / (a_2 * a_2) + invMB[5] * d2 / (a_2 * a_2)) + invMB[6] * d1 / (c_2 * c_2);
2611 bla3 = (invMB[0] * d3 / (a_2 * a_2) + invMB[1] * d2 / (a_2 * a_2)) + invMB[2] * d1 / (c_2 * c_2);
2612 n[0] = (MA[2] * bla1 + MA[1] * bla2) + MA[0] * bla3;
2613 n[4] = (MA[6] * bla1 + MA[5] * bla2) + MA[4] * bla3;
2614 n[8] = (MA[10] * bla1 + MA[9] * bla2) + MA[8] * bla3;
2615
2616 d1 = (MA[4] * invMB[2] + MA[5] * invMB[6]) + MA[6] * invMB[10];
2617 d2 = (MA[4] * invMB[1] + MA[5] * invMB[5]) + MA[6] * invMB[9];
2618 d3 = (MA[4] * invMB[0] + MA[5] * invMB[4]) + MA[6] * invMB[8];
2619 bla1 = (invMB[8] * d3 / (a_2 * a_2) + invMB[9] * d2 / (a_2 * a_2)) + invMB[10] * d1 / (c_2 * c_2);
2620 bla2 = (invMB[4] * d3 / (a_2 * a_2) + invMB[5] * d2 / (a_2 * a_2)) + invMB[6] * d1 / (c_2 * c_2);
2621 bla3 = (invMB[0] * d3 / (a_2 * a_2) + invMB[1] * d2 / (a_2 * a_2)) + invMB[2] * d1 / (c_2 * c_2);
2622 n[1] = (MA[2] * bla1 + MA[1] * bla2) + MA[0] * bla3;
2623 n[5] = (MA[6] * bla1 + MA[5] * bla2) + MA[4] * bla3;
2624 n[9] = (MA[10] * bla1 + MA[9] * bla2) + MA[8] * bla3;
2625
2626 d1 = (MA[8] * invMB[2] + MA[9] * invMB[6]) + MA[10] * invMB[10];
2627 d2 = (MA[8] * invMB[1] + MA[9] * invMB[5]) + MA[10] * invMB[9];
2628 d3 = (MA[8] * invMB[0] + MA[9] * invMB[4]) + MA[10] * invMB[8];
2629 bla1 = (invMB[8] * d3 / (a_2 * a_2) + invMB[9] * d2 / (a_2 * a_2)) + invMB[10] * d1 / (c_2 * c_2);
2630 bla2 = (invMB[4] * d3 / (a_2 * a_2) + invMB[5] * d2 / (a_2 * a_2)) + invMB[6] * d1 / (c_2 * c_2);
2631 bla3 = (invMB[0] * d3 / (a_2 * a_2) + invMB[1] * d2 / (a_2 * a_2)) + invMB[2] * d1 / (c_2 * c_2);
2632 n[2] = (MA[2] * bla1 + MA[1] * bla2) + MA[0] * bla3;
2633 n[6] = (MA[6] * bla1 + MA[5] * bla2) + MA[4] * bla3;
2634 n[10] = (MA[10] * bla1 + MA[9] * bla2) + MA[8] * bla3;
2635
2636 d1 = ((invMB[14] + invMB[2] * MA[12]) + invMB[6] * MA[13]) + invMB[10] * MA[14];
2637 d2 = ((invMB[13] + invMB[1] * MA[12]) + invMB[5] * MA[13]) + invMB[9] * MA[14];
2638 d3 = ((invMB[12] + invMB[0] * MA[12]) + invMB[4] * MA[13]) + invMB[8] * MA[14];
2639 bla1 = (invMB[8] * d3 / (a_2 * a_2) + invMB[9] * d2 / (a_2 * a_2)) + invMB[10] * d1 / (c_2 * c_2);
2640 bla2 = (invMB[4] * d3 / (a_2 * a_2) + invMB[5] * d2 / (a_2 * a_2)) + invMB[6] * d1 / (c_2 * c_2);
2641 bla3 = (invMB[0] * d3 / (a_2 * a_2) + invMB[1] * d2 / (a_2 * a_2)) + invMB[2] * d1 / (c_2 * c_2);
2642 n[3] = (MA[2] * bla1 + MA[1] * bla2) + MA[0] * bla3;
2643 n[7] = (MA[6] * bla1 + MA[5] * bla2) + MA[4] * bla3;
2644 n[11] = (MA[10] * bla1 + MA[9] * bla2) + MA[8] * bla3;
2645 n[15] = (((((-1.0 + MA[12] * bla3) + MA[13] * bla2) + MA[14] * bla1) + invMB[12] * d3 / (a_2 * a_2))
2646 + invMB[13] * d2 / (a_2 * a_2))
2647 + invMB[14] * d1 / (c_2 * c_2);
2648 y = u1[0] * bla3;
2649 b_y = u1[1] * bla2;
2650 c_y = u1[2] * bla1;
2651 d_y = b_j1 * d3 / (a_2 * a_2);
2652 e_y = k1 * d2 / (a_2 * a_2);
2653 f_y = l1 * d1 / (c_2 * c_2);
2654 n[12] = n[3];
2655 n[13] = n[7];
2656 n[14] = n[11];
2657 d1 = ((l1 + invMB[2] * u1[0]) + invMB[6] * u1[1]) + invMB[10] * u1[2];
2658 d2 = ((k1 + invMB[1] * u1[0]) + invMB[5] * u1[1]) + invMB[9] * u1[2];
2659 d3 = ((b_j1 + invMB[0] * u1[0]) + invMB[4] * u1[1]) + invMB[8] * u1[2];
2660 bla1 = (invMB[8] * d3 / (a_2 * a_2) + invMB[9] * d2 / (a_2 * a_2)) + invMB[10] * d1 / (c_2 * c_2);
2661 bla2 = (invMB[4] * d3 / (a_2 * a_2) + invMB[5] * d2 / (a_2 * a_2)) + invMB[6] * d1 / (c_2 * c_2);
2662 bla3 = (invMB[0] * d3 / (a_2 * a_2) + invMB[1] * d2 / (a_2 * a_2)) + invMB[2] * d1 / (c_2 * c_2);
2663 m[0] = (MA[2] * bla1 + MA[1] * bla2) + MA[0] * bla3;
2664 m[1] = (MA[6] * bla1 + MA[5] * bla2) + MA[4] * bla3;
2665 m[2] = (MA[10] * bla1 + MA[9] * bla2) + MA[8] * bla3;
2666 m[3] = ((((((((((y + b_y) + c_y) + d_y) + e_y) + f_y) + MA[12] * bla3) + MA[13] * bla2) + MA[14] * bla1)
2667 + invMB[12] * d3 / (a_2 * a_2))
2668 + invMB[13] * d2 / (a_2 * a_2))
2669 + invMB[14] * d1 / (c_2 * c_2);
2670 m[4] = ((((u1[0] * bla3 + u1[1] * bla2) + u1[2] * bla1) + b_j1 * d3 / (a_2 * a_2)) + k1 * d2 / (a_2 * a_2))
2671 + l1 * d1 / (c_2 * c_2);
2672}
define array structures

◆ detectPartColl()

template<MInt nDim>
void ParticleCollision< nDim >::detectPartColl ( std::vector< LPTSpherical< nDim > > &  partList,
std::vector< LPTEllipsoidal< nDim > > &  partListEllipsoid,
const MFloat  timeStep,
const MFloat  time 
)

void LPT::detectPartColl()

Particle collision detection & execution

version: March-09

Author
Rudie Kunnen, Sven Berger

Definition at line 164 of file lptcollision.cpp.

167 {
168 TRACE();
169
170 collStruct<nDim> thisColl;
171
172 m_timeStep = timeStep;
173
174 MFloat currCollTime = 0.0, outtime;
175 MInt subIndex[3] = {numeric_limits<MInt>::max(), numeric_limits<MInt>::max(), numeric_limits<MInt>::max()};
176
177 MInt index = 1, index2 = 0;
178 MInt factor[MAX_SPACE_DIMENSIONS] = {numeric_limits<MInt>::max(), numeric_limits<MInt>::max(),
179 numeric_limits<MInt>::max()};
180 MFloat thisCollTime;
181
182 // factor[i] is used in the positioning in the storage array:
183 // index = factor[0] * (x_steps) + factor[1] * (y_steps)
184 // + factor[2] * (z_steps)
185 factor[0] = 1;
186 factor[1] = m_noOfSubDomains[0];
187 IF_CONSTEXPR(nDim == 3) { factor[2] = m_noOfSubDomains[0] * m_noOfSubDomains[1]; }
188
189 // *** construct the lists of particles in the subdomains ***
191 for(i1 = partList.begin(); i1 != partList.end(); i1++) {
192 // skip particles that have moved out of the current solver
193 if(!(*i1).toBeDeleted()) {
194 index = 0;
195 index2 = 0;
196 MBool error = false;
197 for(MInt i = 0; i < nDim; i++) {
198 index2 = MInt(floor(((*i1).m_position[i] - m_subDomainCoordOffset[i]) / m_subDomainSize[i]));
199 if((index2 < 0) || (index2 >= m_noOfSubDomains[i])) // IMPORTANT added = to > !!!
200 {
201 error = true;
202 break;
203 } else {
204 index += factor[i] * index2;
205 }
206 }
207
208 if(error) {
209 if(!(*i1).isInvalid()) {
210 stringstream errorMessage;
211 errorMessage << " ERROR: timestep " << globalTimeStep << " proc " << domainId() << " - particle "
212 << (*i1).m_partId << " is lost!" // << endl;
213 << " coord " << (*i1).m_position[0] << " " << (*i1).m_position[1] << " " << (*i1).m_position[2]
214 << " oldcoord " << (*i1).m_oldPos[0] << " " << (*i1).m_oldPos[1] << " " << (*i1).m_oldPos[2]
215 << " cellId " << (*i1).m_cellId << " coords " << m_lpt->c_coordinate((*i1).m_cellId, 0) << " "
216 << m_lpt->c_coordinate((*i1).m_cellId, 1) << " " << m_lpt->c_coordinate((*i1).m_cellId, 2)
217 << " halfLength " << m_lpt->c_cellLengthAtLevel(m_lpt->c_level((*i1).m_cellId) + 1) << endl;
218 m_log << errorMessage.str();
219 }
220 if(!(*i1).wasSend() && !(*i1).toBeDeleted()) {
221 (*i1).toBeDeleted() = true; // delete the lost particle
222 m_log << "particle was lost " << endl;
223 }
224 } else {
225 subDomainContent[index].subDomain.push_back(i1);
226 }
227 }
228 }
229
231 // *** construct the lists of particles in the subdomains ***
232 ellipsListIterator<nDim> i2 = partListEllipsoid.begin();
233 while(i2 != partListEllipsoid.end()) {
234 // skip particles that have moved out of the current solver
235 if(!(*i2).toBeDeleted()) {
236 index = 0;
237 MBool error = false;
238 for(MInt i = 0; i < nDim; i++) {
239 index2 = MInt(floor(((*i2).m_position[i] - m_subDomainCoordOffset[i]) / m_subDomainSize[i]));
240 if((index2 < 0) || (index2 >= m_noOfSubDomains[i])) {
241 error = true;
242 break;
243 } else {
244 index += factor[i] * index2;
245 }
246 }
247
248 if(error) {
249 if(!(*i2).isInvalid()) {
250 stringstream errorMessage;
251 errorMessage << " ERROR: timestep " << globalTimeStep << " proc " << domainId() << " - particle "
252 << (*i2).m_partId << " is lost!" // << endl;
253 << " coord " << (*i2).m_position[0] << " " << (*i2).m_position[1] << " " << (*i2).m_position[2]
254 << " cellId " << (*i1).m_cellId << " coords " << m_lpt->c_coordinate((*i2).m_cellId, 0) << " "
255 << m_lpt->c_coordinate((*i2).m_cellId, 1) << " " << m_lpt->c_coordinate((*i2).m_cellId, 2)
256 << " halfLength " << m_lpt->c_cellLengthAtLevel(m_lpt->c_level((*i2).m_cellId) + 1) << endl;
257 m_log << errorMessage.str();
258 }
259 if(!(*i2).toBeDeleted() && !(*i2).wasSend()) {
260 (*i2).toBeDeleted() = true; // delete the lost particle
261 (*i2).toBeRespawn() = true;
262 (*i2).isInvalid() = true;
263 m_log << "particle was lost " << endl;
264 }
265 } else {
266 subDomainContentEllipsoid[index].subDomain.push_back(i2);
267 }
268 }
269 i2++;
270 }
271 }
272
273
274 // Construct the list of collisions for the current time step.
275 // Take each subdomain and its direct "forward" neighbors,
276 // then check for collisions between particle pairs in these restricted
277 // regions.
278 // array indices:
279 // i - loops over all subdomains
280 // j - loops over particles in subdomains to be considered as particle 1
281 // in collision detection
282 // k - loops over neighboring subdomains: (k % 2) steps in x-dir,
283 // (k / 2) % 2 steps in y-dir, (k % 4) steps in z-dir
284 // l - loops over particles in subdomains to be considered as particle 2
285 // in collision detection
286 for(MInt i = 0; i < m_totalSubDomains; i++) {
287 subIndex[0] = i % m_noOfSubDomains[0];
288 subIndex[1] = (i / m_noOfSubDomains[0]) % m_noOfSubDomains[1];
289 subIndex[2] = i / (m_noOfSubDomains[0] * m_noOfSubDomains[1]);
290 auto& currDomain = subDomainContent[i];
291
292 for(MInt j = 0; j < (MInt)currDomain.subDomain.size(); j++) {
293 // search for collisions in the current subdomain i:
294 // (only considering particle pairs that have not been considered yet)
295 for(MInt l = j + 1; l < (MInt)currDomain.subDomain.size(); l++) {
296 thisCollTime =
297 collisionCheck(currDomain.subDomain.at((MUlong)j), currDomain.subDomain.at((MUlong)l), currCollTime);
298 if(thisCollTime >= 0.0) // when no collision within the current
299 { // time step a negative time is returned
300 // add new collision event to the list
301 thisColl.particle0 = currDomain.subDomain.at((MUlong)j);
302 thisColl.particle1 = currDomain.subDomain.at((MUlong)l);
303 thisColl.collTime = thisCollTime;
304 thisColl.bndryId = -1;
305 collList.push_back(thisColl);
306 }
307 }
308
309 // search for collisions in neighboring subdomains
310 // only the "forward" neighboring subdomains and the three "backward
311 // diagonal" neighbors are included, the others have already been
312 // investigated
313 for(MInt k = 1; k < IPOW2(nDim); k++) { // these are the "forward" neighbors (7 total for 3D, 3 for 2D)
314
315 // edge detection: no particle subdomains outside of domain
316 if(((subIndex[0] + (k % 2)) < m_noOfSubDomains[0]) && ((subIndex[1] + ((k / 2) % 2)) < m_noOfSubDomains[1])) {
317 IF_CONSTEXPR(nDim == 3) {
318 if(!((subIndex[2] + (k / 4)) < m_noOfSubDomains[2])) {
319 continue;
320 }
321 }
322 index =
323 i + (k % 2) + ((k / 2) % 2) * m_noOfSubDomains[0] + (k / 4) * m_noOfSubDomains[0] * m_noOfSubDomains[1];
324 for(MInt l = 0; l < (MInt)subDomainContent[index].subDomain.size(); l++) {
325 thisCollTime = collisionCheck(subDomainContent[i].subDomain.at((MUlong)j),
326 subDomainContent[index].subDomain.at((MUlong)l),
327 currCollTime);
328 if(thisCollTime >= 0.0) // when no collision within the
329 { // current time step a negative time is returned
330 // add new collision event to the list
331 thisColl.particle0 = subDomainContent[i].subDomain.at((MUlong)j);
332 thisColl.particle1 = subDomainContent[index].subDomain.at((MUlong)l);
333 thisColl.collTime = thisCollTime;
334 thisColl.bndryId = -1; // RUDIE new since particle vector -> list
335 collList.push_back(thisColl);
336 }
337 }
338 }
339 }
340 // now the "backward diagonal" neighbors (3 for 3D, 1 for 2D)
341 if((subIndex[0] > 0) && (subIndex[1] < (m_noOfSubDomains[1] - 1))) {
342 index = i + m_noOfSubDomains[0] - 1;
343 for(MInt l = 0; l < (MInt)subDomainContent[index].subDomain.size(); l++) {
344 thisCollTime = collisionCheck(subDomainContent[i].subDomain.at((MUlong)j),
345 subDomainContent[index].subDomain.at((MUlong)l),
346 currCollTime);
347 if(thisCollTime >= 0.0) // when no collision within the current
348 { // time step a negative time is returned
349 // add new collision event to the list
350 thisColl.particle0 = subDomainContent[i].subDomain.at((MUlong)j);
351 thisColl.particle1 = subDomainContent[index].subDomain.at((MUlong)l);
352 thisColl.collTime = thisCollTime;
353 thisColl.bndryId = -1;
354 collList.push_back(thisColl);
355 }
356 }
357 }
358 IF_CONSTEXPR(nDim == 3) {
359 if((subIndex[0] > 0) && (subIndex[2] < (m_noOfSubDomains[2] - 1))) {
360 index = i + m_noOfSubDomains[0] * m_noOfSubDomains[1] - 1;
361 for(MInt l = 0; l < (MInt)subDomainContent[index].subDomain.size(); l++) {
362 thisCollTime = collisionCheck(subDomainContent[i].subDomain.at((MUlong)j),
363 subDomainContent[index].subDomain.at((MUlong)l),
364 currCollTime);
365 if(thisCollTime >= 0.0) // when no collision within the current
366 { // time step a negative time is returned
367 // add new collision event to the list
368 thisColl.particle0 = subDomainContent[i].subDomain.at((MUlong)j);
369 thisColl.particle1 = subDomainContent[index].subDomain.at((MUlong)l);
370 thisColl.collTime = thisCollTime;
371 thisColl.bndryId = -1;
372 collList.push_back(thisColl);
373 }
374 }
375 }
376 }
377 IF_CONSTEXPR(nDim == 3) {
378 if((subIndex[0] > 0) && (subIndex[1] < (m_noOfSubDomains[1] - 1))
379 && (subIndex[2] < (m_noOfSubDomains[2] - 1))) {
380 index = i + m_noOfSubDomains[0] * (1 + m_noOfSubDomains[1]) - 1;
381 for(MInt l = 0; l < (MInt)subDomainContent[index].subDomain.size(); l++) {
382 thisCollTime = collisionCheck(subDomainContent[i].subDomain.at((MUlong)j),
383 subDomainContent[index].subDomain.at((MUlong)l),
384 currCollTime);
385 if(thisCollTime >= 0.0) // when no collision within the current
386 { // time step a negative time is returned
387 // add new collision event to the list
388 thisColl.particle0 = subDomainContent[i].subDomain.at((MUlong)j);
389 thisColl.particle1 = subDomainContent[index].subDomain.at((MUlong)l);
390 thisColl.collTime = thisCollTime;
391 thisColl.bndryId = -1; // RUDIE new since particle vector -> list
392 collList.push_back(thisColl);
393 }
394 }
395 }
396 }
397
398 if(m_includeEllipsoids) { // search for collisions of spheres with ellipsoids...
399 // note that these collisions will only be detected & recorded;
400 // no attempt at elastic collisions etc. is made!
401 // NOTE: This is placed here since it is untested!
402 for(MInt k = subIndex[0] - 1; k < subIndex[0] + 2; k++) {
403 if((k < 0) || (k >= m_noOfSubDomains[0])) {
404 continue;
405 }
406 for(MInt l = subIndex[1] - 1; l < subIndex[1] + 2; l++) {
407 if((l < 0) || (l >= m_noOfSubDomains[1])) {
408 continue;
409 }
410 for(MInt m = subIndex[2] - 1; m < subIndex[2] + 2; m++) {
411 if((m < 0) || (m >= m_noOfSubDomains[2])) {
412 continue;
413 }
414 index = k + m_noOfSubDomains[0] * l + m * m_noOfSubDomains[0] * m_noOfSubDomains[1];
415 for(MInt n = 0; n < (MInt)subDomainContentEllipsoid[index].subDomain.size(); n++) {
417 subDomainContentEllipsoid[index].subDomain.at((MUlong)n));
418 }
419 }
420 }
421 }
422 }
423 }
424 }
425
427 index = 0;
428 index2 = 0;
429 // Detect overlap of ellipsoids.
430 // Take each subdomain and its direct "forward" neighbors,
431 // then check for collisions between particle pairs in these restricted
432 // regions.
433 // array indices:
434 // i - loops over all subdomains
435 // j - loops over particles in subdomains to be considered as particle 1
436 // in collision detection
437 // k - loops over neighboring subdomains: (k % 2) steps in x-dir,
438 // (k / 2) % 2 steps in y-dir, (k % 4) steps in z-dir
439 // l - loops over particles in subdomains to be considered as particle 2
440 // in collision detection
441 for(MInt i = 0; i < m_totalSubDomains; i++) {
442 subIndex[0] = i % m_noOfSubDomains[0];
443 subIndex[1] = (i / m_noOfSubDomains[0]) % m_noOfSubDomains[1];
444 subIndex[2] = i / (m_noOfSubDomains[0] * m_noOfSubDomains[1]);
445
446 for(MInt j = 0; j < (MInt)subDomainContentEllipsoid[i].subDomain.size(); j++) {
447 // search for collisions in the current subdomain i:
448 // (only considering particle pairs that have not been considered yet)
449 for(MInt l = j + 1; l < (MInt)subDomainContentEllipsoid[i].subDomain.size(); l++) {
451 subDomainContentEllipsoid[i].subDomain.at((MUlong)l));
452 }
453
454
455 // search for collisions in neighboring subdomains
456 // only the "forward" neighboring subdomains and the three "backward
457 // diagonal" neighbors are included, the others have already been
458 // investigated
459 for(MInt k = 1; k < 8; k++) { // these are the "forward" neighbors (7 total for 3D)
460
461 // edge detection: no particle subdomains outside of domain
462 if(((subIndex[0] + (k % 2)) < m_noOfSubDomains[0]) && ((subIndex[1] + ((k / 2) % 2)) < m_noOfSubDomains[1])) {
463 IF_CONSTEXPR(nDim == 3) {
464 if(!((subIndex[2] + (k / 4)) < m_noOfSubDomains[2])) {
465 continue;
466 }
467 }
468 index =
469 i + (k % 2) + ((k / 2) % 2) * m_noOfSubDomains[0] + (k / 4) * m_noOfSubDomains[0] * m_noOfSubDomains[1];
470 for(MInt l = 0; l < (MInt)subDomainContentEllipsoid[index].subDomain.size(); l++) {
472 subDomainContentEllipsoid[index].subDomain.at((MUlong)l));
473 }
474 }
475 }
476 // now the "backward diagonal" neighbors (3 for 3D)
477 if((subIndex[0] > 0) && (subIndex[1] < (m_noOfSubDomains[1] - 1))) {
478 index = i + m_noOfSubDomains[0] - 1;
479 for(MInt l = 0; l < (MInt)subDomainContentEllipsoid[index].subDomain.size(); l++) {
481 subDomainContentEllipsoid[index].subDomain.at((MUlong)l));
482 }
483 }
484 if((subIndex[0] > 0) && (subIndex[2] < (m_noOfSubDomains[2] - 1))) {
485 index = i + m_noOfSubDomains[0] * m_noOfSubDomains[1] - 1;
486 for(MInt l = 0; l < (MInt)subDomainContentEllipsoid[index].subDomain.size(); l++) {
488 subDomainContentEllipsoid[index].subDomain.at((MUlong)l));
489 }
490 }
491 if((subIndex[0] > 0) && (subIndex[1] < (m_noOfSubDomains[1] - 1))
492 && (subIndex[2] < (m_noOfSubDomains[2] - 1))) {
493 index = i + m_noOfSubDomains[0] * (1 + m_noOfSubDomains[1]) - 1;
494 for(MInt l = 0; l < (MInt)subDomainContentEllipsoid[index].subDomain.size(); l++) {
496 subDomainContentEllipsoid[index].subDomain.at((MUlong)l));
497 }
498 }
499 }
500 }
501 }
502
503 MInt bndryId;
504
505 // loop until all collisions are accounted for
506 while(!collList.empty()) {
507 // sort the collision list and take the first element
508 collList.sort();
509 thisColl = collList.front();
510
511 partListIterator<nDim> collPair[2];
512 bndryId = thisColl.bndryId;
513 outtime = thisColl.collTime;
514 collPair[0] = thisColl.particle0;
515 collPair[1] = thisColl.particle1;
516
517 if(bndryId > -1) // wall collision
518 {
519 if(!(*collPair[0]).toBeDeleted()) {
520 switch(m_lpt->a_bndryCellId(bndryId)) {
521 case 1012:
522 case 1002: {
523 // OUTLET BOUNDARY
524 if(!(*collPair[0]).wasSend() && !(*collPair[0]).toBeDeleted()) {
525 m_log << "particle left domain through outlet boundary" << endl;
526 (*collPair[0]).toBeDeleted() = true;
527 (*collPair[0]).toBeRespawn() = true;
528 (*collPair[0]).isInvalid() = true;
529 }
530 break;
531 }
532
533 case 1021:
534 case 1001: {
535 // INLET BOUNDARY
536 // check if particle really left the computational domain
537 MFloat l = checkBndryCross(bndryId, collPair[0], 0.0);
538 if(l >= 0.0 && l <= 1.1) {
539 // particle has left the area through inlet boundary
540 if(!(*collPair[0]).wasSend() && !(*collPair[0]).toBeDeleted()) {
541 m_log << "particle left domain through inlet boundary" << endl;
542 (*collPair[0]).toBeDeleted() = true;
543 (*collPair[0]).toBeRespawn() = true;
544 (*collPair[0]).isInvalid() = true;
545 }
546 }
547 break;
548 }
549
550 case 3002:
551 case 3003: // (mgc)
552 case 3803: // driven cavity lid
553 {
554 // WALL COLLISION
555 // particle has left the area through wall boundary
556 // => wall collision is executed
557 MFloat normVel = 0.0;
558 MFloat bndryBasis[MAX_SPACE_DIMENSIONS][MAX_SPACE_DIMENSIONS];
559 MFloat normN[MAX_SPACE_DIMENSIONS - 1];
560 MFloat reboundVel[MAX_SPACE_DIMENSIONS]; //, pointOfImpact[MAX_SPACE_DIMENSIONS];
561 MFloat oldCoordinates[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
562 numeric_limits<MFloat>::max()};
563 std::array<std::array<MFloat, MAX_SPACE_DIMENSIONS>, MAX_SPACE_DIMENSIONS> A;
564 std::array<MFloat, MAX_SPACE_DIMENSIONS> b;
565 fill_n(A[0].data(), MAX_SPACE_DIMENSIONS * MAX_SPACE_DIMENSIONS, 0.0);
566 fill_n(b.data(), MAX_SPACE_DIMENSIONS, 0.0);
567 // MFloat Ab[MAX_SPACE_DIMENSIONS * (MAX_SPACE_DIMENSIONS + 1)];
568 MFloat lambda = outtime / timeStep;
569
570 for(MInt i = 0; i < nDim; i++) {
571 oldCoordinates[i] =
572 (*collPair[0]).m_oldPos[i] + lambda * ((*collPair[0]).m_position[i] - (*collPair[0]).m_oldPos[i]);
573 normVel += POW2(m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i]
574 * ((*collPair[0]).m_position[i] - (*collPair[0]).m_oldPos[i]) / timeStep);
575 // RUDIE the minus sign in front of the 0.5 is there assuming
576 // that the surface normal always points into the fluid!
577 // pointOfImpact[i] = -0.5 * (*collPair[0]).m_diameter
578 // * m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normalVector[i]
579 // + lambda * (*collPair[0]).m_position[i]
580 // + (1.0 - lambda) * (*collPair[0]).m_oldPos[i];
581 }
582
583 // wall-normal velocity at collision
584 // normVel = sqrt(normVel);
585
586 // compute the basis w.r.t. the boundary surface
587 for(MInt i = 0; i < nDim - 1; i++) {
588 normN[i] = 0.0;
589 }
590
591 for(MInt i = 0; i < nDim - 1; i++) {
592 for(MInt j = 0; j < nDim; j++) {
593 normN[i] += POW2(m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[i + 1][j]
594 - m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[0][j]);
595 }
596 }
597
598 for(MInt i = 0; i < nDim - 1; i++) {
599 normN[i] = sqrt(normN[i]);
600 }
601
602 for(MInt i = 0; i < nDim; i++) {
603 bndryBasis[i][0] = m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i];
604 for(MInt j = 1; j < nDim; j++) {
605 bndryBasis[i][j] = (m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[j][i]
606 - m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[0][i])
607 / normN[j - 1];
608 }
609 }
610
611 // perform Gaussian elimination to transform the velocity into the
612 // boundary coordinate system
613 for(MInt i = 0; i < nDim; i++) {
614 A[0][i] = m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_normal[i];
615 for(MInt j = 1; j < nDim; j++) {
616 A[j][i] = (m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[j][i]
617 - m_lpt->m_bndryCells->a[bndryId].m_srfcs[0]->m_planeCoordinates[0][i])
618 / normN[j - 1];
619 }
620 b[i] = (*collPair[0]).m_oldVel[i];
621 }
622
624
625 // Last column of Ab now contains the velocity components w.r.t. the
626 // boundary coordinate system. Compute rebound velocity, set old
627 // velocity to zero, to compute transformed velocity.
628 (*collPair[0]).m_oldVel[0] = 0.0;
629 reboundVel[0] = -b[0];
630
631 for(MInt i = 1; i < nDim; i++) {
632 (*collPair[0]).m_oldVel[i] = 0.0;
633 (*collPair[0]).m_velocity[i] = 0.0;
634 reboundVel[i] = b[i];
635 }
636
637 // Transform the rebound velocity into the x,y,z coordinate system
638 // and save as old velocity. Compute new coordinates.
639 for(MInt i = 0; i < nDim; i++) {
640 for(MInt j = 0; j < nDim; j++) {
641 (*collPair[0]).m_oldVel[i] += bndryBasis[i][j] * reboundVel[j];
642 (*collPair[0]).m_velocity[i] = (*collPair[0]).m_oldVel[i];
643 }
644 (*collPair[0]).m_position[i] = oldCoordinates[i] + (1.0 - lambda) * timeStep * (*collPair[0]).m_oldVel[i];
645 }
646 // update cellId
647 (*collPair[0]).checkCellChange(&(*collPair[0]).m_oldPos[0]);
648
649 // compute old coordinates
650 for(MInt i = 0; i < nDim; i++) {
651 (*collPair[0]).m_oldPos[i] = oldCoordinates[i] + (lambda - 1.0) * timeStep * (*collPair[0]).m_oldVel[i];
652 }
653
654 (*collPair[0]).hasCollided() = true;
655 (*collPair[0]).firstStep() = true;
656
657 // MFloat collTime = solverPtr->m_time - m_particleTimeStep + outtime;
658
659 // write collision event if particle is real on this proc.
660 // RUDIE writing of wall collisions switched off for now...
661 // if (writeThisColl)
662 // writeCollEvent(collTime, (*collPair[0]).m_partId, -1, (*collPair[0]).m_diameter,
663 // 0.0, (*collPair[0]).m_densityRatio, 0.0, normVel, -1.0,
664 // &pointOfImpact[0]);
665
666 break;
667 }
668 default: {
669 // boundary condition id not implemented for particles!
670 cerr << "WARNING: This boundary condition not implemented for particles!" << endl;
671 cerr << "Treated as a solid wall" << endl;
672 }
673 }
674 }
675
676 // remove collisions still in the list that involve collPair[0]
677 // collPair[1] is not relevant since the current collision is with a wall
678 collList.remove_if(compareParticleIds<nDim>(collPair[0]));
679
680 // If particle is still active, check for new collisions of this particle
681 // with others. If yes, add new collision to the list and re-sort it
682 if(!(*collPair[0]).toBeDeleted()) {
683 MInt subCollIndex[3] = {numeric_limits<MInt>::max(), numeric_limits<MInt>::max(),
684 numeric_limits<MInt>::max()}; // gcc 4.8.2 maybe uninitialized
685 MInt _index2;
686 for(MInt i = 0; i < nDim; i++) {
687 subCollIndex[i] = (MInt)(((*collPair[0]).m_position[i] - m_subDomainCoordOffset[i]) / m_subDomainSize[i]);
688 }
689
690 IF_CONSTEXPR(nDim == 2) {
691 // 2D -> lots of for loops in the following:
692 // i - loops over -1, 0, +1 subdomain in x direction
693 // j - loops over -1, 0, +1 subdomain in y direction
694 // l - loops over particles in subdomain
695 for(MInt i = (subCollIndex[0] - 1); i < (subCollIndex[0] + 2); i++) {
696 for(MInt j = (subCollIndex[1] - 1); j < (subCollIndex[1] + 2); j++) {
697 if((i >= 0) && (i < m_noOfSubDomains[0]) && (j >= 0) && (j < m_noOfSubDomains[1])) {
698 _index2 = i + j * m_noOfSubDomains[0];
699 for(MInt l = 0; l < (MInt)subDomainContent[_index2].subDomain.size(); l++) {
700 if((collPair[0] != subDomainContent[_index2].subDomain.at((MUlong)l))
701 && !((*subDomainContent[_index2].subDomain.at((MUlong)l)).toBeDeleted())) {
702 MFloat _thisCollTime =
703 collisionCheck(collPair[0], subDomainContent[_index2].subDomain.at((MUlong)l), currCollTime);
704 if(_thisCollTime >= 0.0) // when no collision within the
705 { // current time step a negative time is returned
706 // add new collision event to the list
707 thisColl.particle0 = collPair[0];
708 thisColl.particle1 = subDomainContent[_index2].subDomain.at((MUlong)l);
709 thisColl.collTime = _thisCollTime;
710 thisColl.bndryId = -1;
711 collList.push_back(thisColl);
712 }
713 }
714 }
715 }
716 }
717 }
718 }
719 else {
720 // 3D -> lots of for loops in the following:
721 // i - loops over -1, 0, +1 subdomain in x direction
722 // j - loops over -1, 0, +1 subdomain in y direction
723 // k - loops over -1, 0, +1 subdomain in z direction
724 // l - loops over particles in subdomain
725 for(MInt i = (subCollIndex[0] - 1); i < (subCollIndex[0] + 2); i++) {
726 for(MInt j = (subCollIndex[1] - 1); j < (subCollIndex[1] + 2); j++) {
727 for(MInt k = (subCollIndex[2] - 1); k < (subCollIndex[2] + 2); k++) {
728 if((i >= 0) && (i < m_noOfSubDomains[0]) && (j >= 0) && (j < m_noOfSubDomains[1]) && (k >= 0)
729 && (k < m_noOfSubDomains[2])) {
730 _index2 = i + j * m_noOfSubDomains[0] + k * m_noOfSubDomains[0] * m_noOfSubDomains[1];
731 for(MInt l = 0; l < (MInt)subDomainContent[_index2].subDomain.size(); l++) {
732 if((collPair[0] != subDomainContent[_index2].subDomain.at((MUlong)l))
733 && !((*subDomainContent[_index2].subDomain.at((MUlong)l)).toBeDeleted())) {
734 MFloat __thisCollTime =
735 collisionCheck(collPair[0], subDomainContent[_index2].subDomain.at((MUlong)l), currCollTime);
736 if(__thisCollTime >= 0.0) // when no collision within the
737 { // current time step a negative time is returned
738 // add new collision event to the list
739 thisColl.particle0 = collPair[0];
740 thisColl.particle1 = subDomainContent[_index2].subDomain.at((MUlong)l);
741 thisColl.collTime = __thisCollTime;
742 thisColl.bndryId = -1;
743 collList.push_back(thisColl);
744 }
745 }
746 }
747 }
748 }
749 }
750 }
751 }
752
753 // check for new wall collisions of this particle
755 }
756
757 currCollTime = outtime;
758
759 } else { // current collision is a particle-particle collision
760 MFloat wdotr = 0.0, relVel = 0.0, meanVel = 0.0, deltap = 0.0;
761 MFloat vi0[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
762 numeric_limits<MFloat>::max()};
763 MFloat vi1[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
764 numeric_limits<MFloat>::max()};
765 MFloat r[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
766 numeric_limits<MFloat>::max()};
767 MFloat x0old[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
768 numeric_limits<MFloat>::max()};
769 MFloat x1old[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
770 numeric_limits<MFloat>::max()};
771 MFloat partMass0, partMass1;
772 MFloat pointOfImpact[MAX_SPACE_DIMENSIONS] = {numeric_limits<MFloat>::max(), numeric_limits<MFloat>::max(),
773 numeric_limits<MFloat>::max()};
774 MFloat rLength = (*collPair[1]).m_diameter / ((*collPair[0]).m_diameter + (*collPair[1]).m_diameter);
775 MInt qmax = 0;
776
777 // do some MBool algebra to determine whether collision is written by this processor
778 // in order to prevent multiple outputs of collisions on domain boundaries
779 // 1) collisions between 2 ghost particles are not written by this proc.
780 // 2) collisions between 2 real particles are written by this proc. by default
781 // 3) a collision between a real and a ghost particle is written by this proc. only
782 // if the real particle has the lowest m_partId
783 MBool writeThisColl = true;
784 MBool haloPart0 = (*collPair[0]).wasSend();
785 MBool haloPart1 = (*collPair[1]).wasSend();
786 MBool larger = ((*collPair[0]).m_partId > (*collPair[1]).m_partId);
787 if(haloPart0 & haloPart1) {
788 writeThisColl = false;
789 }
790 if(haloPart0 ^ haloPart1) {
791 if(haloPart1 & larger) {
792 writeThisColl = false;
793 }
794 if(haloPart0 & !larger) {
795 writeThisColl = false;
796 }
797 }
798
799 // particle velocities before collision, and separation vector at instant
800 // of collision:
801 for(MInt k = 0; k < nDim; k++) {
802 vi0[k] = ((*collPair[0]).m_position[k] - (*collPair[0]).m_oldPos[k]) / timeStep;
803 vi1[k] = ((*collPair[1]).m_position[k] - (*collPair[1]).m_oldPos[k]) / timeStep;
804 r[k] = ((*collPair[0]).m_oldPos[k] + outtime * vi0[k]) - ((*collPair[1]).m_oldPos[k] + outtime * vi1[k]);
805 x0old[k] = (*collPair[0]).m_oldPos[k];
806 x1old[k] = (*collPair[1]).m_oldPos[k];
807 wdotr += r[k] * (vi0[k] - vi1[k]);
808 relVel += POW2(vi0[k] - vi1[k]);
809 meanVel += POW2(vi0[k] + vi1[k]);
810 // subtract the mean flow velocity for the calculation of the meanVel
811 pointOfImpact[k] = (*collPair[1]).m_oldPos[k] + outtime * vi1[k] + r[k] * rLength;
812 }
813
814 // relVel is relative velocity at instance of collision
815 // meanVel is mean velocity at instance of collision
816 // pointOfImpact is position where the particles touch
817 relVel = sqrt(relVel);
818 meanVel = 0.5 * sqrt(meanVel);
819
820 partMass0 = F1B6 * PI * (*collPair[0]).m_densityRatio * POW3((*collPair[0]).m_diameter);
821 partMass1 = F1B6 * PI * (*collPair[1]).m_densityRatio * POW3((*collPair[1]).m_diameter);
822
823 if((m_collisionModel == 1) || (m_collisionModel == 2)) { // hard-sphere collision (no coagulation)
824 // particle velocities and positions after collision:
825 qmax = 2; // after collision, check for new collisions for both particles
826 for(MInt k = 0; k < nDim; k++) { // deltap is change in momentum without m1*m2 in the numerator
827 deltap = -2.0 * wdotr * r[k]
828 / ((partMass0 + partMass1) * 0.25 * POW2((*collPair[0]).m_diameter + (*collPair[1]).m_diameter));
829 (*collPair[0]).m_velocity[k] = vi0[k] + deltap * partMass1;
830 (*collPair[1]).m_velocity[k] = vi1[k] - deltap * partMass0;
831 (*collPair[0]).m_position[k] =
832 (*collPair[0]).m_oldPos[k] + vi0[k] * outtime + (*collPair[0]).m_velocity[k] * (timeStep - outtime);
833 (*collPair[1]).m_position[k] =
834 (*collPair[1]).m_oldPos[k] + vi1[k] * outtime + (*collPair[1]).m_velocity[k] * (timeStep - outtime);
835 }
836
837 // check cell change before updating the old particle coordinates
838 (*collPair[0]).checkCellChange(x0old);
839 (*collPair[1]).checkCellChange(x1old);
840
841 for(MInt k = 0; k < nDim; k++) { // updating particle oldCoords -> necessary in case of multiple
842 // collisions in current time step!
843 (*collPair[0]).m_oldPos[k] = (*collPair[0]).m_position[k] - (*collPair[0]).m_velocity[k] * timeStep;
844 (*collPair[1]).m_oldPos[k] = (*collPair[1]).m_position[k] - (*collPair[1]).m_velocity[k] * timeStep;
845 }
846
847 (*collPair[0]).hasCollided() = true;
848 (*collPair[0]).firstStep() = true;
849 (*collPair[1]).hasCollided() = true;
850 (*collPair[1]).firstStep() = true;
851
852 if(m_collisionModel == 1) {
853 MFloat part2CFL = 0.0;
854 for(MInt k = 0; k < nDim; k++) {
855 part2CFL += POW2((*collPair[1]).m_velocity[k]);
856 }
857 part2CFL *= POW2(timeStep / (*collPair[1]).m_diameter);
858 if(part2CFL > 0.04) {
859 cout << "Caution: a particle CFL number of " << sqrt(part2CFL) << " has been found!\n";
860 }
861 }
862
863 // remove future collisions involving these two particles from list
864 collList.remove_if(compareParticleIds<nDim>(collPair[0]));
865 collList.remove_if(compareParticleIds<nDim>(collPair[1]));
866 }
867
868 if((m_collisionModel == 3) || (m_collisionModel == 4)) { // instantaneous coagulation
869 // particle 0 is the single particle after collision, with partId the
870 // lesser of the two original partIds
871 if((*collPair[0]).m_partId > (*collPair[1]).m_partId) { // swap partIds if necessary
872 qmax = (*collPair[0]).m_partId;
873 (*collPair[0]).m_partId = (*collPair[1]).m_partId;
874 (*collPair[1]).m_partId = qmax;
875 }
876 qmax = 1; // after collision, only collPair[0] needs to be checked for
877 // new collisions
878
879 MFloat FSumMass = 1.0 / (partMass0 + partMass1);
880
881 for(MInt k = 0; k < nDim; k++) {
882 (*collPair[0]).m_velocity[k] =
883 FSumMass * (partMass0 * (*collPair[0]).m_velocity[k] + partMass1 * (*collPair[1]).m_velocity[k]);
884 (*collPair[0]).m_oldVel[k] = (*collPair[1]).m_velocity[k];
885 (*collPair[0]).m_position[k] = FSumMass
886 * (partMass0 * ((*collPair[0]).m_oldPos[k] + outtime * vi0[k])
887 + partMass1 * ((*collPair[1]).m_oldPos[k] + outtime * vi1[k]))
888 + (timeStep - outtime) * (*collPair[0]).m_velocity[k];
889 }
890
891 // check wheter particle changed cells before updating old coordinates
892 (*collPair[0]).checkCellChange(x0old);
893
894 for(MInt k = 0; k < nDim; k++) {
895 (*collPair[0]).m_oldPos[k] = (*collPair[0]).m_position[k] - timeStep * (*collPair[0]).m_velocity[k];
896 }
897
898 MFloat diam0 = (*collPair[0]).m_diameter;
899 MFloat diam1 = (*collPair[1]).m_diameter;
900 MFloat diam03 = POW3(diam0);
901 MFloat diam13 = POW3(diam1);
902 (*collPair[0]).m_diameter = pow(diam03 + diam13, F1B3);
903 (*collPair[0]).m_densityRatio =
904 (diam03 * (*collPair[0]).m_densityRatio + diam13 * (*collPair[1]).m_densityRatio) / (diam03 + diam13);
905
906 // change the m_firstStep flag to true: particle acceleration is not
907 // known anymore and thus simpler time integration required
908 (*collPair[0]).hasCollided() = true;
909 (*collPair[0]).firstStep() = true;
910
911 // remove future collisions involving these two particles from list
912 collList.remove_if(compareParticleIds<nDim>(collPair[0]));
913 collList.remove_if(compareParticleIds<nDim>(collPair[1]));
914
915 // particle collPair[1] of coagulation event is effectively removed
916 (*collPair[1]).toBeDeleted() = true;
917 (*collPair[0]).isInvalid() = true;
918 }
919
920 if((m_collisionModel == 5) || (m_collisionModel == 6)) { // just a registration of the collision event;
921 // particles move through each other without interaction
922
923 if(m_collisionModel == 5) {
924 MFloat part2CFL = 0.0;
925 for(MInt k = 0; k < nDim; k++) {
926 part2CFL += POW2((*collPair[1]).m_velocity[k]);
927 }
928 part2CFL *= POW2(timeStep / (*collPair[1]).m_diameter);
929 if(part2CFL > 0.04) {
930 cout << "Caution: a particle CFL number of " << sqrt(part2CFL) << " has been found!\n";
931 }
932 }
933 // remove the current collision from the list
934 collList.pop_front();
935 }
936
937 // particle CFL is only relevant for retroactive particle collision
938 // detection!
939 if((m_collisionModel == 1) || (m_collisionModel == 3) || (m_collisionModel == 5)) {
940 MFloat part0CFL = 0.0;
941 for(MInt k = 0; k < nDim; k++) {
942 part0CFL += POW2((*collPair[0]).m_velocity[k]);
943 }
944 part0CFL *= POW2(timeStep / (*collPair[0]).m_diameter);
945 if(part0CFL > 0.04) {
946 cout << "Caution: a particle CFL number of " << sqrt(part0CFL) << " has been found!\n";
947 }
948 }
949
950 // update partial time in this time step, to be able to exclude unphysical
951 // earlier collisions that may be found after updates of the "old"
952 // particle velocities
953 currCollTime = outtime;
954
955 if((m_collisionModel != 5) && (m_collisionModel != 6)) {
956 // check for new collisions of these particles with others
957 // if yes, add new collision to the list and re-sort it
958 IF_CONSTEXPR(nDim == 2) {
959 // 2D -> lots of for loops in the following:
960 // q - loops collPair[q], 0 and 1
961 // i - loops over -1, 0, +1 subdomain in x direction
962 // j - loops over -1, 0, +1 subdomain in y direction
963 // l - loops over particles in subdomain
964 for(MInt q = 0; q < qmax; q++) {
965 if((*collPair[q]).toBeDeleted()) {
966 continue;
967 }
968 for(MInt i = 0; i < nDim; i++) {
969 subIndex[i] = (MInt)(((*collPair[q]).m_position[i] - m_subDomainCoordOffset[i]) / m_subDomainSize[i]);
970 }
971
972 for(MInt i = (subIndex[0] - 1); i < (subIndex[0] + 2); i++) {
973 for(MInt j = (subIndex[1] - 1); j < (subIndex[1] + 2); j++) {
974 if((i >= 0) && (i < m_noOfSubDomains[0]) && (j >= 0) && (j < m_noOfSubDomains[1])) {
975 MInt _index2 = i + j * m_noOfSubDomains[0];
976 for(MInt l = 0; l < (MInt)subDomainContent[_index2].subDomain.size(); l++) {
977 if((collPair[q] != subDomainContent[_index2].subDomain.at((MUlong)l))
978 && !((*subDomainContent[_index2].subDomain.at((MUlong)l)).toBeDeleted())) {
979 MFloat _thisCollTime =
980 collisionCheck(collPair[q], subDomainContent[_index2].subDomain.at((MUlong)l), currCollTime);
981 if(_thisCollTime >= 0.0) // when no collision within the
982 { // current time step a negative time is returned
983 // add new collision event to the list
984 thisColl.particle0 = collPair[q];
985 thisColl.particle1 = subDomainContent[_index2].subDomain.at((MUlong)l);
986 thisColl.collTime = _thisCollTime;
987 thisColl.bndryId = -1;
988 collList.push_back(thisColl);
989 }
990 }
991 }
992 }
993 }
994 }
995 }
996 }
997 else {
998 // 3D -> lots of for loops in the following:
999 // q - loops collPair[q], 0 and 1
1000 // i - loops over -1, 0, +1 subdomain in x direction
1001 // j - loops over -1, 0, +1 subdomain in y direction
1002 // k - loops over -1, 0, +1 subdomain in z direction
1003 // l - loops over particles in subdomain
1004 for(MInt q = 0; q < qmax; q++) {
1005 if((*collPair[q]).toBeDeleted()) {
1006 continue;
1007 }
1008 for(MInt i = (subIndex[0] - 1); i < (subIndex[0] + 2); i++) {
1009 for(MInt j = (subIndex[1] - 1); j < (subIndex[1] + 2); j++) {
1010 for(MInt k = (subIndex[2] - 1); k < (subIndex[2] + 2); k++) {
1011 if((i >= 0) && (i < m_noOfSubDomains[0]) && (j >= 0) && (j < m_noOfSubDomains[1]) && (k >= 0)
1012 && (k < m_noOfSubDomains[2])) {
1013 MInt __index2 = i + j * m_noOfSubDomains[0] + k * m_noOfSubDomains[0] * m_noOfSubDomains[1];
1014 for(MInt l = 0; l < (MInt)subDomainContent[__index2].subDomain.size(); l++) {
1015 if((collPair[q] != subDomainContent[__index2].subDomain.at((MUlong)l))
1016 && !((*subDomainContent[__index2].subDomain.at((MUlong)l)).toBeDeleted())) {
1017 MFloat __thisCollTime = collisionCheck(
1018 collPair[q], subDomainContent[__index2].subDomain.at((MUlong)l), currCollTime);
1019 if(__thisCollTime >= 0.0) // when no collision within the
1020 { // current time step a negative time is returned
1021 // add new collision event to the list
1022 thisColl.particle0 = collPair[q];
1023 thisColl.particle1 = subDomainContent[__index2].subDomain.at((MUlong)l);
1024 thisColl.collTime = __thisCollTime;
1025 thisColl.bndryId = -1;
1026 collList.push_back(thisColl);
1027 }
1028 }
1029 }
1030 }
1031 }
1032 }
1033 }
1034 }
1035 }
1036
1037 if(m_lpt->m_wallCollisions) {
1038 // check for new wall collisions of these particles
1039 for(MInt q = 0; q < qmax; q++) {
1040 if((*collPair[q]).toBeDeleted()) {
1041 continue;
1042 }
1044 }
1045 }
1046 }
1047
1048 // write collision event
1049 if(writeThisColl) {
1050 // only record collisions after x = m_particleCollOffset so that the particles have had time to
1051 // adapt to the flow
1052 if(pointOfImpact[0] > m_offset) {
1053 writeCollEvent(time, (*collPair[0]).m_partId, (*collPair[1]).m_partId, (*collPair[0]).m_diameter,
1054 (*collPair[1]).m_diameter, (*collPair[0]).m_densityRatio, (*collPair[1]).m_densityRatio,
1055 relVel, meanVel, pointOfImpact);
1056 }
1057 }
1058 }
1059 }
1060
1061 for(MInt i = 0; i < m_totalSubDomains; i++) {
1062 subDomainContent[i].subDomain.clear();
1063 }
1064
1066 for(MInt i = 0; i < m_totalSubDomains; i++) {
1067 subDomainContentEllipsoid[i].subDomain.clear();
1068 }
1069 }
1070}
maia::lpt::subDomainCollectorEllipsoid< nDim > * subDomainContentEllipsoid
Definition: lptcollision.h:59
MFloat checkBndryCross(MInt, lptParticleI, MFloat)
Checks crossing of boundary surface of the boundary cell.
void collisionCheckSphereEllipsoid(lptParticleI, lptEllipticleI)
Collision check for ellipsoids i2 and i3 calls the corresponding proactive or retroactive method.
MFloat collisionCheck(lptParticleI, lptParticleI, MFloat)
Checks whether particles i and j collide after currCollTime, and returns collision time.
MFloat m_subDomainSize[3]
Definition: lptcollision.h:55
maia::lpt::subDomainCollector< nDim > * subDomainContent
Definition: lptcollision.h:58
MInt m_noOfSubDomains[3]
Definition: lptcollision.h:53
void collisionCheckEllipsoidEllipsoid(lptEllipticleI, lptEllipticleI)
Collision check for ellipsoids i2 and i3 calls the corresponding proactive or retroactive method.
std::list< collStruct< nDim > > collList
Definition: lptcollision.h:51
void writeCollEvent(MFloat collisionTime, MInt particle0, MInt particle1, MFloat diam0, MFloat diam1, MFloat dens0, MFloat dens1, MFloat relVel, MFloat meanVel, MFloat *x)
Add collision data to queue which is to be written.
MFloat m_subDomainCoordOffset[3]
Definition: lptcollision.h:54
MBool m_includeEllipsoids
Definition: lptcollision.h:64
std::vector< LPTSpherical< nDim > >::iterator particle1
std::vector< LPTSpherical< nDim > >::iterator particle0
constexpr Real POW3(const Real x)
Definition: functions.h:123
InfoOutFile m_log
constexpr MLong IPOW2(MInt x)
uint64_t MUlong
Definition: maiatypes.h:65
IdType index(const FloatType *const x, const IdType level)
Return Hilbert index for given location and level in 2D or 3D.
Definition: hilbert.h:165
typename std::vector< LPTSpherical< nDim > >::iterator partListIterator
Definition: lptlib.h:35
typename std::vector< LPTEllipsoidal< nDim > >::iterator ellipsListIterator
Definition: lptlib.h:30
template void solveQR< 3 >(std::array< std::array< MFloat, 3 >, 3 > &, std::array< MFloat, 3 > &)

◆ domainId()

template<MInt nDim>
MInt ParticleCollision< nDim >::domainId ( ) const
inlineprivate

Definition at line 46 of file lptcollision.h.

46{ return m_domainId; }

◆ geometryInteraction()

template<MInt nDim>
void ParticleCollision< nDim >::geometryInteraction

Definition at line 1077 of file lptcollision.cpp.

1077 {
1078 TRACE();
1079
1080
1081 // collStruct<nDim> thisColl;
1082 //
1083 // // in case of a boundary cell, always check for wall collisions
1084 // if(m_fvSolver->a_boundaryId((*partVectorElement).m_cellId) > -1) {
1085 //
1086 // MFloat lambda = checkBndryCross(
1087 // m_fvSolver->a_boundaryId((*partVectorElement).m_cellId), partVectorElement,
1088 // (*partVectorElement).m_diameter);
1089 //
1090 // if(lambda >= 0.0 && lambda <= 1.0) {
1091 // thisColl.particle0 = partVectorElement;
1092 // thisColl.particle1 = partVectorElement;
1093 // thisColl.bndryId = m_fvSolver->a_boundaryId((*partVectorElement).m_cellId);
1094 // thisColl.collTime = lambda * m_timeStep;
1095 // theCollList.push_back(thisColl);
1096 // }
1097 // }
1098 //
1099 // // The particle may encounter a wall which lies inside a neighboring cell.
1100 // // The check is only carried out at the highest grid refinement level, as this
1101 // // level is found near the solid walls and the check requires quite some time
1102
1103 // MFloat lambda;
1104 //
1105 // MFloat centerCoords[MAX_SPACE_DIMENSIONS];
1106 // MInt curCellId = (*partVectorElement).m_cellId;
1107 // MFloat halfLength = m_lpt->c_cellLengthAtLevel(m_lpt->c_level(curCellId) + 1);
1108 // MFloat diagCoords[MAX_SPACE_DIMENSIONS];
1109 //
1110 // //now just c_coordinate!
1111 //
1112 // // diagCoords temporarily holds the difference between particle and
1113 // // cell-center coordinates
1114 // for(MInt m = 0; m < nDim; m++) {
1115 // diagCoords[m] = (*partVectorElement).m_position[m] - centerCoords[m];
1116 // }
1117 //
1118 // // direct neighbors in the direction of the relative displacement between
1119 // // particle and cell center
1120 // for(MInt d = 0; d < nDim; d++) {
1121 // for(MInt n = m_fvSolver->a_identNghbrId((*partVectorElement).m_cellId * 2 * nDim + d);
1122 // n < m_fvSolver->a_identNghbrId((*partVectorElement).m_cellId * 2 * nDim + d + 1);
1123 // n++) {
1124 // if(m_fvSolver->a_boundaryId(m_fvSolver->a_storeNghbrId(n)) > -1) {
1125 // lambda = checkBndryCross(m_fvSolver->a_boundaryId(m_fvSolver->a_storeNghbrId(n)),
1126 // partVectorElement, (*partVectorElement).m_diameter);
1127 // if(lambda >= 0.0 && lambda <= 1.0) {
1128 // thisColl.particle0 = partVectorElement;
1129 // thisColl.particle1 = partVectorElement;
1130 // thisColl.bndryId = m_fvSolver->a_boundaryId(m_fvSolver->a_storeNghbrId(n));
1131 // thisColl.collTime = lambda * m_timeStep;
1132 // theCollList.push_back(thisColl);
1133 // }
1134 // }
1135 // }
1136 //
1137 // // check the diagonal neighbor(s)
1138 // for(MInt d = 0; d < nDim; d++) {
1139 // diagCoords[d] /= fabs(diagCoords[d]);
1140 // diagCoords[d] *= halfLength * 1.2;
1141 // }
1142 //
1143 //
1144 // MFloat tempDiagCoords[3];
1145 //
1146 // for(MInt d = 0; d < 4; d++) {
1147 // curCellId = (*partVectorElement).m_cellId;
1148 // // cycle through directions xy (d=0), xz (1), yz (2), xyz (3)
1149 // tempDiagCoords[0] = centerCoords[0] + float((d - 2) != 0) * diagCoords[0];
1150 // tempDiagCoords[1] = centerCoords[1] + float((d - 1) != 0) * diagCoords[1];
1151 // IF_CONSTEXPR(nDim == 2) {
1152 // tempDiagCoords[2] = centerCoords[2] + float(d != 0) * diagCoords[2];
1153 // }
1154 //
1155 // checkCoordCellChange(m_solver, tempDiagCoords, centerCoords, curCellId);
1156 //
1157 // if((curCellId != (*partVectorElement).m_cellId) &&
1158 // (m_fvSolver->a_boundaryId(curCellId) > -1)) {
1159 // lambda = checkBndryCross(m_fvSolver->a_boundaryId(curCellId),
1160 // partVectorElement, (*partVectorElement).m_diameter);
1161 // if(lambda >= 0.0 && lambda <= 1.0) {
1162 // thisColl.particle0 = partVectorElement;
1163 // thisColl.particle1 = partVectorElement;
1164 // thisColl.bndryId = m_fvSolver->a_boundaryId(curCellId);
1165 // thisColl.collTime = lambda * m_timeStep;
1166 // theCollList.push_back(thisColl);
1167 // }
1168 // }
1169 // }
1170 // }
1171}

◆ init()

template<MInt nDim>
void ParticleCollision< nDim >::init ( )
Author
Sven Berger
Date
June 2016

◆ mpiComm()

template<MInt nDim>
MPI_Comm ParticleCollision< nDim >::mpiComm ( ) const
inlineprivate

Definition at line 49 of file lptcollision.h.

49{ return m_mpiComm; }

◆ noDomains()

template<MInt nDim>
MInt ParticleCollision< nDim >::noDomains ( ) const
inlineprivate

Definition at line 48 of file lptcollision.h.

48{ return m_noDomains; }

◆ solverId()

template<MInt nDim>
MInt ParticleCollision< nDim >::solverId ( ) const
inlineprivate

Definition at line 47 of file lptcollision.h.

47{ return m_solverId; }

◆ testU_CCD()

template<MInt nDim>
MFloat ParticleCollision< nDim >::testU_CCD ( const MFloat u,
const MFloat t4,
const MFloat t3,
const MFloat t2,
const MFloat t1,
const MFloat t0 
)
private

MFloat LPT::testU_CCD(const MFloat& u ,const MFloat& t4, const MFloat& t3, const MFloat& t2, const MFloat& t1, const MFloat& t0)

Aug-2013

Author
Christoph Siewert

Definition at line 2881 of file lptcollision.cpp.

2882 {
2883 TRACE();
2884
2885 MFloat positive = -1;
2886 if((u > 0) && (u <= 1)) {
2887 MFloat result = t4 * u * u * u * u + t3 * u * u * u + t2 * u * u + t1 * u + t0;
2888 if(result >= 0) {
2889 positive = u;
2890 }
2891 }
2892
2893 return positive;
2894}

◆ writeCollData()

template<MInt nDim>
void ParticleCollision< nDim >::writeCollData
Author
Jerry Grimmen, Apr-10

Definition at line 3015 of file lptcollision.cpp.

3015 {
3016 TRACE();
3017
3018 // Read the size of the collision queue and put it into the Netcdf file.
3019 MInt ncmpiCollQueueSize = (MInt)collQueue.size();
3020 // Read the amount of collisions of each domain.
3021 MIntScratchSpace ncmpiCollCount(noDomains(), AT_, "ncmpiCollCount");
3022 MPI_Allgather(&ncmpiCollQueueSize, 1, MPI_INT, &ncmpiCollCount[0], 1, MPI_INT, mpiComm(), AT_, "ncmpiCollQueueSize",
3023 "ncmpiCollCount[0]");
3024
3025 MInt ncmpiCollCountMax = 0;
3026 for(MInt i = 0; i < noDomains(); ++i) {
3027 ncmpiCollCountMax += ncmpiCollCount[i];
3028 }
3029
3030 // Only write collision data if there is any collision at all.
3031 if(ncmpiCollCountMax != 0) {
3032 // Change file name for collision data and create a new file. (Leaves file
3033 // open and in define mode).
3034 stringstream ncmpistream;
3035 string ncmpiFileName;
3036 ncmpistream << "out/collData." << globalTimeStep << ParallelIo::fileExt();
3037 ncmpistream >> ncmpiFileName;
3038 ncmpistream.clear();
3039
3040 using namespace maia::parallel_io;
3041 ParallelIo parallelIo(ncmpiFileName, PIO_REPLACE, mpiComm());
3042
3043 // Define Attribute timestep (double).
3044 parallelIo.setAttribute(m_lpt->m_timeStep, "particleTimestep");
3045
3046 // Define Dimension collCount [noDomains] & Define Variable collCount
3047 // (int) [collCount].
3048 parallelIo.defineArray(PIO_INT, "collCount", noDomains());
3049
3050 // Define dimensions and variables for all collision data.
3051 parallelIo.defineArray(PIO_FLOAT, "collTime", ncmpiCollCountMax);
3052 parallelIo.defineArray(PIO_INT, "part0", ncmpiCollCountMax);
3053 parallelIo.defineArray(PIO_INT, "part1", ncmpiCollCountMax);
3054 parallelIo.defineArray(PIO_FLOAT, "p0diam", ncmpiCollCountMax);
3055 parallelIo.defineArray(PIO_FLOAT, "p1diam", ncmpiCollCountMax);
3056 parallelIo.defineArray(PIO_FLOAT, "p0dens", ncmpiCollCountMax);
3057 parallelIo.defineArray(PIO_FLOAT, "p1dens", ncmpiCollCountMax);
3058 parallelIo.defineArray(PIO_FLOAT, "relVel", ncmpiCollCountMax);
3059 parallelIo.defineArray(PIO_FLOAT, "meanVel", ncmpiCollCountMax);
3060 parallelIo.defineArray(PIO_FLOAT, "collPos", 3 * ncmpiCollCountMax);
3061
3062 // EndDef (Go into data mode).
3063
3064 ParallelIo::size_type ncmpiStart = domainId();
3065 ParallelIo::size_type ncmpiCount = 1;
3066
3067 parallelIo.setOffset(ncmpiCount, ncmpiStart);
3068 parallelIo.writeArray(&ncmpiCollQueueSize, "collCount");
3069
3070 ncmpiStart = 0;
3071 for(MInt i = 0; i < domainId(); ++i) {
3072 ncmpiStart += ncmpiCollCount[i];
3073 }
3074 ncmpiCount = ncmpiCollCount[domainId()];
3075 if(ncmpiStart >= ncmpiCollCountMax) {
3076 if(ncmpiCount == 0) {
3077 ncmpiStart = 0;
3078 } else {
3079 mTerm(1, AT_,
3080 "Error in LPT::writeCollData!! ncmpiStart >= "
3081 "ncmpiCollCountMax but ncmpiCount != 0");
3082 }
3083 }
3084
3085 // Arrays to hold collisions data.
3086 MFloatScratchSpace ncmpiCollTime(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3087 MIntScratchSpace ncmpiPart0(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3088 MIntScratchSpace ncmpiPart1(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3089 MFloatScratchSpace ncmpiP0Diam(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3090 MFloatScratchSpace ncmpiP1Diam(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3091 MFloatScratchSpace ncmpiP0Dens(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3092 MFloatScratchSpace ncmpiP1Dens(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3093 MFloatScratchSpace ncmpiRelVel(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3094 MFloatScratchSpace ncmpiMeanVel(ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3095 MFloatScratchSpace ncmpiCollPos(3 * ncmpiCollCount[domainId()], AT_, "ncmpiCollTime");
3096 MInt ncmpiCountId = 0;
3097
3098 // Write the data from the queue into the array.
3099 while(!collQueue.empty()) {
3100 ncmpiCollTime[ncmpiCountId] = collQueue.front().collTime;
3101 ncmpiPart0[ncmpiCountId] = collQueue.front().part0;
3102 ncmpiPart1[ncmpiCountId] = collQueue.front().part1;
3103 ncmpiP0Diam[ncmpiCountId] = collQueue.front().diam0;
3104 ncmpiP1Diam[ncmpiCountId] = collQueue.front().diam1;
3105 ncmpiP0Dens[ncmpiCountId] = collQueue.front().dens0;
3106 ncmpiP1Dens[ncmpiCountId] = collQueue.front().dens1;
3107 ncmpiRelVel[ncmpiCountId] = collQueue.front().relVel;
3108 ncmpiMeanVel[ncmpiCountId] = collQueue.front().meanVel;
3109 ncmpiCollPos[(3 * ncmpiCountId)] = collQueue.front().collPosX;
3110 ncmpiCollPos[(3 * ncmpiCountId) + 1] = collQueue.front().collPosY;
3111 ncmpiCollPos[(3 * ncmpiCountId) + 2] = collQueue.front().collPosZ;
3112
3113 collQueue.pop();
3114 ++ncmpiCountId;
3115 }
3116
3117 // Put the arrays into the Netcdf file.
3118 parallelIo.setOffset(ncmpiCount, ncmpiStart);
3119 parallelIo.writeArray(&ncmpiCollTime[0], "collTime");
3120 parallelIo.writeArray(&ncmpiPart0[0], "part0");
3121 parallelIo.writeArray(&ncmpiPart1[0], "part1");
3122 parallelIo.writeArray(&ncmpiP0Diam[0], "p0diam");
3123 parallelIo.writeArray(&ncmpiP1Diam[0], "p1diam");
3124 parallelIo.writeArray(&ncmpiP0Dens[0], "p0dens");
3125 parallelIo.writeArray(&ncmpiP1Dens[0], "p1dens");
3126 parallelIo.writeArray(&ncmpiRelVel[0], "relVel");
3127 parallelIo.writeArray(&ncmpiMeanVel[0], "meanVel");
3128
3129 ncmpiCount *= 3;
3130 ParallelIo::size_type ncmpi3Start = 3 * ncmpiStart;
3131 parallelIo.setOffset(ncmpiCount, ncmpi3Start);
3132 parallelIo.writeArray(&ncmpiCollPos[0], "collPos");
3133
3134 // Free memory.
3135 while(!collQueue.empty()) {
3136 collQueue.pop();
3137 }
3138 }
3139
3141 // Read the size of the collision queue and put it into the Netcdf file.
3142 ncmpiCollQueueSize = (MInt)collQueueEllipsoid.size();
3143 // Read the amount of collisions of each domain.
3144 MIntScratchSpace ncmpiEllipsoidCollCount(noDomains(), AT_, "ncmpiEllipsoidCollCount");
3145 MPI_Allgather(&ncmpiCollQueueSize, 1, MPI_INT, &ncmpiEllipsoidCollCount[0], 1, MPI_INT, mpiComm(), AT_,
3146 "ncmpiCollQueueSize", "ncmpiEllipsoidCollCount[0]");
3147
3148 ncmpiCollCountMax = 0;
3149 for(MInt i = 0; i < noDomains(); ++i) {
3150 ncmpiCollCountMax += ncmpiEllipsoidCollCount[i];
3151 }
3152
3153 // Only write collision data if there is any collision at all.
3154 if(ncmpiCollCountMax != 0) {
3155 // Change file name for collision data and create a new file. (Leaves
3156 // file open and in define mode).
3157 stringstream ncmpistream;
3158 string ncmpiFileName;
3159 ncmpistream << "out/collEllipsoid." << globalTimeStep << ParallelIo::fileExt();
3160 ncmpistream >> ncmpiFileName;
3161 ncmpistream.clear();
3162
3163 // WARNING: untested switch from NetCDF/Parallel netCDF to ParallelIo
3164 // The method previously used direct I/O calls, which were replaced by
3165 // ParallelIo methods in summer 2015. However, since the method was not
3166 // used by any of the testcases, this code is still *untested*. Thus,
3167 // if your code uses this part of the code, please make sure that the
3168 // I/O still works as expected and then remove this warning as well as
3169 // the subsequent TERMM().
3170 TERMM(1, "untested I/O method, please see comment for how to proceed");
3171 using namespace maia::parallel_io;
3172 ParallelIo parallelIo(ncmpiFileName, PIO_REPLACE, mpiComm());
3173 ncmpiFileName.clear();
3174
3175 // Define Attribute timestep (double).
3176 MFloat ncmpiTimeStep = globalTimeStep;
3177 parallelIo.setAttribute(ncmpiTimeStep, "timestep");
3178
3179 // Define Dimension overlapCount [noDomains] & Define Variable collCount
3180 // (int) [collCount].
3181 parallelIo.defineArray(PIO_INT, "overlapCount", noDomains());
3182
3183 // Define dimensions and variables for all collision datas.
3184 parallelIo.defineArray(PIO_FLOAT, "collTimeStep", ncmpiCollCountMax);
3185 parallelIo.defineArray(PIO_INT, "part0", ncmpiCollCountMax);
3186 parallelIo.defineArray(PIO_INT, "part1", ncmpiCollCountMax);
3187 parallelIo.defineArray(PIO_FLOAT, "p0semiMinorAxis", ncmpiCollCountMax);
3188 parallelIo.defineArray(PIO_FLOAT, "p1semiMinorAxis", ncmpiCollCountMax);
3189 parallelIo.defineArray(PIO_FLOAT, "p0aspectRatio", ncmpiCollCountMax);
3190 parallelIo.defineArray(PIO_FLOAT, "p1aspectRatio", ncmpiCollCountMax);
3191 parallelIo.defineArray(PIO_FLOAT, "p0dens", ncmpiCollCountMax);
3192 parallelIo.defineArray(PIO_FLOAT, "p1dens", ncmpiCollCountMax);
3193 parallelIo.defineArray(PIO_FLOAT, "collPos", 3 * ncmpiCollCountMax);
3194
3195 // EndDef (Go into data mode).
3196
3197 ParallelIo::size_type ncmpiStart = domainId();
3198 ParallelIo::size_type ncmpiCount = 1;
3199
3200 parallelIo.setOffset(ncmpiCount, ncmpiStart);
3201 parallelIo.writeArray(&ncmpiCollQueueSize, "overlapCount");
3202
3203 ncmpiStart = 0;
3204 for(MInt i = 0; i < domainId(); ++i) {
3205 ncmpiStart += ncmpiEllipsoidCollCount[i];
3206 }
3207 ncmpiCount = ncmpiEllipsoidCollCount[domainId()];
3208 if(ncmpiStart >= ncmpiCollCountMax) {
3209 if(ncmpiCount == 0) {
3210 ncmpiStart = 0;
3211 } else {
3212 mTerm(1, AT_,
3213 "Error in LPT::writeCollData "
3214 "(m_includeEllipsoids)!! ncmpiStart >= "
3215 "ncmpiCollCountMax but ncmpiCount != 0");
3216 }
3217 }
3218
3219 // Arrays to hold collisions data.
3220 MFloatScratchSpace ncmpiCollTimeStep(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiCollTimeStep");
3221 MIntScratchSpace ncmpiPart0(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiPart0");
3222 MIntScratchSpace ncmpiPart1(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiPart1");
3223 MFloatScratchSpace ncmpiP0SemiMinorAxis(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP0SemiMinorAxis");
3224 MFloatScratchSpace ncmpiP1SemiMinorAxis(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP1SemiMinorAxis");
3225 MFloatScratchSpace ncmpiP0AspectRatio(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP0AspectRatio");
3226 MFloatScratchSpace ncmpiP1AspectRatio(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP1AspectRatio");
3227 MFloatScratchSpace ncmpiP0Dens(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP0Dens");
3228 MFloatScratchSpace ncmpiP1Dens(ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiP1Dens");
3229 MFloatScratchSpace ncmpiCollPos(3 * ncmpiEllipsoidCollCount[domainId()], AT_, "ncmpiCollPos");
3230 MInt ncmpiCountId = 0;
3231
3232
3233 // Write the data from the queue into the array.
3234 while(!collQueueEllipsoid.empty()) {
3235 ncmpiCollTimeStep[ncmpiCountId] = collQueueEllipsoid.front().collTimeStep;
3236 ncmpiPart0[ncmpiCountId] = collQueueEllipsoid.front().part0;
3237 ncmpiPart1[ncmpiCountId] = collQueueEllipsoid.front().part1;
3238 ncmpiP0SemiMinorAxis[ncmpiCountId] = collQueueEllipsoid.front().semiMinorAxis0;
3239 ncmpiP1SemiMinorAxis[ncmpiCountId] = collQueueEllipsoid.front().semiMinorAxis1;
3240 ncmpiP0AspectRatio[ncmpiCountId] = collQueueEllipsoid.front().aspectRatio0;
3241 ncmpiP1AspectRatio[ncmpiCountId] = collQueueEllipsoid.front().aspectRatio1;
3242 ncmpiP0Dens[ncmpiCountId] = collQueueEllipsoid.front().dens0;
3243 ncmpiP1Dens[ncmpiCountId] = collQueueEllipsoid.front().dens1;
3244 ncmpiCollPos[(3 * ncmpiCountId)] = collQueueEllipsoid.front().collPosX;
3245 ncmpiCollPos[(3 * ncmpiCountId) + 1] = collQueueEllipsoid.front().collPosY;
3246 ncmpiCollPos[(3 * ncmpiCountId) + 2] = collQueueEllipsoid.front().collPosZ;
3247
3248 collQueueEllipsoid.pop();
3249 ++ncmpiCountId;
3250 }
3251
3252 // Put the arrays into the Netcdf file.
3253 parallelIo.setOffset(ncmpiCount, ncmpiStart);
3254 parallelIo.writeArray(&ncmpiCollTimeStep[0], "collTimeStep");
3255 parallelIo.writeArray(&ncmpiPart0[0], "part0");
3256 parallelIo.writeArray(&ncmpiPart1[0], "part1");
3257 parallelIo.writeArray(&ncmpiP0SemiMinorAxis[0], "p0semiMinorAxis");
3258 parallelIo.writeArray(&ncmpiP1SemiMinorAxis[0], "p1semiMinorAxis");
3259 parallelIo.writeArray(&ncmpiP0AspectRatio[0], "p0aspectRatio");
3260 parallelIo.writeArray(&ncmpiP1AspectRatio[0], "p1aspectRatio");
3261 parallelIo.writeArray(&ncmpiP0Dens[0], "p0dens");
3262 parallelIo.writeArray(&ncmpiP1Dens[0], "p1dens");
3263
3264 ncmpiCount *= 3;
3265 ParallelIo::size_type ncmpi3Start = 3 * ncmpiStart;
3266
3267 parallelIo.setOffset(ncmpiCount, ncmpi3Start);
3268 parallelIo.writeArray(&ncmpiCollPos[0], "collPos");
3269
3270 // Free memory.
3271 while(!collQueueEllipsoid.empty()) {
3272 collQueueEllipsoid.pop();
3273 }
3274 }
3275 }
3276}
MPI_Comm mpiComm() const
Definition: lptcollision.h:49
std::queue< collQueueElem > collQueue
Definition: lptcollision.h:122
This class is a ScratchSpace.
Definition: scratch.h:758
int MPI_Allgather(const void *sendbuf, int sendcount, MPI_Datatype sendtype, void *recvbuf, int recvcount, MPI_Datatype recvtype, MPI_Comm comm, const MString &name, const MString &sndvarname, const MString &rcvvarname)
same as MPI_Allgather
PARALLELIO_DEFAULT_BACKEND ParallelIo
Definition: parallelio.h:292

◆ writeCollEvent()

template<MInt nDim>
void ParticleCollision< nDim >::writeCollEvent ( MFloat  collisionTime,
MInt  particle0,
MInt  particle1,
MFloat  diam0,
MFloat  diam1,
MFloat  dens0,
MFloat  dens1,
MFloat  relVel,
MFloat  meanVel,
MFloat x 
)
private

void LPT::writeCollEvent(MFloat collisionTime, MInt particle0, MInt particle1, MFloat diam0, MFloat diam1, MFloat dens0, MFloat dens1, MFloat relVel, MFloat meanVel, MFloat *x)

store all data concerning particle-particle collisions: collisionTime = exact time of impact particle0 = index of particle 0 particle1 = index of particle 1 relVel = relative velocity |w| = |v_0 - v_1| meanVel = mean velocity |W| = 0.5 * |v_0 + v_1| x[nDim] = point of impact

Author
Rudie Kunnen, modified by Jerry Grimmen (29-4-2010)

Definition at line 2562 of file lptcollision.cpp.

2564 {
2565 TRACE();
2566
2567 // Create a collision element for the collision queue.
2568 // Needed to write collision datas into a collective Netcdf file.
2569 // m_log << std::setprecision(12) << "collTime " << collisionTime << " partId1 " << particle0 << " partId2 " <<
2570 // particle1 << " timestep " << m_timeStep
2571 // << " [" << m_time << ", " << m_time + m_timeStep << "]" << endl;
2572 collQueueElem collData = {collisionTime, diam0, diam1, dens0, dens1, relVel,
2573 meanVel, x[0], x[1], x[2], particle0, particle1};
2574 collQueue.push(collData);
2575}

Friends And Related Function Documentation

◆ LPT< nDim >

template<MInt nDim>
friend class LPT< nDim >
friend

Definition at line 1 of file lptcollision.h.

Member Data Documentation

◆ collList

template<MInt nDim>
std::list<collStruct<nDim> > ParticleCollision< nDim >::collList
private

Definition at line 51 of file lptcollision.h.

◆ collQueue

template<MInt nDim>
std::queue<collQueueElem> ParticleCollision< nDim >::collQueue
private

Definition at line 122 of file lptcollision.h.

◆ collQueueEllipsoid

template<MInt nDim>
std::queue<collQueueElemEllipsoid> ParticleCollision< nDim >::collQueueEllipsoid
private

Definition at line 139 of file lptcollision.h.

◆ m_collisionModel

template<MInt nDim>
MInt ParticleCollision< nDim >::m_collisionModel = -1
private

Definition at line 37 of file lptcollision.h.

◆ m_domainId

template<MInt nDim>
MInt ParticleCollision< nDim >::m_domainId = -1
private

Definition at line 42 of file lptcollision.h.

◆ m_ellipsoidCCD

template<MInt nDim>
MInt ParticleCollision< nDim >::m_ellipsoidCCD = 1
private

Definition at line 63 of file lptcollision.h.

◆ m_includeEllipsoids

template<MInt nDim>
MBool ParticleCollision< nDim >::m_includeEllipsoids = false
private

Definition at line 64 of file lptcollision.h.

◆ m_lpt

template<MInt nDim>
LPT<nDim>* ParticleCollision< nDim >::m_lpt = nullptr
private

Definition at line 39 of file lptcollision.h.

◆ m_mpiComm

template<MInt nDim>
MPI_Comm ParticleCollision< nDim >::m_mpiComm
private

Definition at line 44 of file lptcollision.h.

◆ m_noDomains

template<MInt nDim>
MInt ParticleCollision< nDim >::m_noDomains = -1
private

Definition at line 43 of file lptcollision.h.

◆ m_noOfSubDomains

template<MInt nDim>
MInt ParticleCollision< nDim >::m_noOfSubDomains[3] {}
private

Definition at line 53 of file lptcollision.h.

◆ m_offset

template<MInt nDim>
MFloat ParticleCollision< nDim >::m_offset = -1000.0
private

Definition at line 62 of file lptcollision.h.

◆ m_outputStep

template<MInt nDim>
MInt ParticleCollision< nDim >::m_outputStep = 50
private

Definition at line 61 of file lptcollision.h.

◆ m_solverId

template<MInt nDim>
MInt ParticleCollision< nDim >::m_solverId = -1
private

Definition at line 41 of file lptcollision.h.

◆ m_subDomainCoordOffset

template<MInt nDim>
MFloat ParticleCollision< nDim >::m_subDomainCoordOffset[3] {}
private

Definition at line 54 of file lptcollision.h.

◆ m_subDomainSize

template<MInt nDim>
MFloat ParticleCollision< nDim >::m_subDomainSize[3] {}
private

Definition at line 55 of file lptcollision.h.

◆ m_timeStep

template<MInt nDim>
MFloat ParticleCollision< nDim >::m_timeStep = -1
private

Definition at line 65 of file lptcollision.h.

◆ m_totalSubDomains

template<MInt nDim>
MInt ParticleCollision< nDim >::m_totalSubDomains = 1
private

Definition at line 56 of file lptcollision.h.

◆ subDomainContent

template<MInt nDim>
maia::lpt::subDomainCollector<nDim>* ParticleCollision< nDim >::subDomainContent
private

Definition at line 58 of file lptcollision.h.

◆ subDomainContentEllipsoid

template<MInt nDim>
maia::lpt::subDomainCollectorEllipsoid<nDim>* ParticleCollision< nDim >::subDomainContentEllipsoid
private

Definition at line 59 of file lptcollision.h.


The documentation for this class was generated from the following files: