1446 lines
44 KiB
C++
1446 lines
44 KiB
C++
/**
|
|
* @file IdealSolidSolnPhase.cpp
|
|
* Implementation file for an ideal solid solution model
|
|
* with incompressible thermodynamics (see \ref thermoprops and
|
|
* \link Cantera::IdealSolidSolnPhase IdealSolidSolnPhase\endlink).
|
|
*/
|
|
/*
|
|
* Copyright 2006 Sandia Corporation. Under the terms of Contract
|
|
* DE-AC04-94AL85000, with Sandia Corporation, the U.S. Government
|
|
* retains certain rights in this software.
|
|
*/
|
|
|
|
#include "cantera/thermo/IdealSolidSolnPhase.h"
|
|
#include <iostream>
|
|
using namespace std;
|
|
|
|
namespace Cantera
|
|
{
|
|
|
|
/*
|
|
* Constructor for IdealSolidSolnPhase class:
|
|
* The default form for the generalized concentrations is 0
|
|
* i.e., unity.
|
|
*/
|
|
IdealSolidSolnPhase::IdealSolidSolnPhase(int formGC) :
|
|
ThermoPhase(),
|
|
m_formGC(formGC),
|
|
m_mm(0),
|
|
m_tmin(0.0),
|
|
m_tmax(1000000.),
|
|
m_Pref(OneAtm),
|
|
m_Pcurrent(OneAtm),
|
|
m_tlast(0.0)
|
|
{
|
|
if (formGC < 0 || formGC > 2) {
|
|
throw CanteraError(" IdealSolidSolnPhase Constructor",
|
|
" Illegal value of formGC");
|
|
}
|
|
}
|
|
|
|
IdealSolidSolnPhase::IdealSolidSolnPhase(std::string inputFile, std::string id,
|
|
int formGC) :
|
|
ThermoPhase(),
|
|
m_formGC(formGC),
|
|
m_mm(0),
|
|
m_tmin(0.0),
|
|
m_tmax(1000000.),
|
|
m_Pref(OneAtm),
|
|
m_Pcurrent(OneAtm),
|
|
m_tlast(0.0)
|
|
{
|
|
if (formGC < 0 || formGC > 2) {
|
|
throw CanteraError(" IdealSolidSolnPhase Constructor",
|
|
" Illegal value of formGC");
|
|
}
|
|
constructPhaseFile(inputFile, id);
|
|
}
|
|
//====================================================================================================================
|
|
IdealSolidSolnPhase::IdealSolidSolnPhase(XML_Node& root, std::string id,
|
|
int formGC) :
|
|
ThermoPhase(),
|
|
m_formGC(formGC),
|
|
m_mm(0),
|
|
m_tmin(0.0),
|
|
m_tmax(1000000.),
|
|
m_Pref(OneAtm),
|
|
m_Pcurrent(OneAtm),
|
|
m_tlast(0.0)
|
|
{
|
|
if (formGC < 0 || formGC > 2) {
|
|
throw CanteraError(" IdealSolidSolnPhase Constructor",
|
|
" Illegal value of formGC");
|
|
}
|
|
constructPhaseXML(root, id);
|
|
}
|
|
//====================================================================================================================
|
|
IdealSolidSolnPhase::IdealSolidSolnPhase(const IdealSolidSolnPhase& b)
|
|
{
|
|
*this = b;
|
|
}
|
|
//====================================================================================================================
|
|
|
|
IdealSolidSolnPhase& IdealSolidSolnPhase::
|
|
operator=(const IdealSolidSolnPhase& b)
|
|
{
|
|
if (this != &b) {
|
|
//ThermoPhase::operator=(b);
|
|
// m_spthermo = dupMyselfAsSpeciesThermo(b.m_spthermo);
|
|
m_formGC = b.m_formGC;
|
|
m_mm = b.m_mm;
|
|
m_tmin = b.m_tmin;
|
|
m_tmax = b.m_tmax;
|
|
m_Pref = b.m_Pref;
|
|
m_Pcurrent = b.m_Pcurrent;
|
|
m_speciesMolarVolume = b.m_speciesMolarVolume;
|
|
m_tlast = b.m_tlast;
|
|
m_h0_RT = b.m_h0_RT;
|
|
m_cp0_R = b.m_cp0_R;
|
|
m_g0_RT = b.m_g0_RT;
|
|
m_s0_R = b.m_s0_R;
|
|
m_expg0_RT = b.m_expg0_RT;
|
|
m_pe = b.m_pe;
|
|
m_pp = b.m_pp;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/*
|
|
* Base Class Duplication Function
|
|
* -> given a pointer to ThermoPhase, this function can
|
|
* duplicate the object. (note has to be a separate function
|
|
* not the copy constructor, because it has to be
|
|
* a virtual function)
|
|
*/
|
|
ThermoPhase* IdealSolidSolnPhase::duplMyselfAsThermoPhase() const
|
|
{
|
|
IdealSolidSolnPhase* ii = new IdealSolidSolnPhase(*this);
|
|
return (ThermoPhase*) ii;
|
|
}
|
|
//====================================================================================================================
|
|
/**
|
|
* Equation of state flag. Returns the value cIdealGas, defined
|
|
* in mix_defs.h.
|
|
*/
|
|
int IdealSolidSolnPhase::eosType() const
|
|
{
|
|
integer res;
|
|
switch (m_formGC) {
|
|
case 0:
|
|
res = cIdealSolidSolnPhase0;
|
|
break;
|
|
case 1:
|
|
res = cIdealSolidSolnPhase1;
|
|
break;
|
|
case 2:
|
|
res = cIdealSolidSolnPhase2;
|
|
break;
|
|
default:
|
|
throw CanteraError("eosType", "Unknown type");
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/********************************************************************
|
|
* Molar Thermodynamic Properties of the Solution
|
|
********************************************************************/
|
|
/**
|
|
* Molar enthalpy of the solution. Units: J/kmol.
|
|
* For an ideal, constant partial molar volume solution mixture with
|
|
* pure species phases which exhibit zero volume expansivity and
|
|
* zero isothermal compressibility:
|
|
* \f[
|
|
* \hat h(T,P) = \sum_k X_k \hat h^0_k(T) + (P - P_{ref}) (\sum_k X_k \hat V^0_k)
|
|
* \f]
|
|
* The reference-state pure-species enthalpies at the reference pressure Pref
|
|
* \f$ \hat h^0_k(T) \f$, are computed by the species thermodynamic
|
|
* property manager. They are polynomial functions of temperature.
|
|
* @see SpeciesThermo
|
|
*/
|
|
doublereal IdealSolidSolnPhase::
|
|
enthalpy_mole() const
|
|
{
|
|
const double* eptr = &(enthalpy_RT_ref()[0]);
|
|
doublereal htp = (GasConstant * temperature() * mean_X(eptr));
|
|
return (htp + (pressure() - m_Pref)/molarDensity());
|
|
}
|
|
|
|
/**
|
|
* Molar internal energy of the solution. J/kmol.
|
|
* For an ideal, constant partial molar volume solution mixture with
|
|
* pure species phases which exhibit zero volume expansivity and
|
|
* zero isothermal compressibility:
|
|
* \f[
|
|
* \hat u(T) = \hat h(T,P) - p \hat V = \sum_k X_k \hat h^0_k(T)
|
|
* - P_{ref} (\sum_k X_k \hat V^0_k)
|
|
* \f]
|
|
* and is a function only of temperature.
|
|
* The reference-state pure-species enthalpies
|
|
* \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic
|
|
* property manager.
|
|
* @see SpeciesThermo
|
|
*/
|
|
doublereal IdealSolidSolnPhase::intEnergy_mole() const
|
|
{
|
|
const double* eptr = DATA_PTR(enthalpy_RT_ref().begin());
|
|
doublereal htp = (GasConstant * temperature() *
|
|
mean_X(eptr));
|
|
return (htp - m_Pref / molarDensity());
|
|
}
|
|
|
|
/**
|
|
* Molar entropy of the solution. Units: J/kmol/K.
|
|
* For an ideal, constant partial molar volume solution mixture with
|
|
* pure species phases which exhibit zero volume expansivity:
|
|
* \f[
|
|
* \hat s(T, P, X_k) = \sum_k X_k \hat s^0_k(T)
|
|
* - \hat R \sum_k X_k log(X_k)
|
|
* \f]
|
|
* The reference-state pure-species entropies
|
|
* \f$ \hat s^0_k(T,p_{ref}) \f$ are computed by the species thermodynamic
|
|
* property manager. The pure species entropies are independent of
|
|
* temperature since the volume expansivities are equal to zero.
|
|
* @see SpeciesThermo
|
|
*/
|
|
doublereal IdealSolidSolnPhase::entropy_mole() const
|
|
{
|
|
const double* dptr = DATA_PTR(entropy_R_ref());
|
|
return GasConstant * (mean_X(dptr) - sum_xlogx());
|
|
}
|
|
|
|
/**
|
|
* Molar gibbs free energy of the solution. Units: J/kmol.
|
|
* For an ideal, constant partial molar volume solution mixture with
|
|
* pure species phases which exhibit zero volume expansivity:
|
|
* \f[
|
|
* \hat g(T, P) = \sum_k X_k \hat g^0_k(T,P) + \hat R T \sum_k X_k log(X_k)
|
|
* \f]
|
|
* The reference-state pure-species gibbs free energies
|
|
* \f$ \hat g^0_k(T) \f$ are computed by the species thermodynamic
|
|
* property manager, while the standard state gibbs free energies
|
|
* \f$ \hat g^0_k(T,P) \f$ are computed by the member function, gibbs_RT().
|
|
* @see SpeciesThermo
|
|
*/
|
|
doublereal IdealSolidSolnPhase::gibbs_mole() const
|
|
{
|
|
const double* dptr = DATA_PTR(gibbs_RT_ref());
|
|
doublereal g = mean_X(dptr);
|
|
return (GasConstant * temperature() * (g + sum_xlogx()));
|
|
}
|
|
|
|
/**
|
|
* Molar heat capacity at constant pressure of the solution.
|
|
* Units: J/kmol/K.
|
|
* For an ideal, constant partial molar volume solution mixture with
|
|
* pure species phases which exhibit zero volume expansivity:
|
|
* \f[
|
|
* \hat c_p(T,P) = \sum_k X_k \hat c^0_{p,k}(T) .
|
|
* \f]
|
|
* The heat capacity is independent of pressure.
|
|
* The reference-state pure-species heat capacities
|
|
* \f$ \hat c^0_{p,k}(T) \f$ are computed by the species thermodynamic
|
|
* property manager.
|
|
* @see SpeciesThermo
|
|
*/
|
|
doublereal IdealSolidSolnPhase::cp_mole() const
|
|
{
|
|
const double* dptr = DATA_PTR(cp_R_ref());
|
|
return GasConstant * mean_X(dptr);
|
|
}
|
|
|
|
/********************************************************************
|
|
* Mechanical Equation of State
|
|
********************************************************************/
|
|
/**
|
|
*
|
|
* Calculate the density of the mixture using the partial
|
|
* molar volumes and mole fractions as input
|
|
*
|
|
* The formula for this is
|
|
*
|
|
* \f[
|
|
* \rho = \frac{\sum_k{X_k W_k}}{\sum_k{X_k V_k}}
|
|
* \f]
|
|
*
|
|
* where \f$ X_k \f$ are the mole fractions, \f$W_k\f$ are
|
|
* the molecular weights, and \f$V_k\f$ are the pure species
|
|
* molar volumes.
|
|
*
|
|
* Note, the basis behind this formula is that in an ideal
|
|
* solution the partial molar volumes are equal to the pure
|
|
* species molar volumes. We have additionally specified that
|
|
* in this class that the pure species molar volumes are
|
|
* independent of temperature and pressure.
|
|
*/
|
|
void IdealSolidSolnPhase::calcDensity()
|
|
{
|
|
/*
|
|
* Calculate the molarVolume of the solution (m**3 kmol-1)
|
|
*/
|
|
const doublereal* const dtmp = moleFractdivMMW();
|
|
double invDens = dot(m_speciesMolarVolume.begin(),
|
|
m_speciesMolarVolume.end(), dtmp);
|
|
/*
|
|
* Set the density in the parent State object directly,
|
|
* by calling the State::setDensity() function.
|
|
*/
|
|
double dens = 1.0/invDens;
|
|
State::setDensity(dens);
|
|
}
|
|
|
|
/**
|
|
* Overwritten setDensity() function is necessary because the
|
|
* density is not an indendent variable.
|
|
*
|
|
* This function will now throw an error condition
|
|
*
|
|
* @internal May have to adjust the strategy here to make
|
|
* the eos for these materials slightly compressible, in order
|
|
* to create a condition where the density is a function of
|
|
* the pressure.
|
|
*
|
|
* This function will now throw an error condition.
|
|
*
|
|
* NOTE: This is a virtual function that overwrites the State.h
|
|
* class
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
setDensity(const doublereal rho)
|
|
{
|
|
/*
|
|
* Unless the input density is exactly equal to the density
|
|
* calculated and stored in the State object, we throw an
|
|
* exception. This is because the density is NOT an
|
|
* independent variable.
|
|
*/
|
|
double dens = density();
|
|
if (rho != dens) {
|
|
throw CanteraError("IdealSolidSolnPhase::setDensity",
|
|
"Density is not an independent variable");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* setPressure(double) (virtual from ThermoPhase)
|
|
*
|
|
* Set the pressure at constant temperature. Units: Pa.
|
|
* This method sets a constant within the object.
|
|
* The mass density is not a function of pressure.
|
|
* Note: This function overrides the setPressure() function
|
|
* in the ThermoPhase object.
|
|
* We calculate the density and store it in the
|
|
* State object, because this density is supposed to
|
|
* be current after setting the pressure, and is now
|
|
* a dependent variable.
|
|
*/
|
|
void IdealSolidSolnPhase::setPressure(doublereal p)
|
|
{
|
|
m_Pcurrent = p;
|
|
calcDensity();
|
|
}
|
|
|
|
/*
|
|
* setMolarDensity() (virtual from State)
|
|
* Overwritten setMolarDensity() function is necessary because the
|
|
* density is not an indendent variable.
|
|
*
|
|
* This function will now throw an error condition.
|
|
*
|
|
* NOTE: This is a virtual function that overrides the State.h
|
|
* class
|
|
*/
|
|
void IdealSolidSolnPhase::setMolarDensity(const doublereal n)
|
|
{
|
|
throw CanteraError("IdealSolidSolnPhase::setMolarDensity",
|
|
"Density is not an independent variable");
|
|
}
|
|
|
|
/*
|
|
* setMoleFractions() (virtual from State)
|
|
*
|
|
* Sets the mole fractions and adjusts the internal density.
|
|
*/
|
|
void IdealSolidSolnPhase::setMoleFractions(const doublereal* const x)
|
|
{
|
|
State::setMoleFractions(x);
|
|
calcDensity();
|
|
}
|
|
|
|
/**
|
|
* setMoleFractions_NoNorm() (virtual from State)
|
|
*
|
|
* Sets the mole fractions and adjusts the internal density.
|
|
*/
|
|
void IdealSolidSolnPhase::setMoleFractions_NoNorm(const doublereal* const x)
|
|
{
|
|
State::setMoleFractions(x);
|
|
calcDensity();
|
|
}
|
|
|
|
/*
|
|
* setMassFractions() (virtual from State)
|
|
*
|
|
* Sets the mass fractions and adjusts the internal density.
|
|
*/
|
|
void IdealSolidSolnPhase::setMassFractions(const doublereal* const y)
|
|
{
|
|
State::setMassFractions(y);
|
|
calcDensity();
|
|
}
|
|
|
|
/*
|
|
* setMassFractions_NoNorm() (virtual from State)
|
|
*
|
|
* Sets the mass fractions and adjusts the internal density.
|
|
*/
|
|
void IdealSolidSolnPhase::setMassFractions_NoNorm(const doublereal* const y)
|
|
{
|
|
State::setMassFractions_NoNorm(y);
|
|
calcDensity();
|
|
}
|
|
|
|
/*
|
|
* setConcentrations (virtual from State)
|
|
*
|
|
* Sets the concentrations and adjusts the internal density
|
|
*/
|
|
void IdealSolidSolnPhase::setConcentrations(const doublereal* const c)
|
|
{
|
|
State::setConcentrations(c);
|
|
calcDensity();
|
|
}
|
|
|
|
/********************************************************************
|
|
* Chemical Potentials and Activities
|
|
********************************************************************/
|
|
|
|
/********************************************************************
|
|
*
|
|
* getActivitConcentrations():
|
|
*
|
|
* This method returns the array of generalized
|
|
* concentrations. The generalized concentrations are used
|
|
* in the evaluation of the rates of progress for reactions
|
|
* involving species in this phase. The generalized
|
|
* concentration dividied by the standard concentration is also
|
|
* equal to the activity of species.
|
|
*
|
|
* For this implentation the activity is defined to be the
|
|
* mole fraction of the species. The generalized concentration
|
|
* is defined to be equal to the mole fraction divided by
|
|
* the partial molar volume. The generalized concentrations
|
|
* for species in this phase therefore have units of
|
|
* kmol m<SUP>-3</SUP>. Rate constants must reflect this fact.
|
|
*
|
|
* On a general note, the following must be true.
|
|
* For an ideal solution, the generalized concentration must consist
|
|
* of the mole fraction multiplied by a constant. The constant may be
|
|
* fairly arbitrarily chosen, with differences adsorbed into the
|
|
* reaction rate expression. 1/V_N, 1/V_k, or 1 are equally good,
|
|
* as long as the standard concentration is adjusted accordingly.
|
|
* However, it must be a constant (and not the concentration, btw,
|
|
* which is a function of the mole fractions) in order for the
|
|
* ideal solution properties to hold at the same time having the
|
|
* standard concentration to be independent of the mole fractions.
|
|
*
|
|
* In this implementation the form of the generalized concentrations
|
|
* depend upon the member attribute, m_formGC:
|
|
*
|
|
* <TABLE>
|
|
* <TR><TD> m_formGC </TD><TD> GeneralizedConc </TD><TD> StandardConc </TD></TR>
|
|
* <TR><TD> 0 </TD><TD> X_k </TD><TD> 1.0 </TD></TR>
|
|
* <TR><TD> 1 </TD><TD> X_k / V_k </TD><TD> 1.0 / V_k </TD></TR>
|
|
* <TR><TD> 2 </TD><TD> X_k / V_N </TD><TD> 1.0 / V_N </TD></TR>
|
|
* </TABLE>
|
|
*
|
|
* HKM Note: We have absorbed the pressure dependence of the pure species
|
|
* state into the thermodynamics functions. Therefore the
|
|
* standard state on which the activities are based depend
|
|
* on both temperature and pressure. If we hadn't, it would have
|
|
* appeared in this function in a very awkwards exp[] format.
|
|
*
|
|
* @param c[] Pointer to array of doubles of length m_kk, which on exit
|
|
* will contain the generalized concentrations.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getActivityConcentrations(doublereal* c) const
|
|
{
|
|
const doublereal* const dtmp = moleFractdivMMW();
|
|
const double mmw = meanMolecularWeight();
|
|
switch (m_formGC) {
|
|
case 0:
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
c[k] = dtmp[k] * mmw;
|
|
}
|
|
break;
|
|
case 1:
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
c[k] = dtmp[k] * mmw / m_speciesMolarVolume[k];
|
|
}
|
|
break;
|
|
case 2:
|
|
double atmp = mmw / m_speciesMolarVolume[m_kk-1];
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
c[k] = dtmp[k] * atmp;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* standardConcentration()
|
|
*
|
|
* The standard concentration \f$ C^0_k \f$ used to normalize
|
|
* the generalized concentration.
|
|
* In many cases, this quantity
|
|
* will be the same for all species in a phase.
|
|
* However, for this case, we will return a distinct concentration
|
|
* for each species. This is the inverse of the species molar
|
|
* volume. Units are m<SUP>3</SUP> kmol<SUP>-1</SUP>.
|
|
*
|
|
*
|
|
* @param k Species number: this is a require parameter,
|
|
* a change from the ThermoPhase base class, where it was
|
|
* an optional parameter.
|
|
*/
|
|
doublereal IdealSolidSolnPhase::
|
|
standardConcentration(size_t k) const
|
|
{
|
|
switch (m_formGC) {
|
|
case 0:
|
|
return 1.0;
|
|
case 1:
|
|
return 1.0 / m_speciesMolarVolume[k];
|
|
case 2:
|
|
return 1.0/m_speciesMolarVolume[m_kk-1];
|
|
}
|
|
return 0.0;
|
|
}
|
|
doublereal IdealSolidSolnPhase::
|
|
referenceConcentration(int k) const
|
|
{
|
|
switch (m_formGC) {
|
|
case 0:
|
|
return 1.0;
|
|
case 1:
|
|
return 1.0 / m_speciesMolarVolume[k];
|
|
case 2:
|
|
return 1.0 / m_speciesMolarVolume[m_kk-1];
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
/*********************************************************************
|
|
*
|
|
* logStandardConc()
|
|
*
|
|
* Returns the log of the standard concentration
|
|
*
|
|
* @param k Species number: this is a require parameter,
|
|
* a change from the ThermoPhase base class, where it was
|
|
* an optional parameter.
|
|
*/
|
|
doublereal IdealSolidSolnPhase::
|
|
logStandardConc(size_t k) const
|
|
{
|
|
_updateThermo();
|
|
double res;
|
|
switch (m_formGC) {
|
|
case 0:
|
|
res = 0.0;
|
|
break;
|
|
case 1:
|
|
res = log(1.0/m_speciesMolarVolume[k]);
|
|
break;
|
|
case 2:
|
|
res = log(1.0/m_speciesMolarVolume[m_kk-1]);
|
|
break;
|
|
default:
|
|
throw CanteraError("eosType", "Unknown type");
|
|
break;
|
|
}
|
|
return res;
|
|
}
|
|
|
|
/***********************************************************************
|
|
*
|
|
* getUnitsStandardConcentration()
|
|
*
|
|
* Returns the units of the standard and general concentrations
|
|
* Note they have the same units, as their divisor is
|
|
* defined to be equal to the activity of the kth species
|
|
* in the solution, which is unitless.
|
|
*
|
|
* This routine is used in print out applications where the
|
|
* units are needed. Usually, MKS units are assumed throughout
|
|
* the program and in the XML input files.
|
|
*
|
|
* uA[0] = kmol units - default = 1
|
|
* uA[1] = m units - default = -nDim(), the number of spatial
|
|
* dimensions in the Phase class.
|
|
* uA[2] = kg units - default = 0;
|
|
* uA[3] = Pa(pressure) units - default = 0;
|
|
* uA[4] = Temperature units - default = 0;
|
|
* uA[5] = time units - default = 0
|
|
*
|
|
* For EOS types other than cIdealSolidSolnPhase1, the default
|
|
* kmol/m3 holds for standard concentration units. For
|
|
* cIdealSolidSolnPhase0 type, the standard concentrtion is
|
|
* unitless.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getUnitsStandardConc(double* uA, int, int sizeUA) const
|
|
{
|
|
int eos = eosType();
|
|
if (eos == cIdealSolidSolnPhase0) {
|
|
for (int i = 0; i < sizeUA; i++) {
|
|
uA[i] = 0.0;
|
|
}
|
|
} else {
|
|
for (int i = 0; i < sizeUA; i++) {
|
|
if (i == 0) {
|
|
uA[0] = 1.0;
|
|
}
|
|
if (i == 1) {
|
|
uA[1] = -int(nDim());
|
|
}
|
|
if (i == 2) {
|
|
uA[2] = 0.0;
|
|
}
|
|
if (i == 3) {
|
|
uA[3] = 0.0;
|
|
}
|
|
if (i == 4) {
|
|
uA[4] = 0.0;
|
|
}
|
|
if (i == 5) {
|
|
uA[5] = 0.0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* getActivityCoefficients():
|
|
*
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getActivityCoefficients(doublereal* ac) const
|
|
{
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
ac[k] = 1.0;
|
|
}
|
|
}
|
|
//================================================================================================
|
|
/*
|
|
*
|
|
* getChemPotentials():
|
|
*
|
|
* This function returns a vector of chemical potentials of the
|
|
* species.
|
|
* \f[
|
|
* \mu_k = \mu^o_k(T) + V_k * (p - p_o) + R T ln(X_k)
|
|
* \f]
|
|
* or another way to phrase this is
|
|
* \f[
|
|
* \mu_k = \mu^o_k(T,p) + R T ln(X_k)
|
|
* \f]
|
|
* where \f$ \mu^o_k(T,p) = \mu^o_k(T) + V_k * (p - p_o)\f$
|
|
*
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getChemPotentials(doublereal* mu) const
|
|
{
|
|
doublereal delta_p = m_Pcurrent - m_Pref;
|
|
doublereal xx;
|
|
doublereal RT = temperature() * GasConstant;
|
|
const vector_fp& g_RT = gibbs_RT_ref();
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
xx = std::max(SmallNumber, moleFraction(k));
|
|
mu[k] = RT * (g_RT[k] + log(xx))
|
|
+ delta_p * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
//================================================================================================
|
|
/*
|
|
*
|
|
* getChemPotentials_RT()
|
|
*
|
|
* Get the array of non-dimensional chemical potentials \f$
|
|
* \mu_k / \hat R T \f$, where
|
|
*
|
|
* \f[
|
|
* \mu_k = \mu^o_k(T) + V_k * (p - p_o) + R T ln(X_k)
|
|
* \f]
|
|
* or another way to phrase this is
|
|
* \f[
|
|
* \mu_k = \mu^o_k(T,p) + R T ln(X_k)
|
|
* \f]
|
|
* where \f$ \mu^o_k(T,p) = \mu^o_k(T) + V_k * (p - p_o)\f$
|
|
*
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getChemPotentials_RT(doublereal* mu) const
|
|
{
|
|
doublereal RT = temperature() * GasConstant;
|
|
doublereal delta_pdRT = (m_Pcurrent - m_Pref) / RT;
|
|
doublereal xx;
|
|
const vector_fp& g_RT = gibbs_RT_ref();
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
xx = std::max(SmallNumber, moleFraction(k));
|
|
mu[k] = (g_RT[k] + log(xx))
|
|
+ delta_pdRT * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
* Partial Molar Properties
|
|
********************************************************************/
|
|
|
|
/********************************************************************
|
|
*
|
|
* getPartialMolarEnthalpies()
|
|
*
|
|
* For this phase, the partial molar enthalpies are equal to the
|
|
* pure species enthalpies.
|
|
* \f[
|
|
* \hat h_k(T,P) = \sum_k X_k \hat h^0_k(T) + (p - p_{ref}) (\sum_k X_k \hat V^0_k)
|
|
* \f]
|
|
* The reference-state pure-species enthalpies at the reference
|
|
* pressure p_ref
|
|
* \f$ \hat h^0_k(T) \f$, are computed by the species thermodynamic
|
|
* property manager. They are polynomial functions of temperature.
|
|
* @see SpeciesThermo
|
|
*/
|
|
void IdealSolidSolnPhase::getPartialMolarEnthalpies(doublereal* hbar) const
|
|
{
|
|
const vector_fp& _h = enthalpy_RT_ref();
|
|
doublereal rt = GasConstant * temperature();
|
|
scale(_h.begin(), _h.end(), hbar, rt);
|
|
}
|
|
|
|
/********************************************************************
|
|
*
|
|
* getPartialMolarEntropies()
|
|
*
|
|
* Returns an array of partial molar entropies of the species in the
|
|
* solution. Units: J/kmol.
|
|
* For this phase, the partial molar entropies are equal to the
|
|
* pure species entropies plus the ideal solution contribution.
|
|
* \f[
|
|
* \bar s_k(T,P) = \hat s^0_k(T) - R log(X_k)
|
|
* \f]
|
|
* The reference-state pure-species entropies,\f$ \hat s^0_k(T) \f$,
|
|
* at the reference pressure, \f$ P_{ref} \f$, are computed by the
|
|
* species thermodynamic
|
|
* property manager. They are polynomial functions of temperature.
|
|
* @see SpeciesThermo
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getPartialMolarEntropies(doublereal* sbar) const
|
|
{
|
|
const vector_fp& _s = entropy_R_ref();
|
|
doublereal r = GasConstant;
|
|
doublereal xx;
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
xx = std::max(SmallNumber, moleFraction(k));
|
|
sbar[k] = r * (_s[k] - log(xx));
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
*
|
|
* getPartialMolarCp()
|
|
*
|
|
* For this phase, the partial molar heat capacities are equal
|
|
* to the standard state heat capacities.
|
|
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getPartialMolarCp(doublereal* cpbar) const
|
|
{
|
|
getCp_R(cpbar);
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
cpbar[k] *= GasConstant;
|
|
}
|
|
}
|
|
|
|
/******************************************************************
|
|
*
|
|
* getPartialMolarVolumes()
|
|
*
|
|
* returns an array of partial molar volumes of the species
|
|
* in the solution. Units: m^3 kmol-1.
|
|
*
|
|
* For this solution, thepartial molar volumes are equal to the
|
|
* constant species molar volumes.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getPartialMolarVolumes(doublereal* vbar) const
|
|
{
|
|
getStandardVolumes(vbar);
|
|
}
|
|
|
|
/*****************************************************************
|
|
* Properties of the Standard State of the Species
|
|
* in the Solution
|
|
*****************************************************************/
|
|
|
|
/******************************************************************
|
|
*
|
|
* getPureGibbs()
|
|
*
|
|
* Get the Gibbs functions for the pure species
|
|
* at the current <I>T</I> and <I>P</I> of the solution.
|
|
* We assume an incompressible constant partial molar
|
|
* volume here:
|
|
* \f[
|
|
* \mu^0_k(T,p) = \mu^{ref}_k(T) + (P - P_{ref}) * V_k
|
|
* \f]
|
|
* where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
|
|
* \f$ u^{ref}_k(T)\f$ is the chemical potential of pure
|
|
* species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getPureGibbs(doublereal* gpure) const
|
|
{
|
|
const vector_fp& gibbsrt = gibbs_RT_ref();
|
|
doublereal RT = _RT();
|
|
const doublereal* const gk = DATA_PTR(gibbsrt);
|
|
doublereal delta_p = (m_Pcurrent - m_Pref);
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
gpure[k] = RT * gk[k] + delta_p * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the nondimensional gibbs function for the species
|
|
* standard states at the current T and P of the solution.
|
|
*
|
|
* \f[
|
|
* \mu^0_k(T,P) = \mu^{ref}_k(T) + (P - P_{ref}) * V_k
|
|
* \f]
|
|
* where \f$V_k\f$ is the molar volume of pure species <I>k</I>.
|
|
* \f$ \mu^{ref}_k(T)\f$ is the chemical potential of pure
|
|
* species <I>k</I> at the reference pressure, \f$P_{ref}\f$.
|
|
*
|
|
* @param grt Vector of length m_kk, which on return sr[k]
|
|
* will contain the nondimensional
|
|
* standard state gibbs function for species k.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getGibbs_RT(doublereal* grt) const
|
|
{
|
|
const vector_fp& gibbsrt = gibbs_RT_ref();
|
|
doublereal RT = _RT();
|
|
const doublereal* const gk = DATA_PTR(gibbsrt);
|
|
doublereal delta_prt = (m_Pcurrent - m_Pref)/ RT;
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
grt[k] = gk[k] + delta_prt * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/********************************************************************
|
|
*
|
|
* getEnthalpy_RT()
|
|
*
|
|
* Get the array of nondimensional Enthalpy functions for the ss
|
|
* species at the current <I>T</I> and <I>P</I> of the solution.
|
|
* We assume an incompressible constant partial molar
|
|
* volume here:
|
|
* \f[
|
|
* h^0_k(T,P) = h^{ref}_k(T) + (P - P_{ref}) * V_k
|
|
* \f]
|
|
* where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
|
|
* \f$ h^{ref}_k(T)\f$ is the enthalpy of the pure
|
|
* species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getEnthalpy_RT(doublereal* hrt) const
|
|
{
|
|
const vector_fp& _h = enthalpy_RT_ref();
|
|
doublereal delta_prt = ((m_Pcurrent - m_Pref) /
|
|
(GasConstant * temperature()));
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
hrt[k] = _h[k] + delta_prt * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the nondimensional Entropies for the species
|
|
* standard states at the current T and P of the solution.
|
|
*
|
|
* Note, this is equal to the reference state entropies
|
|
* due to the zero volume expansivity:
|
|
* i.e., (dS/dp)_T = (dV/dT)_P = 0.0
|
|
*
|
|
* @param sr Vector of length m_kk, which on return sr[k]
|
|
* will contain the nondimensional
|
|
* standard state entropy of species k.
|
|
*/
|
|
void IdealSolidSolnPhase::getEntropy_R(doublereal* sr) const
|
|
{
|
|
const vector_fp& _s = entropy_R_ref();
|
|
copy(_s.begin(), _s.end(), sr);
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of nondimensional
|
|
* internal Energies of the standard state at the current temperature
|
|
* of the solution and current pressure for each species.
|
|
* \f[
|
|
* u^0_k(T,P) = h^{ref}_k(T) - P_{ref} * V_k
|
|
* \f]
|
|
*
|
|
* The standard state internal energy is independent of
|
|
* pressure in this equation of state.
|
|
* (inherited from ThermoPhase.h)
|
|
*/
|
|
void IdealSolidSolnPhase::getIntEnergy_RT(doublereal* urt) const
|
|
{
|
|
const vector_fp& _h = enthalpy_RT_ref();
|
|
doublereal prefrt = m_Pref / (GasConstant * temperature());
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
urt[k] = _h[k] - prefrt * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Get the nondimensional heat capacity at constant pressure
|
|
* function for the species
|
|
* standard states at the current T and P of the solution.
|
|
*
|
|
* \f[
|
|
* Cp^0_k(T,P) = Cp^{ref}_k(T)
|
|
* \f]
|
|
* where \f$V_k\f$ is the molar volume of pure species <I>k<\I>.
|
|
* \f$ Cp^{ref}_k(T)\f$ is the constant pressure heat capacity
|
|
* of species <I>k<\I> at the reference pressure, \f$P_{ref}\f$.
|
|
*
|
|
* @param cpr Vector of length m_kk, which on return cpr[k]
|
|
* will contain the nondimensional
|
|
* constant pressure heat capacity for species k.
|
|
*/
|
|
void IdealSolidSolnPhase::getCp_R(doublereal* cpr) const
|
|
{
|
|
const vector_fp& _cpr = cp_R_ref();
|
|
copy(_cpr.begin(), _cpr.end(), cpr);
|
|
}
|
|
|
|
/*
|
|
* Get the molar volumes of each species in their standard
|
|
* states at the current
|
|
* <I>T</I> and <I>P</I> of the solution.
|
|
* units = m^3 / kmol
|
|
*/
|
|
void IdealSolidSolnPhase::getStandardVolumes(doublereal* vol) const
|
|
{
|
|
copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), vol);
|
|
}
|
|
|
|
|
|
/*********************************************************************
|
|
* Thermodynamic Values for the Species Reference States
|
|
*********************************************************************/
|
|
|
|
/*
|
|
* Returns the vector of non-dimensional Enthalpy function
|
|
* of the reference state at the current temperature
|
|
* of the solution and the reference pressure for the species.
|
|
* Units = unitless
|
|
*/
|
|
void IdealSolidSolnPhase::getEnthalpy_RT_ref(doublereal* hrt) const
|
|
{
|
|
_updateThermo();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
hrt[k] = m_h0_RT[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of non-dimensional Gibbs function
|
|
* of the reference state at the current temperature
|
|
* of the solution and the reference pressure for the species.
|
|
* Units = unitless
|
|
*/
|
|
void IdealSolidSolnPhase::getGibbs_RT_ref(doublereal* grt) const
|
|
{
|
|
_updateThermo();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
grt[k] = m_g0_RT[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of Gibbs function
|
|
* of the reference state at the current temperature
|
|
* of the solution and the reference pressure for the species.
|
|
* Units = J / kmol
|
|
*/
|
|
void IdealSolidSolnPhase::getGibbs_ref(doublereal* g) const
|
|
{
|
|
_updateThermo();
|
|
double tmp = GasConstant * temperature();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
g[k] = tmp * m_g0_RT[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of nondimensional
|
|
* internal Energies of the standard state at the current temperature
|
|
* of the solution and current pressure for each species.
|
|
* (inherited from ThermoPhase.h)
|
|
*/
|
|
void IdealSolidSolnPhase::getIntEnergy_RT_ref(doublereal* urt) const
|
|
{
|
|
const vector_fp& _h = enthalpy_RT_ref();
|
|
doublereal prefrt = m_Pref / (GasConstant * temperature());
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
urt[k] = _h[k] - prefrt * m_speciesMolarVolume[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of non-dimensional Entropy function
|
|
* of the reference state at the current temperature
|
|
* of the solution and the reference pressure for the species.
|
|
* Units = unitless
|
|
*/
|
|
void IdealSolidSolnPhase::getEntropy_R_ref(doublereal* er) const
|
|
{
|
|
_updateThermo();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
er[k] = m_s0_R[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns the vector of non-dimensional Entropy function
|
|
* of the reference state at the current temperature
|
|
* of the solution and the reference pressure for the species.
|
|
* Units = unitless
|
|
*/
|
|
void IdealSolidSolnPhase::getCp_R_ref(doublereal* cpr) const
|
|
{
|
|
_updateThermo();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
cpr[k] = m_cp0_R[k];
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Returns a reference to the vector of nondimensional
|
|
* enthalpies of the reference state at the current temperature.
|
|
* Real reason for its existence is that it also checks
|
|
* to see if a recalculation of the reference thermodynamics
|
|
* functions needs to be done.
|
|
*/
|
|
const vector_fp& IdealSolidSolnPhase::enthalpy_RT_ref() const
|
|
{
|
|
_updateThermo();
|
|
return m_h0_RT;
|
|
}
|
|
|
|
/*
|
|
* Returns a reference to the vector of nondimensional
|
|
* enthalpies of the reference state at the current temperature.
|
|
* Real reason for its existence is that it also checks
|
|
* to see if a recalculation of the reference thermodynamics
|
|
* functions needs to be done.
|
|
*/
|
|
const vector_fp& IdealSolidSolnPhase::expGibbs_RT_ref() const
|
|
{
|
|
_updateThermo();
|
|
for (size_t k = 0; k != m_kk; k++) {
|
|
m_expg0_RT[k] = exp(m_g0_RT[k]);
|
|
}
|
|
return m_expg0_RT;
|
|
}
|
|
|
|
/*
|
|
* Returns a reference to the vector of nondimensional
|
|
* enthalpies of the reference state at the current temperature.
|
|
* Real reason for its existence is that it also checks
|
|
* to see if a recalculation of the reference thermodynamics
|
|
* functions needs to be done.
|
|
*/
|
|
const vector_fp& IdealSolidSolnPhase::entropy_R_ref() const
|
|
{
|
|
_updateThermo();
|
|
return m_s0_R;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Utility Functions
|
|
*********************************************************************/
|
|
/*
|
|
* initThermo() function initializes the object for use.
|
|
*
|
|
* Before its invokation, the class isn't ready for calculation.
|
|
*/
|
|
void IdealSolidSolnPhase::initThermo()
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Import and initialize an IdealSolidSolnPhase phase
|
|
* specification in an XML tree into the current object.
|
|
* Here we read an XML description of the phase.
|
|
* We import descriptions of the elements that make up the
|
|
* species in a phase.
|
|
* We import information about the species, including their
|
|
* reference state thermodynamic polynomials. We then freeze
|
|
* the state of the species.
|
|
*
|
|
* This routine calls importPhase() to do most of its work.
|
|
* Then, importPhase() calls initThermoXML() to finish
|
|
* off the work.
|
|
*
|
|
* @param phaseNode This object must be the phase node of a
|
|
* complete XML tree
|
|
* description of the phase, including all of the
|
|
* species data. In other words while "phase" must
|
|
* point to an XML phase object, it must have
|
|
* sibling nodes "speciesData" that describe
|
|
* the species in the phase.
|
|
* @param id ID of the phase. If nonnull, a check is done
|
|
* to see if phaseNode is pointing to the phase
|
|
* with the correct id.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
constructPhaseXML(XML_Node& phaseNode, std::string id)
|
|
{
|
|
string subname = "IdealSolidSolnPhase::constructPhaseXML";
|
|
if (id.size() > 0) {
|
|
string idp = phaseNode.id();
|
|
if (idp != id) {
|
|
throw CanteraError(subname.c_str(),
|
|
"phasenode and Id are incompatible");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check on the thermo field. Must have:
|
|
* <thermo model="IdealSolidSolution" />
|
|
*/
|
|
if (phaseNode.hasChild("thermo")) {
|
|
XML_Node& thNode = phaseNode.child("thermo");
|
|
string mStringa = thNode.attrib("model");
|
|
string mString = lowercase(mStringa);
|
|
if (mString != "idealsolidsolution") {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unknown thermo model: " + mStringa);
|
|
}
|
|
} else {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unspecified thermo model");
|
|
}
|
|
|
|
/*
|
|
* Form of the standard concentrations. Must have one of:
|
|
*
|
|
* <standardConc model="unity" />
|
|
* <standardConc model="molar_volume" />
|
|
* <standardConc model="solvent_volume" />
|
|
*/
|
|
if (phaseNode.hasChild("standardConc")) {
|
|
XML_Node& scNode = phaseNode.child("standardConc");
|
|
string formStringa = scNode.attrib("model");
|
|
string formString = lowercase(formStringa);
|
|
if (formString == "unity") {
|
|
m_formGC = 0;
|
|
} else if (formString == "molar_volume") {
|
|
m_formGC = 1;
|
|
} else if (formString == "solvent_volume") {
|
|
m_formGC = 2;
|
|
} else {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unknown standardConc model: " + formStringa);
|
|
}
|
|
} else {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unspecified standardConc model");
|
|
}
|
|
|
|
bool m_ok = importPhase(phaseNode, this);
|
|
if (!m_ok) {
|
|
throw CanteraError(subname.c_str(),"importPhase failed ");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Initialization of an IdealSolidSolnPhase phase using an
|
|
* xml file
|
|
*
|
|
* This routine is a precursor to constructPhaseFile(XML_Node*)
|
|
* routine, which does most of the work.
|
|
*
|
|
* @param infile XML file containing the description of the
|
|
* phase
|
|
*
|
|
* @param id Optional parameter identifying the name of the
|
|
* phase. If none is given, the first XML
|
|
* phase element will be used.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
constructPhaseFile(std::string inputFile, std::string id)
|
|
{
|
|
if (inputFile.size() == 0) {
|
|
throw CanteraError("IdealSolidSolnPhase::constructPhaseFile",
|
|
"input file is null");
|
|
}
|
|
string path = findInputFile(inputFile);
|
|
ifstream fin(path.c_str());
|
|
if (!fin) {
|
|
throw CanteraError("IdealSolidSolnPhase::constructPhaseFile","could not open "
|
|
+path+" for reading.");
|
|
}
|
|
/*
|
|
* The phase object automatically constructs an XML object.
|
|
* Use this object to store information.
|
|
*/
|
|
XML_Node& phaseNode_XML = xml();
|
|
XML_Node* fxml = new XML_Node();
|
|
fxml->build(fin);
|
|
XML_Node* fxml_phase = findXMLPhase(fxml, id);
|
|
if (!fxml_phase) {
|
|
throw CanteraError("IdealSolidSolnPhase::constructPhaseFile",
|
|
"ERROR: Can not find phase named " +
|
|
id + " in file named " + inputFile);
|
|
}
|
|
fxml_phase->copy(&phaseNode_XML);
|
|
|
|
constructPhaseXML(*fxml_phase, id);
|
|
delete fxml;
|
|
}
|
|
|
|
/*
|
|
* @internal
|
|
* Import and initialize a ThermoPhase object
|
|
* using an XML tree.
|
|
* Here we read extra information about the XML description
|
|
* of a phase. Regular information about elements and species
|
|
* and their reference state thermodynamic information
|
|
* have already been read at this point.
|
|
* For example, we do not need to call this function for
|
|
* ideal gas equations of state.
|
|
* This function is called from importPhase()
|
|
* after the elements and the
|
|
* species are initialized with default ideal solution
|
|
* level data.
|
|
*
|
|
* @param phaseNode This object must be the phase node of a
|
|
* complete XML tree
|
|
* description of the phase, including all of the
|
|
* species data. In other words while "phase" must
|
|
* point to an XML phase object, it must have
|
|
* sibling nodes "speciesData" that describe
|
|
* the species in the phase.
|
|
* @param id ID of the phase. If nonnull, a check is done
|
|
* to see if phaseNode is pointing to the phase
|
|
* with the correct id.
|
|
*/
|
|
void IdealSolidSolnPhase::initThermoXML(XML_Node& phaseNode, std::string id)
|
|
{
|
|
string subname = "IdealSolidSolnPhase::initThermoXML";
|
|
/*
|
|
* Check on the thermo field. Must have:
|
|
* <thermo model="IdealSolidSolution" />
|
|
*/
|
|
if (phaseNode.hasChild("thermo")) {
|
|
XML_Node& thNode = phaseNode.child("thermo");
|
|
string mStringa = thNode.attrib("model");
|
|
string mString = lowercase(mStringa);
|
|
if (mString != "idealsolidsolution") {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unknown thermo model: " + mStringa);
|
|
}
|
|
} else {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unspecified thermo model");
|
|
}
|
|
|
|
/*
|
|
* Form of the standard concentrations. Must have one of:
|
|
*
|
|
* <standardConc model="unity" />
|
|
* <standardConc model="molar_volume" />
|
|
* <standardConc model="solvent_volume" />
|
|
*/
|
|
if (phaseNode.hasChild("standardConc")) {
|
|
XML_Node& scNode = phaseNode.child("standardConc");
|
|
string formStringa = scNode.attrib("model");
|
|
string formString = lowercase(formStringa);
|
|
if (formString == "unity") {
|
|
m_formGC = 0;
|
|
} else if (formString == "molar_volume") {
|
|
m_formGC = 1;
|
|
} else if (formString == "solvent_volume") {
|
|
m_formGC = 2;
|
|
} else {
|
|
throw CanteraError(subname.c_str(),
|
|
"Unknown standardConc model: " + formStringa);
|
|
}
|
|
} else {
|
|
throw CanteraError(subname.c_str(), "Unspecified standardConc model");
|
|
}
|
|
|
|
/*
|
|
* Initialize all of the lengths now that we know how many species
|
|
* there are in the phase.
|
|
*/
|
|
initLengths();
|
|
/*
|
|
* Now go get the molar volumes
|
|
*/
|
|
XML_Node& speciesList = phaseNode.child("speciesArray");
|
|
XML_Node* speciesDB = get_XML_NameID("speciesData", speciesList["datasrc"],
|
|
&phaseNode.root());
|
|
const vector<string>&sss = speciesNames();
|
|
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
XML_Node* s = speciesDB->findByAttr("name", sss[k]);
|
|
XML_Node* ss = s->findByName("standardState");
|
|
m_speciesMolarVolume[k] = ctml::getFloat(*ss, "molarVolume", "toSI");
|
|
}
|
|
|
|
/*
|
|
* Call the base initThermo, which handles setting the initial
|
|
* state.
|
|
*/
|
|
ThermoPhase::initThermoXML(phaseNode, id);
|
|
}
|
|
|
|
/*
|
|
* This internal function adjusts the lengths of arrays
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
initLengths()
|
|
{
|
|
m_kk = nSpecies();
|
|
m_mm = nElements();
|
|
|
|
/*
|
|
* Obtain the limits of the temperature from the species
|
|
* thermo handler's limits.
|
|
*/
|
|
doublereal tmin = m_spthermo->minTemp();
|
|
doublereal tmax = m_spthermo->maxTemp();
|
|
if (tmin > 0.0) {
|
|
m_tmin = tmin;
|
|
}
|
|
if (tmax > 0.0) {
|
|
m_tmax = tmax;
|
|
}
|
|
|
|
/*
|
|
* Obtain the reference pressure by calling the ThermoPhase
|
|
* function refPressure, which in turm calls the
|
|
* species thermo reference pressure function of the
|
|
* same name.
|
|
*/
|
|
m_Pref = refPressure();
|
|
|
|
m_h0_RT.resize(m_kk);
|
|
m_g0_RT.resize(m_kk);
|
|
m_expg0_RT.resize(m_kk);
|
|
m_cp0_R.resize(m_kk);
|
|
m_s0_R.resize(m_kk);
|
|
m_pe.resize(m_kk, 0.0);
|
|
m_pp.resize(m_kk);
|
|
m_speciesMolarVolume.resize(m_kk);
|
|
}
|
|
|
|
/*
|
|
* Set mixture to an equilibrium state consistent with specified
|
|
* element potentials and temperature.
|
|
*
|
|
* @param lambda_RT vector of non-dimensional element potentials
|
|
* \f$ \lambda_m/RT \f$.
|
|
*
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
setToEquilState(const doublereal* lambda_RT)
|
|
{
|
|
const vector_fp& grt = gibbs_RT_ref();
|
|
|
|
// set the pressure and composition to be consistent with
|
|
// the temperature,
|
|
doublereal pres = 0.0;
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
m_pp[k] = -grt[k];
|
|
for (size_t m = 0; m < m_mm; m++) {
|
|
m_pp[k] += nAtoms(k,m)*lambda_RT[m];
|
|
}
|
|
m_pp[k] = m_Pref * exp(m_pp[k]);
|
|
pres += m_pp[k];
|
|
}
|
|
doublereal* dptr = DATA_PTR(m_pp);
|
|
setState_PX(pres, dptr);
|
|
}
|
|
//================================================================================================
|
|
/*
|
|
*
|
|
* speciesMolarVolume()
|
|
*
|
|
* Report the molar volume of species k
|
|
*
|
|
* units - \f$ m^3 kmol^-1 \f$
|
|
*/
|
|
double IdealSolidSolnPhase::
|
|
speciesMolarVolume(int k) const
|
|
{
|
|
return m_speciesMolarVolume[k];
|
|
}
|
|
|
|
/*
|
|
*
|
|
* getSpeciesMolarVolumes():
|
|
*
|
|
* Fill in a return vector containing the species molar volumes
|
|
* units - \f$ m^3 kmol^-1 \f$
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
getSpeciesMolarVolumes(doublereal* smv) const
|
|
{
|
|
copy(m_speciesMolarVolume.begin(), m_speciesMolarVolume.end(), smv);
|
|
}
|
|
//================================================================================================
|
|
/*
|
|
*
|
|
* _updateThermo()
|
|
*
|
|
* This function gets called for every call to functions in this
|
|
* class. It checks to see whether the temperature has changed and
|
|
* thus the reference thermodynamics functions for all of the species
|
|
* must be recalculated.
|
|
* If the temperature has changed, the species thermo manager is called
|
|
* to recalculate G, Cp, H, and S at the current temperature.
|
|
*/
|
|
void IdealSolidSolnPhase::
|
|
_updateThermo() const
|
|
{
|
|
doublereal tnow = temperature();
|
|
if (m_tlast != tnow) {
|
|
/*
|
|
* Update the thermodynamic functions of the reference state.
|
|
*/
|
|
m_spthermo->update(tnow, DATA_PTR(m_cp0_R), DATA_PTR(m_h0_RT),
|
|
DATA_PTR(m_s0_R));
|
|
m_tlast = tnow;
|
|
doublereal rrt = 1.0 / (GasConstant * tnow);
|
|
doublereal deltaE;
|
|
for (size_t k = 0; k < m_kk; k++) {
|
|
deltaE = rrt * m_pe[k];
|
|
m_h0_RT[k] += deltaE;
|
|
m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
|
|
}
|
|
m_tlast = tnow;
|
|
}
|
|
}
|
|
//================================================================================================
|
|
} // end namespace Cantera
|
|
//==================================================================================================
|