inverseDistanceCellCellStencil.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) 2017-2020 OpenCFD Ltd.
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify i
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
30 #include "OBJstream.H"
31 #include "Time.H"
32 #include "fvMeshSubset.H"
33 
34 #include "globalIndex.H"
35 #include "oversetFvPatch.H"
37 #include "syncTools.H"
38 #include "treeBoundBoxList.H"
39 #include "waveMethod.H"
40 
41 #include "regionSplit.H"
42 #include "dynamicOversetFvMesh.H"
43 //#include "minData.H"
44 //#include "FaceCellWave.H"
45 
46 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
47 
48 namespace Foam
49 {
50 namespace cellCellStencils
51 {
52  defineTypeNameAndDebug(inverseDistance, 0);
53  addToRunTimeSelectionTable(cellCellStencil, inverseDistance, mesh);
54 }
55 }
56 
57 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
58 
60 (
61  const labelVector& nDivs,
62  const labelVector& ijk
63 )
64 {
65  return (ijk[0]*nDivs[1] + ijk[1])*nDivs[2] + ijk[2];
66 }
67 
68 
70 (
71  const labelVector& nDivs,
72  const label boxI
73 )
74 {
75  label ij = boxI/nDivs[2];
76  label k = boxI-ij*nDivs[2];
77  label i = ij/nDivs[1];
78  label j = ij-i*nDivs[1];
79 
80  return labelVector(i, j, k);
81 }
82 
83 
85 (
86  const boundBox& bb,
87  const labelVector& nDivs,
88  const point& pt
89 )
90 {
91  const vector d(bb.span());
92  const point relPt(pt-bb.min());
93 
94  return labelVector
95  (
96  floor(relPt[0]/d[0]*nDivs[0]),
97  floor(relPt[1]/d[1]*nDivs[1]),
98  floor(relPt[2]/d[2]*nDivs[2])
99  );
100 }
101 
102 
104 (
105  const boundBox& bb,
106  const labelVector& nDivs,
107  const label boxI
108 )
109 {
110  // Return midpoint of box indicated by boxI
111  labelVector ids(index3(nDivs, boxI));
112 
113  const vector d(bb.span());
114  const vector sz(d[0]/nDivs[0], d[1]/nDivs[1], d[2]/nDivs[2]);
115 
116  return bb.min()+0.5*sz+vector(sz[0]*ids[0], sz[1]*ids[1], sz[2]*ids[2]);
117 }
118 
119 
121 (
122  PackedList<2>& elems,
123  const boundBox& bb,
124  const labelVector& nDivs,
125  const boundBox& subBb,
126  const unsigned int val
127 )
128 {
129  labelVector minIds(index3(bb, nDivs, subBb.min()));
130  labelVector maxIds(index3(bb, nDivs, subBb.max()));
131 
132  for (direction cmpt = 0; cmpt < 3; cmpt++)
133  {
134  if (maxIds[cmpt] < 0 || minIds[cmpt] > nDivs[cmpt])
135  {
136  return;
137  }
138  }
139 
140  labelVector maxIndex(labelVector(nDivs[0]-1, nDivs[1]-1, nDivs[2]-1));
141  minIds = max(labelVector::zero, minIds);
142  maxIds = min(maxIndex, maxIds);
143 
144  for (label i = minIds[0]; i <= maxIds[0]; i++)
145  {
146  for (label j = minIds[1]; j <= maxIds[1]; j++)
147  {
148  for (label k = minIds[2]; k <= maxIds[2]; k++)
149  {
150  label i1 = index(nDivs, labelVector(i, j, k));
151  elems[i1] = val;
152  }
153  }
154  }
155 }
156 
157 
159 (
160  const fvMesh& mesh,
161  const vector& smallVec,
162 
163  const boundBox& bb,
164  const labelVector& nDivs,
166 
167  const labelList& cellMap,
168  labelList& patchCellTypes
169 )
170 {
171  // Mark all voxels that overlap the bounding box of any patch
172 
173  const fvBoundaryMesh& pbm = mesh.boundary();
174 
175  patchTypes = patchCellType::OTHER;
176 
177  // Mark wall boundaries
178  forAll(pbm, patchI)
179  {
180  const fvPatch& fvp = pbm[patchI];
181  const labelList& fc = fvp.faceCells();
182 
183  if (!fvPatch::constraintType(fvp.type()))
184  {
185  //Info<< "Marking cells on proper patch " << fvp.name()
186  // << " with type " << fvp.type() << endl;
187  const polyPatch& pp = fvp.patch();
188  forAll(pp, i)
189  {
190  // Mark in overall patch types
191  patchCellTypes[cellMap[fc[i]]] = patchCellType::PATCH;
192 
193  // Mark in voxel mesh
194  boundBox faceBb(pp.points(), pp[i], false);
195  faceBb.min() -= smallVec;
196  faceBb.max() += smallVec;
197 
198  if (bb.overlaps(faceBb))
199  {
200  fill(patchTypes, bb, nDivs, faceBb, patchCellType::PATCH);
201  }
202  }
203  }
204  }
205 
206  // Override with overset boundaries
207  forAll(pbm, patchI)
208  {
209  const fvPatch& fvp = pbm[patchI];
210  const labelList& fc = fvp.faceCells();
211 
212  if (isA<oversetFvPatch>(fvp))
213  {
214  //Info<< "Marking cells on overset patch " << fvp.name() << endl;
215  const polyPatch& pp = fvp.patch();
216  forAll(pp, i)
217  {
218  // Mark in overall patch types
219  patchCellTypes[cellMap[fc[i]]] = patchCellType::OVERSET;
220 
221  // Mark in voxel mesh
222  boundBox faceBb(pp.points(), pp[i], false);
223  faceBb.min() -= smallVec;
224  faceBb.max() += smallVec;
225 
226  if (bb.overlaps(faceBb))
227  {
228  fill(patchTypes, bb, nDivs, faceBb, patchCellType::OVERSET);
229  }
230  }
231  }
232  }
233 }
234 
235 
237 (
238  const primitiveMesh& mesh,
239  const label celli
240 )
241 {
242  const cellList& cells = mesh.cells();
243  const faceList& faces = mesh.faces();
244  const pointField& points = mesh.points();
245 
246  treeBoundBox bb
247  (
248  vector(GREAT, GREAT, GREAT),
249  vector(-GREAT, -GREAT, -GREAT)
250  );
251 
252  const cell& cFaces = cells[celli];
253 
254  forAll(cFaces, cFacei)
255  {
256  const face& f = faces[cFaces[cFacei]];
257 
258  forAll(f, fp)
259  {
260  const point& p = points[f[fp]];
261 
262  bb.min() = min(bb.min(), p);
263  bb.max() = max(bb.max(), p);
264  }
265  }
266  return bb;
267 }
268 
269 
271 (
272  const boundBox& bb,
273  const labelVector& nDivs,
274  const PackedList<2>& vals,
275  const treeBoundBox& subBb,
276  const unsigned int val
277 )
278 {
279  // Checks if subBb overlaps any voxel set to val
280 
281  labelVector minIds(index3(bb, nDivs, subBb.min()));
282  labelVector maxIds(index3(bb, nDivs, subBb.max()));
283 
284  for (direction cmpt = 0; cmpt < 3; cmpt++)
285  {
286  if (maxIds[cmpt] < 0 || minIds[cmpt] > nDivs[cmpt])
287  {
288  return false;
289  }
290  }
291 
292  labelVector maxIndex(labelVector(nDivs[0]-1, nDivs[1]-1, nDivs[2]-1));
293  minIds = max(labelVector::zero, minIds);
294  maxIds = min(maxIndex, maxIds);
295 
296  for (label i = minIds[0]; i <= maxIds[0]; i++)
297  {
298  for (label j = minIds[1]; j <= maxIds[1]; j++)
299  {
300  for (label k = minIds[2]; k <= maxIds[2]; k++)
301  {
302  label i1 = index(nDivs, labelVector(i, j, k));
303  if (vals[i1] == patchCellType::PATCH)
304  {
305  return true;
306  }
307  }
308  }
309  }
310  return false;
311 }
312 
313 
315 (
316  PstreamBuffers& pBufs,
317 
319 
320  const List<treeBoundBoxList>& patchBb,
321  const List<labelVector>& patchDivisions,
322  const PtrList<PackedList<2>>& patchParts,
323 
324  const label srcI,
325  const label tgtI,
326  labelList& allCellTypes
327 ) const
328 {
329  const treeBoundBoxList& srcPatchBbs = patchBb[srcI];
330  const treeBoundBoxList& tgtPatchBbs = patchBb[tgtI];
331  const labelList& tgtCellMap = meshParts[tgtI].cellMap();
332 
333  // 1. do processor-local src-tgt patch overlap
334  {
335  const treeBoundBox& srcPatchBb = srcPatchBbs[Pstream::myProcNo()];
336  const treeBoundBox& tgtPatchBb = tgtPatchBbs[Pstream::myProcNo()];
337 
338  if (srcPatchBb.overlaps(tgtPatchBb))
339  {
340  const PackedList<2>& srcPatchTypes = patchParts[srcI];
341  const labelVector& zoneDivs = patchDivisions[srcI];
342 
343  forAll(tgtCellMap, tgtCelli)
344  {
345  label celli = tgtCellMap[tgtCelli];
346  treeBoundBox cBb(cellBb(mesh_, celli));
347  cBb.min() -= smallVec_;
348  cBb.max() += smallVec_;
349 
350  if
351  (
352  overlaps
353  (
354  srcPatchBb,
355  zoneDivs,
356  srcPatchTypes,
357  cBb,
359  )
360  )
361  {
362  allCellTypes[celli] = HOLE;
363  }
364  }
365  }
366  }
367 
368 
369  // 2. Send over srcMesh bits that overlap tgt and do calculation
370  pBufs.clear();
371  for (const int procI : Pstream::allProcs())
372  {
373  if (procI != Pstream::myProcNo())
374  {
375  const treeBoundBox& srcPatchBb = srcPatchBbs[Pstream::myProcNo()];
376  const treeBoundBox& tgtPatchBb = tgtPatchBbs[procI];
377 
378  if (srcPatchBb.overlaps(tgtPatchBb))
379  {
380  // Send over complete patch voxel map. Tbd: could
381  // subset
382  UOPstream os(procI, pBufs);
383  os << srcPatchBb << patchDivisions[srcI] << patchParts[srcI];
384  }
385  }
386  }
387  pBufs.finishedSends();
388  for (const int procI : Pstream::allProcs())
389  {
390  if (procI != Pstream::myProcNo())
391  {
392  //const treeBoundBox& srcBb = srcBbs[procI];
393  const treeBoundBox& srcPatchBb = srcPatchBbs[procI];
394  const treeBoundBox& tgtPatchBb = tgtPatchBbs[Pstream::myProcNo()];
395 
396  if (srcPatchBb.overlaps(tgtPatchBb))
397  {
398  UIPstream is(procI, pBufs);
399  {
400  treeBoundBox receivedBb(is);
401  if (srcPatchBb != receivedBb)
402  {
404  << "proc:" << procI
405  << " srcPatchBb:" << srcPatchBb
406  << " receivedBb:" << receivedBb
407  << exit(FatalError);
408  }
409  }
410  const labelVector zoneDivs(is);
411  const PackedList<2> srcPatchTypes(is);
412 
413  forAll(tgtCellMap, tgtCelli)
414  {
415  label celli = tgtCellMap[tgtCelli];
416  treeBoundBox cBb(cellBb(mesh_, celli));
417  cBb.min() -= smallVec_;
418  cBb.max() += smallVec_;
419  if
420  (
421  overlaps
422  (
423  srcPatchBb,
424  zoneDivs,
425  srcPatchTypes,
426  cBb,
428  )
429  )
430  {
431  allCellTypes[celli] = HOLE;
432  }
433  }
434  }
435  }
436  }
437 }
438 
439 
441 (
442  const label destMesh,
443  const label currentDonorMesh,
444  const label newDonorMesh
445 ) const
446 {
447  // This determines for multiple overlapping meshes which one provides
448  // the best donors. Is very basic and only looks at indices of meshes:
449  // - 'nearest' mesh index wins, i.e. on mesh 0 it preferentially uses donors
450  // from mesh 1 over mesh 2 (if applicable)
451  // - if same 'distance' the highest mesh wins. So on mesh 1 it
452  // preferentially uses donors from mesh 2 over mesh 0. This particular
453  // rule helps to avoid some interpolation loops where mesh 1 uses donors
454  // from mesh 0 (usually the background) but mesh 0 then uses
455  // donors from 1.
456 
457  if (currentDonorMesh == -1)
458  {
459  return true;
460  }
461  else
462  {
463  const label currentDist = mag(currentDonorMesh-destMesh);
464  const label newDist = mag(newDonorMesh-destMesh);
465 
466  if (newDist < currentDist)
467  {
468  return true;
469  }
470  else if (newDist == currentDist && newDonorMesh > currentDonorMesh)
471  {
472  return true;
473  }
474  else
475  {
476  return false;
477  }
478  }
479 }
480 
481 
483 (
484  const globalIndex& globalCells,
485  PstreamBuffers& pBufs,
488 
489  const labelList& allCellTypes,
490 
491  const label srcI,
492  const label tgtI,
493  labelListList& allStencil,
494  labelList& allDonor
495 ) const
496 {
497  const treeBoundBoxList& srcBbs = meshBb[srcI];
498  const treeBoundBoxList& tgtBbs = meshBb[tgtI];
499 
500  const fvMesh& srcMesh = meshParts[srcI].subMesh();
501  const labelList& srcCellMap = meshParts[srcI].cellMap();
502  const fvMesh& tgtMesh = meshParts[tgtI].subMesh();
503  const pointField& tgtCc = tgtMesh.cellCentres();
504  const labelList& tgtCellMap = meshParts[tgtI].cellMap();
505 
506  // 1. do processor-local src/tgt overlap
507  {
508  labelList tgtToSrcAddr;
509  waveMethod::calculate(tgtMesh, srcMesh, tgtToSrcAddr);
510  forAll(tgtCellMap, tgtCelli)
511  {
512  label srcCelli = tgtToSrcAddr[tgtCelli];
513  if (srcCelli != -1 && allCellTypes[srcCellMap[srcCelli]] != HOLE)
514  {
515  label celli = tgtCellMap[tgtCelli];
516 
517  // TBD: check for multiple donors. Maybe better one? For
518  // now check 'nearer' mesh
519  if (betterDonor(tgtI, allDonor[celli], srcI))
520  {
521  label globalDonor =
522  globalCells.toGlobal(srcCellMap[srcCelli]);
523  allStencil[celli].setSize(1);
524  allStencil[celli][0] = globalDonor;
525  allDonor[celli] = srcI;
526  }
527  }
528  }
529  }
530 
531 
532  // 2. Send over tgtMesh bits that overlap src and do calculation on
533  // srcMesh.
534 
535 
536  // (remote) processors where the tgt overlaps my src
537  DynamicList<label> tgtOverlapProcs(Pstream::nProcs());
538  // (remote) processors where the src overlaps my tgt
539  DynamicList<label> srcOverlapProcs(Pstream::nProcs());
540  for (const int procI : Pstream::allProcs())
541  {
542  if (procI != Pstream::myProcNo())
543  {
544  if (tgtBbs[procI].overlaps(srcBbs[Pstream::myProcNo()]))
545  {
546  tgtOverlapProcs.append(procI);
547  }
548  if (srcBbs[procI].overlaps(tgtBbs[Pstream::myProcNo()]))
549  {
550  srcOverlapProcs.append(procI);
551  }
552  }
553  }
554 
555 
556 
557  // Indices of tgtcells to send over to each processor
558  List<DynamicList<label>> tgtSendCells(Pstream::nProcs());
559  forAll(srcOverlapProcs, i)
560  {
561  label procI = srcOverlapProcs[i];
562  tgtSendCells[procI].reserve(tgtMesh.nCells()/srcOverlapProcs.size());
563  }
564 
565 
566  forAll(tgtCellMap, tgtCelli)
567  {
568  label celli = tgtCellMap[tgtCelli];
569  if (srcOverlapProcs.size())
570  {
571  treeBoundBox subBb(cellBb(mesh_, celli));
572  subBb.min() -= smallVec_;
573  subBb.max() += smallVec_;
574 
575  forAll(srcOverlapProcs, i)
576  {
577  label procI = srcOverlapProcs[i];
578  if (subBb.overlaps(srcBbs[procI]))
579  {
580  tgtSendCells[procI].append(tgtCelli);
581  }
582  }
583  }
584  }
585 
586  // Send target cell centres to overlapping processors
587  pBufs.clear();
588 
589  forAll(srcOverlapProcs, i)
590  {
591  label procI = srcOverlapProcs[i];
592  const labelList& cellIDs = tgtSendCells[procI];
593 
594  UOPstream os(procI, pBufs);
595  os << UIndirectList<point>(tgtCc, cellIDs);
596  }
597  pBufs.finishedSends();
598 
599  // Receive bits of target processors; find; send back
600  (void)srcMesh.tetBasePtIs();
601  forAll(tgtOverlapProcs, i)
602  {
603  label procI = tgtOverlapProcs[i];
604 
605  UIPstream is(procI, pBufs);
606  pointList samples(is);
607 
608  labelList donors(samples.size(), -1);
609  forAll(samples, sampleI)
610  {
611  const point& sample = samples[sampleI];
612  label srcCelli = srcMesh.findCell(sample, polyMesh::CELL_TETS);
613  if (srcCelli != -1 && allCellTypes[srcCellMap[srcCelli]] != HOLE)
614  {
615  donors[sampleI] = globalCells.toGlobal(srcCellMap[srcCelli]);
616  }
617  }
618 
619  // Use same pStreamBuffers to send back.
620  UOPstream os(procI, pBufs);
621  os << donors;
622  }
623  pBufs.finishedSends();
624 
625  forAll(srcOverlapProcs, i)
626  {
627  label procI = srcOverlapProcs[i];
628  const labelList& cellIDs = tgtSendCells[procI];
629 
630  UIPstream is(procI, pBufs);
631  labelList donors(is);
632 
633  if (donors.size() != cellIDs.size())
634  {
635  FatalErrorInFunction<< "problem : cellIDs:" << cellIDs.size()
636  << " donors:" << donors.size() << abort(FatalError);
637  }
638 
639  forAll(donors, donorI)
640  {
641  label globalDonor = donors[donorI];
642 
643  if (globalDonor != -1)
644  {
645  label celli = tgtCellMap[cellIDs[donorI]];
646 
647  // TBD: check for multiple donors. Maybe better one? For
648  // now check 'nearer' mesh
649  if (betterDonor(tgtI, allDonor[celli], srcI))
650  {
651  allStencil[celli].setSize(1);
652  allStencil[celli][0] = globalDonor;
653  allDonor[celli] = srcI;
654  }
655  }
656  }
657  }
658 }
659 
660 
661 //void Foam::cellCellStencils::inverseDistance::uncompactedRegionSplit
662 //(
663 // const fvMesh& mesh,
664 // const globalIndex& globalFaces,
665 // const label nZones,
666 // const labelList& zoneID,
667 // const labelList& cellTypes,
668 // const boolList& isBlockedFace,
669 // labelList& cellRegion
670 //) const
671 //{
672 // // Pass 1: locally seed 2 cells per zone (one unblocked, one blocked).
673 // // This avoids excessive numbers of front
674 //
675 // // Field on cells and faces.
676 // List<minData> cellData(mesh.nCells());
677 // List<minData> faceData(mesh.nFaces());
678 //
679 // // Take over blockedFaces by seeding a negative number
680 // // (so is always less than the decomposition)
681 //
682 // forAll(isBlockedFace, facei)
683 // {
684 // if (isBlockedFace[facei])
685 // {
686 // faceData[facei] = minData(-2);
687 // }
688 // }
689 //
690 //
691 // labelList seedFace(nZones, -1);
692 //
693 // const labelList& owner = mesh.faceOwner();
694 // const labelList& neighbour = mesh.faceNeighbour();
695 //
696 // forAll(owner, facei)
697 // {
698 // label own = owner[facei];
699 // if (seedFace[zoneID[own]] == -1)
700 // {
701 // if (cellTypes[own] != HOLE)
702 // {
703 // const cell& cFaces = mesh.cells()[own];
704 // forAll(cFaces, i)
705 // {
706 // if (!isBlockedFace[cFaces[i]])
707 // {
708 // seedFace[zoneID[own]] = cFaces[i];
709 // }
710 // }
711 // }
712 // }
713 // }
714 // forAll(neighbour, facei)
715 // {
716 // label nei = neighbour[facei];
717 // if (seedFace[zoneID[nei]] == -1)
718 // {
719 // if (cellTypes[nei] != HOLE)
720 // {
721 // const cell& cFaces = mesh.cells()[nei];
722 // forAll(cFaces, i)
723 // {
724 // if (!isBlockedFace[cFaces[i]])
725 // {
726 // seedFace[zoneID[nei]] = cFaces[i];
727 // }
728 // }
729 // }
730 // }
731 // }
732 //
733 // DynamicList<label> seedFaces(nZones);
734 // DynamicList<minData> seedData(seedFaces.size());
735 // forAll(seedFace, zonei)
736 // {
737 // if (seedFace[zonei] != -1)
738 // {
739 // seedFaces.append(seedFace[zonei]);
740 // seedData.append(minData(globalFaces.toGlobal(seedFace[zonei])));
741 // }
742 // }
743 //
744 // // Propagate information inwards
745 // FaceCellWave<minData> deltaCalc
746 // (
747 // mesh,
748 // List<labelPair>(),
749 // false, // disable walking through cyclicAMI for backwards
750 // // compatibility
751 // seedFaces,
752 // seedData,
753 // faceData,
754 // cellData,
755 // mesh.globalData().nTotalCells()+1
756 // );
757 //
758 // // Extract
759 // cellRegion.setSize(mesh.nCells());
760 // forAll(cellRegion, celli)
761 // {
762 // if (cellData[celli].valid(deltaCalc.data()))
763 // {
764 // cellRegion[celli] = cellData[celli].data();
765 // }
766 // else
767 // {
768 // // Unvisited cell -> only possible if surrounded by blocked faces.
769 // // If so make up region from any of the faces
770 // const cell& cFaces = mesh.cells()[celli];
771 // label facei = cFaces[0];
772 // cellRegion[celli] = globalFaces.toGlobal(facei);
773 // }
774 // }
775 //}
776 //Foam::autoPtr<Foam::globalIndex>
777 //Foam::cellCellStencils::inverseDistance::compactedRegionSplit
778 //(
779 // const fvMesh& mesh,
780 // const globalIndex& globalRegions,
781 // labelList& cellRegion
782 //) const
783 //{
784 // // Now our cellRegion will have
785 // // - non-local regions (i.e. originating from other processors)
786 // // - non-compact locally originating regions
787 // // so we'll need to compact
788 //
789 // // 4a: count per originating processor the number of regions
790 // labelList nOriginating(Pstream::nProcs(), Zero);
791 // {
792 // labelHashSet haveRegion(mesh.nCells()/8);
793 //
794 // forAll(cellRegion, celli)
795 // {
796 // label region = cellRegion[celli];
797 //
798 // // Count originating processor. Use isLocal as efficiency since
799 // // most cells are locally originating.
800 // if (globalRegions.isLocal(region))
801 // {
802 // if (haveRegion.insert(region))
803 // {
804 // nOriginating[Pstream::myProcNo()]++;
805 // }
806 // }
807 // else
808 // {
809 // label proci = globalRegions.whichProcID(region);
810 // if (haveRegion.insert(region))
811 // {
812 // nOriginating[proci]++;
813 // }
814 // }
815 // }
816 // }
817 //
818 // if (debug)
819 // {
820 // Pout<< "Counted " << nOriginating[Pstream::myProcNo()]
821 // << " local regions." << endl;
822 // }
823 //
824 //
825 // // Global numbering for compacted local regions
826 // autoPtr<globalIndex> globalCompactPtr
827 // (
828 // new globalIndex(nOriginating[Pstream::myProcNo()])
829 // );
830 // const globalIndex& globalCompact = globalCompactPtr();
831 //
832 //
833 // // 4b: renumber
834 // // Renumber into compact indices. Note that since we've already made
835 // // all regions global we now need a Map to store the compacting
836 // // information
837 // // instead of a labelList - otherwise we could have used a straight
838 // // labelList.
839 //
840 // // Local compaction map
841 // Map<label> globalToCompact(2*nOriginating[Pstream::myProcNo()]);
842 // // Remote regions we want the compact number for
843 // List<labelHashSet> nonLocal(Pstream::nProcs());
844 // forAll(nonLocal, proci)
845 // {
846 // if (proci != Pstream::myProcNo())
847 // {
848 // nonLocal[proci].resize(2*nOriginating[proci]);
849 // }
850 // }
851 //
852 // forAll(cellRegion, celli)
853 // {
854 // label region = cellRegion[celli];
855 // if (globalRegions.isLocal(region))
856 // {
857 // // Insert new compact region (if not yet present)
858 // globalToCompact.insert
859 // (
860 // region,
861 // globalCompact.toGlobal(globalToCompact.size())
862 // );
863 // }
864 // else
865 // {
866 // nonLocal[globalRegions.whichProcID(region)].insert(region);
867 // }
868 // }
869 //
870 //
871 // // Now we have all the local regions compacted. Now we need to get the
872 // // non-local ones from the processors to whom they are local.
873 // // Convert the nonLocal (labelHashSets) to labelLists.
874 //
875 // labelListList sendNonLocal(Pstream::nProcs());
876 // forAll(sendNonLocal, proci)
877 // {
878 // sendNonLocal[proci] = nonLocal[proci].toc();
879 // }
880 //
881 // if (debug)
882 // {
883 // forAll(sendNonLocal, proci)
884 // {
885 // Pout<< " from processor " << proci
886 // << " want " << sendNonLocal[proci].size()
887 // << " region numbers." << endl;
888 // }
889 // Pout<< endl;
890 // }
891 //
892 //
893 // // Get the wanted region labels into recvNonLocal
894 // labelListList recvNonLocal;
895 // Pstream::exchange<labelList, label>(sendNonLocal, recvNonLocal);
896 //
897 // // Now we have the wanted compact region labels that proci wants in
898 // // recvNonLocal[proci]. Construct corresponding list of compact
899 // // region labels to send back.
900 //
901 // labelListList sendWantedLocal(Pstream::nProcs());
902 // forAll(recvNonLocal, proci)
903 // {
904 // const labelList& nonLocal = recvNonLocal[proci];
905 // sendWantedLocal[proci].setSize(nonLocal.size());
906 //
907 // forAll(nonLocal, i)
908 // {
909 // sendWantedLocal[proci][i] = globalToCompact[nonLocal[i]];
910 // }
911 // }
912 //
913 //
914 // // Send back (into recvNonLocal)
915 // recvNonLocal.clear();
916 // Pstream::exchange<labelList, label>(sendWantedLocal, recvNonLocal);
917 // sendWantedLocal.clear();
918 //
919 // // Now recvNonLocal contains for every element in setNonLocal the
920 // // corresponding compact number. Insert these into the local compaction
921 // // map.
922 //
923 // forAll(recvNonLocal, proci)
924 // {
925 // const labelList& wantedRegions = sendNonLocal[proci];
926 // const labelList& compactRegions = recvNonLocal[proci];
927 //
928 // forAll(wantedRegions, i)
929 // {
930 // globalToCompact.insert(wantedRegions[i], compactRegions[i]);
931 // }
932 // }
933 //
934 // // Finally renumber the regions
935 // forAll(cellRegion, celli)
936 // {
937 // cellRegion[celli] = globalToCompact[cellRegion[celli]];
938 // }
939 //
940 // return globalCompactPtr;
941 //}
942 
943 
945 (
946  const globalIndex& globalCells,
947  const fvMesh& mesh,
948  const labelList& zoneID,
949  const labelListList& stencil,
951 ) const
952 {
953  const fvBoundaryMesh& pbm = mesh.boundary();
954  const labelList& own = mesh.faceOwner();
955  const labelList& nei = mesh.faceNeighbour();
956 
957 
958  // The input cellTypes will be
959  // - HOLE : cell part covered by other-mesh patch
960  // - INTERPOLATED : cell fully covered by other-mesh patch
961  // or next to 'overset' patch
962  // - CALCULATED : otherwise
963  //
964  // so we start a walk from our patches and any cell we cannot reach
965  // (because we walk is stopped by other-mesh patch) is a hole.
966 
967 
968  DebugInfo<< FUNCTION_NAME << " : Starting hole flood filling" << endl;
969 
970  DebugInfo<< FUNCTION_NAME << " : Starting hole cells : "
971  << findIndices(cellTypes, HOLE).size() << endl;
972 
973  boolList isBlockedFace(mesh.nFaces(), false);
974  label nBlocked = 0;
975 
976  for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
977  {
978  label ownType = cellTypes[own[faceI]];
979  label neiType = cellTypes[nei[faceI]];
980  if
981  (
982  (ownType == HOLE && neiType != HOLE)
983  || (ownType != HOLE && neiType == HOLE)
984  )
985  {
986  isBlockedFace[faceI] = true;
987  nBlocked++;
988  }
989  }
990  DebugInfo<< FUNCTION_NAME << " : Marked internal hole boundaries : "
991  << nBlocked << endl;
992 
993 
994  labelList nbrCellTypes;
995  syncTools::swapBoundaryCellList(mesh, cellTypes, nbrCellTypes);
996 
997  for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
998  {
999  label ownType = cellTypes[own[faceI]];
1000  label neiType = nbrCellTypes[faceI-mesh.nInternalFaces()];
1001 
1002  if
1003  (
1004  (ownType == HOLE && neiType != HOLE)
1005  || (ownType != HOLE && neiType == HOLE)
1006  )
1007  {
1008  isBlockedFace[faceI] = true;
1009  nBlocked++;
1010  }
1011  }
1012 
1013  DebugInfo<< FUNCTION_NAME << " : Marked all hole boundaries : "
1014  << nBlocked << endl;
1015 
1016  // Determine regions
1017  regionSplit cellRegion(mesh, isBlockedFace);
1018  const label nRegions = cellRegion.nRegions();
1019 
1020  //labelList cellRegion;
1021  //label nRegions = -1;
1022  //{
1023  // const globalIndex globalFaces(mesh.nFaces());
1024  // uncompactedRegionSplit
1025  // (
1026  // mesh,
1027  // globalFaces,
1028  // gMax(zoneID)+1,
1029  // zoneID,
1030  // cellTypes,
1031  // isBlockedFace,
1032  // cellRegion
1033  // );
1034  // autoPtr<globalIndex> globalRegions
1035  // (
1036  // compactedRegionSplit
1037  // (
1038  // mesh,
1039  // globalFaces,
1040  // cellRegion
1041  // )
1042  // );
1043  // nRegions = globalRegions().size();
1044  //}
1045  DebugInfo<< FUNCTION_NAME << " : Determined regions : "
1046  << nRegions << endl;
1047 
1048  //Info<< typeName << " : detected " << nRegions
1049  // << " mesh regions after overset" << nl << endl;
1050 
1051 
1052 
1053  // Now we'll have a mesh split according to where there are cells
1054  // covered by the other-side patches. See what we can reach from our
1055  // real patches
1056 
1057  // 0 : region not yet determined
1058  // 1 : borders blockage so is not ok (but can be overridden by real
1059  // patch)
1060  // 2 : has real patch in it so is reachable
1061  labelList regionType(nRegions, Zero);
1062 
1063 
1064  // See if any regions borders blockage. Note: isBlockedFace is already
1065  // parallel synchronised.
1066  {
1067  for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
1068  {
1069  if (isBlockedFace[faceI])
1070  {
1071  label ownRegion = cellRegion[own[faceI]];
1072 
1073  if (cellTypes[own[faceI]] != HOLE)
1074  {
1075  if (regionType[ownRegion] == 0)
1076  {
1077  regionType[ownRegion] = 1;
1078  }
1079  }
1080 
1081  label neiRegion = cellRegion[nei[faceI]];
1082 
1083  if (cellTypes[nei[faceI]] != HOLE)
1084  {
1085  if (regionType[neiRegion] == 0)
1086  {
1087  regionType[neiRegion] = 1;
1088  }
1089  }
1090  }
1091  }
1092  for
1093  (
1094  label faceI = mesh.nInternalFaces();
1095  faceI < mesh.nFaces();
1096  faceI++
1097  )
1098  {
1099  if (isBlockedFace[faceI])
1100  {
1101  label ownRegion = cellRegion[own[faceI]];
1102 
1103  if (regionType[ownRegion] == 0)
1104  {
1105  regionType[ownRegion] = 1;
1106  }
1107  }
1108  }
1109  }
1110 
1111 
1112  // Override with real patches
1113  forAll(pbm, patchI)
1114  {
1115  const fvPatch& fvp = pbm[patchI];
1116 
1117  if (isA<oversetFvPatch>(fvp))
1118  {}
1119  else if (!fvPatch::constraintType(fvp.type()))
1120  {
1121  const labelList& fc = fvp.faceCells();
1122  forAll(fc, i)
1123  {
1124  label regionI = cellRegion[fc[i]];
1125 
1126  if (cellTypes[fc[i]] != HOLE && regionType[regionI] != 2)
1127  {
1128  regionType[regionI] = 2;
1129  }
1130  }
1131  }
1132  }
1133 
1134  DebugInfo<< FUNCTION_NAME << " : Done local analysis" << endl;
1135 
1136  // Now we've handled
1137  // - cells next to blocked cells
1138  // - coupled boundaries
1139  // Only thing to handle is the interpolation between regions
1140 
1141 
1142  labelListList compactStencil(stencil);
1143  List<Map<label>> compactMap;
1144  mapDistribute map(globalCells, compactStencil, compactMap);
1145 
1146  DebugInfo<< FUNCTION_NAME << " : Converted stencil into compact form"
1147  << endl;
1148 
1149 
1150  while (true)
1151  {
1152  // Synchronise region status on processors
1153  // (could instead swap status through processor patches)
1154  Pstream::listCombineGather(regionType, maxEqOp<label>());
1155  Pstream::listCombineScatter(regionType);
1156 
1157  DebugInfo<< FUNCTION_NAME << " : Gathered region type" << endl;
1158 
1159  // Communicate region status through interpolative cells
1160  labelList cellRegionType(labelUIndList(regionType, cellRegion));
1161  map.distribute(cellRegionType);
1162 
1163  DebugInfo<< FUNCTION_NAME << " : Interpolated region type" << endl;
1164 
1165 
1166 
1167  label nChanged = 0;
1168  forAll(pbm, patchI)
1169  {
1170  const fvPatch& fvp = pbm[patchI];
1171 
1172  if (isA<oversetFvPatch>(fvp))
1173  {
1174  const labelUList& fc = fvp.faceCells();
1175  forAll(fc, i)
1176  {
1177  label cellI = fc[i];
1178  label regionI = cellRegion[cellI];
1179 
1180  if (regionType[regionI] != 2)
1181  {
1182  const labelList& slots = compactStencil[cellI];
1183  forAll(slots, i)
1184  {
1185  label otherType = cellRegionType[slots[i]];
1186 
1187  if (otherType == 2)
1188  {
1189  //Pout<< "Reachable through interpolation : "
1190  // << regionI << " at cell "
1191  // << mesh.cellCentres()[cellI] << endl;
1192  regionType[regionI] = 2;
1193  nChanged++;
1194  break;
1195  }
1196  }
1197  }
1198  }
1199  }
1200  }
1201 
1202  reduce(nChanged, sumOp<label>());
1203  DebugInfo<< FUNCTION_NAME << " : Determined regions changed : "
1204  << nChanged << endl;
1205 
1206  if (nChanged == 0)
1207  {
1208  break;
1209  }
1210  }
1211 
1212 
1213  // See which regions have not been visited (regionType == 1)
1214  forAll(cellRegion, cellI)
1215  {
1216  label type = regionType[cellRegion[cellI]];
1217  if (type == 1 && cellTypes[cellI] != HOLE)
1218  {
1219  cellTypes[cellI] = HOLE;
1220  }
1221  }
1222  DebugInfo<< FUNCTION_NAME << " : Finished hole flood filling" << endl;
1223 }
1224 
1225 
1228  const label cellI,
1229  const scalar wantedFraction,
1230  bitSet& isFront,
1231  scalarField& fraction
1232 ) const
1233 {
1234  const cell& cFaces = mesh_.cells()[cellI];
1235  forAll(cFaces, i)
1236  {
1237  label nbrFacei = cFaces[i];
1238  if (fraction[nbrFacei] < wantedFraction)
1239  {
1240  fraction[nbrFacei] = wantedFraction;
1241  isFront.set(nbrFacei);
1242  }
1243  }
1244 }
1245 
1246 
1249  const scalar layerRelax,
1250  const labelListList& allStencil,
1251  labelList& allCellTypes,
1252  scalarField& allWeight
1253 ) const
1254 {
1255  // Current front
1256  bitSet isFront(mesh_.nFaces());
1257 
1258  const fvBoundaryMesh& fvm = mesh_.boundary();
1259 
1260 
1261  // 'overset' patches
1262 
1263  forAll(fvm, patchI)
1264  {
1265  if (isA<oversetFvPatch>(fvm[patchI]))
1266  {
1267  const labelList& fc = fvm[patchI].faceCells();
1268  forAll(fc, i)
1269  {
1270  label cellI = fc[i];
1271  if (allCellTypes[cellI] == INTERPOLATED)
1272  {
1273  // Note that acceptors might have been marked hole if
1274  // there are no donors in which case we do not want to
1275  // walk this out. This is an extreme situation.
1276  isFront.set(fvm[patchI].start()+i);
1277  }
1278  }
1279  }
1280  }
1281 
1282 
1283  // Outside of 'hole' region
1284  {
1285  const labelList& own = mesh_.faceOwner();
1286  const labelList& nei = mesh_.faceNeighbour();
1287 
1288  for (label faceI = 0; faceI < mesh_.nInternalFaces(); faceI++)
1289  {
1290  label ownType = allCellTypes[own[faceI]];
1291  label neiType = allCellTypes[nei[faceI]];
1292  if
1293  (
1294  (ownType == HOLE && neiType != HOLE)
1295  || (ownType != HOLE && neiType == HOLE)
1296  )
1297  {
1298  //Pout<< "Front at face:" << faceI
1299  // << " at:" << mesh_.faceCentres()[faceI] << endl;
1300  isFront.set(faceI);
1301  }
1302  }
1303 
1304  labelList nbrCellTypes;
1305  syncTools::swapBoundaryCellList(mesh_, allCellTypes, nbrCellTypes);
1306 
1307  for
1308  (
1309  label faceI = mesh_.nInternalFaces();
1310  faceI < mesh_.nFaces();
1311  faceI++
1312  )
1313  {
1314  label ownType = allCellTypes[own[faceI]];
1315  label neiType = nbrCellTypes[faceI-mesh_.nInternalFaces()];
1316 
1317  if
1318  (
1319  (ownType == HOLE && neiType != HOLE)
1320  || (ownType != HOLE && neiType == HOLE)
1321  )
1322  {
1323  //Pout<< "Front at coupled face:" << faceI
1324  // << " at:" << mesh_.faceCentres()[faceI] << endl;
1325  isFront.set(faceI);
1326  }
1327  }
1328  }
1329 
1330 
1331  // Current interpolation fraction
1332  scalarField fraction(mesh_.nFaces(), Zero);
1333 
1334  forAll(isFront, faceI)
1335  {
1336  if (isFront.test(faceI))
1337  {
1338  fraction[faceI] = 1.0;
1339  }
1340  }
1341 
1342 
1343  while (returnReduce(isFront.any(), orOp<bool>()))
1344  {
1345  // Interpolate cells on front
1346  bitSet newIsFront(mesh_.nFaces());
1347  scalarField newFraction(fraction);
1348  forAll(isFront, faceI)
1349  {
1350  if (isFront.test(faceI))
1351  {
1352  label own = mesh_.faceOwner()[faceI];
1353  if (allCellTypes[own] != HOLE)
1354  {
1355  if (allWeight[own] < fraction[faceI])
1356  {
1357  // Cell wants to become interpolated (if sufficient
1358  // stencil, otherwise becomes hole)
1359  if (allStencil[own].size())
1360  {
1361  allWeight[own] = fraction[faceI];
1362  allCellTypes[own] = INTERPOLATED;
1363  // Add faces of cell (with lower weight) as new
1364  // front
1365  seedCell
1366  (
1367  own,
1368  fraction[faceI]-layerRelax,
1369  newIsFront,
1370  newFraction
1371  );
1372  }
1373  else
1374  {
1375  allWeight[own] = 0.0;
1376  allCellTypes[own] = HOLE;
1377  // Add faces of cell as new front
1378  seedCell
1379  (
1380  own,
1381  1.0,
1382  newIsFront,
1383  newFraction
1384  );
1385  }
1386  }
1387  }
1388  if (mesh_.isInternalFace(faceI))
1389  {
1390  label nei = mesh_.faceNeighbour()[faceI];
1391  if (allCellTypes[nei] != HOLE)
1392  {
1393  if (allWeight[nei] < fraction[faceI])
1394  {
1395  if (allStencil[nei].size())
1396  {
1397  allWeight[nei] = fraction[faceI];
1398  allCellTypes[nei] = INTERPOLATED;
1399  seedCell
1400  (
1401  nei,
1402  fraction[faceI]-layerRelax,
1403  newIsFront,
1404  newFraction
1405  );
1406  }
1407  else
1408  {
1409  allWeight[nei] = 0.0;
1410  allCellTypes[nei] = HOLE;
1411  seedCell
1412  (
1413  nei,
1414  1.0,
1415  newIsFront,
1416  newFraction
1417  );
1418  }
1419  }
1420  }
1421  }
1422  }
1423  }
1424 
1425  syncTools::syncFaceList(mesh_, newIsFront, orEqOp<unsigned int>());
1426  syncTools::syncFaceList(mesh_, newFraction, maxEqOp<scalar>());
1427 
1428  isFront.transfer(newIsFront);
1429  fraction.transfer(newFraction);
1430  }
1431 }
1432 
1433 
1436  const point& sample,
1437  const pointList& donorCcs,
1438  scalarList& weights
1439 ) const
1440 {
1441  // Inverse-distance weighting
1442 
1443  weights.setSize(donorCcs.size());
1444  scalar sum = 0.0;
1445  forAll(donorCcs, i)
1446  {
1447  scalar d = mag(sample-donorCcs[i]);
1448 
1449  if (d > ROOTVSMALL)
1450  {
1451  weights[i] = 1.0/d;
1452  sum += weights[i];
1453  }
1454  else
1455  {
1456  // Short circuit
1457  weights = 0.0;
1458  weights[i] = 1.0;
1459  return;
1460  }
1461  }
1462  forAll(weights, i)
1463  {
1464  weights[i] /= sum;
1465  }
1466 }
1467 
1468 
1471  const globalIndex& globalCells
1472 )
1473 {
1474  // Send cell centre back to donor
1475  // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1476  // The complication is that multiple acceptors need the same donor
1477  // (but with different weights obviously)
1478  // So we do multi-pass:
1479  // - send over cc of acceptor for which we want stencil.
1480  // Consistently choose the acceptor with smallest magSqr in case of
1481  // multiple acceptors for the containing cell/donor.
1482  // - find the cell-cells and weights for the donor
1483  // - send back together with the acceptor cc
1484  // - use the acceptor cc to see if it was 'me' that sent it. If so
1485  // mark me as complete so it doesn't get involved in the next loop.
1486  // - loop until all resolved.
1487 
1488  // Special value for unused points
1489  const vector greatPoint(GREAT, GREAT, GREAT);
1490 
1491  boolList isValidDonor(mesh_.nCells(), true);
1492  forAll(cellTypes_, celli)
1493  {
1494  if (cellTypes_[celli] == HOLE)
1495  {
1496  isValidDonor[celli] = false;
1497  }
1498  }
1499 
1500 
1501  // Has acceptor been handled already?
1502  bitSet doneAcceptor(interpolationCells_.size());
1503 
1504  while (true)
1505  {
1506  pointField samples(cellInterpolationMap().constructSize(), greatPoint);
1507 
1508  // Fill remote slots (override old content). We'll find out later
1509  // on which one has won and mark this one in doneAcceptor.
1510  label nSamples = 0;
1511  forAll(interpolationCells_, i)
1512  {
1513  if (!doneAcceptor[i])
1514  {
1515  label cellI = interpolationCells_[i];
1516  const point& cc = mesh_.cellCentres()[cellI];
1517  const labelList& slots = cellStencil_[cellI];
1518 
1519  if (slots.size() != 1)
1520  {
1521  FatalErrorInFunction<< "Problem:" << slots
1522  << abort(FatalError);
1523  }
1524 
1525  forAll(slots, slotI)
1526  {
1527  label elemI = slots[slotI];
1528  //Pout<< " acceptor:" << cellI
1529  // << " at:" << mesh_.cellCentres()[cellI]
1530  // << " global:" << globalCells.toGlobal(cellI)
1531  // << " found in donor:" << elemI << endl;
1532  minMagSqrEqOp<point>()(samples[elemI], cc);
1533  }
1534  nSamples++;
1535  }
1536  }
1537 
1538 
1539  if (returnReduce(nSamples, sumOp<label>()) == 0)
1540  {
1541  break;
1542  }
1543 
1544  // Send back to donor. Make sure valid point takes priority
1545  mapDistributeBase::distribute<point, minMagSqrEqOp<point>, flipOp>
1546  (
1547  Pstream::commsTypes::nonBlocking,
1548  List<labelPair>(),
1549  mesh_.nCells(),
1550  cellInterpolationMap().constructMap(),
1551  false,
1552  cellInterpolationMap().subMap(),
1553  false,
1554  samples,
1555  greatPoint, // nullValue
1557  flipOp(), // negateOp
1558  UPstream::msgType(),
1559  cellInterpolationMap().comm()
1560  );
1561 
1562  // All the donor cells will now have a valid cell centre. Construct a
1563  // stencil for these.
1564 
1565  DynamicList<label> donorCells(mesh_.nCells());
1566  forAll(samples, cellI)
1567  {
1568  if (samples[cellI] != greatPoint)
1569  {
1570  donorCells.append(cellI);
1571  }
1572  }
1573 
1574 
1575  // Get neighbours (global cell and centre) of donorCells.
1576  labelListList donorCellCells(mesh_.nCells());
1577  pointListList donorCellCentres(mesh_.nCells());
1578  globalCellCells
1579  (
1580  globalCells,
1581  mesh_,
1582  isValidDonor,
1583  donorCells,
1584  donorCellCells,
1585  donorCellCentres
1586  );
1587 
1588  // Determine the weights.
1589  scalarListList donorWeights(mesh_.nCells());
1590  forAll(donorCells, i)
1591  {
1592  label cellI = donorCells[i];
1593  const pointList& donorCentres = donorCellCentres[cellI];
1594  stencilWeights
1595  (
1596  samples[cellI],
1597  donorCentres,
1598  donorWeights[cellI]
1599  );
1600  }
1601 
1602  // Transfer the information back to the acceptor:
1603  // - donorCellCells : stencil (with first element the original donor)
1604  // - donorWeights : weights for donorCellCells
1605  cellInterpolationMap().distribute(donorCellCells);
1606  cellInterpolationMap().distribute(donorWeights);
1607  cellInterpolationMap().distribute(samples);
1608 
1609  // Check which acceptor has won and transfer
1610  forAll(interpolationCells_, i)
1611  {
1612  if (!doneAcceptor[i])
1613  {
1614  label cellI = interpolationCells_[i];
1615  const labelList& slots = cellStencil_[cellI];
1616 
1617  if (slots.size() != 1)
1618  {
1619  FatalErrorInFunction << "Problem:" << slots
1620  << abort(FatalError);
1621  }
1622 
1623  label slotI = slots[0];
1624 
1625  // Important: check if the stencil is actually for this cell
1626  if (samples[slotI] == mesh_.cellCentres()[cellI])
1627  {
1628  cellStencil_[cellI].transfer(donorCellCells[slotI]);
1629  cellInterpolationWeights_[cellI].transfer
1630  (
1631  donorWeights[slotI]
1632  );
1633  // Mark cell as being done so it does not get sent over
1634  // again.
1635  doneAcceptor.set(i);
1636  }
1637  }
1638  }
1639  }
1640 
1641  // Re-do the mapDistribute
1642  List<Map<label>> compactMap;
1643  cellInterpolationMap_.reset
1644  (
1645  new mapDistribute
1646  (
1647  globalCells,
1648  cellStencil_,
1649  compactMap
1650  )
1651  );
1652 }
1653 
1654 
1655 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1656 
1657 Foam::cellCellStencils::inverseDistance::inverseDistance
1659  const fvMesh& mesh,
1660  const dictionary& dict,
1661  const bool doUpdate
1662 )
1663 :
1665  dict_(dict),
1666  smallVec_(Zero),
1667  cellTypes_(labelList(mesh.nCells(), CALCULATED)),
1668  interpolationCells_(0),
1669  cellInterpolationMap_(),
1670  cellStencil_(0),
1671  cellInterpolationWeights_(0),
1672  cellInterpolationWeight_
1673  (
1674  IOobject
1675  (
1676  "cellInterpolationWeight",
1677  mesh_.facesInstance(),
1678  mesh_,
1679  IOobject::NO_READ,
1680  IOobject::NO_WRITE,
1681  false
1682  ),
1683  mesh_,
1685  zeroGradientFvPatchScalarField::typeName
1686  )
1687 {
1688  // Protect local fields from interpolation
1689  nonInterpolatedFields_.insert("cellInterpolationWeight");
1690  nonInterpolatedFields_.insert("cellTypes");
1691  nonInterpolatedFields_.insert("maxMagWeight");
1692 
1693  // For convenience also suppress frequently used displacement field
1694  nonInterpolatedFields_.insert("cellDisplacement");
1695  nonInterpolatedFields_.insert("grad(cellDisplacement)");
1696  const word w("snGradCorr(cellDisplacement)");
1697  const word d("((viscosity*faceDiffusivity)*magSf)");
1698  nonInterpolatedFields_.insert("surfaceIntegrate(("+d+"*"+w+"))");
1699 
1700  // Read zoneID
1701  this->zoneID();
1702 
1703  // Read old-time cellTypes
1704  IOobject io
1705  (
1706  "cellTypes",
1707  mesh_.time().timeName(),
1708  mesh_,
1709  IOobject::READ_IF_PRESENT,
1710  IOobject::NO_WRITE,
1711  false
1712  );
1713  if (io.typeHeaderOk<volScalarField>(true))
1714  {
1715  if (debug)
1716  {
1717  Pout<< "Reading cellTypes from time " << mesh_.time().timeName()
1718  << endl;
1719  }
1720 
1721  const volScalarField volCellTypes(io, mesh_);
1722  forAll(volCellTypes, celli)
1723  {
1724  // Round to integer
1725  cellTypes_[celli] = volCellTypes[celli];
1726  }
1727  }
1728 
1729  if (doUpdate)
1730  {
1731  update();
1732  }
1733 }
1734 
1735 
1736 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
1737 
1739 {}
1740 
1741 
1742 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1743 
1745 {
1746  scalar layerRelax(dict_.getOrDefault("layerRelax", 1.0));
1747 
1748  scalar tol = dict_.getOrDefault("tolerance", 1e-10);
1749  smallVec_ = mesh_.bounds().span()*tol;
1750 
1751  const labelIOList& zoneID = this->zoneID();
1752 
1753  label nZones = gMax(zoneID)+1;
1755  forAll(zoneID, cellI)
1756  {
1757  nCellsPerZone[zoneID[cellI]]++;
1758  }
1761 
1762 
1763  const boundBox& allBb(mesh_.bounds());
1764 
1765 
1768 
1769  // Determine zone meshes and bounding boxes
1770  {
1771  // Per processor, per zone the bounding box
1773  procBb[Pstream::myProcNo()].setSize(nZones);
1774 
1775  forAll(meshParts, zonei)
1776  {
1777  meshParts.set
1778  (
1779  zonei,
1780  new fvMeshSubset(mesh_, zonei, zoneID)
1781  );
1782  const fvMesh& subMesh = meshParts[zonei].subMesh();
1783 
1784  // Trigger early evaluation of mesh dimension (in case there are
1785  // zero cells in mesh)
1786  (void)subMesh.nGeometricD();
1787 
1788  if (subMesh.nPoints())
1789  {
1790  procBb[Pstream::myProcNo()][zonei] =
1791  treeBoundBox(subMesh.points());
1792  procBb[Pstream::myProcNo()][zonei].inflate(1e-6);
1793  }
1794  else
1795  {
1796  // No part of zone on this processor. Make up bb.
1797  procBb[Pstream::myProcNo()][zonei] = treeBoundBox
1798  (
1799  allBb.min() - 2*allBb.span(),
1800  allBb.min() - allBb.span()
1801  );
1802  procBb[Pstream::myProcNo()][zonei].inflate(1e-6);
1803  }
1804  }
1805 
1806  Pstream::gatherList(procBb);
1807  Pstream::scatterList(procBb);
1808 
1809  // Move local bounding boxes to per-mesh indexing
1810  forAll(meshBb, zoneI)
1811  {
1812  treeBoundBoxList& bbs = meshBb[zoneI];
1813  bbs.setSize(Pstream::nProcs());
1814  forAll(procBb, procI)
1815  {
1816  bbs[procI] = procBb[procI][zoneI];
1817  }
1818  }
1819  }
1820 
1821 
1822  // Determine patch bounding boxes. These are either global and provided
1823  // by the user or processor-local as a copy of the mesh bounding box.
1824 
1825  List<treeBoundBoxList> patchBb(nZones);
1826  List<labelVector> patchDivisions(nZones);
1827  PtrList<PackedList<2>> patchParts(nZones);
1828  labelList allPatchTypes(mesh_.nCells(), OTHER);
1829 
1830  {
1831  treeBoundBox globalPatchBb;
1832  if (dict_.readIfPresent("searchBox", globalPatchBb))
1833  {
1834  // All processors, all zones have the same bounding box
1835  patchBb = treeBoundBoxList(Pstream::nProcs(), globalPatchBb);
1836  }
1837  else
1838  {
1839  // Use the meshBb (differing per zone, per processor)
1840  patchBb = meshBb;
1841  }
1842  }
1843 
1844  {
1845  labelVector globalDivs;
1846  if (dict_.readIfPresent("searchBoxDivisions", globalDivs))
1847  {
1848  patchDivisions = globalDivs;
1849  }
1850  else
1851  {
1852  const labelVector& dim = mesh_.geometricD();
1853  label nDivs = -1;
1854  if (mesh_.nGeometricD() == 1)
1855  {
1856  nDivs = mesh_.nCells();
1857  }
1858  else if (mesh_.nGeometricD() == 2)
1859  {
1860  nDivs = label(Foam::sqrt(scalar(mesh_.nCells())));
1861  }
1862  else
1863  {
1864  nDivs = label(Foam::cbrt(scalar(mesh_.nCells())));
1865  }
1866 
1867  labelVector v(nDivs, nDivs, nDivs);
1868  forAll(dim, i)
1869  {
1870  if (dim[i] == -1)
1871  {
1872  v[i] = 1;
1873  }
1874  }
1875  patchDivisions = v;
1876  }
1877  }
1878 
1879  forAll(patchParts, zoneI)
1880  {
1881  patchParts.set
1882  (
1883  zoneI,
1884  new PackedList<2>
1885  (
1886  patchDivisions[zoneI][0]
1887  *patchDivisions[zoneI][1]
1888  *patchDivisions[zoneI][2]
1889  )
1890  );
1891  markBoundaries
1892  (
1893  meshParts[zoneI].subMesh(),
1894  smallVec_,
1895 
1896  patchBb[zoneI][Pstream::myProcNo()],
1897  patchDivisions[zoneI],
1898  patchParts[zoneI],
1899 
1900  meshParts[zoneI].cellMap(),
1901  allPatchTypes
1902  );
1903  }
1904 
1905 
1906  // Print a bit
1907  {
1908  Info<< type() << " : detected " << nZones
1909  << " mesh regions" << endl;
1910  Info<< incrIndent;
1911  forAll(nCellsPerZone, zoneI)
1912  {
1913  Info<< indent<< "zone:" << zoneI
1914  << " nCells:" << nCellsPerZone[zoneI]
1915  << " voxels:" << patchDivisions[zoneI]
1916  << " bb:" << patchBb[zoneI][Pstream::myProcNo()]
1917  << endl;
1918  }
1919  Info<< decrIndent;
1920  }
1921 
1922 
1923  // Current best guess for cells. Includes best stencil. Weights should
1924  // add up to volume.
1925  labelList allCellTypes(mesh_.nCells(), CALCULATED);
1926  labelListList allStencil(mesh_.nCells());
1927  // zoneID of donor
1928  labelList allDonorID(mesh_.nCells(), -1);
1929 
1930  const globalIndex globalCells(mesh_.nCells());
1931 
1933 
1934  // Mark holes (in allCellTypes)
1935  for (label srcI = 0; srcI < meshParts.size()-1; srcI++)
1936  {
1937  for (label tgtI = srcI+1; tgtI < meshParts.size(); tgtI++)
1938  {
1939  markPatchesAsHoles
1940  (
1941  pBufs,
1942 
1943  meshParts,
1944 
1945  patchBb,
1946  patchDivisions,
1947  patchParts,
1948 
1949  srcI,
1950  tgtI,
1951  allCellTypes
1952  );
1953  markPatchesAsHoles
1954  (
1955  pBufs,
1956 
1957  meshParts,
1958 
1959  patchBb,
1960  patchDivisions,
1961  patchParts,
1962 
1963  tgtI,
1964  srcI,
1965  allCellTypes
1966  );
1967  }
1968  }
1969 
1970  // Find donors (which are not holes) in allStencil, allDonorID
1971  for (label srcI = 0; srcI < meshParts.size()-1; srcI++)
1972  {
1973  for (label tgtI = srcI+1; tgtI < meshParts.size(); tgtI++)
1974  {
1975  markDonors
1976  (
1977  globalCells,
1978  pBufs,
1979  meshParts,
1980  meshBb,
1981  allCellTypes,
1982 
1983  tgtI,
1984  srcI,
1985  allStencil,
1986  allDonorID
1987  );
1988  markDonors
1989  (
1990  globalCells,
1991  pBufs,
1992  meshParts,
1993  meshBb,
1994  allCellTypes,
1995 
1996  srcI,
1997  tgtI,
1998  allStencil,
1999  allDonorID
2000  );
2001  }
2002  }
2003 
2004  if (debug)
2005  {
2006  tmp<volScalarField> tfld
2007  (
2008  createField(mesh_, "allCellTypes", allCellTypes)
2009  );
2010  tfld().write();
2011  }
2012 
2013  // Use the patch types and weights to decide what to do
2014  forAll(allPatchTypes, cellI)
2015  {
2016  if (allCellTypes[cellI] != HOLE)
2017  {
2018  switch (allPatchTypes[cellI])
2019  {
2020  case OVERSET:
2021  {
2022  // Require interpolation. See if possible.
2023 
2024  if (allStencil[cellI].size())
2025  {
2026  allCellTypes[cellI] = INTERPOLATED;
2027  }
2028  else
2029  {
2030  // If there are no donors we can either set the
2031  // acceptor cell to 'hole' i.e. nothing gets calculated
2032  // if the acceptor cells go outside the donor meshes or
2033  // we can set it to 'calculated' to have something
2034  // like an acmi type behaviour where only covered
2035  // acceptor cell use the interpolation and non-covered
2036  // become calculated. Uncomment below line. Note: this
2037  // should be switchable?
2038  //allCellTypes[cellI] = CALCULATED;
2039 
2040  allCellTypes[cellI] = HOLE;
2041  }
2042  }
2043  }
2044  }
2045  }
2046 
2047  if (debug)
2048  {
2049  tmp<volScalarField> tfld
2050  (
2051  createField(mesh_, "allCellTypes_patch", allCellTypes)
2052  );
2053  tfld().write();
2054  }
2055 
2056 
2057  // Check previous iteration cellTypes_ for any hole->calculated changes
2058  // If so set the cell either to interpolated (if there are donors) or
2059  // holes (if there are no donors). Note that any interpolated cell might
2060  // still be overwritten by the flood filling
2061  {
2062  label nCalculated = 0;
2063 
2064  forAll(cellTypes_, celli)
2065  {
2066  if (allCellTypes[celli] == CALCULATED && cellTypes_[celli] == HOLE)
2067  {
2068  if (allStencil[celli].size() == 0)
2069  {
2070  // Reset to hole
2071  allCellTypes[celli] = HOLE;
2072  allStencil[celli].clear();
2073  }
2074  else
2075  {
2076  allCellTypes[celli] = INTERPOLATED;
2077  nCalculated++;
2078  }
2079  }
2080  }
2081 
2082  if (debug)
2083  {
2084  Pout<< "Detected " << nCalculated << " cells changing from hole"
2085  << " to calculated. Changed to interpolated"
2086  << endl;
2087  }
2088  }
2089 
2090 
2091  // Mark unreachable bits
2092  findHoles(globalCells, mesh_, zoneID, allStencil, allCellTypes);
2093 
2094  if (debug)
2095  {
2096  tmp<volScalarField> tfld
2097  (
2098  createField(mesh_, "allCellTypes_hole", allCellTypes)
2099  );
2100  tfld().write();
2101  }
2102  if (debug)
2103  {
2104  labelList stencilSize(mesh_.nCells());
2105  forAll(allStencil, celli)
2106  {
2107  stencilSize[celli] = allStencil[celli].size();
2108  }
2109  tmp<volScalarField> tfld
2110  (
2111  createField(mesh_, "allStencil_hole", stencilSize)
2112  );
2113  tfld().write();
2114  }
2115 
2116 
2117  // Add buffer interpolation layer(s) around holes
2118  scalarField allWeight(mesh_.nCells(), Zero);
2119  walkFront(layerRelax, allStencil, allCellTypes, allWeight);
2120 
2121  if (debug)
2122  {
2123  tmp<volScalarField> tfld
2124  (
2125  createField(mesh_, "allCellTypes_front", allCellTypes)
2126  );
2127  tfld().write();
2128  }
2129 
2130 
2131  // Convert cell-cell addressing to stencil in compact notation
2132 
2133  cellTypes_.transfer(allCellTypes);
2134  cellStencil_.setSize(mesh_.nCells());
2135  cellInterpolationWeights_.setSize(mesh_.nCells());
2136  DynamicList<label> interpolationCells;
2137  forAll(cellTypes_, cellI)
2138  {
2139  if (cellTypes_[cellI] == INTERPOLATED)
2140  {
2141  cellStencil_[cellI].transfer(allStencil[cellI]);
2142  cellInterpolationWeights_[cellI].setSize(1);
2143  cellInterpolationWeights_[cellI][0] = 1.0;
2144  interpolationCells.append(cellI);
2145  }
2146  else
2147  {
2148  cellStencil_[cellI].clear();
2149  cellInterpolationWeights_[cellI].clear();
2150  }
2151  }
2152  interpolationCells_.transfer(interpolationCells);
2153 
2154  List<Map<label>> compactMap;
2155  cellInterpolationMap_.reset
2156  (
2157  new mapDistribute(globalCells, cellStencil_, compactMap)
2158  );
2159  cellInterpolationWeight_.transfer(allWeight);
2161  <
2164  >(cellInterpolationWeight_.boundaryFieldRef(), false);
2165 
2166 
2167  if (debug&2)
2168  {
2169  // Dump mesh
2170  mesh_.time().write();
2171 
2172  // Dump stencil
2173  mkDir(mesh_.time().timePath());
2174  OBJstream str(mesh_.time().timePath()/"injectionStencil.obj");
2175  Pout<< type() << " : dumping injectionStencil to "
2176  << str.name() << endl;
2177  pointField cc(mesh_.cellCentres());
2178  cellInterpolationMap().distribute(cc);
2179 
2180  forAll(cellStencil_, celli)
2181  {
2182  const labelList& slots = cellStencil_[celli];
2183  if (slots.size())
2184  {
2185  const point& accCc = mesh_.cellCentres()[celli];
2186  forAll(slots, i)
2187  {
2188  const point& donorCc = cc[slots[i]];
2189  str.write(linePointRef(accCc, 0.1*accCc+0.9*donorCc));
2190  }
2191  }
2192  }
2193  }
2194 
2195 
2196  // Extend stencil to get inverse distance weighted neighbours
2197  createStencil(globalCells);
2198 
2199 
2200  if (debug&2)
2201  {
2202  // Dump weight
2203  cellInterpolationWeight_.instance() = mesh_.time().timeName();
2204  cellInterpolationWeight_.write();
2205 
2206  // Dump max weight
2207  {
2208  scalarField maxMagWeight(mesh_.nCells(), Zero);
2209  forAll(cellStencil_, celli)
2210  {
2211  const scalarList& wghts = cellInterpolationWeights_[celli];
2212  forAll(wghts, i)
2213  {
2214  if (mag(wghts[i]) > mag(maxMagWeight[celli]))
2215  {
2216  maxMagWeight[celli] = wghts[i];
2217  }
2218  }
2219  if (mag(maxMagWeight[celli]) > 1)
2220  {
2221  const pointField& cc = mesh_.cellCentres();
2222  Pout<< "cell:" << celli
2223  << " at:" << cc[celli]
2224  << " zone:" << zoneID[celli]
2225  << " donors:" << cellStencil_[celli]
2226  << " weights:" << wghts
2227  << " coords:"
2228  << UIndirectList<point>(cc, cellStencil_[celli])
2229  << " donorZone:"
2230  << UIndirectList<label>(zoneID, cellStencil_[celli])
2231  << endl;
2232  }
2233  }
2234  tmp<volScalarField> tfld
2235  (
2236  createField(mesh_, "maxMagWeight", maxMagWeight)
2237  );
2239  <
2242  >(tfld.ref().boundaryFieldRef(), false);
2243  tfld().write();
2244  }
2245 
2246  // Dump cell types
2247  {
2248  tmp<volScalarField> tfld
2249  (
2250  createField(mesh_, "cellTypes", cellTypes_)
2251  );
2252  //tfld.ref().correctBoundaryConditions();
2254  <
2257  >(tfld.ref().boundaryFieldRef(), false);
2258  tfld().write();
2259  }
2260 
2261 
2262  // Dump stencil, one per zone
2263  mkDir(mesh_.time().timePath());
2264  pointField cc(mesh_.cellCentres());
2265  cellInterpolationMap().distribute(cc);
2266  forAll(meshParts, zonei)
2267  {
2268  OBJstream str
2269  (
2270  mesh_.time().timePath()
2271  + "/stencil_" + name(zonei) + ".obj"
2272  );
2273  Pout<< type() << " : dumping to " << str.name() << endl;
2274 
2275  const labelList& subMeshCellMap = meshParts[zonei].cellMap();
2276 
2277  forAll(subMeshCellMap, subcelli)
2278  {
2279  const label celli = subMeshCellMap[subcelli];
2280  const labelList& slots = cellStencil_[celli];
2281  const point& accCc = mesh_.cellCentres()[celli];
2282  forAll(slots, i)
2283  {
2284  const point& donorCc = cc[slots[i]];
2285  str.write(linePointRef(accCc, 0.1*accCc+0.9*donorCc));
2286  }
2287  }
2288  }
2289  }
2290 
2291  // Print some stats
2292  {
2293  labelList nCells(count(3, cellTypes_));
2294 
2295  label nLocal = 0;
2296  label nMixed = 0;
2297  label nRemote = 0;
2298  forAll(interpolationCells_, i)
2299  {
2300  label celli = interpolationCells_[i];
2301  const labelList& slots = cellStencil_[celli];
2302 
2303  bool hasLocal = false;
2304  bool hasRemote = false;
2305 
2306  forAll(slots, sloti)
2307  {
2308  if (slots[sloti] >= mesh_.nCells())
2309  {
2310  hasRemote = true;
2311  }
2312  else
2313  {
2314  hasLocal = true;
2315  }
2316  }
2317 
2318  if (hasRemote)
2319  {
2320  if (!hasLocal)
2321  {
2322  nRemote++;
2323  }
2324  else
2325  {
2326  nMixed++;
2327  }
2328  }
2329  else if (hasLocal)
2330  {
2331  nLocal++;
2332  }
2333  }
2334  reduce(nLocal, sumOp<label>());
2335  reduce(nMixed, sumOp<label>());
2336  reduce(nRemote, sumOp<label>());
2337 
2338  Info<< "Overset analysis : nCells : "
2339  << returnReduce(cellTypes_.size(), sumOp<label>()) << nl
2340  << incrIndent
2341  << indent << "calculated : " << nCells[CALCULATED] << nl
2342  << indent << "interpolated : " << nCells[INTERPOLATED]
2343  << " (interpolated from local:" << nLocal
2344  << " mixed local/remote:" << nMixed
2345  << " remote:" << nRemote << ")" << nl
2346  << indent << "hole : " << nCells[HOLE] << nl
2347  << decrIndent << endl;
2348  }
2349 
2350  // Tbd: detect if anything changed. Most likely it did!
2351  return true;
2352 }
2353 
2354 
2355 // ************************************************************************* //
Foam::cellCellStencils::inverseDistance::~inverseDistance
virtual ~inverseDistance()
Destructor.
Definition: inverseDistanceCellCellStencil.C:1738
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::PrimitivePatch::points
const Field< point_type > & points() const noexcept
Return reference to global points.
Definition: PrimitivePatch.H:299
nZones
label nZones
Definition: interpolatedFaces.H:24
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
Foam::polyMesh::points
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1069
Foam::IOobject
Defines the attributes of an object for which implicit objectRegistry management is supported,...
Definition: IOobject.H:169
Foam::treeBoundBox::overlaps
bool overlaps(const boundBox &bb) const
Overlaps other bounding box?
Definition: boundBoxI.H:221
inverseDistanceCellCellStencil.H
p
volScalarField & p
Definition: createFieldRefs.H:8
Foam::dynamicOversetFvMesh::correctBoundaryConditions
static void correctBoundaryConditions(typename GeoField::Boundary &bfld, const bool typeOnly)
Correct boundary conditions of certain type (typeOnly = true)
Definition: dynamicOversetFvMeshTemplates.C:117
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:65
Foam::UOPstream
Output inter-processor communications stream operating on external buffer.
Definition: UOPstream.H:57
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::bitSet
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:63
Foam::OBJstream
OFstream that keeps track of vertices.
Definition: OBJstream.H:58
update
mesh update()
Foam::tmp
A class for managing temporary objects.
Definition: PtrList.H:61
Foam::fvMeshSubset
Given the original mesh and the list of selected cells, it creates the mesh consisting only of the de...
Definition: fvMeshSubset.H:73
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::cellCellStencils::inverseDistance::position
static point position(const boundBox &bb, const labelVector &nDivs, const label boxI)
Convert index back into coordinate.
Definition: inverseDistanceCellCellStencil.C:104
Foam::polyMesh::nGeometricD
label nGeometricD() const
Return the number of valid geometric dimensions in the mesh.
Definition: polyMesh.C:869
Foam::DynamicList< label >
fvMeshSubset.H
Foam::Pstream::scatterList
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
Definition: gatherScatterList.C:215
Foam::cellCellStencils::inverseDistance::stencilWeights
virtual void stencilWeights(const point &sample, const pointList &donorCcs, scalarList &weights) const
Calculate inverse distance weights for a single acceptor.
Definition: inverseDistanceCellCellStencil.C:1435
globalIndex.H
Foam::treeBoundBox
Standard boundBox with extra functionality for use in octree.
Definition: treeBoundBox.H:86
Foam::PstreamBuffers
Buffers for inter-processor communications streams (UOPstream, UIPstream).
Definition: PstreamBuffers.H:88
Foam::bitSet::any
bool any() const
True if any bits in this bitset are set.
Definition: bitSetI.H:468
Foam::bitSet::set
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:574
dynamicOversetFvMesh.H
Foam::orEqOp
Definition: ops.H:86
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::PtrList::set
const T * set(const label i) const
Return const pointer to element (can be nullptr),.
Definition: PtrList.H:138
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:97
meshBb
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(rndGen, 1e-3))
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Foam::PstreamBuffers::clear
void clear()
Reset (clear) individual buffers and reset state.
Definition: PstreamBuffers.C:125
Foam::bitSet::test
bool test(const label pos) const
Test value at specified position, never auto-vivify entries.
Definition: bitSetI.H:520
Foam::incrIndent
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:346
syncTools.H
Foam::min
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:33
Foam::cellCellStencils::inverseDistance::index
static label index(const labelVector &nDivs, const labelVector &)
Convert ijk indices into single index.
Definition: inverseDistanceCellCellStencil.C:60
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:91
Foam::sumOp
Definition: ops.H:213
Foam::primitiveMesh::nPoints
label nPoints() const noexcept
Number of mesh points.
Definition: primitiveMeshI.H:37
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
patchTypes
wordList patchTypes(nPatches)
Foam::fvBoundaryMesh
Foam::fvBoundaryMesh.
Definition: fvBoundaryMesh.H:57
Foam::labelVector
Vector< label > labelVector
Vector of labels.
Definition: labelVector.H:51
Foam::oversetFvPatchField::write
virtual void write(Ostream &os) const
Write.
Definition: oversetFvPatchField.C:222
Foam::boundBox::overlaps
bool overlaps(const boundBox &bb) const
Overlaps/touches boundingBox?
Definition: boundBoxI.H:221
Foam::boundBox::span
vector span() const
The bounding box span (from minimum to maximum)
Definition: boundBoxI.H:127
meshParts
PtrList< fvMeshSubset > meshParts(nZones)
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::primitiveMesh::nCells
label nCells() const noexcept
Number of mesh cells.
Definition: primitiveMeshI.H:96
Foam::cellCellStencils::inverseDistance::overlaps
static bool overlaps(const boundBox &bb, const labelVector &nDivs, const PackedList< 2 > &voxels, const treeBoundBox &subBb, const unsigned int val)
Is any voxel inside subBb set to val.
Definition: inverseDistanceCellCellStencil.C:271
Foam::tmp::ref
T & ref() const
Definition: tmpI.H:227
Foam::Field< vector >
Foam::Info
messageStream Info
Information stream (stdout output on master, null elsewhere)
Foam::polyPatch
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:68
Foam::cellCellStencils::inverseDistance::cellBb
static treeBoundBox cellBb(const primitiveMesh &mesh, const label celli)
Calculate bounding box of cell.
Definition: inverseDistanceCellCellStencil.C:237
Foam::List::setSize
void setSize(const label n)
Alias for resize()
Definition: List.H:222
Foam::cellCellStencils::inverseDistance::walkFront
void walkFront(const scalar layerRelax, const labelListList &allStencil, labelList &allCellTypes, scalarField &allWeight) const
Surround holes with layer(s) of interpolated cells.
Definition: inverseDistanceCellCellStencil.C:1248
Foam::DynamicList::append
DynamicList< T, SizeMin > & append(const T &val)
Append an element to the end of this list.
Definition: DynamicListI.H:511
Foam::mapDistribute
Class containing processor-to-processor mapping information.
Definition: mapDistribute.H:163
Foam::List::transfer
void transfer(List< T > &list)
Definition: List.C:456
Foam::fvPatch
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:65
regionSplit.H
Foam::dimensionedScalar
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
Definition: dimensionedScalarFwd.H:42
samples
scalarField samples(nIntervals, Zero)
Foam::regionSplit
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:140
Foam::PtrList
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers....
Definition: List.H:59
Foam::volScalarField
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:57
Foam::regionSplit::nRegions
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:294
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::cellCellStencils::inverseDistance::markBoundaries
static void markBoundaries(const fvMesh &mesh, const vector &smallVec, const boundBox &bb, const labelVector &nDivs, PackedList< 2 > &patchTypes, const labelList &cellMap, labelList &patchCellTypes)
Mark voxels of patchTypes with type of patch face.
Definition: inverseDistanceCellCellStencil.C:159
Foam::mapDistribute::distribute
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute data using default commsType.
Definition: mapDistributeTemplates.C:152
Foam::cellCellStencils::inverseDistance::fill
static void fill(PackedList< 2 > &elems, const boundBox &bb, const labelVector &nDivs, const boundBox &subBb, const unsigned int val)
Fill all elements overlapping subBb with value val.
Definition: inverseDistanceCellCellStencil.C:121
Foam::PstreamBuffers::finishedSends
void finishedSends(const bool block=true)
Mark all sends as having been done.
Definition: PstreamBuffers.C:73
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::FatalError
error FatalError
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:123
reduce
reduce(hasMovingMesh, orOp< bool >())
os
OBJstream os(runTime.globalPath()/outputName)
mesh
dynamicFvMesh & mesh
Definition: createDynamicFvMesh.H:6
addToRunTimeSelectionTable.H
Macros for easy insertion into run-time selection tables.
Foam::cellCellStencils::inverseDistance::createStencil
virtual void createStencil(const globalIndex &)
Create stencil starting from the donor containing the acceptor.
Definition: inverseDistanceCellCellStencil.C:1470
zoneID
const labelIOList & zoneID
Definition: interpolatedFaces.H:22
Foam::fvMesh
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:85
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::decrIndent
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:353
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::globalIndex
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:68
Foam::indent
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:339
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:51
Foam::maxEqOp
Definition: ops.H:80
nCellsPerZone
labelList nCellsPerZone(nZones, Zero)
treeBoundBoxList.H
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::cellCellStencils::addToRunTimeSelectionTable
addToRunTimeSelectionTable(cellCellStencil, cellVolumeWeight, mesh)
Foam::cellCellStencils::inverseDistance::seedCell
void seedCell(const label cellI, const scalar wantedFraction, bitSet &isFront, scalarField &fraction) const
Seed faces of cell with wantedFraction (if higher than current)
Definition: inverseDistanceCellCellStencil.C:1227
Foam::cellCellStencils::inverseDistance::update
virtual bool update()
Update stencils. Return false if nothing changed.
Definition: inverseDistanceCellCellStencil.C:1744
Foam::Pstream::listCombineGather
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
Definition: combineGatherScatter.C:290
nSamples
const label nSamples(pdfDictionary.get< label >("nSamples"))
Time.H
Foam::polyMesh::findCell
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition: polyMesh.C:1507
Foam::primitiveMesh::cellCentres
const vectorField & cellCentres() const
Definition: primitiveMeshCellCentresAndVols.C:84
Foam::linePointRef
line< point, const point & > linePointRef
A line using referred points.
Definition: linePointRef.H:47
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::Pstream::gatherList
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
Definition: gatherScatterList.C:52
cellTypes
const labelList & cellTypes
Definition: setCellMask.H:33
Foam::UPstream::commsTypes::nonBlocking
DebugInfo
#define DebugInfo
Report an information message using Foam::Info.
Definition: messageStream.H:382
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:463
Foam::nl
constexpr char nl
Definition: Ostream.H:404
Foam::VectorSpace::max
static const Form max
Definition: VectorSpace.H:117
f
labelList f(nPoints)
Foam::cellCellStencil
Calculation of interpolation stencils.
Definition: cellCellStencil.H:61
Foam::BitOps::count
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of 'true' entries.
Definition: BitOps.H:77
Foam::Vector< label >
Foam::List< label >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:144
Foam::PackedList< 2 >
Foam::mag
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
Foam::type
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: MSwindows.C:590
Foam::UList< label >
points
const pointField & points
Definition: gmvOutputHeader.H:1
k
label k
Boltzmann constant.
Definition: LISASMDCalcMethod2.H:41
Foam::constant::electromagnetic::e
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
Foam::IOList< label >
Foam::List::clear
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:116
oversetFvPatch.H
Foam::sum
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &df)
Definition: DimensionedFieldFunctions.C:327
Foam::direction
uint8_t direction
Definition: direction.H:52
Foam::cellCellStencils::inverseDistance::index3
static labelVector index3(const labelVector &nDivs, const label)
Convert single index into ijk.
Definition: inverseDistanceCellCellStencil.C:70
FUNCTION_NAME
#define FUNCTION_NAME
Definition: messageStream.H:295
Foam::roots::type
type
Types of root.
Definition: Roots.H:54
Foam::oversetFvPatchField
Boundary condition for use on overset patches. To be run in combination with special dynamicFvMesh ty...
Definition: oversetFvPatchField.H:56
Foam::fvPatch::faceCells
virtual const labelUList & faceCells() const
Return faceCells.
Definition: fvPatch.C:113
Foam::boundBox
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
Foam::fvPatch::patch
const polyPatch & patch() const
Return the polyPatch.
Definition: fvPatch.H:161
Foam::name
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:59
Foam::UIndirectList
A List with indirect addressing.
Definition: faMatrix.H:60
Foam::cellCellStencils::inverseDistance::findHoles
void findHoles(const globalIndex &globalCells, const fvMesh &mesh, const labelList &zoneID, const labelListList &stencil, labelList &cellTypes) const
Do flood filling to detect unreachable (from patches) sections.
Definition: inverseDistanceCellCellStencil.C:945
Foam::findIndices
labelList findIndices(const ListType &input, typename ListType::const_reference val, label start=0)
Linear search to find all occurrences of given element.
Foam::cellCellStencils::inverseDistance::markDonors
void markDonors(const globalIndex &globalCells, PstreamBuffers &pBufs, const PtrList< fvMeshSubset > &meshParts, const List< treeBoundBoxList > &meshBb, const labelList &allCellTypes, const label srcI, const label tgtI, labelListList &allStencil, labelList &allDonor) const
Determine donors for all tgt cells.
Definition: inverseDistanceCellCellStencil.C:483
Foam::face
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:72
Foam::cellCellStencils::defineTypeNameAndDebug
defineTypeNameAndDebug(cellVolumeWeight, 0)
cells
const cellShapeList & cells
Definition: gmvOutputHeader.H:3
Foam::plusEqOp
Definition: ops.H:72
Foam::PATCH
PDRpatchDef PATCH
Definition: PDRpatchDef.H:112
Foam::UIPstream
Input inter-processor communications stream operating on external buffer.
Definition: UIPstream.H:56
Foam::Pstream::listCombineScatter
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
Definition: combineGatherScatter.C:432
Foam::cbrt
dimensionedScalar cbrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:155
Foam::GeometricField< scalar, fvPatchField, volMesh >
Foam::cellCellStencils::inverseDistance::betterDonor
bool betterDonor(const label destMesh, const label currentDonorMesh, const label newDonorMesh) const
If multiple donors meshes: decide which is best.
Definition: inverseDistanceCellCellStencil.C:441
Foam::treeBoundBoxList
List< treeBoundBox > treeBoundBoxList
List of bounding boxes.
Definition: treeBoundBoxList.H:46
Foam::minMagSqrEqOp
Definition: ops.H:82
Foam::orOp
Definition: ops.H:234
Foam::mkDir
bool mkDir(const fileName &pathName, mode_t mode=0777)
Make a directory and return an error if it could not be created.
Definition: MSwindows.C:507
zeroGradientFvPatchFields.H
Foam::cell
A cell is defined as a list of faces with extra functionality.
Definition: cell.H:54
Foam::gMax
Type gMax(const FieldField< Field, Type > &f)
Definition: FieldFieldFunctions.C:592
OBJstream.H
waveMethod.H
Foam::UPstream::nProcs
static label nProcs(const label communicator=worldComm)
Number of processes in parallel run, and 1 for serial run.
Definition: UPstream.H:445
Foam::bitSet::transfer
void transfer(bitSet &bitset)
Definition: bitSetI.H:544
Foam::dimless
const dimensionSet dimless
Dimensionless.
Definition: dimensionSets.C:189
Foam::cellCellStencils::inverseDistance::markPatchesAsHoles
void markPatchesAsHoles(PstreamBuffers &pBufs, const PtrList< fvMeshSubset > &meshParts, const List< treeBoundBoxList > &patchBb, const List< labelVector > &patchDivisions, const PtrList< PackedList< 2 >> &patchParts, const label srcI, const label tgtI, labelList &allCellTypes) const
Mark all cells overlapping (a voxel covered by) a src patch.
Definition: inverseDistanceCellCellStencil.C:315
Foam::globalIndex::toGlobal
label toGlobal(const label i) const
From local to global index.
Definition: globalIndexI.H:240
sample
Minimal example by using system/controlDict.functions:
Foam::flipOp
Functor to negate primitives. Dummy for most other types.
Definition: flipOp.H:53
Foam::labelUIndList
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: UIndirectList.H:58
Foam::polyMesh::tetBasePtIs
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:892
Foam::primitiveMesh
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:78