ENH: snappyHexMesh: enable late balancing. Fixes #2792

This commit is contained in:
Mattijs Janssens
2023-06-21 14:25:17 +00:00
committed by Andrew Heather
parent da98104a79
commit d3419e4e56
6 changed files with 254 additions and 163 deletions

View File

@ -100,8 +100,8 @@ castellatedMeshControls
// ~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~
// If local number of cells is >= maxLocalCells on any processor // If local number of cells is >= maxLocalCells on any processor
// switches from from refinement followed by balancing // algorithm switches from refinement followed by (weighted) balancing
// (current method) to (weighted) balancing before refinement. // to (weighted) balancing followed by refinement.
maxLocalCells 100000; maxLocalCells 100000;
// Overall cell limit (approximately). Refinement will stop immediately // Overall cell limit (approximately). Refinement will stop immediately
@ -123,9 +123,24 @@ castellatedMeshControls
// Allow a certain level of imbalance during refining // Allow a certain level of imbalance during refining
// (since balancing is quite expensive) // (since balancing is quite expensive)
// Expressed as fraction of perfect balance (= overall number of cells / // Expressed as fraction of perfect balance (= overall number of cells /
// nProcs). 0=balance always. // nProcs). 0=balance always. Can be triggered by using maxCellUnbalance
maxLoadUnbalance 0.10; maxLoadUnbalance 0.10;
// Optional absolute unbalance start trigger. Used to avoid balancing
// in first refinement iterations since balancing is expensive for
// high core counts
// The trigger value is used for two checks:
// a: if on any processor the number of new added cells <= maxCellUnbalance
// the balancing is skipped
// b: if on any processor the value
// (new cell count of proc - idealCellCount) <= maxCellUnbalance
// the balancing is skipped
// Set to -1 to deactivate
//maxCellUnbalance 200000;
// Optional forcing balancing after the mesh is completely refined
//balanceAtEnd false;
// Number of buffer layers between different levels. // Number of buffer layers between different levels.
// 1 means normal 2:1 refinement restriction, larger means slower // 1 means normal 2:1 refinement restriction, larger means slower
// refinement. // refinement.

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd. Copyright (C) 2015-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -1271,6 +1271,17 @@ public:
//- Refine some cells //- Refine some cells
autoPtr<mapPolyMesh> refine(const labelList& cellsToRefine); autoPtr<mapPolyMesh> refine(const labelList& cellsToRefine);
//- Balance the mesh
autoPtr<mapDistributePolyMesh> balance
(
const string& msg,
decompositionMethod& decomposer,
fvMeshDistribute& distributor,
labelList& cellsToRefine,
const scalar maxLoadUnbalance,
const label maxCellUnbalance
);
//- Refine some cells and rebalance //- Refine some cells and rebalance
autoPtr<mapDistributePolyMesh> refineAndBalance autoPtr<mapDistributePolyMesh> refineAndBalance
( (
@ -1278,7 +1289,8 @@ public:
decompositionMethod& decomposer, decompositionMethod& decomposer,
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelList& cellsToRefine, const labelList& cellsToRefine,
const scalar maxLoadUnbalance const scalar maxLoadUnbalance,
const label maxCellUnbalance
); );
//- Balance before refining some cells //- Balance before refining some cells
@ -1288,7 +1300,8 @@ public:
decompositionMethod& decomposer, decompositionMethod& decomposer,
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelList& cellsToRefine, const labelList& cellsToRefine,
const scalar maxLoadUnbalance const scalar maxLoadUnbalance,
const label maxCellUnbalance
); );
//- Calculate list of cells to directionally refine //- Calculate list of cells to directionally refine

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation Copyright (C) 2011-2017 OpenFOAM Foundation
Copyright (C) 2015-2022 OpenCFD Ltd. Copyright (C) 2015-2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -2598,6 +2598,120 @@ Foam::autoPtr<Foam::mapPolyMesh> Foam::meshRefinement::refine
} }
// Load balancing
Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::meshRefinement::balance
(
const string& msg,
decompositionMethod& decomposer,
fvMeshDistribute& distributor,
labelList& cellsToRefine,
const scalar maxLoadUnbalance,
const label maxCellUnbalance
)
{
autoPtr<mapDistributePolyMesh> distMap;
if (Pstream::nProcs() > 1)
{
// First check if we need to balance at all. Precalculate number of
// cells after refinement and see what maximum difference is.
const scalar nNewCells =
scalar(mesh_.nCells() + 7*cellsToRefine.size());
const scalar nNewCellsAll = returnReduce(nNewCells, sumOp<scalar>());
const scalar nIdealNewCells = nNewCellsAll / Pstream::nProcs();
const scalar unbalance = returnReduce
(
mag(1.0-nNewCells/nIdealNewCells),
maxOp<scalar>()
);
// Trigger the balancing to avoid too early balancing for better
// scaling performance.
const scalar nNewCellsOnly = scalar(7*cellsToRefine.size());
const label maxNewCells =
label(returnReduce(nNewCellsOnly, maxOp<scalar>()));
const label maxDeltaCells =
label(mag(returnReduce(nNewCells, maxOp<scalar>())-nIdealNewCells));
// New trigger to avoid too early balancing
// 1. Check if globally one proc exceeds the maxCellUnbalance value
// related to the new added cells at the refinement loop
// 2. Check if globally one proc exceeds the maxCellUnbalance based on
// the average cell count a proc should have
if
(
(maxNewCells <= maxCellUnbalance)
&& (maxDeltaCells <= maxCellUnbalance)
)
{
Info<< "Skipping balancing since trigger value not reached:" << "\n"
<< " Trigger cell count: " << maxCellUnbalance << nl
<< " Max new cell count in proc: " << maxNewCells << nl
<< " Max difference between new cells and balanced: "
<< maxDeltaCells << nl
<< " Max load unbalance " << maxLoadUnbalance
<< nl <<endl;
}
else
{
if (unbalance <= maxLoadUnbalance)
{
Info<< "Skipping balancing since max unbalance " << unbalance
<< " is less than allowable " << maxLoadUnbalance
<< endl;
}
else
{
scalarField cellWeights(mesh_.nCells(), 1);
forAll(cellsToRefine, i)
{
cellWeights[cellsToRefine[i]] += 7;
}
distMap = balance
(
false, //keepZoneFaces
false, //keepBaffles
cellWeights,
decomposer,
distributor
);
// Update cells to refine
distMap().distributeCellIndices(cellsToRefine);
Info<< "Balanced mesh in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
printMeshInfo(debug, "After balancing " + msg);
if (debug&meshRefinement::MESH)
{
Pout<< "Writing balanced " << msg
<< " mesh to time " << timeName() << endl;
write
(
debugType(debug),
writeType(writeLevel() | WRITEMESH),
mesh_.time().path()/timeName()
);
Pout<< "Dumped debug data in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
// test all is still synced across proc patches
checkData();
}
}
}
}
return distMap;
}
// Do refinement of consistent set of cells followed by truncation and // Do refinement of consistent set of cells followed by truncation and
// load balancing. // load balancing.
Foam::autoPtr<Foam::mapDistributePolyMesh> Foam::autoPtr<Foam::mapDistributePolyMesh>
@ -2607,10 +2721,13 @@ Foam::meshRefinement::refineAndBalance
decompositionMethod& decomposer, decompositionMethod& decomposer,
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelList& cellsToRefine, const labelList& cellsToRefine,
const scalar maxLoadUnbalance const scalar maxLoadUnbalance,
const label maxCellUnbalance
) )
{ {
// Do all refinement // Refinement
// ~~~~~~~~~~
refine(cellsToRefine); refine(cellsToRefine);
if (debug&meshRefinement::MESH) if (debug&meshRefinement::MESH)
@ -2638,63 +2755,17 @@ Foam::meshRefinement::refineAndBalance
// Load balancing // Load balancing
// ~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~
autoPtr<mapDistributePolyMesh> distMap; labelList noCellsToRefine;
if (Pstream::nProcs() > 1) auto distMap = balance
{ (
scalar nIdealCells = msg,
mesh_.globalData().nTotalCells() decomposer,
/ Pstream::nProcs(); distributor,
noCellsToRefine, // mesh is already refined; no need to predict
scalar unbalance = returnReduce maxLoadUnbalance,
( maxCellUnbalance
mag(1.0-mesh_.nCells()/nIdealCells), );
maxOp<scalar>()
);
if (unbalance <= maxLoadUnbalance)
{
Info<< "Skipping balancing since max unbalance " << unbalance
<< " is less than allowable " << maxLoadUnbalance
<< endl;
}
else
{
scalarField cellWeights(mesh_.nCells(), 1);
distMap = balance
(
false, //keepZoneFaces
false, //keepBaffles
cellWeights,
decomposer,
distributor
);
Info<< "Balanced mesh in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
printMeshInfo(debug, "After balancing " + msg);
if (debug&meshRefinement::MESH)
{
Pout<< "Writing balanced " << msg
<< " mesh to time " << timeName() << endl;
write
(
debugType(debug),
writeType(writeLevel() | WRITEMESH),
mesh_.time().path()/timeName()
);
Pout<< "Dumped debug data in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
// test all is still synced across proc patches
checkData();
}
}
}
return distMap; return distMap;
} }
@ -2708,7 +2779,8 @@ Foam::meshRefinement::balanceAndRefine
decompositionMethod& decomposer, decompositionMethod& decomposer,
fvMeshDistribute& distributor, fvMeshDistribute& distributor,
const labelList& initCellsToRefine, const labelList& initCellsToRefine,
const scalar maxLoadUnbalance const scalar maxLoadUnbalance,
const label maxCellUnbalance
) )
{ {
labelList cellsToRefine(initCellsToRefine); labelList cellsToRefine(initCellsToRefine);
@ -2737,90 +2809,24 @@ Foam::meshRefinement::balanceAndRefine
//} //}
// Load balancing // Load balancing
// ~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~
autoPtr<mapDistributePolyMesh> distMap; auto distMap = balance
(
if (Pstream::nProcs() > 1) msg,
{ decomposer,
// First check if we need to balance at all. Precalculate number of distributor,
// cells after refinement and see what maximum difference is. cellsToRefine,
scalar nNewCells = scalar(mesh_.nCells() + 7*cellsToRefine.size()); maxLoadUnbalance,
scalar nIdealNewCells = maxCellUnbalance
returnReduce(nNewCells, sumOp<scalar>()) );
/ Pstream::nProcs();
scalar unbalance = returnReduce
(
mag(1.0-nNewCells/nIdealNewCells),
maxOp<scalar>()
);
if (unbalance <= maxLoadUnbalance)
{
Info<< "Skipping balancing since max unbalance " << unbalance
<< " is less than allowable " << maxLoadUnbalance
<< endl;
}
else
{
scalarField cellWeights(mesh_.nCells(), 1);
forAll(cellsToRefine, i)
{
cellWeights[cellsToRefine[i]] += 7;
}
distMap = balance
(
false, //keepZoneFaces
false, //keepBaffles
cellWeights,
decomposer,
distributor
);
// Update cells to refine
distMap().distributeCellIndices(cellsToRefine);
Info<< "Balanced mesh in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
}
//{
// globalIndex globalCells(mesh_.nCells());
//
// Info<< "** Distribution after balancing:" << endl;
// for (const int procI : Pstream::allProcs())
// {
// Info<< " " << procI << '\t'
// << globalCells.localSize(procI) << endl;
// }
// Info<< endl;
//}
printMeshInfo(debug, "After balancing " + msg);
if (debug&meshRefinement::MESH)
{
Pout<< "Writing balanced " << msg
<< " mesh to time " << timeName() << endl;
write
(
debugType(debug),
writeType(writeLevel() | WRITEMESH),
mesh_.time().path()/timeName()
);
Pout<< "Dumped debug data in = "
<< mesh_.time().cpuTimeIncrement() << " s" << endl;
// test all is still synced across proc patches
checkData();
}
}
// Refinement // Refinement
// ~~~~~~~~~~ // ~~~~~~~~~~
// Note: uses updated cellsToRefine
refine(cellsToRefine); refine(cellsToRefine);

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2015 OpenFOAM Foundation Copyright (C) 2011-2015 OpenFOAM Foundation
Copyright (C) 2015-2020,2022 OpenCFD Ltd. Copyright (C) 2015-2020,2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -85,6 +85,7 @@ Foam::refinementParameters::refinementParameters
dict.getOrDefault("useTopologicalSnapDetection", true) dict.getOrDefault("useTopologicalSnapDetection", true)
), ),
maxLoadUnbalance_(dict.getOrDefault<scalar>("maxLoadUnbalance", 0)), maxLoadUnbalance_(dict.getOrDefault<scalar>("maxLoadUnbalance", 0)),
maxCellUnbalance_(dict.getOrDefault<label>("maxCellUnbalance", -1)),
handleSnapProblems_ handleSnapProblems_
( (
dict.getOrDefault<Switch>("handleSnapProblems", true) dict.getOrDefault<Switch>("handleSnapProblems", true)
@ -97,6 +98,10 @@ Foam::refinementParameters::refinementParameters
nFilterIter_(dict.getOrDefault<label>("nFilterIter", 2)), nFilterIter_(dict.getOrDefault<label>("nFilterIter", 2)),
minCellFraction_(dict.getOrDefault<scalar>("minCellFraction", 0)), minCellFraction_(dict.getOrDefault<scalar>("minCellFraction", 0)),
nMinCells_(dict.getOrDefault<label>("nMinCells", 0)), nMinCells_(dict.getOrDefault<label>("nMinCells", 0)),
balanceAtEnd_
(
dict.getOrDefault("balanceAtEnd", false)
),
dryRun_(dryRun) dryRun_(dryRun)
{ {
point locationInMesh; point locationInMesh;

View File

@ -6,7 +6,7 @@
\\/ M anipulation | \\/ M anipulation |
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
Copyright (C) 2011-2014 OpenFOAM Foundation Copyright (C) 2011-2014 OpenFOAM Foundation
Copyright (C) 2015-2020,2022 OpenCFD Ltd. Copyright (C) 2015-2020,2023 OpenCFD Ltd.
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
License License
This file is part of OpenFOAM. This file is part of OpenFOAM.
@ -108,6 +108,9 @@ class refinementParameters
//- Allowed load unbalance //- Allowed load unbalance
const scalar maxLoadUnbalance_; const scalar maxLoadUnbalance_;
//- Trigger cell count to start balancing
const label maxCellUnbalance_;
const Switch handleSnapProblems_; const Switch handleSnapProblems_;
const Switch interfaceRefine_; const Switch interfaceRefine_;
@ -120,6 +123,9 @@ class refinementParameters
const label nMinCells_; const label nMinCells_;
//- Force final balancing after castellation
const bool balanceAtEnd_;
const bool dryRun_; const bool dryRun_;
@ -228,6 +234,12 @@ public:
return maxLoadUnbalance_; return maxLoadUnbalance_;
} }
//- Trigger cell count to start balancing
label maxCellUnbalance() const
{
return maxCellUnbalance_;
}
bool handleSnapProblems() const bool handleSnapProblems() const
{ {
return handleSnapProblems_; return handleSnapProblems_;
@ -266,6 +278,12 @@ public:
return nMinCells_; return nMinCells_;
} }
//- Force final balancing after castallation
bool balanceAtEnd() const
{
return balanceAtEnd_;
}
// Other // Other

View File

@ -179,7 +179,8 @@ Foam::label Foam::snappyRefineDriver::featureEdgeRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -190,7 +191,8 @@ Foam::label Foam::snappyRefineDriver::featureEdgeRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -313,7 +315,8 @@ Foam::label Foam::snappyRefineDriver::smallFeatureRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -324,7 +327,8 @@ Foam::label Foam::snappyRefineDriver::smallFeatureRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -490,7 +494,8 @@ Foam::label Foam::snappyRefineDriver::surfaceOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -501,7 +506,8 @@ Foam::label Foam::snappyRefineDriver::surfaceOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -742,7 +748,8 @@ Foam::label Foam::snappyRefineDriver::gapOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -753,7 +760,8 @@ Foam::label Foam::snappyRefineDriver::gapOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -967,7 +975,8 @@ Foam::label Foam::snappyRefineDriver::bigGapOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -978,7 +987,8 @@ Foam::label Foam::snappyRefineDriver::bigGapOnlyRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -1090,6 +1100,22 @@ Foam::label Foam::snappyRefineDriver::danglingCellRefine
{ {
Info<< "Stopping refining since too few cells selected." Info<< "Stopping refining since too few cells selected."
<< nl << endl; << nl << endl;
if (refineParams.balanceAtEnd())
{
Info<< "Final mesh balancing" << endl;
meshRefiner_.balance
(
"",
decomposer_,
distributor_,
cellsToRefine,
0,
-1
);
}
break; break;
} }
@ -1108,7 +1134,8 @@ Foam::label Foam::snappyRefineDriver::danglingCellRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -1119,7 +1146,8 @@ Foam::label Foam::snappyRefineDriver::danglingCellRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -1453,7 +1481,8 @@ Foam::label Foam::snappyRefineDriver::refinementInterfaceRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -1464,7 +1493,8 @@ Foam::label Foam::snappyRefineDriver::refinementInterfaceRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -1701,7 +1731,8 @@ Foam::label Foam::snappyRefineDriver::boundaryRefinementInterfaceRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -1712,7 +1743,8 @@ Foam::label Foam::snappyRefineDriver::boundaryRefinementInterfaceRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }
@ -1961,7 +1993,8 @@ Foam::label Foam::snappyRefineDriver::shellRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
else else
@ -1972,7 +2005,8 @@ Foam::label Foam::snappyRefineDriver::shellRefine
decomposer_, decomposer_,
distributor_, distributor_,
cellsToRefine, cellsToRefine,
refineParams.maxLoadUnbalance() refineParams.maxLoadUnbalance(),
refineParams.maxCellUnbalance()
); );
} }
} }