From b76178bd16875f7b183eb131d4ff24691539905e Mon Sep 17 00:00:00 2001 From: andy <andy> Date: Tue, 18 Sep 2012 16:38:59 +0100 Subject: [PATCH] ENH: Corrected cloud penetration for parallel cases --- .../KinematicCloud/KinematicCloudI.H | 165 ++++++++++-------- 1 file changed, 95 insertions(+), 70 deletions(-) diff --git a/src/lagrangian/intermediate/clouds/Templates/KinematicCloud/KinematicCloudI.H b/src/lagrangian/intermediate/clouds/Templates/KinematicCloud/KinematicCloudI.H index a6bdf47cc46..87b9136a4ec 100644 --- a/src/lagrangian/intermediate/clouds/Templates/KinematicCloud/KinematicCloudI.H +++ b/src/lagrangian/intermediate/clouds/Templates/KinematicCloud/KinematicCloudI.H @@ -24,6 +24,7 @@ License \*---------------------------------------------------------------------------*/ #include "fvmSup.H" +#include "SortableList.H" // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // @@ -343,99 +344,123 @@ inline Foam::scalar Foam::KinematicCloud<CloudType>::Dmax() const template<class CloudType> inline Foam::scalar Foam::KinematicCloud<CloudType>::penetration ( - const scalar& prc + const scalar& fraction ) const { - scalar distance = 0.0; - scalar mTot = 0.0; + if ((fraction < 0) || (fraction > 1)) + { + FatalErrorIn + ( + "inline Foam::scalar Foam::KinematicCloud<CloudType>::penetration" + "(" + "const scalar&" + ") const" + ) + << "fraction should be in the range 0 < fraction < 1" + << exit(FatalError); + } - label np = this->size(); + scalar distance = 0.0; - // arrays containing the parcels mass and - // distance from injector in ascending order - scalarField mass(np); - scalarField dist(np); + const label nParcel = this->size(); + globalIndex globalParcels(nParcel); + const label nParcelSum = globalParcels.size(); - if (np > 0) + if (nParcelSum == 0) { - label n = 0; + return distance; + } - // first arrange the parcels in ascending order - // the first parcel is closest to its injection position - // and the last one is most far away. - forAllConstIter(typename KinematicCloud<CloudType>, *this, iter) - { - const parcelType& p = iter(); - scalar mi = p.nParticle()*p.mass(); - scalar di = mag(p.position() - p.position0()); - mTot += mi; + // lists of parcels mass and distance from initial injection point + List<scalar> mass(nParcel, 0.0); + List<scalar> dist(nParcel, 0.0); - // insert at the last place - mass[n] = mi; - dist[n] = di; + label i = 0; + scalar mSum = 0.0; + forAllConstIter(typename KinematicCloud<CloudType>, *this, iter) + { + const parcelType& p = iter(); + scalar m = p.nParticle()*p.mass(); + scalar d = mag(p.position() - p.position0()); + mSum += m; - label i = 0; - bool found = false; + mass[i] = m; + dist[i] = d; - // insert the parcel in the correct place - // and move the others - while ((i < n) && (!found)) - { - if (di < dist[i]) - { - found = true; - for (label j=n; j>i; j--) - { - mass[j] = mass[j-1]; - dist[j] = dist[j-1]; - } - mass[i] = mi; - dist[i] = di; - } - i++; - } - n++; - } + i++; } - reduce(mTot, sumOp<scalar>()); + // calculate total mass across all processors + reduce(mSum, sumOp<scalar>()); + + // flatten the mass list + List<scalar> allMass(nParcelSum, 0.0); + SubList<scalar> + ( + allMass, + globalParcels.localSize(Pstream::myProcNo()), + globalParcels.offset(Pstream::myProcNo()) + ).assign(mass); + + // flatten the distance list + SortableList<scalar> allDist(nParcelSum, 0.0); + SubList<scalar> + ( + allDist, + globalParcels.localSize(Pstream::myProcNo()), + globalParcels.offset(Pstream::myProcNo()) + ).assign(dist); + + // sort allDist distances into ascending order + // note: allMass masses are left unsorted + allDist.sort(); - if (np > 0) + if (nParcelSum > 1) { - scalar mLimit = prc*mTot; - scalar mOff = (1.0 - prc)*mTot; + const scalar mLimit = fraction*mSum; + const labelList& indices = allDist.indices(); - if (np > 1) + if (mLimit > (mSum - allMass[indices.last()])) { - // 'prc' is large enough that the parcel most far - // away will be used, no need to loop... - if (mLimit > mTot - mass[np-1]) - { - distance = dist[np-1]; - } - else + distance = allDist.last(); + } + else + { + // assuming that 'fraction' is generally closer to 1 than 0, loop + // through in reverse distance order + const scalar mThreshold = (1.0 - fraction)*mSum; + scalar mCurrent = 0.0; + label i0 = 0; + + forAllReverse(indices, i) { - scalar mOffSum = 0.0; - label i = np; + label indI = indices[i]; + + mCurrent += allMass[indI]; - while ((mOffSum < mOff) && (i>0)) + if (mCurrent > mThreshold) { - i--; - mOffSum += mass[i]; + i0 = i; + break; } - distance = - dist[i+1] - + (dist[i] - dist[i+1])*(mOffSum - mOff) - /mass[i+1] ; } - } - else - { - distance = dist[0]; + + if (i0 == indices.size() - 1) + { + distance = allDist.last(); + } + else + { + // linearly interpolate to determine distance + scalar alpha = (mCurrent - mThreshold)/allMass[indices[i0]]; + distance = allDist[i0] + alpha*(allDist[i0+1] - allDist[i0]); + } } } - - reduce(distance, maxOp<scalar>()); + else + { + distance = allDist.first(); + } return distance; } -- GitLab