/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2011-2017 OpenFOAM Foundation
-------------------------------------------------------------------------------
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 .
\*---------------------------------------------------------------------------*/
#include "multiphaseMixture.H"
#include "alphaContactAngleFvPatchScalarField.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"
#include "unitConversion.H"
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
void Foam::multiphaseMixture::calcAlphas()
{
scalar level = 0.0;
alphas_ == 0.0;
for (const phase& ph : phases_)
{
alphas_ += level * ph;
level += 1.0;
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::multiphaseMixture::multiphaseMixture
(
const volVectorField& U,
const surfaceScalarField& phi
)
:
IOdictionary
(
IOobject
(
"transportProperties",
U.time().constant(),
U.db(),
IOobject::MUST_READ_IF_MODIFIED,
IOobject::NO_WRITE
)
),
phases_(lookup("phases"), phase::iNew(U, phi)),
mesh_(U.mesh()),
U_(U),
phi_(phi),
rhoPhi_
(
IOobject
(
"rhoPhi",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::NO_WRITE
),
mesh_,
dimensionedScalar(dimMass/dimTime, Zero)
),
alphas_
(
IOobject
(
"alphas",
mesh_.time().timeName(),
mesh_,
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
mesh_,
dimensionedScalar(dimless, Zero)
),
nu_
(
IOobject
(
"nu",
mesh_.time().timeName(),
mesh_
),
mu()/rho()
),
sigmas_(lookup("sigmas")),
dimSigma_(1, 0, -2, 0, 0),
deltaN_
(
"deltaN",
1e-8/cbrt(average(mesh_.V()))
)
{
rhoPhi_.setOriented();
calcAlphas();
alphas_.write();
}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
Foam::tmp
Foam::multiphaseMixture::rho() const
{
auto iter = phases_.cbegin();
tmp trho = iter()*iter().rho();
volScalarField& rho = trho.ref();
for (++iter; iter != phases_.cend(); ++iter)
{
rho += iter()*iter().rho();
}
return trho;
}
Foam::tmp
Foam::multiphaseMixture::rho(const label patchi) const
{
auto iter = phases_.cbegin();
tmp trho = iter().boundaryField()[patchi]*iter().rho().value();
scalarField& rho = trho.ref();
for (++iter; iter != phases_.cend(); ++iter)
{
rho += iter().boundaryField()[patchi]*iter().rho().value();
}
return trho;
}
Foam::tmp
Foam::multiphaseMixture::mu() const
{
auto iter = phases_.cbegin();
tmp tmu = iter()*iter().rho()*iter().nu();
volScalarField& mu = tmu.ref();
for (++iter; iter != phases_.cend(); ++iter)
{
mu += iter()*iter().rho()*iter().nu();
}
return tmu;
}
Foam::tmp
Foam::multiphaseMixture::mu(const label patchi) const
{
auto iter = phases_.cbegin();
tmp tmu =
(
iter().boundaryField()[patchi]
*iter().rho().value()
*iter().nu(patchi)
);
scalarField& mu = tmu.ref();
for (++iter; iter != phases_.cend(); ++iter)
{
mu +=
(
iter().boundaryField()[patchi]
*iter().rho().value()
*iter().nu(patchi)
);
}
return tmu;
}
Foam::tmp
Foam::multiphaseMixture::muf() const
{
auto iter = phases_.cbegin();
tmp tmuf =
fvc::interpolate(iter())*iter().rho()*fvc::interpolate(iter().nu());
surfaceScalarField& muf = tmuf.ref();
for (++iter; iter != phases_.cend(); ++iter)
{
muf +=
fvc::interpolate(iter())*iter().rho()*fvc::interpolate(iter().nu());
}
return tmuf;
}
Foam::tmp
Foam::multiphaseMixture::nu() const
{
return nu_;
}
Foam::tmp
Foam::multiphaseMixture::nu(const label patchi) const
{
return nu_.boundaryField()[patchi];
}
Foam::tmp
Foam::multiphaseMixture::nuf() const
{
return muf()/fvc::interpolate(rho());
}
Foam::tmp
Foam::multiphaseMixture::surfaceTensionForce() const
{
tmp tstf
(
new surfaceScalarField
(
IOobject
(
"surfaceTensionForce",
mesh_.time().timeName(),
mesh_
),
mesh_,
dimensionedScalar(dimensionSet(1, -2, -2, 0, 0), Zero)
)
);
surfaceScalarField& stf = tstf.ref();
stf.setOriented();
forAllConstIters(phases_, iter1)
{
const phase& alpha1 = iter1();
auto iter2 = iter1;
for (++iter2; iter2 != phases_.cend(); ++iter2)
{
const phase& alpha2 = iter2();
auto sigma = sigmas_.cfind(interfacePair(alpha1, alpha2));
if (!sigma.found())
{
FatalErrorInFunction
<< "Cannot find interface " << interfacePair(alpha1, alpha2)
<< " in list of sigma values"
<< exit(FatalError);
}
stf += dimensionedScalar("sigma", dimSigma_, *sigma)
*fvc::interpolate(K(alpha1, alpha2))*
(
fvc::interpolate(alpha2)*fvc::snGrad(alpha1)
- fvc::interpolate(alpha1)*fvc::snGrad(alpha2)
);
}
}
return tstf;
}
void Foam::multiphaseMixture::solve()
{
correct();
const Time& runTime = mesh_.time();
volScalarField& alpha = phases_.first();
const dictionary& alphaControls = mesh_.solverDict("alpha");
label nAlphaSubCycles(alphaControls.get