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-------------------------------------------------------------------------------
11License
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
35template<class CloudType>
37
38template<class CloudType>
40 sqrt(3*SMALL);
41
42
43// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
44
45template<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
58template<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
75template<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
125template<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
175template<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
436template<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
456template<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
476template<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
488template<class CloudType>
490(
491 typename CloudType::parcelType& pA,
492 typename CloudType::parcelType& pB
493) const
494{
495 pairModel_->evaluatePair(pA, pB);
496}
497
498
499template<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
522template<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
560template<class CloudType>
562(
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
578template<class CloudType>
580{}
581
582
583// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
584
585template<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
614template<class CloudType>
616{
617 preInteraction();
618
619 parcelInteraction();
620
621 wallInteraction();
622
623 postInteraction();
624}
625
626
627// ************************************************************************* //
const List< DynamicList< molecule * > > & cellOccupancy
Templated collision model class.
Templated base class for dsmc cloud.
Definition: DSMCCloud.H:75
virtual label nSubCycles() const
Return the number of times to subcycle the current.
virtual ~PairCollision()
Destructor.
virtual void collide()
Templated pair interaction class.
Definition: PairModel.H:56
Templated wall interaction class.
Definition: WallModel.H:56
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
A class for handling words, derived from Foam::string.
Definition: word.H:68
U
Definition: pEqn.H:72
volScalarField & p
dynamicFvMesh & mesh
#define NotImplemented
Issue a FatalErrorIn for a function not currently implemented.
Definition: error.H:517
dimensionedScalar pos(const dimensionedScalar &ds)
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:47
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:83
List< label > labelList
A List of labels.
Definition: List.H:66
dimensionedSymmTensor sqr(const dimensionedVector &dv)
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:680
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:44
vector point
Point is a vector.
Definition: point.H:43
dimensionedScalar sqrt(const dimensionedScalar &ds)
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
PointHit< point > pointHit
A PointIndexHit for 3D points.
Definition: pointHit.H:44
tmp< DimensionedField< TypeR, GeoMesh > > New(const tmp< DimensionedField< TypeR, GeoMesh > > &tdf1, const word &name, const dimensionSet &dimensions)
Global function forwards to reuseTmpDimensionedField::New.
T returnReduce(const T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce (copy) and return value.
dimensioned< typename typeOfMag< Type >::type > magSqr(const dimensioned< Type > &dt)
dictionary dict
volScalarField & b
Definition: createFields.H:27
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333