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