ENH: balancing before refinement
[OpenFOAM-1.6.x.git] / src / autoMesh / autoHexMesh / autoHexMeshDriver / autoRefineDriver.C
blobccc63d2608a813fcd8c919d73d9e746e5f112e5f
1 /*---------------------------------------------------------------------------*\
2   =========                 |
3   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
4    \\    /   O peration     |
5     \\  /    A nd           | Copyright (C) 1991-2009 OpenCFD Ltd.
6      \\/     M anipulation  |
7 -------------------------------------------------------------------------------
8 License
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
19     for more details.
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"
29 #include "fvMesh.H"
30 #include "Time.H"
31 #include "cellSet.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 * * * * * * * * * * * * * //
42 namespace Foam
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
58 ) const
60     Info<< "Reading external feature lines." << endl;
62     const fvMesh& mesh = meshRefiner_.mesh();
64     featureMeshes.setSize(featDicts.size());
65     featureLevels.setSize(featDicts.size());
67     forAll(featDicts, i)
68     {
69         const dictionary& dict = featDicts[i];
71         fileName featFileName(dict.lookup("file"));
73         featureMeshes.set
74         (
75             i,
76             new featureEdgeMesh
77             (
78                 IOobject
79                 (
80                     featFileName,                       // name
81                     //mesh.time().findInstance("triSurface", featFileName),
82                     //                                    // instance
83                     mesh.time().constant(),             // instance
84                     "triSurface",                       // local
85                     mesh.time(),                        // registry
86                     IOobject::MUST_READ,
87                     IOobject::NO_WRITE,
88                     false
89                 )
90             )
91         );
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;
100     }
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,
133     const label maxIter,
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);
146     label iter = 0;
148     if (featureMeshes.size() && maxIter > 0)
149     {
150         for (; iter < maxIter; iter++)
151         {
152             Info<< nl
153                 << "Feature refinement iteration " << iter << nl
154                 << "------------------------------" << nl
155                 << endl;
157             labelList candidateCells
158             (
159                 meshRefiner_.refineCandidates
160                 (
161                     refineParams.keepPoints()[0],    // For now only use one.
162                     refineParams.curvature(),
164                     featureMeshes,
165                     featureLevels,
167                     true,               // featureRefinement
168                     false,              // internalRefinement
169                     false,              // surfaceRefinement
170                     false,              // curvatureRefinement
171                     refineParams.maxGlobalCells(),
172                     refineParams.maxLocalCells()
173                 )
174             );
175             labelList cellsToRefine
176             (
177                 meshRefiner_.meshCutter().consistentRefinement
178                 (
179                     candidateCells,
180                     true
181                 )
182             );
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()
193                 << ')' << endl;
195             if (nCellsToRefine <= minRefine)
196             {
197                 Info<< "Stopping refining since too few cells selected."
198                     << nl << endl;
199                 break;
200             }
203             if (debug > 0)
204             {
205                 const_cast<Time&>(mesh.time())++;
206             }
209             if
210             (
211                 returnReduce
212                 (
213                     (mesh.nCells() >= refineParams.maxLocalCells()),
214                     orOp<bool>()
215                 )
216             )
217             {
218                 meshRefiner_.balanceAndRefine
219                 (
220                     "feature refinement iteration " + name(iter),
221                     decomposer_,
222                     distributor_,
223                     cellsToRefine,
224                     refineParams.maxLoadUnbalance()
225                 );
226             }
227             else
228             {
229                 meshRefiner_.refineAndBalance
230                 (
231                     "feature refinement iteration " + name(iter),
232                     decomposer_,
233                     distributor_,
234                     cellsToRefine,
235                     refineParams.maxLoadUnbalance()
236                 );
237             }
238         }
239     }
240     return iter;
244 Foam::label Foam::autoRefineDriver::surfaceOnlyRefine
246     const refinementParameters& refineParams,
247     const label maxIter
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());
256     label iter;
257     for (iter = 0; iter < maxIter; iter++)
258     {
259         Info<< nl
260             << "Surface refinement iteration " << iter << nl
261             << "------------------------------" << nl
262             << endl;
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
273         (
274             meshRefiner_.refineCandidates
275             (
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()
288             )
289         );
290         labelList cellsToRefine
291         (
292             meshRefiner_.meshCutter().consistentRefinement
293             (
294                 candidateCells,
295                 true
296             )
297         );
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()
307             << ')' << endl;
309         // Stop when no cells to refine or have done minimum nessecary
310         // iterations and not enough cells to refine.
311         if
312         (
313             nCellsToRefine == 0
314          || (
315                 iter >= overallMaxLevel
316              && nCellsToRefine <= refineParams.minRefineCells()
317             )
318         )
319         {
320             Info<< "Stopping refining since too few cells selected."
321                 << nl << endl;
322             break;
323         }
326         if (debug)
327         {
328             const_cast<Time&>(mesh.time())++;
329         }
332         if
333         (
334             returnReduce
335             (
336                 (mesh.nCells() >= refineParams.maxLocalCells()),
337                 orOp<bool>()
338             )
339         )
340         {
341             meshRefiner_.balanceAndRefine
342             (
343                 "surface refinement iteration " + name(iter),
344                 decomposer_,
345                 distributor_,
346                 cellsToRefine,
347                 refineParams.maxLoadUnbalance()
348             );
349         }
350         else
351         {
352             meshRefiner_.refineAndBalance
353             (
354                 "surface refinement iteration " + name(iter),
355                 decomposer_,
356                 distributor_,
357                 cellsToRefine,
358                 refineParams.maxLoadUnbalance()
359             );
360         }
361     }
362     return iter;
366 void Foam::autoRefineDriver::removeInsideCells
368     const refinementParameters& refineParams,
369     const label nBufferLayers
372     Info<< nl
373         << "Removing mesh beyond surface intersections" << nl
374         << "------------------------------------------" << nl
375         << endl;
377     const fvMesh& mesh = meshRefiner_.mesh();
379     if (debug)
380     {
381        const_cast<Time&>(mesh.time())++;
382     }
384     meshRefiner_.splitMesh
385     (
386         nBufferLayers,                  // nBufferLayers
387         globalToPatch_,
388         refineParams.keepPoints()[0]
389     );
391     if (debug)
392     {
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;
398     }
402 Foam::label Foam::autoRefineDriver::shellRefine
404     const refinementParameters& refineParams,
405     const label maxIter
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>
416     (
417         mesh.nFaces(),
418         -1,
419         meshRefiner_.intersectedFaces(),
420         0
421     );
423     // Determine the maximum refinement level over all volume refinement
424     // regions. This determines the minumum number of shell refinement
425     // iterations.
426     label overallMaxShellLevel = meshRefiner_.shells().maxLevel();
428     label iter;
429     for (iter = 0; iter < maxIter; iter++)
430     {
431         Info<< nl
432             << "Shell refinement iteration " << iter << nl
433             << "----------------------------" << nl
434             << endl;
436         const PtrList<featureEdgeMesh> dummyFeatures;
438         labelList candidateCells
439         (
440             meshRefiner_.refineCandidates
441             (
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()
454             )
455         );
457         if (debug)
458         {
459             Pout<< "Dumping " << candidateCells.size()
460                 << " cells to cellSet candidateCellsFromShells." << endl;
462             cellSet(mesh, "candidateCellsFromShells", candidateCells).write();
463         }
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
469         //    surface.
470         //  - possibly we want to have bFaces only the initial set of faces
471         //    and maintain the list while doing the refinement.
472         labelList bFaces
473         (
474             findIndices(meshRefiner_.userFaceData()[0].second(), 0)
475         );
477         //Info<< "Collected boundary faces : "
478         //    << returnReduce(bFaces.size(), sumOp<label>()) << endl;
480         labelList cellsToRefine;
482         if (refineParams.nBufferLayers() <= 2)
483         {
484             cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement
485             (
486                 refineParams.nBufferLayers(),
487                 candidateCells,                     // cells to refine
488                 bFaces,                             // faces for nBufferLayers
489                 1,                                  // point difference
490                 meshRefiner_.intersectedPoints()    // points to check
491             );
492         }
493         else
494         {
495             cellsToRefine = meshRefiner_.meshCutter().consistentSlowRefinement2
496             (
497                 refineParams.nBufferLayers(),
498                 candidateCells,                 // cells to refine
499                 bFaces                          // faces for nBufferLayers
500             );
501         }
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()
512             << ')' << endl;
514         // Stop when no cells to refine or have done minimum nessecary
515         // iterations and not enough cells to refine.
516         if
517         (
518             nCellsToRefine == 0
519          || (
520                 iter >= overallMaxShellLevel
521              && nCellsToRefine <= refineParams.minRefineCells()
522             )
523         )
524         {
525             Info<< "Stopping refining since too few cells selected."
526                 << nl << endl;
527             break;
528         }
531         if (debug)
532         {
533             const_cast<Time&>(mesh.time())++;
534         }
536         if
537         (
538             returnReduce
539             (
540                 (mesh.nCells() >= refineParams.maxLocalCells()),
541                 orOp<bool>()
542             )
543         )
544         {
545             meshRefiner_.balanceAndRefine
546             (
547                 "shell refinement iteration " + name(iter),
548                 decomposer_,
549                 distributor_,
550                 cellsToRefine,
551                 refineParams.maxLoadUnbalance()
552             );
553         }
554         else
555         {
556             meshRefiner_.refineAndBalance
557             (
558                 "shell refinement iteration " + name(iter),
559                 decomposer_,
560                 distributor_,
561                 cellsToRefine,
562                 refineParams.maxLoadUnbalance()
563             );
564         }
565     }
566     meshRefiner_.userFaceData().clear();
568     return iter;
572 void Foam::autoRefineDriver::baffleAndSplitMesh
574     const refinementParameters& refineParams,
575     const bool handleSnapProblems,
576     const dictionary& motionDict
579     Info<< nl
580         << "Splitting mesh at surface intersections" << nl
581         << "---------------------------------------" << nl
582         << endl;
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
590     (
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?
595         motionDict,
596         const_cast<Time&>(mesh.time()),
597         globalToPatch_,
598         refineParams.keepPoints()[0]
599     );
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
612     // same cellZone.
614     if (meshRefiner_.surfaces().getNamedSurfaces().size())
615     {
616         Info<< nl
617             << "Introducing zones for interfaces" << nl
618             << "--------------------------------" << nl
619             << endl;
621         const fvMesh& mesh = meshRefiner_.mesh();
623         if (debug)
624         {
625             const_cast<Time&>(mesh.time())++;
626         }
628         meshRefiner_.zonify
629         (
630             refineParams.keepPoints()[0],
631             refineParams.allowFreeStandingZoneFaces()
632         );
634         if (debug)
635         {
636             Pout<< "Writing zoned mesh to time "
637                 << meshRefiner_.timeName() << '.' << endl;
638             meshRefiner_.write
639             (
640                 debug,
641                 mesh.time().path()/meshRefiner_.timeName()
642             );
643         }
645         // Check that all faces are synced
646         meshRefinement::checkCoupledFaceZones(mesh);
647     }
651 void Foam::autoRefineDriver::splitAndMergeBaffles
653     const refinementParameters& refineParams,
654     const bool handleSnapProblems,
655     const dictionary& motionDict
658     Info<< nl
659         << "Handling cells with snap problems" << nl
660         << "---------------------------------" << nl
661         << endl;
663     const fvMesh& mesh = meshRefiner_.mesh();
665     // Introduce baffles and split mesh
666     if (debug)
667     {
668         const_cast<Time&>(mesh.time())++;
669     }
671     const scalarField& perpAngle = meshRefiner_.surfaces().perpendicularAngle();
673     meshRefiner_.baffleAndSplitMesh
674     (
675         handleSnapProblems,
676         handleSnapProblems,                 // remove perp edge connected cells
677         perpAngle,                          // perp angle
678         false,                              // merge free standing baffles?
679         motionDict,
680         const_cast<Time&>(mesh.time()),
681         globalToPatch_,
682         refineParams.keepPoints()[0]
683     );
685     if (debug)
686     {
687         const_cast<Time&>(mesh.time())++;
688     }
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
697     (
698         meshRefiner_.getDuplicateFaces   // get all baffles
699         (
700             identity(mesh.nFaces()-mesh.nInternalFaces())
701           + mesh.nInternalFaces()
702         )
703     );
705     label nCouples = returnReduce(couples.size(), sumOp<label>());
707     Info<< "Detected unsplittable baffles : "
708         << nCouples << endl;
710     if (nCouples > 0)
711     {
712         // Actually merge baffles. Note: not exactly parallellized. Should
713         // convert baffle faces into processor faces if they resulted
714         // from them.
715         meshRefiner_.mergeBaffles(couples);
717         if (debug)
718         {
719             // Debug:test all is still synced across proc patches
720             meshRefiner_.checkData();
721         }
722         Info<< "Merged free-standing baffles in = "
723             << mesh.time().cpuTimeIncrement() << " s." << endl;
724     }
726     if (debug)
727     {
728         Pout<< "Writing handleProblemCells mesh to time "
729             << meshRefiner_.timeName() << '.' << endl;
730         meshRefiner_.write(debug, mesh.time().path()/meshRefiner_.timeName());
731     }
735 void Foam::autoRefineDriver::mergePatchFaces
737     const refinementParameters& refineParams
740     const fvMesh& mesh = meshRefiner_.mesh();
742     Info<< nl
743         << "Merge refined boundary faces" << nl
744         << "----------------------------" << nl
745         << endl;
747     if (debug)
748     {
749         const_cast<Time&>(mesh.time())++;
750     }
752     meshRefiner_.mergePatchFaces
753     (
754         Foam::cos(45*mathematicalConstant::pi/180.0),
755         Foam::cos(45*mathematicalConstant::pi/180.0),
756         meshRefiner_.meshedPatches()
757     );
759     if (debug)
760     {
761         meshRefiner_.checkData();
762     }
764     meshRefiner_.mergeEdges(Foam::cos(45*mathematicalConstant::pi/180.0));
766     if (debug)
767     {
768         meshRefiner_.checkData();
769     }
773 void Foam::autoRefineDriver::doRefine
775     const dictionary& refineDict,
776     const refinementParameters& refineParams,
777     const bool prepareForSnapping,
778     const dictionary& motionDict
781     Info<< nl
782         << "Refinement phase" << nl
783         << "----------------" << nl
784         << endl;
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
794     featureEdgeRefine
795     (
796         refineParams,
797         featDicts,
798         100,    // maxIter
799         0       // min cells to refine
800     );
802     // Refine based on surface
803     surfaceOnlyRefine
804     (
805         refineParams,
806         100     // maxIter
807     );
809     // Remove cells (a certain distance) beyond surface intersections
810     removeInsideCells
811     (
812         refineParams,
813         1       // nBufferLayers
814     );
816     // Internal mesh refinement
817     shellRefine
818     (
819         refineParams,
820         100    // maxIter
821     );
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)
834     {
835         mergePatchFaces(refineParams);
836     }
839     if (Pstream::parRun())
840     {
841         Info<< nl
842             << "Doing final balancing" << nl
843             << "---------------------" << nl
844             << endl;
846         if (debug)
847         {
848             const_cast<Time&>(mesh.time())++;
849         }
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
853         // internal faces.
854         meshRefiner_.balance
855         (
856             true,
857             false,
858             scalarField(mesh.nCells(), 1), // dummy weights
859             decomposer_,
860             distributor_
861         );
862     }
866 // ************************************************************************* //