meshRefinement.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) 2011-2017 OpenFOAM Foundation
9  Copyright (C) 2015-2024 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "meshRefinement.H"
30 #include "volMesh.H"
31 #include "volFields.H"
32 #include "surfaceMesh.H"
33 #include "syncTools.H"
34 #include "Time.H"
35 #include "refinementSurfaces.H"
36 #include "refinementFeatures.H"
37 #include "decompositionMethod.H"
38 #include "regionSplit.H"
39 #include "fvMeshDistribute.H"
40 #include "indirectPrimitivePatch.H"
41 #include "polyTopoChange.H"
42 #include "removeCells.H"
43 #include "mapDistributePolyMesh.H"
44 #include "localPointRegion.H"
45 #include "pointMesh.H"
46 #include "pointFields.H"
47 #include "slipPointPatchFields.H"
51 #include "processorPointPatch.H"
52 #include "globalIndex.H"
53 #include "meshTools.H"
54 #include "OFstream.H"
55 #include "Random.H"
56 #include "searchableSurfaces.H"
57 #include "treeBoundBox.H"
59 #include "fvMeshTools.H"
60 #include "motionSmoother.H"
61 #include "faceSet.H"
62 #include "topoDistanceData.H"
63 #include "FaceCellWave.H"
64 #include "PackedBoolList.H"
65 
66 // Leak path
67 #include "shortestPathSet.H"
68 #include "meshSearch.H"
69 
70 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
71 
72 namespace Foam
73 {
74  defineTypeNameAndDebug(meshRefinement, 0);
75 }
76 
77 
78 const Foam::Enum
79 <
81 >
83 ({
84  { MeshType::CASTELLATED, "castellated" },
85  { MeshType::CASTELLATEDBUFFERLAYER, "castellatedBufferLayer" },
86  { MeshType::CASTELLATEDBUFFERLAYER2, "castellatedBufferLayer2" }
87 });
88 
89 
90 const Foam::Enum
91 <
93 >
95 ({
96  { debugType::MESH, "mesh" },
97  { debugType::OBJINTERSECTIONS, "intersections" },
98  { debugType::FEATURESEEDS, "featureSeeds" },
99  { debugType::ATTRACTION, "attraction" },
100  { debugType::LAYERINFO, "layerInfo" },
101 });
102 
103 
104 //const Foam::Enum
105 //<
106 // Foam::meshRefinement::outputType
107 //>
108 //Foam::meshRefinement::outputTypeNames
109 //({
110 // { outputType::OUTPUTLAYERINFO, "layerInfo" }
111 //});
112 
113 
114 const Foam::Enum
115 <
117 >
119 ({
120  { writeType::WRITEMESH, "mesh" },
121  { writeType::NOWRITEREFINEMENT, "noRefinement" },
122  { writeType::WRITELEVELS, "scalarLevels" },
123  { writeType::WRITELAYERSETS, "layerSets" },
124  { writeType::WRITELAYERFIELDS, "layerFields" },
125 });
126 
127 
128 Foam::meshRefinement::writeType Foam::meshRefinement::writeLevel_;
129 
130 //Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel_;
131 
132 // Inside/outside test for polyMesh:.findCell()
133 // 2.4.x : default = polyMesh::FACE_DIAG_TRIS
134 // 1712 : default = polyMesh::CELL_TETS
135 //
136 // - CELL_TETS is better with concave cells, but much slower.
137 // - use faster method (FACE_DIAG_TRIS) here
138 
141 
142 
143 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
144 
145 Foam::label Foam::meshRefinement::globalFaceCount(const labelList& elems) const
146 {
147  //- Check for duplicates
148  const bitSet isElem(mesh_.nFaces(), elems);
149  if (label(isElem.count()) != elems.size())
150  {
151  FatalErrorInFunction << "Problem Duplicates:"
152  << " isElem:" << isElem.count()
153  << " elems:" << elems.size()
154  << exit(FatalError);
155  }
156 
157  //- Check for same entries on coupled faces
158  {
159  bitSet isElem2(isElem);
160  syncTools::swapFaceList(mesh_, isElem2);
161 
162  for
163  (
164  label facei = mesh_.nInternalFaces();
165  facei < mesh_.nFaces();
166  facei++
167  )
168  {
169  if (isElem2[facei] != isElem[facei])
170  {
172  << "at face:" << facei
173  << " at:" << mesh_.faceCentres()[facei]
174  << " patch:" << mesh_.boundaryMesh().whichPatch(facei)
175  << " isElem:" << isElem[facei]
176  << " isElem2:" << isElem2[facei]
177  << exit(FatalError);
178  }
179  }
180  }
181 
182  //- Count number of master elements
183  const bitSet isMaster(syncTools::getMasterFaces(mesh_));
184  label count = 0;
185  for (const label i : isElem)
186  {
187  if (isMaster[i])
188  {
189  count++;
190  }
191  }
192  return returnReduce(count, sumOp<label>());
193 }
194 
195 
196 void Foam::meshRefinement::calcNeighbourData
197 (
198  labelList& neiLevel,
199  pointField& neiCc
200 ) const
201 {
202  const labelList& cellLevel = meshCutter_.cellLevel();
203  const pointField& cellCentres = mesh_.cellCentres();
204 
205  const label nBoundaryFaces = mesh_.nBoundaryFaces();
206 
207  if (neiLevel.size() != nBoundaryFaces || neiCc.size() != nBoundaryFaces)
208  {
210  << nBoundaryFaces << " neiLevel:" << neiLevel.size()
211  << abort(FatalError);
212  }
213 
214  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
215 
216  labelHashSet addedPatchIDSet(meshedPatches());
217 
218  forAll(patches, patchi)
219  {
220  const polyPatch& pp = patches[patchi];
221 
222  const labelUList& faceCells = pp.faceCells();
223  const vectorField::subField faceCentres = pp.faceCentres();
224  const vectorField::subField faceAreas = pp.faceAreas();
225 
226  label bFacei = pp.start()-mesh_.nInternalFaces();
227 
228  if (pp.coupled())
229  {
230  forAll(faceCells, i)
231  {
232  neiLevel[bFacei] = cellLevel[faceCells[i]];
233  neiCc[bFacei] = cellCentres[faceCells[i]];
234  bFacei++;
235  }
236  }
237  else if (addedPatchIDSet.found(patchi))
238  {
239  // Face was introduced from cell-cell intersection. Try to
240  // reconstruct other side cell(centre). Three possibilities:
241  // - cells same size.
242  // - preserved cell smaller. Not handled.
243  // - preserved cell larger.
244  forAll(faceCells, i)
245  {
246  // Extrapolate the face centre.
247  const vector fn = normalised(faceAreas[i]);
248 
249  label own = faceCells[i];
250  label ownLevel = cellLevel[own];
251  label faceLevel = meshCutter_.faceLevel(pp.start()+i);
252  if (faceLevel < 0)
253  {
254  // Due to e.g. face merging no longer a consistent
255  // refinementlevel of face. Assume same as cell
256  faceLevel = ownLevel;
257  }
258 
259  // Normal distance from face centre to cell centre
260  scalar d = ((faceCentres[i] - cellCentres[own]) & fn);
261  if (faceLevel > ownLevel)
262  {
263  // Other cell more refined. Adjust normal distance
264  d *= 0.5;
265  }
266  neiLevel[bFacei] = faceLevel;
267  // Calculate other cell centre by extrapolation
268  neiCc[bFacei] = faceCentres[i] + d*fn;
269  bFacei++;
270  }
271  }
272  else
273  {
274  forAll(faceCells, i)
275  {
276  neiLevel[bFacei] = cellLevel[faceCells[i]];
277  neiCc[bFacei] = faceCentres[i];
278  bFacei++;
279  }
280  }
281  }
282 
283  // Swap coupled boundaries. Apply separation to cc since is coordinate.
285  syncTools::swapBoundaryFaceList(mesh_, neiLevel);
286 }
287 
288 
289 void Foam::meshRefinement::calcCellCellRays
290 (
291  const pointField& neiCc,
292  const labelList& neiLevel,
293  const labelList& testFaces,
294  pointField& start,
295  pointField& end,
296  labelList& minLevel
297 ) const
298 {
299  const labelList& cellLevel = meshCutter_.cellLevel();
300  const pointField& cellCentres = mesh_.cellCentres();
301 
302 
303  // Mark all non-coupled or coupled+master faces. Leaves only slave of
304  // coupled unset.
305  bitSet isMaster(mesh_.nBoundaryFaces(), true);
306  {
307  for (const polyPatch& pp : mesh_.boundaryMesh())
308  {
309  if (pp.coupled() && !refCast<const coupledPolyPatch>(pp).owner())
310  {
311  isMaster.unset(labelRange(pp.offset(), pp.size()));
312  }
313  }
314  }
315 
316 
317  start.setSize(testFaces.size());
318  end.setSize(testFaces.size());
319  minLevel.setSize(testFaces.size());
320 
321  forAll(testFaces, i)
322  {
323  const label facei = testFaces[i];
324  const label own = mesh_.faceOwner()[facei];
325 
326  if (mesh_.isInternalFace(facei))
327  {
328  const label nei = mesh_.faceNeighbour()[facei];
329 
330  start[i] = cellCentres[own];
331  end[i] = cellCentres[nei];
332  minLevel[i] = min(cellLevel[own], cellLevel[nei]);
333  }
334  else
335  {
336  const label bFacei = facei - mesh_.nInternalFaces();
337 
338  if (isMaster[bFacei])
339  {
340  start[i] = cellCentres[own];
341  end[i] = neiCc[bFacei];
342  }
343  else
344  {
345  // Slave face
346  start[i] = neiCc[bFacei];
347  end[i] = cellCentres[own];
348  }
349  minLevel[i] = min(cellLevel[own], neiLevel[bFacei]);
350  }
351  }
352 
353  // Extend segments a bit
354  {
355  const vectorField smallVec(ROOTSMALL*(end-start));
356  start -= smallVec;
357  end += smallVec;
358  }
359 }
360 
363 {
364  // Stats on edges to test. Count proc faces only once.
365  bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
366 
367  {
368  const label nMasterFaces =
369  returnReduce(isMasterFace.count(), sumOp<label>());
370 
371  label nChangedFaces = 0;
372  forAll(changedFaces, i)
373  {
374  if (isMasterFace.test(changedFaces[i]))
375  {
376  ++nChangedFaces;
377  }
378  }
379  reduce(nChangedFaces, sumOp<label>());
380 
381  if (!dryRun_)
382  {
383  Info<< "Edge intersection testing:" << nl
384  << " Number of edges : " << nMasterFaces << nl
385  << " Number of edges to retest : " << nChangedFaces
386  << endl;
387  }
388  }
389 
390 
391  // Get boundary face centre and level. Coupled aware.
392  labelList neiLevel(mesh_.nBoundaryFaces());
393  pointField neiCc(mesh_.nBoundaryFaces());
394  calcNeighbourData(neiLevel, neiCc);
395 
396  // Collect segments we want to test for
397  pointField start(changedFaces.size());
398  pointField end(changedFaces.size());
399  {
400  labelList minLevel;
401  calcCellCellRays
402  (
403  neiCc,
404  neiLevel,
405  changedFaces,
406  start,
407  end,
408  minLevel
409  );
410  }
411 
412 
413  // Do tests in one go
414  labelList surfaceHit;
415  {
416  labelList surfaceLevel;
417  surfaces_.findHigherIntersection
418  (
419  shells_,
420  start,
421  end,
422  labelList(start.size(), -1), // accept any intersection
423  surfaceHit,
424  surfaceLevel
425  );
426  }
427 
428  // Keep just surface hit
429  forAll(surfaceHit, i)
430  {
431  surfaceIndex_[changedFaces[i]] = surfaceHit[i];
432  }
433 
434  // Make sure both sides have same information. This should be
435  // case in general since same vectors but just to make sure.
436  syncTools::syncFaceList(mesh_, surfaceIndex_, maxEqOp<label>());
437 
438  label nTotHits = returnReduce(countHits(), sumOp<label>());
439 
440  if (!dryRun_)
441  {
442  Info<< " Number of intersected edges : " << nTotHits << endl;
443  }
444 
445  // Set files to same time as mesh
446  setInstance(mesh_.facesInstance());
447 }
448 
449 
450 void Foam::meshRefinement::nearestFace
451 (
452  const labelUList& startFaces,
453  const bitSet& isBlockedFace,
454 
455  autoPtr<mapDistribute>& mapPtr,
456  labelList& faceToStart,
457  const label nIter
458 ) const
459 {
460  // From startFaces walk out (but not through isBlockedFace). Returns
461  // faceToStart which is the index into startFaces (or rather distributed
462  // version of it). E.g.
463  // pointField startFc(mesh.faceCentres(), startFaces);
464  // mapPtr().distribute(startFc);
465  // forAll(faceToStart, facei)
466  // {
467  // const label sloti = faceToStart[facei];
468  // if (sloti != -1)
469  // {
470  // Pout<< "face:" << mesh.faceCentres()[facei]
471  // << " nearest:" << startFc[sloti]
472  // << endl;
473  // }
474  // }
475 
476 
477  // Consecutive global numbering for start elements
478  const globalIndex globalStart(startFaces.size());
479 
480  // Field on cells and faces.
481  List<topoDistanceData<label>> cellData(mesh_.nCells());
482  List<topoDistanceData<label>> faceData(mesh_.nFaces());
483 
484  // Mark blocked faces to there not visited
485  for (const label facei : isBlockedFace)
486  {
487  faceData[facei] = topoDistanceData<label>(0, -1);
488  }
489 
490  List<topoDistanceData<label>> startData(startFaces.size());
491  forAll(startFaces, i)
492  {
493  const label facei = startFaces[i];
494  if (isBlockedFace[facei])
495  {
496  FatalErrorInFunction << "Start face:" << facei
497  << " at:" << mesh_.faceCentres()[facei]
498  << " is also blocked" << exit(FatalError);
499  }
500  startData[i] = topoDistanceData<label>(0, globalStart.toGlobal(i));
501  }
502 
503 
504  // Propagate information inwards
505  FaceCellWave<topoDistanceData<label>> deltaCalc
506  (
507  mesh_,
508  startFaces,
509  startData,
510  faceData,
511  cellData,
512  0
513  );
514  deltaCalc.iterate(nIter);
515 
516  // And extract
517 
518  faceToStart.setSize(mesh_.nFaces());
519  faceToStart = -1;
520  bool haveWarned = false;
521  forAll(faceData, facei)
522  {
523  if (!faceData[facei].valid(deltaCalc.data()))
524  {
525  if (!haveWarned)
526  {
528  << "Did not visit some faces, e.g. face " << facei
529  << " at " << mesh_.faceCentres()[facei]
530  << endl;
531  haveWarned = true;
532  }
533  }
534  else
535  {
536  faceToStart[facei] = faceData[facei].data();
537  }
538  }
539 
540  // Compact
541  List<Map<label>> compactMap;
542  mapPtr.reset(new mapDistribute(globalStart, faceToStart, compactMap));
543 }
544 
545 
546 void Foam::meshRefinement::nearestPatch
547 (
548  const labelList& adaptPatchIDs,
549  labelList& nearestPatch,
550  labelList& nearestZone
551 ) const
552 {
553  // Determine nearest patch for all mesh faces. Used when removing cells
554  // to give some reasonable patch to exposed faces.
555 
556  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
557 
558  nearestZone.setSize(mesh_.nFaces(), -1);
559 
560  if (adaptPatchIDs.size())
561  {
562  nearestPatch.setSize(mesh_.nFaces(), adaptPatchIDs[0]);
563 
564 
565  // Get per-face the zone or -1
566  labelList faceToZone(mesh_.nFaces(), -1);
567  {
568  for (const faceZone& fz : mesh_.faceZones())
569  {
570  UIndirectList<label>(faceToZone, fz) = fz.index();
571  }
572  }
573 
574 
575  // Count number of faces in adaptPatchIDs
576  label nFaces = 0;
577  forAll(adaptPatchIDs, i)
578  {
579  const polyPatch& pp = patches[adaptPatchIDs[i]];
580  nFaces += pp.size();
581  }
582 
583  // Field on cells and faces.
584  List<topoDistanceData<labelPair>> cellData(mesh_.nCells());
585  List<topoDistanceData<labelPair>> faceData(mesh_.nFaces());
586 
587  // Start of changes
588  labelList patchFaces(nFaces);
589  List<topoDistanceData<labelPair>> patchData(nFaces);
590  nFaces = 0;
591  forAll(adaptPatchIDs, i)
592  {
593  label patchi = adaptPatchIDs[i];
594  const polyPatch& pp = patches[patchi];
595 
596  forAll(pp, i)
597  {
598  patchFaces[nFaces] = pp.start()+i;
599  patchData[nFaces] = topoDistanceData<labelPair>
600  (
601  0,
602  labelPair
603  (
604  patchi,
605  faceToZone[pp.start()+i]
606  )
607  );
608  nFaces++;
609  }
610  }
611 
612  // Propagate information inwards
613  FaceCellWave<topoDistanceData<labelPair>> deltaCalc
614  (
615  mesh_,
616  patchFaces,
617  patchData,
618  faceData,
619  cellData,
620  mesh_.globalData().nTotalCells()+1
621  );
622 
623  // And extract
624 
625  bool haveWarned = false;
626  forAll(faceData, facei)
627  {
628  if (!faceData[facei].valid(deltaCalc.data()))
629  {
630  if (!haveWarned)
631  {
633  << "Did not visit some faces, e.g. face " << facei
634  << " at " << mesh_.faceCentres()[facei] << endl
635  << "Assigning these faces to patch "
636  << adaptPatchIDs[0]
637  << endl;
638  haveWarned = true;
639  }
640  }
641  else
642  {
643  const labelPair& data = faceData[facei].data();
644  nearestPatch[facei] = data.first();
645  nearestZone[facei] = data.second();
646  }
647  }
648  }
649  else
650  {
651  // Use patch 0
652  nearestPatch.setSize(mesh_.nFaces(), 0);
653  }
654 }
655 
656 
657 Foam::labelList Foam::meshRefinement::nearestPatch
658 (
659  const labelList& adaptPatchIDs
660 ) const
661 {
662  labelList nearestAdaptPatch;
663  labelList nearestAdaptZone;
664  nearestPatch(adaptPatchIDs, nearestAdaptPatch, nearestAdaptZone);
665  return nearestAdaptPatch;
666 }
667 
668 
669 void Foam::meshRefinement::nearestIntersection
670 (
671  const labelList& surfacesToTest,
672  const labelList& testFaces,
673 
674  labelList& surface1,
675  List<pointIndexHit>& hit1,
676  labelList& region1,
677  labelList& surface2,
678  List<pointIndexHit>& hit2,
679  labelList& region2
680 ) const
681 {
682  // Swap neighbouring cell centres and cell level
683  labelList neiLevel(mesh_.nBoundaryFaces());
684  pointField neiCc(mesh_.nBoundaryFaces());
685  calcNeighbourData(neiLevel, neiCc);
686 
687 
688  // Collect segments
689 
690  pointField start(testFaces.size());
691  pointField end(testFaces.size());
692  labelList minLevel(testFaces.size());
693 
694  calcCellCellRays
695  (
696  neiCc,
697  neiLevel,
698  testFaces,
699  start,
700  end,
701  minLevel
702  );
703 
704  // Do tests in one go
705 
706  surfaces_.findNearestIntersection
707  (
708  surfacesToTest,
709  start,
710  end,
711 
712  surface1,
713  hit1,
714  region1,
715  surface2,
716  hit2,
717  region2
718  );
719 }
720 
721 
722 Foam::labelList Foam::meshRefinement::nearestIntersection
723 (
724  const labelList& surfacesToTest,
725  const label defaultRegion
726 ) const
727 {
728  // Determine nearest intersection for all mesh faces. Used when removing
729  // cells to give some reasonable patch to exposed faces. Use this
730  // function instead of nearestPatch if you don't have patches yet.
731 
732 
733  // All faces with any intersection
734  const labelList testFaces(intersectedFaces());
735 
736  // Find intersection (if any)
737  labelList surface1;
738  List<pointIndexHit> hit1;
739  labelList region1;
740  labelList surface2;
741  List<pointIndexHit> hit2;
742  labelList region2;
743  nearestIntersection
744  (
745  surfacesToTest,
746  testFaces,
747 
748  surface1,
749  hit1,
750  region1,
751  surface2,
752  hit2,
753  region2
754  );
755 
756 
757  labelList nearestRegion(mesh_.nFaces(), defaultRegion);
758 
759  // Field on cells and faces.
760  List<topoDistanceData<label>> cellData(mesh_.nCells());
761  List<topoDistanceData<label>> faceData(mesh_.nFaces());
762 
763  // Start walking from all intersected faces
764  DynamicList<label> patchFaces(testFaces.size());
765  DynamicList<topoDistanceData<label>> patchData(testFaces.size());
766  forAll(testFaces, i)
767  {
768  label facei = testFaces[i];
769  if (surface1[i] != -1)
770  {
771  patchFaces.append(facei);
772  label regioni = surfaces_.globalRegion(surface1[i], region1[i]);
773  patchData.append(topoDistanceData<label>(0, regioni));
774  }
775  else if (surface2[i] != -1)
776  {
777  patchFaces.append(facei);
778  label regioni = surfaces_.globalRegion(surface2[i], region2[i]);
779  patchData.append(topoDistanceData<label>(0, regioni));
780  }
781  }
782 
783  // Propagate information inwards
784  FaceCellWave<topoDistanceData<label>> deltaCalc
785  (
786  mesh_,
787  patchFaces,
788  patchData,
789  faceData,
790  cellData,
791  mesh_.globalData().nTotalCells()+1
792  );
793 
794  // And extract
795 
796  bool haveWarned = false;
797  forAll(faceData, facei)
798  {
799  if (!faceData[facei].valid(deltaCalc.data()))
800  {
801  if (!haveWarned)
802  {
804  << "Did not visit some faces, e.g. face " << facei
805  << " at " << mesh_.faceCentres()[facei] << endl
806  << "Assigning these faces to global region "
807  << defaultRegion << endl;
808  haveWarned = true;
809  }
810  }
811  else
812  {
813  nearestRegion[facei] = faceData[facei].data();
814  }
815  }
816 
817  return nearestRegion;
818 }
819 
820 
822 (
823  const string& msg,
824  const polyMesh& mesh,
825  const List<scalar>& fld
826 )
827 {
828  if (fld.size() != mesh.nPoints())
829  {
831  << msg << endl
832  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
833  << abort(FatalError);
834  }
835 
836  Pout<< "Checking field " << msg << endl;
837  scalarField minFld(fld);
839  (
840  mesh,
841  minFld,
842  minEqOp<scalar>(),
843  GREAT
844  );
845  scalarField maxFld(fld);
847  (
848  mesh,
849  maxFld,
850  maxEqOp<scalar>(),
851  -GREAT
852  );
853  forAll(minFld, pointi)
854  {
855  const scalar& minVal = minFld[pointi];
856  const scalar& maxVal = maxFld[pointi];
857  if (mag(minVal-maxVal) > SMALL)
858  {
859  Pout<< msg << " at:" << mesh.points()[pointi] << nl
860  << " minFld:" << minVal << nl
861  << " maxFld:" << maxVal << nl
862  << endl;
863  }
864  }
865 }
866 
867 
869 (
870  const string& msg,
871  const polyMesh& mesh,
872  const List<point>& fld
873 )
874 {
875  if (fld.size() != mesh.nPoints())
876  {
878  << msg << endl
879  << "fld size:" << fld.size() << " mesh points:" << mesh.nPoints()
880  << abort(FatalError);
881  }
882 
883  Pout<< "Checking field " << msg << endl;
884  pointField minFld(fld);
886  (
887  mesh,
888  minFld,
890  point(GREAT, GREAT, GREAT)
891  );
892  pointField maxFld(fld);
894  (
895  mesh,
896  maxFld,
898  vector::zero
899  );
900  forAll(minFld, pointi)
901  {
902  const point& minVal = minFld[pointi];
903  const point& maxVal = maxFld[pointi];
904  if (mag(minVal-maxVal) > SMALL)
905  {
906  Pout<< msg << " at:" << mesh.points()[pointi] << nl
907  << " minFld:" << minVal << nl
908  << " maxFld:" << maxVal << nl
909  << endl;
910  }
911  }
912 }
913 
916 {
917  Pout<< "meshRefinement::checkData() : Checking refinement structure."
918  << endl;
919  meshCutter_.checkMesh();
920 
921  Pout<< "meshRefinement::checkData() : Checking refinement levels."
922  << endl;
923  meshCutter_.checkRefinementLevels(1, labelList(0));
924 
925 
926  const label nBnd = mesh_.nBoundaryFaces();
927 
928  Pout<< "meshRefinement::checkData() : Checking synchronization."
929  << endl;
930 
931  // Check face centres
932  {
933  // Boundary face centres
934  pointField::subList boundaryFc
935  (
936  mesh_.faceCentres(),
937  nBnd,
938  mesh_.nInternalFaces()
939  );
940 
941  // Get neighbouring face centres
942  pointField neiBoundaryFc(boundaryFc);
944  (
945  mesh_,
946  neiBoundaryFc,
947  eqOp<point>()
948  );
949 
950  // Compare
951  testSyncBoundaryFaceList
952  (
953  mergeDistance_,
954  "testing faceCentres : ",
955  boundaryFc,
956  neiBoundaryFc
957  );
958  }
959 
960  // Check meshRefinement
961  const labelList& surfIndex = surfaceIndex();
962 
963 
964  {
965  // Get boundary face centre and level. Coupled aware.
966  labelList neiLevel(nBnd);
967  pointField neiCc(nBnd);
968  calcNeighbourData(neiLevel, neiCc);
969 
970  // Collect segments we want to test for
971  pointField start(mesh_.nFaces());
972  pointField end(mesh_.nFaces());
973 
974  forAll(start, facei)
975  {
976  start[facei] = mesh_.cellCentres()[mesh_.faceOwner()[facei]];
977 
978  if (mesh_.isInternalFace(facei))
979  {
980  end[facei] = mesh_.cellCentres()[mesh_.faceNeighbour()[facei]];
981  }
982  else
983  {
984  end[facei] = neiCc[facei-mesh_.nInternalFaces()];
985  }
986  }
987 
988  // Extend segments a bit
989  {
990  const vectorField smallVec(ROOTSMALL*(end-start));
991  start -= smallVec;
992  end += smallVec;
993  }
994 
995 
996  // Do tests in one go
997  labelList surfaceHit;
998  {
999  labelList surfaceLevel;
1000  surfaces_.findHigherIntersection
1001  (
1002  shells_,
1003  start,
1004  end,
1005  labelList(start.size(), -1), // accept any intersection
1006  surfaceHit,
1007  surfaceLevel
1008  );
1009  }
1010  // Get the coupled hit
1011  labelList neiHit
1012  (
1014  (
1015  surfaceHit,
1016  nBnd,
1017  mesh_.nInternalFaces()
1018  )
1019  );
1020  syncTools::swapBoundaryFaceList(mesh_, neiHit);
1021 
1022  // Check
1023  forAll(surfaceHit, facei)
1024  {
1025  if (surfIndex[facei] != surfaceHit[facei])
1026  {
1027  if (mesh_.isInternalFace(facei))
1028  {
1030  << "Internal face:" << facei
1031  << " fc:" << mesh_.faceCentres()[facei]
1032  << " cached surfaceIndex_:" << surfIndex[facei]
1033  << " current:" << surfaceHit[facei]
1034  << " ownCc:"
1035  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
1036  << " neiCc:"
1037  << mesh_.cellCentres()[mesh_.faceNeighbour()[facei]]
1038  << endl;
1039  }
1040  else if
1041  (
1042  surfIndex[facei]
1043  != neiHit[facei-mesh_.nInternalFaces()]
1044  )
1045  {
1047  << "Boundary face:" << facei
1048  << " fc:" << mesh_.faceCentres()[facei]
1049  << " cached surfaceIndex_:" << surfIndex[facei]
1050  << " current:" << surfaceHit[facei]
1051  << " ownCc:"
1052  << mesh_.cellCentres()[mesh_.faceOwner()[facei]]
1053  << " neiCc:"
1054  << neiCc[facei-mesh_.nInternalFaces()]
1055  << " end:" << end[facei]
1056  << " ownLevel:"
1057  << meshCutter_.cellLevel()[mesh_.faceOwner()[facei]]
1058  << " faceLevel:"
1059  << meshCutter_.faceLevel(facei)
1060  << endl;
1061  }
1062  }
1063  }
1064  }
1065  {
1066  labelList::subList boundarySurface
1067  (
1068  surfaceIndex_,
1069  mesh_.nBoundaryFaces(),
1070  mesh_.nInternalFaces()
1071  );
1072 
1073  labelList neiBoundarySurface(boundarySurface);
1075  (
1076  mesh_,
1077  neiBoundarySurface
1078  );
1079 
1080  // Compare
1081  testSyncBoundaryFaceList
1082  (
1083  0, // tolerance
1084  "testing surfaceIndex() : ",
1085  boundarySurface,
1086  neiBoundarySurface
1087  );
1088  }
1089 
1090 
1091  // Find duplicate faces
1092  Pout<< "meshRefinement::checkData() : Counting duplicate faces."
1093  << endl;
1094 
1095  labelList duplicateFace
1096  (
1098  (
1099  mesh_,
1100  identity(mesh_.nBoundaryFaces(), mesh_.nInternalFaces())
1101  )
1102  );
1103 
1104  // Count
1105  {
1106  label nDup = 0;
1107 
1108  forAll(duplicateFace, i)
1109  {
1110  if (duplicateFace[i] != -1)
1111  {
1112  nDup++;
1113  }
1114  }
1115  nDup /= 2; // will have counted both faces of duplicate
1116  Pout<< "meshRefinement::checkData() : Found " << nDup
1117  << " duplicate pairs of faces." << endl;
1118  }
1119 }
1120 
1123 {
1124  meshCutter_.setInstance(inst);
1125  surfaceIndex_.instance() = inst;
1126 }
1127 
1128 
1130 (
1131  const labelList& cellsToRemove,
1132  const labelList& exposedFaces,
1133  const labelList& exposedPatchIDs,
1134  removeCells& cellRemover
1135 )
1136 {
1137  polyTopoChange meshMod(mesh_);
1138 
1139  // Arbitrary: put exposed faces into last patch.
1140  cellRemover.setRefinement
1141  (
1142  cellsToRemove,
1143  exposedFaces,
1144  exposedPatchIDs,
1145  meshMod
1146  );
1147 
1148  // Remove any unnecessary fields
1149  mesh_.clearOut();
1150  mesh_.moving(false);
1151 
1152  // Change the mesh (no inflation)
1153  autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1154  mapPolyMesh& map = *mapPtr;
1155 
1156  // Update fields
1157  mesh_.updateMesh(map);
1158 
1159  // Move mesh (since morphing might not do this)
1160  if (map.hasMotionPoints())
1161  {
1162  mesh_.movePoints(map.preMotionPoints());
1163  }
1164  else
1165  {
1166  // Delete mesh volumes. No other way to do this?
1167  mesh_.clearOut();
1168  }
1169 
1170  // Reset the instance for if in overwrite mode
1171  mesh_.setInstance(timeName());
1172  setInstance(mesh_.facesInstance());
1173 
1174  // Update local mesh data
1175  cellRemover.updateMesh(map);
1176 
1177  // Update intersections. Recalculate intersections for exposed faces.
1178  labelList newExposedFaces = renumber
1179  (
1180  map.reverseFaceMap(),
1181  exposedFaces
1182  );
1183 
1184  //Pout<< "removeCells : updating intersections for "
1185  // << newExposedFaces.size() << " newly exposed faces." << endl;
1186 
1187  updateMesh(map, newExposedFaces);
1188 
1189  return mapPtr;
1190 }
1191 
1192 
1194 (
1195  const face& f,
1196  const labelPair& split,
1197 
1198  face& f0,
1199  face& f1
1200 )
1201 {
1202  if (split.find(-1) != -1)
1203  {
1204  FatalErrorInFunction<< "Illegal split " << split
1205  << " on face " << f << exit(FatalError);
1206  }
1207 
1208  label nVerts = split[1]-split[0];
1209  if (nVerts < 0)
1210  {
1211  nVerts += f.size();
1212  }
1213  nVerts += 1;
1214 
1215 
1216  // Split into f0, f1
1217  f0.resize_nocopy(nVerts);
1218 
1219  label fp = split[0];
1220  forAll(f0, i)
1221  {
1222  f0[i] = f[fp];
1223  fp = f.fcIndex(fp);
1224  }
1225 
1226  f1.resize_nocopy(f.size()-f0.size()+2);
1227  fp = split[1];
1228  forAll(f1, i)
1229  {
1230  f1[i] = f[fp];
1231  fp = f.fcIndex(fp);
1232  }
1233 }
1234 
1235 
1237 (
1238  const labelList& splitFaces,
1239  const labelPairList& splits,
1240  const labelPairList& splitPatches,
1241  //const List<Pair<point>>& splitPoints,
1242  polyTopoChange& meshMod
1243 ) const
1244 {
1245  face f0, f1;
1246 
1247  forAll(splitFaces, i)
1248  {
1249  const label facei = splitFaces[i];
1250  const auto& split = splits[i];
1251  const auto& twoPatches = splitPatches[i];
1252 
1253  const face& f = mesh_.faces()[facei];
1254 
1255  // Split as start and end index in face
1256  splitFace(f, split, f0, f1);
1257 
1258  // Determine face properties
1259  label own = mesh_.faceOwner()[facei];
1260  label nei = -1;
1261  label patch0 = -1;
1262  label patch1 = -1;
1263  if (facei >= mesh_.nInternalFaces())
1264  {
1265  patch0 =
1266  (
1267  twoPatches[0] != -1
1268  ? twoPatches[0]
1269  : mesh_.boundaryMesh().whichPatch(facei)
1270  );
1271  patch1 =
1272  (
1273  twoPatches[1] != -1
1274  ? twoPatches[1]
1275  : mesh_.boundaryMesh().whichPatch(facei)
1276  );
1277  }
1278  else
1279  {
1280  nei = mesh_.faceNeighbour()[facei];
1281  }
1282 
1283  label zonei = mesh_.faceZones().whichZone(facei);
1284  bool zoneFlip = false;
1285  if (zonei != -1)
1286  {
1287  const faceZone& fz = mesh_.faceZones()[zonei];
1288  zoneFlip = fz.flipMap()[fz.whichFace(facei)];
1289  }
1290 
1291 
1292  if (debug)
1293  {
1294  Pout<< "face:" << facei << " verts:" << f
1295  << " split into f0:" << f0
1296  << " f1:" << f1 << endl;
1297  }
1298 
1299  // Change/add faces
1300  meshMod.modifyFace
1301  (
1302  f0, // modified face
1303  facei, // label of face
1304  own, // owner
1305  nei, // neighbour
1306  false, // face flip
1307  patch0, // patch for face
1308  zonei, // zone for face
1309  zoneFlip // face flip in zone
1310  );
1311 
1312  meshMod.addFace
1313  (
1314  f1, // modified face
1315  own, // owner
1316  nei, // neighbour
1317  -1, // master point
1318  -1, // master edge
1319  facei, // master face
1320  false, // face flip
1321  patch1, // patch for face
1322  zonei, // zone for face
1323  zoneFlip // face flip in zone
1324  );
1325 
1326 
1328  //meshMod.modifyPoint
1329  //(
1330  // f[split[0]],
1331  // splitPoints[i][0],
1332  // -1,
1333  // true
1334  //);
1335  //meshMod.modifyPoint
1336  //(
1337  // f[split[1]],
1338  // splitPoints[i][1],
1339  // -1,
1340  // true
1341  //);
1342  }
1343 }
1344 
1345 
1347 (
1348  const labelList& splitFaces,
1349  const labelPairList& splits,
1350  const labelPairList& splitPatches,
1351  const dictionary& motionDict,
1352 
1353  labelList& duplicateFace,
1354  List<labelPair>& baffles
1355 )
1356 {
1357  label nSplit = returnReduce(splitFaces.size(), sumOp<label>());
1358  Info<< nl
1359  << "Splitting " << nSplit
1360  << " faces across diagonals" << "." << nl << endl;
1361 
1362  // To undo: store original faces
1363  faceList originalFaces(UIndirectList<face>(mesh_.faces(), splitFaces));
1364  labelPairList facePairs(splitFaces.size(), labelPair(-1, -1));
1365 
1366 
1367  {
1368  polyTopoChange meshMod(mesh_);
1369  meshMod.setCapacity
1370  (
1371  meshMod.points().size(),
1372  meshMod.faces().size()+splitFaces.size(),
1373  mesh_.nCells()
1374  );
1375 
1376  // Insert the mesh changes
1377  doSplitFaces(splitFaces, splits, splitPatches, meshMod);
1378 
1379  // Remove any unnecessary fields
1380  mesh_.clearOut();
1381  mesh_.moving(false);
1382 
1383  // Change the mesh (no inflation)
1384  autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1385  mapPolyMesh& map = *mapPtr;
1386 
1387  // Update fields
1388  mesh_.updateMesh(map);
1389 
1390  // Move mesh (since morphing might not do this)
1391  if (map.hasMotionPoints())
1392  {
1393  mesh_.movePoints(map.preMotionPoints());
1394  }
1395  else
1396  {
1397  mesh_.clearOut();
1398  }
1399 
1400  // Reset the instance for if in overwrite mode
1401  mesh_.setInstance(timeName());
1402  setInstance(mesh_.facesInstance());
1403 
1404 
1405  // Update local mesh data
1406  // ~~~~~~~~~~~~~~~~~~~~~~
1407 
1408  forAll(originalFaces, i)
1409  {
1410  inplaceRenumber(map.reversePointMap(), originalFaces[i]);
1411  }
1412 
1413  {
1414  Map<label> splitFaceToIndex(invertToMap(splitFaces));
1415 
1416  forAll(map.faceMap(), facei)
1417  {
1418  label oldFacei = map.faceMap()[facei];
1419 
1420  const auto oldFaceFnd = splitFaceToIndex.cfind(oldFacei);
1421 
1422  if (oldFaceFnd.good())
1423  {
1424  labelPair& twoFaces = facePairs[oldFaceFnd.val()];
1425  if (twoFaces[0] == -1)
1426  {
1427  twoFaces[0] = facei;
1428  }
1429  else if (twoFaces[1] == -1)
1430  {
1431  twoFaces[1] = facei;
1432  }
1433  else
1434  {
1436  << "problem: twoFaces:" << twoFaces
1437  << exit(FatalError);
1438  }
1439  }
1440  }
1441  }
1442 
1443 
1444  // Update baffle data
1445  // ~~~~~~~~~~~~~~~~~~
1446 
1447  if (duplicateFace.size())
1448  {
1450  (
1451  map.faceMap(),
1452  label(-1),
1453  duplicateFace
1454  );
1455  }
1456 
1457  const labelList& oldToNewFaces = map.reverseFaceMap();
1458  forAll(baffles, i)
1459  {
1460  labelPair& baffle = baffles[i];
1461  baffle.first() = oldToNewFaces[baffle.first()];
1462  baffle.second() = oldToNewFaces[baffle.second()];
1463 
1464  if (baffle.first() == -1 || baffle.second() == -1)
1465  {
1467  << "Removed baffle : faces:" << baffle
1468  << exit(FatalError);
1469  }
1470  }
1471 
1472 
1473  // Update intersections
1474  // ~~~~~~~~~~~~~~~~~~~~
1475 
1476  {
1477  DynamicList<label> changedFaces(facePairs.size());
1478  forAll(facePairs, i)
1479  {
1480  changedFaces.append(facePairs[i].first());
1481  changedFaces.append(facePairs[i].second());
1482  }
1483 
1484  // Update intersections on changed faces
1485  updateMesh(map, growFaceCellFace(changedFaces));
1486  }
1487  }
1488 
1489 
1490 
1491  // Undo loop
1492  // ~~~~~~~~~
1493  // Maintains two bits of information:
1494  // facePairs : two faces originating from the same face
1495  // originalFaces : original face in current vertices
1496 
1497 
1498  for (label iteration = 0; iteration < 100; iteration++)
1499  {
1500  Info<< nl
1501  << "Undo iteration " << iteration << nl
1502  << "----------------" << endl;
1503 
1504 
1505  // Check mesh for errors
1506  // ~~~~~~~~~~~~~~~~~~~~~
1507 
1508  faceSet errorFaces(mesh_, "errorFaces", mesh_.nBoundaryFaces());
1509  bool hasErrors = motionSmoother::checkMesh
1510  (
1511  false, // report
1512  mesh_,
1513  motionDict,
1514  errorFaces,
1515  dryRun_
1516  );
1517  if (!hasErrors)
1518  {
1519  break;
1520  }
1521 
1522  // Extend faces
1523  {
1524  const labelList grownFaces(growFaceCellFace(errorFaces));
1525  errorFaces.clear();
1526  errorFaces.insert(grownFaces);
1527  }
1528 
1529 
1530  // Merge face pairs
1531  // ~~~~~~~~~~~~~~~~
1532  // (if one of the faces is in the errorFaces set)
1533 
1534  polyTopoChange meshMod(mesh_);
1535 
1536  // Indices (in facePairs) of merged faces
1537  labelHashSet mergedIndices(facePairs.size());
1538  forAll(facePairs, index)
1539  {
1540  const labelPair& twoFaces = facePairs[index];
1541 
1542  if
1543  (
1544  errorFaces.found(twoFaces.first())
1545  || errorFaces.found(twoFaces.second())
1546  )
1547  {
1548  const face& originalFace = originalFaces[index];
1549 
1550 
1551  // Determine face properties
1552  label own = mesh_.faceOwner()[twoFaces[0]];
1553  label nei = -1;
1554  label patchi = -1;
1555  if (twoFaces[0] >= mesh_.nInternalFaces())
1556  {
1557  patchi = mesh_.boundaryMesh().whichPatch(twoFaces[0]);
1558  }
1559  else
1560  {
1561  nei = mesh_.faceNeighbour()[twoFaces[0]];
1562  }
1563 
1564  label zonei = mesh_.faceZones().whichZone(twoFaces[0]);
1565  bool zoneFlip = false;
1566  if (zonei != -1)
1567  {
1568  const faceZone& fz = mesh_.faceZones()[zonei];
1569  zoneFlip = fz.flipMap()[fz.whichFace(twoFaces[0])];
1570  }
1571 
1572  // Modify first face
1573  meshMod.modifyFace
1574  (
1575  originalFace, // modified face
1576  twoFaces[0], // label of face
1577  own, // owner
1578  nei, // neighbour
1579  false, // face flip
1580  patchi, // patch for face
1581  zonei, // zone for face
1582  zoneFlip // face flip in zone
1583  );
1584  // Merge second face into first
1585  meshMod.removeFace(twoFaces[1], twoFaces[0]);
1586 
1587  mergedIndices.insert(index);
1588  }
1589  }
1590 
1591  label n = returnReduce(mergedIndices.size(), sumOp<label>());
1592 
1593  Info<< "Detected " << n
1594  << " split faces that will be restored to their original faces."
1595  << nl << endl;
1596 
1597  if (n == 0)
1598  {
1599  // Nothing to be restored
1600  break;
1601  }
1602 
1603  nSplit -= n;
1604 
1605 
1606  // Remove any unnecessary fields
1607  mesh_.clearOut();
1608  mesh_.moving(false);
1609 
1610  // Change the mesh (no inflation)
1611  autoPtr<mapPolyMesh> mapPtr = meshMod.changeMesh(mesh_, false, true);
1612  mapPolyMesh& map = *mapPtr;
1613 
1614  // Update fields
1615  mesh_.updateMesh(map);
1616 
1617  // Move mesh (since morphing might not do this)
1618  if (map.hasMotionPoints())
1619  {
1620  mesh_.movePoints(map.preMotionPoints());
1621  }
1622  else
1623  {
1624  mesh_.clearOut();
1625  }
1626 
1627  // Reset the instance for if in overwrite mode
1628  mesh_.setInstance(timeName());
1629  setInstance(mesh_.facesInstance());
1630 
1631 
1632  // Update local mesh data
1633  // ~~~~~~~~~~~~~~~~~~~~~~
1634 
1635  {
1636  const labelList& oldToNewFaces = map.reverseFaceMap();
1637  const labelList& oldToNewPoints = map.reversePointMap();
1638 
1639  // Compact out merged faces
1640  DynamicList<label> changedFaces(mergedIndices.size());
1641 
1642  label newIndex = 0;
1643  forAll(facePairs, index)
1644  {
1645  const labelPair& oldSplit = facePairs[index];
1646  label new0 = oldToNewFaces[oldSplit[0]];
1647  label new1 = oldToNewFaces[oldSplit[1]];
1648 
1649  if (!mergedIndices.found(index))
1650  {
1651  // Faces still split
1652  if (new0 < 0 || new1 < 0)
1653  {
1655  << "Problem: oldFaces:" << oldSplit
1656  << " newFaces:" << labelPair(new0, new1)
1657  << exit(FatalError);
1658  }
1659 
1660  facePairs[newIndex] = labelPair(new0, new1);
1661  originalFaces[newIndex] = renumber
1662  (
1663  oldToNewPoints,
1664  originalFaces[index]
1665  );
1666  newIndex++;
1667  }
1668  else
1669  {
1670  // Merged face. Only new0 kept.
1671  if (new0 < 0 || new1 == -1)
1672  {
1674  << "Problem: oldFaces:" << oldSplit
1675  << " newFace:" << labelPair(new0, new1)
1676  << exit(FatalError);
1677  }
1678  changedFaces.append(new0);
1679  }
1680  }
1681 
1682  facePairs.setSize(newIndex);
1683  originalFaces.setSize(newIndex);
1684 
1685 
1686  // Update intersections
1687  updateMesh(map, growFaceCellFace(changedFaces));
1688  }
1689 
1690  // Update baffle data
1691  // ~~~~~~~~~~~~~~~~~~
1692  {
1693  if (duplicateFace.size())
1694  {
1696  (
1697  map.faceMap(),
1698  label(-1),
1699  duplicateFace
1700  );
1701  }
1702 
1703  const labelList& reverseFaceMap = map.reverseFaceMap();
1704  forAll(baffles, i)
1705  {
1706  labelPair& baffle = baffles[i];
1707  baffle.first() = reverseFaceMap[baffle.first()];
1708  baffle.second() = reverseFaceMap[baffle.second()];
1709 
1710  if (baffle.first() == -1 || baffle.second() == -1)
1711  {
1713  << "Removed baffle : faces:" << baffle
1714  << exit(FatalError);
1715  }
1716  }
1717  }
1718 
1719  }
1720 
1721  return nSplit;
1722 }
1723 
1724 
1725 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
1726 
1727 Foam::meshRefinement::meshRefinement
1728 (
1729  fvMesh& mesh,
1730  const scalar mergeDistance,
1731  const bool overwrite,
1732  const refinementSurfaces& surfaces,
1733  const refinementFeatures& features,
1734  const shellSurfaces& shells,
1735  const shellSurfaces& limitShells,
1736  const labelUList& checkFaces,
1737  const MeshType meshType,
1738  const bool dryRun
1739 )
1740 :
1741  mesh_(mesh),
1742  mergeDistance_(mergeDistance),
1743  overwrite_(overwrite),
1744  oldInstance_(mesh.pointsInstance()),
1745  surfaces_(surfaces),
1746  features_(features),
1747  shells_(shells),
1748  limitShells_(limitShells),
1749  meshType_(meshType),
1750  dryRun_(dryRun),
1751  meshCutter_
1752  (
1753  mesh,
1754  false // do not try to read history.
1755  ),
1756  surfaceIndex_
1757  (
1758  IOobject
1759  (
1760  "surfaceIndex",
1761  mesh_.facesInstance(),
1762  polyMesh::meshSubDir,
1763  mesh_,
1764  IOobject::NO_READ,
1765  IOobject::NO_WRITE,
1766  IOobject::NO_REGISTER
1767  ),
1768  labelList(mesh_.nFaces(), -1)
1769  ),
1770  userFaceData_(0)
1771 {
1772  // recalculate intersections for all faces
1773  updateIntersections(checkFaces);
1774 }
1775 
1776 
1777 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
1780 {
1781  if (surfaceIndex_.size() != mesh_.nFaces())
1782  {
1783  const_cast<meshRefinement&>(*this).updateIntersections
1784  (
1785  identity(mesh_.nFaces())
1786  );
1787  }
1788  return surfaceIndex_;
1789 }
1790 
1793 {
1794  if (surfaceIndex_.size() != mesh_.nFaces())
1795  {
1796  updateIntersections(identity(mesh_.nFaces()));
1797  }
1798  return surfaceIndex_;
1799 }
1800 
1802 Foam::label Foam::meshRefinement::countHits() const
1803 {
1804  // Stats on edges to test. Count proc faces only once.
1805  bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
1806 
1807  label nHits = 0;
1808 
1809  const labelList& surfIndex = surfaceIndex();
1810 
1811  forAll(surfIndex, facei)
1812  {
1813  if (surfIndex[facei] >= 0 && isMasterFace.test(facei))
1814  {
1815  ++nHits;
1816  }
1817  }
1818  return nHits;
1819 }
1820 
1821 
1823 (
1824  const bool keepZoneFaces,
1825  const bool keepBaffles,
1826  const labelList& singleProcPoints,
1827  const scalarField& cellWeights,
1828  decompositionMethod& decomposer,
1829  fvMeshDistribute& distributor
1830 )
1831 {
1833 
1834  if (Pstream::parRun())
1835  {
1836  // Wanted distribution
1838 
1839 
1840  // Faces where owner and neighbour are not 'connected' so can
1841  // go to different processors.
1842  boolList blockedFace;
1843  label nUnblocked = 0;
1844 
1845  // Faces that move as block onto single processor
1846  PtrList<labelList> specifiedProcessorFaces;
1847  labelList specifiedProcessor;
1848 
1849  // Pairs of baffles
1850  List<labelPair> couples;
1851 
1852  // Constraints from decomposeParDict
1853  decomposer.setConstraints
1854  (
1855  mesh_,
1856  blockedFace,
1857  specifiedProcessorFaces,
1858  specifiedProcessor,
1859  couples
1860  );
1861 
1862 
1863  if (keepZoneFaces || keepBaffles)
1864  {
1865  if (keepZoneFaces)
1866  {
1867  // Determine decomposition to keep/move surface zones
1868  // on one processor. The reason is that snapping will make these
1869  // into baffles, move and convert them back so if they were
1870  // proc boundaries after baffling&moving the points might be no
1871  // longer synchronised so recoupling will fail. To prevent this
1872  // keep owner&neighbour of such a surface zone on the same
1873  // processor.
1874 
1875  const faceZoneMesh& fZones = mesh_.faceZones();
1876  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
1877 
1878  // Get faces whose owner and neighbour should stay together,
1879  // i.e. they are not 'blocked'.
1880 
1881  forAll(fZones, zonei)
1882  {
1883  const faceZone& fZone = fZones[zonei];
1884 
1885  forAll(fZone, i)
1886  {
1887  label facei = fZone[i];
1888  if (blockedFace[facei])
1889  {
1890  if
1891  (
1892  mesh_.isInternalFace(facei)
1893  || pbm[pbm.whichPatch(facei)].coupled()
1894  )
1895  {
1896  blockedFace[facei] = false;
1897  nUnblocked++;
1898  }
1899  }
1900  }
1901  }
1902 
1903 
1904  // If the faceZones are not synchronised the blockedFace
1905  // might not be synchronised. If you are sure the faceZones
1906  // are synchronised remove below check.
1908  (
1909  mesh_,
1910  blockedFace,
1911  andEqOp<bool>() // combine operator
1912  );
1913  }
1914  reduce(nUnblocked, sumOp<label>());
1915 
1916  if (keepZoneFaces)
1917  {
1918  Info<< "Found " << nUnblocked
1919  << " zoned faces to keep together." << endl;
1920  }
1921 
1922 
1923  // Extend un-blockedFaces with any cyclics
1924  {
1925  boolList separatedCoupledFace(mesh_.nFaces(), false);
1926  selectSeparatedCoupledFaces(separatedCoupledFace);
1927 
1928  label nSeparated = 0;
1929  forAll(separatedCoupledFace, facei)
1930  {
1931  if (separatedCoupledFace[facei])
1932  {
1933  if (blockedFace[facei])
1934  {
1935  blockedFace[facei] = false;
1936  nSeparated++;
1937  }
1938  }
1939  }
1940  reduce(nSeparated, sumOp<label>());
1941  Info<< "Found " << nSeparated
1942  << " separated coupled faces to keep together." << endl;
1943 
1944  nUnblocked += nSeparated;
1945  }
1946 
1947 
1948  if (keepBaffles)
1949  {
1950  const label nBnd = mesh_.nBoundaryFaces();
1951 
1952  labelList coupledFace(mesh_.nFaces(), -1);
1953  {
1954  // Get boundary baffles that need to stay together
1955  List<labelPair> allCouples
1956  (
1958  );
1959 
1960  // Merge with any couples from
1961  // decompositionMethod::setConstraints
1962  forAll(couples, i)
1963  {
1964  const labelPair& baffle = couples[i];
1965  coupledFace[baffle.first()] = baffle.second();
1966  coupledFace[baffle.second()] = baffle.first();
1967  }
1968  forAll(allCouples, i)
1969  {
1970  const labelPair& baffle = allCouples[i];
1971  coupledFace[baffle.first()] = baffle.second();
1972  coupledFace[baffle.second()] = baffle.first();
1973  }
1974  }
1975 
1976  couples.setSize(nBnd);
1977  label nCpl = 0;
1978  forAll(coupledFace, facei)
1979  {
1980  if (coupledFace[facei] != -1 && facei < coupledFace[facei])
1981  {
1982  couples[nCpl++] = labelPair(facei, coupledFace[facei]);
1983  }
1984  }
1985  couples.setSize(nCpl);
1986  }
1987  label nCouples = returnReduce(couples.size(), sumOp<label>());
1988 
1989  if (keepBaffles)
1990  {
1991  Info<< "Found " << nCouples << " baffles to keep together."
1992  << endl;
1993  }
1994  }
1995 
1996 
1997  // Make sure blockedFace not set on couples
1998  forAll(couples, i)
1999  {
2000  const labelPair& baffle = couples[i];
2001  blockedFace[baffle.first()] = false;
2002  blockedFace[baffle.second()] = false;
2003  }
2004 
2005  if (returnReduceOr(singleProcPoints.size()))
2006  {
2007  // Modify couples to force all selected points be on the same
2008  // processor
2009 
2010  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2011 
2012  label nPointFaces = 0;
2013  for (const label pointi : singleProcPoints)
2014  {
2015  for (const label facei : mesh_.pointFaces()[pointi])
2016  {
2017  if (blockedFace[facei])
2018  {
2019  if
2020  (
2021  mesh_.isInternalFace(facei)
2022  || pbm[pbm.whichPatch(facei)].coupled()
2023  )
2024  {
2025  blockedFace[facei] = false;
2026  nPointFaces++;
2027  }
2028  }
2029  }
2030  }
2031  reduce(nPointFaces, sumOp<label>());
2032  Info<< "Found " << nPointFaces
2033  << " additional point-coupled faces to keep together." << endl;
2034 
2035  nUnblocked += nPointFaces;
2036  }
2037 
2038 
2039  distribution = decomposer.decompose
2040  (
2041  mesh_,
2042  cellWeights,
2043  blockedFace,
2044  specifiedProcessorFaces,
2045  specifiedProcessor,
2046  couples // explicit connections
2047  );
2048 
2049  if (debug)
2050  {
2051  labelList nProcCells(distributor.countCells(distribution));
2052  Pout<< "Wanted distribution:" << nProcCells << endl;
2053 
2055 
2056  Pout<< "Wanted resulting decomposition:" << endl;
2057  forAll(nProcCells, proci)
2058  {
2059  Pout<< " " << proci << '\t' << nProcCells[proci] << endl;
2060  }
2061  Pout<< endl;
2062  }
2063 
2064  // Do actual sending/receiving of mesh
2065  map = distributor.distribute(distribution);
2066 
2067  // Update numbering of meshRefiner
2068  distribute(map());
2069 
2070  // Set correct instance (for if overwrite)
2071  mesh_.setInstance(timeName());
2072  setInstance(mesh_.facesInstance());
2073 
2074 
2075  if (debug && keepZoneFaces)
2076  {
2077  const faceZoneMesh& fZones = mesh_.faceZones();
2078  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2079 
2080  // Check that faceZone faces are indeed internal
2081  forAll(fZones, zonei)
2082  {
2083  const faceZone& fZone = fZones[zonei];
2084 
2085  forAll(fZone, i)
2086  {
2087  label facei = fZone[i];
2088  label patchi = pbm.whichPatch(facei);
2089 
2090  if (patchi >= 0 && pbm[patchi].coupled())
2091  {
2093  << "Face at " << mesh_.faceCentres()[facei]
2094  << " on zone " << fZone.name()
2095  << " is on coupled patch " << pbm[patchi].name()
2096  << endl;
2097  }
2098  }
2099  }
2100  }
2101  }
2102 
2103  return map;
2104 }
2105 
2108 {
2109  label nBoundaryFaces = 0;
2110 
2111  const labelList& surfIndex = surfaceIndex();
2112 
2113  forAll(surfIndex, facei)
2114  {
2115  if (surfIndex[facei] != -1)
2116  {
2117  nBoundaryFaces++;
2118  }
2119  }
2120 
2121  labelList surfaceFaces(nBoundaryFaces);
2122  nBoundaryFaces = 0;
2123 
2124  forAll(surfIndex, facei)
2125  {
2126  if (surfIndex[facei] != -1)
2127  {
2128  surfaceFaces[nBoundaryFaces++] = facei;
2129  }
2130  }
2131  return surfaceFaces;
2132 }
2133 
2136 {
2137  const faceList& faces = mesh_.faces();
2138 
2139  // Mark all points on faces that will become baffles
2140  bitSet isBoundaryPoint(mesh_.nPoints());
2141 
2142  const labelList& surfIndex = surfaceIndex();
2143 
2144  forAll(surfIndex, facei)
2145  {
2146  if (surfIndex[facei] != -1)
2147  {
2148  isBoundaryPoint.set(faces[facei]);
2149  }
2150  }
2151 
2153  //labelList adaptPatchIDs(meshedPatches());
2154  //forAll(adaptPatchIDs, i)
2155  //{
2156  // label patchi = adaptPatchIDs[i];
2157  //
2158  // if (patchi != -1)
2159  // {
2160  // const polyPatch& pp = mesh_.boundaryMesh()[patchi];
2161  // forAll(pp, i)
2162  // {
2163  // isBoundaryPoint.set(faces[pp.start()+i]);
2164  // }
2165  // }
2166  //}
2167 
2168  // Make sure all processors have the same data
2169  syncTools::syncPointList(mesh_, isBoundaryPoint, orEqOp<unsigned int>(), 0);
2170 
2171  return isBoundaryPoint.sortedToc();
2172 }
2173 
2174 
2175 //- Create patch from set of patches
2177 (
2178  const polyMesh& mesh,
2179  const labelList& patchIDs
2180 )
2181 {
2183 
2184  // Count faces.
2185  label nFaces = 0;
2186 
2187  forAll(patchIDs, i)
2188  {
2189  const polyPatch& pp = patches[patchIDs[i]];
2190 
2191  nFaces += pp.size();
2192  }
2193 
2194  // Collect faces.
2195  labelList addressing(nFaces);
2196  nFaces = 0;
2197 
2198  forAll(patchIDs, i)
2199  {
2200  const polyPatch& pp = patches[patchIDs[i]];
2201 
2202  label meshFacei = pp.start();
2203 
2204  forAll(pp, i)
2205  {
2206  addressing[nFaces++] = meshFacei++;
2207  }
2208  }
2209 
2211  (
2212  IndirectList<face>(mesh.faces(), addressing),
2213  mesh.points()
2214  );
2215 }
2216 
2217 
2219 (
2220  const pointMesh& pMesh,
2221  const labelList& adaptPatchIDs
2222 )
2223 {
2224  const polyMesh& mesh = pMesh();
2225 
2226  // Construct displacement field.
2227  const pointBoundaryMesh& pointPatches = pMesh.boundary();
2228 
2229  wordList patchFieldTypes
2230  (
2231  pointPatches.size(),
2232  slipPointPatchVectorField::typeName
2233  );
2234 
2235  forAll(adaptPatchIDs, i)
2236  {
2237  patchFieldTypes[adaptPatchIDs[i]] =
2238  fixedValuePointPatchVectorField::typeName;
2239  }
2240 
2241  forAll(pointPatches, patchi)
2242  {
2243  if (isA<processorPointPatch>(pointPatches[patchi]))
2244  {
2245  patchFieldTypes[patchi] = calculatedPointPatchVectorField::typeName;
2246  }
2247  else if (isA<cyclicPointPatch>(pointPatches[patchi]))
2248  {
2249  patchFieldTypes[patchi] = cyclicSlipPointPatchVectorField::typeName;
2250  }
2251  }
2252 
2253  // Note: time().timeName() instead of meshRefinement::timeName() since
2254  // postprocessable field.
2256  (
2257  IOobject
2258  (
2259  "pointDisplacement",
2260  mesh.time().timeName(),
2261  mesh,
2264  ),
2265  pMesh,
2267  patchFieldTypes
2268  );
2269 }
2270 
2271 
2274  const faceZoneMesh& fZones = mesh.faceZones();
2275 
2276  // Check any zones are present anywhere and in same order
2277 
2278  {
2279  List<wordList> zoneNames(Pstream::nProcs());
2280  zoneNames[Pstream::myProcNo()] = fZones.names();
2281  Pstream::allGatherList(zoneNames);
2282 
2283  // All have same data now. Check.
2284  forAll(zoneNames, proci)
2285  {
2286  if
2287  (
2288  proci != Pstream::myProcNo()
2289  && (zoneNames[proci] != zoneNames[Pstream::myProcNo()])
2290  )
2291  {
2293  << "faceZones are not synchronised on processors." << nl
2294  << "Processor " << proci << " has faceZones "
2295  << zoneNames[proci] << nl
2296  << "Processor " << Pstream::myProcNo()
2297  << " has faceZones "
2298  << zoneNames[Pstream::myProcNo()] << nl
2299  << exit(FatalError);
2300  }
2301  }
2302  }
2303 
2304  // Check that coupled faces are present on both sides.
2305 
2306  labelList faceToZone(mesh.nBoundaryFaces(), -1);
2307 
2308  forAll(fZones, zonei)
2309  {
2310  const faceZone& fZone = fZones[zonei];
2311 
2312  forAll(fZone, i)
2313  {
2314  label bFacei = fZone[i]-mesh.nInternalFaces();
2315 
2316  if (bFacei >= 0)
2317  {
2318  if (faceToZone[bFacei] == -1)
2319  {
2320  faceToZone[bFacei] = zonei;
2321  }
2322  else if (faceToZone[bFacei] == zonei)
2323  {
2325  << "Face " << fZone[i] << " in zone "
2326  << fZone.name()
2327  << " is twice in zone!"
2328  << abort(FatalError);
2329  }
2330  else
2331  {
2333  << "Face " << fZone[i] << " in zone "
2334  << fZone.name()
2335  << " is also in zone "
2336  << fZones[faceToZone[bFacei]].name()
2337  << abort(FatalError);
2338  }
2339  }
2340  }
2341  }
2342 
2343  labelList neiFaceToZone(faceToZone);
2344  syncTools::swapBoundaryFaceList(mesh, neiFaceToZone);
2345 
2346  forAll(faceToZone, i)
2347  {
2348  if (faceToZone[i] != neiFaceToZone[i])
2349  {
2351  << "Face " << mesh.nInternalFaces()+i
2352  << " is in zone " << faceToZone[i]
2353  << ", its coupled face is in zone " << neiFaceToZone[i]
2354  << abort(FatalError);
2355  }
2356  }
2357 }
2358 
2359 
2361 (
2362  const polyMesh& mesh,
2363  const bitSet& isMasterEdge,
2364  const labelList& meshPoints,
2365  const edgeList& edges,
2366  scalarField& edgeWeights,
2367  scalarField& invSumWeight
2368 )
2369 {
2370  const pointField& pts = mesh.points();
2371 
2372  // Calculate edgeWeights and inverse sum of edge weights
2373  edgeWeights.setSize(isMasterEdge.size());
2374  invSumWeight.setSize(meshPoints.size());
2375 
2376  forAll(edges, edgei)
2377  {
2378  const edge& e = edges[edgei];
2379  scalar eMag = max
2380  (
2381  SMALL,
2382  mag
2383  (
2384  pts[meshPoints[e[1]]]
2385  - pts[meshPoints[e[0]]]
2386  )
2387  );
2388  edgeWeights[edgei] = 1.0/eMag;
2389  }
2390 
2391  // Sum per point all edge weights
2392  weightedSum
2393  (
2394  mesh,
2395  isMasterEdge,
2396  meshPoints,
2397  edges,
2398  edgeWeights,
2399  scalarField(meshPoints.size(), 1.0), // data
2400  invSumWeight
2401  );
2402 
2403  // Inplace invert
2404  forAll(invSumWeight, pointi)
2405  {
2406  scalar w = invSumWeight[pointi];
2407 
2408  if (w > 0.0)
2409  {
2410  invSumWeight[pointi] = 1.0/w;
2411  }
2412  }
2413 }
2414 
2415 
2417 (
2419  const label insertPatchi,
2420  const word& patchName,
2421  const dictionary& patchDict
2422 )
2423 {
2424  // Clear local fields and e.g. polyMesh parallelInfo.
2425  mesh.clearOut();
2426 
2427  polyBoundaryMesh& polyPatches =
2428  const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
2429  fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
2430 
2431  // The new location (at the end)
2432  const label patchi = polyPatches.size();
2433 
2434  // Add polyPatch at the end
2435  polyPatches.push_back
2436  (
2438  (
2439  patchName,
2440  patchDict,
2441  insertPatchi,
2442  polyPatches
2443  )
2444  );
2445 
2446  fvPatches.push_back
2447  (
2448  fvPatch::New
2449  (
2450  polyPatches[patchi], // point to newly added polyPatch
2451  mesh.boundary()
2452  )
2453  );
2454 
2455  addPatchFields<volScalarField>
2456  (
2457  mesh,
2459  );
2460  addPatchFields<volVectorField>
2461  (
2462  mesh,
2464  );
2465  addPatchFields<volSphericalTensorField>
2466  (
2467  mesh,
2469  );
2470  addPatchFields<volSymmTensorField>
2471  (
2472  mesh,
2474  );
2475  addPatchFields<volTensorField>
2476  (
2477  mesh,
2479  );
2480 
2481  // Surface fields
2482 
2483  addPatchFields<surfaceScalarField>
2484  (
2485  mesh,
2487  );
2488  addPatchFields<surfaceVectorField>
2489  (
2490  mesh,
2492  );
2493  addPatchFields<surfaceSphericalTensorField>
2494  (
2495  mesh,
2497  );
2498  addPatchFields<surfaceSymmTensorField>
2499  (
2500  mesh,
2502  );
2503  addPatchFields<surfaceTensorField>
2504  (
2505  mesh,
2507  );
2508  return patchi;
2509 }
2510 
2511 
2513 (
2515  const word& patchName,
2516  const dictionary& patchInfo
2517 )
2518 {
2519  polyBoundaryMesh& polyPatches =
2520  const_cast<polyBoundaryMesh&>(mesh.boundaryMesh());
2521  fvBoundaryMesh& fvPatches = const_cast<fvBoundaryMesh&>(mesh.boundary());
2522 
2523  const label patchi = polyPatches.findPatchID(patchName);
2524  if (patchi != -1)
2525  {
2526  // Already there
2527  return patchi;
2528  }
2529 
2530 
2531  label insertPatchi = polyPatches.size();
2532  label startFacei = mesh.nFaces();
2533 
2534  forAll(polyPatches, patchi)
2535  {
2536  const polyPatch& pp = polyPatches[patchi];
2537 
2538  if (isA<processorPolyPatch>(pp))
2539  {
2540  insertPatchi = patchi;
2541  startFacei = pp.start();
2542  break;
2543  }
2544  }
2545 
2546  dictionary patchDict(patchInfo);
2547  patchDict.set("nFaces", 0);
2548  patchDict.set("startFace", startFacei);
2549 
2550  // Below is all quite a hack. Feel free to change once there is a better
2551  // mechanism to insert and reorder patches.
2552 
2553  label addedPatchi = appendPatch(mesh, insertPatchi, patchName, patchDict);
2554 
2555 
2556  // Create reordering list
2557  // patches before insert position stay as is
2558  labelList oldToNew(addedPatchi+1);
2559  for (label i = 0; i < insertPatchi; i++)
2560  {
2561  oldToNew[i] = i;
2562  }
2563  // patches after insert position move one up
2564  for (label i = insertPatchi; i < addedPatchi; i++)
2565  {
2566  oldToNew[i] = i+1;
2567  }
2568  // appended patch gets moved to insert position
2569  oldToNew[addedPatchi] = insertPatchi;
2570 
2571  // Shuffle into place
2572  polyPatches.reorder(oldToNew, true);
2573  fvPatches.reorder(oldToNew);
2574 
2575  reorderPatchFields<volScalarField>(mesh, oldToNew);
2576  reorderPatchFields<volVectorField>(mesh, oldToNew);
2577  reorderPatchFields<volSphericalTensorField>(mesh, oldToNew);
2578  reorderPatchFields<volSymmTensorField>(mesh, oldToNew);
2579  reorderPatchFields<volTensorField>(mesh, oldToNew);
2580  reorderPatchFields<surfaceScalarField>(mesh, oldToNew);
2581  reorderPatchFields<surfaceVectorField>(mesh, oldToNew);
2582  reorderPatchFields<surfaceSphericalTensorField>(mesh, oldToNew);
2583  reorderPatchFields<surfaceSymmTensorField>(mesh, oldToNew);
2584  reorderPatchFields<surfaceTensorField>(mesh, oldToNew);
2585 
2586  return insertPatchi;
2587 }
2588 
2589 
2591 (
2592  const word& name,
2593  const dictionary& patchInfo
2594 )
2595 {
2596  label meshedi = meshedPatches_.find(name);
2597 
2598  if (meshedi != -1)
2599  {
2600  // Already there. Get corresponding polypatch
2601  return mesh_.boundaryMesh().findPatchID(name);
2602  }
2603  else
2604  {
2605  // Add patch
2606  label patchi = addPatch(mesh_, name, patchInfo);
2607 
2608 // dictionary patchDict(patchInfo);
2609 // patchDict.set("nFaces", 0);
2610 // patchDict.set("startFace", 0);
2611 // autoPtr<polyPatch> ppPtr
2612 // (
2613 // polyPatch::New
2614 // (
2615 // name,
2616 // patchDict,
2617 // 0,
2618 // mesh_.boundaryMesh()
2619 // )
2620 // );
2621 // label patchi = fvMeshTools::addPatch
2622 // (
2623 // mesh_,
2624 // ppPtr(),
2625 // dictionary(), // optional field values
2626 // fvPatchFieldBase::calculatedType(),
2627 // true
2628 // );
2629 
2630  // Store
2631  meshedPatches_.append(name);
2632 
2633  // Clear patch based addressing
2634  faceToCoupledPatch_.clear();
2635 
2636  return patchi;
2637  }
2638 }
2639 
2640 
2643  const polyBoundaryMesh& patches = mesh_.boundaryMesh();
2644 
2645  DynamicList<label> patchIDs(meshedPatches_.size());
2646  forAll(meshedPatches_, i)
2647  {
2648  label patchi = patches.findPatchID(meshedPatches_[i]);
2649 
2650  if (patchi == -1)
2651  {
2653  << "Problem : did not find patch " << meshedPatches_[i]
2654  << endl << "Valid patches are " << patches.names()
2655  << endl; //abort(FatalError);
2656  }
2657  else if (!polyPatch::constraintType(patches[patchi].type()))
2658  {
2659  patchIDs.append(patchi);
2660  }
2661  }
2662 
2663  return patchIDs;
2664 }
2665 
2666 
2668 (
2669  const word& fzName,
2670  const word& masterPatch,
2671  const word& slavePatch,
2672  const surfaceZonesInfo::faceZoneType& fzType
2673 )
2674 {
2675  label zonei = surfaceZonesInfo::addFaceZone
2676  (
2677  fzName, //name
2678  labelList(0), //addressing
2679  boolList(0), //flipmap
2680  mesh_
2681  );
2682 
2683  faceZoneToMasterPatch_.insert(fzName, masterPatch);
2684  faceZoneToSlavePatch_.insert(fzName, slavePatch);
2685  faceZoneToType_.insert(fzName, fzType);
2686 
2687  return zonei;
2688 }
2689 
2690 
2692 (
2693  const word& fzName,
2694  label& masterPatchID,
2695  label& slavePatchID,
2697 ) const
2698 {
2699  const polyBoundaryMesh& pbm = mesh_.boundaryMesh();
2700 
2701  if (!faceZoneToMasterPatch_.found(fzName))
2702  {
2703  return false;
2704  }
2705  else
2706  {
2707  const word& masterName = faceZoneToMasterPatch_[fzName];
2708  masterPatchID = pbm.findPatchID(masterName);
2709 
2710  const word& slaveName = faceZoneToSlavePatch_[fzName];
2711  slavePatchID = pbm.findPatchID(slaveName);
2712 
2713  fzType = faceZoneToType_[fzName];
2714 
2715  return true;
2716  }
2717 }
2718 
2719 
2720 Foam::label Foam::meshRefinement::addPointZone(const word& name)
2722  pointZoneMesh& pointZones = mesh_.pointZones();
2723 
2724  label zoneI = pointZones.findZoneID(name);
2725 
2726  if (zoneI == -1)
2727  {
2728  zoneI = pointZones.size();
2729  pointZones.clearAddressing();
2730 
2731  pointZones.emplace_back
2732  (
2733  name, // name
2734  zoneI, // index
2735  pointZones // pointZoneMesh
2736  );
2737  }
2738  return zoneI;
2739 }
2740 
2741 
2744  for (const polyPatch& pp : mesh_.boundaryMesh())
2745  {
2746  // Check all coupled. Avoid using .coupled() so we also pick up AMI.
2747  const auto* cpp = isA<coupledPolyPatch>(pp);
2748 
2749  if (cpp && (cpp->separated() || !cpp->parallel()))
2750  {
2751  SubList<bool>(selected, pp.size(), pp.start()) = true;
2752  }
2753  }
2754 }
2755 
2756 
2758 (
2760 ) const
2761 {
2762  // Count number of faces per edge. Parallel consistent.
2763 
2764  const labelListList& edgeFaces = pp.edgeFaces();
2765  labelList nEdgeFaces(edgeFaces.size());
2766  forAll(edgeFaces, edgei)
2767  {
2768  nEdgeFaces[edgei] = edgeFaces[edgei].size();
2769  }
2770 
2771  // Sync across processor patches
2772  if (Pstream::parRun())
2773  {
2774  const globalMeshData& globalData = mesh_.globalData();
2775  const mapDistribute& map = globalData.globalEdgeSlavesMap();
2776  const indirectPrimitivePatch& cpp = globalData.coupledPatch();
2777 
2778  // Match pp edges to coupled edges
2779  labelList patchEdges;
2780  labelList coupledEdges;
2781  PackedBoolList sameEdgeOrientation;
2783  (
2784  pp,
2785  cpp,
2786  patchEdges,
2787  coupledEdges,
2788  sameEdgeOrientation
2789  );
2790 
2791  // Convert patch-edge data into cpp-edge data
2792  labelList coupledNEdgeFaces(map.constructSize(), Zero);
2793  UIndirectList<label>(coupledNEdgeFaces, coupledEdges) =
2794  UIndirectList<label>(nEdgeFaces, patchEdges);
2795 
2796  // Synchronise
2797  globalData.syncData
2798  (
2799  coupledNEdgeFaces,
2800  globalData.globalEdgeSlaves(),
2801  globalData.globalEdgeTransformedSlaves(),
2802  map,
2803  plusEqOp<label>()
2804  );
2805 
2806  // Convert back from cpp-edge to patch-edge
2807  UIndirectList<label>(nEdgeFaces, patchEdges) =
2808  UIndirectList<label>(coupledNEdgeFaces, coupledEdges);
2809  }
2810  return nEdgeFaces;
2811 }
2812 
2813 
2815 (
2816  const polyMesh& mesh,
2817  const vector& perturbVec,
2818  const point& p
2819 )
2820 {
2821  // Force calculation of base points (needs to be synchronised)
2822  (void)mesh.tetBasePtIs();
2823 
2824  label celli = mesh.findCell(p, findCellMode);
2825 
2826  if (returnReduceAnd(celli < 0))
2827  {
2828  // See if we can perturb a bit
2829  celli = mesh.findCell(p+perturbVec, findCellMode);
2830  }
2831  return celli;
2832 }
2833 
2834 
2836 (
2837  const polyMesh& mesh,
2838  const labelList& cellToRegion,
2839  const vector& perturbVec,
2840  const point& p
2841 )
2842 {
2843  label regioni = -1;
2844 
2845  // Force calculation of base points (needs to be synchronised)
2846  (void)mesh.tetBasePtIs();
2847 
2848  label celli = mesh.findCell(p, findCellMode);
2849  if (celli != -1)
2850  {
2851  regioni = cellToRegion[celli];
2852  }
2853  reduce(regioni, maxOp<label>());
2854 
2855  if (regioni == -1)
2856  {
2857  // See if we can perturb a bit
2858  celli = mesh.findCell(p+perturbVec, findCellMode);
2859  if (celli != -1)
2860  {
2861  regioni = cellToRegion[celli];
2862  }
2863  reduce(regioni, maxOp<label>());
2864  }
2865  return regioni;
2866 }
2867 
2868 
2869 Foam::fileName Foam::meshRefinement::writeLeakPath
2870 (
2871  const polyMesh& mesh,
2872  const pointField& locationsInMesh,
2873  const pointField& locationsOutsideMesh,
2874  const boolList& blockedFace,
2876 )
2877 {
2879 
2880  fileName outputDir
2881  (
2882  mesh.time().globalPath()
2884  / mesh.pointsInstance()
2885  );
2886  outputDir.clean(); // Remove unneeded ".."
2887 
2888  // Write the leak path
2889 
2890  meshSearch searchEngine(mesh);
2891  shortestPathSet leakPath
2892  (
2893  "leakPath",
2894  mesh,
2895  searchEngine,
2897  false, //true,
2898  50, // tbd. Number of iterations
2899  pbm.groupPatchIDs()["wall"],
2900  locationsInMesh,
2901  locationsOutsideMesh,
2902  blockedFace
2903  );
2904 
2905  // Split leak path according to segment. Note: segment index
2906  // is global (= index in locationsInsideMesh)
2907  List<pointList> segmentPoints;
2908  List<scalarList> segmentDist;
2909  {
2910  label nSegments = 0;
2911  if (leakPath.segments().size())
2912  {
2913  nSegments = max(leakPath.segments())+1;
2914  }
2915  reduce(nSegments, maxOp<label>());
2916 
2917  labelList nElemsPerSegment(nSegments, Zero);
2918  for (label segmenti : leakPath.segments())
2919  {
2920  nElemsPerSegment[segmenti]++;
2921  }
2922  segmentPoints.setSize(nElemsPerSegment.size());
2923  segmentDist.setSize(nElemsPerSegment.size());
2924  forAll(nElemsPerSegment, i)
2925  {
2926  segmentPoints[i].setSize(nElemsPerSegment[i]);
2927  segmentDist[i].setSize(nElemsPerSegment[i]);
2928  }
2929  nElemsPerSegment = 0;
2930 
2931  forAll(leakPath, elemi)
2932  {
2933  label segmenti = leakPath.segments()[elemi];
2934  pointList& points = segmentPoints[segmenti];
2935  scalarList& dist = segmentDist[segmenti];
2936  label& n = nElemsPerSegment[segmenti];
2937 
2938  points[n] = leakPath[elemi];
2939  dist[n] = leakPath.distance()[elemi];
2940  n++;
2941  }
2942  }
2943 
2944  PtrList<coordSet> allLeakPaths(segmentPoints.size());
2945  forAll(allLeakPaths, segmenti)
2946  {
2947  // Collect data from all processors
2948  List<pointList> gatheredPts(Pstream::nProcs());
2949  gatheredPts[Pstream::myProcNo()] = std::move(segmentPoints[segmenti]);
2950  Pstream::gatherList(gatheredPts);
2951 
2952  List<scalarList> gatheredDist(Pstream::nProcs());
2953  gatheredDist[Pstream::myProcNo()] = std::move(segmentDist[segmenti]);
2954  Pstream::gatherList(gatheredDist);
2955 
2956  // Combine processor lists into one big list.
2957  pointList allPts
2958  (
2959  ListListOps::combine<pointList>
2960  (
2961  gatheredPts, accessOp<pointList>()
2962  )
2963  );
2964  scalarList allDist
2965  (
2966  ListListOps::combine<scalarList>
2967  (
2968  gatheredDist, accessOp<scalarList>()
2969  )
2970  );
2971 
2972  // Sort according to distance
2973  labelList indexSet(Foam::sortedOrder(allDist));
2974 
2975  allLeakPaths.set
2976  (
2977  segmenti,
2978  new coordSet
2979  (
2980  leakPath.name(),
2981  leakPath.axis(),
2982  pointList(allPts, indexSet),
2983  //scalarList(allDist, indexSet)
2984  scalarList(allPts.size(), scalar(segmenti))
2985  )
2986  );
2987  }
2988 
2989  fileName fName;
2990  if (Pstream::master())
2991  {
2992  List<scalarField> allLeakData(allLeakPaths.size());
2993  forAll(allLeakPaths, segmenti)
2994  {
2995  allLeakData[segmenti] = allLeakPaths[segmenti].distance();
2996  }
2997 
2998  writer.nFields(1);
2999 
3000  writer.open
3001  (
3002  allLeakPaths,
3003  (outputDir / allLeakPaths[0].name())
3004  );
3005 
3006  fName = writer.write("leakPath", allLeakData);
3007 
3008  // Force writing to finish before FatalError exit
3009  writer.close(true);
3010  }
3011 
3012  // Probably do not need to broadcast name (only written on master anyhow)
3013  Pstream::broadcast(fName);
3014 
3015  return fName;
3016 }
3017 
3018 
3019 // Modify cellRegion to be consistent with locationsInMesh.
3020 // - all regions not in locationsInMesh are set to -1
3021 // - check that all regions inside locationsOutsideMesh are set to -1
3023 (
3024  const polyMesh& mesh,
3025  const vector& perturbVec,
3026  const pointField& locationsInMesh,
3027  const pointField& locationsOutsideMesh,
3028  const label nRegions,
3029  labelList& cellRegion,
3030  const boolList& blockedFace,
3031  // Leak-path
3032  const bool exitIfLeakPath,
3033  const refPtr<coordSetWriter>& leakPathFormatter
3034 )
3035 {
3036  bitSet insideCell(mesh.nCells());
3037 
3038  // Mark all cells reachable from locationsInMesh
3039  labelList insideRegions(locationsInMesh.size());
3040  forAll(insideRegions, i)
3041  {
3042  // Find the region containing the point
3043  label regioni = findRegion
3044  (
3045  mesh,
3046  cellRegion,
3047  perturbVec,
3048  locationsInMesh[i]
3049  );
3050 
3051  insideRegions[i] = regioni;
3052 
3053  // Mark all cells in the region as being inside
3054  forAll(cellRegion, celli)
3055  {
3056  if (cellRegion[celli] == regioni)
3057  {
3058  insideCell.set(celli);
3059  }
3060  }
3061  }
3062 
3063 
3064 
3065  // Check that all the locations outside the
3066  // mesh do not conflict with those inside
3067  forAll(locationsOutsideMesh, i)
3068  {
3069  // Find the region containing the point,
3070  // and the corresponding inside region index
3071 
3072  label indexi;
3073  label regioni = findRegion
3074  (
3075  mesh,
3076  cellRegion,
3077  perturbVec,
3078  locationsOutsideMesh[i]
3079  );
3080 
3081  if (regioni == -1 && (indexi = insideRegions.find(regioni)) != -1)
3082  {
3083  if (leakPathFormatter)
3084  {
3085  const fileName fName
3086  (
3087  writeLeakPath
3088  (
3089  mesh,
3090  locationsInMesh,
3091  locationsOutsideMesh,
3092  blockedFace,
3093  leakPathFormatter.constCast()
3094  )
3095  );
3096  Info<< "Dumped leak path to " << fName << endl;
3097  }
3098 
3099  auto& err =
3100  (
3101  exitIfLeakPath
3104  );
3105 
3106  err << "Location in mesh " << locationsInMesh[indexi]
3107  << " is inside same mesh region " << regioni
3108  << " as one of the locations outside mesh "
3109  << locationsOutsideMesh << endl;
3110 
3111  if (exitIfLeakPath)
3112  {
3114  }
3115  }
3116  }
3117 
3118 
3119  label nRemove = 0;
3120 
3121  // Now update cellRegion to -1 for unreachable cells
3122  forAll(insideCell, celli)
3123  {
3124  if (!insideCell.test(celli))
3125  {
3126  cellRegion[celli] = -1;
3127  ++nRemove;
3128  }
3129  else if (cellRegion[celli] == -1)
3130  {
3131  ++nRemove;
3132  }
3133  }
3134 
3135  return nRemove;
3136 }
3137 
3138 
3140 (
3141  const labelList& globalToMasterPatch,
3142  const labelList& globalToSlavePatch,
3143  const pointField& locationsInMesh,
3144  const pointField& locationsOutsideMesh,
3145  const bool exitIfLeakPath,
3146  const refPtr<coordSetWriter>& leakPathFormatter
3147 )
3148 {
3149  // Force calculation of face decomposition (used in findCell)
3150  (void)mesh_.tetBasePtIs();
3151 
3152  // Determine connected regions. regionSplit is the labelList with the
3153  // region per cell.
3154 
3155  boolList blockedFace(mesh_.nFaces(), false);
3156  selectSeparatedCoupledFaces(blockedFace);
3157 
3158  regionSplit cellRegion(mesh_, blockedFace);
3159 
3160  label nRemove = findRegions
3161  (
3162  mesh_,
3163  vector::uniform(mergeDistance_), // perturbVec
3164  locationsInMesh,
3165  locationsOutsideMesh,
3166  cellRegion.nRegions(),
3167  cellRegion,
3168  blockedFace,
3169  // Leak-path
3170  exitIfLeakPath,
3171  leakPathFormatter
3172  );
3173 
3174  // Subset
3175  // ~~~~~~
3176 
3177  // Get cells to remove
3178  DynamicList<label> cellsToRemove(nRemove);
3179  forAll(cellRegion, celli)
3180  {
3181  if (cellRegion[celli] == -1)
3182  {
3183  cellsToRemove.append(celli);
3184  }
3185  }
3186  cellsToRemove.shrink();
3187 
3188  label nTotCellsToRemove = returnReduce
3189  (
3190  cellsToRemove.size(),
3191  sumOp<label>()
3192  );
3193 
3194 
3195  autoPtr<mapPolyMesh> mapPtr;
3196  if (nTotCellsToRemove > 0)
3197  {
3198  label nCellsToKeep =
3199  mesh_.globalData().nTotalCells()
3200  - nTotCellsToRemove;
3201 
3202  Info<< "Keeping all cells containing points " << locationsInMesh << endl
3203  << "Selected for keeping : "
3204  << nCellsToKeep
3205  << " cells." << endl;
3206 
3207 
3208  // Remove cells
3209  removeCells cellRemover(mesh_);
3210 
3211  labelList exposedFaces(cellRemover.getExposedFaces(cellsToRemove));
3212  labelList exposedPatch;
3213 
3214  label nExposedFaces = returnReduce(exposedFaces.size(), sumOp<label>());
3215  if (nExposedFaces)
3216  {
3217  // FatalErrorInFunction
3218  // << "Removing non-reachable cells should only expose"
3219  // << " boundary faces" << nl
3220  // << "ExposedFaces:" << exposedFaces << abort(FatalError);
3221 
3222  // Patch for exposed faces for lack of anything sensible.
3223  label defaultPatch = 0;
3224  if (globalToMasterPatch.size())
3225  {
3226  defaultPatch = globalToMasterPatch[0];
3227  }
3228 
3230  << "Removing non-reachable cells exposes "
3231  << nExposedFaces << " internal or coupled faces." << endl
3232  << " These get put into patch " << defaultPatch << endl;
3233  exposedPatch.setSize(exposedFaces.size(), defaultPatch);
3234  }
3235 
3236  mapPtr = doRemoveCells
3237  (
3238  cellsToRemove,
3239  exposedFaces,
3240  exposedPatch,
3241  cellRemover
3242  );
3243  }
3244  return mapPtr;
3245 }
3246 
3247 
3250  // mesh_ already distributed; distribute my member data
3251 
3252  // surfaceQueries_ ok.
3253 
3254  // refinement
3255  meshCutter_.distribute(map);
3256 
3257  // surfaceIndex is face data.
3258  map.distributeFaceData(surfaceIndex_);
3259 
3260  // faceToPatch (baffles that were on coupled faces) is not maintained
3261  // (since baffling also disconnects points)
3262  faceToCoupledPatch_.clear();
3263 
3264  // maintainedFaces are indices of faces.
3265  forAll(userFaceData_, i)
3266  {
3267  map.distributeFaceData(userFaceData_[i].second());
3268  }
3269 
3270  // Redistribute surface and any fields on it.
3271  {
3272  Random rndGen(653213);
3273 
3274  // Get local mesh bounding box. Single box for now.
3276  (
3277  1,
3278  treeBoundBox(mesh_.points()).extend(rndGen, 1e-4)
3279  );
3280 
3281  // Distribute all geometry (so refinementSurfaces and shellSurfaces)
3282  searchableSurfaces& geometry =
3283  const_cast<searchableSurfaces&>(surfaces_.geometry());
3284 
3285  forAll(geometry, i)
3286  {
3288  autoPtr<mapDistribute> pointMap;
3289  geometry[i].distribute
3290  (
3291  meshBb,
3292  false, // do not keep outside triangles
3293  faceMap,
3294  pointMap
3295  );
3296 
3297  if (faceMap)
3298  {
3299  // (ab)use the instance() to signal current modification time
3300  geometry[i].instance() = geometry[i].time().timeName();
3301  }
3302 
3303  faceMap.clear();
3304  pointMap.clear();
3305  }
3306  }
3307 }
3308 
3309 
3311 (
3312  const mapPolyMesh& map,
3313  const labelList& changedFaces
3314 )
3315 {
3316  Map<label> dummyMap(0);
3317 
3318  updateMesh(map, changedFaces, dummyMap, dummyMap, dummyMap);
3319 }
3320 
3321 
3323 (
3324  const labelList& pointsToStore,
3325  const labelList& facesToStore,
3326  const labelList& cellsToStore
3327 )
3328 {
3329  // For now only meshCutter has storable/retrievable data.
3330  meshCutter_.storeData
3331  (
3332  pointsToStore,
3333  facesToStore,
3334  cellsToStore
3335  );
3336 }
3337 
3338 
3340 (
3341  const mapPolyMesh& map,
3342  const labelList& changedFaces,
3343  const Map<label>& pointsToRestore,
3344  const Map<label>& facesToRestore,
3345  const Map<label>& cellsToRestore
3346 )
3347 {
3348  // For now only meshCutter has storable/retrievable data.
3349 
3350  // Update numbering of cells/vertices.
3351  meshCutter_.updateMesh
3352  (
3353  map,
3354  pointsToRestore,
3355  facesToRestore,
3356  cellsToRestore
3357  );
3358 
3359  // Update surfaceIndex
3360  updateList(map.faceMap(), label(-1), surfaceIndex_);
3361 
3362  // Update faceToCoupledPatch_
3363  {
3364  Map<label> newFaceToPatch(faceToCoupledPatch_.size());
3365  forAllConstIters(faceToCoupledPatch_, iter)
3366  {
3367  const label newFacei = map.reverseFaceMap()[iter.key()];
3368 
3369  if (newFacei >= 0)
3370  {
3371  newFaceToPatch.insert(newFacei, iter.val());
3372  }
3373  }
3374  faceToCoupledPatch_.transfer(newFaceToPatch);
3375  }
3376 
3377 
3378  // Update cached intersection information
3379  updateIntersections(changedFaces);
3380 
3381  // Update maintained faces
3382  forAll(userFaceData_, i)
3383  {
3384  labelList& data = userFaceData_[i].second();
3385 
3386  if (userFaceData_[i].first() == KEEPALL)
3387  {
3388  // extend list with face-from-face data
3389  updateList(map.faceMap(), label(-1), data);
3390  }
3391  else if (userFaceData_[i].first() == MASTERONLY)
3392  {
3393  // keep master only
3394  labelList newFaceData(map.faceMap().size(), -1);
3395 
3396  forAll(newFaceData, facei)
3397  {
3398  label oldFacei = map.faceMap()[facei];
3399 
3400  if (oldFacei >= 0 && map.reverseFaceMap()[oldFacei] == facei)
3401  {
3402  newFaceData[facei] = data[oldFacei];
3403  }
3404  }
3405  data.transfer(newFaceData);
3406  }
3407  else
3408  {
3409  // remove any face that has been refined i.e. referenced more than
3410  // once.
3411 
3412  // 1. Determine all old faces that get referenced more than once.
3413  // These get marked with -1 in reverseFaceMap
3414  labelList reverseFaceMap(map.reverseFaceMap());
3415 
3416  forAll(map.faceMap(), facei)
3417  {
3418  label oldFacei = map.faceMap()[facei];
3419 
3420  if (oldFacei >= 0)
3421  {
3422  if (reverseFaceMap[oldFacei] != facei)
3423  {
3424  // facei is slave face. Mark old face.
3425  reverseFaceMap[oldFacei] = -1;
3426  }
3427  }
3428  }
3429 
3430  // 2. Map only faces with intact reverseFaceMap
3431  labelList newFaceData(map.faceMap().size(), -1);
3432  forAll(newFaceData, facei)
3433  {
3434  label oldFacei = map.faceMap()[facei];
3435 
3436  if (oldFacei >= 0)
3437  {
3438  if (reverseFaceMap[oldFacei] == facei)
3439  {
3440  newFaceData[facei] = data[oldFacei];
3441  }
3442  }
3443  }
3444  data.transfer(newFaceData);
3445  }
3446  }
3447 }
3448 
3449 
3450 bool Foam::meshRefinement::write() const
3452  bool writeOk = mesh_.write();
3453 
3454  // Make sure that any distributed surfaces (so ones which probably have
3455  // been changed) get written as well.
3456  // Note: should ideally have some 'modified' flag to say whether it
3457  // has been changed or not.
3458  searchableSurfaces& geometry =
3459  const_cast<searchableSurfaces&>(surfaces_.geometry());
3460 
3461  forAll(geometry, i)
3462  {
3463  searchableSurface& s = geometry[i];
3464 
3465  // Check if instance() of surface is not constant or system.
3466  // Is good hint that surface is distributed.
3467  if
3468  (
3469  s.instance() != s.time().system()
3470  && s.instance() != s.time().caseSystem()
3471  && s.instance() != s.time().constant()
3472  && s.instance() != s.time().caseConstant()
3473  )
3474  {
3475  // Make sure it gets written to current time, not constant.
3476  s.instance() = s.time().timeName();
3477  writeOk = writeOk && s.write();
3478  }
3479  }
3480 
3481  return writeOk;
3482 }
3483 
3484 
3486 (
3487  const polyMesh& mesh,
3488  const labelList& meshPoints
3489 )
3490 {
3491  const label myProci = UPstream::myProcNo();
3492  const globalIndex globalPoints(meshPoints.size());
3493 
3494  labelList myPoints
3495  (
3496  Foam::identity(globalPoints.range(myProci))
3497  );
3498 
3500  (
3501  mesh,
3502  meshPoints,
3503  myPoints,
3504  minEqOp<label>(),
3505  labelMax
3506  );
3507 
3508 
3509  bitSet isPatchMasterPoint(meshPoints.size());
3510  forAll(meshPoints, pointi)
3511  {
3512  if (myPoints[pointi] == globalPoints.toGlobal(myProci, pointi))
3513  {
3514  isPatchMasterPoint.set(pointi);
3515  }
3516  }
3517 
3518  return isPatchMasterPoint;
3519 }
3520 
3521 
3523 (
3524  const polyMesh& mesh,
3525  const labelList& meshEdges
3526 )
3527 {
3528  const label myProci = UPstream::myProcNo();
3529  const globalIndex globalEdges(meshEdges.size());
3530 
3531  labelList myEdges
3532  (
3533  Foam::identity(globalEdges.range(myProci))
3534  );
3535 
3537  (
3538  mesh,
3539  meshEdges,
3540  myEdges,
3541  minEqOp<label>(),
3542  labelMax
3543  );
3544 
3545 
3546  bitSet isMasterEdge(meshEdges.size());
3547  forAll(meshEdges, edgei)
3548  {
3549  if (myEdges[edgei] == globalEdges.toGlobal(myProci, edgei))
3550  {
3551  isMasterEdge.set(edgei);
3552  }
3553  }
3554 
3555  return isMasterEdge;
3556 }
3557 
3558 
3560 (
3561  const bool debug,
3562  const string& msg,
3563  const bool printCellLevel
3564 )
3565 const
3566 {
3567  const globalMeshData& pData = mesh_.globalData();
3568 
3569  if (debug)
3570  {
3571  Pout<< msg.c_str()
3572  << " : cells(local):" << mesh_.nCells()
3573  << " faces(local):" << mesh_.nFaces()
3574  << " points(local):" << mesh_.nPoints()
3575  << endl;
3576  }
3577 
3578  {
3579  bitSet isMasterFace(syncTools::getMasterFaces(mesh_));
3580  label nMasterFaces = isMasterFace.count();
3581 
3582  bitSet isMeshMasterPoint(syncTools::getMasterPoints(mesh_));
3583  label nMasterPoints = isMeshMasterPoint.count();
3584 
3585  Info<< msg.c_str()
3586  << " : cells:" << pData.nTotalCells()
3587  << " faces:" << returnReduce(nMasterFaces, sumOp<label>())
3588  << " points:" << returnReduce(nMasterPoints, sumOp<label>());
3589 
3590  if (UPstream::parRun())
3591  {
3592  const scalar nIdealCells =
3593  scalar(pData.nTotalCells())/Pstream::nProcs();
3594  const scalar unbalance = returnReduce
3595  (
3596  mag(1.0-mesh_.nCells()/nIdealCells),
3597  maxOp<scalar>()
3598  );
3599  Info<< " unbalance:" << unbalance;
3600  }
3601  Info<< endl;
3602  }
3603 
3604  if (printCellLevel)
3605  {
3606  const labelList& cellLevel = meshCutter_.cellLevel();
3607 
3608  labelList nCells(gMax(cellLevel)+1, Zero);
3609 
3610  forAll(cellLevel, celli)
3611  {
3612  nCells[cellLevel[celli]]++;
3613  }
3614 
3616 
3618  if (Pstream::master())
3619  {
3620  Info<< "Cells per refinement level:" << endl;
3621  forAll(nCells, leveli)
3622  {
3623  Info<< " " << leveli << '\t' << nCells[leveli]
3624  << endl;
3625  }
3626  }
3627  }
3628 }
3629 
3630 
3633  if (overwrite_ && mesh_.time().timeIndex() == 0)
3634  {
3635  return oldInstance_;
3636  }
3637 
3638  return mesh_.time().timeName();
3639 }
3640 
3641 
3644  // Note: use time().timeName(), not meshRefinement::timeName()
3645  // so as to dump the fields to 0, not to constant.
3646  {
3647  volScalarField volRefLevel
3648  (
3649  IOobject
3650  (
3651  "cellLevel",
3652  mesh_.time().timeName(),
3653  mesh_,
3657  ),
3658  mesh_,
3661  );
3662 
3663  const labelList& cellLevel = meshCutter_.cellLevel();
3664 
3665  forAll(volRefLevel, celli)
3666  {
3667  volRefLevel[celli] = cellLevel[celli];
3668  }
3669 
3670  volRefLevel.write();
3671  }
3672 
3673  // Dump pointLevel
3674  {
3675  const pointMesh& pMesh = pointMesh::New(mesh_);
3676 
3677  pointScalarField pointRefLevel
3678  (
3679  IOobject
3680  (
3681  "pointLevel",
3682  mesh_.time().timeName(),
3683  mesh_,
3687  ),
3688  pMesh,
3690  );
3691 
3692  const labelList& pointLevel = meshCutter_.pointLevel();
3693 
3694  forAll(pointRefLevel, pointi)
3695  {
3696  pointRefLevel[pointi] = pointLevel[pointi];
3697  }
3698 
3699  pointRefLevel.write();
3700  }
3701 }
3702 
3703 
3704 void Foam::meshRefinement::dumpIntersections(const fileName& prefix) const
3706  {
3707  OFstream str(prefix + "_edges.obj");
3708  label verti = 0;
3709  Pout<< "meshRefinement::dumpIntersections :"
3710  << " Writing cellcentre-cellcentre intersections to file "
3711  << str.name() << endl;
3712 
3713 
3714  // Redo all intersections
3715  // ~~~~~~~~~~~~~~~~~~~~~~
3716 
3717  // Get boundary face centre and level. Coupled aware.
3718  labelList neiLevel(mesh_.nBoundaryFaces());
3719  pointField neiCc(mesh_.nBoundaryFaces());
3720  calcNeighbourData(neiLevel, neiCc);
3721 
3722  labelList intersectionFaces(intersectedFaces());
3723 
3724  // Collect segments we want to test for
3725  pointField start(intersectionFaces.size());
3726  pointField end(intersectionFaces.size());
3727  {
3728  labelList minLevel;
3729  calcCellCellRays
3730  (
3731  neiCc,
3732  labelList(neiCc.size(), -1),
3733  intersectionFaces,
3734  start,
3735  end,
3736  minLevel
3737  );
3738  }
3739 
3740 
3741  // Do tests in one go
3742  labelList surfaceHit;
3743  List<pointIndexHit> surfaceHitInfo;
3744  surfaces_.findAnyIntersection
3745  (
3746  start,
3747  end,
3748  surfaceHit,
3749  surfaceHitInfo
3750  );
3751 
3752  forAll(intersectionFaces, i)
3753  {
3754  if (surfaceHit[i] != -1)
3755  {
3756  meshTools::writeOBJ(str, start[i]);
3757  verti++;
3758  meshTools::writeOBJ(str, surfaceHitInfo[i].point());
3759  verti++;
3760  meshTools::writeOBJ(str, end[i]);
3761  verti++;
3762  str << "l " << verti-2 << ' ' << verti-1 << nl
3763  << "l " << verti-1 << ' ' << verti << nl;
3764  }
3765  }
3766  }
3767 
3768  Pout<< endl;
3769 }
3770 
3771 
3773 (
3774  const debugType debugFlags,
3775  const writeType writeFlags,
3776  const fileName& prefix
3777 ) const
3778 {
3779  if (writeFlags & WRITEMESH)
3780  {
3781  write();
3782  }
3783 
3784  if (writeFlags && !(writeFlags & NOWRITEREFINEMENT))
3785  {
3786  meshCutter_.write();
3787 
3788  // Force calculation before writing
3789  (void)surfaceIndex();
3790  surfaceIndex_.write();
3791  }
3792 
3793  if (writeFlags & WRITELEVELS)
3794  {
3795  dumpRefinementLevel();
3796  }
3797 
3798  if ((debugFlags & OBJINTERSECTIONS) && prefix.size())
3799  {
3800  dumpIntersections(prefix);
3801  }
3802 }
3803 
3804 
3807  IOobject io
3808  (
3809  "dummy",
3810  mesh.facesInstance(),
3812  mesh
3813  );
3814  fileName setsDir(io.path());
3815 
3816  if (topoSet::debug) DebugVar(setsDir);
3817 
3818  // Remove local files
3819  if (exists(setsDir/"surfaceIndex"))
3820  {
3821  rm(setsDir/"surfaceIndex");
3822  }
3823 
3824  // Remove other files
3826 }
3827 
3828 
3831  return writeLevel_;
3832 }
3833 
3834 
3835 void Foam::meshRefinement::writeLevel(const writeType flags)
3837  writeLevel_ = flags;
3838 }
3839 
3840 
3841 //Foam::meshRefinement::outputType Foam::meshRefinement::outputLevel()
3842 //{
3843 // return outputLevel_;
3844 //}
3845 //
3846 //
3847 //void Foam::meshRefinement::outputLevel(const outputType flags)
3848 //{
3849 // outputLevel_ = flags;
3850 //}
3851 
3852 
3854 (
3856  const word& keyword,
3857  const bool noExit,
3858  enum keyType::option matchOpt
3859 )
3860 {
3861  const dictionary* dictptr = dict.findDict(keyword, matchOpt);
3862 
3863  if (!dictptr)
3864  {
3866  << "Entry '" << keyword
3867  << "' not found (or not a dictionary) in dictionary "
3868  << dict.relativeName() << nl;
3869 
3870  if (noExit)
3871  {
3872  // Dummy return
3873  return dictionary::null;
3874  }
3875  else
3876  {
3878  }
3879  }
3880 
3881  return *dictptr;
3882 }
3883 
3884 
3886 (
3888  const word& keyword,
3889  const bool noExit,
3890  enum keyType::option matchOpt
3891 )
3892 {
3893  const entry* eptr = dict.findEntry(keyword, matchOpt);
3894 
3895  if (!eptr)
3896  {
3898  << "Entry '" << keyword << "' not found in dictionary "
3899  << dict.relativeName() << nl;
3900 
3901  if (noExit)
3902  {
3903  // Dummy return
3904  return ITstream::empty_stream();
3905  }
3906  else
3907  {
3909  }
3910  }
3911 
3912  return eptr->stream();
3913 }
3914 
3915 
3916 // ************************************************************************* //
static const word & zeroGradientType() noexcept
The type name for zeroGradient patch fields.
Definition: fvPatchField.H:221
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
static void listCombineGather(UList< T > &values, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Combines List elements.
List< scalar > scalarList
List of scalar.
Definition: scalarList.H:32
This class separates the mesh into distinct unconnected regions, each of which is then given a label ...
Definition: regionSplit.H:136
static bool checkMesh(const bool report, const polyMesh &mesh, const dictionary &dict, labelHashSet &wrongFaces, const bool dryRun=false)
Check mesh with mesh settings in dict. Collects incorrect faces.
const labelList patchIDs(pbm.indices(polyPatchNames, true))
const Field< point_type > & faceAreas() const
Return face area vectors for patch.
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search...
Definition: meshSearch.H:56
const polyBoundaryMesh & pbm
static void swapFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled face values. Uses eqOp.
Definition: syncTools.H:567
const T & first() const noexcept
Access the first element.
Definition: Pair.H:137
label addFaceZone(const word &fzName, const word &masterPatch, const word &slavePatch, const surfaceZonesInfo::faceZoneType &fzType)
Add/lookup faceZone and update information. Return index of.
static void syncFaceList(const polyMesh &mesh, UList< T > &faceValues, const CombineOp &cop, const bool parRun=UPstream::parRun())
Synchronize values on all mesh faces.
Definition: syncTools.H:465
dictionary dict
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
labelList getExposedFaces(const bitSet &removedCell) const
Get labels of faces exposed after cells removal.
Definition: removeCells.C:77
std::enable_if< std::is_same< bool, TypeT >::value, bool >::type unset(const label i)
Unset the bool entry at specified position, always false for out-of-range access. ...
Definition: UList.H:805
unsigned int count(const bool on=true) const
Count number of bits set.
Definition: bitSetI.H:420
static const dictionary & subDict(const dictionary &dict, const word &keyword, const bool noExit, enum keyType::option matchOpt=keyType::REGEX)
Wrapper around dictionary::subDict which does not exit.
void clearAddressing()
Clear addressing.
Definition: ZoneMesh.C:905
Definition: ops.H:67
void set(const bitSet &bitset)
Set specified bits from another bitset.
Definition: bitSetI.H:498
A class for handling file names.
Definition: fileName.H:72
A list of face labels.
Definition: faceSet.H:47
const DynamicList< face > & faces() const
label addPointZone(const word &name)
Add pointZone if does not exist. Return index of zone.
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
Foam::pointBoundaryMesh.
const fileName & facesInstance() const
Return the current instance directory for faces.
Definition: polyMesh.C:859
A face is a list of labels corresponding to mesh vertices.
Definition: face.H:68
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
MeshType
Enumeration for how to operate.
vtk::lineWriter writer(edgeCentres, edgeList::null(), fileName(aMesh.time().globalPath()/"finiteArea-edgesCentres"))
static bitSet getMasterFaces(const polyMesh &mesh)
Get per face whether it is uncoupled or a master of a coupled set of faces.
Definition: syncTools.C:119
label countHits() const
Count number of intersections (local)
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
label nPoints() const noexcept
Number of mesh points.
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:129
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:608
void append(const T &val)
Append an element at the end of the list.
Definition: List.H:521
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
const labelIOList & tetBasePtIs() const
Return the tetBasePtIs.
Definition: polyMesh.C:899
const bitSet isBlockedFace(intersectedFaces())
bool getFaceZoneInfo(const word &fzName, label &masterPatchID, label &slavePatchID, surfaceZonesInfo::faceZoneType &fzType) const
Lookup faceZone information. Return false if no information.
virtual const fileName & name() const override
Read/write access to the name of the stream.
Definition: OSstream.H:134
static label findRegions(const polyMesh &, const vector &perturbVec, const pointField &locationsInMesh, const pointField &locationsOutsideMesh, const label nRegions, labelList &cellRegion, const boolList &blockedFace, const bool exitIfLeakPath, const refPtr< coordSetWriter > &leakPathFormatter)
Find regions points are in.
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
static void removeFiles(const polyMesh &)
Helper: remove all relevant files from mesh instance.
Definition: hexRef8.C:5829
const mapDistribute & globalEdgeSlavesMap() const
static const pointMesh & New(const polyMesh &mesh, Args &&... args)
Get existing or create MeshObject registered with typeName.
Definition: MeshObject.C:53
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
static label findRegion(const polyMesh &, const labelList &cellRegion, const vector &perturbVec, const point &p)
Find region point is in. Uses optional perturbation to re-test.
Various mesh related information for a parallel run. Upon construction, constructs all info using par...
IntListType renumber(const labelUList &oldToNew, const IntListType &input)
Renumber the values within a list.
Output to file stream as an OSstream, normally using std::ofstream for the actual output...
Definition: OFstream.H:71
void printMeshInfo(const bool debug, const string &msg, const bool printCellLevel) const
Print some mesh stats.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
autoPtr< mapPolyMesh > doRemoveCells(const labelList &cellsToRemove, const labelList &exposedFaces, const labelList &exposedPatchIDs, removeCells &cellRemover)
Remove cells. Put exposedFaces into exposedPatchIDs.
static ITstream & lookup(const dictionary &dict, const word &keyword, const bool noExit, enum keyType::option matchOpt=keyType::REGEX)
Wrapper around dictionary::lookup which does not exit.
static void syncBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions, const CombineOp &cop)
Synchronize locations on boundary faces only.
Definition: syncTools.H:445
static void matchEdges(const PrimitivePatch< FaceList1, PointField1 > &p1, const PrimitivePatch< FaceList2, PointField2 > &p2, labelList &p1EdgeLabels, labelList &p2EdgeLabels, bitSet &sameOrientation)
Find corresponding edges on patches sharing the same points.
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: UListI.H:265
label splitFacesUndo(const labelList &splitFaces, const labelPairList &splits, const labelPairList &splitPatches, const dictionary &motionDict, labelList &duplicateFace, List< labelPair > &baffles)
Split faces along diagonal. Maintain mesh quality. Return.
Given list of cells to remove, insert all the topology changes.
Definition: removeCells.H:59
static void swapBoundaryFaceList(const polyMesh &mesh, UList< T > &faceValues, const bool parRun=UPstream::parRun())
Swap coupled boundary face values. Uses eqOp.
Definition: syncTools.H:524
Random rndGen
Definition: createFields.H:23
static word meshSubDir
Return the mesh sub-directory name (usually "polyMesh")
Definition: polyMesh.H:411
void reorder(const labelUList &oldToNew, const bool validBoundary)
Reorders patches. Ordering does not have to be done in.
dimensioned< vector > dimensionedVector
Dimensioned vector obtained from generic dimensioned type.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
static void gatherList(const UList< commsStruct > &comms, UList< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
void setConstraints(const polyMesh &mesh, boolList &blockedFace, PtrList< labelList > &specifiedProcessorFaces, labelList &specifiedProcessor, List< labelPair > &explicitConnections) const
Helper: extract constraints:
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1061
void reorder(const labelUList &oldToNew, const bool check=false)
Reorder elements. Reordering must be unique (ie, shuffle).
Definition: UPtrList.C:79
void clear() noexcept
Same as reset(nullptr)
Definition: autoPtr.H:255
label constructSize() const noexcept
Constructed data size.
labelList intersectedFaces() const
Get faces with intersection.
static writeType writeLevel()
Get/set write level.
void clearOut(const bool isMeshUpdate=false)
Clear all geometry and addressing.
Definition: fvMesh.C:227
static const Enum< MeshType > MeshTypeNames
Class containing mesh-to-mesh mapping information after a mesh distribution where we send parts of me...
static const word & calculatedType() noexcept
The type name for calculated patch fields.
void resize_nocopy(const label len)
Adjust allocated size of list without necessarily.
Definition: ListI.H:168
void writeOBJ(Ostream &os, const point &pt)
Write obj representation of a point.
Definition: meshTools.C:196
label whichFace(const label globalCellID) const
Helper function to re-direct to zone::localID(...)
Definition: faceZone.C:397
static bitSet getMasterEdges(const polyMesh &mesh, const labelList &meshEdges)
Determine master edge for subset of edges. If coupled.
Base class of (analytical or triangulated) surface. Encapsulates all the search routines. WIP.
Ignore writing from objectRegistry::writeObject()
const labelListList & globalEdgeSlaves() const
quaternion normalised(const quaternion &q)
Return the normalised (unit) quaternion of the given quaternion.
Definition: quaternionI.H:674
const dimensionSet dimless
Dimensionless.
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1086
static void calculateEdgeWeights(const polyMesh &mesh, const bitSet &isMasterEdge, const labelList &meshPoints, const edgeList &edges, scalarField &edgeWeights, scalarField &invSumWeight)
Helper: calculate edge weights (1/length)
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
label nFaces() const noexcept
Number of mesh faces.
labelList intersectedPoints() const
Get points on surfaces with intersection and boundary faces.
autoPtr< mapPolyMesh > changeMesh(polyMesh &mesh, const labelUList &patchMap, const bool inflate, const bool syncParallel=true, const bool orderCells=false, const bool orderPoints=false)
Inplace changes mesh without change of patches.
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.
cellDecomposition
Enumeration defining the decomposition of the cell for.
Definition: polyMesh.H:104
Finds shortest path (in terms of cell centres) to walk on mesh from any point in insidePoints to any ...
void write(const word &fieldName, const UList< Type > &field)
Write primitive field of CellData (Poly or Line) or PointData values.
A class for managing references or pointers (no reference counting)
Definition: HashPtrTable.H:49
T & emplace_back(Args &&... args)
Construct and append an element to the end of the list, return reference to the new list element...
Definition: PtrListI.H:105
Class containing mesh-to-mesh mapping information after a change in polyMesh topology.
Definition: mapPolyMesh.H:158
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
Pair< int > faceMap(const label facePi, const face &faceP, const label faceNi, const face &faceN)
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all communicator ranks. Does nothing in non-paral...
static labelPairList findDuplicateFacePairs(const polyMesh &)
Helper routine to find all baffles (two boundary faces.
fileName path() const
The complete path for the object (with instance, local,...).
Definition: IOobject.C:480
Container for data on surfaces used for surface-driven refinement. Contains all the data about the le...
static label addPatch(fvMesh &, const word &name, const dictionary &)
Helper:add patch to mesh. Update all registered fields.
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
Mesh representing a set of points created from polyMesh.
Definition: pointMesh.H:45
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
static void syncData(List< Type > &elems, const labelListList &slaves, const labelListList &transformedSlaves, const mapDistribute &slavesMap, const globalIndexAndTransform &, const CombineOp &cop, const TransformOp &top)
Helper: synchronise data with transforms.
const labelList & reverseFaceMap() const noexcept
Reverse face map.
Definition: mapPolyMesh.H:620
label fcIndex(const label i) const noexcept
The forward circular index. The next index in the list which returns to the first at the end of the l...
Definition: UListI.H:90
T & constCast() const
Return non-const reference to the object or to the contents of a (non-null) managed pointer...
Definition: refPtr.H:278
void reset(T *p=nullptr) noexcept
Delete managed object and set to new given pointer.
Definition: autoPtrI.H:37
static const Enum< writeType > writeTypeNames
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
Encapsulates queries for features.
void distributeFaceData(List< T > &values) const
Distribute list of face data.
static label appendPatch(fvMesh &, const label insertPatchi, const word &, const dictionary &)
Helper:append patch to end of mesh.
void distribute(const mapDistributePolyMesh &)
Update local numbering for mesh redistribution.
static void updateList(const labelList &newToOld, const T &nullValue, List< T > &elems)
Helper: reorder list according to map.
word timeName
Definition: getTimeIndex.H:3
fileName::Type type(const fileName &name, const bool followLink=true)
Return the file type: DIRECTORY or FILE, normally following symbolic links.
Definition: POSIX.C:799
void write(vtk::formatter &fmt, const Type &val, const label n=1)
Component-wise write of a value (N times)
A list of faces which address into the list of points.
unsigned int count(const UList< bool > &bools, const bool val=true)
Count number of &#39;true&#39; entries.
Definition: BitOps.H:73
Calculates a unique integer (label so might not have enough room - 2G max) for processor + local inde...
Definition: globalIndex.H:61
A List obtained as a section of another List.
Definition: SubList.H:50
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1077
Sends/receives parts of mesh+fvfields to neighbouring processors. Used in load balancing.
bool returnReduceAnd(const bool value, const label comm=UPstream::worldComm)
Perform logical (and) MPI Allreduce on a copy. Uses UPstream::reduceAnd.
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
const fileName & pointsInstance() const
Return the current instance directory for points.
Definition: polyMesh.C:853
void setSize(const label n)
Alias for resize()
Definition: List.H:320
dynamicFvMesh & mesh
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for expressions::valueTypeCode::INVALID.
Definition: exprTraits.C:127
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.
const pointField & points
label findZoneID(const word &zoneName) const
Find zone index by name, return -1 if not found.
Definition: ZoneMesh.C:718
const_iterator cfind(const Key &key) const
Find and return an const_iterator set at the hashed entry.
Definition: HashTableI.H:113
An edge is a list of two vertex labels. This can correspond to a directed graph edge or an edge on a ...
Definition: edge.H:59
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i), works like std::iota() but returning a...
Definition: labelLists.C:44
fileName globalPath() const
Return global path for the case = rootPath/globalCaseName. Same as TimePaths::globalPath() ...
Definition: Time.H:512
const polyBoundaryMesh & boundaryMesh() const noexcept
Return boundary mesh.
Definition: polyMesh.H:609
A class for handling words, derived from Foam::string.
Definition: word.H:63
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
static bitSet getMasterPoints(const polyMesh &mesh)
Get per point whether it is uncoupled or a master of a coupled set of points.
Definition: syncTools.C:61
const DynamicList< point > & points() const
Points. Shrunk after constructing mesh (or calling of compact())
wordList names() const
Return a list of patch names.
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const Field< point_type > & faceCentres() const
Return face centres for patch.
Base class for writing coordSet(s) and tracks with fields.
static void checkCoupledFaceZones(const polyMesh &)
Helper function: check that face zones are synced.
static const dictionary null
An empty dictionary, which is also the parent for all dictionaries.
Definition: dictionary.H:486
void doSplitFaces(const labelList &splitFaces, const labelPairList &splits, const labelPairList &splitPatches, polyTopoChange &meshMod) const
Split faces into two.
Container for searchableSurfaces. The collection is specified as a dictionary. For example...
static tmp< T > New(Args &&... args)
Construct tmp with forwarding arguments.
Definition: tmp.H:206
bool exists(const fileName &name, const bool checkGzip=true, const bool followLink=true)
Does the name exist (as DIRECTORY or FILE) in the file system?
Definition: POSIX.C:835
const labelList & surfaceIndex() const
Per start-end edge the index of the surface hit.
static void swapBoundaryFacePositions(const polyMesh &mesh, UList< point > &positions, const bool parRun=UPstream::parRun())
Swap coupled positions. Uses eqOp.
Definition: syncTools.H:545
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, const bool multiZone=false)
Modify vertices or cell of face.
const labelListList & edgeFaces() const
Return edge-face addressing.
Abstract base class for domain decomposition.
label nInternalFaces() const noexcept
Number of internal faces.
Encapsulates queries for volume refinement (&#39;refine all cells within shell&#39;).
Definition: shellSurfaces.H:53
const labelList & reversePointMap() const noexcept
Reverse point map.
Definition: mapPolyMesh.H:582
Vector< scalar > vector
Definition: vector.H:57
virtual const faceList & faces() const
Return raw faces.
Definition: polyMesh.C:1103
label whichPatch(const label meshFacei) const
Return patch index for a given mesh face index. Uses binary search.
Accumulating histogram of values. Specified bin resolution automatic generation of bins...
Definition: distribution.H:57
const HashTable< labelList > & groupPatchIDs() const
The patch indices per patch group.
void updateMesh(const mapPolyMesh &)
Force recalculation of locally stored data on topological change.
Definition: removeCells.H:149
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
errorManip< error > abort(error &err)
Definition: errorManip.H:139
static void syncPointList(const polyMesh &mesh, List< T > &pointValues, const CombineOp &cop, const T &nullValue, const TransformOp &top)
Synchronize values on all mesh points.
bool test(const label pos) const
Test for True value at specified position, never auto-vivify entries.
Definition: bitSet.H:329
Random number generator.
Definition: Random.H:55
void setRefinement(const bitSet &removedCell, const labelUList &facesToExpose, const labelUList &patchIDs, polyTopoChange &) const
Play commands into polyTopoChange to remove cells.
Definition: removeCells.C:181
word timeName() const
Replacement for Time::timeName() that returns oldInstance (if overwrite_)
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
void setCapacity(const label nPoints, const label nFaces, const label nCells)
Explicitly pre-size the dynamic storage for expected mesh size for if construct-without-mesh.
A Vector of values with scalar precision, where scalar is float/double depending on the compilation f...
static word timeName(const scalar t, const int precision=precision_)
Return a time name for the given scalar time value formatted with the given precision.
Definition: Time.C:714
autoPtr< mapDistributePolyMesh > balance(const bool keepZoneFaces, const bool keepBaffles, const labelList &singleProcPoints, const scalarField &cellWeights, decompositionMethod &decomposer, fvMeshDistribute &distributor)
Redecompose according to cell count.
void checkData()
Debugging: check that all faces still obey start()>end()
int debug
Static debugging option.
Pair< label > labelPair
A pair of labels.
Definition: Pair.H:51
Type gMax(const FieldField< Field, Type > &f)
const faceZoneMesh & faceZones() const noexcept
Return face zone mesh.
Definition: polyMesh.H:671
virtual bool open(const fileName &file, bool parallel=UPstream::parRun())
Open file for writing (creates parent directory).
defineTypeNameAndDebug(combustionModel, 0)
static bool clean(std::string &str)
Cleanup filename string, possibly applies other transformations such as changing the path separator e...
Definition: fileName.C:192
label addMeshedPatch(const word &name, const dictionary &)
Add patch originating from meshing. Update meshedPatches_.
labelList meshedPatches() const
Get patchIDs for patches added in addMeshedPatch.
static void splitFace(const face &f, const labelPair &split, face &f0, face &f1)
Helper: split face into:
autoPtr< mapDistributePolyMesh > distribute(const labelList &dist)
Send cells to neighbours according to distribution.
labelList f(nPoints)
void setSize(const label newLen)
Same as resize()
Definition: PtrList.H:337
label nTotalCells() const noexcept
Total global number of mesh cells.
static autoPtr< indirectPrimitivePatch > makePatch(const polyMesh &, const labelList &)
Create patch from set of patches.
fileName relativeName(const bool caseTag=false) const
The dictionary name relative to the case.
Definition: dictionary.C:179
void updateMesh(const mapPolyMesh &, const labelList &changedFaces)
Update for external change to mesh. changedFaces are in new mesh.
void updateIntersections(const labelList &changedFaces)
Find any intersection of surface. Store in surfaceIndex_.
static const Foam::polyMesh::cellDecomposition findCellMode(Foam::polyMesh::FACE_DIAG_TRIS)
bool hasMotionPoints() const noexcept
Has valid preMotionPoints?
Definition: mapPolyMesh.H:767
autoPtr< mapPolyMesh > splitMeshRegions(const labelList &globalToMasterPatch, const labelList &globalToSlavePatch, const pointField &locationsInMesh, const pointField &locationsOutsideMesh, const bool exitIfLeakPath, const refPtr< coordSetWriter > &leakPathFormatter)
Split mesh. Keep part containing point. Return empty map if.
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;for(const word &name :lagrangianScalarNames){ IOField< scalar > fld(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
Helper class which maintains intersections of (changing) mesh with (static) surfaces.
Use additional distance field for (scalar) axis.
static bool split(const std::string &line, std::string &key, std::string &val)
Definition: cpuInfo.C:32
const indirectPrimitivePatch & coupledPatch() const
Return patch of all coupled faces.
static void allGatherList(UList< T > &values, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Gather data, but keep individual values separate. Uses MPI_Allgather or manual linear/tree communicat...
void setInstance(const fileName &)
Set instance of all local IOobjects.
Calculates points shared by more than two processor patches or cyclic patches.
Definition: globalPoints.H:98
void inplaceRenumber(const labelUList &oldToNew, IntListType &input)
Inplace renumber the values within a list.
Class containing processor-to-processor mapping information.
static bool constraintType(const word &patchType)
Return true if the given type is a constraint type.
Definition: polyPatch.C:255
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:37
A bitSet stores bits (elements with only two states) in packed internal format and supports a variety...
Definition: bitSet.H:59
#define WarningInFunction
Report a warning using Foam::Warning.
Enum is a wrapper around a list of names/values that represent particular enumeration (or int) values...
Definition: error.H:64
static void testSyncPointList(const string &msg, const polyMesh &mesh, const List< scalar > &fld)
const dimensionSet dimLength(0, 1, 0, 0, 0, 0, 0)
Definition: dimensionSets.H:50
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:637
dimensioned< scalar > dimensionedScalar
Dimensioned scalar obtained from generic dimensioned type.
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.
static bitSet getMasterPoints(const polyMesh &mesh, const labelList &meshPoints)
Determine master point for subset of points. If coupled.
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:78
A List with indirect addressing. Like IndirectList but does not store addressing. ...
Definition: faMatrix.H:52
Direct mesh changes based on v1.3 polyTopoChange syntax.
void close()
End the file contents and close the file after writing.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1094
const char * end
Definition: SVGTools.H:223
const polyBoundaryMesh & patches
const word & name() const noexcept
The zone name.
Nothing to be read.
option
Enumeration for the data type and search/match modes (bitmask)
Definition: keyType.H:79
static const word & calculatedType() noexcept
The type name for calculated patch fields.
Definition: fvPatchField.H:204
Automatically write from objectRegistry::writeObject()
static word outputPrefix
Directory prefix.
void push_back(T *ptr)
Append an element to the end of the list.
Definition: PtrListI.H:114
For use with FaceCellWave. Determines topological distance to starting faces. Templated on passive tr...
label nRegions() const
Return total number of regions.
Definition: regionSplit.H:337
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:84
label findCell(const point &p, const cellDecomposition=CELL_TETS) const
Find cell enclosing this location and return index.
Definition: polyMesh.C:1511
static const Enum< debugType > debugTypeNames
const boolList & flipMap() const noexcept
Return face flip map.
Definition: faceZone.H:367
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 with extra functionality for use in octree.
Definition: treeBoundBox.H:90
wordList names() const
A list of the zone names.
Definition: ZoneMesh.C:451
messageStream Info
Information stream (stdout output on master, null elsewhere)
constexpr label labelMax
Definition: label.H:55
static ITstream & empty_stream()
Return reference to an empty ITstream, for functions needing to return an ITstream reference but whic...
Definition: ITstream.C:68
const fvBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: fvMesh.H:395
SubField< vector > subField
Declare type of subField.
Definition: Field.H:128
writeType
Enumeration for what to write. Used as a bit-pattern.
label n
Field< vector > vectorField
Specialisation of Field<T> for vector.
static autoPtr< polyPatch > New(const word &patchType, const word &name, const label size, const label start, const label index, const polyBoundaryMesh &bm)
Return pointer to a new patch created on freestore from components.
Definition: polyPatchNew.C:28
faceZoneType
What to do with faceZone faces.
debugType
Enumeration for what to debug. Used as a bit-pattern.
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
#define DebugVar(var)
Report a variable name and value.
T * data() noexcept
Return pointer to the underlying array serving as data storage.
Definition: FixedListI.H:121
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:75
entry * set(entry *entryPtr)
Assign a new entry, overwriting any existing entry.
Definition: dictionary.C:765
static autoPtr< fvPatch > New(const polyPatch &, const fvBoundaryMesh &)
Return a pointer to a new patch created on freestore from polyPatch.
Definition: fvPatchNew.C:28
A subset of mesh faces organised as a primitive patch.
Definition: faceZone.H:60
const labelList & faceMap() const noexcept
Old face map.
Definition: mapPolyMesh.H:503
static void syncEdgeList(const polyMesh &mesh, List< T > &edgeValues, const CombineOp &cop, const T &nullValue, const TransformOp &top, const FlipOp &fop)
Synchronize values on all mesh edges.
bool write() const
Write mesh and all data.
List< point > pointList
List of point.
Definition: pointList.H:32
List< label > labelList
A List of labels.
Definition: List.H:62
static tmp< pointVectorField > makeDisplacementField(const pointMesh &pMesh, const labelList &adaptPatchIDs)
Helper function to make a pointVectorField with correct.
volScalarField & p
IOobject io("surfaceFilmProperties", mesh.time().constant(), mesh, IOobject::READ_IF_PRESENT, IOobject::NO_WRITE, IOobject::NO_REGISTER)
A class for managing temporary objects.
Definition: HashPtrTable.H:50
static autoPtr< T > New(Args &&... args)
Construct autoPtr with forwarding arguments.
Definition: autoPtr.H:178
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
bool coupled
const T & second() const noexcept
Access the second element.
Definition: Pair.H:147
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))
const pointBoundaryMesh & boundary() const noexcept
Return reference to boundary mesh.
Definition: pointMesh.H:160
void dumpIntersections(const fileName &prefix) const
Debug: Write intersection information to OBJ format.
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
label nBoundaryFaces() const noexcept
Number of boundary faces (== nFaces - nInternalFaces)
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
static labelList countCells(const labelList &)
Helper function: count cells per processor in wanted distribution.
void removeFace(const label facei, const label mergeFacei)
Remove/merge face.
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:180
Map< label > invertToMap(const labelUList &values)
Create inverse mapping, which is a lookup table into the given list.
Definition: ListOps.C:107
List< bool > boolList
A List of bools.
Definition: List.H:60
A List with indirect addressing.
Definition: IndirectList.H:60
void dumpRefinementLevel() const
Write refinement level as volScalarFields for postprocessing.
const pointField & preMotionPoints() const noexcept
Pre-motion point positions.
Definition: mapPolyMesh.H:759
labelList countEdgeFaces(const uindirectPrimitivePatch &pp) const
Count number of faces per patch edge. Parallel consistent.
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
label size() const noexcept
Number of entries.
Definition: PackedList.H:393
Do not request registration (bool: false)
void reduce(T &value, const BinaryOp &bop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Reduce inplace (cf. MPI Allreduce) using linear/tree communication schedule.
List< treeBoundBox > meshBb(1, treeBoundBox(coarseMesh.points()).extend(rndGen, 1e-3))
An input stream of tokens.
Definition: ITstream.H:52
static label addFaceZone(const word &name, const labelList &addressing, const boolList &flipMap, polyMesh &mesh)
static label findCell(const polyMesh &, const vector &perturbVec, const point &p)
Find cell point is in. Uses optional perturbation to re-test.
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
forAllConstIters(mixture.phases(), phase)
Definition: pEqn.H:28
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
virtual labelList decompose(const pointField &points, const scalarField &pointWeights=scalarField::null()) const
Return the wanted processor number for every coordinate, using uniform or specified point weights...
static void listCombineReduce(List< T > &values, const CombineOp &cop, const int tag=UPstream::msgType(), const label comm=UPstream::worldComm)
Combines List elements. After completion all processors have the same data.
static const Enum< coordFormat > coordFormatNames
String representation of coordFormat enum.
Definition: coordSet.H:74
const labelListList & globalEdgeTransformedSlaves() const
bool rm(const fileName &file)
Remove a file (or its gz equivalent), returning true if successful.
Definition: POSIX.C:1404
const pointField & pts
const dictionary * findDict(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a sub-dictionary pointer if present (and it is a dictionary) otherwise return nullptr...
Definition: dictionaryI.H:124
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127