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-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 "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  false
534  ),
535  mesh_,
537  zeroGradientFvPatchScalarField::typeName
538  ),
539  allowInterpolatedDonors_
540  (
541  dict.getOrDefault("allowInterpolatedDonors", true)
542  )
543 {
544  // Protect local fields from interpolation
545  nonInterpolatedFields_.insert("cellTypes");
546  nonInterpolatedFields_.insert("cellInterpolationWeight");
547 
548  // For convenience also suppress frequently used displacement field
549  nonInterpolatedFields_.insert("cellDisplacement");
550  nonInterpolatedFields_.insert("grad(cellDisplacement)");
551  const word w("snGradCorr(cellDisplacement)");
552  const word d("((viscosity*faceDiffusivity)*magSf)");
553  nonInterpolatedFields_.insert("surfaceIntegrate(("+d+"*"+w+"))");
554 
555  // Read zoneID
556  this->zoneID();
557 
559  dict_.getOrDefault("overlapTolerance", defaultOverlapTolerance_);
560 
561  // Read old-time cellTypes
562  IOobject io
563  (
564  "cellTypes",
565  mesh_.time().timeName(),
566  mesh_,
569  false
570  );
571  if (io.typeHeaderOk<volScalarField>(true))
572  {
573  if (debug)
574  {
575  Pout<< "Reading cellTypes from time " << mesh_.time().timeName()
576  << endl;
577  }
578 
579  const volScalarField volCellTypes(io, mesh_);
580  forAll(volCellTypes, celli)
581  {
582  // Round to integer
583  cellTypes_[celli] = volCellTypes[celli];
584  }
585  }
586 
587  if (doUpdate)
588  {
589  update();
590  }
591 }
592 
593 
594 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
595 
597 {}
598 
599 
600 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
601 
603 {
604  scalar layerRelax(dict_.getOrDefault("layerRelax", 1.0));
605  const labelIOList& zoneID = this->zoneID();
606 
607  label nZones = gMax(zoneID)+1;
608  labelList nCellsPerZone(nZones, Zero);
609  forAll(zoneID, cellI)
610  {
611  nCellsPerZone[zoneID[cellI]]++;
612  }
614 
615  Info<< typeName << " : detected " << nZones
616  << " mesh regions" << nl << endl;
617 
618 
619  PtrList<fvMeshSubset> meshParts(nZones);
620 
621  Info<< incrIndent;
622  forAll(meshParts, zonei)
623  {
624  Info<< indent<< "zone:" << zonei << " nCells:"
625  << nCellsPerZone[zonei] << nl;
626 
627  meshParts.set
628  (
629  zonei,
630  new fvMeshSubset(mesh_, zonei, zoneID)
631  );
632  }
633  Info<< decrIndent;
634 
635 
636  // Current best guess for cells. Includes best stencil. Weights should
637  // add up to volume.
638  labelList allCellTypes(mesh_.nCells(), CALCULATED);
639  labelList allPatchTypes(mesh_.nCells(), OTHER);
640  labelListList allStencil(mesh_.nCells());
641  scalarListList allWeights(mesh_.nCells());
642  // zoneID of donor
643  labelList allDonorID(mesh_.nCells(), -1);
644 
645 
646  // Marking patch cells
647  forAll(meshParts, partI)
648  {
649  const fvMesh& partMesh = meshParts[partI].subMesh();
650  const labelList& partCellMap = meshParts[partI].cellMap();
651 
652  // Mark cells with
653  // - overset boundary
654  // - other, proper boundary
655  // - other cells
656  Info<< "Marking patch-cells on zone " << partI << endl;
657  markPatchCells(partMesh, partCellMap, allPatchTypes);
658  }
659 
660  if ((debug&2) && (mesh_.time().outputTime()))
661  {
663  (
664  createField(mesh_, "allPatchTypes", allPatchTypes)
665  );
666  tfld().write();
667  }
668 
669 
670  labelList nCells(count(3, allPatchTypes));
671  Info<< nl
672  << "After patch analysis : nCells : "
673  << returnReduce(allPatchTypes.size(), sumOp<label>()) << nl
674  << incrIndent
675  << indent << "other : " << nCells[OTHER] << nl
676  << indent << "patch : " << nCells[PATCH] << nl
677  << indent << "overset: " << nCells[OVERSET] << nl
678  << decrIndent << endl;
679 
680  globalIndex globalCells(mesh_.nCells());
681 
682  for (label srcI = 0; srcI < meshParts.size()-1; srcI++)
683  {
684  const fvMesh& srcMesh = meshParts[srcI].subMesh();
685  const labelList& srcCellMap = meshParts[srcI].cellMap();
686 
687  for (label tgtI = srcI+1; tgtI < meshParts.size(); tgtI++)
688  {
689  const fvMesh& tgtMesh = meshParts[tgtI].subMesh();
690  const labelList& tgtCellMap = meshParts[tgtI].cellMap();
691 
692  meshToMesh mapper
693  (
694  srcMesh,
695  tgtMesh,
697  HashTable<word>(0), // patchMap,
698  wordList(0), // cuttingPatches
700  false // do not normalise
701  );
702 
703  {
704  // Get tgt patch types on src mesh
705  labelList interpolatedTgtPatchTypes(srcMesh.nCells(), -1);
706  interpolatePatchTypes
707  (
708  mapper.tgtMap(), // How to get remote data local
709  mapper.srcToTgtCellAddr(),
710  labelList(labelUIndList(allPatchTypes, tgtCellMap)),
711  interpolatedTgtPatchTypes
712  );
713 
714  // Get target cell labels in global cell indexing (on overall
715  // mesh)
716  labelList tgtGlobalCells(tgtMesh.nCells());
717  {
718  forAll(tgtCellMap, tgtCellI)
719  {
720  label cellI = tgtCellMap[tgtCellI];
721  tgtGlobalCells[tgtCellI] = globalCells.toGlobal(cellI);
722  }
723  if (mapper.tgtMap())
724  {
725  mapper.tgtMap()->distribute(tgtGlobalCells);
726  }
727  }
728 
729 
730  combineCellTypes
731  (
732  srcI,
733  srcMesh,
734  srcCellMap,
735 
736  tgtI,
737  mapper.srcToTgtCellAddr(),
738  mapper.srcToTgtCellWght(),
739  tgtGlobalCells,
740  interpolatedTgtPatchTypes,
741 
742  // Overall mesh data
743  allStencil,
744  allWeights,
745  allCellTypes,
746  allDonorID
747  );
748  }
749 
750  {
751  // Get src patch types on tgt mesh
752  labelList interpolatedSrcPatchTypes(tgtMesh.nCells(), -1);
753  interpolatePatchTypes
754  (
755  mapper.srcMap(), // How to get remote data local
756  mapper.tgtToSrcCellAddr(),
757  labelList(labelUIndList(allPatchTypes, srcCellMap)),
758  interpolatedSrcPatchTypes
759  );
760 
761  labelList srcGlobalCells(srcMesh.nCells());
762  {
763  forAll(srcCellMap, srcCellI)
764  {
765  label cellI = srcCellMap[srcCellI];
766  srcGlobalCells[srcCellI] = globalCells.toGlobal(cellI);
767  }
768  if (mapper.srcMap())
769  {
770  mapper.srcMap()->distribute(srcGlobalCells);
771  }
772  }
773 
774  combineCellTypes
775  (
776  tgtI,
777  tgtMesh,
778  tgtCellMap,
779 
780  srcI,
781  mapper.tgtToSrcCellAddr(),
782  mapper.tgtToSrcCellWght(),
783  srcGlobalCells,
784  interpolatedSrcPatchTypes,
785 
786  // Overall mesh data
787  allStencil,
788  allWeights,
789  allCellTypes,
790  allDonorID
791  );
792  }
793  }
794  }
795 
796 
797  if ((debug&2) && (mesh_.time().outputTime()))
798  {
800  (
801  createField(mesh_, "allCellTypes", allCellTypes)
802  );
803  tfld().write();
804 
805  tmp<volScalarField> tdonors
806  (
807  createField(mesh_, "allDonorID", allDonorID)
808  );
809  tdonors().write();
810 
811  }
812 
813 
814  // Use the patch types and weights to decide what to do
815  forAll(allPatchTypes, cellI)
816  {
817  if (allCellTypes[cellI] != HOLE)
818  {
819  switch (allPatchTypes[cellI])
820  {
821  case OVERSET:
822  {
823  // Interpolate. Check if enough overlap
824  scalar v = mesh_.V()[cellI];
825  scalar overlapVol = sum(allWeights[cellI]);
826  if (overlapVol > overlapTolerance_*v)
827  {
828  allCellTypes[cellI] = INTERPOLATED;
829  }
830  else
831  {
832  allCellTypes[cellI] = HOLE;
833  allWeights[cellI].clear();
834  allStencil[cellI].clear();
835  }
836  break;
837  }
838  }
839  }
840  }
841 
842 
843  if ((debug&2) && (mesh_.time().outputTime()))
844  {
846  (
847  createField(mesh_, "allCellTypes_patch", allCellTypes)
848  );
849  tfld().write();
850 
851  labelList stencilSize(mesh_.nCells());
852  forAll(allStencil, celli)
853  {
854  stencilSize[celli] = allStencil[celli].size();
855  }
856  tmp<volScalarField> tfldStencil
857  (
858  createField(mesh_, "allStencil_patch", stencilSize)
859  );
860  tfldStencil().write();
861  }
862 
863 
864  // Mark unreachable bits
865  findHoles(globalCells, mesh_, zoneID, allStencil, allCellTypes);
866 
867  if ((debug&2) && (mesh_.time().outputTime()))
868  {
870  (
871  createField(mesh_, "allCellTypes_hole", allCellTypes)
872  );
873  tfld().write();
874 
875  labelList stencilSize(mesh_.nCells());
876  forAll(allStencil, celli)
877  {
878  stencilSize[celli] = allStencil[celli].size();
879  }
880  tmp<volScalarField> tfldStencil
881  (
882  createField(mesh_, "allStencil_hole", stencilSize)
883  );
884  tfldStencil().write();
885  }
886 
887 
888  // Add buffer interpolation layer around holes
889  scalarField allWeight(mesh_.nCells(), Zero);
890 
891  labelListList compactStencil(allStencil);
892  List<Map<label>> compactStencilMap;
893  mapDistribute map(globalCells, compactStencil, compactStencilMap);
894 
895  scalarList compactCellVol(mesh_.V());
896  map.distribute(compactCellVol);
897 
898  walkFront
899  (
900  globalCells,
901  layerRelax,
902  allStencil,
903  allCellTypes,
904  allWeight,
905  compactCellVol,
906  compactStencil,
907  zoneID,
908  dict_.getOrDefault("holeLayers", 1),
909  dict_.getOrDefault("useLayer", -1)
910  );
911 
912 
913  if ((debug&2) && (mesh_.time().outputTime()))
914  {
916  (
917  createField(mesh_, "allCellTypes_front", allCellTypes)
918  );
919  tfld().write();
920 
921  labelList stencilSize(mesh_.nCells());
922  forAll(allStencil, celli)
923  {
924  stencilSize[celli] = allStencil[celli].size();
925  }
926  tmp<volScalarField> tfldStencil
927  (
928  createField(mesh_, "allStencil_front", stencilSize)
929  );
930  tfldStencil().write();
931  }
932 
933  // Check previous iteration cellTypes_ for any hole->calculated changes
934  // If so set the cell either to interpolated (if there are donors) or
935  // holes (if there are no donors). Note that any interpolated cell might
936  // still be overwritten by the flood filling
937  {
938  label nCalculated = 0;
939 
940  forAll(cellTypes_, celli)
941  {
942  if (allCellTypes[celli] == CALCULATED && cellTypes_[celli] == HOLE)
943  {
944  if (allStencil[celli].size() == 0)
945  {
946  // Reset to hole
947  allCellTypes[celli] = HOLE;
948  allWeights[celli].clear();
949  allStencil[celli].clear();
950  }
951  else
952  {
953  allCellTypes[celli] = INTERPOLATED;
954  nCalculated++;
955  }
956  }
957  }
958 
959  if (debug)
960  {
961  Pout<< "Detected " << nCalculated << " cells changing from hole"
962  << " to calculated. Changed these to interpolated"
963  << endl;
964  }
965  }
966 
967 
968  labelList compactCellTypes(allCellTypes);
969  map.distribute(compactCellTypes);
970 
971  label nHoleDonors = 0;
972  forAll(allCellTypes, cellI)
973  {
974  if (allCellTypes[cellI] == INTERPOLATED)
975  {
976  const labelList& slots = compactStencil[cellI];
977  forAll (slots, subCellI)
978  {
979  if
980  (
981  compactCellTypes[slots[0]] == HOLE
982  ||
983  (
984  !allowInterpolatedDonors_
985  && compactCellTypes[slots[0]] == INTERPOLATED
986  )
987  )
988  {
989  allWeights[cellI][subCellI] = 0;
990  nHoleDonors++;
991  }
992  }
993  }
994  else
995  {
996  allWeights[cellI].clear();
997  allStencil[cellI].clear();
998  }
999  }
1000  reduce(nHoleDonors, sumOp<label>());
1001 
1002 
1003  // Normalize weights
1004  forAll(allCellTypes, cellI)
1005  {
1006  if (allCellTypes[cellI] == INTERPOLATED)
1007  {
1008  const scalar s = sum(allWeights[cellI]);
1009 
1010  if (s < SMALL)
1011  {
1012  allCellTypes[cellI] = POROUS;
1013  allWeights[cellI].clear();
1014  allStencil[cellI].clear();
1015  }
1016  else
1017  {
1018  forAll(allWeights[cellI], i)
1019  {
1020  allWeights[cellI][i] /= s;
1021  }
1022  }
1023  }
1024  }
1025 
1026  // Write to volField for debugging
1027  if ((debug&2) && (mesh_.time().outputTime()))
1028  {
1029  if ((debug&2) && (mesh_.time().outputTime()))
1030  {
1031  tmp<volScalarField> tfld
1032  (
1033  createField(mesh_, "allCellTypes_final", allCellTypes)
1034  );
1035  tfld().write();
1036  }
1037  }
1038 
1039 
1040  cellTypes_.transfer(allCellTypes);
1041  cellStencil_.transfer(allStencil);
1042  cellInterpolationWeights_.transfer(allWeights);
1043  cellInterpolationWeight_.transfer(allWeight);
1044  //cellInterpolationWeight_.correctBoundaryConditions();
1046  <
1049  >(cellInterpolationWeight_.boundaryFieldRef(), false);
1050 
1051  DynamicList<label> interpolationCells;
1052  forAll(cellStencil_, cellI)
1053  {
1054  if (cellStencil_[cellI].size())
1055  {
1056  interpolationCells.append(cellI);
1057  }
1058  }
1059  interpolationCells_.transfer(interpolationCells);
1060 
1061 
1062  List<Map<label>> compactMap;
1063  cellInterpolationMap_.reset
1064  (
1065  new mapDistribute(globalCells, cellStencil_, compactMap)
1066  );
1067 
1068  // Dump interpolation stencil
1069  if ((debug&2) && (mesh_.time().outputTime()))
1070  {
1071  // Dump weight
1072  cellInterpolationWeight_.instance() = mesh_.time().timeName();
1073  cellInterpolationWeight_.write();
1074 
1075 
1076  mkDir(mesh_.time().timePath());
1077  OBJstream str(mesh_.time().timePath()/"stencil2.obj");
1078  Info<< typeName << " : dumping to " << str.name() << endl;
1079  pointField cc(mesh_.cellCentres());
1080  cellInterpolationMap().distribute(cc);
1081 
1082  forAll(interpolationCells_, compactI)
1083  {
1084  label cellI = interpolationCells_[compactI];
1085  const labelList& slots = cellStencil_[cellI];
1086 
1087  Pout<< "cellI:" << cellI << " at:"
1088  << mesh_.cellCentres()[cellI]
1089  << " calculated from slots:" << slots
1090  << " cc:" << UIndirectList<point>(cc, slots)
1091  << " weights:" << cellInterpolationWeights_[cellI]
1092  << endl;
1093 
1094  forAll(slots, i)
1095  {
1096  if (cellInterpolationWeights_[cellI][slots[i]] > 0)
1097  {
1098  const point& donorCc = cc[slots[i]];
1099  const point& accCc = mesh_.cellCentres()[cellI];
1100  str.writeLine(accCc, 0.1*accCc+0.9*donorCc);
1101  }
1102  }
1103  }
1104  }
1105 
1106  {
1107  labelList nCells(count(3, cellTypes_));
1108  Info<< "Overset analysis : nCells : "
1109  << returnReduce(cellTypes_.size(), sumOp<label>()) << nl
1110  << incrIndent
1111  << indent << "calculated : " << nCells[CALCULATED] << nl
1112  << indent << "interpolated : " << nCells[INTERPOLATED] << nl
1113  << indent << "hole : " << nCells[HOLE] << nl
1114  << decrIndent << endl;
1115  }
1116 
1117  return true;
1118 }
1119 
1122 (
1123  const point& sample,
1124  const pointList& donorCcs,
1125  scalarList& weights
1126 ) const
1127 {
1128  // Inverse-distance weighting
1129 
1130  weights.setSize(donorCcs.size());
1131  scalar sum = 0.0;
1132  forAll(donorCcs, i)
1133  {
1134  scalar d = mag(sample-donorCcs[i]);
1135 
1136  if (d > ROOTVSMALL)
1137  {
1138  weights[i] = 1.0/d;
1139  sum += weights[i];
1140  }
1141  else
1142  {
1143  // Short circuit
1144  weights = 0.0;
1145  weights[i] = 1.0;
1146  return;
1147  }
1148  }
1149  forAll(weights, i)
1150  {
1151  weights[i] /= sum;
1152  }
1153 }
1154 
1155 
1156 // ************************************************************************* //
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:136
List< labelList > labelListList
A List of labelList.
Definition: labelList.H:51
scalar overlapTolerance_
Tolerance for volume overlap. Fraction of volume.
dictionary dict
const autoPtr< mapDistribute > & tgtMap() const
Target map pointer - valid if no singleMeshProc.
Definition: meshToMeshI.H:88
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:118
Ostream & indent(Ostream &os)
Indent stream.
Definition: Ostream.H:449
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:120
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:578
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 data using default commsType.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
wordList patchTypes(nPatches)
virtual bool update()
Update stencils. Return false if nothing changed.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
A finiteVolume patch using a polyPatch and a fvBoundaryMesh.
Definition: fvPatch.H:68
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)
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: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.
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)
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:413
const dictionary dict_
Dictionary of motion control parameters.
GeometricField< scalar, fvPatchField, volMesh > volScalarField
Definition: volFieldsFwd.H:84
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 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:63
PDRpatchDef PATCH
Definition: PDRpatchDef.H:120
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
Calculation of interpolation stencils.
const autoPtr< mapDistribute > & srcMap() const
Source map pointer - valid if no singleMeshProc.
Definition: meshToMeshI.H:81
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
virtual const labelUList & faceCells() const
Return faceCells.
Definition: fvPatch.C:107
label size() const noexcept
The number of elements in the list.
Definition: UPtrListI.H:99
A HashTable similar to std::unordered_map.
Definition: HashTable.H:102
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
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 time name of given scalar time formatted with the given precision.
Definition: Time.C:760
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:467
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
A List of words.
Definition: fileName.H:58
const labelListList & tgtToSrcCellAddr() const
Return const access to the target to source cell addressing.
Definition: meshToMeshI.H:44
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
Volume-weighted interpolation stencil.
Class containing processor-to-processor mapping information.
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:79
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:57
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.
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
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:458
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:166
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
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.
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:157