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