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