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