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 "syncTools.H"
33 #include "refinementParameters.H"
34 #include "featureEdgeMesh.H"
35 #include "refinementSurfaces.H"
36 #include "shellSurfaces.H"
37 #include "mapDistributePolyMesh.H"
38 #include "mathematicalConstants.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 mesh.time().constant(), // instance
84 "triSurface", // local
85 mesh.time(), // registry
93 featureMeshes[i].mergePoints(meshRefiner_.mergeDistance());
94 featureLevels[i] = readLabel(dict.lookup("level"));
96 Info<< "Refinement level " << featureLevels[i]
97 << " for all cells crossed by feature " << featFileName
98 << " (" << featureMeshes[i].points().size() << " points, "
99 << featureMeshes[i].edges().size() << " edges)." << endl;
102 Info<< "Read feature lines in = "
103 << mesh.time().cpuTimeIncrement() << " s" << nl << endl;
105 return featureMeshes.size();
109 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
111 // Construct from components
112 Foam::autoRefineDriver::autoRefineDriver
114 meshRefinement& meshRefiner,
115 decompositionMethod& decomposer,
116 fvMeshDistribute& distributor,
117 const labelList& globalToPatch
120 meshRefiner_(meshRefiner),
121 decomposer_(decomposer),
122 distributor_(distributor),
123 globalToPatch_(globalToPatch)
127 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
129 Foam::label Foam::autoRefineDriver::featureEdgeRefine
131 const refinementParameters& refineParams,
132 const PtrList<dictionary>& featDicts,
134 const label minRefine
137 const fvMesh& mesh = meshRefiner_.mesh();
139 // Read explicit feature edges
140 PtrList<featureEdgeMesh> featureMeshes;
141 // Per feature the refinement level
142 labelList featureLevels;
143 readFeatureEdges(featDicts, featureMeshes, featureLevels);
148 if (featureMeshes.size() && maxIter > 0)
150 for (; iter < maxIter; iter++)
153 << "Feature refinement iteration " << iter << nl
154 << "------------------------------" << nl
157 labelList candidateCells
159 meshRefiner_.refineCandidates
161 refineParams.keepPoints()[0], // For now only use one.
162 refineParams.curvature(),
167 true, // featureRefinement
168 false, // internalRefinement
169 false, // surfaceRefinement
170 false, // curvatureRefinement
171 refineParams.maxGlobalCells(),
172 refineParams.maxLocalCells()
175 labelList cellsToRefine
177 meshRefiner_.meshCutter().consistentRefinement
183 Info<< "Determined cells to refine in = "
184 << mesh.time().cpuTimeIncrement() << " s" << endl;
188 label nCellsToRefine = cellsToRefine.size();
189 reduce(nCellsToRefine, sumOp<label>());
191 Info<< "Selected for feature refinement : " << nCellsToRefine
192 << " cells (out of " << mesh.globalData().nTotalCells()
195 if (nCellsToRefine <= minRefine)
197 Info<< "Stopping refining since too few cells selected."
205 const_cast<Time&>(mesh.time())++;
213 (mesh.nCells() >= refineParams.maxLocalCells()),
218 meshRefiner_.balanceAndRefine
220 "feature refinement iteration " + name(iter),
224 refineParams.maxLoadUnbalance()
229 meshRefiner_.refineAndBalance
231 "feature refinement iteration " + name(iter),
235 refineParams.maxLoadUnbalance()
244 Foam::label Foam::autoRefineDriver::surfaceOnlyRefine
246 const refinementParameters& refineParams,
250 const fvMesh& mesh = meshRefiner_.mesh();
252 // Determine the maximum refinement level over all surfaces. This
253 // determines the minumum number of surface refinement iterations.
254 label overallMaxLevel = max(meshRefiner_.surfaces().maxLevel());
257 for (iter = 0; iter < maxIter; iter++)
260 << "Surface refinement iteration " << iter << nl
261 << "------------------------------" << nl
265 // Determine cells to refine
266 // ~~~~~~~~~~~~~~~~~~~~~~~~~
267 // Only look at surface intersections (minLevel and surface curvature),
268 // do not do internal refinement (refinementShells)
270 const PtrList<featureEdgeMesh> dummyFeatures;
272 labelList candidateCells
274 meshRefiner_.refineCandidates
276 refineParams.keepPoints()[0],
277 refineParams.curvature(),
279 dummyFeatures, // dummy featureMeshes;
280 labelList(0), // dummy featureLevels;
282 false, // featureRefinement
283 false, // internalRefinement
284 true, // surfaceRefinement
285 true, // curvatureRefinement
286 refineParams.maxGlobalCells(),
287 refineParams.maxLocalCells()
290 labelList cellsToRefine
292 meshRefiner_.meshCutter().consistentRefinement
298 Info<< "Determined cells to refine in = "
299 << mesh.time().cpuTimeIncrement() << " s" << endl;
302 label nCellsToRefine = cellsToRefine.size();
303 reduce(nCellsToRefine, sumOp<label>());
305 Info<< "Selected for refinement : " << nCellsToRefine
306 << " cells (out of " << mesh.globalData().nTotalCells()
309 // Stop when no cells to refine or have done minimum nessecary
310 // iterations and not enough cells to refine.
315 iter >= overallMaxLevel
316 && nCellsToRefine <= refineParams.minRefineCells()
320 Info<< "Stopping refining since too few cells selected."
328 const_cast<Time&>(mesh.time())++;
336 (mesh.nCells() >= refineParams.maxLocalCells()),
341 meshRefiner_.balanceAndRefine
343 "surface refinement iteration " + name(iter),
347 refineParams.maxLoadUnbalance()
352 meshRefiner_.refineAndBalance
354 "surface refinement iteration " + name(iter),
358 refineParams.maxLoadUnbalance()
366 void Foam::autoRefineDriver::removeInsideCells
368 const refinementParameters& refineParams,
369 const label nBufferLayers
373 << "Removing mesh beyond surface intersections" << nl
374 << "------------------------------------------" << nl
377 const fvMesh& mesh = meshRefiner_.mesh();
381 const_cast<Time&>(mesh.time())++;
384 meshRefiner_.splitMesh
386 nBufferLayers, // nBufferLayers
388 refineParams.keepPoints()[0]
393 Pout<< "Writing subsetted mesh to time "
394 << meshRefiner_.timeName() << '.' << endl;
395 meshRefiner_.write(debug, mesh.time().path()/meshRefiner_.timeName());
396 Pout<< "Dumped mesh in = "
397 << mesh.time().cpuTimeIncrement() << " s\n" << nl << endl;
402 Foam::label Foam::autoRefineDriver::shellRefine
404 const refinementParameters& refineParams,
408 const fvMesh& mesh = meshRefiner_.mesh();
410 // Mark current boundary faces with 0. Have meshRefiner maintain them.
411 meshRefiner_.userFaceData().setSize(1);
413 // mark list to remove any refined faces
414 meshRefiner_.userFaceData()[0].first() = meshRefinement::REMOVE;
415 meshRefiner_.userFaceData()[0].second() = createWithValues<labelList>
419 meshRefiner_.intersectedFaces(),
423 // Determine the maximum refinement level over all volume refinement
424 // regions. This determines the minumum number of shell refinement
426 label overallMaxShellLevel = meshRefiner_.shells().maxLevel();
429 for (iter = 0; iter < maxIter; iter++)
432 << "Shell refinement iteration " << iter << nl
433 << "----------------------------" << nl
436 const PtrList<featureEdgeMesh> dummyFeatures;
438 labelList candidateCells
440 meshRefiner_.refineCandidates
442 refineParams.keepPoints()[0],
443 refineParams.curvature(),
445 dummyFeatures, // dummy featureMeshes;
446 labelList(0), // dummy featureLevels;
448 false, // featureRefinement
449 true, // internalRefinement
450 false, // surfaceRefinement
451 false, // curvatureRefinement
452 refineParams.maxGlobalCells(),
453 refineParams.maxLocalCells()
459 Pout<< "Dumping " << candidateCells.size()
460 << " cells to cellSet candidateCellsFromShells." << endl;
462 cellSet(mesh, "candidateCellsFromShells", candidateCells).write();
465 // Problem choosing starting faces for bufferlayers (bFaces)
466 // - we can't use the current intersected boundary faces
467 // (intersectedFaces) since this grows indefinitely
468 // - if we use 0 faces we don't satisfy bufferLayers from the
470 // - possibly we want to have bFaces only the initial set of faces
471 // and maintain the list while doing the refinement.
474 findIndices(meshRefiner_.userFaceData()[0].second(), 0)
477 //Info<< "Collected boundary faces : "
478 // << returnReduce(bFaces.size(), sumOp<label>()) << endl;
480 labelList cellsToRefine;
482 if (refineParams.nBufferLayers() <= 2)
484 cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement
486 refineParams.nBufferLayers(),
487 candidateCells, // cells to refine
488 bFaces, // faces for nBufferLayers
489 1, // point difference
490 meshRefiner_.intersectedPoints() // points to check
495 cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement2
497 refineParams.nBufferLayers(),
498 candidateCells, // cells to refine
499 bFaces // faces for nBufferLayers
503 Info<< "Determined cells to refine in = "
504 << mesh.time().cpuTimeIncrement() << " s" << endl;
507 label nCellsToRefine = cellsToRefine.size();
508 reduce(nCellsToRefine, sumOp<label>());
510 Info<< "Selected for internal refinement : " << nCellsToRefine
511 << " cells (out of " << mesh.globalData().nTotalCells()
514 // Stop when no cells to refine or have done minimum nessecary
515 // iterations and not enough cells to refine.
520 iter >= overallMaxShellLevel
521 && nCellsToRefine <= refineParams.minRefineCells()
525 Info<< "Stopping refining since too few cells selected."
533 const_cast<Time&>(mesh.time())++;
540 (mesh.nCells() >= refineParams.maxLocalCells()),
545 meshRefiner_.balanceAndRefine
547 "shell refinement iteration " + name(iter),
551 refineParams.maxLoadUnbalance()
556 meshRefiner_.refineAndBalance
558 "shell refinement iteration " + name(iter),
562 refineParams.maxLoadUnbalance()
566 meshRefiner_.userFaceData().clear();
572 void Foam::autoRefineDriver::baffleAndSplitMesh
574 const refinementParameters& refineParams,
575 const bool handleSnapProblems,
576 const dictionary& motionDict
580 << "Splitting mesh at surface intersections" << nl
581 << "---------------------------------------" << nl
584 const fvMesh& mesh = meshRefiner_.mesh();
586 // Introduce baffles at surface intersections. Note:
587 // meshRefiment::surfaceIndex() will
588 // be like boundary face from now on so not coupled anymore.
589 meshRefiner_.baffleAndSplitMesh
591 handleSnapProblems, // detect&remove potential snap problem
592 false, // perpendicular edge connected cells
593 scalarField(0), // per region perpendicular angle
594 !handleSnapProblems, // merge free standing baffles?
596 const_cast<Time&>(mesh.time()),
598 refineParams.keepPoints()[0]
603 void Foam::autoRefineDriver::zonify
605 const refinementParameters& refineParams
608 // Mesh is at its finest. Do zoning
609 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
610 // This puts all faces with intersection across a zoneable surface
611 // into that surface's faceZone. All cells inside faceZone get given the
614 if (meshRefiner_.surfaces().getNamedSurfaces().size())
617 << "Introducing zones for interfaces" << nl
618 << "--------------------------------" << nl
621 const fvMesh& mesh = meshRefiner_.mesh();
625 const_cast<Time&>(mesh.time())++;
630 refineParams.keepPoints()[0],
631 refineParams.allowFreeStandingZoneFaces()
636 Pout<< "Writing zoned mesh to time "
637 << meshRefiner_.timeName() << '.' << endl;
641 mesh.time().path()/meshRefiner_.timeName()
645 // Check that all faces are synced
646 meshRefinement::checkCoupledFaceZones(mesh);
651 void Foam::autoRefineDriver::splitAndMergeBaffles
653 const refinementParameters& refineParams,
654 const bool handleSnapProblems,
655 const dictionary& motionDict
659 << "Handling cells with snap problems" << nl
660 << "---------------------------------" << nl
663 const fvMesh& mesh = meshRefiner_.mesh();
665 // Introduce baffles and split mesh
668 const_cast<Time&>(mesh.time())++;
671 const scalarField& perpAngle = meshRefiner_.surfaces().perpendicularAngle();
673 meshRefiner_.baffleAndSplitMesh
676 handleSnapProblems, // remove perp edge connected cells
677 perpAngle, // perp angle
678 false, // merge free standing baffles?
680 const_cast<Time&>(mesh.time()),
682 refineParams.keepPoints()[0]
687 const_cast<Time&>(mesh.time())++;
690 // Duplicate points on baffles that are on more than one cell
691 // region. This will help snapping pull them to separate surfaces.
692 meshRefiner_.dupNonManifoldPoints();
695 // Merge all baffles that are still remaining after duplicating points.
696 List<labelPair> couples
698 meshRefiner_.getDuplicateFaces // get all baffles
700 identity(mesh.nFaces()-mesh.nInternalFaces())
701 + mesh.nInternalFaces()
705 label nCouples = returnReduce(couples.size(), sumOp<label>());
707 Info<< "Detected unsplittable baffles : "
712 // Actually merge baffles. Note: not exactly parallellized. Should
713 // convert baffle faces into processor faces if they resulted
715 meshRefiner_.mergeBaffles(couples);
719 // Debug:test all is still synced across proc patches
720 meshRefiner_.checkData();
722 Info<< "Merged free-standing baffles in = "
723 << mesh.time().cpuTimeIncrement() << " s." << endl;
728 Pout<< "Writing handleProblemCells mesh to time "
729 << meshRefiner_.timeName() << '.' << endl;
730 meshRefiner_.write(debug, mesh.time().path()/meshRefiner_.timeName());
735 void Foam::autoRefineDriver::mergePatchFaces
737 const refinementParameters& refineParams
740 const fvMesh& mesh = meshRefiner_.mesh();
743 << "Merge refined boundary faces" << nl
744 << "----------------------------" << nl
749 const_cast<Time&>(mesh.time())++;
752 meshRefiner_.mergePatchFaces
754 Foam::cos(45*mathematicalConstant::pi/180.0),
755 Foam::cos(45*mathematicalConstant::pi/180.0),
756 meshRefiner_.meshedPatches()
761 meshRefiner_.checkData();
764 meshRefiner_.mergeEdges(Foam::cos(45*mathematicalConstant::pi/180.0));
768 meshRefiner_.checkData();
773 void Foam::autoRefineDriver::doRefine
775 const dictionary& refineDict,
776 const refinementParameters& refineParams,
777 const bool prepareForSnapping,
778 const dictionary& motionDict
782 << "Refinement phase" << nl
783 << "----------------" << nl
786 const fvMesh& mesh = meshRefiner_.mesh();
788 // Check that all the keep points are inside the mesh.
789 refineParams.findCells(mesh);
791 PtrList<dictionary> featDicts(refineDict.lookup("features"));
793 // Refine around feature edges
799 0 // min cells to refine
802 // Refine based on surface
809 // Remove cells (a certain distance) beyond surface intersections
816 // Internal mesh refinement
823 // Introduce baffles at surface intersections
824 baffleAndSplitMesh(refineParams, prepareForSnapping, motionDict);
826 // Mesh is at its finest. Do optional zoning.
827 zonify(refineParams);
829 // Pull baffles apart
830 splitAndMergeBaffles(refineParams, prepareForSnapping, motionDict);
832 // Do something about cells with refined faces on the boundary
833 if (prepareForSnapping)
835 mergePatchFaces(refineParams);
839 if (Pstream::parRun())
842 << "Doing final balancing" << nl
843 << "---------------------" << nl
848 const_cast<Time&>(mesh.time())++;
851 // Do final balancing. Keep zoned faces on one processor since the
852 // snap phase will convert them to baffles and this only works for
858 scalarField(mesh.nCells(), 1), // dummy weights
866 // ************************************************************************* //