1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 option) any later version.
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
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM; if not, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*----------------------------------------------------------------------------*/
27 #include "autoRefineDriver.H"
28 #include "meshRefinement.H"
32 #include "mapDistributePolyMesh.H"
34 #include "syncTools.H"
35 #include "refinementParameters.H"
36 #include "featureEdgeMesh.H"
37 #include "refinementSurfaces.H"
38 #include "shellSurfaces.H"
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
45 defineTypeNameAndDebug(autoRefineDriver, 0);
47 } // End namespace Foam
50 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
52 // Read explicit feature edges
53 Foam::label Foam::autoRefineDriver::readFeatureEdges
55 const PtrList<dictionary>& featDicts,
56 PtrList<featureEdgeMesh>& featureMeshes,
57 labelList& featureLevels
60 Info<< "Reading external feature lines." << endl;
62 const fvMesh& mesh = meshRefiner_.mesh();
64 featureMeshes.setSize(featDicts.size());
65 featureLevels.setSize(featDicts.size());
69 const dictionary& dict = featDicts[i];
71 fileName featFileName(dict.lookup("file"));
81 mesh.time().findInstance("triSurface", featFileName),
83 "triSurface", // local
84 mesh.time(), // registry
92 featureMeshes[i].mergePoints(meshRefiner_.mergeDistance());
93 featureLevels[i] = readLabel(dict.lookup("level"));
95 Info<< "Refinement level " << featureLevels[i]
96 << " for all cells crossed by feature " << featFileName
97 << " (" << featureMeshes[i].points().size() << " points, "
98 << featureMeshes[i].edges().size() << " edges)." << endl;
101 Info<< "Read feature lines in = "
102 << mesh.time().cpuTimeIncrement() << " s" << nl << endl;
104 return featureMeshes.size();
108 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
110 // Construct from components
111 Foam::autoRefineDriver::autoRefineDriver
113 meshRefinement& meshRefiner,
114 decompositionMethod& decomposer,
115 fvMeshDistribute& distributor,
116 const labelList& globalToPatch
119 meshRefiner_(meshRefiner),
120 decomposer_(decomposer),
121 distributor_(distributor),
122 globalToPatch_(globalToPatch)
126 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
128 Foam::label Foam::autoRefineDriver::featureEdgeRefine
130 const refinementParameters& refineParams,
131 const PtrList<dictionary>& featDicts,
133 const label minRefine
136 const fvMesh& mesh = meshRefiner_.mesh();
138 // Read explicit feature edges
139 PtrList<featureEdgeMesh> featureMeshes;
140 // Per feature the refinement level
141 labelList featureLevels;
142 readFeatureEdges(featDicts, featureMeshes, featureLevels);
147 if (featureMeshes.size() && maxIter > 0)
149 for (; iter < maxIter; iter++)
152 << "Feature refinement iteration " << iter << nl
153 << "------------------------------" << nl
156 labelList candidateCells
158 meshRefiner_.refineCandidates
160 refineParams.keepPoints()[0], // For now only use one.
161 refineParams.curvature(),
166 true, // featureRefinement
167 false, // internalRefinement
168 false, // surfaceRefinement
169 false, // curvatureRefinement
170 refineParams.maxGlobalCells(),
171 refineParams.maxLocalCells()
174 labelList cellsToRefine
176 meshRefiner_.meshCutter().consistentRefinement
182 Info<< "Determined cells to refine in = "
183 << mesh.time().cpuTimeIncrement() << " s" << endl;
187 label nCellsToRefine = cellsToRefine.size();
188 reduce(nCellsToRefine, sumOp<label>());
190 Info<< "Selected for feature refinement : " << nCellsToRefine
191 << " cells (out of " << mesh.globalData().nTotalCells()
194 if (nCellsToRefine <= minRefine)
196 Info<< "Stopping refining since too few cells selected."
204 const_cast<Time&>(mesh.time())++;
207 meshRefiner_.refineAndBalance
209 "feature refinement iteration " + name(iter),
220 Foam::label Foam::autoRefineDriver::surfaceOnlyRefine
222 const refinementParameters& refineParams,
226 const fvMesh& mesh = meshRefiner_.mesh();
228 // Determine the maximum refinement level over all surfaces. This
229 // determines the minumum number of surface refinement iterations.
230 label overallMaxLevel = max(meshRefiner_.surfaces().maxLevel());
233 for (iter = 0; iter < maxIter; iter++)
236 << "Surface refinement iteration " << iter << nl
237 << "------------------------------" << nl
241 // Determine cells to refine
242 // ~~~~~~~~~~~~~~~~~~~~~~~~~
243 // Only look at surface intersections (minLevel and surface curvature),
244 // do not do internal refinement (refinementShells)
246 const PtrList<featureEdgeMesh> dummyFeatures;
248 labelList candidateCells
250 meshRefiner_.refineCandidates
252 refineParams.keepPoints()[0],
253 refineParams.curvature(),
255 dummyFeatures, // dummy featureMeshes;
256 labelList(0), // dummy featureLevels;
258 false, // featureRefinement
259 false, // internalRefinement
260 true, // surfaceRefinement
261 true, // curvatureRefinement
262 refineParams.maxGlobalCells(),
263 refineParams.maxLocalCells()
266 labelList cellsToRefine
268 meshRefiner_.meshCutter().consistentRefinement
274 Info<< "Determined cells to refine in = "
275 << mesh.time().cpuTimeIncrement() << " s" << endl;
278 label nCellsToRefine = cellsToRefine.size();
279 reduce(nCellsToRefine, sumOp<label>());
281 Info<< "Selected for refinement : " << nCellsToRefine
282 << " cells (out of " << mesh.globalData().nTotalCells()
285 // Stop when no cells to refine or have done minimum nessecary
286 // iterations and not enough cells to refine.
291 iter >= overallMaxLevel
292 && nCellsToRefine <= refineParams.minRefineCells()
296 Info<< "Stopping refining since too few cells selected."
304 const_cast<Time&>(mesh.time())++;
307 meshRefiner_.refineAndBalance
309 "surface refinement iteration " + name(iter),
319 void Foam::autoRefineDriver::removeInsideCells
321 const refinementParameters& refineParams,
322 const label nBufferLayers
326 << "Removing mesh beyond surface intersections" << nl
327 << "------------------------------------------" << nl
330 const fvMesh& mesh = meshRefiner_.mesh();
334 const_cast<Time&>(mesh.time())++;
337 meshRefiner_.splitMesh
339 nBufferLayers, // nBufferLayers
341 refineParams.keepPoints()[0]
346 Pout<< "Writing subsetted mesh to time "
347 << meshRefiner_.timeName() << '.' << endl;
348 meshRefiner_.write(debug, mesh.time().path()/meshRefiner_.timeName());
349 Pout<< "Dumped mesh in = "
350 << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
355 Foam::label Foam::autoRefineDriver::shellRefine
357 const refinementParameters& refineParams,
361 const fvMesh& mesh = meshRefiner_.mesh();
363 // Mark current boundary faces with 0. Have meshRefiner maintain them.
364 meshRefiner_.userFaceData().setSize(1);
366 // mark list to remove any refined faces
367 meshRefiner_.userFaceData()[0].first() = meshRefinement::REMOVE;
368 meshRefiner_.userFaceData()[0].second() = createWithValues<labelList>
372 meshRefiner_.intersectedFaces(),
376 // Determine the maximum refinement level over all volume refinement
377 // regions. This determines the minumum number of shell refinement
379 label overallMaxShellLevel = meshRefiner_.shells().maxLevel();
382 for (iter = 0; iter < maxIter; iter++)
385 << "Shell refinement iteration " << iter << nl
386 << "----------------------------" << nl
389 const PtrList<featureEdgeMesh> dummyFeatures;
391 labelList candidateCells
393 meshRefiner_.refineCandidates
395 refineParams.keepPoints()[0],
396 refineParams.curvature(),
398 dummyFeatures, // dummy featureMeshes;
399 labelList(0), // dummy featureLevels;
401 false, // featureRefinement
402 true, // internalRefinement
403 false, // surfaceRefinement
404 false, // curvatureRefinement
405 refineParams.maxGlobalCells(),
406 refineParams.maxLocalCells()
412 Pout<< "Dumping " << candidateCells.size()
413 << " cells to cellSet candidateCellsFromShells." << endl;
415 cellSet(mesh, "candidateCellsFromShells", candidateCells).write();
418 // Problem choosing starting faces for bufferlayers (bFaces)
419 // - we can't use the current intersected boundary faces
420 // (intersectedFaces) since this grows indefinitely
421 // - if we use 0 faces we don't satisfy bufferLayers from the
423 // - possibly we want to have bFaces only the initial set of faces
424 // and maintain the list while doing the refinement.
427 findIndices(meshRefiner_.userFaceData()[0].second(), 0)
430 //Info<< "Collected boundary faces : "
431 // << returnReduce(bFaces.size(), sumOp<label>()) << endl;
433 labelList cellsToRefine;
435 if (refineParams.nBufferLayers() <= 2)
437 cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement
439 refineParams.nBufferLayers(),
440 candidateCells, // cells to refine
441 bFaces, // faces for nBufferLayers
442 1, // point difference
443 meshRefiner_.intersectedPoints() // points to check
448 cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement2
450 refineParams.nBufferLayers(),
451 candidateCells, // cells to refine
452 bFaces // faces for nBufferLayers
456 Info<< "Determined cells to refine in = "
457 << mesh.time().cpuTimeIncrement() << " s" << endl;
460 label nCellsToRefine = cellsToRefine.size();
461 reduce(nCellsToRefine, sumOp<label>());
463 Info<< "Selected for internal refinement : " << nCellsToRefine
464 << " cells (out of " << mesh.globalData().nTotalCells()
467 // Stop when no cells to refine or have done minimum nessecary
468 // iterations and not enough cells to refine.
473 iter >= overallMaxShellLevel
474 && nCellsToRefine <= refineParams.minRefineCells()
478 Info<< "Stopping refining since too few cells selected."
486 const_cast<Time&>(mesh.time())++;
489 meshRefiner_.refineAndBalance
491 "shell refinement iteration " + name(iter),
497 meshRefiner_.userFaceData().clear();
503 void Foam::autoRefineDriver::baffleAndSplitMesh
505 const refinementParameters& refineParams,
506 const bool handleSnapProblems,
507 const dictionary& motionDict
511 << "Splitting mesh at surface intersections" << nl
512 << "---------------------------------------" << nl
515 const fvMesh& mesh = meshRefiner_.mesh();
517 // Introduce baffles at surface intersections. Note:
518 // meshRefiment::surfaceIndex() will
519 // be like boundary face from now on so not coupled anymore.
520 meshRefiner_.baffleAndSplitMesh
522 handleSnapProblems, // detect&remove potential snap problem
523 false, // perpendicular edge connected cells
524 scalarField(0), // per region perpendicular angle
525 !handleSnapProblems, // merge free standing baffles?
527 const_cast<Time&>(mesh.time()),
529 refineParams.keepPoints()[0]
534 void Foam::autoRefineDriver::zonify
536 const refinementParameters& refineParams
539 // Mesh is at its finest. Do zoning
540 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
541 // This puts all faces with intersection across a zoneable surface
542 // into that surface's faceZone. All cells inside faceZone get given the
545 if (meshRefiner_.surfaces().getNamedSurfaces().size())
548 << "Introducing zones for interfaces" << nl
549 << "--------------------------------" << nl
552 const fvMesh& mesh = meshRefiner_.mesh();
556 const_cast<Time&>(mesh.time())++;
559 meshRefiner_.zonify(refineParams.keepPoints()[0]);
563 Pout<< "Writing zoned mesh to time "
564 << meshRefiner_.timeName() << '.' << endl;
568 mesh.time().path()/meshRefiner_.timeName()
572 // Check that all faces are synced
573 meshRefinement::checkCoupledFaceZones(mesh);
578 void Foam::autoRefineDriver::splitAndMergeBaffles
580 const refinementParameters& refineParams,
581 const bool handleSnapProblems,
582 const dictionary& motionDict
586 << "Handling cells with snap problems" << nl
587 << "---------------------------------" << nl
590 const fvMesh& mesh = meshRefiner_.mesh();
592 // Introduce baffles and split mesh
595 const_cast<Time&>(mesh.time())++;
598 const scalarField& perpAngle = meshRefiner_.surfaces().perpendicularAngle();
600 meshRefiner_.baffleAndSplitMesh
603 handleSnapProblems, // remove perp edge connected cells
604 perpAngle, // perp angle
605 false, // merge free standing baffles?
607 const_cast<Time&>(mesh.time()),
609 refineParams.keepPoints()[0]
614 const_cast<Time&>(mesh.time())++;
617 // Duplicate points on baffles that are on more than one cell
618 // region. This will help snapping pull them to separate surfaces.
619 meshRefiner_.dupNonManifoldPoints();
622 // Merge all baffles that are still remaining after duplicating points.
623 List<labelPair> couples
625 meshRefiner_.getDuplicateFaces // get all baffles
627 identity(mesh.nFaces()-mesh.nInternalFaces())
628 + mesh.nInternalFaces()
632 label nCouples = returnReduce(couples.size(), sumOp<label>());
634 Info<< "Detected unsplittable baffles : "
639 // Actually merge baffles. Note: not exactly parallellized. Should
640 // convert baffle faces into processor faces if they resulted
642 meshRefiner_.mergeBaffles(couples);
646 // Debug:test all is still synced across proc patches
647 meshRefiner_.checkData();
649 Info<< "Merged free-standing baffles in = "
650 << mesh.time().cpuTimeIncrement() << " s." << endl;
655 Pout<< "Writing handleProblemCells mesh to time "
656 << meshRefiner_.timeName() << '.' << endl;
657 meshRefiner_.write(debug, mesh.time().path()/meshRefiner_.timeName());
662 void Foam::autoRefineDriver::mergePatchFaces
664 const refinementParameters& refineParams
667 const fvMesh& mesh = meshRefiner_.mesh();
670 << "Merge refined boundary faces" << nl
671 << "----------------------------" << nl
676 const_cast<Time&>(mesh.time())++;
679 meshRefiner_.mergePatchFaces
681 Foam::cos(45*mathematicalConstant::pi/180.0),
682 Foam::cos(45*mathematicalConstant::pi/180.0),
683 meshRefiner_.meshedPatches()
688 meshRefiner_.checkData();
691 meshRefiner_.mergeEdges(Foam::cos(45*mathematicalConstant::pi/180.0));
695 meshRefiner_.checkData();
700 void Foam::autoRefineDriver::doRefine
702 const dictionary& refineDict,
703 const refinementParameters& refineParams,
704 const bool prepareForSnapping,
705 const dictionary& motionDict
709 << "Refinement phase" << nl
710 << "----------------" << nl
713 const fvMesh& mesh = meshRefiner_.mesh();
715 // Check that all the keep points are inside the mesh.
716 refineParams.findCells(mesh);
718 PtrList<dictionary> featDicts(refineDict.lookup("features"));
720 // Refine around feature edges
726 0 // min cells to refine
729 // Refine based on surface
736 // Remove cells (a certain distance) beyond surface intersections
743 // Internal mesh refinement
750 // Introduce baffles at surface intersections
751 baffleAndSplitMesh(refineParams, prepareForSnapping, motionDict);
753 // Mesh is at its finest. Do optional zoning.
754 zonify(refineParams);
756 // Pull baffles apart
757 splitAndMergeBaffles(refineParams, prepareForSnapping, motionDict);
759 // Do something about cells with refined faces on the boundary
760 if (prepareForSnapping)
762 mergePatchFaces(refineParams);
766 if (Pstream::parRun())
769 << "Doing final balancing" << nl
770 << "---------------------" << nl
775 const_cast<Time&>(mesh.time())++;
778 // Do final balancing. Keep zoned faces on one processor.
790 // ************************************************************************* //