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-2018 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 "mapPolyMesh.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<mapPolyMesh> morphMap = meshMod.changeMesh(mesh, false);
517 
518  if (morphMap().hasMotionPoints())
519  {
520  mesh.movePoints(morphMap().preMotionPoints());
521  }
522 
523  // Update topology on cellRemover
524  cellRemover.updateMesh(morphMap());
525 
526  // Update refLevel for removed cells.
527  const labelList& cellMap = morphMap().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.timeName() << nl
542  << endl;
543 
545  mesh.write();
546  refLevel.write();
547  }
548 
549  // Update cutCells for removed cells.
550  cutCells.updateMesh(morphMap());
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 
642  IOobject motionObj
643  (
644  "motionProperties",
645  runTime.constant(),
646  mesh,
649  );
650 
651  // corrector for mesh motion
652  twoDPointCorrector* correct2DPtr = nullptr;
653 
654  if (motionObj.typeHeaderOk<IOdictionary>(true))
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 = new twoDPointCorrector(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(readLabel(refineDict.lookup("nCutLayers")));
685  label cellLimit(readLabel(refineDict.lookup("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(readScalar(refineDict.lookup("minEdgeLen")));
692  scalar maxEdgeLen(readScalar(refineDict.lookup("maxEdgeLen")));
693  scalar curvature(readScalar(refineDict.lookup("curvature")));
694  scalar curvDist(readScalar(refineDict.lookup("curvatureDistance")));
695  pointField outsidePts(refineDict.lookup("outsidePoints"));
696  label refinementLimit(readLabel(refineDict.lookup("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.timeName(),
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.objectPath() << 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.objectPath() << 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.timeName()
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.timeName() << 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.timeName() << 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 // ************************************************************************* //
const polyBoundaryMesh & boundaryMesh() const
Return boundary mesh.
Definition: polyMesh.H:434
Various (local, not parallel) searches on polyMesh; uses (demand driven) octree to search...
Definition: meshSearch.H:57
virtual tmp< scalarField > movePoints(const pointField &)
Move points, returns volumes swept by faces in motion.
Definition: polyMesh.C:1287
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:434
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
const word & name() const
Return name.
Definition: IOobject.H:295
A class for handling file names.
Definition: fileName.H:79
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
error FatalError
A list of keyword definitions, which are a keyword followed by any number of values (e...
Definition: dictionary.H:158
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:319
label nInternalFaces() const
virtual const labelList & faceNeighbour() const
Return face neighbour.
Definition: polyMesh.C:1175
Cell-face mesh analysis engine.
Definition: primitiveMesh.H:74
uint8_t direction
Definition: direction.H:45
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:461
Does multiple pass refinement to refine cells in multiple directions.
void size(const label)
Override size to be inconsistent with allocated storage.
Definition: ListI.H:163
bool empty() const
Return true if the hash table is empty.
Definition: HashTableI.H:72
Given list of cells to remove insert all the topology changes.
Definition: removeCells.H:59
label nCells() const
static word defaultRegion
Return the default region name.
Definition: polyMesh.H:309
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:256
virtual void updateMesh(const mapPolyMesh &morphMap)
Update any stored data for new labels.
Definition: cellSet.C:225
A simple wrapper around bool so that it can be read as a word: true/false, on/off, yes/no, y/n, t/f, or none/any.
Definition: Switch.H:60
virtual const pointField & points() const =0
Return mesh points.
label findPatchID(const word &patchName) const
Find patch index given a name.
static void noParallel()
Remove the parallel options.
Definition: argList.C:174
A bounding box defined in terms of the points at its extremities.
Definition: boundBox.H:58
const cellList & cells() const
static word timeName(const scalar, const int precision=precision_)
Return time name of given scalar time.
Definition: Time.C:626
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
bool readBool(Istream &)
Definition: boolIO.C:60
patches[0]
bool insert(const Key &key)
Insert a new entry.
Definition: HashSet.H:108
Class to control time during OpenFOAM simulations that is also the top-level objectRegistry.
Definition: Time.H:68
label size() const
Return number of elements in table.
Definition: HashTableI.H:65
static labelHashSet getHangingCells(const primitiveMesh &mesh, const labelHashSet &internalCells)
Get cells using points on &#39;outside&#39; only.
Definition: surfaceSets.C:282
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:52
HashSet< label, Hash< label > > labelHashSet
A HashSet with label keys.
Definition: HashSet.H:208
virtual autoPtr< polyPatch > clone(const polyBoundaryMesh &bm) const
Construct and return a clone, resetting the boundary mesh.
Definition: polyPatch.H:222
Helper class to search on triSurface.
scalar y
vectorField pointField
pointField is a vectorField.
Definition: pointFieldFwd.H:42
dynamicFvMesh & mesh
An edge is a list of two point labels. The functionality it provides supports the discretisation on a...
Definition: edge.H:58
bool found(const Key &) const
Return true if hashedEntry is found in table.
Definition: HashTable.C:113
Class applies a two-dimensional correction to mesh motion point field.
A class for handling words, derived from string.
Definition: word.H:59
const fileName & local() const
Definition: IOobject.H:388
const word & constant() const
Return constant name.
Definition: TimePaths.H:124
virtual const labelList & faceOwner() const
Return face owner.
Definition: polyMesh.C:1169
List< label > labelList
A List of labels.
Definition: labelList.H:56
bool readScalar(const char *buf, doubleScalar &s)
Read whole of buf as a scalar. Return true if successful.
Definition: doubleScalar.H:68
const vectorField & cellCentres() const
forAllConstIter(PtrDictionary< phaseModel >, mixture.phases(), phase)
Definition: pEqn.H:29
errorManip< error > abort(error &err)
Definition: errorManip.H:131
label readLabel(Istream &is)
Definition: label.H:64
virtual void addSet(const topoSet &set)
Add elements present in set.
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
void addPatches(const List< polyPatch *> &, const bool validBoundary=true)
Add boundary patches.
Definition: polyMesh.C:909
const word & system() const
Return system name.
Definition: TimePaths.H:114
Foam::polyBoundaryMesh.
bool isInternalFace(const label faceIndex) const
Return true if given face label is internal to the mesh.
void removeBoundary()
Remove boundary patches.
Definition: polyMeshClear.C:36
vector vec(const pointField &) const
Return the vector (end - start)
Definition: edgeI.H:175
static const char nl
Definition: Ostream.H:265
const vector & planeNormal() const
Return plane normal.
const Time & time() const
Return time.
Empty front and back plane patch. Used for 2-D geometries.
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
const triSurface & surface() const
Return reference to the surface.
label nEdges() const
label size() const
Return the number of elements in the UPtrList.
Definition: UPtrListI.H:29
const edgeList & edges() const
Return mesh edges. Uses calcEdges.
A topoSetSource to select cells based on relation to surface.
Definition: surfaceToCell.H:60
void setSize(const label)
Reset size of List.
Definition: List.C:281
const fileName & instance() const
Definition: IOobject.H:378
label patchi
#define WarningInFunction
Report a warning using Foam::Warning.
string & expand(const bool allowEmpty=false)
Expand initial tildes and all occurrences of environment variables.
Definition: string.C:95
A collection of cell labels.
Definition: cellSet.H:48
virtual void subset(const topoSet &set)
Subset contents. Only elements present in both sets remain.
Direct mesh changes based on v1.3 polyTopoChange syntax.
label start() const
Return start label of this patch in the polyMesh face list.
Definition: polyPatch.H:303
messageStream Info
dimensioned< scalar > mag(const dimensioned< Type > &)
An auto-pointer similar to the STL auto_ptr but with automatic casting to a reference to the type and...
Definition: PtrList.H:52
Mesh consisting of general polyhedral cells.
Definition: polyMesh.H:74
List< Key > toc() const
Return the table of contents.
Definition: HashTable.C:202
virtual bool write(const bool write=true) const
Write using setting from DB.
A patch is a list of labels that address the faces in the global face list.
Definition: polyPatch.H:66
Triangulated surface description with patch information.
Definition: triSurface.H:66
IOobject defines the attributes of an object for which implicit objectRegistry management is supporte...
Definition: IOobject.H:92
fileName objectPath() const
Return complete path + object name.
Definition: IOobject.H:404
const labelListList & cellCells() const
void transfer(List< T > &)
Transfer the contents of the argument List into this list.
Definition: List.C:342
Namespace for OpenFOAM.
ITstream & lookup(const word &, bool recursive=false, bool patternMatch=true) const
Find and return an entry data stream.
Definition: dictionary.C:583