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