Skip to content
Permalink
Browse files
chtMultiRegionFoam: Added support for residual convergence controls
Patch contributed by Tobias Holzmann
Resolves patch request https://bugs.openfoam.org/view.php?id=2524
  • Loading branch information
Henry Weller committed May 4, 2017
1 parent d26c6c3 commit a884a44e4729ae662fa1e4361ccf67e7c498ca04
Showing 16 changed files with 239 additions and 20 deletions.
@@ -0,0 +1,66 @@
// Residual control used?
bool resControlUsed = false;
int nFluidControlled = fluidRegions.size();
int nSolidControlled = solidRegions.size();

// Check wheater there is a single regions that uses residual control
forAll(fluidRegions, i)
{
if (residualControlUsedFluid[i])
{
resControlUsed = true;
}
}

forAll(solidRegions, i)
{
if(residualControlUsedSolid[i])
{
resControlUsed = true;
}
}

if (resControlUsed)
{
int nFluidConv = 0;
int nSolidConv = 0;

// Sum of all converged regions (Note: if no residual control is used
// the residualReached* flag is already set to true)
forAll(fluidRegions, i)
{
if (residualReachedFluid[i])
{
nFluidConv++;
}
}

forAll(solidRegions, i)
{
if (residualReachedSolid[i])
{
nSolidConv++;
}
}

if (nFluidConv == nFluidControlled && nSolidConv == nSolidControlled)
{
// Activate flag to go to the 'Final' loop using the 'Final'
// relaxation factors
allRegionsConverged = true;
}
}

if (finalIter && resControlUsed && !allRegionsConverged)
{
Info<< "\nRegions not converged after " << nOuterCorr
<< " outer correctors" << endl;
}
else if (finalIter && resControlUsed && allRegionsConverged)
{
Info<< "\nRegions converged after " << oCorr
<< " outer correctors" << endl;

// Leave PIMPLE loop
break;
}
@@ -2,7 +2,7 @@
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation
\\ / A nd | Copyright (C) 2011-2017 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
License
@@ -86,19 +86,28 @@ int main(int argc, char *argv[])
}
}

bool allRegionsConverged = false;
bool finalIter = false;

// --- PIMPLE loop
for (int oCorr=0; oCorr<nOuterCorr; oCorr++)
{
bool finalIter = oCorr == nOuterCorr-1;
Info<< "Pimple iteration " << oCorr << "\n";

if (oCorr == nOuterCorr-1 || allRegionsConverged)
{
finalIter = true;
}

forAll(fluidRegions, i)
{
Info<< "\nSolving for fluid region "
<< fluidRegions[i].name() << endl;
#include "setRegionFluidFields.H"
#include "readFluidMultiRegionPIMPLEControls.H"
#include "readFluidMultiRegionResidualControls.H"
#include "solveFluid.H"
#include "residualControlsFluid.H"
}

forAll(solidRegions, i)
@@ -107,9 +116,12 @@ int main(int argc, char *argv[])
<< solidRegions[i].name() << endl;
#include "setRegionSolidFields.H"
#include "readSolidMultiRegionPIMPLEControls.H"
#include "readSolidMultiRegionResidualControls.H"
#include "solveSolid.H"
#include "residualControlsSolid.H"
}

#include "checkResidualControls.H"
}

runTime.write();
@@ -1,2 +1,7 @@
#include "createFluidFields.H"
#include "createSolidFields.H"

SolverPerformance<vector> solvPerfU;
SolverPerformance<scalar> solvPerfE;
SolverPerformance<scalar> solvPerfh;
SolverPerformance<scalar> solvPerfp_rgh;
@@ -26,7 +26,7 @@

fvOptions.constrain(EEqn);

EEqn.solve(mesh.solver(he.select(finalIter)));
solvPerfE = EEqn.solve(mesh.solver(he.select(finalIter)));

fvOptions.correct(he);

@@ -18,19 +18,20 @@

if (momentumPredictor)
{
solve
(
UEqn
==
fvc::reconstruct
solvPerfU =
solve
(
UEqn
==
fvc::reconstruct
(
- ghf*fvc::snGrad(rho)
- fvc::snGrad(p_rgh)
)*mesh.magSf()
),
mesh.solver(U.select(finalIter))
);
(
- ghf*fvc::snGrad(rho)
- fvc::snGrad(p_rgh)
)*mesh.magSf()
),
mesh.solver(U.select(finalIter))
);

fvOptions.correct(U);
K = 0.5*magSqr(U);
@@ -15,6 +15,8 @@ PtrList<volScalarField> dpdtFluid(fluidRegions.size());

List<scalar> initialMassFluid(fluidRegions.size());
List<bool> frozenFlowFluid(fluidRegions.size(), false);
List<bool> residualReachedFluid(fluidRegions.size(), true);
List<bool> residualControlUsedFluid(fluidRegions.size(), false);

PtrList<IOMRFZoneList> MRFfluid(fluidRegions.size());
PtrList<fv::options> fluidFvOptions(fluidRegions.size());
@@ -45,16 +45,16 @@
- fvm::laplacian(rhorAUf, p_rgh)
);

p_rghEqn.solve
solvPerfp_rgh = p_rghEqn.solve
(
mesh.solver
(
p_rgh.select
(
(
oCorr == nOuterCorr-1
&& corr == nCorr-1
&& nonOrth == nNonOrthCorr
oCorr == nOuterCorr-1
&& corr == nCorr-1
&& nonOrth == nNonOrthCorr
)
)
)
@@ -0,0 +1,35 @@
const dictionary& residualControl =
mesh.solutionDict().subDict("PIMPLE").subOrEmptyDict("residualControl");

scalar UTol = -1.;
scalar ETol = -1.;
scalar p_rghTol = -1.;

if (!residualControl.empty())
{
if (!residualControl.subOrEmptyDict("U").empty())
{
UTol = readScalar(residualControl.subDict("U").lookup("tolerance"));
}

if (!residualControl.subOrEmptyDict("p_rgh").empty())
{
p_rghTol =
readScalar
(
residualControl.subDict("p_rgh").lookup("tolerance")
);
}

if (!residualControl.subOrEmptyDict("h").empty())
{
ETol = readScalar(residualControl.subDict("h").lookup("tolerance"));
}

// Residual control used?
if (UTol != -1 || ETol != -1 || p_rghTol != -1)
{
residualControlUsed = true;
resReachedFluid = false;
}
}
@@ -0,0 +1,56 @@
// Residual control used
if (residualControlUsed)
{
bool UConv = false;
bool p_rghConv = false;
bool EConv = false;

// Check which field is not used for control
{
if (UTol == -1)
{
UConv = true;
}

if (p_rghTol == -1)
{
p_rghConv = true;
}

if (ETol == -1)
{
EConv = true;
}
}

// Get the last initial residual of the solvers
if (momentumPredictor && !UConv)
{
if (UTol > cmptMax(solvPerfU.initialResidual()))
{
UConv = true;
}
}

if (!p_rghConv)
{
if (p_rghTol > solvPerfp_rgh.initialResidual())
{
p_rghConv = true;
}
}

if (!EConv)
{
if (ETol > solvPerfE.initialResidual())
{
EConv = true;
}
}

// Check if each field is converged
if (UConv && p_rghConv && EConv)
{
resReachedFluid = true;
}
}
@@ -33,3 +33,6 @@
);

const bool frozenFlow = frozenFlowFluid[i];

bool& resReachedFluid = residualReachedFluid[i];
bool& residualControlUsed = residualControlUsedFluid[i];
@@ -6,6 +6,9 @@
PtrList<volScalarField> betavSolid(solidRegions.size());
PtrList<volSymmTensorField> aniAlphas(solidRegions.size());

List<bool> residualReachedSolid(solidRegions.size(), false);
List<bool> residualControlUsedSolid(solidRegions.size(), false);

// Populate solid field pointer lists
forAll(solidRegions, i)
{
@@ -0,0 +1,25 @@
const dictionary& residualControl =
mesh.solutionDict().subDict("PIMPLE").subOrEmptyDict("residualControl");

scalar hTol = -1.;

if (!residualControl.empty())
{
if (!residualControl.subOrEmptyDict("h").empty())
{
hTol = readScalar(residualControl.subDict("h").lookup("tolerance"));

// Used residual control for actual solid region
if (hTol != -1)
{
residualControlUsed = true;
}
}

// Residual control used?
if (hTol != -1)
{
residualControlUsed = true;
resReachedSolid = false;
}
}
@@ -0,0 +1,8 @@
// Residual control used
if (residualControlUsed)
{
if (hTol > solvPerfh.initialResidual())
{
resReachedSolid = true;
}
}
@@ -30,3 +30,6 @@ volScalarField& h = thermo.he();
const volScalarField& betav = betavSolid[i];

fv::options& fvOptions = solidHeatSources[i];

bool& resReachedSolid = residualReachedSolid[i];
bool& residualControlUsed = residualControlUsedSolid[i];
@@ -2,7 +2,7 @@ scalar DiNum = -GREAT;

forAll(solidRegions, i)
{
//- Note: do not use setRegionSolidFields.H to avoid double registering Cp
// Note: do not use setRegionSolidFields.H to avoid double registering Cp
//#include "setRegionSolidFields.H"
const solidThermo& thermo = thermos[i];

@@ -22,7 +22,7 @@ if (finalIter)

fvOptions.constrain(hEqn);

hEqn.solve(mesh.solver(h.select(finalIter)));
solvPerfh = hEqn.solve(mesh.solver(h.select(finalIter)));

fvOptions.correct(h);
}

0 comments on commit a884a44

Please sign in to comment.