1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
26 #include "PairCollision.H"
27 #include "PairModel.H"
28 #include "WallModel.H"
30 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
32 template<class CloudType>
33 Foam::scalar Foam::PairCollision<CloudType>::cosPhiMinFlatWall = 1 - SMALL;
35 template<class CloudType>
36 Foam::scalar Foam::PairCollision<CloudType>::flatWallDuplicateExclusion =
40 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
42 template<class CloudType>
43 void Foam::PairCollision<CloudType>::preInteraction()
45 // Set accumulated quantities to zero
46 forAllIter(typename CloudType, this->owner(), iter)
48 typename CloudType::parcelType& p = iter();
52 p.torque() = vector::zero;
57 template<class CloudType>
58 void Foam::PairCollision<CloudType>::parcelInteraction()
60 PstreamBuffers pBufs(Pstream::nonBlocking);
62 il_.sendReferredData(this->owner().cellOccupancy(), pBufs);
64 realRealInteraction();
66 il_.receiveReferredData(pBufs);
68 realReferredInteraction();
72 template<class CloudType>
73 void Foam::PairCollision<CloudType>::realRealInteraction()
75 // Direct interaction list (dil)
76 const labelListList& dil = il_.dil();
78 typename CloudType::parcelType* pA_ptr = NULL;
79 typename CloudType::parcelType* pB_ptr = NULL;
81 List<DynamicList<typename CloudType::parcelType*> >& cellOccupancy =
82 this->owner().cellOccupancy();
84 forAll(dil, realCellI)
86 // Loop over all Parcels in cell A (a)
87 forAll(cellOccupancy[realCellI], a)
89 pA_ptr = cellOccupancy[realCellI][a];
91 forAll(dil[realCellI], interactingCells)
93 List<typename CloudType::parcelType*> cellBParcels =
94 cellOccupancy[dil[realCellI][interactingCells]];
96 // Loop over all Parcels in cell B (b)
97 forAll(cellBParcels, b)
99 pB_ptr = cellBParcels[b];
101 evaluatePair(*pA_ptr, *pB_ptr);
105 // Loop over the other Parcels in cell A (aO)
106 forAll(cellOccupancy[realCellI], aO)
108 pB_ptr = cellOccupancy[realCellI][aO];
110 // Do not double-evaluate, compare pointers, arbitrary
114 evaluatePair(*pA_ptr, *pB_ptr);
122 template<class CloudType>
123 void Foam::PairCollision<CloudType>::realReferredInteraction()
125 // Referred interaction list (ril)
126 const labelListList& ril = il_.ril();
128 List<IDLList<typename CloudType::parcelType> >& referredParticles =
129 il_.referredParticles();
131 List<DynamicList<typename CloudType::parcelType*> >& cellOccupancy =
132 this->owner().cellOccupancy();
134 // Loop over all referred cells
135 forAll(ril, refCellI)
137 IDLList<typename CloudType::parcelType>& refCellRefParticles =
138 referredParticles[refCellI];
140 const labelList& realCells = ril[refCellI];
142 // Loop over all referred parcels in the referred cell
146 typename IDLList<typename CloudType::parcelType>,
151 // Loop over all real cells in that the referred cell is
152 // to supply interactions to
154 forAll(realCells, realCellI)
156 List<typename CloudType::parcelType*> realCellParcels =
157 cellOccupancy[realCells[realCellI]];
159 forAll(realCellParcels, realParcelI)
163 *realCellParcels[realParcelI],
173 template<class CloudType>
174 void Foam::PairCollision<CloudType>::wallInteraction()
176 const polyMesh& mesh = this->owner().mesh();
178 const labelListList& dil = il_.dil();
180 const labelListList directWallFaces = il_.dwfil();
182 const labelList& patchID = mesh.boundaryMesh().patchID();
184 const volVectorField& U = mesh.lookupObject<volVectorField>(il_.UName());
186 List<DynamicList<typename CloudType::parcelType*> >& cellOccupancy =
187 this->owner().cellOccupancy();
189 // Storage for the wall interaction sites
190 DynamicList<point> flatSitePoints;
191 DynamicList<scalar> flatSiteExclusionDistancesSqr;
192 DynamicList<WallSiteData<vector> > flatSiteData;
193 DynamicList<point> otherSitePoints;
194 DynamicList<scalar> otherSiteDistances;
195 DynamicList<WallSiteData<vector> > otherSiteData;
196 DynamicList<point> sharpSitePoints;
197 DynamicList<scalar> sharpSiteExclusionDistancesSqr;
198 DynamicList<WallSiteData<vector> > sharpSiteData;
200 forAll(dil, realCellI)
202 // The real wall faces in range of this real cell
203 const labelList& realWallFaces = directWallFaces[realCellI];
205 // Loop over all Parcels in cell
206 forAll(cellOccupancy[realCellI], cellParticleI)
208 flatSitePoints.clear();
209 flatSiteExclusionDistancesSqr.clear();
210 flatSiteData.clear();
211 otherSitePoints.clear();
212 otherSiteDistances.clear();
213 otherSiteData.clear();
214 sharpSitePoints.clear();
215 sharpSiteExclusionDistancesSqr.clear();
216 sharpSiteData.clear();
218 typename CloudType::parcelType& p =
219 *cellOccupancy[realCellI][cellParticleI];
221 const point& pos = p.position();
223 scalar r = wallModel_->pREff(p);
225 // real wallFace interactions
227 forAll(realWallFaces, realWallFaceI)
229 label realFaceI = realWallFaces[realWallFaceI];
231 pointHit nearest = mesh.faces()[realFaceI].nearestPoint
237 if (nearest.distance() < r)
239 vector normal = mesh.faceAreas()[realFaceI];
241 normal /= mag(normal);
243 const vector& nearPt = nearest.rawPoint();
245 vector pW = nearPt - pos;
247 scalar normalAlignment = normal & pW/mag(pW);
249 // Find the patchIndex and wallData for WallSiteData object
250 label patchI = patchID[realFaceI - mesh.nInternalFaces()];
253 realFaceI - mesh.boundaryMesh()[patchI].start();
255 WallSiteData<vector> wSD
258 U.boundaryField()[patchI][patchFaceI]
261 bool particleHit = false;
262 if (normalAlignment > cosPhiMinFlatWall)
264 // Guard against a flat interaction being
265 // present on the boundary of two or more
266 // faces, which would create duplicate contact
267 // points. Duplicates are discarded.
270 !duplicatePointInList
274 sqr(r*flatWallDuplicateExclusion)
278 flatSitePoints.append(nearPt);
280 flatSiteExclusionDistancesSqr.append
282 sqr(r) - sqr(nearest.distance())
285 flatSiteData.append(wSD);
292 otherSitePoints.append(nearPt);
294 otherSiteDistances.append(nearest.distance());
296 otherSiteData.append(wSD);
303 this->owner().functions().postFace(p, realFaceI);
304 this->owner().functions().postPatch
314 // referred wallFace interactions
316 // The labels of referred wall faces in range of this real cell
317 const labelList& cellRefWallFaces = il_.rwfilInverse()[realCellI];
321 forAll(cellRefWallFaces, rWFI)
323 label refWallFaceI = cellRefWallFaces[rWFI];
325 const referredWallFace& rwf =
326 il_.referredWallFaces()[refWallFaceI];
328 const pointField& pts = rwf.points();
330 pointHit nearest = rwf.nearestPoint(pos, pts);
332 if (nearest.distance() < r)
334 vector normal = rwf.normal(pts);
336 normal /= mag(normal);
338 const vector& nearPt = nearest.rawPoint();
340 vector pW = nearPt - pos;
342 scalar normalAlignment = normal & pW/mag(pW);
344 // Find the patchIndex and wallData for WallSiteData object
346 WallSiteData<vector> wSD
349 il_.referredWallData()[refWallFaceI]
352 bool particleHit = false;
353 if (normalAlignment > cosPhiMinFlatWall)
355 // Guard against a flat interaction being
356 // present on the boundary of two or more
357 // faces, which would create duplicate contact
358 // points. Duplicates are discarded.
361 !duplicatePointInList
365 sqr(r*flatWallDuplicateExclusion)
369 flatSitePoints.append(nearPt);
371 flatSiteExclusionDistancesSqr.append
373 sqr(r) - sqr(nearest.distance())
376 flatSiteData.append(wSD);
383 otherSitePoints.append(nearPt);
385 otherSiteDistances.append(nearest.distance());
387 otherSiteData.append(wSD);
394 // TODO: call cloud function objects for referred
395 // wall particle interactions
400 // All flat interaction sites found, now classify the
401 // other sites as being in range of a flat interaction, or
402 // a sharp interaction, being aware of not duplicating the
403 // sharp interaction sites.
405 // The "other" sites need to evaluated in order of
406 // ascending distance to their nearest point so that
407 // grouping occurs around the closest in any group
409 labelList sortedOtherSiteIndices;
411 sortedOrder(otherSiteDistances, sortedOtherSiteIndices);
413 forAll(sortedOtherSiteIndices, siteI)
415 label orderedIndex = sortedOtherSiteIndices[siteI];
417 const point& otherPt = otherSitePoints[orderedIndex];
421 !duplicatePointInList
425 flatSiteExclusionDistancesSqr
429 // Not in range of a flat interaction, must be a
430 // sharp interaction.
434 !duplicatePointInList
438 sharpSiteExclusionDistancesSqr
442 sharpSitePoints.append(otherPt);
444 sharpSiteExclusionDistancesSqr.append
446 sqr(r) - sqr(otherSiteDistances[orderedIndex])
449 sharpSiteData.append(otherSiteData[orderedIndex]);
467 template<class CloudType>
468 bool Foam::PairCollision<CloudType>::duplicatePointInList
470 const DynamicList<point>& existingPoints,
471 const point& pointToTest,
472 scalar duplicateRangeSqr
475 forAll(existingPoints, i)
477 if (magSqr(existingPoints[i] - pointToTest) < duplicateRangeSqr)
487 template<class CloudType>
488 bool Foam::PairCollision<CloudType>::duplicatePointInList
490 const DynamicList<point>& existingPoints,
491 const point& pointToTest,
492 const scalarList& duplicateRangeSqr
495 forAll(existingPoints, i)
497 if (magSqr(existingPoints[i] - pointToTest) < duplicateRangeSqr[i])
507 template<class CloudType>
508 void Foam::PairCollision<CloudType>::postInteraction()
510 // Delete any collision records where no collision occurred this step
512 forAllIter(typename CloudType, this->owner(), iter)
514 typename CloudType::parcelType& p = iter();
516 p.collisionRecords().update();
521 template<class CloudType>
522 void Foam::PairCollision<CloudType>::evaluatePair
524 typename CloudType::parcelType& pA,
525 typename CloudType::parcelType& pB
528 pairModel_->evaluatePair(pA, pB);
532 template<class CloudType>
533 void Foam::PairCollision<CloudType>::evaluateWall
535 typename CloudType::parcelType& p,
536 const List<point>& flatSitePoints,
537 const List<WallSiteData<vector> >& flatSiteData,
538 const List<point>& sharpSitePoints,
539 const List<WallSiteData<vector> >& sharpSiteData
542 wallModel_->evaluateWall
553 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
555 template<class CloudType>
556 Foam::PairCollision<CloudType>::PairCollision
558 const dictionary& dict,
562 CollisionModel<CloudType>(dict, owner, typeName),
565 PairModel<CloudType>::New
573 WallModel<CloudType>::New
582 readScalar(this->coeffDict().lookup("maxInteractionDistance")),
585 this->coeffDict().lookupOrDefault
587 "writeReferredParticleCloud",
591 this->coeffDict().lookupOrDefault("UName", word("U"))
596 template<class CloudType>
597 Foam::PairCollision<CloudType>::PairCollision(PairCollision<CloudType>& cm)
599 CollisionModel<CloudType>(cm),
602 il_(cm.owner().mesh())
606 "Foam::PairCollision<CloudType>::PairCollision"
608 "PairCollision<CloudType>& cm"
614 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
616 template<class CloudType>
617 Foam::PairCollision<CloudType>::~PairCollision()
621 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
623 template<class CloudType>
624 Foam::label Foam::PairCollision<CloudType>::nSubCycles() const
626 label nSubCycles = 1;
628 if (pairModel_->controlsTimestep())
630 label nPairSubCycles = returnReduce
632 pairModel_->nSubCycles(), maxOp<label>()
635 nSubCycles = max(nSubCycles, nPairSubCycles);
638 if (wallModel_->controlsTimestep())
640 label nWallSubCycles = returnReduce
642 wallModel_->nSubCycles(), maxOp<label>()
645 nSubCycles = max(nSubCycles, nWallSubCycles);
652 template<class CloudType>
653 bool Foam::PairCollision<CloudType>::controlsWallInteraction() const
659 template<class CloudType>
660 void Foam::PairCollision<CloudType>::collide()
672 // ************************************************************************* //