InteractionLists.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-2022 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 "InteractionLists.H"
31#include "indexedOctree.H"
32#include "treeDataFace.H"
33#include "treeDataCell.H"
34#include "volFields.H"
35#include "meshTools.H"
36
37// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
38
39template<class ParticleType>
41{
42 Info<< "Building InteractionLists with interaction distance "
43 << maxDistance_ << endl;
44
45 Random rndGen(419715);
46
47 const vector interactionVec = maxDistance_*vector::one;
48
49 treeBoundBox procBb(treeBoundBox(mesh_.points()));
50
51 treeBoundBox extendedProcBb
52 (
53 procBb.min() - interactionVec,
54 procBb.max() + interactionVec
55 );
56
57 treeBoundBoxList allExtendedProcBbs(Pstream::nProcs());
58
59 allExtendedProcBbs[Pstream::myProcNo()] = extendedProcBb;
60
61 Pstream::allGatherList(allExtendedProcBbs);
62
63 List<treeBoundBox> extendedProcBbsInRange;
64 List<label> extendedProcBbsTransformIndex;
65 List<label> extendedProcBbsOrigProc;
66
67 findExtendedProcBbsInRange
68 (
69 procBb,
70 allExtendedProcBbs,
71 mesh_.globalData().globalTransforms(),
72 extendedProcBbsInRange,
73 extendedProcBbsTransformIndex,
74 extendedProcBbsOrigProc
75 );
76
77 treeBoundBoxList cellBbs(mesh_.nCells());
78
79 forAll(cellBbs, celli)
80 {
81 cellBbs[celli] = treeBoundBox
82 (
83 mesh_.cells()[celli].points
84 (
85 mesh_.faces(),
86 mesh_.points()
87 )
88 );
89 }
90
91 const globalIndexAndTransform& globalTransforms =
92 mesh_.globalData().globalTransforms();
93
94 // Recording which cells are in range of an extended boundBox, as
95 // only these cells will need to be tested to determine which
96 // referred cells that they interact with.
97 bitSet cellInRangeOfCoupledPatch(mesh_.nCells(), false);
98
99 // IAndT: index (=local cell index) and transform (from
100 // globalIndexAndTransform)
101 DynamicList<labelPair> cellIAndTToExchange;
102
103 DynamicList<treeBoundBox> cellBbsToExchange;
104
105 DynamicList<label> procToDistributeCellTo;
106
107 forAll(extendedProcBbsInRange, ePBIRI)
108 {
109 const treeBoundBox& otherExtendedProcBb =
110 extendedProcBbsInRange[ePBIRI];
111
112 label transformIndex = extendedProcBbsTransformIndex[ePBIRI];
113
114 label origProc = extendedProcBbsOrigProc[ePBIRI];
115
116 forAll(cellBbs, celli)
117 {
118 const treeBoundBox& cellBb = cellBbs[celli];
119
120 if (cellBb.overlaps(otherExtendedProcBb))
121 {
122 // This cell is in range of the Bb of the other
123 // processor Bb, and so needs to be referred to it
124
125 cellInRangeOfCoupledPatch.set(celli);
126
127 cellIAndTToExchange.append
128 (
129 globalTransforms.encode(celli, transformIndex)
130 );
131
132 cellBbsToExchange.append(cellBb);
133
134 procToDistributeCellTo.append(origProc);
135 }
136 }
137 }
138
139 buildMap(cellMapPtr_, procToDistributeCellTo);
140
141 // Needed for reverseDistribute
142 label preDistributionCellMapSize = procToDistributeCellTo.size();
143
144 cellMap().distribute(cellBbsToExchange);
145
146 cellMap().distribute(cellIAndTToExchange);
147
148 // Determine labelList specifying only cells that are in range of
149 // a coupled boundary to build an octree limited to these cells.
150 DynamicList<label> coupledPatchRangeCells;
151
152 forAll(cellInRangeOfCoupledPatch, celli)
153 {
154 if (cellInRangeOfCoupledPatch[celli])
155 {
156 coupledPatchRangeCells.append(celli);
157 }
158 }
159
160 treeBoundBox procBbRndExt
161 (
162 treeBoundBox(mesh_.points()).extend(rndGen, 1e-4)
163 );
164
165 indexedOctree<treeDataCell> coupledPatchRangeTree
166 (
167 treeDataCell
168 (
169 true, // Cache cell bb
170 mesh_,
171 coupledPatchRangeCells, // Subset of mesh
172 polyMesh::CELL_TETS // Consistent with tracking
173 ),
174 procBbRndExt,
175 8, // maxLevel,
176 10, // leafSize,
177 100.0 // duplicity
178 );
179
180 ril_.setSize(cellBbsToExchange.size());
181
182 // This needs to be a boolList, not bitSet if
183 // reverseDistribute is called.
184 boolList cellBbRequiredByAnyCell(cellBbsToExchange.size(), false);
185
186 Info<< " Building referred interaction lists" << endl;
187
188 forAll(cellBbsToExchange, bbI)
189 {
190 const labelPair& ciat = cellIAndTToExchange[bbI];
191
192 const vectorTensorTransform& transform = globalTransforms.transform
193 (
194 globalTransforms.transformIndex(ciat)
195 );
196
197 treeBoundBox tempTransformedBb
198 (
199 transform.invTransformPosition(cellBbsToExchange[bbI].points())
200 );
201
202 treeBoundBox extendedBb
203 (
204 tempTransformedBb.min() - interactionVec,
205 tempTransformedBb.max() + interactionVec
206 );
207
208 // Find all elements intersecting box.
209 labelList interactingElems
210 (
211 coupledPatchRangeTree.findBox(extendedBb)
212 );
213
214 if (!interactingElems.empty())
215 {
216 cellBbRequiredByAnyCell[bbI] = true;
217 }
219 ril_[bbI].setSize(interactingElems.size(), -1);
220
221 forAll(interactingElems, i)
222 {
223 label elemI = interactingElems[i];
224
225 // Here, a more detailed geometric test could be applied,
226 // i.e. a more accurate bounding volume like a OBB or
227 // convex hull or an exact geometrical test.
229 label c = coupledPatchRangeTree.shapes().cellLabels()[elemI];
230
231 ril_[bbI][i] = c;
232 }
233 }
234
235 // Perform subset of ril_, to remove any referred cells that do
236 // not interact. They will not be sent from originating
237 // processors. This assumes that the disappearance of the cell
238 // from the sending list of the source processor, simply removes
239 // the referred cell from the ril_, all of the subsequent indices
240 // shuffle down one, but the order and structure is preserved,
241 // i.e. it, is as if the cell had never been referred in the first
242 // place.
243
244 inplaceSubset(cellBbRequiredByAnyCell, ril_);
245
246 // Send information about which cells are actually required back
247 // to originating processors.
248
249 // At this point, cellBbsToExchange does not need to be maintained
250 // or distributed as it is not longer needed.
251
252 cellBbsToExchange.setSize(0);
253
254 cellMap().reverseDistribute
255 (
256 preDistributionCellMapSize,
257 cellBbRequiredByAnyCell
258 );
259
260 cellMap().reverseDistribute
261 (
262 preDistributionCellMapSize,
263 cellIAndTToExchange
264 );
265
266 // Perform ordering of cells to send, this invalidates the
267 // previous value of preDistributionCellMapSize.
268
269 preDistributionCellMapSize = -1;
270
271 // Move all of the used cells to refer to the start of the list
272 // and truncate it
273
274 inplaceSubset(cellBbRequiredByAnyCell, cellIAndTToExchange);
275
276 inplaceSubset(cellBbRequiredByAnyCell, procToDistributeCellTo);
277
278 preDistributionCellMapSize = procToDistributeCellTo.size();
279
280 // Rebuild mapDistribute with only required referred cells
281 buildMap(cellMapPtr_, procToDistributeCellTo);
282
283 // Store cellIndexAndTransformToDistribute
284 cellIndexAndTransformToDistribute_.transfer(cellIAndTToExchange);
285
286 // Determine inverse addressing for referred cells
287
288 rilInverse_.setSize(mesh_.nCells());
289
290 // Temporary Dynamic lists for accumulation
291 List<DynamicList<label>> rilInverseTemp(rilInverse_.size());
292
293 // Loop over all referred cells
294 forAll(ril_, refCelli)
295 {
296 const labelList& realCells = ril_[refCelli];
297
298 // Loop over all real cells in that the referred cell is to
299 // supply interactions to and record the index of this
300 // referred cell in the real cells entry in rilInverse
301
302 forAll(realCells, realCelli)
303 {
304 rilInverseTemp[realCells[realCelli]].append(refCelli);
305 }
306 }
307
308 forAll(rilInverse_, celli)
309 {
310 rilInverse_[celli].transfer(rilInverseTemp[celli]);
311 }
312
313 // Determine which wall faces to refer
314
315 // The referring of wall patch data relies on patches having the same
316 // index on each processor.
317 mesh_.boundaryMesh().checkParallelSync(true);
318
319 // Determine the index of all of the wall faces on this processor
320 DynamicList<label> localWallFaces;
321
322 for (const polyPatch& patch : mesh_.boundaryMesh())
323 {
324 if (isA<wallPolyPatch>(patch))
325 {
326 const scalarField areaFraction(patch.areaFraction());
327
328 forAll(areaFraction, facei)
329 {
330 if (areaFraction[facei] > 0.5)
331 {
332 localWallFaces.append(facei + patch.start());
333 }
334 }
335 }
336 }
337
338 treeBoundBoxList wallFaceBbs(localWallFaces.size());
339
340 forAll(wallFaceBbs, i)
341 {
342 wallFaceBbs[i] =
343 treeBoundBox
344 (
345 mesh_.points(),
346 mesh_.faces()[localWallFaces[i]]
347 );
348 }
349
350 // IAndT: index and transform
351 DynamicList<labelPair> wallFaceIAndTToExchange;
352
353 DynamicList<treeBoundBox> wallFaceBbsToExchange;
354
355 DynamicList<label> procToDistributeWallFaceTo;
356
357 forAll(extendedProcBbsInRange, ePBIRI)
358 {
359 const treeBoundBox& otherExtendedProcBb =
360 extendedProcBbsInRange[ePBIRI];
361
362 label transformIndex = extendedProcBbsTransformIndex[ePBIRI];
363
364 label origProc = extendedProcBbsOrigProc[ePBIRI];
365
366 forAll(wallFaceBbs, i)
367 {
368 const treeBoundBox& wallFaceBb = wallFaceBbs[i];
369
370 if (wallFaceBb.overlaps(otherExtendedProcBb))
371 {
372 // This wall face is in range of the Bb of the other
373 // processor Bb, and so needs to be referred to it
374
375 label wallFacei = localWallFaces[i];
376
377 wallFaceIAndTToExchange.append
378 (
379 globalTransforms.encode(wallFacei, transformIndex)
380 );
381
382 wallFaceBbsToExchange.append(wallFaceBb);
383
384 procToDistributeWallFaceTo.append(origProc);
385 }
386 }
387 }
388
389 buildMap(wallFaceMapPtr_, procToDistributeWallFaceTo);
390
391 // Needed for reverseDistribute
392 label preDistributionWallFaceMapSize = procToDistributeWallFaceTo.size();
393
394 wallFaceMap().distribute(wallFaceBbsToExchange);
395
396 wallFaceMap().distribute(wallFaceIAndTToExchange);
397
398 indexedOctree<treeDataCell> allCellsTree
399 (
400 treeDataCell(true, mesh_, polyMesh::CELL_TETS),
401 procBbRndExt,
402 8, // maxLevel,
403 10, // leafSize,
404 100.0 // duplicity
405 );
406
407 rwfil_.setSize(wallFaceBbsToExchange.size());
408
409 // This needs to be a boolList, not bitSet if
410 // reverseDistribute is called.
411 boolList wallFaceBbRequiredByAnyCell(wallFaceBbsToExchange.size(), false);
412
413 forAll(wallFaceBbsToExchange, bbI)
414 {
415 const labelPair& wfiat = wallFaceIAndTToExchange[bbI];
416
417 const vectorTensorTransform& transform = globalTransforms.transform
418 (
419 globalTransforms.transformIndex(wfiat)
420 );
421
422 treeBoundBox tempTransformedBb
423 (
424 transform.invTransformPosition(wallFaceBbsToExchange[bbI].points())
425 );
426
427 treeBoundBox extendedBb
428 (
429 tempTransformedBb.min() - interactionVec,
430 tempTransformedBb.max() + interactionVec
431 );
432
433 // Find all elements intersecting box.
434 labelList interactingElems
435 (
436 coupledPatchRangeTree.findBox(extendedBb)
437 );
438
439 if (!interactingElems.empty())
440 {
441 wallFaceBbRequiredByAnyCell[bbI] = true;
442 }
443
444 rwfil_[bbI].setSize(interactingElems.size(), -1);
445
446 forAll(interactingElems, i)
447 {
448 label elemI = interactingElems[i];
449
450 // Here, a more detailed geometric test could be applied,
451 // i.e. a more accurate bounding volume like a OBB or
452 // convex hull or an exact geometrical test.
453
454 label c = coupledPatchRangeTree.shapes().cellLabels()[elemI];
455
456 rwfil_[bbI][i] = c;
457 }
458 }
459
460 // Perform subset of rwfil_, to remove any referred wallFaces that do
461 // not interact. They will not be sent from originating
462 // processors. This assumes that the disappearance of the wallFace
463 // from the sending list of the source processor, simply removes
464 // the referred wallFace from the rwfil_, all of the subsequent indices
465 // shuffle down one, but the order and structure is preserved,
466 // i.e. it, is as if the wallFace had never been referred in the first
467 // place.
468
469 inplaceSubset(wallFaceBbRequiredByAnyCell, rwfil_);
470
471 // Send information about which wallFaces are actually required
472 // back to originating processors.
473
474 // At this point, wallFaceBbsToExchange does not need to be
475 // maintained or distributed as it is not longer needed.
476
477 wallFaceBbsToExchange.setSize(0);
478
479 wallFaceMap().reverseDistribute
480 (
481 preDistributionWallFaceMapSize,
482 wallFaceBbRequiredByAnyCell
483 );
484
485 wallFaceMap().reverseDistribute
486 (
487 preDistributionWallFaceMapSize,
488 wallFaceIAndTToExchange
489 );
490
491 // Perform ordering of wallFaces to send, this invalidates the
492 // previous value of preDistributionWallFaceMapSize.
493
494 preDistributionWallFaceMapSize = -1;
495
496 // Move all of the used wallFaces to refer to the start of the
497 // list and truncate it
498
499 inplaceSubset(wallFaceBbRequiredByAnyCell, wallFaceIAndTToExchange);
500
501 inplaceSubset(wallFaceBbRequiredByAnyCell, procToDistributeWallFaceTo);
502
503 preDistributionWallFaceMapSize = procToDistributeWallFaceTo.size();
504
505 // Rebuild mapDistribute with only required referred wallFaces
506 buildMap(wallFaceMapPtr_, procToDistributeWallFaceTo);
507
508 // Store wallFaceIndexAndTransformToDistribute
509 wallFaceIndexAndTransformToDistribute_.transfer(wallFaceIAndTToExchange);
510
511 // Determine inverse addressing for referred wallFaces
512
513 rwfilInverse_.setSize(mesh_.nCells());
514
515 // Temporary Dynamic lists for accumulation
516 List<DynamicList<label>> rwfilInverseTemp(rwfilInverse_.size());
517
518 // Loop over all referred wall faces
519 forAll(rwfil_, refWallFacei)
520 {
521 const labelList& realCells = rwfil_[refWallFacei];
522
523 // Loop over all real cells in that the referred wall face is
524 // to supply interactions to and record the index of this
525 // referred wall face in the real cells entry in rwfilInverse
526
527 forAll(realCells, realCelli)
528 {
529 rwfilInverseTemp[realCells[realCelli]].append(refWallFacei);
530 }
531 }
532
533 forAll(rwfilInverse_, celli)
534 {
535 rwfilInverse_[celli].transfer(rwfilInverseTemp[celli]);
536 }
537
538 // Refer wall faces to the appropriate processor
539 referredWallFaces_.setSize(wallFaceIndexAndTransformToDistribute_.size());
540
541 forAll(referredWallFaces_, rWFI)
542 {
543 const labelPair& wfiat = wallFaceIndexAndTransformToDistribute_[rWFI];
544
545 label wallFaceIndex = globalTransforms.index(wfiat);
546
547 const vectorTensorTransform& transform = globalTransforms.transform
548 (
549 globalTransforms.transformIndex(wfiat)
550 );
551
552 const face& f = mesh_.faces()[wallFaceIndex];
553
554 label patchi = mesh_.boundaryMesh().patchID()
555 [
556 wallFaceIndex - mesh_.nInternalFaces()
557 ];
558
559 referredWallFaces_[rWFI] = referredWallFace
560 (
561 face(identity(f.size())),
562 transform.invTransformPosition(f.points(mesh_.points())),
563 patchi
564 );
565 }
566
567 wallFaceMap().distribute(referredWallFaces_);
568
569 if (writeCloud_)
570 {
571 writeReferredWallFaces();
572 }
573
574 // Direct interaction list and direct wall faces
575
576 Info<< " Building direct interaction lists" << endl;
577
578 indexedOctree<treeDataFace> wallFacesTree
579 (
580 treeDataFace(true, mesh_, localWallFaces),
581 procBbRndExt,
582 8, // maxLevel,
583 10, // leafSize,
584 100.0
585 );
586
587 dil_.setSize(mesh_.nCells());
588
589 dwfil_.setSize(mesh_.nCells());
590
591 forAll(cellBbs, celli)
592 {
593 const treeBoundBox& cellBb = cellBbs[celli];
594
595 treeBoundBox extendedBb
596 (
597 cellBb.min() - interactionVec,
598 cellBb.max() + interactionVec
599 );
600
601 // Find all cells intersecting extendedBb
602 labelList interactingElems(allCellsTree.findBox(extendedBb));
603
604 // Reserve space to avoid multiple resizing
605 DynamicList<label> cellDIL(interactingElems.size());
606
607 for (const label elemi : interactingElems)
608 {
609 const label c = allCellsTree.shapes().cellLabels()[elemi];
610
611 // Here, a more detailed geometric test could be applied,
612 // i.e. a more accurate bounding volume like a OBB or
613 // convex hull, or an exact geometrical test.
614
615 // The higher index cell is added to the lower index
616 // cell's DIL. A cell is not added to its own DIL.
617 if (c > celli)
618 {
619 cellDIL.append(c);
620 }
621 }
622
623 dil_[celli].transfer(cellDIL);
624
625 // Find all wall faces intersecting extendedBb
626 interactingElems = wallFacesTree.findBox(extendedBb);
627
628 dwfil_[celli].setSize(interactingElems.size(), -1);
629
630 forAll(interactingElems, i)
631 {
632 const label elemi = interactingElems[i];
633
634 const label f = wallFacesTree.shapes().faceLabels()[elemi];
635
636 dwfil_[celli][i] = f;
637 }
638 }
639}
640
641
642template<class ParticleType>
644(
645 const treeBoundBox& procBb,
646 const List<treeBoundBox>& allExtendedProcBbs,
647 const globalIndexAndTransform& globalTransforms,
648 List<treeBoundBox>& extendedProcBbsInRange,
649 List<label>& extendedProcBbsTransformIndex,
650 List<label>& extendedProcBbsOrigProc
651)
652{
653 extendedProcBbsInRange.setSize(0);
654 extendedProcBbsTransformIndex.setSize(0);
655 extendedProcBbsOrigProc.setSize(0);
656
657 DynamicList<treeBoundBox> tmpExtendedProcBbsInRange;
658 DynamicList<label> tmpExtendedProcBbsTransformIndex;
659 DynamicList<label> tmpExtendedProcBbsOrigProc;
660
661 label nTrans = globalTransforms.nIndependentTransforms();
662
663 forAll(allExtendedProcBbs, proci)
664 {
665 labelList permutationIndices(nTrans, Zero);
666
667 if (nTrans == 0 && proci != Pstream::myProcNo())
668 {
669 treeBoundBox extendedReferredProcBb = allExtendedProcBbs[proci];
670
671 if (procBb.overlaps(extendedReferredProcBb))
672 {
673 tmpExtendedProcBbsInRange.append(extendedReferredProcBb);
674
675 // Dummy index, there are no transforms, so there will
676 // be no resultant transform when this is decoded.
677 tmpExtendedProcBbsTransformIndex.append(0);
678
679 tmpExtendedProcBbsOrigProc.append(proci);
680 }
681 }
682 else if (nTrans == 3)
683 {
684 label& i = permutationIndices[0];
685 label& j = permutationIndices[1];
686 label& k = permutationIndices[2];
687
688 for (i = -1; i <= 1; i++)
689 {
690 for (j = -1; j <= 1; j++)
691 {
692 for (k = -1; k <= 1; k++)
693 {
694 if
695 (
696 i == 0
697 && j == 0
698 && k == 0
699 && proci == Pstream::myProcNo()
700 )
701 {
702 // Skip this processor's extended boundBox
703 // when it has no transformation
704 continue;
705 }
706
707 label transI = globalTransforms.encodeTransformIndex
708 (
709 permutationIndices
710 );
711
712 const vectorTensorTransform& transform =
713 globalTransforms.transform(transI);
714
715 treeBoundBox extendedReferredProcBb
716 (
717 transform.transformPosition
718 (
719 allExtendedProcBbs[proci].points()
720 )
721 );
722
723 if (procBb.overlaps(extendedReferredProcBb))
724 {
725 tmpExtendedProcBbsInRange.append
726 (
727 extendedReferredProcBb
728 );
729
730 tmpExtendedProcBbsTransformIndex.append(transI);
731
732 tmpExtendedProcBbsOrigProc.append(proci);
733 }
734 }
735 }
736 }
737 }
738 else if (nTrans == 2)
739 {
740 label& i = permutationIndices[0];
741 label& j = permutationIndices[1];
742
743 for (i = -1; i <= 1; i++)
744 {
745 for (j = -1; j <= 1; j++)
746 {
747 if (i == 0 && j == 0 && proci == Pstream::myProcNo())
748 {
749 // Skip this processor's extended boundBox
750 // when it has no transformation
751 continue;
752 }
753
754 label transI = globalTransforms.encodeTransformIndex
755 (
756 permutationIndices
757 );
758
759 const vectorTensorTransform& transform =
760 globalTransforms.transform(transI);
761
762 treeBoundBox extendedReferredProcBb
763 (
764 transform.transformPosition
765 (
766 allExtendedProcBbs[proci].points()
767 )
768 );
769
770 if (procBb.overlaps(extendedReferredProcBb))
771 {
772 tmpExtendedProcBbsInRange.append
773 (
774 extendedReferredProcBb
775 );
776
777 tmpExtendedProcBbsTransformIndex.append(transI);
778
779 tmpExtendedProcBbsOrigProc.append(proci);
780 }
781 }
782 }
783 }
784 else if (nTrans == 1)
785 {
786 label& i = permutationIndices[0];
787
788 for (i = -1; i <= 1; i++)
789 {
790 if (i == 0 && proci == Pstream::myProcNo())
791 {
792 // Skip this processor's extended boundBox when it
793 // has no transformation
794 continue;
795 }
796
797 label transI = globalTransforms.encodeTransformIndex
798 (
799 permutationIndices
800 );
801
802 const vectorTensorTransform& transform =
803 globalTransforms.transform(transI);
804
805 treeBoundBox extendedReferredProcBb
806 (
807 transform.transformPosition
808 (
809 allExtendedProcBbs[proci].points()
810 )
811 );
812
813 if (procBb.overlaps(extendedReferredProcBb))
814 {
815 tmpExtendedProcBbsInRange.append
816 (
817 extendedReferredProcBb
818 );
819
820 tmpExtendedProcBbsTransformIndex.append(transI);
821
822 tmpExtendedProcBbsOrigProc.append(proci);
823 }
824 }
825 }
826 }
827
828 extendedProcBbsInRange.transfer(tmpExtendedProcBbsInRange);
829 extendedProcBbsTransformIndex.transfer(tmpExtendedProcBbsTransformIndex);
830 extendedProcBbsOrigProc.transfer(tmpExtendedProcBbsOrigProc);
831}
832
833
834template<class ParticleType>
836(
837 autoPtr<mapDistribute>& mapPtr,
838 const List<label>& toProc
839)
840{
841 // Determine send map
842 // ~~~~~~~~~~~~~~~~~~
843
844 // 1. Count
845 labelList nSend(Pstream::nProcs(), Zero);
846
847 for (const label proci : toProc)
848 {
849 nSend[proci]++;
850 }
851
852 // 2. Size sendMap
853 labelListList sendMap(Pstream::nProcs());
854
855 forAll(nSend, proci)
856 {
857 sendMap[proci].setSize(nSend[proci]);
858
859 nSend[proci] = 0;
860 }
861
862 // 3. Fill sendMap
863 forAll(toProc, i)
864 {
865 label proci = toProc[i];
866
867 sendMap[proci][nSend[proci]++] = i;
868 }
869
870 // 4. Send over how many I need to receive
871 labelList recvSizes;
872 Pstream::exchangeSizes(sendMap, recvSizes);
873
874
875 // Determine receive map
876 // ~~~~~~~~~~~~~~~~~~~~~
877
878 labelListList constructMap(Pstream::nProcs());
879
880 // Local transfers first
881 constructMap[Pstream::myProcNo()] = identity
882 (
883 sendMap[Pstream::myProcNo()].size()
884 );
885
886 label constructSize = constructMap[Pstream::myProcNo()].size();
887
888 forAll(constructMap, proci)
889 {
890 if (proci != Pstream::myProcNo())
891 {
892 const label nRecv = recvSizes[proci];
893
894 constructMap[proci].setSize(nRecv);
895
896 for (label i = 0; i < nRecv; i++)
897 {
898 constructMap[proci][i] = constructSize++;
899 }
900 }
901 }
902
903 mapPtr.reset
904 (
905 new mapDistribute
906 (
907 constructSize,
908 std::move(sendMap),
909 std::move(constructMap)
910 )
911 );
912}
913
914
915template<class ParticleType>
917(
918 const List<DynamicList<ParticleType*>>& cellOccupancy
919)
920{
921 const globalIndexAndTransform& globalTransforms =
922 mesh_.globalData().globalTransforms();
923
924 referredParticles_.setSize(cellIndexAndTransformToDistribute_.size());
925
926 // Clear all existing referred particles
927
928 forAll(referredParticles_, i)
929 {
930 referredParticles_[i].clear();
931 }
932
933 // Clear all particles that may have been populated into the cloud
934 cloud_.clear();
935
936 forAll(cellIndexAndTransformToDistribute_, i)
937 {
938 const labelPair ciat = cellIndexAndTransformToDistribute_[i];
939
940 label cellIndex = globalTransforms.index(ciat);
941
942 List<ParticleType*> realParticles = cellOccupancy[cellIndex];
943
944 IDLList<ParticleType>& particlesToRefer = referredParticles_[i];
945
946 forAll(realParticles, rM)
947 {
948 const ParticleType& particle = *realParticles[rM];
949
950 particlesToRefer.append(particle.clone().ptr());
951
952 prepareParticleToBeReferred(particlesToRefer.last(), ciat);
953 }
954 }
955}
956
957
958template<class ParticleType>
960(
961 ParticleType* particle,
962 labelPair ciat
963)
964{
965 const globalIndexAndTransform& globalTransforms =
966 mesh_.globalData().globalTransforms();
967
968 const vectorTensorTransform& transform = globalTransforms.transform
969 (
970 globalTransforms.transformIndex(ciat)
971 );
972
973 particle->prepareForInteractionListReferral(transform);
974}
975
976
977template<class ParticleType>
979{
980 if (writeCloud_)
981 {
982 forAll(referredParticles_, refCelli)
983 {
984 const IDLList<ParticleType>& refCell =
985 referredParticles_[refCelli];
986
987 for (const ParticleType& p : refCell)
988 {
989 cloud_.addParticle
990 (
991 static_cast<ParticleType*>(p.clone().ptr())
992 );
993 }
994 }
995 }
996}
997
998
999template<class ParticleType>
1001{
1002 const globalIndexAndTransform& globalTransforms =
1003 mesh_.globalData().globalTransforms();
1004
1005 referredWallData_.setSize
1006 (
1007 wallFaceIndexAndTransformToDistribute_.size()
1008 );
1009
1010 const volVectorField& U = mesh_.lookupObject<volVectorField>(UName_);
1011
1012 forAll(referredWallData_, rWVI)
1013 {
1014 const labelPair& wfiat = wallFaceIndexAndTransformToDistribute_[rWVI];
1015
1016 label wallFaceIndex = globalTransforms.index(wfiat);
1017
1018 const vectorTensorTransform& transform = globalTransforms.transform
1019 (
1020 globalTransforms.transformIndex(wfiat)
1021 );
1022
1023 label patchi = mesh_.boundaryMesh().patchID()
1024 [
1025 wallFaceIndex - mesh_.nInternalFaces()
1026 ];
1027
1028 label patchFacei =
1029 wallFaceIndex
1030 - mesh_.boundaryMesh()[patchi].start();
1031
1032 // Need to transform velocity when tensor transforms are
1033 // supported
1034 referredWallData_[rWVI] = U.boundaryField()[patchi][patchFacei];
1035
1036 if (transform.hasR())
1037 {
1038 referredWallData_[rWVI] =
1039 transform.R().T() & referredWallData_[rWVI];
1040 }
1041 }
1042}
1043
1044
1045template<class ParticleType>
1047{
1048 if (referredWallFaces_.empty())
1049 {
1050 return;
1051 }
1052
1053 fileName objDir = mesh_.time().timePath()/cloud::prefix;
1054
1055 mkDir(objDir);
1056
1057 fileName objFileName = "referredWallFaces.obj";
1058
1059 OFstream str(objDir/objFileName);
1060
1061 Info<< " Writing "
1062 << mesh_.time().timeName()/cloud::prefix/objFileName
1063 << endl;
1064
1065 label offset = 1;
1066
1067 forAll(referredWallFaces_, rWFI)
1068 {
1069 const referredWallFace& rwf = referredWallFaces_[rWFI];
1070
1071 forAll(rwf, fPtI)
1072 {
1073 meshTools::writeOBJ(str, rwf.points()[rwf[fPtI]]);
1074 }
1075
1076 str<< 'f';
1077
1078 forAll(rwf, fPtI)
1079 {
1080 str<< ' ' << fPtI + offset;
1081 }
1082
1083 str<< nl;
1084
1085 offset += rwf.size();
1086 }
1087}
1088
1089
1090// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1091
1092template<class ParticleType>
1094:
1095 mesh_(mesh),
1096 cloud_(mesh_, "nullptr_Cloud", IDLList<ParticleType>()),
1097 writeCloud_(false),
1098 cellMapPtr_(),
1099 wallFaceMapPtr_(),
1100 maxDistance_(0.0),
1101 dil_(),
1102 dwfil_(),
1103 ril_(),
1104 rilInverse_(),
1105 cellIndexAndTransformToDistribute_(),
1106 wallFaceIndexAndTransformToDistribute_(),
1107 referredWallFaces_(),
1108 UName_("unknown_U"),
1109 referredWallData_(),
1110 referredParticles_()
1111{}
1112
1113
1114template<class ParticleType>
1116(
1117 const polyMesh& mesh,
1118 scalar maxDistance,
1119 bool writeCloud,
1120 const word& UName
1121)
1122:
1123 mesh_(mesh),
1124 cloud_(mesh_, "referredParticleCloud", IDLList<ParticleType>()),
1125 writeCloud_(writeCloud),
1126 cellMapPtr_(),
1127 wallFaceMapPtr_(),
1128 maxDistance_(maxDistance),
1129 dil_(),
1130 dwfil_(),
1131 ril_(),
1132 rilInverse_(),
1133 cellIndexAndTransformToDistribute_(),
1134 wallFaceIndexAndTransformToDistribute_(),
1135 referredWallFaces_(),
1136 UName_(UName),
1137 referredWallData_(),
1138 referredParticles_()
1139{
1140 buildInteractionLists();
1141}
1142
1143
1144// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1145
1146template<class ParticleType>
1148{}
1149
1150
1151// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
1152
1153template<class ParticleType>
1155(
1157 PstreamBuffers& pBufs
1158)
1159{
1160 if (mesh_.changing())
1161 {
1163 << "Mesh changing, rebuilding InteractionLists from scratch."
1164 << endl;
1165
1166 buildInteractionLists();
1167 }
1168
1169 prepareWallDataToRefer();
1170
1171 prepareParticlesToRefer(cellOccupancy);
1172
1173 for (const int domain : Pstream::allProcs())
1174 {
1175 const labelList& subMap = cellMap().subMap()[domain];
1176
1177 if (subMap.size())
1178 {
1179 UOPstream toDomain(domain, pBufs);
1180
1181 UIndirectList<IDLList<ParticleType>> subMappedParticles
1182 (
1183 referredParticles_,
1184 subMap
1185 );
1186
1187 forAll(subMappedParticles, i)
1188 {
1189 toDomain << subMappedParticles[i];
1190 }
1191 }
1192 }
1193
1194 // Using the mapDistribute to start sending and receiving the
1195 // buffer but not block, i.e. it is calling
1196 // pBufs.finishedSends(false);
1197 wallFaceMap().send(pBufs, referredWallData_);
1198}
1199
1200
1201template<class ParticleType>
1203(
1204 PstreamBuffers& pBufs,
1205 const label startOfRequests
1206)
1207{
1208 Pstream::waitRequests(startOfRequests);
1209
1210 referredParticles_.setSize(cellMap().constructSize());
1211
1212 for (const int domain : Pstream::allProcs())
1213 {
1214 const labelList& constructMap = cellMap().constructMap()[domain];
1215
1216 if (constructMap.size())
1217 {
1218 UIPstream str(domain, pBufs);
1219
1220 forAll(constructMap, i)
1221 {
1222 referredParticles_[constructMap[i]] = IDLList<ParticleType>
1223 (
1224 str,
1225 typename ParticleType::iNew(mesh_)
1226 );
1227 }
1228 }
1229 }
1230
1231 forAll(referredParticles_, refCelli)
1232 {
1233 IDLList<ParticleType>& refCell = referredParticles_[refCelli];
1234 for (ParticleType& p : refCell)
1235 {
1236 p.correctAfterInteractionListReferral(ril_[refCelli][0]);
1237 }
1238 }
1239
1240 fillReferredParticleCloud();
1241
1242 wallFaceMap().receive(pBufs, referredWallData_);
1243}
1244
1245
1246// ************************************************************************* //
label k
const List< DynamicList< molecule * > > & cellOccupancy
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects.
Definition: DynamicList.H:72
Template class for intrusive linked lists.
Definition: ILList.H:69
Builds direct interaction list, specifying which local (real) cells are potentially in range of each ...
void sendReferredData(const List< DynamicList< ParticleType * > > &cellOccupancy, PstreamBuffers &pBufs)
Prepare and send referred particles and wall data,.
void receiveReferredData(PstreamBuffers &pBufs, const label startReq=0)
Receive referred data.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: List.H:77
Buffers for inter-processor communications streams (UOPstream, UIPstream).
UPstream::rangeType allProcs() const noexcept
Range of ranks indices associated with PstreamBuffers.
A List with indirect addressing. Like IndirectList but does not store addressing.
Definition: IndirectList.H:79
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
static void waitRequests(const label start=0)
Wait until all requests (from start onwards) have finished.
Definition: UPstream.C:100
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:81
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 WarningInFunction
Report a warning using Foam::Warning.
const dimensionedScalar c
Speed of light in a vacuum.
const std::string patch
OpenFOAM patch number as a std::string.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:57
void inplaceSubset(const BoolListType &select, ListType &input, const bool invert=false)
Inplace extract elements of the input list when select is true.
GeometricField< vector, fvPatchField, volMesh > volVectorField
Definition: volFieldsFwd.H:83
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
dimensionSet transform(const dimensionSet &ds)
Return the argument; transformations do not change the dimensions.
Definition: dimensionSet.C:536
List< label > labelList
A List of labels.
Definition: List.H:66
messageStream Info
Information stream (stdout output on master, null elsewhere)
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:56
List< treeBoundBox > treeBoundBoxList
List of bounding boxes.
List< bool > boolList
A List of bools.
Definition: List.H:64
constexpr char nl
The newline '\n' character (0x0a)
Definition: Ostream.H:53
labelList f(nPoints)
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
const word UName(propsDict.getOrDefault< word >("U", "U"))
mkDir(pdfPath)
Random rndGen
Definition: createFields.H:23