diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/checkResidualControls.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/checkResidualControls.H new file mode 100644 index 000000000..8068798cd --- /dev/null +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/checkResidualControls.H @@ -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; +} diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/chtMultiRegionFoam.C b/applications/solvers/heatTransfer/chtMultiRegionFoam/chtMultiRegionFoam.C index 43db99de9..4262eecbf 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/chtMultiRegionFoam.C +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/chtMultiRegionFoam.C @@ -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,11 +86,18 @@ int main(int argc, char *argv[]) } } + bool allRegionsConverged = false; + bool finalIter = false; // --- PIMPLE loop for (int oCorr=0; oCorr solvPerfU; +SolverPerformance solvPerfE; +SolverPerformance solvPerfh; +SolverPerformance solvPerfp_rgh; diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/EEqn.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/EEqn.H index d8f4516f5..f62d0c8c5 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/EEqn.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/EEqn.H @@ -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); diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/UEqn.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/UEqn.H index a12d0e814..2cd3d22d8 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/UEqn.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/UEqn.H @@ -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); diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/createFluidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/createFluidFields.H index be3ec79a2..294685e79 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/createFluidFields.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/createFluidFields.H @@ -15,6 +15,8 @@ PtrList dpdtFluid(fluidRegions.size()); List initialMassFluid(fluidRegions.size()); List frozenFlowFluid(fluidRegions.size(), false); +List residualReachedFluid(fluidRegions.size(), true); +List residualControlUsedFluid(fluidRegions.size(), false); PtrList MRFfluid(fluidRegions.size()); PtrList fluidFvOptions(fluidRegions.size()); diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/pEqn.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/pEqn.H index a8a0807f2..bf634563c 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/pEqn.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/pEqn.H @@ -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 ) ) ) diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/readFluidMultiRegionResidualControls.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/readFluidMultiRegionResidualControls.H new file mode 100644 index 000000000..ec51c8be3 --- /dev/null +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/readFluidMultiRegionResidualControls.H @@ -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; + } + } diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/residualControlsFluid.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/residualControlsFluid.H new file mode 100644 index 000000000..a1b2523f6 --- /dev/null +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/residualControlsFluid.H @@ -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; + } +} diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/setRegionFluidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/setRegionFluidFields.H index 8d3a291be..3544cfa5b 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/setRegionFluidFields.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/fluid/setRegionFluidFields.H @@ -33,3 +33,6 @@ ); const bool frozenFlow = frozenFlowFluid[i]; + + bool& resReachedFluid = residualReachedFluid[i]; + bool& residualControlUsed = residualControlUsedFluid[i]; diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H index ab10b81f9..9977fe6e1 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/createSolidFields.H @@ -6,6 +6,9 @@ PtrList betavSolid(solidRegions.size()); PtrList aniAlphas(solidRegions.size()); + List residualReachedSolid(solidRegions.size(), false); + List residualControlUsedSolid(solidRegions.size(), false); + // Populate solid field pointer lists forAll(solidRegions, i) { diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/readSolidMultiRegionResidualControls.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/readSolidMultiRegionResidualControls.H new file mode 100644 index 000000000..8cde24213 --- /dev/null +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/readSolidMultiRegionResidualControls.H @@ -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; + } + } diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/residualControlsSolid.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/residualControlsSolid.H new file mode 100644 index 000000000..32ef7dbcb --- /dev/null +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/residualControlsSolid.H @@ -0,0 +1,8 @@ +// Residual control used +if (residualControlUsed) +{ + if (hTol > solvPerfh.initialResidual()) + { + resReachedSolid = true; + } +} diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H index 98b081952..1e4b4bc4f 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/setRegionSolidFields.H @@ -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]; diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solidRegionDiffusionNo.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solidRegionDiffusionNo.H index 6e87fb920..ec93c58da 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solidRegionDiffusionNo.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solidRegionDiffusionNo.H @@ -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]; diff --git a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solveSolid.H b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solveSolid.H index 30a670768..f7a2cbc12 100644 --- a/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solveSolid.H +++ b/applications/solvers/heatTransfer/chtMultiRegionFoam/solid/solveSolid.H @@ -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); }