Commit 5daa38d5 authored by sergio's avatar sergio
Browse files

ENH:

Update of overRhoPimpleDyMFoam and overInterDyMFoam solvers.
Adding corresponding tutorials with best possible settings
The main effort was put on reducing pressure spikes as the
stencil change with hole cells on the background mesh.
parent d2b32fcc
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | Copyright (C) 2011 OpenFOAM Foundation
\\/ M anipulation | Copyright (C) 2018 OpenCFD Ltd.
-------------------------------------------------------------------------------
License
This file is part of OpenFOAM.
OpenFOAM is free software: you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
Global
continuityErrs
Description
Calculates and prints the continuity errors.
\*---------------------------------------------------------------------------*/
{
dimensionedScalar totalMass = fvc::domainIntegrate(cellMask*rho);
scalar sumLocalContErr =
(
fvc::domainIntegrate(mag(cellMask*(rho - thermo.rho())))/totalMass
).value();
scalar globalContErr =
(
fvc::domainIntegrate(cellMask*(rho - thermo.rho()))/totalMass
).value();
cumulativeContErr += globalContErr;
Info<< "time step continuity errors : sum local = " << sumLocalContErr
<< ", global = " << globalContErr
<< ", cumulative = " << cumulativeContErr
<< endl;
}
// ************************************************************************* //
CorrectPhi
(
U,
phi,
p,
rho,
psi,
dimensionedScalar("rAUf", dimTime, 1),
divrhoU,
pimple
);
if (mesh.changing())
{
volVectorField::Boundary& bfld = U.boundaryFieldRef();
forAll(bfld, patchi)
{
if (bfld[patchi].fixesValue())
{
bfld[patchi].initEvaluate();
}
}
surfaceScalarField::Boundary& phiBfld = phi.boundaryFieldRef();
forAll(bfld, patchi)
{
if (bfld[patchi].fixesValue())
{
bfld[patchi].evaluate();
phiBfld[patchi] =
rho.boundaryField()[patchi]
* (
bfld[patchi]
& mesh.Sf().boundaryField()[patchi]
);
}
}
}
// Initialize BCs list for pcorr to zero-gradient
wordList pcorrTypes
(
p.boundaryField().size(),
zeroGradientFvPatchScalarField::typeName
);
// Set BCs of pcorr to fixed-value for patches at which p is fixed
forAll(p.boundaryField(), patchi)
{
if (p.boundaryField()[patchi].fixesValue())
{
pcorrTypes[patchi] = fixedValueFvPatchScalarField::typeName;
}
}
volScalarField pcorr
(
IOobject
(
"pcorr",
runTime.timeName(),
mesh,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh,
dimensionedScalar(p.dimensions(), Zero),
pcorrTypes
);
mesh.setFluxRequired(pcorr.name());
{
dimensionedScalar rAUf("rAUf", dimTime, 1.0);
while (pimple.correctNonOrthogonal())
{
fvScalarMatrix pcorrEqn
(
fvm::ddt(psi, pcorr)
+ fvc::div(phi)
- fvm::laplacian(rAUf, pcorr)
==
divrhoU()
);
pcorrEqn.solve(mesh.solver(pcorr.select(pimple.finalInnerIter())));
//Bypass virtual layer
//mesh.fvMesh::solve(pcorrEqn, d);
if (pimple.finalNonOrthogonalIter())
{
phi += pcorrEqn.flux();
}
}
}
#include "createTimeControls.H"
bool correctPhi
bool ddtCorr
(
pimple.dict().lookupOrDefault("correctPhi", true)
);
bool checkMeshCourantNo
(
pimple.dict().lookupOrDefault("checkMeshCourantNo", false)
pimple.dict().lookupOrDefault("ddtCorr", true)
);
Info<< "Reading thermophysical properties\n" << endl;
autoPtr<psiThermo> pThermo
autoPtr<fluidThermo> pThermo
(
psiThermo::New(mesh)
fluidThermo::New(mesh)
);
psiThermo& thermo = pThermo();
fluidThermo& thermo = pThermo();
thermo.validate(args.executable(), "h", "e");
volScalarField& p = thermo.p();
......@@ -39,6 +39,8 @@ volVectorField U
#include "compressibleCreatePhi.H"
pressureControl pressureControl(p, rho, pimple.dict(), false);
dimensionedScalar rhoMax
(
dimensionedScalar::lookupOrDefault
......@@ -63,42 +65,25 @@ dimensionedScalar rhoMin
mesh.setFluxRequired(p.name());
Info<< "Creating field dpdt\n" << endl;
volScalarField dpdt
(
IOobject
(
"dpdt",
runTime.timeName(),
mesh
),
mesh,
dimensionedScalar(p.dimensions()/dimTime, Zero)
);
Info<< "Creating field kinetic energy K\n" << endl;
volScalarField K("K", 0.5*magSqr(U));
#include "createDpdt.H"
#include "createK.H"
//- Overset specific
// Add solver-specific interpolations
{
dictionary oversetDict;
oversetDict.add("U", true);
oversetDict.add("p", true);
oversetDict.add("HbyA", true);
oversetDict.add("grad(p)", true);
const_cast<dictionary&>
(
mesh.schemesDict()
).add
(
"oversetInterpolationRequired",
oversetDict,
true
);
wordHashSet& nonInt =
const_cast<wordHashSet&>(Stencil::New(mesh).nonInterpolatedFields());
nonInt.insert("HbyA");
nonInt.insert("grad(p)");
nonInt.insert("surfaceIntegrate(phi)");
nonInt.insert("surfaceIntegrate(phiHbyA)");
nonInt.insert("cellMask");
nonInt.insert("cellDisplacement");
nonInt.insert("interpolatedCells");
nonInt.insert("cellInterpolationWeight");
}
// Mask field for zeroing out contributions on hole cells
......
......@@ -38,10 +38,11 @@ Description
#include "fvCFD.H"
#include "dynamicFvMesh.H"
#include "psiThermo.H"
#include "fluidThermo.H"
#include "turbulentFluidThermoModel.H"
#include "bound.H"
#include "pimpleControl.H"
#include "pressureControl.H"
#include "CorrectPhi.H"
#include "fvOptions.H"
#include "localEulerDdtScheme.H"
......@@ -56,13 +57,13 @@ int main(int argc, char *argv[])
#include "setRootCase.H"
#include "createTime.H"
#include "createDynamicFvMesh.H"
#include "createControl.H"
#include "createDyMControls.H"
#include "createRDeltaT.H"
#include "initContinuityErrs.H"
#include "createFields.H"
#include "createMRF.H"
#include "createFvOptions.H"
#include "createRhoUf.H"
#include "createRhoUfIfPresent.H"
#include "createControls.H"
turbulence->validate();
......@@ -80,66 +81,107 @@ int main(int argc, char *argv[])
while (runTime.run())
{
#include "readControls.H"
#include "readDyMControls.H"
// Store divrhoU from the previous mesh so that it can be mapped
// and used in correctPhi to ensure the corrected phi has the
// same divergence
autoPtr<volScalarField> divrhoU;
if (correctPhi)
{
// Store divrhoU from the previous mesh so that it can be mapped
// and used in correctPhi to ensure the corrected phi has the
// same divergence
volScalarField divrhoU
divrhoU.reset
(
"divrhoU",
fvc::div(fvc::absolute(phi, rho, U))
new volScalarField
(
"divrhoU",
fvc::div(fvc::absolute(phi, rho, U))
)
);
}
if (LTS)
{
#include "setRDeltaT.H"
}
else
if (LTS)
{
#include "setRDeltaT.H"
}
else
{
#include "compressibleCourantNo.H"
#include "setDeltaT.H"
}
++runTime;
Info<< "Time = " << runTime.timeName() << nl << endl;
// --- Pressure-velocity PIMPLE corrector loop
while (pimple.loop())
{
if (pimple.firstIter() || moveMeshOuterCorrectors)
{
#include "compressibleCourantNo.H"
#include "setDeltaT.H"
}
++runTime;
// Do any mesh changes
mesh.update();
Info<< "Time = " << runTime.timeName() << nl << endl;
if (mesh.changing())
{
MRF.update();
// Store momentum to set rhoUf for introduced faces.
volVectorField rhoU("rhoU", rho*U);
#include "setCellMask.H"
// Do any mesh changes
mesh.update();
const surfaceScalarField faceMaskOld
(
localMin<scalar>(mesh).interpolate(cellMask.oldTime())
);
if (mesh.changing())
{
#include "setCellMask.H"
}
// Zero Uf on old faceMask (H-I)
rhoUf() *= faceMaskOld;
if (mesh.changing() && correctPhi)
{
// Calculate absolute flux from the mapped surface velocity
phi = mesh.Sf() & rhoUf;
surfaceVectorField rhoUfint(fvc::interpolate(rho*U));
#include "correctPhi.H"
// Update Uf and phi on new C-I faces
rhoUf() += (1-faceMaskOld)*rhoUfint;
// Make the fluxes relative to the mesh-motion
fvc::makeRelative(phi, rho, U);
}
}
// Update Uf boundary
forAll(rhoUf().boundaryField(), patchI)
{
rhoUf().boundaryFieldRef()[patchI] =
rhoUfint.boundaryField()[patchI];
}
if (mesh.changing() && checkMeshCourantNo)
{
#include "meshCourantNo.H"
}
// Calculate absolute flux from the mapped surface velocity
phi = mesh.Sf() & rhoUf();
#include "rhoEqn.H"
Info<< "rhoEqn max/min : " << max(rho).value()
<< " " << min(rho).value() << endl;
if (correctPhi)
{
#include "correctPhi.H"
}
// Zero phi on current H-I
const surfaceScalarField faceMask
(
localMin<scalar>(mesh).interpolate(cellMask)
);
phi *= faceMask;
U *= cellMask;
// Make the fluxes relative to the mesh-motion
fvc::makeRelative(phi, rho, U);
}
if (checkMeshCourantNo)
{
#include "meshCourantNo.H"
}
}
if (pimple.firstIter() && !pimple.SIMPLErho())
{
#include "rhoEqn.H"
}
// --- Pressure-velocity PIMPLE corrector loop
while (pimple.loop())
{
#include "UEqn.H"
#include "EEqn.H"
......@@ -155,6 +197,8 @@ int main(int argc, char *argv[])
}
}
rho = thermo.rho();
runTime.write();
runTime.printExecutionTime(Info);
......
rho = thermo.rho();
rho = max(rho, rhoMin);
rho = min(rho, rhoMax);
rho.relax();
if (!pimple.SIMPLErho())
{
rho = thermo.rho();
}
// Thermodynamic density needs to be updated by psi*d(p) after the
// pressure solution
const volScalarField psip0(psi*p);
surfaceScalarField faceMask(localMin<scalar>(mesh).interpolate(cellMask));
volScalarField rAU("rAU", 1.0/UEqn.A());
mesh.interpolate(rAU);
volScalarField rAU(1.0/UEqn.A());
surfaceScalarField rhorAUf("rhorAUf", faceMask*fvc::interpolate(rho*rAU));
surfaceScalarField rhorAUf("rhorAUf", fvc::interpolate(rho*rAU));
volVectorField HbyA("HbyA", U);
HbyA = constrainHbyA(cellMask*rAU*UEqn.H(), U, p);
HbyA = constrainHbyA(rAU*UEqn.H(), U, p);
if (pimple.nCorrPISO() <= 1)
{
tUEqn.clear();
}
surfaceScalarField phiHbyA
(
"phiHbyA",
fvc::interpolate(rho)*fvc::flux(HbyA)
);
if (ddtCorr)
{
surfaceScalarField faceMaskOld
(
localMin<scalar>(mesh).interpolate(cellMask.oldTime())
);
phiHbyA +=
faceMaskOld*MRF.zeroFilter(rhorAUf*fvc::ddtCorr(rho, U, phi, rhoUf));
}
fvc::makeRelative(phiHbyA, rho, U);
MRF.makeRelative(fvc::interpolate(rho), phiHbyA);
// Update the pressure BCs to ensure flux consistency
constrainPressure(p, rho, U, phiHbyA, rhorAUf, MRF);
if (pimple.transonic())
{
surfaceScalarField phid
(
"phid",
fvc::interpolate(psi)
*(
fvc::flux(HbyA)
+ rhorAUf*fvc::ddtCorr(rho, U, rhoUf)/fvc::interpolate(rho)
)
(fvc::interpolate(psi)/fvc::interpolate(rho))*phiHbyA
);
fvc::makeRelative(phid, psi, U);
MRF.makeRelative(fvc::interpolate(psi), phid);
phiHbyA -= fvc::interpolate(psi*p)*phiHbyA/fvc::interpolate(rho);
fvScalarMatrix pDDtEqn
(
fvc::ddt(rho) + psi*correction(fvm::ddt(p))
+ fvc::div(phiHbyA) + fvm::div(phid, p)
==
fvOptions(psi, p, rho.name())
);
while (pimple.correctNonOrthogonal())
{
fvScalarMatrix pEqn
(
fvm::ddt(psi, p)
+ fvm::div(phid, p)
- fvm::laplacian(rhorAUf, p)
==
fvOptions(psi, p, rho.name())
);
fvScalarMatrix pEqn(pDDtEqn - fvm::laplacian(rhorAUf, p));
// Relax the pressure equation to ensure diagonal-dominance
pEqn.relax();
pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
if (pimple.finalNonOrthogonalIter())
{
phi == pEqn.flux();
phi = phiHbyA + pEqn.flux();
}
}
}
else
{
surfaceScalarField phiHbyA
fvScalarMatrix pDDtEqn
(
"phiHbyA",
fvc::flux(rho*HbyA)
+ rhorAUf*fvc::ddtCorr(rho, U, rhoUf)
fvc::ddt(rho) + psi*correction(fvm::ddt(p))
+ fvc::div(phiHbyA)
==
fvOptions(psi, p, rho.name())
);
fvc::makeRelative(phiHbyA, rho, U);
MRF.makeRelative(fvc::interpolate(rho), phiHbyA);
// Update the pressure BCs to ensure flux consistency
constrainPressure(p, rho, U, phiHbyA, rhorAUf, MRF);
while (pimple.correctNonOrthogonal())
{
// Pressure corrector
fvScalarMatrix pEqn
(
fvm::ddt(psi, p)
+ fvc::div(phiHbyA)
- fvm::laplacian(rhorAUf, p)
==
fvOptions(psi, p, rho.name())
);
fvScalarMatrix pEqn(pDDtEqn - fvm::laplacian(rhorAUf, p));
pEqn.solve(mesh.solver(p.select(pimple.finalInnerIter())));
......@@ -91,25 +104,24 @@ else
// Explicitly relax pressure for momentum corrector
p.relax();
// Recalculate density from the relaxed pressure
rho = thermo.rho();
rho = max(rho, rhoMin);
rho = min(rho, rhoMax);
rho.relax();
Info<< "rho max/min : " << max(rho).value()
<< " " << min(rho).value() << endl;
volVectorField gradP(fvc::grad(p));
//mesh.interpolate(gradP);