PairCollision.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2019-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "PairCollision.H"
30 #include "PairModel.H"
31 #include "WallModel.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
35 template<class CloudType>
37 
38 template<class CloudType>
40  sqrt(3*SMALL);
41 
42 
43 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44 
45 template<class CloudType>
47 {
48  // Set accumulated quantities to zero
49  for (typename CloudType::parcelType& p : this->owner())
50  {
51  p.f() = Zero;
52 
53  p.torque() = Zero;
54  }
55 }
56 
57 
58 template<class CloudType>
60 {
61  PstreamBuffers pBufs(Pstream::commsTypes::nonBlocking);
62 
63  label startOfRequests = Pstream::nRequests();
64 
65  il_.sendReferredData(this->owner().cellOccupancy(), pBufs);
66 
67  realRealInteraction();
68 
69  il_.receiveReferredData(pBufs, startOfRequests);
70 
71  realReferredInteraction();
72 }
73 
74 
75 template<class CloudType>
77 {
78  // Direct interaction list (dil)
79  const labelListList& dil = il_.dil();
80 
81  typename CloudType::parcelType* pA_ptr = nullptr;
82  typename CloudType::parcelType* pB_ptr = nullptr;
83 
84  List<DynamicList<typename CloudType::parcelType*>>& cellOccupancy =
85  this->owner().cellOccupancy();
86 
87  forAll(dil, realCelli)
88  {
89  // Loop over all Parcels in cell A (a)
90  forAll(cellOccupancy[realCelli], a)
91  {
92  pA_ptr = cellOccupancy[realCelli][a];
93 
94  forAll(dil[realCelli], interactingCells)
95  {
96  List<typename CloudType::parcelType*> cellBParcels =
97  cellOccupancy[dil[realCelli][interactingCells]];
98 
99  // Loop over all Parcels in cell B (b)
100  forAll(cellBParcels, b)
101  {
102  pB_ptr = cellBParcels[b];
103 
104  evaluatePair(*pA_ptr, *pB_ptr);
105  }
106  }
107 
108  // Loop over the other Parcels in cell A (aO)
109  forAll(cellOccupancy[realCelli], aO)
110  {
111  pB_ptr = cellOccupancy[realCelli][aO];
112 
113  // Do not double-evaluate, compare pointers, arbitrary
114  // order
115  if (pB_ptr > pA_ptr)
116  {
117  evaluatePair(*pA_ptr, *pB_ptr);
118  }
119  }
120  }
121  }
122 }
123 
124 
125 template<class CloudType>
127 {
128  // Referred interaction list (ril)
129  const labelListList& ril = il_.ril();
130 
131  List<IDLList<typename CloudType::parcelType>>& referredParticles =
132  il_.referredParticles();
133 
134  List<DynamicList<typename CloudType::parcelType*>>& cellOccupancy =
135  this->owner().cellOccupancy();
136 
137  // Loop over all referred cells
138  forAll(ril, refCelli)
139  {
140  IDLList<typename CloudType::parcelType>& refCellRefParticles =
141  referredParticles[refCelli];
142 
143  const labelList& realCells = ril[refCelli];
144 
145  // Loop over all referred parcels in the referred cell
146 
147  for
148  (
149  typename CloudType::parcelType& referredParcel
150  : refCellRefParticles
151  )
152  {
153  // Loop over all real cells in that the referred cell is
154  // to supply interactions to
155 
156  forAll(realCells, realCelli)
157  {
158  List<typename CloudType::parcelType*> realCellParcels =
159  cellOccupancy[realCells[realCelli]];
160 
161  forAll(realCellParcels, realParcelI)
162  {
163  evaluatePair
164  (
165  *realCellParcels[realParcelI],
166  referredParcel
167  );
168  }
169  }
170  }
171  }
172 }
173 
174 
175 template<class CloudType>
177 {
178  const polyMesh& mesh = this->owner().mesh();
179 
180  const labelListList& dil = il_.dil();
181 
182  const labelListList& directWallFaces = il_.dwfil();
183 
184  const labelList& patchID = mesh.boundaryMesh().patchID();
185 
186  const volVectorField& U = mesh.lookupObject<volVectorField>(il_.UName());
187 
188  List<DynamicList<typename CloudType::parcelType*>>& cellOccupancy =
189  this->owner().cellOccupancy();
190 
191  // Storage for the wall interaction sites
192  DynamicList<point> flatSitePoints;
193  DynamicList<scalar> flatSiteExclusionDistancesSqr;
194  DynamicList<WallSiteData<vector>> flatSiteData;
195  DynamicList<point> otherSitePoints;
196  DynamicList<scalar> otherSiteDistances;
197  DynamicList<WallSiteData<vector>> otherSiteData;
198  DynamicList<point> sharpSitePoints;
199  DynamicList<scalar> sharpSiteExclusionDistancesSqr;
200  DynamicList<WallSiteData<vector>> sharpSiteData;
201 
202  forAll(dil, realCelli)
203  {
204  // The real wall faces in range of this real cell
205  const labelList& realWallFaces = directWallFaces[realCelli];
206 
207  // Loop over all Parcels in cell
208  forAll(cellOccupancy[realCelli], cellParticleI)
209  {
210  flatSitePoints.clear();
211  flatSiteExclusionDistancesSqr.clear();
212  flatSiteData.clear();
213  otherSitePoints.clear();
214  otherSiteDistances.clear();
215  otherSiteData.clear();
216  sharpSitePoints.clear();
217  sharpSiteExclusionDistancesSqr.clear();
218  sharpSiteData.clear();
219 
220  typename CloudType::parcelType& p =
221  *cellOccupancy[realCelli][cellParticleI];
222 
223  const point pos(p.position());
224 
225  scalar r = wallModel_->pREff(p);
226 
227  // real wallFace interactions
228 
229  forAll(realWallFaces, realWallFacei)
230  {
231  label realFacei = realWallFaces[realWallFacei];
232 
233  pointHit nearest = mesh.faces()[realFacei].nearestPoint
234  (
235  pos,
236  mesh.points()
237  );
238 
239  if (nearest.distance() < r)
240  {
241  const vector normal =
242  normalised(mesh.faceAreas()[realFacei]);
243 
244  const vector& nearPt = nearest.rawPoint();
245 
246  const vector pW = normalised(nearPt - pos);
247 
248  const scalar normalAlignment = normal & pW;
249 
250  // Find the patchIndex and wallData for WallSiteData object
251  label patchi = patchID[realFacei - mesh.nInternalFaces()];
252 
253  label patchFacei =
254  realFacei - mesh.boundaryMesh()[patchi].start();
255 
256  WallSiteData<vector> wSD
257  (
258  patchi,
259  U.boundaryField()[patchi][patchFacei]
260  );
261 
262  if (normalAlignment > cosPhiMinFlatWall)
263  {
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.
268  if
269  (
270  !duplicatePointInList
271  (
272  flatSitePoints,
273  nearPt,
274  sqr(r*flatWallDuplicateExclusion)
275  )
276  )
277  {
278  flatSitePoints.append(nearPt);
279 
280  flatSiteExclusionDistancesSqr.append
281  (
282  sqr(r) - sqr(nearest.distance())
283  );
284 
285  flatSiteData.append(wSD);
286  }
287  }
288  else
289  {
290  otherSitePoints.append(nearPt);
291 
292  otherSiteDistances.append(nearest.distance());
293 
294  otherSiteData.append(wSD);
295  }
296  }
297  }
298 
299  // referred wallFace interactions
300 
301  // The labels of referred wall faces in range of this real cell
302  const labelList& cellRefWallFaces = il_.rwfilInverse()[realCelli];
303 
304  forAll(cellRefWallFaces, rWFI)
305  {
306  label refWallFacei = cellRefWallFaces[rWFI];
307 
308  const referredWallFace& rwf =
309  il_.referredWallFaces()[refWallFacei];
310 
311  const pointField& pts = rwf.points();
312 
313  pointHit nearest = rwf.nearestPoint(pos, pts);
314 
315  if (nearest.distance() < r)
316  {
317  const vector normal = rwf.unitNormal(pts);
318 
319  const vector& nearPt = nearest.rawPoint();
320 
321  const vector pW = normalised(nearPt - pos);
322 
323  const scalar normalAlignment = normal & pW;
324 
325  // Find the patchIndex and wallData for WallSiteData object
326 
327  WallSiteData<vector> wSD
328  (
329  rwf.patchIndex(),
330  il_.referredWallData()[refWallFacei]
331  );
332 
333  if (normalAlignment > cosPhiMinFlatWall)
334  {
335  // Guard against a flat interaction being
336  // present on the boundary of two or more
337  // faces, which would create duplicate contact
338  // points. Duplicates are discarded.
339  if
340  (
341  !duplicatePointInList
342  (
343  flatSitePoints,
344  nearPt,
345  sqr(r*flatWallDuplicateExclusion)
346  )
347  )
348  {
349  flatSitePoints.append(nearPt);
350 
351  flatSiteExclusionDistancesSqr.append
352  (
353  sqr(r) - sqr(nearest.distance())
354  );
355 
356  flatSiteData.append(wSD);
357  }
358  }
359  else
360  {
361  otherSitePoints.append(nearPt);
362 
363  otherSiteDistances.append(nearest.distance());
364 
365  otherSiteData.append(wSD);
366  }
367  }
368  }
369 
370  // All flat interaction sites found, now classify the
371  // other sites as being in range of a flat interaction, or
372  // a sharp interaction, being aware of not duplicating the
373  // sharp interaction sites.
374 
375  // The "other" sites need to evaluated in order of
376  // ascending distance to their nearest point so that
377  // grouping occurs around the closest in any group
378 
379  labelList sortedOtherSiteIndices
380  (
381  sortedOrder(otherSiteDistances)
382  );
383 
384  for (const label orderedIndex : sortedOtherSiteIndices)
385  {
386  const point& otherPt = otherSitePoints[orderedIndex];
387 
388  if
389  (
390  !duplicatePointInList
391  (
392  flatSitePoints,
393  otherPt,
394  flatSiteExclusionDistancesSqr
395  )
396  )
397  {
398  // Not in range of a flat interaction, must be a
399  // sharp interaction.
400 
401  if
402  (
403  !duplicatePointInList
404  (
405  sharpSitePoints,
406  otherPt,
407  sharpSiteExclusionDistancesSqr
408  )
409  )
410  {
411  sharpSitePoints.append(otherPt);
412 
413  sharpSiteExclusionDistancesSqr.append
414  (
415  sqr(r) - sqr(otherSiteDistances[orderedIndex])
416  );
417 
418  sharpSiteData.append(otherSiteData[orderedIndex]);
419  }
420  }
421  }
422 
423  evaluateWall
424  (
425  p,
426  flatSitePoints,
427  flatSiteData,
428  sharpSitePoints,
429  sharpSiteData
430  );
431  }
432  }
433 }
434 
435 
436 template<class CloudType>
438 (
439  const DynamicList<point>& existingPoints,
440  const point& pointToTest,
441  scalar duplicateRangeSqr
442 ) const
443 {
444  forAll(existingPoints, i)
445  {
446  if (magSqr(existingPoints[i] - pointToTest) < duplicateRangeSqr)
447  {
448  return true;
449  }
450  }
451 
452  return false;
453 }
454 
455 
456 template<class CloudType>
458 (
459  const DynamicList<point>& existingPoints,
460  const point& pointToTest,
461  const scalarList& duplicateRangeSqr
462 ) const
463 {
464  forAll(existingPoints, i)
465  {
466  if (magSqr(existingPoints[i] - pointToTest) < duplicateRangeSqr[i])
467  {
468  return true;
469  }
470  }
471 
472  return false;
473 }
474 
475 
476 template<class CloudType>
478 {
479  // Delete any collision records where no collision occurred this step
480 
481  for (typename CloudType::parcelType& p : this->owner())
482  {
483  p.collisionRecords().update();
484  }
485 }
486 
487 
488 template<class CloudType>
490 (
491  typename CloudType::parcelType& pA,
492  typename CloudType::parcelType& pB
493 ) const
494 {
495  pairModel_->evaluatePair(pA, pB);
496 }
497 
498 
499 template<class CloudType>
501 (
502  typename CloudType::parcelType& p,
503  const List<point>& flatSitePoints,
504  const List<WallSiteData<vector>>& flatSiteData,
505  const List<point>& sharpSitePoints,
506  const List<WallSiteData<vector>>& sharpSiteData
507 ) const
508 {
509  wallModel_->evaluateWall
510  (
511  p,
512  flatSitePoints,
513  flatSiteData,
514  sharpSitePoints,
515  sharpSiteData
516  );
517 }
518 
519 
520 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
521 
522 template<class CloudType>
524 (
525  const dictionary& dict,
526  CloudType& owner
527 )
528 :
529  CollisionModel<CloudType>(dict, owner, typeName),
530  pairModel_
531  (
533  (
534  this->coeffDict(),
535  this->owner()
536  )
537  ),
538  wallModel_
539  (
541  (
542  this->coeffDict(),
543  this->owner()
544  )
545  ),
546  il_
547  (
548  owner.mesh(),
549  this->coeffDict().getScalar("maxInteractionDistance"),
550  this->coeffDict().getOrDefault
551  (
552  "writeReferredParticleCloud",
553  false
554  ),
555  this->coeffDict().template getOrDefault<word>("U", "U")
556  )
557 {}
558 
559 
560 template<class CloudType>
562 (
563  const PairCollision<CloudType>& cm
564 )
565 :
567  pairModel_(nullptr),
568  wallModel_(nullptr),
569  il_(cm.owner().mesh())
570 {
571  // Need to clone to PairModel and WallModel
573 }
574 
575 
576 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
577 
578 template<class CloudType>
580 {}
581 
582 
583 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
584 
585 template<class CloudType>
587 {
588  label nSubCycles = 1;
589 
590  if (pairModel_->controlsTimestep())
591  {
592  label nPairSubCycles = returnReduce
593  (
594  pairModel_->nSubCycles(), maxOp<label>()
595  );
596 
597  nSubCycles = max(nSubCycles, nPairSubCycles);
598  }
599 
600  if (wallModel_->controlsTimestep())
601  {
602  label nWallSubCycles = returnReduce
603  (
604  wallModel_->nSubCycles(), maxOp<label>()
605  );
606 
607  nSubCycles = max(nSubCycles, nWallSubCycles);
608  }
609 
610  return nSubCycles;
611 }
612 
613 
614 template<class CloudType>
616 {
617  preInteraction();
618 
619  parcelInteraction();
620 
621  wallInteraction();
622 
623  postInteraction();
624 }
625 
626 
627 // ************************************************************************* //
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::pointField
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
Foam::maxOp
Definition: ops.H:223
Foam::scalarList
List< scalar > scalarList
A List of scalars.
Definition: scalarList.H:64
p
volScalarField & p
Definition: createFieldRefs.H:8
WallModel.H
Foam::returnReduce
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
Definition: PstreamReduceOps.H:94
Foam::dictionary::getScalar
scalar getScalar(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Same as get< scalar >(const word&, keyType::option)
Definition: dictionary.H:1512
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::PairCollision::nSubCycles
virtual label nSubCycles() const
Return the number of times to subcycle the current.
Definition: PairCollision.C:586
Foam::PairCollision
Definition: PairCollision.H:64
Foam::PairCollision::collide
virtual void collide()
Definition: PairCollision.C:615
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
Foam::magSqr
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
PairCollision.H
NotImplemented
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:517
Foam::constant::physicoChemical::b
const dimensionedScalar b
Wien displacement law constant: default SI units: [m.K].
Definition: createFields.H:27
cellOccupancy
const List< DynamicList< molecule * > > & cellOccupancy
Definition: calculateMDFields.H:1
Foam::DSMCCloud::mesh
const fvMesh & mesh() const
Return reference to the mesh.
Definition: DSMCCloudI.H:44
patchID
label patchID
Definition: boundaryProcessorFaPatchPoints.H:5
Foam::max
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
Foam::DSMCCloud
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:71
Foam::DSMCCloud::cellOccupancy
const List< DynamicList< ParcelType * > > & cellOccupancy() const
Return the cell occupancy addressing.
Definition: DSMCCloudI.H:75
Foam::PairCollision::~PairCollision
virtual ~PairCollision()
Destructor.
Definition: PairCollision.C:579
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
Foam::pointHit
PointHit< point > pointHit
A PointIndexHit for 3D points.
Definition: pointHit.H:44
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::WallModel
Templated wall interaction class.
Definition: PairCollision.H:56
Foam::normalised
VectorSpace< Form, Cmpt, Ncmpts > normalised(const VectorSpace< Form, Cmpt, Ncmpts > &vs)
Definition: VectorSpaceI.H:487
Foam::volVectorField
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:62
Foam::labelListList
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
U
U
Definition: pEqn.H:72
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:51
Foam::PairCollision::PairCollision
PairCollision(const dictionary &dict, CloudType &owner)
Construct from components.
Definition: PairCollision.C:524
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::PairModel
Templated pair interaction class.
Definition: PairCollision.H:53
Foam::sortedOrder
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
Foam::point
vector point
Point is a vector.
Definition: point.H:43
PairModel.H
Foam::CollisionModel
Templated collision model class.
Definition: CollidingCloud.H:58
Foam::pos
dimensionedScalar pos(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:177