meshRefinement.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration | Website: https://openfoam.org
5  \\ / A nd | Copyright (C) 2011-2022 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #include "meshRefinement.H"
27 #include "volMesh.H"
28 #include "volFields.H"
29 #include "surfaceMesh.H"
30 #include "syncTools.H"
31 #include "Time.H"
32 #include "refinementHistory.H"
33 #include "refinementSurfaces.H"
34 #include "refinementFeatures.H"
35 #include "decompositionMethod.H"
36 #include "regionSplit.H"
37 #include "fvMeshDistribute.H"
38 #include "indirectPrimitivePatch.H"
39 #include "polyTopoChange.H"
40 #include "removeCells.H"
41 #include "polyDistributionMap.H"
42 #include "localPointRegion.H"
43 #include "pointMesh.H"
44 #include "pointFields.H"
45 #include "slipPointPatchFields.H"
49 #include "processorPointPatch.H"
50 #include "globalIndex.H"
51 #include "meshTools.H"
52 #include "OFstream.H"
53 #include "geomDecomp.H"
54 #include "Random.H"
55 #include "searchableSurfaces.H"
56 #include "treeBoundBox.H"
57 #include "fvMeshTools.H"
58 
59 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
60 
61 namespace Foam
62 {
63  defineTypeNameAndDebug(meshRefinement, 0);
64 
65  template<>
66  const char* Foam::NamedEnum
67  <
69  5
70  >::names[] =
71  {
72  "mesh",
73  "intersections",
74  "featureSeeds",
75  "attraction",
76  "layerInfo"
77  };
78 
79  template<>
80  const char* Foam::NamedEnum
81  <
83  1
84  >::names[] =
85  {
86  "layerInfo"
87  };
88 
89  template<>
90  const char* Foam::NamedEnum
91  <
93  5
94  >::names[] =
95  {
96  "mesh",
97  "noRefinement",
98  "scalarLevels",
99  "layerSets",
100  "layerFields"
101  };
102 
103 }
104 
107 
110 
113 
114 
115 Foam::meshRefinement::writeType Foam::meshRefinement::writeLevel_;
116 
117 Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel_;
118 
119 
120 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
121 
122 void Foam::meshRefinement::calcNeighbourData
123 (
124  labelList& neiLevel,
125  pointField& neiCc
126 ) const
127 {
128  const labelList& cellLevel = meshCutter_.cellLevel();
129  const pointField& cellCentres = mesh_.cellCentres();
130 
131  const label nBoundaryFaces = mesh_.nFaces() - mesh_.nInternalFaces();
132 
133  if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
134  {
136  << nBoundaryFaces << " neiLevel:" << neiLevel.size()
137  << abort(FatalError);
138  }
139 
140  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
141 
142  labelHashSet addedPatchIDSet(meshedPatches());
143 
144  forAll(patches, patchi)
145  {
146  const polyPatch& pp = patches[patchi];
147 
148  const labelUList& faceCells = pp.faceCells();
149  const vectorField::subField faceCentres = pp.faceCentres();
150  const vectorField::subField faceAreas = pp.faceAreas();
151 
152  label bFacei = pp.start() - mesh_.nInternalFaces();
153 
154  if (pp.coupled())
155  {
156  forAll(faceCells, i)
157  {
158  neiLevel[bFacei] = cellLevel[faceCells[i]];
159  neiCc[bFacei] = cellCentres[faceCells[i]];
160  bFacei++;
161  }
162  }
163  else if (addedPatchIDSet.found(patchi))
164  {
165  // Face was introduced from cell-cell intersection. Try to
166  // reconstruct other side cell(centre). Three possibilities:
167  // - cells same size.
168  // - preserved cell smaller. Not handled.
169  // - preserved cell larger.
170  forAll(faceCells, i)
171  {
172  // Extrapolate the face centre.
173  const vector fn = faceAreas[i]/(mag(faceAreas[i]) + vSmall);
174 
175  const label own = faceCells[i];
176  const label ownLevel = cellLevel[own];
177  const label faceLevel = meshCutter_.faceLevel(pp.start() + i);
178 
179  // Normal distance from face centre to cell centre
180  scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
181  if (faceLevel > ownLevel)
182  {
183  // Other cell more refined. Adjust normal distance
184  d *= 0.5;
185  }
186  neiLevel[bFacei] = faceLevel;
187  // Calculate other cell centre by extrapolation
188  neiCc[bFacei] = faceCentres[i] + d*fn;
189  bFacei++;
190  }
191  }
192  else
193  {
194  forAll(faceCells, i)
195  {
196  neiLevel[bFacei] = cellLevel[faceCells[i]];
197  neiCc[bFacei] = faceCentres[i];
198  bFacei++;
199  }
200  }
201  }
202 
203  // Swap coupled boundaries. Apply separation to cc since is coordinate.
205  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
206 }
207 
208 
209 void Foam::meshRefinement::updateIntersections(const labelList& changedFaces)
210 {
211  const pointField& cellCentres = mesh_.cellCentres();
212 
213  // Stats on edges to test. Count proc faces only once.
214  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
215 
216  {
217  label nMasterFaces = 0;
218  forAll(isMasterFace, facei)
219  {
220  if (isMasterFace.get(facei) == 1)
221  {
222  nMasterFaces++;
223  }
224  }
225  reduce(nMasterFaces, sumOp<label>());
226 
227  label nChangedFaces = 0;
228  forAll(changedFaces, i)
229  {
230  if (isMasterFace.get(changedFaces[i]) == 1)
231  {
232  nChangedFaces++;
233  }
234  }
235  reduce(nChangedFaces, sumOp<label>());
236 
237  Info<< "Edge intersection testing:" << nl
238  << " Number of edges : " << nMasterFaces << nl
239  << " Number of edges to retest : " << nChangedFaces
240  << endl;
241  }
242 
243 
244  // Get boundary face centre and level. Coupled aware.
245  labelList neiLevel(mesh_.nFaces() - mesh_.nInternalFaces());
246  pointField neiCc(mesh_.nFaces() - mesh_.nInternalFaces());
247  calcNeighbourData(neiLevel, neiCc);
248 
249  // Collect segments we want to test for
250  pointField start(changedFaces.size());
251  pointField end(changedFaces.size());
252 
253  forAll(changedFaces, i)
254  {
255  const label facei = changedFaces[i];
256  const label own = mesh_.faceOwner()[facei];
257 
258  start[i] = cellCentres[own];
259  if (mesh_.isInternalFace(facei))
260  {
261  end[i] = cellCentres[mesh_.faceNeighbour()[facei]];
262  }
263  else
264  {
265  end[i] = neiCc[facei-mesh_.nInternalFaces()];
266  }
267  }
268 
269  // Extend segments a bit
270  {
271  const vectorField smallVec(rootSmall*(end-start));
272  start -= smallVec;
273  end += smallVec;
274  }
275 
276 
277  // Do tests in one go
278  labelList surfaceHit;
279  {
280  labelList surfaceLevel;
281  surfaces_.findHigherIntersection
282  (
283  start,
284  end,
285  labelList(start.size(), -1), // accept any intersection
286  surfaceHit,
287  surfaceLevel
288  );
289  }
290 
291  // Keep just surface hit
292  forAll(surfaceHit, i)
293  {
294  surfaceIndex_[changedFaces[i]] = surfaceHit[i];
295  }
296 
297  // Make sure both sides have same information. This should be
298  // case in general since same vectors but just to make sure.
299  syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>());
300 
301  const label nHits = countHits();
302  const label nTotHits = returnReduce(nHits, sumOp<label>());
303 
304  Info<< " Number of intersected edges : " << nTotHits << endl;
305 
306  // Set files to same time as mesh
307  setInstance(mesh_.facesInstance());
308 }
309 
310 
312 (
313  const string& msg,
314  const polyMesh& mesh,
315  const List<scalar>& fld
316 )
317 {
318  if (fld.size() != mesh.nPoints())
319  {
321  << msg << endl
322  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
323  << abort(FatalError);
324  }
325 
326  Pout<< "Checking field " << msg << endl;
327  scalarField minFld(fld);
329  (
330  mesh,
331  minFld,
332  minEqOp<scalar>(),
333  great
334  );
335  scalarField maxFld(fld);
337  (
338  mesh,
339  maxFld,
340  maxEqOp<scalar>(),
341  -great
342  );
343  forAll(minFld, pointi)
344  {
345  const scalar& minVal = minFld[pointi];
346  const scalar& maxVal = maxFld[pointi];
347  if (mag(minVal-maxVal) > small)
348  {
349  Pout<< msg << " at:" << mesh.points()[pointi] << nl
350  << " minFld:" << minVal << nl
351  << " maxFld:" << maxVal << nl
352  << endl;
353  }
354  }
355 }
356 
357 
359 (
360  const string& msg,
361  const polyMesh& mesh,
362  const List<point>& fld
363 )
364 {
365  if (fld.size() != mesh.nPoints())
366  {
368  << msg << endl
369  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
370  << abort(FatalError);
371  }
372 
373  Pout<< "Checking field " << msg << endl;
374  pointField minFld(fld);
376  (
377  mesh,
378  minFld,
380  point(great, great, great)
381  );
382  pointField maxFld(fld);
384  (
385  mesh,
386  maxFld,
389  );
390  forAll(minFld, pointi)
391  {
392  const point& minVal = minFld[pointi];
393  const point& maxVal = maxFld[pointi];
394  if (mag(minVal-maxVal) > small)
395  {
396  Pout<< msg << " at:" << mesh.points()[pointi] << nl
397  << " minFld:" << minVal << nl
398  << " maxFld:" << maxVal << nl
399  << endl;
400  }
401  }
402 }
403 
404 
406 {
407  Pout<< "meshRefinement::checkData() : Checking refinement structure."
408  << endl;
409  meshCutter_.checkMesh();
410 
411  Pout<< "meshRefinement::checkData() : Checking refinement levels."
412  << endl;
413  meshCutter_.checkRefinementLevels(1, labelList(0));
414 
415 
416  label nBnd = mesh_.nFaces() - mesh_.nInternalFaces();
417 
418  Pout<< "meshRefinement::checkData() : Checking synchronisation."
419  << endl;
420 
421  // Check face centres
422  {
423  // Boundary face centres
424  pointField::subList boundaryFc
425  (
426  mesh_.faceCentres(),
427  nBnd,
428  mesh_.nInternalFaces()
429  );
430 
431  // Get neighbouring face centres
432  pointField neiBoundaryFc(boundaryFc);
434  (
435  mesh_,
436  neiBoundaryFc,
437  eqOp<point>()
438  );
439 
440  // Compare
441  testSyncBoundaryFaceList
442  (
443  mergeDistance_,
444  "testing faceCentres : ",
445  boundaryFc,
446  neiBoundaryFc
447  );
448  }
449  // Check meshRefinement
450  {
451  // Get boundary face centre and level. Coupled aware.
452  labelList neiLevel(nBnd);
453  pointField neiCc(nBnd);
454  calcNeighbourData(neiLevel, neiCc);
455 
456  // Collect segments we want to test for
457  pointField start(mesh_.nFaces());
458  pointField end(mesh_.nFaces());
459 
460  forAll(start, facei)
461  {
462  start[facei] = mesh_.cellCentres()[mesh_.faceOwner()[facei]];
463 
464  if (mesh_.isInternalFace(facei))
465  {
466  end[facei] = mesh_.cellCentres()[mesh_.faceNeighbour()[facei]];
467  }
468  else
469  {
470  end[facei] = neiCc[facei-mesh_.nInternalFaces()];
471  }
472  }
473 
474  // Extend segments a bit
475  {
476  const vectorField smallVec(rootSmall*(end-start));
477  start -= smallVec;
478  end += smallVec;
479  }
480 
481 
482  // Do tests in one go
483  labelList surfaceHit;
484  {
485  labelList surfaceLevel;
486  surfaces_.findHigherIntersection
487  (
488  start,
489  end,
490  labelList(start.size(), -1), // accept any intersection
491  surfaceHit,
492  surfaceLevel
493  );
494  }
495  // Get the coupled hit
496  labelList neiHit
497  (
499  (
500  surfaceHit,
501  nBnd,
502  mesh_.nInternalFaces()
503  )
504  );
505  syncTools::swapBoundaryFaceList(mesh_, neiHit);
506 
507  // Check
508  forAll(surfaceHit, facei)
509  {
510  if (surfaceIndex_[facei] != surfaceHit[facei])
511  {
512  if (mesh_.isInternalFace(facei))
513  {
515  << "Internal face:" << facei
516  << " fc:" << mesh_.faceCentres()[facei]
517  << " cached surfaceIndex_:" << surfaceIndex_[facei]
518  << " current:" << surfaceHit[facei]
519  << " ownCc:"
520  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
521  << " neiCc:"
522  << mesh_.cellCentres()[mesh_.faceNeighbour()[facei]]
523  << endl;
524  }
525  else if
526  (
527  surfaceIndex_[facei]
528  != neiHit[facei-mesh_.nInternalFaces()]
529  )
530  {
532  << "Boundary face:" << facei
533  << " fc:" << mesh_.faceCentres()[facei]
534  << " cached surfaceIndex_:" << surfaceIndex_[facei]
535  << " current:" << surfaceHit[facei]
536  << " ownCc:"
537  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
538  << " end:" << end[facei]
539  << endl;
540  }
541  }
542  }
543  }
544  {
545  labelList::subList boundarySurface
546  (
547  surfaceIndex_,
548  mesh_.nFaces() - mesh_.nInternalFaces(),
549  mesh_.nInternalFaces()
550  );
551 
552  labelList neiBoundarySurface(boundarySurface);
554  (
555  mesh_,
556  neiBoundarySurface
557  );
558 
559  // Compare
560  testSyncBoundaryFaceList
561  (
562  0, // tolerance
563  "testing surfaceIndex() : ",
564  boundarySurface,
565  neiBoundarySurface
566  );
567  }
568 
569 
570  // Find duplicate faces
571  Pout<< "meshRefinement::checkData() : Counting duplicate faces."
572  << endl;
573 
574  labelList duplicateFace
575  (
577  (
578  mesh_,
579  identity(mesh_.nFaces() - mesh_.nInternalFaces())
580  + mesh_.nInternalFaces()
581  )
582  );
583 
584  // Count
585  {
586  label nDup = 0;
587 
588  forAll(duplicateFace, i)
589  {
590  if (duplicateFace[i] != -1)
591  {
592  nDup++;
593  }
594  }
595  nDup /= 2; // will have counted both faces of duplicate
596  Pout<< "meshRefinement::checkData() : Found " << nDup
597  << " duplicate pairs of faces." << endl;
598  }
599 }
600 
601 
603 {
604  meshCutter_.setInstance(inst);
605  surfaceIndex_.instance() = inst;
606 }
607 
608 
609 Foam::autoPtr<Foam::polyTopoChangeMap> Foam::meshRefinement::doRemoveCells
610 (
611  const labelList& cellsToRemove,
612  const labelList& exposedFaces,
613  const labelList& exposedPatchIDs,
614  removeCells& cellRemover
615 )
616 {
617  polyTopoChange meshMod(mesh_);
618 
619  // Arbitrary: put exposed faces into last patch.
620  cellRemover.setRefinement
621  (
622  cellsToRemove,
623  exposedFaces,
624  exposedPatchIDs,
625  meshMod
626  );
627 
628  // Change the mesh (no inflation)
629  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh_, false, true);
630 
631  // Update fields
632  mesh_.topoChange(map);
633 
634  // Move mesh (since morphing might not do this)
635  if (map().hasMotionPoints())
636  {
637  mesh_.movePoints(map().preMotionPoints());
638  }
639  else
640  {
641  // Delete mesh volumes. No other way to do this?
642  mesh_.clearOut();
643  }
644 
645  // Reset the instance for if in overwrite mode
646  mesh_.setInstance(timeName());
647  setInstance(mesh_.facesInstance());
648 
649  // Update local mesh data
650  cellRemover.topoChange(map);
651 
652  // Update intersections. Recalculate intersections for exposed faces.
653  labelList newExposedFaces = renumber
654  (
655  map().reverseFaceMap(),
656  exposedFaces
657  );
658 
659  // Pout<< "removeCells : updating intersections for "
660  // << newExposedFaces.size() << " newly exposed faces." << endl;
661 
662  topoChange(map, newExposedFaces);
663 
664  return map;
665 }
666 
667 
669 (
670  const labelList& splitFaces,
671  const labelPairList& splits
672 )
673 {
674  polyTopoChange meshMod(mesh_);
675 
676  forAll(splitFaces, i)
677  {
678  const label facei = splitFaces[i];
679  const face& f = mesh_.faces()[facei];
680 
681  // Split as start and end index in face
682  const labelPair& split = splits[i];
683 
684  label nVerts = split[1] - split[0];
685  if (nVerts < 0)
686  {
687  nVerts += f.size();
688  }
689  nVerts += 1;
690 
691 
692  // Split into f0, f1
693  face f0(nVerts);
694 
695  label fp = split[0];
696  forAll(f0, i)
697  {
698  f0[i] = f[fp];
699  fp = f.fcIndex(fp);
700  }
701 
702  face f1(f.size() - f0.size() + 2);
703  fp = split[1];
704  forAll(f1, i)
705  {
706  f1[i] = f[fp];
707  fp = f.fcIndex(fp);
708  }
709 
710 
711  // Determine face properties
712  const label own = mesh_.faceOwner()[facei];
713  label nei = -1;
714  label patchi = -1;
715  if (facei >= mesh_.nInternalFaces())
716  {
717  patchi = mesh_.boundaryMesh().whichPatch(facei);
718  }
719  else
720  {
721  nei = mesh_.faceNeighbour()[facei];
722  }
723 
724  const label zonei = mesh_.faceZones().whichZone(facei);
725  bool zoneFlip = false;
726  if (zonei != -1)
727  {
728  const faceZone& fz = mesh_.faceZones()[zonei];
729  zoneFlip = fz.flipMap()[fz.whichFace(facei)];
730  }
731 
732 
733  if (debug)
734  {
735  Pout<< "face:" << facei << " verts:" << f
736  << " split into f0:" << f0
737  << " f1:" << f1 << endl;
738  }
739 
740  // Change/add faces
741  meshMod.modifyFace
742  (
743  f0, // modified face
744  facei, // label of face
745  own, // owner
746  nei, // neighbour
747  false, // face flip
748  patchi, // patch for face
749  zonei, // zone for face
750  zoneFlip // face flip in zone
751  );
752 
753  meshMod.addFace
754  (
755  f1, // modified face
756  own, // owner
757  nei, // neighbour
758  -1, // master point
759  -1, // master edge
760  facei, // master face
761  false, // face flip
762  patchi, // patch for face
763  zonei, // zone for face
764  zoneFlip // face flip in zone
765  );
766  }
767 
768 
769 
770  // Change the mesh (no inflation)
771  autoPtr<polyTopoChangeMap> map = meshMod.changeMesh(mesh_, false, true);
772 
773  // Update fields
774  mesh_.topoChange(map);
775 
776  // Move mesh (since morphing might not do this)
777  if (map().hasMotionPoints())
778  {
779  mesh_.movePoints(map().preMotionPoints());
780  }
781  else
782  {
783  // Delete mesh volumes. No other way to do this?
784  mesh_.clearOut();
785  }
786 
787  // Reset the instance for if in overwrite mode
788  mesh_.setInstance(timeName());
789  setInstance(mesh_.facesInstance());
790 
791  // Update local mesh data
792  const labelList& oldToNew = map().reverseFaceMap();
793  labelList newSplitFaces(renumber(oldToNew, splitFaces));
794  // Add added faces (every splitFaces becomes two faces)
795  label sz = newSplitFaces.size();
796  newSplitFaces.setSize(2*sz);
797  forAll(map().faceMap(), facei)
798  {
799  label oldFacei = map().faceMap()[facei];
800  if (oldToNew[oldFacei] != facei)
801  {
802  // Added face
803  newSplitFaces[sz++] = facei;
804  }
805  }
806 
807  topoChange(map, newSplitFaces);
808 
809  return map;
810 }
811 
812 
815 //void Foam::meshRefinement::getCoupledRegionMaster
816 //(
817 // const globalIndex& globalCells,
818 // const boolList& blockedFace,
819 // const regionSplit& globalRegion,
820 // Map<label>& regionToMaster
821 //) const
822 //{
823 // const polyBoundaryMesh& patches = mesh_.boundaryMesh();
824 //
825 // forAll(patches, patchi)
826 // {
827 // const polyPatch& pp = patches[patchi];
828 //
829 // if (isA<processorPolyPatch>(pp))
830 // {
831 // forAll(pp, i)
832 // {
833 // label facei = pp.start() + i;
834 //
835 // if (!blockedFace[facei])
836 // {
837 // // Only if there is a connection to the neighbour
838 // // will there be a multi-domain region; if not through
839 // // this face then through another.
840 //
841 // label celli = mesh_.faceOwner()[facei];
842 // label globalCelli = globalCells.toGlobal(celli);
843 //
844 // Map<label>::iterator iter =
845 // regionToMaster.find(globalRegion[celli]);
846 //
847 // if (iter != regionToMaster.end())
848 // {
849 // label master = iter();
850 // iter() = min(master, globalCelli);
851 // }
852 // else
853 // {
854 // regionToMaster.insert
855 // (
856 // globalRegion[celli],
857 // globalCelli
858 // );
859 // }
860 // }
861 // }
862 // }
863 // }
864 //
865 // // Do reduction
866 // Pstream::mapCombineGather(regionToMaster, minEqOp<label>());
867 // Pstream::mapCombineScatter(regionToMaster);
868 //}
869 //
870 //
871 //void Foam::meshRefinement::calcLocalRegions
872 //(
873 // const globalIndex& globalCells,
874 // const labelList& globalRegion,
875 // const Map<label>& coupledRegionToMaster,
876 // const scalarField& cellWeights,
877 //
878 // Map<label>& globalToLocalRegion,
879 // pointField& localPoints,
880 // scalarField& localWeights
881 //) const
882 //{
883 // globalToLocalRegion.resize(globalRegion.size());
884 // DynamicList<point> localCc(globalRegion.size()/2);
885 // DynamicList<scalar> localWts(globalRegion.size()/2);
886 //
887 // forAll(globalRegion, celli)
888 // {
889 // Map<label>::const_iterator fndMaster =
890 // coupledRegionToMaster.find(globalRegion[celli]);
891 //
892 // if (fndMaster != coupledRegionToMaster.end())
893 // {
894 // // Multi-processor region.
895 // if (globalCells.toGlobal(celli) == fndMaster())
896 // {
897 // // I am master. Allocate region for me.
898 // globalToLocalRegion.insert
899 // (
900 // globalRegion[celli],
901 // localCc.size()
902 // );
903 // localCc.append(mesh_.cellCentres()[celli]);
904 // localWts.append(cellWeights[celli]);
905 // }
906 // }
907 // else
908 // {
909 // // Single processor region.
910 // if
911 // (
912 // globalToLocalRegion.insert
913 // (
914 // globalRegion[celli],
915 // localCc.size()
916 // )
917 // )
918 // {
919 // localCc.append(mesh_.cellCentres()[celli]);
920 // localWts.append(cellWeights[celli]);
921 // }
922 // }
923 // }
924 //
925 // localPoints.transfer(localCc);
926 // localWeights.transfer(localWts);
927 //
928 // if (localPoints.size() != globalToLocalRegion.size())
929 // {
930 // FatalErrorInFunction
931 // << "localPoints:" << localPoints.size()
932 // << " globalToLocalRegion:" << globalToLocalRegion.size()
933 // << exit(FatalError);
934 // }
935 //}
936 //
937 //
938 //Foam::label Foam::meshRefinement::getShiftedRegion
939 //(
940 // const globalIndex& indexer,
941 // const Map<label>& globalToLocalRegion,
942 // const Map<label>& coupledRegionToShifted,
943 // const label globalRegion
944 //)
945 //{
946 // Map<label>::const_iterator iter =
947 // globalToLocalRegion.find(globalRegion);
948 //
949 // if (iter != globalToLocalRegion.end())
950 // {
951 // // Region is 'owned' locally. Convert local region index into global.
952 // return indexer.toGlobal(iter());
953 // }
954 // else
955 // {
956 // return coupledRegionToShifted[globalRegion];
957 // }
958 //}
959 //
960 //
962 //void Foam::meshRefinement::addUnique(const label elem, labelList& lst)
963 //{
964 // if (findIndex(lst, elem) == -1)
965 // {
966 // label sz = lst.size();
967 // lst.setSize(sz+1);
968 // lst[sz] = elem;
969 // }
970 //}
971 //
972 //
973 //void Foam::meshRefinement::calcRegionRegions
974 //(
975 // const labelList& globalRegion,
976 // const Map<label>& globalToLocalRegion,
977 // const Map<label>& coupledRegionToMaster,
978 // labelListList& regionRegions
979 //) const
980 //{
981 // // Global region indexing since we now know the shifted regions.
982 // globalIndex shiftIndexer(globalToLocalRegion.size());
983 //
984 // // Redo the coupledRegionToMaster to be in shifted region indexing.
985 // Map<label> coupledRegionToShifted(coupledRegionToMaster.size());
986 // forAllConstIter(Map<label>, coupledRegionToMaster, iter)
987 // {
988 // label region = iter.key();
989 //
990 // Map<label>::const_iterator fndRegion = globalToLocalRegion.find
991 // (region);
992 //
993 // if (fndRegion != globalToLocalRegion.end())
994 // {
995 // // A local cell is master of this region. Get its shifted region.
996 // coupledRegionToShifted.insert
997 // (
998 // region,
999 // shiftIndexer.toGlobal(fndRegion())
1000 // );
1001 // }
1002 // Pstream::mapCombineGather(coupledRegionToShifted, minEqOp<label>());
1003 // Pstream::mapCombineScatter(coupledRegionToShifted);
1004 // }
1005 //
1006 //
1007 // // Determine region-region connectivity.
1008 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1009 // // This is for all my regions (so my local ones or the ones I am master
1010 // // of) the neighbouring region indices.
1011 //
1012 //
1013 // // Transfer lists.
1014 // PtrList<HashSet<edge, Hash<edge>>> regionConnectivity
1015 // (Pstream::nProcs());
1016 // forAll(regionConnectivity, proci)
1017 // {
1018 // if (proci != Pstream::myProcNo())
1019 // {
1020 // regionConnectivity.set
1021 // (
1022 // proci,
1023 // new HashSet<edge, Hash<edge>>
1024 // (
1025 // coupledRegionToShifted.size()
1026 // / Pstream::nProcs()
1027 // )
1028 // );
1029 // }
1030 // }
1031 //
1032 //
1033 // // Connectivity. For all my local regions the connected regions.
1034 // regionRegions.setSize(globalToLocalRegion.size());
1035 //
1036 // // Add all local connectivity to regionRegions; add all non-local
1037 // // to the transferlists.
1038 // for (label facei = 0; facei < mesh_.nInternalFaces(); facei++)
1039 // {
1040 // label ownRegion = globalRegion[mesh_.faceOwner()[facei]];
1041 // label neiRegion = globalRegion[mesh_.faceNeighbour()[facei]];
1042 //
1043 // if (ownRegion != neiRegion)
1044 // {
1045 // label shiftOwnRegion = getShiftedRegion
1046 // (
1047 // shiftIndexer,
1048 // globalToLocalRegion,
1049 // coupledRegionToShifted,
1050 // ownRegion
1051 // );
1052 // label shiftNeiRegion = getShiftedRegion
1053 // (
1054 // shiftIndexer,
1055 // globalToLocalRegion,
1056 // coupledRegionToShifted,
1057 // neiRegion
1058 // );
1059 //
1060 //
1061 // // Connection between two regions. Send to owner of region.
1062 // // - is ownRegion 'owned' by me
1063 // // - is neiRegion 'owned' by me
1064 //
1065 // if (shiftIndexer.isLocal(shiftOwnRegion))
1066 // {
1067 // label localI = shiftIndexer.toLocal(shiftOwnRegion);
1068 // addUnique(shiftNeiRegion, regionRegions[localI]);
1069 // }
1070 // else
1071 // {
1072 // label masterProc = shiftIndexer.whichProcID(shiftOwnRegion);
1073 // regionConnectivity[masterProc].insert
1074 // (
1075 // edge(shiftOwnRegion, shiftNeiRegion)
1076 // );
1077 // }
1078 //
1079 // if (shiftIndexer.isLocal(shiftNeiRegion))
1080 // {
1081 // label localI = shiftIndexer.toLocal(shiftNeiRegion);
1082 // addUnique(shiftOwnRegion, regionRegions[localI]);
1083 // }
1084 // else
1085 // {
1086 // label masterProc = shiftIndexer.whichProcID(shiftNeiRegion);
1087 // regionConnectivity[masterProc].insert
1088 // (
1089 // edge(shiftOwnRegion, shiftNeiRegion)
1090 // );
1091 // }
1092 // }
1093 // }
1094 //
1095 //
1096 // // Send
1097 // forAll(regionConnectivity, proci)
1098 // {
1099 // if (proci != Pstream::myProcNo())
1100 // {
1101 // OPstream str(Pstream::commsTypes::blocking, proci);
1102 // str << regionConnectivity[proci];
1103 // }
1104 // }
1105 // // Receive
1106 // forAll(regionConnectivity, proci)
1107 // {
1108 // if (proci != Pstream::myProcNo())
1109 // {
1110 // IPstream str(Pstream::commsTypes::blocking, proci);
1111 // str >> regionConnectivity[proci];
1112 // }
1113 // }
1114 //
1115 // // Add to addressing.
1116 // forAll(regionConnectivity, proci)
1117 // {
1118 // if (proci != Pstream::myProcNo())
1119 // {
1120 // for
1121 // (
1122 // HashSet<edge, Hash<edge>>::const_iterator iter =
1123 // regionConnectivity[proci].begin();
1124 // iter != regionConnectivity[proci].end();
1125 // ++iter
1126 // )
1127 // {
1128 // const edge& e = iter.key();
1129 //
1130 // bool someLocal = false;
1131 // if (shiftIndexer.isLocal(e[0]))
1132 // {
1133 // label localI = shiftIndexer.toLocal(e[0]);
1134 // addUnique(e[1], regionRegions[localI]);
1135 // someLocal = true;
1136 // }
1137 // if (shiftIndexer.isLocal(e[1]))
1138 // {
1139 // label localI = shiftIndexer.toLocal(e[1]);
1140 // addUnique(e[0], regionRegions[localI]);
1141 // someLocal = true;
1142 // }
1143 //
1144 // if (!someLocal)
1145 // {
1146 // FatalErrorInFunction
1147 // << "Received from processor " << proci
1148 // << " connection " << e
1149 // << " where none of the elements is local to me."
1150 // << abort(FatalError);
1151 // }
1152 // }
1153 // }
1154 // }
1155 //}
1156 
1157 
1158 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1159 
1162  fvMesh& mesh,
1163  const dictionary& refineDict,
1164  const scalar mergeDistance,
1165  const bool overwrite,
1166  refinementSurfaces& surfaces,
1167  const refinementFeatures& features,
1168  const refinementRegions& shells
1169 )
1170 :
1171  mesh_(mesh),
1172  mergeDistance_(mergeDistance),
1173  overwrite_(overwrite),
1174  oldInstance_(mesh.pointsInstance()),
1175  surfaces_(surfaces),
1176  features_(features),
1177  shells_(shells),
1178  meshCutter_
1179  (
1180  mesh,
1181  false // do not try to read history.
1182  ),
1183  surfaceIndex_
1184  (
1185  IOobject
1186  (
1187  "surfaceIndex",
1188  mesh_.facesInstance(),
1190  mesh_,
1193  false
1194  ),
1195  labelList(mesh_.nFaces(), -1)
1196  ),
1197  userFaceData_(0)
1198 {
1199  surfaces.setMinLevelFields
1200  (
1201  shells_,
1202  meshCutter_.level0EdgeLength(),
1203  refineDict.lookupOrDefault<Switch>("extendedRefinementSpan", true)
1204  );
1205 
1206  // recalculate intersections for all faces
1207  updateIntersections(identity(mesh_.nFaces()));
1208 }
1209 
1210 
1211 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1212 
1214 {
1215  // Stats on edges to test. Count proc faces only once.
1216  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
1217 
1218  label nHits = 0;
1219 
1220  forAll(surfaceIndex_, facei)
1221  {
1222  if (surfaceIndex_[facei] >= 0 && isMasterFace.get(facei) == 1)
1223  {
1224  nHits++;
1225  }
1226  }
1227  return nHits;
1228 }
1229 
1230 
1232 //Foam::labelList Foam::meshRefinement::decomposeCombineRegions
1233 //(
1234 // const scalarField& cellWeights,
1235 // const boolList& blockedFace,
1236 // const List<labelPair>& explicitConnections,
1237 // decompositionMethod& decomposer
1238 //) const
1239 //{
1240 // // Determine global regions, separated by blockedFaces
1241 // regionSplit globalRegion(mesh_, blockedFace, explicitConnections);
1242 //
1243 // // Now globalRegion has global region per cell. Problem is that
1244 // // the region might span multiple domains so we want to get
1245 // // a "region master" per domain. Note that multi-processor
1246 // // regions can only occur on cells on coupled patches.
1247 // // Note: since the number of regions does not change by this the
1248 // // process can be seen as just a shift of a region onto a single
1249 // // processor.
1250 //
1251 //
1252 // // Global cell numbering engine
1253 // globalIndex globalCells(mesh_.nCells());
1254 //
1255 //
1256 // // Determine per coupled region the master cell (lowest numbered cell
1257 // // on lowest numbered processor)
1258 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1259 // // (does not determine master for non-coupled=fully-local regions)
1260 //
1261 // Map<label> coupledRegionToMaster(mesh_.nFaces() - mesh_.nInternalFaces());
1262 // getCoupledRegionMaster
1263 // (
1264 // globalCells,
1265 // blockedFace,
1266 // globalRegion,
1267 // coupledRegionToMaster
1268 // );
1269 //
1270 // // Determine my regions
1271 // // ~~~~~~~~~~~~~~~~~~~~
1272 // // These are the fully local ones or the coupled ones of which I am master
1273 //
1274 // Map<label> globalToLocalRegion;
1275 // pointField localPoints;
1276 // scalarField localWeights;
1277 // calcLocalRegions
1278 // (
1279 // globalCells,
1280 // globalRegion,
1281 // coupledRegionToMaster,
1282 // cellWeights,
1283 //
1284 // globalToLocalRegion,
1285 // localPoints,
1286 // localWeights
1287 // );
1288 //
1289 //
1290 //
1291 // // Find distribution for regions
1292 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1293 //
1294 // labelList regionDistribution;
1295 //
1296 // if (isA<geomDecomp>(decomposer))
1297 // {
1298 // regionDistribution = decomposer.decompose(localPoints, localWeights);
1299 // }
1300 // else
1301 // {
1302 // labelListList regionRegions;
1303 // calcRegionRegions
1304 // (
1305 // globalRegion,
1306 // globalToLocalRegion,
1307 // coupledRegionToMaster,
1308 //
1309 // regionRegions
1310 // );
1311 //
1312 // regionDistribution = decomposer.decompose
1313 // (
1314 // regionRegions,
1315 // localPoints,
1316 // localWeights
1317 // );
1318 // }
1319 //
1320 //
1321 //
1322 // // Convert region-based decomposition back to cell-based one
1323 // // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1324 //
1325 // // Transfer destination processor back to all. Use global reduce for now.
1326 // Map<label> regionToDist(coupledRegionToMaster.size());
1327 // forAllConstIter(Map<label>, coupledRegionToMaster, iter)
1328 // {
1329 // label region = iter.key();
1330 //
1331 // Map<label>::const_iterator regionFnd = globalToLocalRegion.find
1332 // (region);
1333 //
1334 // if (regionFnd != globalToLocalRegion.end())
1335 // {
1336 // // Master cell is local. Store my distribution.
1337 // regionToDist.insert(iter.key(), regionDistribution[regionFnd()]);
1338 // }
1339 // else
1340 // {
1341 // // Master cell is not on this processor. Make sure it is
1342 // // overridden.
1343 // regionToDist.insert(iter.key(), labelMax);
1344 // }
1345 // }
1346 // Pstream::mapCombineGather(regionToDist, minEqOp<label>());
1347 // Pstream::mapCombineScatter(regionToDist);
1348 //
1349 //
1350 // // Determine destination for all cells
1351 // labelList distribution(mesh_.nCells());
1352 //
1353 // forAll(globalRegion, celli)
1354 // {
1355 // Map<label>::const_iterator fndRegion =
1356 // regionToDist.find(globalRegion[celli]);
1357 //
1358 // if (fndRegion != regionToDist.end())
1359 // {
1360 // distribution[celli] = fndRegion();
1361 // }
1362 // else
1363 // {
1364 // // region is local to the processor.
1365 // label localRegioni = globalToLocalRegion[globalRegion[celli]];
1366 //
1367 // distribution[celli] = regionDistribution[localRegioni];
1368 // }
1369 // }
1370 //
1371 // return distribution;
1372 //}
1373 
1374 
1377  const bool keepZoneFaces,
1378  const bool keepBaffles,
1379  const scalarField& cellWeights,
1380  decompositionMethod& decomposer,
1381  fvMeshDistribute& distributor
1382 )
1383 {
1385 
1386  if (Pstream::parRun())
1387  {
1388  // Wanted distribution
1390 
1391 
1392  // Faces where owner and neighbour are not 'connected' so can
1393  // go to different processors.
1394  boolList blockedFace;
1395  label nUnblocked = 0;
1396 
1397  // Faces that move as block onto single processor
1398  PtrList<labelList> specifiedProcessorFaces;
1399  labelList specifiedProcessor;
1400 
1401  // Pairs of baffles
1402  List<labelPair> couples;
1403 
1404  // Constraints from decomposeParDict
1405  decomposer.setConstraints
1406  (
1407  mesh_,
1408  blockedFace,
1409  specifiedProcessorFaces,
1410  specifiedProcessor,
1411  couples
1412  );
1413 
1414 
1415  if (keepZoneFaces || keepBaffles)
1416  {
1417  if (keepZoneFaces)
1418  {
1419  // Determine decomposition to keep/move surface zones
1420  // on one processor. The reason is that snapping will make these
1421  // into baffles, move and convert them back so if they were
1422  // proc boundaries after baffling&moving the points might be no
1423  // longer synchronised so recoupling will fail. To prevent this
1424  // keep owner&neighbour of such a surface zone on the same
1425  // processor.
1426 
1427  const PtrList<surfaceZonesInfo>& surfZones =
1428  surfaces().surfZones();
1429  const meshFaceZones& fZones = mesh_.faceZones();
1430  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
1431 
1432  // Get faces whose owner and neighbour should stay together,
1433  // i.e. they are not 'blocked'.
1434 
1435  forAll(surfZones, surfi)
1436  {
1437  const word& fzName = surfZones[surfi].faceZoneName();
1438 
1439  if (fzName.size())
1440  {
1441  // Get zone
1442  const faceZone& fZone = fZones[fzName];
1443 
1444  forAll(fZone, i)
1445  {
1446  const label facei = fZone[i];
1447  if (blockedFace[facei])
1448  {
1449  if
1450  (
1451  mesh_.isInternalFace(facei)
1452  || pbm[pbm.whichPatch(facei)].coupled()
1453  )
1454  {
1455  blockedFace[facei] = false;
1456  nUnblocked++;
1457  }
1458  }
1459  }
1460  }
1461  }
1462 
1463 
1464  // If the faceZones are not synchronised the blockedFace
1465  // might not be synchronised. If you are sure the faceZones
1466  // are synchronised remove below check.
1468  (
1469  mesh_,
1470  blockedFace,
1471  andEqOp<bool>() // combine operator
1472  );
1473  }
1474  reduce(nUnblocked, sumOp<label>());
1475 
1476  if (keepZoneFaces)
1477  {
1478  Info<< "Found " << nUnblocked
1479  << " zoned faces to keep together." << endl;
1480  }
1481 
1482 
1483  // Extend un-blockedFaces with any cyclics
1484  {
1485  boolList separatedCoupledFace(mesh_.nFaces(), false);
1486  selectSeparatedCoupledFaces(separatedCoupledFace);
1487 
1488  label nSeparated = 0;
1489  forAll(separatedCoupledFace, facei)
1490  {
1491  if (separatedCoupledFace[facei])
1492  {
1493  if (blockedFace[facei])
1494  {
1495  blockedFace[facei] = false;
1496  nSeparated++;
1497  }
1498  }
1499  }
1500  reduce(nSeparated, sumOp<label>());
1501  Info<< "Found " << nSeparated
1502  << " separated coupled faces to keep together." << endl;
1503 
1504  nUnblocked += nSeparated;
1505  }
1506 
1507 
1508  if (keepBaffles)
1509  {
1510  const label nBnd = mesh_.nFaces() - mesh_.nInternalFaces();
1511 
1512  labelList coupledFace(mesh_.nFaces(), -1);
1513  {
1514  // Get boundary baffles that need to stay together
1515  List<labelPair> allCouples
1516  (
1518  );
1519 
1520  // Merge with any couples from
1521  // decompositionMethod::setConstraints
1522  forAll(couples, i)
1523  {
1524  const labelPair& baffle = couples[i];
1525  coupledFace[baffle.first()] = baffle.second();
1526  coupledFace[baffle.second()] = baffle.first();
1527  }
1528  forAll(allCouples, i)
1529  {
1530  const labelPair& baffle = allCouples[i];
1531  coupledFace[baffle.first()] = baffle.second();
1532  coupledFace[baffle.second()] = baffle.first();
1533  }
1534  }
1535 
1536  couples.setSize(nBnd);
1537  label nCpl = 0;
1538  forAll(coupledFace, facei)
1539  {
1540  if (coupledFace[facei] != -1 && facei < coupledFace[facei])
1541  {
1542  couples[nCpl++] = labelPair(facei, coupledFace[facei]);
1543  }
1544  }
1545  couples.setSize(nCpl);
1546  }
1547  label nCouples = returnReduce(couples.size(), sumOp<label>());
1548 
1549  if (keepBaffles)
1550  {
1551  Info<< "Found " << nCouples << " baffles to keep together."
1552  << endl;
1553  }
1554 
1555  // if (nUnblocked > 0 || nCouples > 0)
1556  //{
1557  // Info<< "Applying special decomposition to keep baffles"
1558  // << " and zoned faces together." << endl;
1559  //
1560  // distribution = decomposeCombineRegions
1561  // (
1562  // cellWeights,
1563  // blockedFace,
1564  // couples,
1565  // decomposer
1566  // );
1567  //
1568  // labelList nProcCells(distributor.countCells(distribution));
1569  // Pstream::listCombineGather(nProcCells, plusEqOp<label>());
1570  // Pstream::listCombineScatter(nProcCells);
1571  //
1572  // Info<< "Calculated decomposition:" << endl;
1573  // forAll(nProcCells, proci)
1574  // {
1575  // Info<< " " << proci << '\t' << nProcCells[proci]
1576  // << endl;
1577  // }
1578  // Info<< endl;
1579  //}
1580  // else
1581  //{
1582  // // Normal decomposition
1583  // distribution = decomposer.decompose
1584  // (
1585  // mesh_,
1586  // mesh_.cellCentres(),
1587  // cellWeights
1588  // );
1589  //}
1590  }
1591  // else
1592  //{
1593  // // Normal decomposition
1594  // distribution = decomposer.decompose
1595  // (
1596  // mesh_,
1597  // cellWeights
1598  // );
1599  //}
1600 
1601 
1602  // Make sure blockedFace not set on couples
1603  forAll(couples, i)
1604  {
1605  const labelPair& baffle = couples[i];
1606  blockedFace[baffle.first()] = false;
1607  blockedFace[baffle.second()] = false;
1608  }
1609 
1610  distribution = decomposer.decompose
1611  (
1612  mesh_,
1613  cellWeights,
1614  blockedFace,
1615  specifiedProcessorFaces,
1616  specifiedProcessor,
1617  couples // explicit connections
1618  );
1619 
1620  if (debug)
1621  {
1622  labelList nProcCells(distributor.countCells(distribution));
1623  Pout<< "Wanted distribution:" << nProcCells << endl;
1624 
1626  Pstream::listCombineScatter(nProcCells);
1627 
1628  Pout<< "Wanted resulting decomposition:" << endl;
1629  forAll(nProcCells, proci)
1630  {
1631  Pout<< " " << proci << '\t' << nProcCells[proci] << endl;
1632  }
1633  Pout<< endl;
1634  }
1635 
1636  mesh_.clearOut();
1637 
1638  // Do actual sending/receiving of mesh
1639  map = distributor.distribute(distribution);
1640 
1641  // Update numbering of meshRefiner
1642  distribute(map);
1643 
1644  // Set correct instance (for if overwrite)
1645  mesh_.setInstance(timeName());
1646  setInstance(mesh_.facesInstance());
1647  }
1648 
1649  return map;
1650 }
1651 
1652 
1654 {
1655  label nBoundaryFaces = 0;
1656 
1657  forAll(surfaceIndex_, facei)
1658  {
1659  if (surfaceIndex_[facei] != -1)
1660  {
1661  nBoundaryFaces++;
1662  }
1663  }
1664 
1665  labelList surfaceFaces(nBoundaryFaces);
1666  nBoundaryFaces = 0;
1667 
1668  forAll(surfaceIndex_, facei)
1669  {
1670  if (surfaceIndex_[facei] != -1)
1671  {
1672  surfaceFaces[nBoundaryFaces++] = facei;
1673  }
1674  }
1675  return surfaceFaces;
1676 }
1677 
1678 
1680 {
1681  const faceList& faces = mesh_.faces();
1682 
1683  // Mark all points on faces that will become baffles
1684  PackedBoolList isBoundaryPoint(mesh_.nPoints());
1685  label nBoundaryPoints = 0;
1686 
1687  forAll(surfaceIndex_, facei)
1688  {
1689  if (surfaceIndex_[facei] != -1)
1690  {
1691  const face& f = faces[facei];
1692 
1693  forAll(f, fp)
1694  {
1695  if (isBoundaryPoint.set(f[fp], 1u))
1696  {
1697  nBoundaryPoints++;
1698  }
1699  }
1700  }
1701  }
1702 
1704  // labelList adaptPatchIDs(meshedPatches());
1705  // forAll(adaptPatchIDs, i)
1706  //{
1707  // label patchi = adaptPatchIDs[i];
1708  //
1709  // if (patchi != -1)
1710  // {
1711  // const polyPatch& pp = mesh_.boundaryMesh()[patchi];
1712  //
1713  // label facei = pp.start();
1714  //
1715  // forAll(pp, i)
1716  // {
1717  // const face& f = faces[facei];
1718  //
1719  // forAll(f, fp)
1720  // {
1721  // if (isBoundaryPoint.set(f[fp], 1u))
1722  // nBoundaryPoints++;
1723  // }
1724  // }
1725  // facei++;
1726  // }
1727  // }
1728  //}
1729 
1730 
1731  // Pack
1732  labelList boundaryPoints(nBoundaryPoints);
1733  nBoundaryPoints = 0;
1734  forAll(isBoundaryPoint, pointi)
1735  {
1736  if (isBoundaryPoint.get(pointi) == 1u)
1737  {
1738  boundaryPoints[nBoundaryPoints++] = pointi;
1739  }
1740  }
1741 
1742  return boundaryPoints;
1743 }
1744 
1745 
1748  const polyMesh& mesh,
1749  const labelList& patchIDs
1750 )
1751 {
1752  const polyBoundaryMesh& patches = mesh.boundaryMesh();
1753 
1754  // Count faces.
1755  label nFaces = 0;
1756 
1757  forAll(patchIDs, i)
1758  {
1759  const polyPatch& pp = patches[patchIDs[i]];
1760 
1761  nFaces += pp.size();
1762  }
1763 
1764  // Collect faces.
1765  labelList addressing(nFaces);
1766  nFaces = 0;
1767 
1768  forAll(patchIDs, i)
1769  {
1770  const polyPatch& pp = patches[patchIDs[i]];
1771 
1772  label meshFacei = pp.start();
1773 
1774  forAll(pp, i)
1775  {
1776  addressing[nFaces++] = meshFacei++;
1777  }
1778  }
1779 
1781  (
1783  (
1784  IndirectList<face>(mesh.faces(), addressing),
1785  mesh.points()
1786  )
1787  );
1788 }
1789 
1790 
1793  const pointMesh& pMesh,
1794  const labelList& adaptPatchIDs
1795 )
1796 {
1797  // Construct displacement field.
1798  const pointBoundaryMesh& pointPatches = pMesh.boundary();
1799 
1800  wordList patchFieldTypes
1801  (
1802  pointPatches.size(),
1803  slipPointPatchVectorField::typeName
1804  );
1805 
1806  forAll(adaptPatchIDs, i)
1807  {
1808  patchFieldTypes[adaptPatchIDs[i]] =
1809  fixedValuePointPatchVectorField::typeName;
1810  }
1811 
1812  forAll(pointPatches, patchi)
1813  {
1814  if (isA<processorPointPatch>(pointPatches[patchi]))
1815  {
1816  patchFieldTypes[patchi] = calculatedPointPatchVectorField::typeName;
1817  }
1818  else if (isA<cyclicPointPatch>(pointPatches[patchi]))
1819  {
1820  patchFieldTypes[patchi] = cyclicSlipPointPatchVectorField::typeName;
1821  }
1822  }
1823 
1824  // Note: time().timeName() instead of meshRefinement::timeName() since
1825  // postprocessable field.
1827  (
1829  (
1830  "pointDisplacement",
1831  pMesh,
1833  patchFieldTypes
1834  )
1835  );
1836  return tfld;
1837 }
1838 
1839 
1841 {
1842  const meshFaceZones& fZones = mesh.faceZones();
1843 
1844  // Check any zones are present anywhere and in same order
1845 
1846  {
1847  List<wordList> zoneNames(Pstream::nProcs());
1848  zoneNames[Pstream::myProcNo()] = fZones.names();
1849  Pstream::gatherList(zoneNames);
1850  Pstream::scatterList(zoneNames);
1851  // All have same data now. Check.
1852  forAll(zoneNames, proci)
1853  {
1854  if (proci != Pstream::myProcNo())
1855  {
1856  if (zoneNames[proci] != zoneNames[Pstream::myProcNo()])
1857  {
1859  << "faceZones are not synchronised on processors." << nl
1860  << "Processor " << proci << " has faceZones "
1861  << zoneNames[proci] << nl
1862  << "Processor " << Pstream::myProcNo()
1863  << " has faceZones "
1864  << zoneNames[Pstream::myProcNo()] << nl
1865  << exit(FatalError);
1866  }
1867  }
1868  }
1869  }
1870 
1871  // Check that coupled faces are present on both sides.
1872 
1873  labelList faceToZone(mesh.nFaces() - mesh.nInternalFaces(), -1);
1874 
1875  forAll(fZones, zonei)
1876  {
1877  const faceZone& fZone = fZones[zonei];
1878 
1879  forAll(fZone, i)
1880  {
1881  label bFacei = fZone[i]-mesh.nInternalFaces();
1882 
1883  if (bFacei >= 0)
1884  {
1885  if (faceToZone[bFacei] == -1)
1886  {
1887  faceToZone[bFacei] = zonei;
1888  }
1889  else if (faceToZone[bFacei] == zonei)
1890  {
1892  << "Face " << fZone[i] << " in zone "
1893  << fZone.name()
1894  << " is twice in zone!"
1895  << abort(FatalError);
1896  }
1897  else
1898  {
1900  << "Face " << fZone[i] << " in zone "
1901  << fZone.name()
1902  << " is also in zone "
1903  << fZones[faceToZone[bFacei]].name()
1904  << abort(FatalError);
1905  }
1906  }
1907  }
1908  }
1909 
1910  labelList neiFaceToZone(faceToZone);
1911  syncTools::swapBoundaryFaceList(mesh, neiFaceToZone);
1912 
1913  forAll(faceToZone, i)
1914  {
1915  if (faceToZone[i] != neiFaceToZone[i])
1916  {
1918  << "Face " << mesh.nInternalFaces() + i
1919  << " is in zone " << faceToZone[i]
1920  << ", its coupled face is in zone " << neiFaceToZone[i]
1921  << abort(FatalError);
1922  }
1923  }
1924 }
1925 
1926 
1929  const polyMesh& mesh,
1930  const PackedBoolList& isMasterEdge,
1931  const labelList& meshPoints,
1932  const edgeList& edges,
1933  scalarField& edgeWeights,
1934  scalarField& invSumWeight
1935 )
1936 {
1937  const pointField& pts = mesh.points();
1938 
1939  // Calculate edgeWeights and inverse sum of edge weights
1940  edgeWeights.setSize(isMasterEdge.size());
1941  invSumWeight.setSize(meshPoints.size());
1942 
1943  forAll(edges, edgei)
1944  {
1945  const edge& e = edges[edgei];
1946  scalar eMag = max
1947  (
1948  small,
1949  mag
1950  (
1951  pts[meshPoints[e[1]]]
1952  - pts[meshPoints[e[0]]]
1953  )
1954  );
1955  edgeWeights[edgei] = 1.0/eMag;
1956  }
1957 
1958  // Sum per point all edge weights
1959  weightedSum
1960  (
1961  mesh,
1962  isMasterEdge,
1963  meshPoints,
1964  edges,
1965  edgeWeights,
1966  scalarField(meshPoints.size(), 1.0), // data
1967  invSumWeight
1968  );
1969 
1970  // Inplace invert
1971  forAll(invSumWeight, pointi)
1972  {
1973  scalar w = invSumWeight[pointi];
1974 
1975  if (w > 0.0)
1976  {
1977  invSumWeight[pointi] = 1.0/w;
1978  }
1979  }
1980 }
1981 
1982 
1985  const word& name,
1986  const dictionary& patchInfo
1987 )
1988 {
1989  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
1990 
1991  const label meshedI = findIndex(meshedPatches_, name);
1992 
1993  if (meshedI != -1)
1994  {
1995  // Already there. Get corresponding polypatch
1996  return pbm.findPatchID(name);
1997  }
1998  else
1999  {
2000  // Add patch
2001 
2002  label patchi = pbm.findPatchID(name);
2003  if (patchi == -1)
2004  {
2005  patchi = pbm.size();
2006  forAll(pbm, i)
2007  {
2008  const polyPatch& pp = pbm[i];
2009 
2010  if (isA<processorPolyPatch>(pp))
2011  {
2012  patchi = i;
2013  break;
2014  }
2015  }
2016 
2017  dictionary patchDict(patchInfo);
2018  patchDict.set("nFaces", 0);
2019  patchDict.set("startFace", 0);
2020  autoPtr<polyPatch> ppPtr
2021  (
2023  (
2024  name,
2025  patchDict,
2026  0,
2027  pbm
2028  )
2029  );
2030  mesh_.addPatch
2031  (
2032  patchi,
2033  ppPtr(),
2034  dictionary(), // optional field values
2036  true // validBoundary
2037  );
2038  }
2039 
2040  // Store
2041  meshedPatches_.append(name);
2042 
2043  return patchi;
2044  }
2045 }
2046 
2047 
2049 {
2050  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2051 
2052  DynamicList<label> patchIDs(meshedPatches_.size());
2053  forAll(meshedPatches_, i)
2054  {
2055  label patchi = patches.findPatchID(meshedPatches_[i]);
2056 
2057  if (patchi == -1)
2058  {
2060  << "Problem : did not find patch " << meshedPatches_[i]
2061  << endl << "Valid patches are " << patches.names()
2062  << abort(FatalError);
2063  }
2064  if (!polyPatch::constraintType(patches[patchi].type()))
2065  {
2066  patchIDs.append(patchi);
2067  }
2068  }
2069 
2070  return move(patchIDs);
2071 }
2072 
2073 
2075 {
2076  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2077 
2078  forAll(patches, patchi)
2079  {
2080  // Check all coupled. Avoid using .coupled() so we also pick up AMI.
2081  if (isA<coupledPolyPatch>(patches[patchi]))
2082  {
2083  const coupledPolyPatch& cpp = refCast<const coupledPolyPatch>
2084  (
2085  patches[patchi]
2086  );
2087 
2088  if (cpp.transform().transformsPosition())
2089  {
2090  forAll(cpp, i)
2091  {
2092  selected[cpp.start() + i] = true;
2093  }
2094  }
2095  }
2096  }
2097 }
2098 
2099 
2102  const polyMesh& mesh,
2103  const labelList& cellRegion,
2104  const vector& perturbVec,
2105  const point& location
2106 )
2107 {
2108  label regioni = -1;
2109  label celli = mesh.findCell(location);
2110  if (celli != -1)
2111  {
2112  regioni = cellRegion[celli];
2113  }
2114  reduce(regioni, maxOp<label>());
2115 
2116  if (regioni == -1)
2117  {
2118  // See if we can perturb a bit
2119  celli = mesh.findCell(location + perturbVec);
2120  if (celli != -1)
2121  {
2122  regioni = cellRegion[celli];
2123  }
2124  reduce(regioni, maxOp<label>());
2125  }
2126 
2127  return regioni;
2128 }
2129 
2130 
2133  const polyMesh& mesh,
2134  labelList& cellRegion,
2135  const vector& perturbVec,
2136  const refinementParameters::cellSelectionPoints& selectionPoints
2137 )
2138 {
2139  // List of all cells selected cells
2140  PackedBoolList selectedCells(mesh.nCells());
2141 
2142  if (selectionPoints.outside().size())
2143  {
2144  // Select all cells before removing those in regions
2145  // containing locations in selectionPoints.outside()
2146  selectedCells = true;
2147 
2148  // For each of the selectionPoints.outside() find the corresponding
2149  // region and deselect the cells
2150  forAll(selectionPoints.outside(), i)
2151  {
2152  // Find the region corresponding to the selectionPoints.outside()[i]
2153  const label regioni = findRegion
2154  (
2155  mesh,
2156  cellRegion,
2157  perturbVec,
2158  selectionPoints.outside()[i]
2159  );
2160 
2161  // Deselect the cells in the region from selectedCells
2162  forAll(cellRegion, celli)
2163  {
2164  if (cellRegion[celli] == regioni)
2165  {
2166  selectedCells[celli] = false;
2167  }
2168  }
2169  }
2170  }
2171 
2172  // For each of the selectionPoints.inside() find the corresponding region
2173  // and select the cells
2174  forAll(selectionPoints.inside(), i)
2175  {
2176  // Find the region corresponding to the selectionPoints.inside()[i]
2177  const label regioni = findRegion
2178  (
2179  mesh,
2180  cellRegion,
2181  perturbVec,
2182  selectionPoints.inside()[i]
2183  );
2184 
2185  // Add all the cells in the region to selectedCells
2186  forAll(cellRegion, celli)
2187  {
2188  if (cellRegion[celli] == regioni)
2189  {
2190  selectedCells[celli] = true;
2191  }
2192  }
2193  }
2194 
2195  // For all unmarked cells set cellRegion to -1
2196  forAll(selectedCells, celli)
2197  {
2198  if (!selectedCells[celli])
2199  {
2200  cellRegion[celli] = -1;
2201  }
2202  }
2203 }
2204 
2205 
2208  const labelList& globalToMasterPatch,
2209  const labelList& globalToSlavePatch,
2210  const refinementParameters::cellSelectionPoints& selectionPoints
2211 )
2212 {
2213  // Force calculation of face decomposition (used in findCell)
2214  (void)mesh_.tetBasePtIs();
2215 
2216  // Determine connected regions. regionSplit is the labelList with the
2217  // region per cell.
2218 
2219  boolList blockedFace(mesh_.nFaces(), false);
2220  selectSeparatedCoupledFaces(blockedFace);
2221 
2222  regionSplit cellRegion(mesh_, blockedFace);
2223 
2224  findRegions
2225  (
2226  mesh_,
2227  cellRegion,
2228  mergeDistance_*vector::one,
2229  selectionPoints
2230  );
2231 
2232  // Subset
2233  // ~~~~~~
2234 
2235  // Get cells to remove
2236  DynamicList<label> cellsToRemove(mesh_.nCells());
2237  forAll(cellRegion, celli)
2238  {
2239  if (cellRegion[celli] == -1)
2240  {
2241  cellsToRemove.append(celli);
2242  }
2243  }
2244  cellsToRemove.shrink();
2245 
2246  const label nCellsToRemove = returnReduce
2247  (
2248  cellsToRemove.size(),
2249  sumOp<label>()
2250  );
2251 
2252  if (nCellsToRemove)
2253  {
2254  label nCellsToKeep = mesh_.nCells() - cellsToRemove.size();
2255  reduce(nCellsToKeep, sumOp<label>());
2256 
2257  Info<< "Keeping all cells in regions containing any point in "
2258  << selectionPoints.inside() << endl
2259  << "Selected for keeping : " << nCellsToKeep << " cells." << endl;
2260 
2261  // Remove cells
2262  removeCells cellRemover(mesh_);
2263 
2264  const labelList exposedFaces
2265  (
2266  cellRemover.getExposedFaces(cellsToRemove)
2267  );
2268 
2269  labelList exposedPatch;
2270 
2271  const label nExposedFaces =
2272  returnReduce(exposedFaces.size(), sumOp<label>());
2273 
2274  if (nExposedFaces)
2275  {
2276  // Patch for exposed faces for lack of anything sensible.
2277  label defaultPatch = 0;
2278  if (globalToMasterPatch.size())
2279  {
2280  defaultPatch = globalToMasterPatch[0];
2281  }
2282 
2284  << "Removing non-reachable cells exposes "
2285  << nExposedFaces << " internal or coupled faces." << endl
2286  << " These get put into patch " << defaultPatch << endl;
2287 
2288  exposedPatch.setSize(exposedFaces.size(), defaultPatch);
2289  }
2290 
2291  return doRemoveCells
2292  (
2293  cellsToRemove,
2294  exposedFaces,
2295  exposedPatch,
2296  cellRemover
2297  );
2298  }
2299  else
2300  {
2301  return autoPtr<polyTopoChangeMap>();
2302  }
2303 }
2304 
2305 
2307 {
2308  // mesh_ already distributed; distribute my member data
2309 
2310  // surfaceQueries_ ok.
2311 
2312  // refinement
2313  meshCutter_.distribute(map);
2314 
2315  // surfaceIndex is face data.
2316  map.distributeFaceData(surfaceIndex_);
2317 
2318  // maintainedFaces are indices of faces.
2319  forAll(userFaceData_, i)
2320  {
2321  map.distributeFaceData(userFaceData_[i].second());
2322  }
2323 
2324  // Redistribute surface and any fields on it.
2325  {
2326  // Get local mesh bounding box. Single box for now.
2328  treeBoundBox& bb = meshBb[0];
2329  bb = treeBoundBox(mesh_.points()).extend(1e-4);
2330 
2331  // Distribute all geometry (so refinementSurfaces and refinementRegions)
2332  searchableSurfaces& geometry =
2333  const_cast<searchableSurfaces&>(surfaces_.geometry());
2334 
2335  forAll(geometry, i)
2336  {
2338  autoPtr<distributionMap> pointMap;
2339  geometry[i].distribute
2340  (
2341  meshBb,
2342  false, // do not keep outside triangles
2343  faceMap,
2344  pointMap
2345  );
2346 
2347  if (faceMap.valid())
2348  {
2349  // (ab)use the instance() to signal current modification time
2350  geometry[i].instance() = geometry[i].time().timeName();
2351  }
2352 
2353  faceMap.clear();
2354  pointMap.clear();
2355  }
2356  }
2357 }
2358 
2359 
2362  const polyTopoChangeMap& map,
2363  const labelList& changedFaces
2364 )
2365 {
2366  Map<label> dummyMap(0);
2367 
2368  topoChange(map, changedFaces, dummyMap, dummyMap, dummyMap);
2369 }
2370 
2371 
2374  const labelList& pointsToStore,
2375  const labelList& facesToStore,
2376  const labelList& cellsToStore
2377 )
2378 {
2379  // For now only meshCutter has storable/retrievable data.
2380  meshCutter_.storeData
2381  (
2382  pointsToStore,
2383  facesToStore,
2384  cellsToStore
2385  );
2386 }
2387 
2388 
2391  const polyTopoChangeMap& map,
2392  const labelList& changedFaces,
2393  const Map<label>& pointsToRestore,
2394  const Map<label>& facesToRestore,
2395  const Map<label>& cellsToRestore
2396 )
2397 {
2398  // For now only meshCutter has storable/retrievable data.
2399 
2400  // Update numbering of cells/vertices.
2401  meshCutter_.topoChange
2402  (
2403  map,
2404  pointsToRestore,
2405  facesToRestore,
2406  cellsToRestore
2407  );
2408 
2409  // Update surfaceIndex
2410  updateList(map.faceMap(), label(-1), surfaceIndex_);
2411 
2412  // Update cached intersection information
2413  updateIntersections(changedFaces);
2414 
2415  // Update maintained faces
2416  forAll(userFaceData_, i)
2417  {
2418  labelList& data = userFaceData_[i].second();
2419 
2420  if (userFaceData_[i].first() == KEEPALL)
2421  {
2422  // extend list with face-from-face data
2423  updateList(map.faceMap(), label(-1), data);
2424  }
2425  else if (userFaceData_[i].first() == MASTERONLY)
2426  {
2427  // keep master only
2428  labelList newFaceData(map.faceMap().size(), -1);
2429 
2430  forAll(newFaceData, facei)
2431  {
2432  label oldFacei = map.faceMap()[facei];
2433 
2434  if (oldFacei >= 0 && map.reverseFaceMap()[oldFacei] == facei)
2435  {
2436  newFaceData[facei] = data[oldFacei];
2437  }
2438  }
2439  data.transfer(newFaceData);
2440  }
2441  else
2442  {
2443  // remove any face that has been refined i.e. referenced more than
2444  // once.
2445 
2446  // 1. Determine all old faces that get referenced more than once.
2447  // These get marked with -1 in reverseFaceMap
2448  labelList reverseFaceMap(map.reverseFaceMap());
2449 
2450  forAll(map.faceMap(), facei)
2451  {
2452  const label oldFacei = map.faceMap()[facei];
2453 
2454  if (oldFacei >= 0)
2455  {
2456  if (reverseFaceMap[oldFacei] != facei)
2457  {
2458  // facei is slave face. Mark old face.
2459  reverseFaceMap[oldFacei] = -1;
2460  }
2461  }
2462  }
2463 
2464  // 2. Map only faces with intact reverseFaceMap
2465  labelList newFaceData(map.faceMap().size(), -1);
2466  forAll(newFaceData, facei)
2467  {
2468  const label oldFacei = map.faceMap()[facei];
2469 
2470  if (oldFacei >= 0)
2471  {
2472  if (reverseFaceMap[oldFacei] == facei)
2473  {
2474  newFaceData[facei] = data[oldFacei];
2475  }
2476  }
2477  }
2478  data.transfer(newFaceData);
2479  }
2480  }
2481 }
2482 
2483 
2485 {
2486  bool writeOk = mesh_.write();
2487 
2488  // Make sure that any distributed surfaces (so ones which probably have
2489  // been changed) get written as well.
2490  // Note: should ideally have some 'modified' flag to say whether it
2491  // has been changed or not.
2492  searchableSurfaces& geometry =
2493  const_cast<searchableSurfaces&>(surfaces_.geometry());
2494 
2495  forAll(geometry, i)
2496  {
2497  searchableSurface& s = geometry[i];
2498 
2499  // Check if instance() of surface is not constant or system.
2500  // Is good hint that surface is distributed.
2501  if
2502  (
2503  s.instance() != s.time().system()
2504  && s.instance() != s.time().caseSystem()
2505  && s.instance() != s.time().constant()
2506  && s.instance() != s.time().caseConstant()
2507  )
2508  {
2509  // Make sure it gets written to current time, not constant.
2510  s.instance() = s.time().timeName();
2511  writeOk = writeOk && s.write();
2512  }
2513  }
2514 
2515  return writeOk;
2516 }
2517 
2518 
2521  const polyMesh& mesh,
2522  const labelList& meshPoints
2523 )
2524 {
2525  const globalIndex globalPoints(meshPoints.size());
2526 
2527  labelList myPoints(meshPoints.size());
2528  forAll(meshPoints, pointi)
2529  {
2530  myPoints[pointi] = globalPoints.toGlobal(pointi);
2531  }
2532 
2534  (
2535  mesh,
2536  meshPoints,
2537  myPoints,
2538  minEqOp<label>(),
2539  labelMax
2540  );
2541 
2542 
2543  PackedBoolList isPatchMasterPoint(meshPoints.size());
2544  forAll(meshPoints, pointi)
2545  {
2546  if (myPoints[pointi] == globalPoints.toGlobal(pointi))
2547  {
2548  isPatchMasterPoint[pointi] = true;
2549  }
2550  }
2551 
2552  return isPatchMasterPoint;
2553 }
2554 
2555 
2558  const polyMesh& mesh,
2559  const labelList& meshEdges
2560 )
2561 {
2562  const globalIndex globalEdges(meshEdges.size());
2563 
2564  labelList myEdges(meshEdges.size());
2565  forAll(meshEdges, edgei)
2566  {
2567  myEdges[edgei] = globalEdges.toGlobal(edgei);
2568  }
2569 
2571  (
2572  mesh,
2573  meshEdges,
2574  myEdges,
2575  minEqOp<label>(),
2576  labelMax
2577  );
2578 
2579 
2580  PackedBoolList isMasterEdge(meshEdges.size());
2581  forAll(meshEdges, edgei)
2582  {
2583  if (myEdges[edgei] == globalEdges.toGlobal(edgei))
2584  {
2585  isMasterEdge[edgei] = true;
2586  }
2587  }
2588 
2589  return isMasterEdge;
2590 }
2591 
2592 
2593 void Foam::meshRefinement::printMeshInfo(const bool debug, const string& msg)
2594 const
2595 {
2596  const globalMeshData& pData = mesh_.globalData();
2597 
2598  if (debug)
2599  {
2600  Pout<< msg.c_str()
2601  << " : cells(local):" << mesh_.nCells()
2602  << " faces(local):" << mesh_.nFaces()
2603  << " points(local):" << mesh_.nPoints()
2604  << endl;
2605  }
2606 
2607  {
2608  PackedBoolList isMasterFace(syncTools::getMasterFaces(mesh_));
2609  label nMasterFaces = 0;
2610  forAll(isMasterFace, i)
2611  {
2612  if (isMasterFace[i])
2613  {
2614  nMasterFaces++;
2615  }
2616  }
2617 
2618  PackedBoolList isMeshMasterPoint(syncTools::getMasterPoints(mesh_));
2619  label nMasterPoints = 0;
2620  forAll(isMeshMasterPoint, i)
2621  {
2622  if (isMeshMasterPoint[i])
2623  {
2624  nMasterPoints++;
2625  }
2626  }
2627 
2628  Info<< msg.c_str()
2629  << " : cells:" << pData.nTotalCells()
2630  << " faces:" << returnReduce(nMasterFaces, sumOp<label>())
2631  << " points:" << returnReduce(nMasterPoints, sumOp<label>())
2632  << endl;
2633  }
2634 
2635 
2636  // if (debug)
2637  {
2638  const labelList& cellLevel = meshCutter_.cellLevel();
2639 
2640  labelList nCells(gMax(cellLevel) + 1, 0);
2641 
2642  forAll(cellLevel, celli)
2643  {
2644  nCells[cellLevel[celli]]++;
2645  }
2646 
2649 
2650  Info<< "Cells per refinement level:" << endl;
2651  forAll(nCells, leveli)
2652  {
2653  Info<< " " << leveli << '\t' << nCells[leveli]
2654  << endl;
2655  }
2656  }
2657 }
2658 
2659 
2661 {
2662  if (overwrite_ && mesh_.time().timeIndex() == 0)
2663  {
2664  return oldInstance_;
2665  }
2666  else
2667  {
2668  return mesh_.time().timeName();
2669  }
2670 }
2671 
2672 
2674 {
2675  // Note: use time().timeName(), not meshRefinement::timeName()
2676  // so as to dump the fields to 0, not to constant.
2677  {
2678  volScalarField volRefLevel
2679  (
2680  IOobject
2681  (
2682  "cellLevel",
2683  mesh_.time().timeName(),
2684  mesh_,
2687  false
2688  ),
2689  mesh_,
2691  );
2692 
2693  const labelList& cellLevel = meshCutter_.cellLevel();
2694 
2695  forAll(volRefLevel, celli)
2696  {
2697  volRefLevel[celli] = cellLevel[celli];
2698  }
2699 
2700  volRefLevel.write();
2701  }
2702 
2703  // Dump pointLevel
2704  {
2705  const pointMesh& pMesh = pointMesh::New(mesh_);
2706 
2707  pointScalarField pointRefLevel
2708  (
2709  IOobject
2710  (
2711  "pointLevel",
2712  mesh_.time().timeName(),
2713  mesh_,
2716  false
2717  ),
2718  pMesh,
2720  );
2721 
2722  const labelList& pointLevel = meshCutter_.pointLevel();
2723 
2724  forAll(pointRefLevel, pointi)
2725  {
2726  pointRefLevel[pointi] = pointLevel[pointi];
2727  }
2728 
2729  pointRefLevel.write();
2730  }
2731 }
2732 
2733 
2735 {
2736  {
2737  const pointField& cellCentres = mesh_.cellCentres();
2738 
2739  OFstream str(prefix + "_edges.obj");
2740  label vertI = 0;
2741  Pout<< "meshRefinement::dumpIntersections :"
2742  << " Writing cellcentre-cellcentre intersections to file "
2743  << str.name() << endl;
2744 
2745 
2746  // Redo all intersections
2747  // ~~~~~~~~~~~~~~~~~~~~~~
2748 
2749  // Get boundary face centre and level. Coupled aware.
2750  labelList neiLevel(mesh_.nFaces() - mesh_.nInternalFaces());
2751  pointField neiCc(mesh_.nFaces() - mesh_.nInternalFaces());
2752  calcNeighbourData(neiLevel, neiCc);
2753 
2754  labelList intersectionFaces(intersectedFaces());
2755 
2756  // Collect segments we want to test for
2757  pointField start(intersectionFaces.size());
2758  pointField end(intersectionFaces.size());
2759 
2760  forAll(intersectionFaces, i)
2761  {
2762  const label facei = intersectionFaces[i];
2763  start[i] = cellCentres[mesh_.faceOwner()[facei]];
2764 
2765  if (mesh_.isInternalFace(facei))
2766  {
2767  end[i] = cellCentres[mesh_.faceNeighbour()[facei]];
2768  }
2769  else
2770  {
2771  end[i] = neiCc[facei-mesh_.nInternalFaces()];
2772  }
2773  }
2774 
2775  // Extend segments a bit
2776  {
2777  const vectorField smallVec(rootSmall*(end-start));
2778  start -= smallVec;
2779  end += smallVec;
2780  }
2781 
2782 
2783  // Do tests in one go
2784  labelList surfaceHit;
2785  List<pointIndexHit> surfaceHitInfo;
2786  surfaces_.findAnyIntersection
2787  (
2788  start,
2789  end,
2790  surfaceHit,
2791  surfaceHitInfo
2792  );
2793 
2794  forAll(intersectionFaces, i)
2795  {
2796  if (surfaceHit[i] != -1)
2797  {
2798  meshTools::writeOBJ(str, start[i]);
2799  vertI++;
2800  meshTools::writeOBJ(str, surfaceHitInfo[i].hitPoint());
2801  vertI++;
2802  meshTools::writeOBJ(str, end[i]);
2803  vertI++;
2804  str << "l " << vertI-2 << ' ' << vertI-1 << nl
2805  << "l " << vertI-1 << ' ' << vertI << nl;
2806  }
2807  }
2808  }
2809 
2810  Pout<< endl;
2811 }
2812 
2813 
2816  const debugType debugFlags,
2817  const writeType writeFlags,
2818  const fileName& prefix
2819 ) const
2820 {
2821  if (writeFlags & WRITEMESH)
2822  {
2823  write();
2824  }
2825 
2826  if (writeFlags && !(writeFlags & NOWRITEREFINEMENT))
2827  {
2828  meshCutter_.write();
2829  surfaceIndex_.write();
2830  }
2831 
2832  if (writeFlags & WRITELEVELS)
2833  {
2834  dumpRefinementLevel();
2835  }
2836 
2837  if (debugFlags & OBJINTERSECTIONS && prefix.size())
2838  {
2839  dumpIntersections(prefix);
2840  }
2841 }
2842 
2843 
2845 {
2846  return writeLevel_;
2847 }
2848 
2849 
2851 {
2852  writeLevel_ = flags;
2853 }
2854 
2855 
2857 {
2858  return outputLevel_;
2859 }
2860 
2861 
2863 {
2864  outputLevel_ = flags;
2865 }
2866 
2867 
2868 // ************************************************************************* //
const fvPatchList & patches
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:453
ListType renumber(const labelUList &oldToNew, const ListType &)
Renumber the values (not the indices) of a list.
virtual labelList decompose(const pointField &points, const scalarField &pointWeights)
Return for every coordinate the wanted processor number.
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:116
labelList first(const UList< labelPair > &p)
Definition: patchToPatch.C:38
static void scatterList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Scatter data. Reverse of gatherList.
void printMeshInfo(const bool, const string &) const
Print some mesh stats.
static void listCombineScatter(const List< commsStruct > &comms, List< T > &Value, const int tag, const label comm)
Scatter data. Reverse of combineGather.
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
autoPtr< polyTopoChangeMap > changeMesh(polyMesh &mesh, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
layerAndWeight max(const layerAndWeight &a, const layerAndWeight &b)
FvWallInfoData< WallInfo, label > label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
const word & name() const
Return name.
Definition: IOobject.H:315
IOoutputType
Enumeration for what to output.
A class for handling file names.
Definition: fileName.H:79
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::pointBoundaryMesh.
unsigned int get(const label) const
Get value at index I.
Definition: PackedListI.H:954
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:75
void setRefinement(const labelList &cellsToRemove, const labelList &facesToExpose, const labelList &patchIDs, polyTopoChange &) const
Play commands into polyTopoChange to remove cells.
Definition: removeCells.C:179
const labelList & faceMap() const
Old face map.
label countHits() const
Count number of intersections (local)
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:156
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:306
label nInternalFaces() const
static void swapBoundaryFacePositions(const polyMesh &mesh, UList< point > &l)
Swap coupled positions.
Definition: syncTools.H:452
IOdebugType
Enumeration for what to debug.
label nFaces() const
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
Output to file stream.
Definition: OFstream.H:82
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:328
void topoChange(const polyTopoChangeMap &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
static const NamedEnum< IOoutputType, 1 > IOoutputTypeNames
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:164
const boolList & flipMap() const
Return face flip map.
Definition: faceZone.H:249
label fcIndex(const label i) const
Return the forward circular index, i.e. the next index.
Definition: UListI.H:58
static int myProcNo(const label communicator=0)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:429
Given list of cells to remove insert all the topology changes.
Definition: removeCells.H:59
label nCells() const
static tmp< GeometricField< vector, pointPatchField, pointMesh > > New(const word &name, const Internal &, const PtrList< pointPatchField< vector >> &)
Return a temporary field constructed from name,.
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
autoPtr< polyTopoChangeMap > splitFaces(const labelList &splitFaces, const labelPairList &splits)
Split faces into two.
label nTotalCells() const
Return total number of cells in decomposed mesh.
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none/any.
Definition: Switch.H:60
labelList intersectedFaces() const
Get faces with intersection.
static writeType writeLevel()
Get/set write level.
Abstract base class with a fat-interface to all derived classes covering all possible ways in which t...
Definition: fvPatchField.H:66
label findPatchID(const word &patchName) const
Find patch index given a name.
labelList identity(const label len)
Create identity map (map[i] == i) of given length.
Definition: ListOps.C:104
Encapsulates queries for volume refinement (&#39;refine all cells within shell&#39;).
The coupledPolyPatch is an abstract base class for patches that couple regions of the computational d...
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of point.
Definition: meshTools.C:203
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:307
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
const dimensionSet dimless
virtual const transformer & transform() const =0
Return transformation between the coupled patches.
Pre-declare related SubField type.
Definition: Field.H:60
PrimitivePatch< IndirectList< face >, const pointField & > indirectPrimitivePatch
Foam::indirectPrimitivePatch.
labelList intersectedPoints() const
Get points on surfaces with intersection and boundary faces.
const fileName & name() const
Return the name of the stream.
Definition: OFstream.H:120
Initialise the NamedEnum HashTable from the static list of names.
Definition: NamedEnum.H:51
static void listCombineGather(const List< commsStruct > &comms, List< T > &Value, const CombineOp &cop, const int tag, const label comm)
static PackedBoolList getMasterFaces(const polyMesh &)
Get per face whether it is uncoupled or a master of a.
Definition: syncTools.C:153
scalar f1
Definition: createFields.H:15
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
const dimensionSet dimLength
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
IOwriteType
Enumeration for what to write.
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1211
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:48
wordList names() const
Return a list of zone names.
Definition: MeshZones.C:256
fileName caseSystem() const
Return system name for the case.
Definition: TimePaths.C:110
meshRefinement(fvMesh &mesh, const dictionary &refineDict, const scalar mergeDistance, const bool overwrite, refinementSurfaces &, const refinementFeatures &, const refinementRegions &)
Construct from components.
void topoChange(const polyTopoChangeMap &)
Force recalculation of locally stored data on topological change.
Definition: removeCells.H:115
static bool constraintType(const word &pt)
Return true if the given type is a constraint type.
Definition: polyPatch.C:265
Encapsulates queries for features.
void clear()
Delete object (if the pointer is valid) and set pointer to.
Definition: autoPtrI.H:126
const labelList & reverseFaceMap() const
Reverse face map.
const List< point > & inside() const
Return the points inside the surface regions to selected cells.
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:63
A List obtained as a section of another List.
Definition: SubList.H:53
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
gmvFile<< "tracers "<< particles.size()<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().x()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().position().y()<< " ";}gmvFile<< nl;forAllConstIter(Cloud< passiveParticle >, particles, iter){ gmvFile<< iter().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))
autoPtr< polyDistributionMap > distribute(const labelList &dist)
Send cells to neighbours according to distribution.
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:882
An ordered pair of two objects of type <T> with first() and second() elements.
Definition: contiguous.H:49
virtual bool coupled() const
Return true if this patch is geometrically coupled (i.e. faces and.
Definition: polyPatch.H:316
Definition: ops.H:70
label addFace(const face &f, const label own, const label nei, const label masterPointID, const label masterEdgeID, const label masterFaceID, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip)
Add face to cells. Return new face label.
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:56
static void calculateEdgeWeights(const polyMesh &mesh, const PackedBoolList &isMasterEdge, const labelList &meshPoints, const edgeList &edges, scalarField &edgeWeights, scalarField &invSumWeight)
Helper: calculate edge weights (1/length)
const labelUList & faceCells() const
Return face-cell addressing.
Definition: polyPatch.C:340
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
static void syncEdgeList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh edges.
static word timeName(const scalar, const int precision=curPrecision_)
Return time name of given scalar time.
Definition: Time.C:666
A class for handling words, derived from string.
Definition: word.H:59
static PackedBoolList getMasterEdges(const polyMesh &mesh, const labelList &meshEdges)
Determine master edge for subset of edges. If coupled.
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
wordList names() const
Return a list of patch names.
void append(const T &)
Append an element at the end of the list.
Definition: ListI.H:178
void setConstraints(const polyMesh &mesh, boolList &blockedFace, PtrList< labelList > &specifiedProcessorFaces, labelList &specifiedProcessor, List< labelPair > &explicitConnections)
Helper: extract constraints:
const word & constant() const
Return constant name.
Definition: TimePaths.H:123
static const NamedEnum< IOdebugType, 5 > IOdebugTypeNames
static void checkCoupledFaceZones(const polyMesh &)
Helper function: check that face zones are synced.
Container for searchableSurfaces.
void write(std::ostream &os, const bool binary, List< floatScalar > &fField)
Write floats ascii or binary.
Pair< label > labelPair
Label pair.
Definition: labelPair.H:48
static const label labelMax
Definition: label.H:62
word timeName
Definition: getTimeIndex.H:3
List< label > labelList
A List of labels.
Definition: labelList.H:56
static const zero Zero
Definition: zero.H:97
Abstract base class for decomposition.
const word & name() const
Return name.
Definition: zone.H:147
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1224
Accumulating histogram of values. Specified bin resolution automatic generation of bins...
Definition: distribution.H:58
const PtrList< surfaceZonesInfo > & surfZones() const
bool valid() const
Return true if the autoPtr valid (ie, the pointer is set)
Definition: autoPtrI.H:83
errorManip< error > abort(error &err)
Definition: errorManip.H:131
A 1D vector of objects of type <T>, where the size of the vector is known and can be used for subscri...
Definition: HashTable.H:60
word timeName() const
Replacement for Time::timeName() : return oldInstance (if.
const word & system() const
Return system name.
Definition: TimePaths.H:113
Foam::polyBoundaryMesh.
List< treeBoundBox > meshBb(1, treeBoundBox(boundBox(coarseMesh.points(), false)).extend(1e-3))
const vectorField::subField faceAreas() const
Return face areas.
Definition: polyPatch.C:309
fileName caseConstant() const
Return constant name for the case.
Definition: TimePaths.C:123
static const char nl
Definition: Ostream.H:260
void checkData()
Debugging: check that all faces still obey start()>end()
Type gMax(const FieldField< Field, Type > &f)
defineTypeNameAndDebug(combustionModel, 0)
Database for solution and other reduced data.
Definition: data.H:51
label addMeshedPatch(const word &name, const dictionary &)
Add patch originating from meshing. Update meshedPatches_.
static PackedBoolList getMasterPoints(const polyMesh &)
Get per point whether it is uncoupled or a master of a.
Definition: syncTools.C:65
labelList meshedPatches() const
Get patchIDs for patches added in addMeshedPatch.
autoPtr< polyDistributionMap > balance(const bool keepZoneFaces, const bool keepBaffles, const scalarField &cellWeights, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Redecompose according to cell count.
void setMinLevelFields(const refinementRegions &shells, const scalar level0EdgeLength, const bool extendedRefinementSpan)
Calculate the refinement level for every element.
labelList f(nPoints)
label findIndex(const ListType &, typename ListType::const_reference, const label start=0)
Find first occurrence of given element and return index,.
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
static outputType outputLevel()
Get/set output level.
bool transformsPosition() const
Return true if the transformer transforms a point.
Definition: transformerI.H:146
labelList second(const UList< labelPair > &p)
Definition: patchToPatch.C:48
const Type & second() const
Return second.
Definition: Pair.H:110
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
void distributeFaceData(List< T > &lst) const
Distribute list of face data.
void setInstance(const fileName &)
Set instance of all local IOobjects.
static void syncFaceList(const polyMesh &mesh, UList< T > &l, const CombineOp &cop)
Synchronise values on all mesh faces.
Definition: syncTools.H:387
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:100
void setSize(const label)
Reset size of List.
Definition: List.C:281
void modifyFace(const face &f, const label facei, const label own, const label nei, const bool flipFaceFlux, const label patchID, const label zoneID, const bool zoneFlip)
Modify vertices or cell of face.
void distribute(const polyDistributionMap &)
Update local numbering for mesh redistribution.
A bit-packed bool list.
static bool & parRun()
Is this a parallel run?
Definition: UPstream.H:399
static label nProcs(const label communicator=0)
Number of processes in parallel run.
Definition: UPstream.H:411
label patchi
autoPtr< polyTopoChangeMap > splitMeshRegions(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const refinementParameters::cellSelectionPoints &selectionPoints)
Split mesh according to selectionPoints.
void storeData(const labelList &pointsToStore, const labelList &facesToStore, const labelList &cellsToStore)
Signal points/face/cells for which to store data.
vector point
Point is a vector.
Definition: point.H:41
T lookupOrDefault(const word &, const T &, bool recursive=false, bool patternMatch=true) const
Find and return a T,.
#define WarningInFunction
Report a warning using Foam::Warning.
static void testSyncPointList(const string &msg, const polyMesh &mesh, const List< scalar > &fld)
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
const Time & time() const
Return time.
Definition: IOobject.C:318
A templated 1D list of pointers to objects of type <T>, where the size of the array is known and used...
Definition: List.H:70
prefixOSstream Pout(cout, "Pout")
Definition: IOstreams.H:53
static void syncBoundaryFacePositions(const polyMesh &mesh, UList< point > &l, const CombineOp &cop)
Synchronise locations on boundary faces only.
Definition: syncTools.H:369
const meshFaceZones & faceZones() const
Return face zones.
Definition: polyMesh.H:495
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:95
Direct mesh changes based on v1.3 polyTopoChange syntax.
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:306
fileType type(const fileName &, const bool checkVariants=true, const bool followLink=true)
Return the file type: directory or file.
Definition: POSIX.C:488
static void syncPointList(const polyMesh &, List< T > &, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronise values on all mesh points.
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition: polyMesh.C:1647
void set(entry *)
Assign a new entry, overwrite any existing entry.
Definition: dictionary.C:1291
static labelList findDuplicateFaces(const primitiveMesh &, const labelList &)
Helper routine to find baffles (two boundary faces using the.
void selectSeparatedCoupledFaces(boolList &) const
Select coupled faces that are not collocated.
Standard boundBox + extra functionality for use in octree.
Definition: treeBoundBox.H:87
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
static void findRegions(const polyMesh &, labelList &cellRegion, const vector &perturbVec, const refinementParameters::cellSelectionPoints &selectionPoints)
Find regions points are in and update cellRegion.
label nPoints() const
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return a pointer to a new patch created on freestore from.
Definition: polyPatchNew.C:32
T returnReduce(const T &Value, const BinaryOp &bop, const int tag=Pstream::msgType(), const label comm=UPstream::worldComm)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
const doubleScalar e
Elementary charge.
Definition: doubleScalar.H:105
label size() const
Number of entries.
Definition: PackedListI.H:711
fileName & instance() const
Return the instance directory, constant, system, <time> etc.
Definition: IOobject.C:355
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:76
labelList getExposedFaces(const labelList &cellsToRemove) const
Get labels of exposed faces.
Definition: removeCells.C:73
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &l)
Swap coupled boundary face values.
Definition: syncTools.H:436
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:65
bool write() const
Write mesh and all data.
virtual bool write(const bool write=true) const
Write using setting from DB.
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
A class for managing temporary objects.
Definition: PtrList.H:53
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
static PackedBoolList getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
void dumpIntersections(const fileName &prefix) const
Debug: Write intersection information to OBJ format.
const pointBoundaryMesh & boundary() const
Return reference to boundary mesh.
Definition: pointMesh.H:97
static labelList countCells(const labelList &)
Helper function: count cells per processor in wanted distribution.
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:98
static label findRegion(const polyMesh &, const labelList &cellRegion, const vector &perturbVec, const point &location)
Find region point is in. Uses optional perturbation to re-test.
static void gatherList(const List< commsStruct > &comms, List< T > &Values, const int tag, const label comm)
Gather data but keep individual values separate.
const Type & first() const
Return first.
Definition: Pair.H:98
label whichPatch(const label faceIndex) const
Return patch index for a given face label.
void dumpRefinementLevel() const
Write refinement level as volScalarFields for postprocessing.
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
const List< point > & outside() const
Return the points outside the surface region to deselect cells.
Namespace for OpenFOAM.
static const NamedEnum< IOwriteType, 5 > IOwriteTypeNames
Class to hold the points to select cells inside and outside.
const vectorField::subField faceCentres() const
Return face centres.
Definition: polyPatch.C:303