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