solvers::incompressibleMultiphaseVoF: New solver module for multiphase VoF simulations

executed with foamRun for single region simulations of foamMultiRun for
multi-region simulations.  Replaces multiphaseInterFoam and all the
corresponding tutorials have been updated and moved to
tutorials/modules/incompressibleMultiphaseVoF.

incompressibleMultiphaseVoF is derived from the multiphaseVoFSolver which adds
multiphase capability to the VoFSolver base-class used as the basis of all
two-phase and multiphase VoF solvers.

Class
    Foam::solvers::incompressibleMultiphaseVoF

Description
    Solver module for the solution of multiple incompressible, isothermal
    immiscible fluids using a VOF (volume of fluid) phase-fraction based
    interface capturing approach, with optional mesh motion and mesh topology
    changes including adaptive re-meshing.

    The momentum and other fluid properties are of the "mixture" and a single
    momentum equation is solved.

    A mixture approach for momentum transport is provided in which a single
    laminar, RAS or LES model is selected to model the momentum stress.

    Uses the flexible PIMPLE (PISO-SIMPLE) solution for time-resolved and
    pseudo-transient and steady simulations.

SourceFiles
    incompressibleMultiphaseVoF.C

See also
    Foam::solvers::VoFSolver
    Foam::solvers::multiphaseVoFSolver
This commit is contained in:
Henry Weller
2023-01-10 10:12:43 +00:00
parent 7f1fb2fb11
commit ffdb211bdc
127 changed files with 2116 additions and 1284 deletions

View File

@ -1,12 +0,0 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Parse arguments for library compilation
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
multiphaseInterFoam/Allwmake $targetType $*
compressibleMultiphaseInterFoam/Allwmake $targetType $*
driftFluxFoam/Allwmake $targetType $*
wmake $targetType cavitatingFoam
#------------------------------------------------------------------------------

View File

@ -1,5 +1,4 @@
EXE_INC = \
-I$(FOAM_SOLVERS)/multiphase/multiphaseInterFoam/incompressibleMultiphaseMixture/lnInclude \
-IcompressibleMultiphaseMixture/lnInclude \
-I$(LIB_SRC)/physicalProperties/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \

View File

@ -1,3 +1,4 @@
phase/phase.C
compressiblePhase/compressiblePhase.C
compressibleMultiphaseMixture.C

View File

@ -1,5 +1,4 @@
EXE_INC = \
-I$(FOAM_SOLVERS)/multiphase/multiphaseInterFoam/incompressibleMultiphaseMixture/lnInclude \
-I$(LIB_SRC)/physicalProperties/lnInclude \
-I$(LIB_SRC)/multiphaseModels/multiphaseProperties/lnInclude \
-I$(LIB_SRC)/thermophysicalModels/basic/lnInclude \
@ -7,7 +6,6 @@ EXE_INC = \
-I$(LIB_SRC)/meshTools/lnInclude
LIB_LIBS = \
-lincompressibleMultiphaseMixture \
-lfluidThermophysicalModels \
-lmultiphaseProperties \
-lspecie \

View File

@ -1,7 +0,0 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
wclean libso incompressibleMultiphaseMixture
wclean
#------------------------------------------------------------------------------

View File

@ -1,10 +0,0 @@
#!/bin/sh
cd ${0%/*} || exit 1 # Run from this directory
# Parse arguments for library compilation
. $WM_PROJECT_DIR/wmake/scripts/AllwmakeParseArguments
wmake $targetType incompressibleMultiphaseMixture
wmake $targetType
#------------------------------------------------------------------------------

View File

@ -1,3 +0,0 @@
multiphaseInterFoam.C
EXE = $(FOAM_APPBIN)/multiphaseInterFoam

View File

@ -1,24 +0,0 @@
EXE_INC = \
-IincompressibleMultiphaseMixture/lnInclude \
-I$(LIB_SRC)/physicalProperties/lnInclude \
-I$(LIB_SRC)/twoPhaseModels/VoF \
-I$(LIB_SRC)/twoPhaseModels/interfaceCompression/lnInclude \
-I$(LIB_SRC)/twoPhaseModels/interfaceProperties/lnInclude \
-I$(LIB_SRC)/MomentumTransportModels/momentumTransportModels/lnInclude \
-I$(LIB_SRC)/MomentumTransportModels/incompressible/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude \
-I$(LIB_SRC)/sampling/lnInclude
EXE_LIBS = \
-lincompressibleMultiphaseMixture \
-lphysicalProperties \
-linterfaceCompression \
-linterfaceProperties \
-lmomentumTransportModels \
-lincompressibleMomentumTransportModels \
-lfiniteVolume \
-lfvModels \
-lfvConstraints \
-lmeshTools \
-lsampling

View File

@ -1,31 +0,0 @@
fvVectorMatrix UEqn
(
fvm::ddt(rho, U) + fvm::div(rhoPhi, U)
+ MRF.DDt(rho, U)
+ turbulence->divDevTau(rho, U)
==
fvModels.source(rho, U)
);
UEqn.relax();
fvConstraints.constrain(UEqn);
if (pimple.momentumPredictor())
{
solve
(
UEqn
==
fvc::reconstruct
(
(
mixture.surfaceTensionForce()
- ghf*fvc::snGrad(rho)
- fvc::snGrad(p_rgh)
) * mesh.magSf()
)
);
fvConstraints.constrain(U);
}

View File

@ -1,21 +0,0 @@
// Calculate absolute flux
// from the mapped surface velocity
phi = mesh.Sf() & Uf();
correctUphiBCs(U, phi, true);
CorrectPhi
(
phi,
U,
p_rgh,
surfaceScalarField("rAUf", fvc::interpolate(rAU())),
geometricZeroField(),
pressureReference,
pimple
);
#include "continuityErrs.H"
// Make the flux relative to the mesh motion
fvc::makeRelative(phi, U);

View File

@ -1,90 +0,0 @@
Info<< "Reading field p_rgh\n" << endl;
volScalarField p_rgh
(
IOobject
(
"p_rgh",
runTime.name(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
Info<< "Reading field U\n" << endl;
volVectorField U
(
IOobject
(
"U",
runTime.name(),
mesh,
IOobject::MUST_READ,
IOobject::AUTO_WRITE
),
mesh
);
#include "createPhi.H"
incompressibleMultiphaseMixture mixture(U, phi);
// Need to store rho for ddt(rho, U)
volScalarField rho
(
IOobject
(
"rho",
runTime.name(),
mesh,
IOobject::READ_IF_PRESENT
),
mixture.rho()
);
rho.oldTime();
// Construct incompressible turbulence model
autoPtr<incompressible::momentumTransportModel> turbulence
(
incompressible::momentumTransportModel::New(U, phi, mixture)
);
#include "readGravitationalAcceleration.H"
#include "readhRef.H"
#include "gh.H"
volScalarField p
(
IOobject
(
"p",
runTime.name(),
mesh,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
p_rgh + rho*gh
);
pressureReference pressureReference(p, p_rgh, pimple.dict());
if (p_rgh.needReference())
{
p += dimensionedScalar
(
"p",
p.dimensions(),
pressureReference.refValue()
- getRefCellValue(p, pressureReference.refCell())
);
p_rgh = p - rho*gh;
}
mesh.schemes().setFluxRequired(p_rgh.name());
#include "createMRF.H"
#include "createFvModels.H"
#include "createFvConstraints.H"

View File

@ -1,5 +0,0 @@
phase/phase.C
incompressiblePhase/incompressiblePhase.C
incompressibleMultiphaseMixture.C
LIB = $(FOAM_LIBBIN)/libincompressibleMultiphaseMixture

View File

@ -1,14 +0,0 @@
EXE_INC = \
-IalphaContactAngle \
-I$(LIB_SRC)/physicalProperties/lnInclude \
-I$(LIB_SRC)/multiphaseModels/multiphaseProperties/lnInclude \
-I$(LIB_SRC)/twoPhaseModels/interfaceProperties/lnInclude \
-I$(LIB_SRC)/finiteVolume/lnInclude \
-I$(LIB_SRC)/meshTools/lnInclude
LIB_LIBS = \
-linterfaceProperties \
-lphysicalProperties \
-lmultiphaseProperties \
-lfiniteVolume \
-lmeshTools

View File

@ -1,595 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
#include "incompressibleMultiphaseMixture.H"
#include "alphaContactAngleFvPatchScalarField.H"
#include "correctContactAngle.H"
#include "Time.H"
#include "subCycle.H"
#include "MULES.H"
#include "surfaceInterpolate.H"
#include "fvcGrad.H"
#include "fvcSnGrad.H"
#include "fvcDiv.H"
#include "fvcFlux.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::incompressibleMultiphaseMixture::calcAlphas()
{
scalar level = 0.0;
alphas_ == 0.0;
forAll(phases_, phasei)
{
alphas_ += level*phases_[phasei];
level += 1.0;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::incompressibleMultiphaseMixture::incompressibleMultiphaseMixture
(
const volVectorField& U,
const surfaceScalarField& phi
)
:
IOdictionary
(
IOobject
(
"phaseProperties",
U.time().constant(),
U.db(),
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
),
phases_(lookup("phases"), incompressiblePhase::iNew(U.mesh())),
mesh_(U.mesh()),
U_(U),
phi_(phi),
rhoPhi_
(
IOobject
(
"rhoPhi",
mesh_.time().name(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimMass/dimTime, 0)
),
alphas_
(
IOobject
(
"alphas",
mesh_.time().name(),
mesh_,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh_,
dimensionedScalar(dimless, 0)
),
nu_
(
IOobject
(
"nu",
mesh_.time().name(),
mesh_
),
mu()/rho()
),
sigmas_(lookup("sigmas")),
dimSigma_(1, 0, -2, 0, 0),
deltaN_
(
"deltaN",
1e-8/pow(average(mesh_.V()), 1.0/3.0)
)
{
calcAlphas();
alphas_.write();
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp<Foam::volScalarField>
Foam::incompressibleMultiphaseMixture::rho() const
{
tmp<volScalarField> trho
(
phases_[0]*phases_[0].rho()
);
volScalarField& rho = trho.ref();
for (label phasei=1; phasei<phases_.size(); phasei++)
{
rho += phases_[phasei]*phases_[phasei].rho();
}
return trho;
}
Foam::tmp<Foam::scalarField>
Foam::incompressibleMultiphaseMixture::rho(const label patchi) const
{
tmp<scalarField> trho
(
phases_[0].boundaryField()[patchi]*phases_[0].rho().value()
);
scalarField& rho = trho.ref();
for (label phasei=1; phasei<phases_.size(); phasei++)
{
rho +=
phases_[phasei].boundaryField()[patchi]
*phases_[phasei].rho().value();
}
return trho;
}
Foam::tmp<Foam::volScalarField>
Foam::incompressibleMultiphaseMixture::mu() const
{
tmp<volScalarField> tmu
(
phases_[0]*phases_[0].rho()*phases_[0].nu()
);
volScalarField& mu = tmu.ref();
for (label phasei=1; phasei<phases_.size(); phasei++)
{
mu += phases_[phasei]*phases_[phasei].rho()*phases_[phasei].nu();
}
return tmu;
}
Foam::tmp<Foam::scalarField>
Foam::incompressibleMultiphaseMixture::mu(const label patchi) const
{
tmp<scalarField> tmu
(
phases_[0].boundaryField()[patchi]
*phases_[0].rho().value()
*phases_[0].nu(patchi)
);
scalarField& mu = tmu.ref();
for (label phasei=1; phasei<phases_.size(); phasei++)
{
mu +=
phases_[phasei].boundaryField()[patchi]
*phases_[phasei].rho().value()
*phases_[phasei].nu(patchi);
}
return tmu;
}
Foam::tmp<Foam::surfaceScalarField>
Foam::incompressibleMultiphaseMixture::muf() const
{
tmp<surfaceScalarField> tmuf
(
fvc::interpolate(phases_[0])
*phases_[0].rho()*fvc::interpolate(phases_[0].nu())
);
surfaceScalarField& muf = tmuf.ref();
for (label phasei=1; phasei<phases_.size(); phasei++)
{
muf +=
fvc::interpolate(phases_[phasei])
*phases_[phasei].rho()*fvc::interpolate(phases_[phasei].nu());
}
return tmuf;
}
Foam::tmp<Foam::volScalarField>
Foam::incompressibleMultiphaseMixture::nu() const
{
return nu_;
}
Foam::tmp<Foam::scalarField>
Foam::incompressibleMultiphaseMixture::nu(const label patchi) const
{
return nu_.boundaryField()[patchi];
}
Foam::tmp<Foam::surfaceScalarField>
Foam::incompressibleMultiphaseMixture::nuf() const
{
return muf()/fvc::interpolate(rho());
}
Foam::tmp<Foam::surfaceScalarField>
Foam::incompressibleMultiphaseMixture::surfaceTensionForce() const
{
tmp<surfaceScalarField> tstf
(
surfaceScalarField::New
(
"surfaceTensionForce",
mesh_,
dimensionedScalar(dimensionSet(1, -2, -2, 0, 0), 0)
)
);
surfaceScalarField& stf = tstf.ref();
forAll(phases_, phasei)
{
const incompressiblePhase& alpha1 = phases_[phasei];
for (label phasej = phasei+1; phasej<phases_.size(); phasej++)
{
const incompressiblePhase& alpha2 = phases_[phasej];
sigmaTable::const_iterator sigma =
sigmas_.find(interfacePair(alpha1, alpha2));
if (sigma == sigmas_.end())
{
FatalErrorInFunction
<< "Cannot find interface " << interfacePair(alpha1, alpha2)
<< " in list of sigma values"
<< exit(FatalError);
}
stf += dimensionedScalar(dimSigma_, sigma())
*fvc::interpolate(K(alpha1, alpha2))*
(
fvc::interpolate(alpha2)*fvc::snGrad(alpha1)
- fvc::interpolate(alpha1)*fvc::snGrad(alpha2)
);
}
}
return tstf;
}
void Foam::incompressibleMultiphaseMixture::solve()
{
correct();
const Time& runTime = mesh_.time();
const dictionary& alphaControls = mesh_.solution().solverDict("alpha");
label nAlphaSubCycles(alphaControls.lookup<label>("nAlphaSubCycles"));
scalar cAlpha(alphaControls.lookup<scalar>("cAlpha"));
if (nAlphaSubCycles > 1)
{
surfaceScalarField rhoPhiSum
(
IOobject
(
"rhoPhiSum",
runTime.name(),
mesh_
),
mesh_,
dimensionedScalar(rhoPhi_.dimensions(), 0)
);
dimensionedScalar totalDeltaT = runTime.deltaT();
List<volScalarField*> alphaPtrs(phases_.size());
forAll(phases_, phasei)
{
alphaPtrs[phasei] = &phases_[phasei];
}
for
(
subCycle<volScalarField, subCycleFields> alphaSubCycle
(
alphaPtrs,
nAlphaSubCycles
);
!(++alphaSubCycle).end();
)
{
solveAlphas(cAlpha);
rhoPhiSum += (runTime.deltaT()/totalDeltaT)*rhoPhi_;
}
rhoPhi_ = rhoPhiSum;
}
else
{
solveAlphas(cAlpha);
}
// Update the mixture kinematic viscosity
nu_ = mu()/rho();
}
void Foam::incompressibleMultiphaseMixture::correct()
{
forAll(phases_, phasei)
{
phases_[phasei].correct();
}
}
Foam::tmp<Foam::surfaceVectorField>
Foam::incompressibleMultiphaseMixture::nHatfv
(
const volScalarField& alpha1,
const volScalarField& alpha2
) const
{
/*
// Cell gradient of alpha
volVectorField gradAlpha =
alpha2*fvc::grad(alpha1) - alpha1*fvc::grad(alpha2);
// Interpolated face-gradient of alpha
surfaceVectorField gradAlphaf = fvc::interpolate(gradAlpha);
*/
surfaceVectorField gradAlphaf
(
fvc::interpolate(alpha2)*fvc::interpolate(fvc::grad(alpha1))
- fvc::interpolate(alpha1)*fvc::interpolate(fvc::grad(alpha2))
);
// Face unit interface normal
return gradAlphaf/(mag(gradAlphaf) + deltaN_);
}
Foam::tmp<Foam::surfaceScalarField> Foam::incompressibleMultiphaseMixture::nHatf
(
const volScalarField& alpha1,
const volScalarField& alpha2
) const
{
// Face unit interface normal flux
return nHatfv(alpha1, alpha2) & mesh_.Sf();
}
Foam::tmp<Foam::volScalarField> Foam::incompressibleMultiphaseMixture::K
(
const phase& alpha1,
const phase& alpha2
) const
{
tmp<surfaceVectorField> tnHatfv = nHatfv(alpha1, alpha2);
correctContactAngle
(
alpha1,
alpha2,
U_.boundaryField(),
deltaN_,
tnHatfv.ref().boundaryFieldRef()
);
// Simple expression for curvature
return -fvc::div(tnHatfv & mesh_.Sf());
}
Foam::tmp<Foam::volScalarField>
Foam::incompressibleMultiphaseMixture::nearInterface() const
{
tmp<volScalarField> tnearInt
(
volScalarField::New
(
"nearInterface",
mesh_,
dimensionedScalar(dimless, 0)
)
);
forAll(phases_, phasei)
{
tnearInt.ref() = max
(
tnearInt(),
pos0(phases_[phasei] - 0.01)*pos0(0.99 - phases_[phasei])
);
}
return tnearInt;
}
void Foam::incompressibleMultiphaseMixture::solveAlphas
(
const scalar cAlpha
)
{
word alphaScheme("div(phi,alpha)");
word alpharScheme("div(phirb,alpha)");
surfaceScalarField phic(mag(phi_/mesh_.magSf()));
phic = min(cAlpha*phic, max(phic));
UPtrList<const volScalarField> alphas(phases_.size());
PtrList<surfaceScalarField> alphaPhis(phases_.size());
forAll(phases_, phasei)
{
const incompressiblePhase& alpha = phases_[phasei];
alphas.set(phasei, &alpha);
alphaPhis.set
(
phasei,
new surfaceScalarField
(
"phi" + alpha.name() + "Corr",
fvc::flux
(
phi_,
alpha,
alphaScheme
)
)
);
surfaceScalarField& alphaPhi = alphaPhis[phasei];
forAll(phases_, phasej)
{
incompressiblePhase& alpha2 = phases_[phasej];
if (&alpha2 == &alpha) continue;
surfaceScalarField phir(phic*nHatf(alpha, alpha2));
alphaPhi += fvc::flux
(
-fvc::flux(-phir, alpha2, alpharScheme),
alpha,
alpharScheme
);
}
// Limit alphaPhi for each phase
MULES::limit
(
1.0/mesh_.time().deltaT().value(),
geometricOneField(),
alpha,
phi_,
alphaPhi,
zeroField(),
zeroField(),
oneField(),
zeroField(),
false
);
}
MULES::limitSum(alphas, alphaPhis, phi_);
rhoPhi_ = dimensionedScalar(dimensionSet(1, 0, -1, 0, 0), 0);
volScalarField sumAlpha
(
IOobject
(
"sumAlpha",
mesh_.time().name(),
mesh_
),
mesh_,
dimensionedScalar(dimless, 0)
);
forAll(phases_, phasei)
{
incompressiblePhase& alpha = phases_[phasei];
surfaceScalarField& alphaPhi = alphaPhis[phasei];
MULES::explicitSolve
(
geometricOneField(),
alpha,
alphaPhi
);
rhoPhi_ += alphaPhi*alpha.rho();
Info<< alpha.name() << " volume fraction, min, max = "
<< alpha.weightedAverage(mesh_.V()).value()
<< ' ' << min(alpha).value()
<< ' ' << max(alpha).value()
<< endl;
sumAlpha += alpha;
}
Info<< "Phase-sum volume fraction, min, max = "
<< sumAlpha.weightedAverage(mesh_.V()).value()
<< ' ' << min(sumAlpha).value()
<< ' ' << max(sumAlpha).value()
<< endl;
// Correct the sum of the phase-fractions to avoid 'drift'
volScalarField sumCorr(1.0 - sumAlpha);
forAll(phases_, phasei)
{
incompressiblePhase& alpha = phases_[phasei];
alpha += alpha*sumCorr;
}
calcAlphas();
}
bool Foam::incompressibleMultiphaseMixture::read()
{
if (regIOobject::read())
{
lookup("sigmas") >> sigmas_;
return true;
}
else
{
return false;
}
}
// ************************************************************************* //

View File

@ -1,270 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::incompressibleMultiphaseMixture
Description
Incompressible multiphase mixture with built in solution for the
phase fractions with interface compression for interface-capturing.
Derived from viscosity so that it can be used in conjunction
with the incompressible turbulence models.
Surface tension and contact-angle is handled for the interface
between each phase-pair.
SourceFiles
incompressibleMultiphaseMixture.C
\*---------------------------------------------------------------------------*/
#ifndef incompressibleMultiphaseMixture_H
#define incompressibleMultiphaseMixture_H
#include "viscosity.H"
#include "IOdictionary.H"
#include "incompressiblePhase.H"
#include "PtrListDictionary.H"
#include "volFields.H"
#include "surfaceFields.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class incompressibleMultiphaseMixture Declaration
\*---------------------------------------------------------------------------*/
class incompressibleMultiphaseMixture
:
public IOdictionary,
public viscosity
{
public:
class interfacePair
:
public Pair<word>
{
public:
class hash
:
public Hash<interfacePair>
{
public:
hash()
{}
label operator()(const interfacePair& key) const
{
return word::hash()(key.first()) + word::hash()(key.second());
}
};
// Constructors
interfacePair()
{}
interfacePair(const word& alpha1Name, const word& alpha2Name)
:
Pair<word>(alpha1Name, alpha2Name)
{}
interfacePair(const phase& alpha1, const phase& alpha2)
:
Pair<word>(alpha1.name(), alpha2.name())
{}
// Friend Operators
friend bool operator==
(
const interfacePair& a,
const interfacePair& b
)
{
return
(
((a.first() == b.first()) && (a.second() == b.second()))
|| ((a.first() == b.second()) && (a.second() == b.first()))
);
}
friend bool operator!=
(
const interfacePair& a,
const interfacePair& b
)
{
return (!(a == b));
}
};
private:
// Private Data
//- Dictionary of phases
PtrListDictionary<incompressiblePhase> phases_;
const fvMesh& mesh_;
const volVectorField& U_;
const surfaceScalarField& phi_;
surfaceScalarField rhoPhi_;
volScalarField alphas_;
volScalarField nu_;
typedef HashTable<scalar, interfacePair, interfacePair::hash>
sigmaTable;
sigmaTable sigmas_;
dimensionSet dimSigma_;
//- Stabilisation for normalisation of the interface normal
const dimensionedScalar deltaN_;
// Private Member Functions
void calcAlphas();
void solveAlphas(const scalar cAlpha);
tmp<surfaceVectorField> nHatfv
(
const volScalarField& alpha1,
const volScalarField& alpha2
) const;
tmp<surfaceScalarField> nHatf
(
const volScalarField& alpha1,
const volScalarField& alpha2
) const;
tmp<volScalarField> K(const phase& alpha1, const phase& alpha2) const;
public:
// Constructors
//- Construct from components
incompressibleMultiphaseMixture
(
const volVectorField& U,
const surfaceScalarField& phi
);
//- Destructor
virtual ~incompressibleMultiphaseMixture()
{}
// Member Functions
//- Return the phases
const PtrListDictionary<incompressiblePhase>& phases() const
{
return phases_;
}
//- Return the velocity
const volVectorField& U() const
{
return U_;
}
//- Return the volumetric flux
const surfaceScalarField& phi() const
{
return phi_;
}
const surfaceScalarField& rhoPhi() const
{
return rhoPhi_;
}
//- Return the mixture density
tmp<volScalarField> rho() const;
//- Return the mixture density for patch
tmp<scalarField> rho(const label patchi) const;
//- Return the dynamic laminar viscosity
tmp<volScalarField> mu() const;
//- Return the dynamic laminar viscosity for patch
tmp<scalarField> mu(const label patchi) const;
//- Return the face-interpolated dynamic laminar viscosity
tmp<surfaceScalarField> muf() const;
//- Return the kinematic laminar viscosity
tmp<volScalarField> nu() const;
//- Return the laminar viscosity for patch
tmp<scalarField> nu(const label patchi) const;
//- Return the face-interpolated dynamic laminar viscosity
tmp<surfaceScalarField> nuf() const;
tmp<surfaceScalarField> surfaceTensionForce() const;
//- Indicator of the proximity of the interface
// Field values are 1 near and 0 away for the interface.
tmp<volScalarField> nearInterface() const;
//- Solve for the mixture phase-fractions
void solve();
//- Correct the mixture properties
void correct();
//- Read base phaseProperties dictionary
bool read();
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,66 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
\*---------------------------------------------------------------------------*/
#include "incompressiblePhase.H"
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::incompressiblePhase::incompressiblePhase
(
const word& name,
const fvMesh& mesh
)
:
phase(name, mesh),
nuModel_(viscosityModel::New(mesh, name)),
rho_("rho", dimDensity, nuModel_())
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
Foam::autoPtr<Foam::incompressiblePhase>
Foam::incompressiblePhase::clone() const
{
NotImplemented;
return autoPtr<incompressiblePhase>(nullptr);
}
void Foam::incompressiblePhase::correct()
{
nuModel_->correct();
}
bool Foam::incompressiblePhase::read(const dictionary& dict)
{
dict.lookup("rho") >> rho_;
return true;
}
// ************************************************************************* //

View File

@ -1,148 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Class
Foam::incompressiblePhase
Description
Single incompressible phase derived from the phase.
Used as part of the multiphaseMixture for interface-capturing
multiphase simulations.
SourceFiles
incompressiblePhase.C
\*---------------------------------------------------------------------------*/
#ifndef incompressiblePhase_H
#define incompressiblePhase_H
#include "phase.H"
#include "dictionaryEntry.H"
#include "viscosityModel.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
namespace Foam
{
/*---------------------------------------------------------------------------*\
Class incompressiblePhase Declaration
\*---------------------------------------------------------------------------*/
class incompressiblePhase
:
public phase
{
// Private Data
autoPtr<viscosityModel> nuModel_;
dimensionedScalar rho_;
public:
// Constructors
//- Construct from components
incompressiblePhase
(
const word& name,
const fvMesh& mesh
);
//- Return clone
autoPtr<incompressiblePhase> clone() const;
//- Return a pointer to a new incompressiblePhase created on freestore
// from Istream
class iNew
{
const fvMesh& mesh_;
public:
iNew(const fvMesh& mesh)
:
mesh_(mesh)
{}
autoPtr<incompressiblePhase> operator()(Istream& is) const
{
const word name(is);
return autoPtr<incompressiblePhase>
(
new incompressiblePhase(name, mesh_)
);
}
};
// Member Functions
//- Return const-access to incompressiblePhase1 viscosityModel
const viscosityModel& nuModel() const
{
return nuModel_();
}
//- Return the kinematic laminar viscosity
tmp<volScalarField> nu() const
{
return nuModel_->nu();
}
//- Return the laminar viscosity for patch
tmp<scalarField> nu(const label patchi) const
{
return nuModel_->nu(patchi);
}
//- Return const-access to incompressiblePhase1 density
const dimensionedScalar& rho() const
{
return rho_;
}
//- Correct the incompressiblePhase properties
void correct();
//- Inherit read from phase
using phase::read;
//- Read base incompressiblePhaseProperties dictionary
bool read(const dictionary& incompressiblePhaseDict);
};
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
} // End namespace Foam
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
#endif
// ************************************************************************* //

View File

@ -1,50 +0,0 @@
tmp<volScalarField> rAU;
if (correctPhi)
{
rAU = new volScalarField
(
IOobject
(
"rAU",
runTime.name(),
mesh,
IOobject::READ_IF_PRESENT,
IOobject::AUTO_WRITE
),
mesh,
dimensionedScalar(dimTime/dimDensity, 1)
);
correctUphiBCs(U, phi, true);
CorrectPhi
(
phi,
U,
p_rgh,
surfaceScalarField("rAUf", fvc::interpolate(rAU())),
geometricZeroField(),
pressureReference,
pimple
);
#include "continuityErrs.H"
}
else
{
correctUphiBCs(U, phi, true);
CorrectPhi
(
phi,
U,
p_rgh,
dimensionedScalar(dimTime/rho.dimensions(), 1),
geometricZeroField(),
pressureReference,
pimple
);
#include "continuityErrs.H"
}

View File

@ -1,159 +0,0 @@
/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2011-2023 OpenFOAM Foundation
\\/ M anipulation |
-------------------------------------------------------------------------------
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/>.
Application
multiphaseInterFoam
Description
Solver for n incompressible fluids which captures the interfaces and
includes surface-tension and contact-angle effects for each phase, with
optional mesh motion and mesh topology changes.
Turbulence modelling is generic, i.e. laminar, RAS or LES may be selected.
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "incompressibleMultiphaseMixture.H"
#include "incompressibleMomentumTransportModels.H"
#include "pimpleControl.H"
#include "pressureReference.H"
#include "fvModels.H"
#include "fvConstraints.H"
#include "CorrectPhi.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
int main(int argc, char *argv[])
{
#include "postProcess.H"
#include "setRootCaseLists.H"
#include "createTime.H"
#include "createMesh.H"
#include "initContinuityErrs.H"
#include "createDyMControls.H"
#include "createFields.H"
#include "initCorrectPhi.H"
#include "createUfIfPresent.H"
turbulence->validate();
#include "CourantNo.H"
#include "setInitialDeltaT.H"
const surfaceScalarField& rhoPhi(mixture.rhoPhi());
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
Info<< "\nStarting time loop\n" << endl;
while (pimple.run(runTime))
{
#include "readDyMControls.H"
#include "CourantNo.H"
#include "alphaCourantNo.H"
#include "setDeltaT.H"
fvModels.preUpdateMesh();
// Update the mesh for topology change, mesh to mesh mapping
mesh.update();
runTime++;
Info<< "Time = " << runTime.userTimeName() << nl << endl;
// --- Pressure-velocity PIMPLE corrector loop
while (pimple.loop())
{
if (pimple.firstPimpleIter() || pimple.moveMeshOuterCorrectors())
{
scalar timeBeforeMeshUpdate = runTime.elapsedCpuTime();
// Move the mesh
mesh.move();
if (mesh.changing())
{
Info<< "Execution time for mesh.update() = "
<< runTime.elapsedCpuTime() - timeBeforeMeshUpdate
<< " s" << endl;
gh = (g & mesh.C()) - ghRef;
ghf = (g & mesh.Cf()) - ghRef;
MRF.update();
if (correctPhi)
{
#include "correctPhi.H"
}
mixture.correct();
if (checkMeshCourantNo)
{
#include "meshCourantNo.H"
}
}
}
fvModels.correct();
mixture.solve();
rho = mixture.rho();
if (pimple.predictTransport())
{
turbulence->predict();
}
#include "UEqn.H"
// --- Pressure corrector loop
while (pimple.correct())
{
#include "pEqn.H"
}
if (pimple.correctTransport())
{
turbulence->correct();
}
}
runTime.write();
Info<< "ExecutionTime = " << runTime.elapsedCpuTime() << " s"
<< " ClockTime = " << runTime.elapsedClockTime() << " s"
<< nl << endl;
}
Info<< "End\n" << endl;
return 0;
}
// ************************************************************************* //

View File

@ -1,94 +0,0 @@
{
if (rAU.valid())
{
rAU.ref() = 1.0/UEqn.A();
}
else
{
rAU = 1.0/UEqn.A();
}
surfaceScalarField rAUf("rAUf", fvc::interpolate(rAU()));
volVectorField HbyA(constrainHbyA(rAU()*UEqn.H(), U, p_rgh));
surfaceScalarField phiHbyA
(
"phiHbyA",
fvc::flux(HbyA)
+ MRF.zeroFilter(fvc::interpolate(rho*rAU())*fvc::ddtCorr(U, phi, Uf))
);
MRF.makeRelative(phiHbyA);
if (p_rgh.needReference())
{
fvc::makeRelative(phiHbyA, U);
adjustPhi(phiHbyA, U, p_rgh);
fvc::makeAbsolute(phiHbyA, U);
}
surfaceScalarField phig
(
(
mixture.surfaceTensionForce()
- ghf*fvc::snGrad(rho)
)*rAUf*mesh.magSf()
);
phiHbyA += phig;
// Update the pressure BCs to ensure flux consistency
constrainPressure(p_rgh, U, phiHbyA, rAUf, MRF);
while (pimple.correctNonOrthogonal())
{
fvScalarMatrix p_rghEqn
(
fvm::laplacian(rAUf, p_rgh) == fvc::div(phiHbyA)
);
p_rghEqn.setReference
(
pressureReference.refCell(),
getRefCellValue(p_rgh, pressureReference.refCell())
);
p_rghEqn.solve();
if (pimple.finalNonOrthogonalIter())
{
phi = phiHbyA - p_rghEqn.flux();
p_rgh.relax();
U = HbyA + rAU()*fvc::reconstruct((phig - p_rghEqn.flux())/rAUf);
U.correctBoundaryConditions();
fvConstraints.constrain(U);
}
}
#include "continuityErrs.H"
// Correct Uf if the mesh is moving
fvc::correctUf(Uf, U, phi, MRF);
// Make the fluxes relative to the mesh motion
fvc::makeRelative(phi, U);
p == p_rgh + rho*gh;
if (p_rgh.needReference())
{
p += dimensionedScalar
(
"p",
p.dimensions(),
pressureReference.refValue()
- getRefCellValue(p, pressureReference.refCell())
);
p_rgh = p - rho*gh;
}
if (!correctPhi)
{
rAU.clear();
}
}