/*---------------------------------------------------------------------------*\
========= |
\\ / F ield | OpenFOAM: The Open Source CFD Toolbox
\\ / O peration | Website: https://openfoam.org
\\ / A nd | Copyright (C) 2020-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 .
\*---------------------------------------------------------------------------*/
#include "HeatTransferPhaseSystem.H"
#include "fvmSup.H"
#include "rhoFluidMulticomponentThermo.H"
// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
template
void Foam::HeatTransferPhaseSystem::addDmdtHefs
(
const phaseSystem::dmdtfTable& dmdtfs,
phaseSystem::heatTransferTable& eqns
) const
{
// Loop the pairs
forAllConstIter(phaseSystem::dmdtfTable, dmdtfs, dmdtfIter)
{
const phaseInterface interface(*this, dmdtfIter.key());
const volScalarField& dmdtf = *dmdtfIter();
const volScalarField dmdtf21(posPart(dmdtf));
const volScalarField dmdtf12(negPart(dmdtf));
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
const rhoFluidThermo& thermo1 = phase1.fluidThermo();
const rhoFluidThermo& thermo2 = phase2.fluidThermo();
const volScalarField& he1 = thermo1.he();
const volScalarField& he2 = thermo2.he();
const volScalarField hs1(thermo1.hs());
const volScalarField hs2(thermo2.hs());
const volScalarField K1(phase1.K());
const volScalarField K2(phase2.K());
// Transfer of sensible enthalpy within the phases
*eqns[phase1.name()] +=
dmdtf*hs1 + fvm::Sp(dmdtf12, he1) - dmdtf12*he1;
*eqns[phase2.name()] -=
dmdtf*hs2 + fvm::Sp(dmdtf21, he2) - dmdtf21*he2;
// Transfer of sensible enthalpy between the phases
*eqns[phase1.name()] += dmdtf21*(hs2 - hs1);
*eqns[phase2.name()] -= dmdtf12*(hs1 - hs2);
// Transfer of kinetic energy
*eqns[phase1.name()] += dmdtf21*K2 + dmdtf12*K1;
*eqns[phase2.name()] -= dmdtf12*K1 + dmdtf21*K2;
}
}
template
void Foam::HeatTransferPhaseSystem::addDmidtHefs
(
const phaseSystem::dmidtfTable& dmidtfs,
phaseSystem::heatTransferTable& eqns
) const
{
static const dimensionedScalar one(dimless, 1);
// Loop the pairs
forAllConstIter(phaseSystem::dmidtfTable, dmidtfs, dmidtfIter)
{
const phaseInterface interface(*this, dmidtfIter.key());
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
const rhoFluidThermo& thermo1 = phase1.fluidThermo();
const rhoFluidThermo& thermo2 = phase2.fluidThermo();
const rhoFluidMulticomponentThermo* mcThermoPtr1 =
isA(thermo1)
? &refCast(thermo1)
: static_cast(nullptr);
const rhoFluidMulticomponentThermo* mcThermoPtr2 =
isA(thermo2)
? &refCast(thermo2)
: static_cast(nullptr);
const volScalarField& he1 = thermo1.he();
const volScalarField& he2 = thermo2.he();
const volScalarField hs1(thermo1.hs());
const volScalarField hs2(thermo2.hs());
const volScalarField K1(phase1.K());
const volScalarField K2(phase2.K());
// Loop the species
forAllConstIter(HashPtrTable, *dmidtfIter(), dmidtfJter)
{
const word& specie = dmidtfJter.key();
// Mass transfer rates
const volScalarField& dmidtf = *dmidtfJter();
const volScalarField dmidtf21(posPart(dmidtf));
const volScalarField dmidtf12(negPart(dmidtf));
// Specie indices
const label speciei1 =
mcThermoPtr1 ? mcThermoPtr1->species()[specie] : -1;
const label speciei2 =
mcThermoPtr2 ? mcThermoPtr2->species()[specie] : -1;
// Enthalpies
const volScalarField hsi1
(
mcThermoPtr1
? mcThermoPtr1->hsi(speciei1, thermo1.p(), thermo1.T())
: tmp(hs1)
);
const volScalarField hsi2
(
mcThermoPtr2
? mcThermoPtr2->hsi(speciei2, thermo2.p(), thermo2.T())
: tmp(hs2)
);
// Limited mass fractions
tmp tYi1, tYi2;
if (residualY_ > 0)
{
tYi1 =
mcThermoPtr1
? max(mcThermoPtr1->Y(speciei1), residualY_)
: volScalarField::New("Yi1", this->mesh(), one);
tYi2 =
mcThermoPtr2
? max(mcThermoPtr2->Y(speciei2), residualY_)
: volScalarField::New("Yi2", this->mesh(), one);
}
// Transfer of sensible enthalpy within the phases
*eqns[phase1.name()] += dmidtf*hsi1;
*eqns[phase2.name()] -= dmidtf*hsi2;
if (residualY_ > 0)
{
*eqns[phase1.name()] +=
fvm::Sp(dmidtf12/tYi1(), he1) - dmidtf12/tYi1()*he1;
*eqns[phase2.name()] -=
fvm::Sp(dmidtf21/tYi2(), he2) - dmidtf21/tYi2()*he2;
}
// Transfer of sensible enthalpy between the phases
*eqns[phase1.name()] += dmidtf21*(hsi2 - hsi1);
*eqns[phase2.name()] -= dmidtf12*(hsi1 - hsi2);
// Transfer of kinetic energy
*eqns[phase1.name()] += dmidtf21*K2 + dmidtf12*K1;
*eqns[phase2.name()] -= dmidtf12*K1 + dmidtf21*K2;
}
}
}
template
void Foam::HeatTransferPhaseSystem::addDmdtHefsWithoutL
(
const phaseSystem::dmdtfTable& dmdtfs,
const phaseSystem::dmdtfTable& Tfs,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
// Loop the pairs
forAllConstIter(phaseSystem::dmdtfTable, dmdtfs, dmdtfIter)
{
const phaseInterface interface(*this, dmdtfIter.key());
const volScalarField& dmdtf = *dmdtfIter();
const volScalarField dmdtf21(posPart(dmdtf));
const volScalarField dmdtf12(negPart(dmdtf));
const volScalarField& Tf = *Tfs[dmdtfIter.key()];
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
const rhoFluidThermo& thermo1 = phase1.fluidThermo();
const rhoFluidThermo& thermo2 = phase2.fluidThermo();
const volScalarField& he1 = thermo1.he();
const volScalarField& he2 = thermo2.he();
const volScalarField K1(phase1.K());
const volScalarField K2(phase2.K());
// Interface enthalpies
const volScalarField hsf1(thermo1.hs(thermo1.p(), Tf));
const volScalarField hsf2(thermo2.hs(thermo1.p(), Tf));
// Transfer of energy from the interface into the bulk
switch (scheme)
{
case latentHeatScheme::symmetric:
{
*eqns[phase1.name()] += dmdtf*hsf1;
*eqns[phase2.name()] -= dmdtf*hsf2;
break;
}
case latentHeatScheme::upwind:
{
// Bulk enthalpies
const volScalarField hs1(thermo1.hs());
const volScalarField hs2(thermo2.hs());
*eqns[phase1.name()] += dmdtf21*hsf1 + dmdtf12*hs1;
*eqns[phase2.name()] -= dmdtf12*hsf2 + dmdtf21*hs2;
break;
}
}
*eqns[phase1.name()] += fvm::Sp(dmdtf12, he1) - dmdtf12*he1;
*eqns[phase2.name()] -= fvm::Sp(dmdtf21, he2) - dmdtf21*he2;
// Transfer of kinetic energy
*eqns[phase1.name()] += dmdtf21*K2 + dmdtf12*K1;
*eqns[phase2.name()] -= dmdtf12*K1 + dmdtf21*K2;
}
}
template
void Foam::HeatTransferPhaseSystem::addDmdtL
(
const phaseSystem::dmdtfTable& dmdtfs,
const phaseSystem::dmdtfTable& Tfs,
const scalar weight,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
// Loop the pairs
forAllConstIter(phaseSystem::dmdtfTable, dmdtfs, dmdtfIter)
{
const phaseInterface interface(*this, dmdtfIter.key());
const volScalarField& dmdtf = *dmdtfIter();
const volScalarField dmdtf21(posPart(dmdtf));
const volScalarField dmdtf12(negPart(dmdtf));
const volScalarField& Tf = *Tfs[dmdtfIter.key()];
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
// Latent heat contribution
const volScalarField L(this->L(interface, dmdtf, Tf, scheme));
*eqns[phase1.name()] += ((1 - weight)*dmdtf12 + weight*dmdtf21)*L;
*eqns[phase2.name()] += ((1 - weight)*dmdtf21 + weight*dmdtf12)*L;
}
}
template
void Foam::HeatTransferPhaseSystem::addDmdtHefs
(
const phaseSystem::dmdtfTable& dmdtfs,
const phaseSystem::dmdtfTable& Tfs,
const scalar weight,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
addDmdtHefsWithoutL(dmdtfs, Tfs, scheme, eqns);
addDmdtL(dmdtfs, Tfs, weight, scheme, eqns);
}
template
void Foam::HeatTransferPhaseSystem::addDmidtHefsWithoutL
(
const phaseSystem::dmidtfTable& dmidtfs,
const phaseSystem::dmdtfTable& Tfs,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
static const dimensionedScalar one(dimless, 1);
// Loop the pairs
forAllConstIter(phaseSystem::dmidtfTable, dmidtfs, dmidtfIter)
{
const phaseInterface interface(*this, dmidtfIter.key());
const volScalarField& Tf = *Tfs[dmidtfIter.key()];
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
const rhoFluidThermo& thermo1 = phase1.fluidThermo();
const rhoFluidThermo& thermo2 = phase2.fluidThermo();
const rhoFluidMulticomponentThermo* mcThermoPtr1 =
isA(thermo1)
? &refCast(thermo1)
: static_cast(nullptr);
const rhoFluidMulticomponentThermo* mcThermoPtr2 =
isA(thermo2)
? &refCast(thermo2)
: static_cast(nullptr);
const volScalarField& he1 = thermo1.he();
const volScalarField& he2 = thermo2.he();
const volScalarField K1(phase1.K());
const volScalarField K2(phase2.K());
// Interface enthalpies
const volScalarField hsf1(thermo1.hs(thermo1.p(), Tf));
const volScalarField hsf2(thermo2.hs(thermo2.p(), Tf));
// Loop the species
forAllConstIter(HashPtrTable, *dmidtfIter(), dmidtfJter)
{
const word& specie = dmidtfJter.key();
// Mass transfer rates
const volScalarField& dmidtf = *dmidtfJter();
const volScalarField dmidtf21(posPart(dmidtf));
const volScalarField dmidtf12(negPart(dmidtf));
// Specie indices
const label speciei1 =
mcThermoPtr1 ? mcThermoPtr1->species()[specie] : -1;
const label speciei2 =
mcThermoPtr2 ? mcThermoPtr2->species()[specie] : -1;
// Interface enthalpies
const volScalarField hsfi1
(
mcThermoPtr1
? mcThermoPtr1->hsi(speciei1, thermo1.p(), Tf)
: tmp(hsf1)
);
const volScalarField hsfi2
(
mcThermoPtr2
? mcThermoPtr2->hsi(speciei2, thermo2.p(), Tf)
: tmp(hsf2)
);
// Limited mass fractions
tmp tYi1, tYi2;
if (this->residualY_ > 0)
{
tYi1 =
mcThermoPtr1
? max(mcThermoPtr1->Y(speciei1), this->residualY_)
: volScalarField::New("Yi1", this->mesh(), one);
tYi2 =
mcThermoPtr2
? max(mcThermoPtr2->Y(speciei2), this->residualY_)
: volScalarField::New("Yi2", this->mesh(), one);
}
// Transfer of energy from the interface into the bulk
switch (scheme)
{
case latentHeatScheme::symmetric:
{
*eqns[phase1.name()] += dmidtf*hsfi1;
*eqns[phase2.name()] -= dmidtf*hsfi2;
break;
}
case latentHeatScheme::upwind:
{
// Bulk enthalpies
const volScalarField hsi1
(
mcThermoPtr1
? mcThermoPtr1->hsi(speciei1, thermo1.p(), thermo1.T())
: thermo1.hs()
);
const volScalarField hsi2
(
mcThermoPtr2
? mcThermoPtr2->hsi(speciei2, thermo2.p(), thermo2.T())
: thermo2.hs()
);
*eqns[phase1.name()] += dmidtf21*hsfi1 + dmidtf12*hsi1;
*eqns[phase2.name()] -= dmidtf12*hsfi2 + dmidtf21*hsi2;
break;
}
}
if (this->residualY_ > 0)
{
*eqns[phase1.name()] +=
fvm::Sp(dmidtf12/tYi1(), he1) - dmidtf12/tYi1()*he1;
}
if (this->residualY_ > 0)
{
*eqns[phase2.name()] -=
fvm::Sp(dmidtf21/tYi2(), he2) - dmidtf21/tYi2()*he2;
}
// Transfer of kinetic energy
*eqns[phase1.name()] += dmidtf21*K2 + dmidtf12*K1;
*eqns[phase2.name()] -= dmidtf12*K1 + dmidtf21*K2;
}
}
}
template
void Foam::HeatTransferPhaseSystem::addDmidtL
(
const phaseSystem::dmidtfTable& dmidtfs,
const phaseSystem::dmdtfTable& Tfs,
const scalar weight,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
// Loop the pairs
forAllConstIter(phaseSystem::dmidtfTable, dmidtfs, dmidtfIter)
{
const phaseInterface interface(*this, dmidtfIter.key());
const volScalarField& Tf = *Tfs[dmidtfIter.key()];
const phaseModel& phase1 = interface.phase1();
const phaseModel& phase2 = interface.phase2();
// Loop the species
forAllConstIter(HashPtrTable, *dmidtfIter(), dmidtfJter)
{
const word& specie = dmidtfJter.key();
// Mass transfer rates
const volScalarField& dmidtf = *dmidtfJter();
const volScalarField dmidtf21(posPart(dmidtf));
const volScalarField dmidtf12(negPart(dmidtf));
// Latent heat contribution
const volScalarField Li
(
this->Li(interface, specie, dmidtf, Tf, scheme)
);
*eqns[phase1.name()] +=
((1 - weight)*dmidtf12 + weight*dmidtf21)*Li;
*eqns[phase2.name()] +=
((1 - weight)*dmidtf21 + weight*dmidtf12)*Li;
}
}
}
template
void Foam::HeatTransferPhaseSystem::addDmidtHefs
(
const phaseSystem::dmidtfTable& dmidtfs,
const phaseSystem::dmdtfTable& Tfs,
const scalar weight,
const latentHeatScheme scheme,
phaseSystem::heatTransferTable& eqns
) const
{
addDmidtHefsWithoutL(dmidtfs, Tfs, scheme, eqns);
addDmidtL(dmidtfs, Tfs, weight, scheme, eqns);
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
template
Foam::HeatTransferPhaseSystem::HeatTransferPhaseSystem
(
const fvMesh& mesh
)
:
heatTransferPhaseSystem(),
BasePhaseSystem(mesh),
residualY_(this->template lookupOrDefault("residualY", -1))
{}
// * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
template
Foam::HeatTransferPhaseSystem::~HeatTransferPhaseSystem()
{}
// * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
template
Foam::tmp
Foam::HeatTransferPhaseSystem::L
(
const phaseInterface& interface,
const volScalarField& dmdtf,
const volScalarField& Tf,
const latentHeatScheme scheme
) const
{
const rhoFluidThermo& thermo1 = interface.phase1().fluidThermo();
const rhoFluidThermo& thermo2 = interface.phase2().fluidThermo();
// Interface enthalpies
const volScalarField haf1(thermo1.ha(thermo1.p(), Tf));
const volScalarField haf2(thermo2.ha(thermo2.p(), Tf));
switch (scheme)
{
case latentHeatScheme::symmetric:
{
return haf2 - haf1;
}
case latentHeatScheme::upwind:
{
// Bulk enthalpies
const volScalarField ha1(thermo1.ha());
const volScalarField ha2(thermo2.ha());
return
neg0(dmdtf)*haf2 + pos(dmdtf)*ha2
- pos0(dmdtf)*haf1 - neg(dmdtf)*ha1;
}
}
return tmp(nullptr);
}
template
Foam::tmp
Foam::HeatTransferPhaseSystem::L
(
const phaseInterface& interface,
const scalarField& dmdtf,
const scalarField& Tf,
const labelUList& cells,
const latentHeatScheme scheme
) const
{
const rhoFluidThermo& thermo1 = interface.phase1().fluidThermo();
const rhoFluidThermo& thermo2 = interface.phase2().fluidThermo();
// Interface enthalpies
const scalarField haf1(thermo1.ha(Tf, cells));
const scalarField haf2(thermo2.ha(Tf, cells));
switch (scheme)
{
case latentHeatScheme::symmetric:
{
return haf2 - haf1;
}
case latentHeatScheme::upwind:
{
const scalarField T1(UIndirectList(thermo1.T(), cells));
const scalarField T2(UIndirectList(thermo2.T(), cells));
// Bulk enthalpies
const scalarField ha1(thermo1.ha(T1, cells));
const scalarField ha2(thermo2.ha(T2, cells));
return
neg0(dmdtf)*haf2 + pos(dmdtf)*ha2
- pos0(dmdtf)*haf1 - neg(dmdtf)*ha1;
}
}
return tmp(nullptr);
}
template
Foam::tmp
Foam::HeatTransferPhaseSystem::Li
(
const phaseInterface& interface,
const word& specie,
const volScalarField& dmdtf,
const volScalarField& Tf,
const latentHeatScheme scheme
) const
{
const rhoFluidThermo& thermo1 = interface.phase1().fluidThermo();
const rhoFluidThermo& thermo2 = interface.phase2().fluidThermo();
const rhoFluidMulticomponentThermo* mcThermoPtr1 =
isA(thermo1)
? &refCast(thermo1)
: static_cast(nullptr);
const rhoFluidMulticomponentThermo* mcThermoPtr2 =
isA(thermo2)
? &refCast(thermo2)
: static_cast(nullptr);
const label speciei1 =
mcThermoPtr1 ? mcThermoPtr1->species()[specie] : -1;
const label speciei2 =
mcThermoPtr2 ? mcThermoPtr2->species()[specie] : -1;
// Interface enthalpies
const volScalarField hafi1
(
mcThermoPtr1
? mcThermoPtr1->hai(speciei1, thermo1.p(), Tf)
: thermo1.ha(thermo1.p(), Tf)
);
const volScalarField hafi2
(
mcThermoPtr2
? mcThermoPtr2->hai(speciei2, thermo2.p(), Tf)
: thermo2.ha(thermo1.p(), Tf)
);
switch (scheme)
{
case latentHeatScheme::symmetric:
{
return hafi2 - hafi1;
}
case latentHeatScheme::upwind:
{
// Bulk enthalpies
const volScalarField hai1
(
mcThermoPtr1
? mcThermoPtr1->hai(speciei1, thermo1.p(), thermo1.T())
: thermo1.ha()
);
const volScalarField hai2
(
mcThermoPtr2
? mcThermoPtr2->hai(speciei2, thermo2.p(), thermo2.T())
: thermo2.ha()
);
return
neg0(dmdtf)*hafi2 + pos(dmdtf)*hai2
- pos0(dmdtf)*hafi1 - neg(dmdtf)*hai1;
}
}
return tmp(nullptr);
}
template
Foam::tmp
Foam::HeatTransferPhaseSystem::Li
(
const phaseInterface& interface,
const word& specie,
const scalarField& dmdtf,
const scalarField& Tf,
const labelUList& cells,
const latentHeatScheme scheme
) const
{
const rhoFluidThermo& thermo1 = interface.phase1().fluidThermo();
const rhoFluidThermo& thermo2 = interface.phase2().fluidThermo();
const rhoFluidMulticomponentThermo* mcThermoPtr1 =
isA(thermo1)
? &refCast(thermo1)
: static_cast(nullptr);
const rhoFluidMulticomponentThermo* mcThermoPtr2 =
isA(thermo2)
? &refCast(thermo2)
: static_cast(nullptr);
const label speciei1 =
mcThermoPtr1 ? mcThermoPtr1->species()[specie] : -1;
const label speciei2 =
mcThermoPtr2 ? mcThermoPtr2->species()[specie] : -1;
const scalarField p1(UIndirectList(thermo1.p(), cells));
const scalarField p2(UIndirectList(thermo2.p(), cells));
// Interface enthalpies
const scalarField hafi1
(
mcThermoPtr1
? mcThermoPtr1->hai(speciei1, p1, Tf)
: thermo1.ha(Tf, cells)
);
const scalarField hafi2
(
mcThermoPtr2
? mcThermoPtr2->hai(speciei2, p2, Tf)
: thermo2.ha(Tf, cells)
);
switch (scheme)
{
case latentHeatScheme::symmetric:
{
return hafi2 - hafi1;
}
case latentHeatScheme::upwind:
{
const scalarField T1(UIndirectList(thermo1.T(), cells));
const scalarField T2(UIndirectList(thermo2.T(), cells));
// Bulk enthalpies
const scalarField hai1
(
mcThermoPtr1
? mcThermoPtr1->hai(speciei1, p1, T1)
: thermo1.ha(T1, cells)
);
const scalarField hai2
(
mcThermoPtr2
? mcThermoPtr2->hai(speciei2, p2, T2)
: thermo2.ha(T2, cells)
);
return
neg0(dmdtf)*hafi2 + pos(dmdtf)*hai2
- pos0(dmdtf)*hafi1 - neg(dmdtf)*hai1;
}
}
return tmp(nullptr);
}
template
bool Foam::HeatTransferPhaseSystem::read()
{
if (BasePhaseSystem::read())
{
bool readOK = true;
// Models ...
return readOK;
}
else
{
return false;
}
}
// ************************************************************************* //