snappyRefineMesh.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-2016 OpenFOAM Foundation
9  Copyright (C) 2018-2022 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 Application
28  snappyRefineMesh
29 
30 Group
31  grpMeshAdvancedUtilities
32 
33 Description
34  Refine cells near to a surface.
35 
36 \*---------------------------------------------------------------------------*/
37 
38 #include "argList.H"
39 #include "Time.H"
40 #include "polyMesh.H"
41 #include "twoDPointCorrector.H"
42 #include "OFstream.H"
43 #include "multiDirRefinement.H"
44 
45 #include "triSurface.H"
46 #include "triSurfaceSearch.H"
47 
48 #include "cellSet.H"
49 #include "pointSet.H"
50 #include "surfaceToCell.H"
51 #include "surfaceToPoint.H"
52 #include "cellToPoint.H"
53 #include "pointToCell.H"
54 #include "cellToCell.H"
55 #include "surfaceSets.H"
56 #include "polyTopoChange.H"
57 #include "polyTopoChanger.H"
58 #include "mapPolyMesh.H"
59 #include "labelIOList.H"
60 #include "emptyPolyPatch.H"
61 #include "removeCells.H"
62 #include "meshSearch.H"
63 
64 using namespace Foam;
65 
66 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
67 
68 
69 // Max cos angle for edges to be considered aligned with axis.
70 static const scalar edgeTol = 1e-3;
71 
72 
73 void writeSet(const cellSet& cells, const string& msg)
74 {
75  Info<< "Writing " << msg << " (" << cells.size() << ") to cellSet "
76  << cells.instance()/cells.local()/cells.name()
77  << endl;
78  cells.write();
79 }
80 
81 
82 direction getNormalDir(const twoDPointCorrector* correct2DPtr)
83 {
84  direction dir = 3;
85 
86  if (correct2DPtr)
87  {
88  const vector& normal = correct2DPtr->planeNormal();
89 
90  if (mag(normal & vector(1, 0, 0)) > 1-edgeTol)
91  {
92  dir = 0;
93  }
94  else if (mag(normal & vector(0, 1, 0)) > 1-edgeTol)
95  {
96  dir = 1;
97  }
98  else if (mag(normal & vector(0, 0, 1)) > 1-edgeTol)
99  {
100  dir = 2;
101  }
102  }
103  return dir;
104 }
105 
106 
107 
108 // Calculate some edge statistics on mesh. Return min. edge length over all
109 // directions but exclude component (0=x, 1=y, 2=z, other=none)
110 scalar getEdgeStats(const primitiveMesh& mesh, const direction excludeCmpt)
111 {
112  label nX = 0;
113  label nY = 0;
114  label nZ = 0;
115 
116  scalar minX = GREAT;
117  scalar maxX = -GREAT;
118  vector x(1, 0, 0);
119 
120  scalar minY = GREAT;
121  scalar maxY = -GREAT;
122  vector y(0, 1, 0);
123 
124  scalar minZ = GREAT;
125  scalar maxZ = -GREAT;
126  vector z(0, 0, 1);
127 
128  scalar minOther = GREAT;
129  scalar maxOther = -GREAT;
130 
131  const edgeList& edges = mesh.edges();
132 
133  forAll(edges, edgei)
134  {
135  const edge& e = edges[edgei];
136 
137  vector eVec(e.vec(mesh.points()));
138 
139  scalar eMag = mag(eVec);
140 
141  eVec /= eMag;
142 
143  if (mag(eVec & x) > 1-edgeTol)
144  {
145  minX = min(minX, eMag);
146  maxX = max(maxX, eMag);
147  nX++;
148  }
149  else if (mag(eVec & y) > 1-edgeTol)
150  {
151  minY = min(minY, eMag);
152  maxY = max(maxY, eMag);
153  nY++;
154  }
155  else if (mag(eVec & z) > 1-edgeTol)
156  {
157  minZ = min(minZ, eMag);
158  maxZ = max(maxZ, eMag);
159  nZ++;
160  }
161  else
162  {
163  minOther = min(minOther, eMag);
164  maxOther = max(maxOther, eMag);
165  }
166  }
167 
168  Info<< "Mesh bounding box:" << boundBox(mesh.points()) << nl << nl
169  << "Mesh edge statistics:" << nl
170  << " x aligned : number:" << nX << "\tminLen:" << minX
171  << "\tmaxLen:" << maxX << nl
172  << " y aligned : number:" << nY << "\tminLen:" << minY
173  << "\tmaxLen:" << maxY << nl
174  << " z aligned : number:" << nZ << "\tminLen:" << minZ
175  << "\tmaxLen:" << maxZ << nl
176  << " other : number:" << mesh.nEdges() - nX - nY - nZ
177  << "\tminLen:" << minOther
178  << "\tmaxLen:" << maxOther << nl << endl;
179 
180  if (excludeCmpt == 0)
181  {
182  return min(minY, min(minZ, minOther));
183  }
184  else if (excludeCmpt == 1)
185  {
186  return min(minX, min(minZ, minOther));
187  }
188  else if (excludeCmpt == 2)
189  {
190  return min(minX, min(minY, minOther));
191  }
192  else
193  {
194  return min(minX, min(minY, min(minZ, minOther)));
195  }
196 }
197 
198 
199 // Adds empty patch if not yet there. Returns patchID.
200 label addPatch(polyMesh& mesh, const word& patchName)
201 {
202  label patchi = mesh.boundaryMesh().findPatchID(patchName);
203 
204  if (patchi == -1)
205  {
207 
208  polyPatchList newPatches(patches.size() + 1);
209 
210  label nPatches = 0;
211 
212  // Add empty patch as 0th entry (Note: only since subsetMesh wants this)
213  patchi = 0;
214  {
215  newPatches.set
216  (
217  nPatches,
218  new emptyPolyPatch
219  (
220  patchName,
221  0,
223  nPatches,
224  patches,
225  emptyPolyPatch::typeName
226  )
227  );
228  ++nPatches;
229  }
230 
231  for (const polyPatch& pp : patches)
232  {
233  newPatches.set
234  (
235  nPatches,
236  pp.clone
237  (
238  patches,
239  nPatches,
240  pp.size(),
241  pp.start()
242  )
243  );
244  ++nPatches;
245  }
246 
248  mesh.addPatches(newPatches);
249 
250  Info<< "Created patch oldInternalFaces at " << patchi << endl;
251  }
252  else
253  {
254  Info<< "Reusing patch oldInternalFaces at " << patchi << endl;
255  }
256 
257 
258  return patchi;
259 }
260 
261 
262 // Take surface and select cells based on surface curvature.
263 void selectCurvatureCells
264 (
265  const polyMesh& mesh,
266  const fileName& surfName,
267  const triSurfaceSearch& querySurf,
268  const scalar nearDist,
269  const scalar curvature,
270  cellSet& cells
271 )
272 {
273  // Use surfaceToCell to do actual calculation.
274 
275  // Since we're adding make sure set is on disk.
276  cells.write();
277 
278  // Take centre of cell 0 as outside point since info not used.
279 
280  surfaceToCell cutSource
281  (
282  mesh,
283  surfName,
284  querySurf.surface(),
285  querySurf,
286  pointField(1, mesh.cellCentres()[0]),
287  false, // includeCut
288  false, // includeInside
289  false, // includeOutside
290  false, // geometricOnly
291  nearDist,
292  curvature
293  );
294 
295  cutSource.applyToSet(topoSetSource::ADD, cells);
296 }
297 
298 
299 // cutCells contains currently selected cells to be refined. Add neighbours
300 // on the inside or outside to them.
301 void addCutNeighbours
302 (
303  const polyMesh& mesh,
304  const bool selectInside,
305  const bool selectOutside,
306  const labelHashSet& inside,
307  const labelHashSet& outside,
308  labelHashSet& cutCells
309 )
310 {
311  // Pick up face neighbours of cutCells
312 
313  labelHashSet addCutFaces(cutCells.size());
314 
315  for (const label celli : cutCells)
316  {
317  const labelList& cFaces = mesh.cells()[celli];
318 
319  forAll(cFaces, i)
320  {
321  const label facei = cFaces[i];
322 
323  if (mesh.isInternalFace(facei))
324  {
325  label nbr = mesh.faceOwner()[facei];
326 
327  if (nbr == celli)
328  {
329  nbr = mesh.faceNeighbour()[facei];
330  }
331 
332  if (selectInside && inside.found(nbr))
333  {
334  addCutFaces.insert(nbr);
335  }
336  else if (selectOutside && outside.found(nbr))
337  {
338  addCutFaces.insert(nbr);
339  }
340  }
341  }
342  }
343 
344  Info<< " Selected an additional " << addCutFaces.size()
345  << " neighbours of cutCells to refine" << endl;
346 
347  for (const label facei : addCutFaces)
348  {
349  cutCells.insert(facei);
350  }
351 }
352 
353 
354 // Return true if any cells had to be split to keep a difference between
355 // neighbouring refinement levels < limitDiff.
356 // Gets cells which will be refined (so increase the refinement level) and
357 // updates it.
358 bool limitRefinementLevel
359 (
360  const primitiveMesh& mesh,
361  const label limitDiff,
362  const labelHashSet& excludeCells,
363  const labelList& refLevel,
364  labelHashSet& cutCells
365 )
366 {
367  // Do simple check on validity of refinement level.
368  forAll(refLevel, celli)
369  {
370  if (!excludeCells.found(celli))
371  {
372  const labelList& cCells = mesh.cellCells()[celli];
373 
374  forAll(cCells, i)
375  {
376  label nbr = cCells[i];
377 
378  if (!excludeCells.found(nbr))
379  {
380  if (refLevel[celli] - refLevel[nbr] >= limitDiff)
381  {
383  << "Level difference between neighbouring cells "
384  << celli << " and " << nbr
385  << " greater than or equal to " << limitDiff << endl
386  << "refLevels:" << refLevel[celli] << ' '
387  << refLevel[nbr] << abort(FatalError);
388  }
389  }
390  }
391  }
392  }
393 
394 
395  labelHashSet addCutCells(cutCells.size());
396 
397  for (const label celli : cutCells)
398  {
399  // celli will be refined.
400  const labelList& cCells = mesh.cellCells()[celli];
401 
402  forAll(cCells, i)
403  {
404  const label nbr = cCells[i];
405 
406  if (!excludeCells.found(nbr) && !cutCells.found(nbr))
407  {
408  if (refLevel[celli] + 1 - refLevel[nbr] >= limitDiff)
409  {
410  addCutCells.insert(nbr);
411  }
412  }
413  }
414  }
415 
416  if (addCutCells.size())
417  {
418  // Add cells to cutCells.
419 
420  Info<< "Added an additional " << addCutCells.size() << " cells"
421  << " to satisfy 1:" << limitDiff << " refinement level"
422  << endl;
423 
424  for (const label celli : addCutCells)
425  {
426  cutCells.insert(celli);
427  }
428  return true;
429  }
430 
431  Info<< "Added no additional cells"
432  << " to satisfy 1:" << limitDiff << " refinement level"
433  << endl;
434 
435  return false;
436 }
437 
438 
439 // Do all refinement (i.e. refCells) according to refineDict and update
440 // refLevel afterwards for added cells
441 void doRefinement
442 (
443  polyMesh& mesh,
444  const dictionary& refineDict,
445  const labelHashSet& refCells,
446  labelList& refLevel
447 )
448 {
449  label oldCells = mesh.nCells();
450 
451  // Multi-iteration, multi-direction topology modifier.
452  multiDirRefinement multiRef
453  (
454  mesh,
455  refCells.toc(),
456  refineDict
457  );
458 
459  //
460  // Update refLevel for split cells
461  //
462 
463  refLevel.setSize(mesh.nCells());
464 
465  for (label celli = oldCells; celli < mesh.nCells(); celli++)
466  {
467  refLevel[celli] = 0;
468  }
469 
470  const labelListList& addedCells = multiRef.addedCells();
471 
472  forAll(addedCells, oldCelli)
473  {
474  const labelList& added = addedCells[oldCelli];
475 
476  if (added.size())
477  {
478  // Give all cells resulting from split the refinement level
479  // of the master.
480  label masterLevel = ++refLevel[oldCelli];
481 
482  forAll(added, i)
483  {
484  refLevel[added[i]] = masterLevel;
485  }
486  }
487  }
488 }
489 
490 
491 // Subset mesh and update refLevel and cutCells
492 void subsetMesh
493 (
494  polyMesh& mesh,
495  const label writeMesh,
496  const label patchi, // patchID for exposed faces
497  const labelHashSet& cellsToRemove,
498  cellSet& cutCells,
499  labelIOList& refLevel
500 )
501 {
502  removeCells cellRemover(mesh);
503 
504  labelList cellLabels(cellsToRemove.toc());
505 
506  Info<< "Mesh has:" << mesh.nCells() << " cells."
507  << " Removing:" << cellLabels.size() << " cells" << endl;
508 
509  // exposed faces
510  labelList exposedFaces(cellRemover.getExposedFaces(cellLabels));
511 
512  polyTopoChange meshMod(mesh);
513  cellRemover.setRefinement
514  (
515  cellLabels,
516  exposedFaces,
517  labelList(exposedFaces.size(), patchi),
518  meshMod
519  );
520 
521  // Do all changes
522  Info<< "Morphing ..." << endl;
523 
524  const Time& runTime = mesh.time();
525 
526  autoPtr<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
527 
528  if (morphMap().hasMotionPoints())
529  {
530  mesh.movePoints(morphMap().preMotionPoints());
531  }
532 
533  // Update topology on cellRemover
534  cellRemover.updateMesh(morphMap());
535 
536  // Update refLevel for removed cells.
537  const labelList& cellMap = morphMap().cellMap();
538 
539  labelList newRefLevel(cellMap.size());
540 
541  forAll(cellMap, i)
542  {
543  newRefLevel[i] = refLevel[cellMap[i]];
544  }
545 
546  // Transfer back to refLevel
547  refLevel.transfer(newRefLevel);
548 
549  if (writeMesh)
550  {
551  Info<< "Writing refined mesh to time " << runTime.timeName() << nl
552  << endl;
553 
555  mesh.write();
556  refLevel.write();
557  }
558 
559  // Update cutCells for removed cells.
560  cutCells.updateMesh(morphMap());
561 }
562 
563 
564 // Divide the cells according to status compared to surface. Constructs sets:
565 // - cutCells : all cells cut by surface
566 // - inside : all cells inside surface
567 // - outside : ,, outside ,,
568 // and a combined set:
569 // - selected : sum of above according to selectCut/Inside/Outside flags.
570 void classifyCells
571 (
572  const polyMesh& mesh,
573  const fileName& surfName,
574  const triSurfaceSearch& querySurf,
575  const pointField& outsidePts,
576 
577  const bool selectCut,
578  const bool selectInside,
579  const bool selectOutside,
580 
581  const label nCutLayers,
582 
583  cellSet& inside,
584  cellSet& outside,
585  cellSet& cutCells,
586  cellSet& selected
587 )
588 {
589  // Cut faces with surface and classify cells
591  (
592  mesh,
593  surfName,
594  querySurf.surface(),
595  querySurf,
596  outsidePts,
597 
598  nCutLayers,
599 
600  inside,
601  outside,
602  cutCells
603  );
604 
605  // Combine wanted parts into selected
606  if (selectCut)
607  {
608  selected.addSet(cutCells);
609  }
610  if (selectInside)
611  {
612  selected.addSet(inside);
613  }
614  if (selectOutside)
615  {
616  selected.addSet(outside);
617  }
618 
619  Info<< "Determined cell status:" << endl
620  << " inside :" << inside.size() << endl
621  << " outside :" << outside.size() << endl
622  << " cutCells:" << cutCells.size() << endl
623  << " selected:" << selected.size() << endl
624  << endl;
625 
626  writeSet(inside, "inside cells");
627  writeSet(outside, "outside cells");
628  writeSet(cutCells, "cut cells");
629  writeSet(selected, "selected cells");
630 }
631 
632 
633 
634 int main(int argc, char *argv[])
635 {
637  (
638  "Refine cells near to a surface"
639  );
641 
642  #include "setRootCase.H"
643  #include "createTime.H"
644  #include "createPolyMesh.H"
645 
646  // If necessary add oldInternalFaces patch
647  label newPatchi = addPatch(mesh, "oldInternalFaces");
648 
649 
650  //
651  // Read motionProperties dictionary
652  //
653 
654  Info<< "Checking for motionProperties\n" << endl;
655 
656  IOobject motionObj
657  (
658  "motionProperties",
659  runTime.constant(),
660  mesh,
663  );
664 
665  // corrector for mesh motion
666  twoDPointCorrector* correct2DPtr = nullptr;
667 
668  if (motionObj.typeHeaderOk<IOdictionary>(true))
669  {
670  Info<< "Reading " << runTime.constant() / "motionProperties"
671  << endl << endl;
672 
673  IOdictionary motionProperties(motionObj);
674 
675  if (motionProperties.get<bool>("twoDMotion"))
676  {
677  Info<< "Correcting for 2D motion" << endl << endl;
678  correct2DPtr = new twoDPointCorrector(mesh);
679  }
680  }
681 
682  IOdictionary refineDict
683  (
684  IOobject
685  (
686  "snappyRefineMeshDict",
687  runTime.system(),
688  mesh,
691  )
692  );
693 
694  fileName surfName(refineDict.get<fileName>("surface"));
695  surfName.expand();
696  const label nCutLayers(refineDict.get<label>("nCutLayers"));
697  const label cellLimit(refineDict.get<label>("cellLimit"));
698  const bool selectCut(refineDict.get<bool>("selectCut"));
699  const bool selectInside(refineDict.get<bool>("selectInside"));
700  const bool selectOutside(refineDict.get<bool>("selectOutside"));
701  const bool selectHanging(refineDict.get<bool>("selectHanging"));
702 
703  const scalar minEdgeLen(refineDict.get<scalar>("minEdgeLen"));
704  const scalar maxEdgeLen(refineDict.get<scalar>("maxEdgeLen"));
705  const scalar curvature(refineDict.get<scalar>("curvature"));
706  const scalar curvDist(refineDict.get<scalar>("curvatureDistance"));
707  pointField outsidePts(refineDict.lookup("outsidePoints"));
708  const label refinementLimit(refineDict.get<label>("splitLevel"));
709  const bool writeMesh(refineDict.get<bool>("writeMesh"));
710 
711  Info<< "Cells to be used for meshing (0=false, 1=true):" << nl
712  << " cells cut by surface : " << selectCut << nl
713  << " cells inside of surface : " << selectInside << nl
714  << " cells outside of surface : " << selectOutside << nl
715  << " hanging cells : " << selectHanging << nl
716  << endl;
717 
718 
719  if (nCutLayers > 0 && selectInside)
720  {
722  << "Illogical settings : Both nCutLayers>0 and selectInside true."
723  << endl
724  << "This would mean that inside cells get removed but should be"
725  << " included in final mesh" << endl;
726  }
727 
728  // Surface.
729  triSurface surf(surfName);
730 
731  // Search engine on surface
732  triSurfaceSearch querySurf(surf);
733 
734  // Search engine on mesh. No face decomposition since mesh unwarped.
736 
737  // Check all 'outside' points
738  forAll(outsidePts, outsidei)
739  {
740  const point& outsidePoint = outsidePts[outsidei];
741 
742  if (queryMesh.findCell(outsidePoint, -1, false) == -1)
743  {
745  << "outsidePoint " << outsidePoint
746  << " is not inside any cell"
747  << exit(FatalError);
748  }
749  }
750 
751 
752 
753  // Current refinement level. Read if present.
754  labelIOList refLevel
755  (
756  IOobject
757  (
758  "refinementLevel",
759  runTime.timeName(),
761  mesh,
764  ),
766  );
767 
768  label maxLevel = max(refLevel);
769 
770  if (maxLevel > 0)
771  {
772  Info<< "Read existing refinement level from file "
773  << refLevel.objectPath() << nl
774  << " min level : " << min(refLevel) << nl
775  << " max level : " << maxLevel << nl
776  << endl;
777  }
778  else
779  {
780  Info<< "Created zero refinement level in file "
781  << refLevel.objectPath() << nl
782  << endl;
783  }
784 
785 
786 
787 
788  // Print edge stats on original mesh. Leave out 2d-normal direction
789  direction normalDir(getNormalDir(correct2DPtr));
790  scalar meshMinEdgeLen = getEdgeStats(mesh, normalDir);
791 
792  while (meshMinEdgeLen > minEdgeLen)
793  {
794  // Get inside/outside/cutCells cellSets.
795  cellSet inside(mesh, "inside", mesh.nCells()/10);
796  cellSet outside(mesh, "outside", mesh.nCells()/10);
797  cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
798  cellSet selected(mesh, "selected", mesh.nCells()/10);
799 
800  classifyCells
801  (
802  mesh,
803  surfName,
804  querySurf,
805  outsidePts,
806 
807  selectCut, // for determination of selected
808  selectInside, // for determination of selected
809  selectOutside, // for determination of selected
810 
811  nCutLayers, // How many layers of cutCells to include
812 
813  inside,
814  outside,
815  cutCells,
816  selected // not used but determined anyway.
817  );
818 
819  Info<< " Selected " << cutCells.name() << " with "
820  << cutCells.size() << " cells" << endl;
821 
822  if ((curvDist > 0) && (meshMinEdgeLen < maxEdgeLen))
823  {
824  // Done refining enough close to surface. Now switch to more
825  // intelligent refinement where only cutCells on surface curvature
826  // are refined.
827  cellSet curveCells(mesh, "curveCells", mesh.nCells()/10);
828 
829  selectCurvatureCells
830  (
831  mesh,
832  surfName,
833  querySurf,
834  maxEdgeLen,
835  curvature,
836  curveCells
837  );
838 
839  Info<< " Selected " << curveCells.name() << " with "
840  << curveCells.size() << " cells" << endl;
841 
842  // Add neighbours to cutCells. This is if selectCut is not
843  // true and so outside and/or inside cells get exposed there is
844  // also refinement in them.
845  if (!selectCut)
846  {
847  addCutNeighbours
848  (
849  mesh,
850  selectInside,
851  selectOutside,
852  inside,
853  outside,
854  cutCells
855  );
856  }
857 
858  // Subset cutCells to only curveCells
859  cutCells.subset(curveCells);
860 
861  Info<< " Removed cells not on surface curvature. Selected "
862  << cutCells.size() << endl;
863  }
864 
865 
866  if (nCutLayers > 0)
867  {
868  // Subset mesh to remove inside cells altogether. Updates cutCells,
869  // refLevel.
870  subsetMesh(mesh, writeMesh, newPatchi, inside, cutCells, refLevel);
871  }
872 
873 
874  // Added cells from 2:1 refinement level restriction.
875  while
876  (
877  limitRefinementLevel
878  (
879  mesh,
880  refinementLimit,
881  labelHashSet(),
882  refLevel,
883  cutCells
884  )
885  )
886  {}
887 
888 
889  Info<< " Current cells : " << mesh.nCells() << nl
890  << " Selected for refinement :" << cutCells.size() << nl
891  << endl;
892 
893  if (cutCells.empty())
894  {
895  Info<< "Stopping refining since 0 cells selected to be refined ..."
896  << nl << endl;
897  break;
898  }
899 
900  if ((mesh.nCells() + 8*cutCells.size()) > cellLimit)
901  {
902  Info<< "Stopping refining since cell limit reached ..." << nl
903  << "Would refine from " << mesh.nCells()
904  << " to " << mesh.nCells() + 8*cutCells.size() << " cells."
905  << nl << endl;
906  break;
907  }
908 
909  doRefinement
910  (
911  mesh,
912  refineDict,
913  cutCells,
914  refLevel
915  );
916 
917  Info<< " After refinement:" << mesh.nCells() << nl
918  << endl;
919 
920  if (writeMesh)
921  {
922  Info<< " Writing refined mesh to time " << runTime.timeName()
923  << nl << endl;
924 
926  mesh.write();
927  refLevel.write();
928  }
929 
930  // Update mesh edge stats.
931  meshMinEdgeLen = getEdgeStats(mesh, normalDir);
932  }
933 
934 
935  if (selectHanging)
936  {
937  // Get inside/outside/cutCells cellSets.
938  cellSet inside(mesh, "inside", mesh.nCells()/10);
939  cellSet outside(mesh, "outside", mesh.nCells()/10);
940  cellSet cutCells(mesh, "cutCells", mesh.nCells()/10);
941  cellSet selected(mesh, "selected", mesh.nCells()/10);
942 
943  classifyCells
944  (
945  mesh,
946  surfName,
947  querySurf,
948  outsidePts,
949 
950  selectCut,
951  selectInside,
952  selectOutside,
953 
954  nCutLayers,
955 
956  inside,
957  outside,
958  cutCells,
959  selected
960  );
961 
962 
963  // Find any cells which have all their points on the outside of the
964  // selected set and refine them
965  labelHashSet hanging = surfaceSets::getHangingCells(mesh, selected);
966 
967  Info<< "Detected " << hanging.size() << " hanging cells"
968  << " (cells with all points on"
969  << " outside of cellSet 'selected').\nThese would probably result"
970  << " in flattened cells when snapping the mesh to the surface"
971  << endl;
972 
973  Info<< "Refining " << hanging.size() << " hanging cells" << nl
974  << endl;
975 
976  // Added cells from 2:1 refinement level restriction.
977  while
978  (
979  limitRefinementLevel
980  (
981  mesh,
982  refinementLimit,
983  labelHashSet(),
984  refLevel,
985  hanging
986  )
987  )
988  {}
989 
990  doRefinement(mesh, refineDict, hanging, refLevel);
991 
992  Info<< "Writing refined mesh to time " << runTime.timeName() << nl
993  << endl;
994 
995  // Write final mesh
997  mesh.write();
998  refLevel.write();
999 
1000  }
1001  else if (!writeMesh)
1002  {
1003  Info<< "Writing refined mesh to time " << runTime.timeName() << nl
1004  << endl;
1005 
1006  // Write final mesh. (will have been written already if writeMesh=true)
1008  mesh.write();
1009  refLevel.write();
1010  }
1011 
1012 
1013  Info<< "End\n" << endl;
1014 
1015  return 0;
1016 }
1017 
1018 
1019 // ************************************************************************* //
label nPatches
Definition: readKivaGrid.H:396
label findPatchID(const word &patchName, const bool allowNotFound=true) const
Find patch index given a name, return -1 if not found.
ITstream & lookup(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return an entry data stream. FatalIOError if not found, or not a stream. ...
Definition: dictionary.C:367
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search...
Definition: meshSearch.H:56
static void addNote(const string &note)
Add extra notes for the usage information.
Definition: argList.C:462
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
Required Variables.
uint8_t direction
Definition: direction.H:46
A class for handling file names.
Definition: fileName.H:72
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
dimensioned< typename typeOfMag< Type >::type > mag(const dimensioned< Type > &dt)
void transfer(List< T > &list)
Transfer the contents of the argument List into this list and annul the argument list.
Definition: List.C:326
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
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:598
bool found(const Key &key) const
Same as contains()
Definition: HashTable.H:1354
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1122
const word & name() const noexcept
Return the object name.
Definition: IOobjectI.H:195
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:75
label max(const labelHashSet &set, label maxValue=labelMin)
Find the max value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:40
Add elements to current set.
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
Does multiple pass refinement to refine cells in multiple directions.
Given list of cells to remove, insert all the topology changes.
Definition: removeCells.H:59
engineTime & runTime
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:531
virtual void updateMesh(const mapPolyMesh &morphMap)
Update any stored data for new labels.
Definition: cellSet.C:181
virtual void movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: fvMesh.C:918
static unsigned int defaultPrecision() noexcept
Return the default precision.
Definition: IOstream.H:423
static void noParallel()
Remove the parallel options.
Definition: argList.C:584
A bounding box defined in terms of min/max extrema points.
Definition: boundBox.H:63
const cellList & cells() const
Ignore writing from objectRegistry::writeObject()
T get(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find and return a T. FatalIOError if not found, or if the number of tokens is incorrect.
const Time & time() const
Return the top-level database.
Definition: fvMesh.H:360
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:69
fileName objectPath() const
The complete path + object name.
Definition: IOobjectI.H:284
bool isInternalFace(const label faceIndex) const noexcept
Return true if given face label is internal to the mesh.
static labelHashSet getHangingCells(const primitiveMesh &mesh, const labelHashSet &internalCells)
Get cells using points on &#39;outside&#39; only.
Definition: surfaceSets.C:274
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
virtual const pointField & points() const
Return raw points.
Definition: polyMesh.C:1078
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:421
HashSet< label, Hash< label > > labelHashSet
A HashSet of labels, uses label hasher.
Definition: HashSet.H:85
label size() const noexcept
The number of elements in table.
Definition: HashTable.H:342
Helper class to search on triSurface.
scalar y
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:38
const dimensionedScalar e
Elementary charge.
Definition: createFields.H:11
void setSize(const label n)
Alias for resize()
Definition: List.H:316
dynamicFvMesh & mesh
virtual void addSet(const topoSet &set)
Add elements present in set.
Definition: topoSet.C:549
const cellShapeList & cells
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
Class applies a two-dimensional correction to mesh motion point field.
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
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:405
label size() const noexcept
The number of entries in the list.
Definition: UPtrListI.H:106
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:118
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1116
Reading is optional [identical to LAZY_READ].
virtual bool write(const bool writeOnProc=true) const
Write using setting from DB.
virtual void subset(const topoSet &set)
Subset contents. Only elements present in both sets remain.
Definition: topoSet.C:542
label nInternalFaces() const noexcept
Number of internal faces.
Vector< scalar > vector
Definition: vector.H:57
label min(const labelHashSet &set, label minValue=labelMax)
Find the min value in labelHashSet, optionally limited by second argument.
Definition: hashSets.C:26
const vectorField & cellCentres() const
errorManip< error > abort(error &err)
Definition: errorManip.H:139
static void getSurfaceSets(const polyMesh &mesh, const fileName &surfName, const triSurface &surf, const triSurfaceSearch &querySurf, const pointField &outsidePts, const label nCutLayers, labelHashSet &inside, labelHashSet &outside, labelHashSet &cut)
Divide cells into cut,inside and outside.
Definition: surfaceSets.C:215
label nEdges() const
Number of mesh edges.
virtual bool write(const bool writeOnProc=true) const
Write mesh using IO settings from time.
Definition: fvMesh.C:1102
A polyBoundaryMesh is a polyPatch list with additional search methods and registered IO...
void removeBoundary()
Remove boundary patches.
Definition: polyMeshClear.C:32
bool empty() const noexcept
True if the hash table is empty.
Definition: HashTable.H:337
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
const word & constant() const noexcept
Return constant name.
Definition: TimePathsI.H:112
const vector & planeNormal() const
Return plane normal.
Empty front and back plane patch. Used for 2-D geometries.
const triSurface & surface() const
Return reference to the surface.
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
A topoSetCellSource to select cells based on relation to a surface given by an external file...
#define WarningInFunction
Report a warning using Foam::Warning.
string & expand(const bool allowEmpty=false)
Inplace expand initial tags, tildes, and all occurrences of environment variables as per stringOps::e...
Definition: string.C:166
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
A collection of cell labels.
Definition: cellSet.H:47
Direct mesh changes based on v1.3 polyTopoChange syntax.
const polyBoundaryMesh & patches
Automatically write from objectRegistry::writeObject()
messageStream Info
Information stream (stdout output on master, null elsewhere)
Pointer management similar to std::unique_ptr, with some additional methods and type checking...
Definition: HashPtrTable.H:48
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< Key > toc() const
The table of contents (the keys) in unsorted order.
Definition: HashTable.C:124
List< label > labelList
A List of labels.
Definition: List.H:62
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:69
Triangulated surface description with patch information.
Definition: triSurface.H:71
void addPatches(polyPatchList &plist, const bool validBoundary=true)
Add boundary patches.
Definition: polyMesh.C:971
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:172
const labelListList & cellCells() const
uindirectPrimitivePatch pp(UIndirectList< face >(mesh.faces(), faceLabels), mesh.points())
Namespace for OpenFOAM.
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:127