cellVolumeWeightCellCellStencil.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) 2014-2023 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 "meshToMesh.H"
33 #include "cellVolumeWeightMethod.H"
34 #include "fvMeshSubset.H"
35 #include "regionSplit.H"
36 #include "globalIndex.H"
37 #include "oversetFvPatch.H"
39 #include "syncTools.H"
41 #include "oversetFvPatchField.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47 namespace cellCellStencils
48 {
51 }
52 }
53 
54 Foam::scalar
56 
57 
58 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
59 
61 (
62  const globalIndex& globalCells,
63  const fvMesh& mesh,
64  const labelList& zoneID,
65  const labelListList& stencil,
67 ) const
68 {
69  const fvBoundaryMesh& pbm = mesh.boundary();
70  const labelList& own = mesh.faceOwner();
71  const labelList& nei = mesh.faceNeighbour();
72 
73  // so we start a walk from our patches and any cell we cannot reach
74  // (because we walk is stopped by other-mesh patch) is a hole.
75 
76 
77  boolList isBlockedFace(mesh.nFaces(), false);
78  for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
79  {
80  label ownType = cellTypes[own[faceI]];
81  label neiType = cellTypes[nei[faceI]];
82  if
83  (
84  (ownType == HOLE && neiType != HOLE)
85  || (ownType != HOLE && neiType == HOLE)
86  )
87  {
88  isBlockedFace[faceI] = true;
89  }
90  }
91 
92  labelList nbrCellTypes;
94 
95  for (label faceI = mesh.nInternalFaces(); faceI < mesh.nFaces(); faceI++)
96  {
97  label ownType = cellTypes[own[faceI]];
98  label neiType = nbrCellTypes[faceI-mesh.nInternalFaces()];
99 
100  if
101  (
102  (ownType == HOLE && neiType != HOLE)
103  || (ownType != HOLE && neiType == HOLE)
104  )
105  {
106  isBlockedFace[faceI] = true;
107  }
108  }
109 
110  regionSplit cellRegion(mesh, isBlockedFace);
111 
112  Info<< typeName << " : detected " << cellRegion.nRegions()
113  << " mesh regions after overset" << nl << endl;
114 
115 
116 
117  // Now we'll have a mesh split according to where there are cells
118  // covered by the other-side patches. See what we can reach from our
119  // real patches
120 
121  // 0 : region not yet determined
122  // 1 : borders blockage so is not ok (but can be overridden by real
123  // patch)
124  // 2 : has real patch in it so is reachable
125  labelList regionType(cellRegion.nRegions(), Zero);
126 
127 
128  // See if any regions borders blockage. Note: isBlockedFace is already
129  // parallel synchronised.
130  {
131  for (label faceI = 0; faceI < mesh.nInternalFaces(); faceI++)
132  {
133  if (isBlockedFace[faceI])
134  {
135  label ownRegion = cellRegion[own[faceI]];
136 
137  if (cellTypes[own[faceI]] != HOLE)
138  {
139  if (regionType[ownRegion] == 0)
140  {
141  //Pout<< "Mark region:" << ownRegion
142  // << " on zone:" << zoneID[own[faceI]]
143  // << " as next to blockage at:"
144  // << mesh.faceCentres()[faceI] << endl;
145  regionType[ownRegion] = 1;
146  }
147  }
148 
149  label neiRegion = cellRegion[nei[faceI]];
150 
151  if (cellTypes[nei[faceI]] != HOLE)
152  {
153  if (regionType[neiRegion] == 0)
154  {
155  //Pout<< "Mark region:" << neiRegion
156  // << " on zone:" << zoneID[nei[faceI]]
157  // << " as next to blockage at:"
158  // << mesh.faceCentres()[faceI] << endl;
159  regionType[neiRegion] = 1;
160  }
161  }
162  }
163  }
164  for
165  (
166  label faceI = mesh.nInternalFaces();
167  faceI < mesh.nFaces();
168  faceI++
169  )
170  {
171  if (isBlockedFace[faceI])
172  {
173  label ownRegion = cellRegion[own[faceI]];
174 
175  if (regionType[ownRegion] == 0)
176  {
177  //Pout<< "Mark region:" << ownRegion
178  // << " on zone:" << zoneID[own[faceI]]
179  // << " as next to blockage at:"
180  // << mesh.faceCentres()[faceI] << endl;
181  regionType[ownRegion] = 1;
182  }
183  }
184  }
185  }
186 
187 
188  // Override with real patches
189  forAll(pbm, patchI)
190  {
191  const fvPatch& fvp = pbm[patchI];
192 
193  if (isA<oversetFvPatch>(fvp))
194  {}
195  else if (!fvPatch::constraintType(fvp.type()))
196  {
197  //Pout<< "Proper patch " << fvp.name() << " of type " << fvp.type()
198  // << endl;
199 
200  const labelList& fc = fvp.faceCells();
201  forAll(fc, i)
202  {
203  label regionI = cellRegion[fc[i]];
204 
205  if (cellTypes[fc[i]] != HOLE && regionType[regionI] != 2)
206  {
207  //Pout<< "reachable region : " << regionI
208  // << " at cell " << mesh.cellCentres()[fc[i]]
209  // << " on zone " << zoneID[fc[i]] << endl;
210  regionType[regionI] = 2;
211  }
212  }
213  }
214  }
215 
216  // Now we've handled
217  // - cells next to blocked cells
218  // - coupled boundaries
219  // Only thing to handle is the interpolation between regions
220 
221 
222  labelListList compactStencil(stencil);
223  List<Map<label>> compactMap;
224  mapDistribute map(globalCells, compactStencil, compactMap);
225 
226  while (true)
227  {
228  // Synchronise region status on processors
229  // (could instead swap status through processor patches)
231 
232  // Communicate region status through interpolative cells
233  labelList cellRegionType(labelUIndList(regionType, cellRegion));
234  map.distribute(cellRegionType);
235 
236 
237  label nChanged = 0;
238  forAll(pbm, patchI)
239  {
240  const fvPatch& fvp = pbm[patchI];
241 
242  if (isA<oversetFvPatch>(fvp))
243  {
244  const labelUList& fc = fvp.faceCells();
245  forAll(fc, i)
246  {
247  label cellI = fc[i];
248  label regionI = cellRegion[cellI];
249 
250  if (regionType[regionI] != 2)
251  {
252  const labelList& slots = compactStencil[cellI];
253  forAll(slots, i)
254  {
255  label otherType = cellRegionType[slots[i]];
256 
257  if (otherType == 2)
258  {
259  //Pout<< "Reachable through interpolation : "
260  // << regionI << " at cell "
261  // << mesh.cellCentres()[cellI] << endl;
262  regionType[regionI] = 2;
263  nChanged++;
264  break;
265  }
266  }
267  }
268  }
269  }
270  }
271 
272 
273  if (!returnReduceOr(nChanged))
274  {
275  break;
276  }
277  }
278 
279 
280  // See which regions have not been visited (regionType == 1)
281  forAll(cellRegion, cellI)
282  {
283  label type = regionType[cellRegion[cellI]];
284  if (type == 1 && cellTypes[cellI] != HOLE)
285  {
286  cellTypes[cellI] = HOLE;
287  }
288  }
289 }
290 
291 
293 (
294  const fvMesh& mesh,
295  const labelList& cellMap,
296  labelList& patchCellTypes
297 ) const
298 {
299  const fvBoundaryMesh& pbm = mesh.boundary();
300 
301  forAll(pbm, patchI)
302  {
303  const fvPatch& fvp = pbm[patchI];
304  const labelList& fc = fvp.faceCells();
305 
306  if (isA<oversetFvPatch>(fvp))
307  {
308  //Pout<< "Marking cells on overset patch " << fvp.name() << endl;
309  forAll(fc, i)
310  {
311  label cellI = fc[i];
312  patchCellTypes[cellMap[cellI]] = OVERSET;
313  }
314  }
315  else if (!fvPatch::constraintType(fvp.type()))
316  {
317  //Pout<< "Marking cells on proper patch " << fvp.name()
318  // << " with type " << fvp.type() << endl;
319  forAll(fc, i)
320  {
321  label cellI = fc[i];
322  if (patchCellTypes[cellMap[cellI]] != OVERSET)
323  {
324  patchCellTypes[cellMap[cellI]] = PATCH;
325  }
326  }
327  }
328  }
329 }
330 
331 
333 (
334  const labelListList& addressing,
335  const labelList& patchTypes,
336  labelList& result
337 ) const
338 {
339  forAll(result, cellI)
340  {
341  const labelList& slots = addressing[cellI];
342  forAll(slots, i)
343  {
344  label type = patchTypes[slots[i]];
345 
346  if (type == OVERSET)
347  {
348  // 'overset' overrides anything
349  result[cellI] = OVERSET;
350  break;
351  }
352  else if (type == PATCH)
353  {
354  // 'patch' overrides -1 and 'other'
355  result[cellI] = PATCH;
356  break;
357  }
358  else if (result[cellI] == -1)
359  {
360  // 'other' overrides -1 only
361  result[cellI] = OTHER;
362  }
363  }
364  }
365 }
366 
367 
369 (
370  const autoPtr<mapDistribute>& mapPtr,
371  const labelListList& addressing,
372  const labelList& patchTypes,
373  labelList& result
374 ) const
375 {
376  if (result.size() != addressing.size())
377  {
378  FatalErrorInFunction << "result:" << result.size()
379  << " addressing:" << addressing.size() << exit(FatalError);
380  }
381 
382 
383  // Initialise to not-mapped
384  result = -1;
385 
386  if (mapPtr)
387  {
388  // Pull remote data into order of addressing
389  labelList work(patchTypes);
390  mapPtr().distribute(work);
391 
392  interpolatePatchTypes(addressing, work, result);
393  }
394  else
395  {
396  interpolatePatchTypes(addressing, patchTypes, result);
397  }
398 }
399 
400 
402 (
403  const label subZoneID,
404  const fvMesh& subMesh,
405  const labelList& subCellMap,
406 
407  const label donorZoneID,
408  const labelListList& addressing,
409  const List<scalarList>& weights,
410  const labelList& otherCells,
411  const labelList& interpolatedOtherPatchTypes,
412 
413  labelListList& allStencil,
414  scalarListList& allWeights,
415  labelList& allCellTypes,
416  labelList& allDonorID
417 ) const
418 {
419  forAll(subCellMap, subCellI)
420  {
421  label cellI = subCellMap[subCellI];
422 
423  bool validDonors = true;
424  switch (interpolatedOtherPatchTypes[subCellI])
425  {
426  case -1:
427  {
428  validDonors = false;
429  }
430  break;
431 
432  case OTHER:
433  {
434  // No patch interaction so keep valid
435  }
436  break;
437 
438  case PATCH:
439  {
440  // Patch-patch interaction... For now disable always
441  allCellTypes[cellI] = HOLE;
442  validDonors = false;
443  // Alternative is to look at the amount of overlap but this
444  // is not very robust
445 // if (allCellTypes[cellI] != HOLE)
446 // {
447 // scalar overlapVol = sum(weights[subCellI]);
448 // scalar v = mesh_.V()[cellI];
449 // if (overlapVol < (1.0-overlapTolerance_)*v)
450 // {
451 // //Pout<< "** Patch overlap:" << cellI
452 // // << " at:" << mesh_.cellCentres()[cellI] << endl;
453 // allCellTypes[cellI] = HOLE;
454 // validDonors = false;
455 // }
456 // }
457  }
458  break;
459 
460  case OVERSET:
461  {
462  validDonors = true;
463  }
464  break;
465  }
466 
467 
468  if (validDonors)
469  {
470  // There are a few possible choices how to choose between multiple
471  // donor candidates:
472  // 1 highest overlap volume. However this is generally already
473  // 99.9% so you're just measuring truncation error.
474  // 2 smallest donors cells or most donor cells. This is quite
475  // often done but can cause switching of donor zone from one
476  // time step to the other if the donor meshes are non-uniform
477  // and the acceptor cells just happens to be sweeping through
478  // some small donor cells.
479  // 3 nearest zoneID. So zone 0 preferentially interpolates from
480  // zone 1, zone 1 preferentially from zone 2 etc.
481 
482  //- Option 1:
483  //scalar currentVol = sum(allWeights[cellI]);
484  //if (overlapVol[subCellI] > currentVol)
485 
486  //- Option 3:
487  label currentDiff = mag(subZoneID-allDonorID[cellI]);
488  label thisDiff = mag(subZoneID-donorZoneID);
489 
490  if
491  (
492  allDonorID[cellI] == -1
493  || (thisDiff < currentDiff)
494  || (thisDiff == currentDiff && donorZoneID > allDonorID[cellI])
495  )
496  {
497  allWeights[cellI] = weights[subCellI];
498  allStencil[cellI] =
499  labelUIndList(otherCells, addressing[subCellI]);
500  allDonorID[cellI] = donorZoneID;
501  }
502  }
503  }
504 }
505 
506 
507 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
509 Foam::cellCellStencils::cellVolumeWeight::cellVolumeWeight
510 (
511  const fvMesh& mesh,
512  const dictionary& dict,
513  const bool doUpdate
514 )
515 :
517  dict_(dict),
518  overlapTolerance_(defaultOverlapTolerance_),
519  cellTypes_(labelList(mesh.nCells(), CALCULATED)),
520  interpolationCells_(0),
521  cellInterpolationMap_(),
522  cellStencil_(0),
523  cellInterpolationWeights_(0),
524  cellInterpolationWeight_
525  (
526  IOobject
527  (
528  "cellInterpolationWeight",
529  mesh_.facesInstance(),
530  mesh_,
531  IOobject::NO_READ,
532  IOobject::NO_WRITE,
533  IOobject::NO_REGISTER
534  ),
535  mesh_,
538  ),
539  allowInterpolatedDonors_
540  (
541  dict.getOrDefault("allowInterpolatedDonors", true)
542  )
543 {
544  // Add motion-solver fields to non-interpolated fields
546 
547  // Read zoneID
548  this->zoneID();
549 
551  dict_.getOrDefault("overlapTolerance", defaultOverlapTolerance_);
552 
553  // Read old-time cellTypes
554  IOobject io
555  (
556  "cellTypes",
557  mesh_.time().timeName(),
558  mesh_,
562  );
563  if (io.typeHeaderOk<volScalarField>(true))
564  {
565  if (debug)
566  {
567  Pout<< "Reading cellTypes from time " << mesh_.time().timeName()
568  << endl;
569  }
570 
571  const volScalarField volCellTypes(io, mesh_);
572  forAll(volCellTypes, celli)
573  {
574  // Round to integer
575  cellTypes_[celli] = volCellTypes[celli];
576  }
577  }
578 
579  if (doUpdate)
580  {
581  update();
582  }
583 }
584 
585 
586 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
587 
589 {}
590 
591 
592 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
593 
595 {
596  scalar layerRelax(dict_.getOrDefault("layerRelax", 1.0));
597  const labelIOList& zoneID = this->zoneID();
598 
599  label nZones = gMax(zoneID)+1;
600  labelList nCellsPerZone(nZones, Zero);
601  forAll(zoneID, cellI)
602  {
603  nCellsPerZone[zoneID[cellI]]++;
604  }
606 
607  Info<< typeName << " : detected " << nZones
608  << " mesh regions" << nl << endl;
609 
610 
611  PtrList<fvMeshSubset> meshParts(nZones);
612 
613  Info<< incrIndent;
614  forAll(meshParts, zonei)
615  {
616  Info<< indent<< "zone:" << zonei << " nCells:"
617  << nCellsPerZone[zonei] << nl;
618 
619  meshParts.set
620  (
621  zonei,
622  new fvMeshSubset(mesh_, zonei, zoneID)
623  );
624  }
625  Info<< decrIndent;
626 
627 
628  // Current best guess for cells. Includes best stencil. Weights should
629  // add up to volume.
630  labelList allCellTypes(mesh_.nCells(), CALCULATED);
631  labelList allPatchTypes(mesh_.nCells(), OTHER);
632  labelListList allStencil(mesh_.nCells());
633  scalarListList allWeights(mesh_.nCells());
634  // zoneID of donor
635  labelList allDonorID(mesh_.nCells(), -1);
636 
637 
638  // Marking patch cells
639  forAll(meshParts, partI)
640  {
641  const fvMesh& partMesh = meshParts[partI].subMesh();
642  const labelList& partCellMap = meshParts[partI].cellMap();
643 
644  // Mark cells with
645  // - overset boundary
646  // - other, proper boundary
647  // - other cells
648  Info<< "Marking patch-cells on zone " << partI << endl;
649  markPatchCells(partMesh, partCellMap, allPatchTypes);
650  }
651 
652  if ((debug & 2) && mesh_.time().writeTime())
653  {
655  (
656  createField(mesh_, "allPatchTypes", allPatchTypes)
657  );
658  tfld().write();
659  }
660 
661 
662  labelList nCells(count(3, allPatchTypes));
663  Info<< nl
664  << "After patch analysis : nCells : "
665  << returnReduce(allPatchTypes.size(), sumOp<label>()) << nl
666  << incrIndent
667  << indent << "other : " << nCells[OTHER] << nl
668  << indent << "patch : " << nCells[PATCH] << nl
669  << indent << "overset: " << nCells[OVERSET] << nl
670  << decrIndent << endl;
671 
672  globalIndex globalCells(mesh_.nCells());
673 
674  for (label srcI = 0; srcI < meshParts.size()-1; srcI++)
675  {
676  const fvMesh& srcMesh = meshParts[srcI].subMesh();
677  const labelList& srcCellMap = meshParts[srcI].cellMap();
678 
679  for (label tgtI = srcI+1; tgtI < meshParts.size(); tgtI++)
680  {
681  const fvMesh& tgtMesh = meshParts[tgtI].subMesh();
682  const labelList& tgtCellMap = meshParts[tgtI].cellMap();
683 
684  meshToMesh mapper
685  (
686  srcMesh,
687  tgtMesh,
689  HashTable<word>(0), // patchMap,
690  wordList(0), // cuttingPatches
692  false // do not normalise
693  );
694 
695  {
696  // Get tgt patch types on src mesh
697  labelList interpolatedTgtPatchTypes(srcMesh.nCells(), -1);
698  interpolatePatchTypes
699  (
700  mapper.tgtMap(), // How to get remote data local
701  mapper.srcToTgtCellAddr(),
702  labelList(labelUIndList(allPatchTypes, tgtCellMap)),
703  interpolatedTgtPatchTypes
704  );
705 
706  // Get target cell labels in global cell indexing (on overall
707  // mesh)
708  labelList tgtGlobalCells(tgtMesh.nCells());
709  {
710  forAll(tgtCellMap, tgtCellI)
711  {
712  label cellI = tgtCellMap[tgtCellI];
713  tgtGlobalCells[tgtCellI] = globalCells.toGlobal(cellI);
714  }
715  if (mapper.tgtMap())
716  {
717  mapper.tgtMap()->distribute(tgtGlobalCells);
718  }
719  }
720 
721 
722  combineCellTypes
723  (
724  srcI,
725  srcMesh,
726  srcCellMap,
727 
728  tgtI,
729  mapper.srcToTgtCellAddr(),
730  mapper.srcToTgtCellWght(),
731  tgtGlobalCells,
732  interpolatedTgtPatchTypes,
733 
734  // Overall mesh data
735  allStencil,
736  allWeights,
737  allCellTypes,
738  allDonorID
739  );
740  }
741 
742  {
743  // Get src patch types on tgt mesh
744  labelList interpolatedSrcPatchTypes(tgtMesh.nCells(), -1);
745  interpolatePatchTypes
746  (
747  mapper.srcMap(), // How to get remote data local
748  mapper.tgtToSrcCellAddr(),
749  labelList(labelUIndList(allPatchTypes, srcCellMap)),
750  interpolatedSrcPatchTypes
751  );
752 
753  labelList srcGlobalCells(srcMesh.nCells());
754  {
755  forAll(srcCellMap, srcCellI)
756  {
757  label cellI = srcCellMap[srcCellI];
758  srcGlobalCells[srcCellI] = globalCells.toGlobal(cellI);
759  }
760  if (mapper.srcMap())
761  {
762  mapper.srcMap()->distribute(srcGlobalCells);
763  }
764  }
765 
766  combineCellTypes
767  (
768  tgtI,
769  tgtMesh,
770  tgtCellMap,
771 
772  srcI,
773  mapper.tgtToSrcCellAddr(),
774  mapper.tgtToSrcCellWght(),
775  srcGlobalCells,
776  interpolatedSrcPatchTypes,
777 
778  // Overall mesh data
779  allStencil,
780  allWeights,
781  allCellTypes,
782  allDonorID
783  );
784  }
785  }
786  }
787 
788 
789  if ((debug & 2) && mesh_.time().writeTime())
790  {
792  (
793  createField(mesh_, "allCellTypes", allCellTypes)
794  );
795  tfld().write();
796 
797  tmp<volScalarField> tdonors
798  (
799  createField(mesh_, "allDonorID", allDonorID)
800  );
801  tdonors().write();
802 
803  }
804 
805 
806  // Use the patch types and weights to decide what to do
807  forAll(allPatchTypes, cellI)
808  {
809  if (allCellTypes[cellI] != HOLE)
810  {
811  switch (allPatchTypes[cellI])
812  {
813  case OVERSET:
814  {
815  // Interpolate. Check if enough overlap
816  scalar v = mesh_.V()[cellI];
817  scalar overlapVol = sum(allWeights[cellI]);
818  if (overlapVol > overlapTolerance_*v)
819  {
820  allCellTypes[cellI] = INTERPOLATED;
821  }
822  else
823  {
824  allCellTypes[cellI] = HOLE;
825  allWeights[cellI].clear();
826  allStencil[cellI].clear();
827  }
828  break;
829  }
830  }
831  }
832  }
833 
834 
835  if ((debug & 2) && mesh_.time().writeTime())
836  {
838  (
839  createField(mesh_, "allCellTypes_patch", allCellTypes)
840  );
841  tfld().write();
842 
843  labelList stencilSize(mesh_.nCells());
844  forAll(allStencil, celli)
845  {
846  stencilSize[celli] = allStencil[celli].size();
847  }
848  tmp<volScalarField> tfldStencil
849  (
850  createField(mesh_, "allStencil_patch", stencilSize)
851  );
852  tfldStencil().write();
853  }
854 
855 
856  // Mark unreachable bits
857  findHoles(globalCells, mesh_, zoneID, allStencil, allCellTypes);
858 
859  if ((debug & 2) && mesh_.time().writeTime())
860  {
862  (
863  createField(mesh_, "allCellTypes_hole", allCellTypes)
864  );
865  tfld().write();
866 
867  labelList stencilSize(mesh_.nCells());
868  forAll(allStencil, celli)
869  {
870  stencilSize[celli] = allStencil[celli].size();
871  }
872  tmp<volScalarField> tfldStencil
873  (
874  createField(mesh_, "allStencil_hole", stencilSize)
875  );
876  tfldStencil().write();
877  }
878 
879 
880  // Add buffer interpolation layer around holes
881  scalarField allWeight(mesh_.nCells(), Zero);
882 
883  labelListList compactStencil(allStencil);
884  List<Map<label>> compactStencilMap;
885  mapDistribute map(globalCells, compactStencil, compactStencilMap);
886 
887  scalarList compactCellVol(mesh_.V());
888  map.distribute(compactCellVol);
889 
890  walkFront
891  (
892  globalCells,
893  layerRelax,
894  allStencil,
895  allCellTypes,
896  allWeight,
897  compactCellVol,
898  compactStencil,
899  zoneID,
900  dict_.getOrDefault("holeLayers", 1),
901  dict_.getOrDefault("useLayer", -1)
902  );
903 
904 
905  if ((debug & 2) && mesh_.time().writeTime())
906  {
908  (
909  createField(mesh_, "allCellTypes_front", allCellTypes)
910  );
911  tfld().write();
912 
913  labelList stencilSize(mesh_.nCells());
914  forAll(allStencil, celli)
915  {
916  stencilSize[celli] = allStencil[celli].size();
917  }
918  tmp<volScalarField> tfldStencil
919  (
920  createField(mesh_, "allStencil_front", stencilSize)
921  );
922  tfldStencil().write();
923  }
924 
925  // Check previous iteration cellTypes_ for any hole->calculated changes
926  // If so set the cell either to interpolated (if there are donors) or
927  // holes (if there are no donors). Note that any interpolated cell might
928  // still be overwritten by the flood filling
929  {
930  label nCalculated = 0;
931 
932  forAll(cellTypes_, celli)
933  {
934  if (allCellTypes[celli] == CALCULATED && cellTypes_[celli] == HOLE)
935  {
936  if (allStencil[celli].size() == 0)
937  {
938  // Reset to hole
939  allCellTypes[celli] = HOLE;
940  allWeights[celli].clear();
941  allStencil[celli].clear();
942  }
943  else
944  {
945  allCellTypes[celli] = INTERPOLATED;
946  nCalculated++;
947  }
948  }
949  }
950 
951  if (debug)
952  {
953  Pout<< "Detected " << nCalculated << " cells changing from hole"
954  << " to calculated. Changed these to interpolated"
955  << endl;
956  }
957  }
958 
959 
960  labelList compactCellTypes(allCellTypes);
961  map.distribute(compactCellTypes);
962 
963  label nHoleDonors = 0;
964  forAll(allCellTypes, cellI)
965  {
966  if (allCellTypes[cellI] == INTERPOLATED)
967  {
968  const labelList& slots = compactStencil[cellI];
969  forAll (slots, subCellI)
970  {
971  if
972  (
973  compactCellTypes[slots[0]] == HOLE
974  ||
975  (
976  !allowInterpolatedDonors_
977  && compactCellTypes[slots[0]] == INTERPOLATED
978  )
979  )
980  {
981  allWeights[cellI][subCellI] = 0;
982  nHoleDonors++;
983  }
984  }
985  }
986  else
987  {
988  allWeights[cellI].clear();
989  allStencil[cellI].clear();
990  }
991  }
992  reduce(nHoleDonors, sumOp<label>());
993 
994 
995  // Normalize weights
996  forAll(allCellTypes, cellI)
997  {
998  if (allCellTypes[cellI] == INTERPOLATED)
999  {
1000  const scalar s = sum(allWeights[cellI]);
1001 
1002  if (s < SMALL)
1003  {
1004  allCellTypes[cellI] = POROUS;
1005  allWeights[cellI].clear();
1006  allStencil[cellI].clear();
1007  }
1008  else
1009  {
1010  forAll(allWeights[cellI], i)
1011  {
1012  allWeights[cellI][i] /= s;
1013  }
1014  }
1015  }
1016  }
1017 
1018  // Write to volField for debugging
1019  if ((debug & 2) && mesh_.time().writeTime())
1020  {
1021  tmp<volScalarField> tfld
1022  (
1023  createField(mesh_, "allCellTypes_final", allCellTypes)
1024  );
1025  tfld().write();
1026  }
1027 
1028 
1029  cellTypes_.transfer(allCellTypes);
1030  cellStencil_.transfer(allStencil);
1031  cellInterpolationWeights_.transfer(allWeights);
1032  cellInterpolationWeight_.transfer(allWeight);
1033  //cellInterpolationWeight_.correctBoundaryConditions();
1035  <
1038  >(cellInterpolationWeight_.boundaryFieldRef(), false);
1039 
1040  DynamicList<label> interpolationCells;
1041  forAll(cellStencil_, cellI)
1042  {
1043  if (cellStencil_[cellI].size())
1044  {
1045  interpolationCells.append(cellI);
1046  }
1047  }
1048  interpolationCells_.transfer(interpolationCells);
1049 
1050 
1051  List<Map<label>> compactMap;
1052  cellInterpolationMap_.reset
1053  (
1054  new mapDistribute(globalCells, cellStencil_, compactMap)
1055  );
1056 
1057  // Dump interpolation stencil
1058  if ((debug & 2) && mesh_.time().writeTime())
1059  {
1060  // Dump weight
1061  cellInterpolationWeight_.instance() = mesh_.time().timeName();
1062  cellInterpolationWeight_.write();
1063 
1064 
1065  mkDir(mesh_.time().timePath());
1066  OBJstream str(mesh_.time().timePath()/"stencil2.obj");
1067  Info<< typeName << " : dumping to " << str.name() << endl;
1068  pointField cc(mesh_.cellCentres());
1069  cellInterpolationMap().distribute(cc);
1070 
1071  forAll(interpolationCells_, compactI)
1072  {
1073  label cellI = interpolationCells_[compactI];
1074  const labelList& slots = cellStencil_[cellI];
1075 
1076  Pout<< "cellI:" << cellI << " at:"
1077  << mesh_.cellCentres()[cellI]
1078  << " calculated from slots:" << slots
1079  << " cc:" << UIndirectList<point>(cc, slots)
1080  << " weights:" << cellInterpolationWeights_[cellI]
1081  << endl;
1082 
1083  forAll(slots, i)
1084  {
1085  if (cellInterpolationWeights_[cellI][slots[i]] > 0)
1086  {
1087  const point& donorCc = cc[slots[i]];
1088  const point& accCc = mesh_.cellCentres()[cellI];
1089  str.writeLine(accCc, 0.1*accCc+0.9*donorCc);
1090  }
1091  }
1092  }
1093  }
1094 
1095  Info << this->info();
1096 
1097  return true;
1098 }
1099 
1102 (
1103  const point& sample,
1104  const pointList& donorCcs,
1105  scalarList& weights
1106 ) const
1107 {
1108  // Inverse-distance weighting
1109 
1110  weights.setSize(donorCcs.size());
1111  scalar sum = 0.0;
1112  forAll(donorCcs, i)
1113  {
1114  scalar d = mag(sample-donorCcs[i]);
1115 
1116  if (d > ROOTVSMALL)
1117  {
1118  weights[i] = 1.0/d;
1119  sum += weights[i];
1120  }
1121  else
1122  {
1123  // Short circuit
1124  weights = 0.0;
1125  weights[i] = 1.0;
1126  return;
1127  }
1128  }
1129  forAll(weights, i)
1130  {
1131  weights[i] /= sum;
1132  }
1133 }
1134 
1135 
1136 // ************************************************************************* //
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:136
scalar overlapTolerance_
Tolerance for volume overlap. Fraction of volume.
const polyBoundaryMesh & pbm
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
dimensioned< Type > sum(const DimensionedField< Type, GeoMesh > &f1)
const word zeroGradientType
A zeroGradient patch field type.
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:493
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
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:129
virtual void stencilWeights(const point &sample, const pointList &donorCcs, scalarList &weights) const
Calculate inverse distance weights for a single acceptor. Revert.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
void combineCellTypes(const label subZoneID, const fvMesh &subMesh, const labelList &subCellMap, const label donorZoneID, const labelListList &toOtherCells, const List< scalarList > &weights, const labelList &otherCells, const labelList &interpolatedOtherPatchTypes, labelListList &allStencil, scalarListList &allWeights, labelList &allCellTypes, labelList &allDonorID) const
void distribute(List< T > &fld, const bool dummyTransform=true, const int tag=UPstream::msgType()) const
Distribute List data using default commsType, default flip/negate operator.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
wordList patchTypes(nPatches)
UIndirectList< label > labelUIndList
UIndirectList of labels.
Definition: IndirectList.H:65
virtual bool update()
Update stencils. Return false if nothing changed.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:70
void findHoles(const globalIndex &globalCells, const fvMesh &mesh, const labelList &zoneID, const labelListList &stencil, labelList &cellTypes) const
Find cells next to cells of type PATCH.
defineTypeNameAndDebug(cellVolumeWeight, 0)
Template invariant parts for fvPatchField.
Definition: fvPatchField.H:77
Class to calculate the cell-addressing between two overlapping meshes.
Definition: meshToMesh.H:60
Ignore writing from objectRegistry::writeObject()
const dimensionSet dimless
Dimensionless.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
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.
List< labelList > labelListList
List of labelList.
Definition: labelList.H:38
Macros for easy insertion into run-time selection tables.
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
const dictionary dict_
Dictionary of motion control parameters.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:81
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
const labelListList & srcToTgtCellAddr() const
Return const access to the source to target cell addressing.
Definition: meshToMeshI.H:38
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:61
PDRpatchDef PATCH
Definition: PDRpatchDef.H:120
void suppressMotionFields()
Helper: populate nonInterpolatedFields_ with motion solver.
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
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:614
Calculation of interpolation stencils.
const autoPtr< mapDistribute > & srcMap() const noexcept
Source map pointer - valid if no singleMeshProc.
Definition: meshToMeshI.H:101
void clear()
Clear the list, i.e. set size to zero.
Definition: ListI.H:137
virtual const labelUList & faceCells() const
Return faceCells.
Definition: fvPatch.C:107
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
Reading is optional [identical to LAZY_READ].
A HashTable similar to std::unordered_map.
Definition: HashTable.H:108
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:159
const fvMesh & mesh_
Reference to the mesh.
const labelList & cellTypes
Definition: setCellMask.H:27
static void correctBoundaryConditions(typename GeoField::Boundary &bfld, const bool typeOnly)
Correct boundary conditions of certain type (typeOnly = true)
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 a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
int debug
Static debugging option.
Type gMax(const FieldField< Field, Type > &f)
void interpolatePatchTypes(const labelListList &addressing, const labelList &patchTypes, labelList &result) const
interpolate (= combine) patch types
Ostream & decrIndent(Ostream &os)
Decrement the indent level.
Definition: Ostream.H:511
Holds a reference to the original mesh (the baseMesh) and optionally to a subset of that mesh (the su...
Definition: fvMeshSubset.H:75
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.
List< word > wordList
List of word.
Definition: fileName.H:59
const labelListList & tgtToSrcCellAddr() const
Return const access to the target to source cell addressing.
Definition: meshToMeshI.H:44
const labelIOList & zoneID() const
Helper: get reference to registered zoneID. Loads volScalarField.
Volume-weighted interpolation stencil.
Class containing processor-to-processor mapping information.
label toGlobal(const label proci, const label i) const
From local to global on proci.
Definition: globalIndexI.H:308
static scalar defaultOverlapTolerance_
Default overlap tolerance. Fraction of volume.
label nCells() const noexcept
Number of mesh cells.
A list of pointers to objects of type <T>, with allocation/deallocation management of the pointers...
Definition: List.H:55
Foam::fvBoundaryMesh.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:56
virtual const labelUList & cellTypes() const
Return the cell type list.
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:328
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.
const autoPtr< mapDistribute > & tgtMap() const noexcept
Target map pointer - valid if no singleMeshProc.
Definition: meshToMeshI.H:108
messageStream Info
Information stream (stdout output on master, null elsewhere)
const scalarListList & srcToTgtCellWght() const
Return const access to the source to target cell weights.
Definition: meshToMeshI.H:50
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
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
A class for managing temporary objects.
Definition: HashPtrTable.H:50
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
void markPatchCells(const fvMesh &mesh, const labelList &cellMap, labelList &patchCellTypes) const
according to additionalDocumentation/MEJ_oversetMesh.txt
Ostream & incrIndent(Ostream &os)
Increment the indent level.
Definition: Ostream.H:502
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
Do not request registration (bool: false)
Namespace for OpenFOAM.
static tmp< volScalarField > createField(const fvMesh &mesh, const scalar val)
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.
const scalarListList & tgtToSrcCellWght() const
Return const access to the target to source cell weights.
Definition: meshToMeshI.H:56
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127