/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration |
\\ / A nd | www.openfoam.com
\\/ M anipulation |
-------------------------------------------------------------------------------
Copyright (C) 2020-2021 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 .
\*---------------------------------------------------------------------------*/
#include "LiquidEvapFuchsKnudsen.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template
void Foam::LiquidEvapFuchsKnudsen::calcXcSolution
(
const scalar massliq,
const scalar masssol,
scalar& Xliq,
scalar& Xsol
) const
{
const scalar Yliq = massliq/(massliq + masssol);
const scalar Ysol = 1 - Yliq;
Xliq = Yliq/liquids_.properties()[liqToLiqMap_].W();
Xsol = Ysol/this->owner().thermo().solids().properties()[solToSolMap_].W();
Xliq /= (Xliq + Xsol);
Xsol = 1 - Xliq;
}
template
Foam::tmp Foam::LiquidEvapFuchsKnudsen::calcXc
(
const label celli
) const
{
scalarField Xc(this->owner().thermo().carrier().Y().size());
forAll(Xc, i)
{
Xc[i] =
this->owner().thermo().carrier().Y()[i][celli]
/this->owner().thermo().carrier().W(i);
}
return Xc/sum(Xc);
}
template
Foam::scalar Foam::LiquidEvapFuchsKnudsen::Sh
(
const scalar Re,
const scalar Sc
) const
{
return cbrt(1 + Sc*Re)*max(1, pow(Re, 0.077));
}
template
Foam::scalar Foam::LiquidEvapFuchsKnudsen::activityCoeff
(
const scalar Xliq,
const scalar Xsol
) const
{
switch (method_)
{
case pUNIFAC:
{
FatalErrorInFunction
<< "Activity coefficient UNIFAC is not implemented " << nl
<< abort(FatalError);
break;
}
case pHoff:
{
const scalar ic = this->coeffDict().getScalar("ic");
return inv((1 + ic*Xsol/(Xliq + ROOTVSMALL)));
break;
}
}
return -1;
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::LiquidEvapFuchsKnudsen::LiquidEvapFuchsKnudsen
(
const dictionary& dict,
CloudType& owner
)
:
PhaseChangeModel(dict, owner, typeName),
method_(pHoff),
gamma_(this->coeffDict().getScalar("gamma")),
alpha_(this->coeffDict().getScalar("alpham")),
liquids_(owner.thermo().liquids()),
solution_(this->coeffDict().lookup("solution")),
liqToCarrierMap_(-1),
liqToLiqMap_(-1),
solToSolMap_(-1)
{
if (solution_.size() > 2)
{
FatalErrorInFunction
<< "Solution is not well defined. It should be (liquid solid)"
<< nl << exit(FatalError);
}
else
{
Info<< "Participating liquid-solid species:" << endl;
Info<< " " << solution_[0] << endl;
liqToCarrierMap_ =
owner.composition().carrierId(solution_[0]);
// Determine mapping between model active liquids and global liquids
const label idLiquid = owner.composition().idLiquid();
liqToLiqMap_ =
owner.composition().localId(idLiquid, solution_[0]);
// Mapping for the solid
const label idSolid = owner.composition().idSolid();
solToSolMap_ =
owner.composition().localId(idSolid, solution_[1]);
const word activityCoefficienType
(
this->coeffDict().getWord("activityCoefficient")
);
if (activityCoefficienType == "Hoff")
{
method_ = pHoff;
}
else if (activityCoefficienType == "UNIFAC")
{
method_ = pUNIFAC;
}
else
{
FatalErrorInFunction
<< "activityCoefficient must be either 'Hoff' or 'UNIFAC'"
<< nl << exit(FatalError);
}
}
}
template
Foam::LiquidEvapFuchsKnudsen::LiquidEvapFuchsKnudsen
(
const LiquidEvapFuchsKnudsen& pcm
)
:
PhaseChangeModel(pcm),
method_(pcm.method_),
gamma_(pcm.gamma_),
alpha_(pcm.alpha_),
liquids_(pcm.owner().thermo().liquids()),
solution_(pcm.solution_),
liqToCarrierMap_(pcm.liqToCarrierMap_),
liqToLiqMap_(pcm.liqToLiqMap_),
solToSolMap_(pcm.solToSolMap_)
{}
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template
void Foam::LiquidEvapFuchsKnudsen::calculate
(
const scalar dt,
const label celli,
const scalar Re,
const scalar Pr,
const scalar d,
const scalar nu,
const scalar rho,
const scalar T,
const scalar Ts,
const scalar pc,
const scalar Tc,
const scalarField& X,
const scalarField& solMass,
const scalarField& liqMass,
scalarField& dMassPC
) const
{
const scalar rhog = this->owner().thermo().thermo().rho()()[celli];
const label gid = liqToCarrierMap_;
const label lid = liqToLiqMap_;
const label sid = solToSolMap_;
const scalar W = liquids_.properties()[lid].W();
const scalar YeInf = this->owner().thermo().carrier().Y()[gid][celli];
const scalar sigma = liquids_.properties()[lid].sigma(pc, Ts);
// Kelvin effect
const scalar Ke = exp(4*sigma*W/(RR*rho*d*T));
// vapour diffusivity [m2/s]
const scalar Dab = liquids_.properties()[lid].D(pc, Ts);
// saturation pressure for species i [pa]
const scalar pSat = liquids_.properties()[lid].pv(pc, T);
scalar Xliq(0), Xsol(0);
calcXcSolution(liqMass[lid], solMass[sid], Xliq, Xsol);
// Activity Coefficient (gammaE*Xe)
const scalar gamma = activityCoeff(Xliq, Xsol);
// water concentration at surface
const scalar Rliq = RR/W;
const scalar YeSurf = max(gamma*Ke*pSat/(Rliq*T*rhog), 0);
const scalar Kn = 2*gamma_/d;
const scalar Cm =
(1+Kn)/(1+ (4/(3*alpha_) + 0.377)*Kn + sqr(Kn)*4/(3*alpha_));
// Schmidt number
const scalar Sc = nu/(Dab + ROOTVSMALL);
// Sherwood number
const scalar Sherwood = Sh(Re, Sc);
// mass flux density [kg/m2/s]
const scalar Ni = (rhog*Sherwood*Dab*Cm/d)*log((1 - YeInf)/(1 - YeSurf));
// mass transfer [kg]
const scalar As = Foam::constant::mathematical::pi*d*d;
dMassPC[lid] += Ni*As*dt;
}
template
Foam::scalar Foam::LiquidEvapFuchsKnudsen::dh
(
const label idc,
const label idl,
const scalar p,
const scalar T
) const
{
scalar dh = 0;
typedef PhaseChangeModel parent;
switch (parent::enthalpyTransfer_)
{
case (parent::etLatentHeat):
{
dh = liquids_.properties()[idl].hl(p, T);
break;
}
case (parent::etEnthalpyDifference):
{
scalar hc = this->owner().composition().carrier().Ha(idc, p, T);
scalar hp = liquids_.properties()[idl].h(p, T);
dh = hc - hp;
break;
}
default:
{
FatalErrorInFunction
<< "Unknown enthalpyTransfer type" << abort(FatalError);
}
}
return dh;
}
template
Foam::scalar Foam::LiquidEvapFuchsKnudsen::Tvap
(
const scalarField& X
) const
{
return Zero;
}
template
Foam::scalar Foam::LiquidEvapFuchsKnudsen::TMax
(
const scalar p,
const scalarField& X
) const
{
// If liquid is present calculates pvInter
if (sum(X) > SMALL)
{
return liquids_.pvInvert(p, X);
}
else
{
return GREAT;
}
}
// ************************************************************************* //