Skip to content

Commit

Permalink
reactingTwoPhaseEulerFoam: Added support for thermally-driven phase-c…
Browse files Browse the repository at this point in the history
…hange (boiling)

The interfacial temperature is assumed equal to the saturation
temperature.  Only a single species is considered volatile and the other
species to not affect the mass-transfer.
  • Loading branch information
Henry Weller committed Jul 16, 2015
1 parent 8e7c777 commit 69a87c5
Show file tree
Hide file tree
Showing 7 changed files with 793 additions and 288 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ License
#include "BlendedInterfacialModel.H"
#include "heatTransferModel.H"
#include "massTransferModel.H"
#include "interfaceCompositionModel.H"

#include "HashPtrTable.H"

Expand Down Expand Up @@ -59,12 +58,6 @@ HeatAndMassTransferPhaseSystem
massTransferModels_
);

this->generatePairsAndSubModels
(
"interfaceComposition",
interfaceCompositionModels_
);

forAllConstIter
(
phaseSystem::phasePairTable,
Expand Down Expand Up @@ -332,263 +325,6 @@ Foam::HeatAndMassTransferPhaseSystem<BasePhaseSystem>::heatTransfer() const
}


template<class BasePhaseSystem>
Foam::autoPtr<Foam::phaseSystem::massTransferTable>
Foam::HeatAndMassTransferPhaseSystem<BasePhaseSystem>::massTransfer() const
{
// Create a mass transfer matrix for each species of each phase
autoPtr<phaseSystem::massTransferTable> eqnsPtr
(
new phaseSystem::massTransferTable()
);

phaseSystem::massTransferTable& eqns = eqnsPtr();

forAllConstIter
(
phaseSystem::phaseModelTable,
this->phaseModels_,
phaseModelIter
)
{
const phaseModel& phase(phaseModelIter());

const PtrList<volScalarField>& Yi = phase.Y();

forAll(Yi, i)
{
eqns.insert
(
Yi[i].name(),
new fvScalarMatrix(Yi[i], dimMass/dimTime)
);
}
}

// Reset the interfacial mass flow rates
forAllConstIter
(
phaseSystem::phasePairTable,
this->phasePairs_,
phasePairIter
)
{
const phasePair& pair(phasePairIter());

if (pair.ordered())
{
continue;
}

*dmdt_[pair] =
*dmdtExplicit_[pair];

*dmdtExplicit_[pair] =
dimensionedScalar("zero", dimDensity/dimTime, 0);
}

// Sum up the contribution from each interface composition model
forAllConstIter
(
interfaceCompositionModelTable,
interfaceCompositionModels_,
interfaceCompositionModelIter
)
{
const interfaceCompositionModel& compositionModel
(
interfaceCompositionModelIter()
);

const phasePair& pair
(
this->phasePairs_[interfaceCompositionModelIter.key()]
);
const phaseModel& phase = pair.phase1();
const phaseModel& otherPhase = pair.phase2();
const phasePairKey key(phase.name(), otherPhase.name());

const volScalarField& Tf(*Tf_[key]);

volScalarField& dmdtExplicit(*dmdtExplicit_[key]);
volScalarField& dmdt(*dmdt_[key]);

scalar dmdtSign(Pair<word>::compare(dmdt_.find(key).key(), key));

const volScalarField K
(
massTransferModels_[key][phase.name()]->K()
);

forAllConstIter
(
hashedWordList,
compositionModel.species(),
memberIter
)
{
const word& member = *memberIter;

const word name
(
IOobject::groupName(member, phase.name())
);

const word otherName
(
IOobject::groupName(member, otherPhase.name())
);

const volScalarField KD
(
K*compositionModel.D(member)
);

const volScalarField Yf
(
compositionModel.Yf(member, Tf)
);

// Implicit transport through the phase
*eqns[name] +=
phase.rho()*KD*Yf
- fvm::Sp(phase.rho()*KD, eqns[name]->psi());

// Sum the mass transfer rate
dmdtExplicit += dmdtSign*phase.rho()*KD*Yf;
dmdt -= dmdtSign*phase.rho()*KD*eqns[name]->psi();

// Explicit transport out of the other phase
if (eqns.found(otherName))
{
*eqns[otherName] -=
otherPhase.rho()*KD*compositionModel.dY(member, Tf);
}
}
}

return eqnsPtr;
}


template<class BasePhaseSystem>
void Foam::HeatAndMassTransferPhaseSystem<BasePhaseSystem>::correctThermo()
{
BasePhaseSystem::correctThermo();

// This loop solves for the interface temperatures, Tf, and updates the
// interface composition models.
//
// The rate of heat transfer to the interface must equal the latent heat
// consumed at the interface, i.e.:
//
// H1*(T1 - Tf) + H2*(T2 - Tf) == mDotL
// == K*rho*(Yfi - Yi)*Li
//
// Yfi is likely to be a strong non-linear (typically exponential) function
// of Tf, so the solution for the temperature is newton-accelerated

forAllConstIter
(
phaseSystem::phasePairTable,
this->phasePairs_,
phasePairIter
)
{
const phasePair& pair(phasePairIter());

if (pair.ordered())
{
continue;
}

const phasePairKey key12(pair.first(), pair.second(), true);
const phasePairKey key21(pair.second(), pair.first(), true);

volScalarField H1(heatTransferModels_[pair][pair.first()]->K());
volScalarField H2(heatTransferModels_[pair][pair.second()]->K());
dimensionedScalar HSmall("small", heatTransferModel::dimK, SMALL);

volScalarField mDotL
(
IOobject
(
"mDotL",
this->mesh().time().timeName(),
this->mesh()
),
this->mesh(),
dimensionedScalar("zero", dimEnergy/dimVolume/dimTime, 0)
);
volScalarField mDotLPrime
(
IOobject
(
"mDotLPrime",
this->mesh().time().timeName(),
this->mesh()
),
this->mesh(),
dimensionedScalar("zero", mDotL.dimensions()/dimTemperature, 0)
);

volScalarField& Tf = *Tf_[pair];

// Add latent heats from forward and backward models
if (interfaceCompositionModels_.found(key12))
{
interfaceCompositionModels_[key12]->addMDotL
(
massTransferModels_[pair][pair.first()]->K(),
Tf,
mDotL,
mDotLPrime
);
}
if (interfaceCompositionModels_.found(key21))
{
interfaceCompositionModels_[key21]->addMDotL
(
massTransferModels_[pair][pair.second()]->K(),
Tf,
mDotL,
mDotLPrime
);
}

// Update the interface temperature by applying one step of newton's
// method to the interface relation
Tf -=
(
H1*(Tf - pair.phase1().thermo().T())
+ H2*(Tf - pair.phase2().thermo().T())
+ mDotL
)
/(
max(H1 + H2 + mDotLPrime, HSmall)
);

// Update the interface compositions
if (interfaceCompositionModels_.found(key12))
{
interfaceCompositionModels_[key12]->update(Tf);
}
if (interfaceCompositionModels_.found(key21))
{
interfaceCompositionModels_[key21]->update(Tf);
}

Tf.correctBoundaryConditions();

Info<< "Tf." << pair.name()
<< ": min = " << min(Tf.internalField())
<< ", mean = " << average(Tf.internalField())
<< ", max = " << max(Tf.internalField())
<< endl;
}
}


template<class BasePhaseSystem>
bool Foam::HeatAndMassTransferPhaseSystem<BasePhaseSystem>::read()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,8 @@ Class
Foam::HeatAndMassTransferPhaseSystem
Description
Class which models interfacial heat and mass transfer between a number of
phases. Mass is transferred to or from a phase according to a composition
model at the surface of another phase. Heat is transferred from a phase to
an interfacial temperature. The interface temperature is calculated such
that the net rate at which the heat is transferred to the interface is
equal to the latent heat consumed by the mass transfer.
Base class to support interfacial heat and mass transfer between a number
of phases.
SourceFiles
HeatAndMassTransferPhaseSystem.C
Expand All @@ -53,7 +49,6 @@ class BlendedInterfacialModel;
class blendingMethod;
class heatTransferModel;
class massTransferModel;
class interfaceCompositionModel;

/*---------------------------------------------------------------------------*\
Class HeatAndMassTransferPhaseSystem Declaration
Expand Down Expand Up @@ -88,13 +83,6 @@ protected:
phasePairKey::hash
> massTransferModelTable;

typedef HashTable
<
autoPtr<interfaceCompositionModel>,
phasePairKey,
phasePairKey::hash
> interfaceCompositionModelTable;


// Protected data

Expand All @@ -117,9 +105,6 @@ protected:
//- Mass transfer models
massTransferModelTable massTransferModels_;

//- Interface composition models
interfaceCompositionModelTable interfaceCompositionModels_;


public:

Expand Down Expand Up @@ -151,10 +136,10 @@ public:

//- Return the mass transfer matrices
virtual autoPtr<phaseSystem::massTransferTable>
massTransfer() const;
massTransfer() const = 0;

//- Correct the thermodynamics
virtual void correctThermo();
virtual void correctThermo() = 0;

//- Read base phaseProperties dictionary
virtual bool read();
Expand Down

0 comments on commit 69a87c5

Please sign in to comment.