moved files to thermo subdirectory

This commit is contained in:
Dave Goodwin 2007-05-04 14:02:39 +00:00
parent 95b303ddbd
commit a04e7309a2
60 changed files with 16812 additions and 16 deletions

View file

@ -0,0 +1,143 @@
/**
* @file ConstCpPoly.cpp
* Declarations for the \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType \endlink object that
* employs a constant heat capacity assumption (see \ref spthermo and
* \link Cantera::ConstCpPoly ConstCpPoly \endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#include "ConstCpPoly.h"
#include <math.h>
namespace Cantera {
ConstCpPoly::ConstCpPoly()
: m_t0(0.0),
m_cp0_R(0.0),
m_h0_R(0.0),
m_s0_R(0.0),
m_logt0(0.0),
m_lowT(0.0),
m_highT(0.0),
m_Pref(0.0),
m_index(0) {
}
ConstCpPoly::ConstCpPoly(int n, doublereal tlow, doublereal thigh,
doublereal pref,
const doublereal* coeffs) :
m_lowT (tlow),
m_highT (thigh),
m_Pref (pref),
m_index (n) {
m_t0 = coeffs[0];
m_h0_R = coeffs[1] / GasConstant;
m_s0_R = coeffs[2] / GasConstant;
m_cp0_R = coeffs[3] / GasConstant;
m_logt0 = log(m_t0);
}
ConstCpPoly::ConstCpPoly(const ConstCpPoly& b) :
m_t0 (b.m_t0),
m_cp0_R (b.m_cp0_R),
m_h0_R (b.m_h0_R),
m_s0_R (b.m_s0_R),
m_logt0 (b.m_logt0),
m_lowT (b.m_lowT),
m_highT (b.m_highT),
m_Pref (b.m_Pref),
m_index (b.m_index)
{
}
ConstCpPoly& ConstCpPoly::operator=(const ConstCpPoly& b) {
if (&b != this) {
m_t0 = b.m_t0;
m_cp0_R = b.m_cp0_R;
m_h0_R = b.m_h0_R;
m_s0_R = b.m_s0_R;
m_logt0 = b.m_logt0;
m_lowT = b.m_lowT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
}
return *this;
}
ConstCpPoly::~ConstCpPoly(){}
SpeciesThermoInterpType *
ConstCpPoly::duplMyselfAsSpeciesThermoInterpType() const {
ConstCpPoly* newCCP = new ConstCpPoly(*this);
return (SpeciesThermoInterpType*) newCCP;
}
doublereal ConstCpPoly::minTemp() const {
return m_lowT;
}
doublereal ConstCpPoly::maxTemp() const {
return m_highT;
}
doublereal ConstCpPoly::refPressure() const {
return m_Pref;
}
void ConstCpPoly::updateProperties(const doublereal* tt,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
double t = *tt;
doublereal logt = log(t);
doublereal rt = 1.0/t;
cp_R[m_index] = m_cp0_R;
h_RT[m_index] = rt*(m_h0_R + (t - m_t0) * m_cp0_R);
s_R[m_index] = m_s0_R + m_cp0_R * (logt - m_logt0);
}
void ConstCpPoly::updatePropertiesTemp(const doublereal temp,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
doublereal logt = log(temp);
doublereal rt = 1.0/temp;
cp_R[m_index] = m_cp0_R;
h_RT[m_index] = rt*(m_h0_R + (temp - m_t0) * m_cp0_R);
s_R[m_index] = m_s0_R + m_cp0_R * (logt - m_logt0);
}
void ConstCpPoly::reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = CONSTANT_CP;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
coeffs[0] = m_t0;
coeffs[1] = m_h0_R * GasConstant;
coeffs[2] = m_s0_R * GasConstant;
coeffs[3] = m_cp0_R * GasConstant;
}
void ConstCpPoly::modifyParameters(doublereal* coeffs) {
m_t0 = coeffs[0];
m_h0_R = coeffs[1] / GasConstant;
m_s0_R = coeffs[2] / GasConstant;
m_cp0_R = coeffs[3] / GasConstant;
m_logt0 = log(m_t0);
}
}

View file

@ -0,0 +1,196 @@
/**
* @file ConstCpPoly.h
* Headers for the \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink
* object that employs a constant heat capacity assumption (see \ref spthermo and
* \link Cantera::ConstCpPoly ConstCpPoly\endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_CONSTCPPOLY_H
#define CT_CONSTCPPOLY_H
#include "SpeciesThermoInterpType.h"
namespace Cantera {
/**
* A constant-heat capacity species thermodynamic property manager class.
* This makes the
* assumption that the heat capacity is a constant. Then, the following
* relations are used to complete the specification of the thermodynamic
* functions for the species.
*
* \f[
* \frac{c_p(T)}{R} = Cp0\_R
* \f]
* \f[
* \frac{h^0(T)}{RT} = \frac{1}{T} * (h0\_R + (T - T_0) * Cp0\_R)
* \f]
* \f[
* \frac{s^0(T)}{R} = (s0\_R + (log(T) - log(T_0)) * Cp0\_R)
* \f]
*
* This parameterization takes 4 input values. These are:
* - c[0] = \f$ T_0 \f$(Kelvin)
* - c[1] = \f$ H_k^o(T_0, p_{ref}) \f$ (J/kmol)
* - c[2] = \f$ S_k^o(T_0, p_{ref}) \f$ (J/kmol K)
* - c[3] = \f$ {Cp}_k^o(T_0, p_{ref}) \f$ (J(kmol K)
*
* The multispecies SimpleThermo class makes the same assumptions as
* this class does.
*
* @see SimpleThermo
*
* @ingroup spthermo
*/
class ConstCpPoly: public SpeciesThermoInterpType {
public:
//! empty constructor
ConstCpPoly();
//! Constructor used in templated instantiations
/*!
* @param n Species index
* @param tlow Minimum temperature
* @param thigh Maximum temperature
* @param pref reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state for species n.
* There are 4 coefficients for the %ConstCpPoly parameterization.
* - c[0] = \f$ T_0 \f$(Kelvin)
* - c[1] = \f$ H_k^o(T_0, p_{ref}) \f$ (J/kmol)
* - c[2] = \f$ S_k^o(T_0, p_{ref}) \f$ (J/kmol K)
* - c[3] = \f$ {Cp}_k^o(T_0, p_{ref}) \f$ (J(kmol K)
*
*/
ConstCpPoly(int n, doublereal tlow, doublereal thigh,
doublereal pref,
const doublereal* coeffs);
//! copy constructor
ConstCpPoly(const ConstCpPoly&);
//! Assignment operator
ConstCpPoly& operator=(const ConstCpPoly&);
//! Destructor
virtual ~ConstCpPoly();
//! Duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const;
//! Returns the minimum temperature that the thermo
//! parameterization is valid
doublereal minTemp() const;
//! Returns the maximum temperature that the thermo
//! parameterization is valid
doublereal maxTemp() const;
//! Returns the reference pressure (Pa)
doublereal refPressure() const;
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return CONSTANT_CP; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* Form and Length of the temperature polynomial:
* - m_t[0] = tt;
*
* @param tt Vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
void updateProperties(const doublereal* tt,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const;
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const;
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const;
//! Modify parameters for the standard state
/*!
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs);
protected:
//! Base temperature
doublereal m_t0;
//! Dimensionless value of the heat capacity
doublereal m_cp0_R;
//! dimensionless value of the enthaply at t0
doublereal m_h0_R;
//! Dimensionless value of the entropy at t0
doublereal m_s0_R;
//! log of the t0 value
doublereal m_logt0;
//! Minimum temperature for which the parameterization is valid (Kelvin)
doublereal m_lowT;
//! Maximum temperature for which the parameterization is valid (Kelvin)
doublereal m_highT;
//! Reference pressure (Pa)
doublereal m_Pref;
//! Species Index
int m_index;
private:
};
}
#endif

View file

@ -0,0 +1,151 @@
/**
* @file ConstDensityThermo.cpp
* Declarations for a Thermo manager for incompressible ThermoPhases
* (see \ref thermoprops and \link Cantera::ConstDensityThermo ConstDensityThermo
\endlink).
*/
/*
* $Id$
*
* Copyright 2002 California Institute of Technology
*/
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "mix_defs.h"
#include "ConstDensityThermo.h"
#include "SpeciesThermo.h"
#include <math.h>
namespace Cantera {
int ConstDensityThermo::
eosType() const { return cIncompressible; }
doublereal ConstDensityThermo::enthalpy_mole() const {
doublereal p0 = m_spthermo->refPressure();
return GasConstant * temperature() *
mean_X(&enthalpy_RT()[0])
+ (pressure() - p0)/molarDensity();
}
doublereal ConstDensityThermo::intEnergy_mole() const {
doublereal p0 = m_spthermo->refPressure();
return GasConstant * temperature() *
mean_X(&enthalpy_RT()[0])
- p0/molarDensity();
}
doublereal ConstDensityThermo::entropy_mole() const {
return GasConstant * (mean_X(&entropy_R()[0]) -
sum_xlogx());
}
doublereal ConstDensityThermo::gibbs_mole() const {
return enthalpy_mole() - temperature() * entropy_mole();
}
doublereal ConstDensityThermo::cp_mole() const {
return GasConstant * mean_X(&cp_R()[0]);
}
doublereal ConstDensityThermo::cv_mole() const {
return cp_mole();
}
doublereal ConstDensityThermo::pressure() const {
return m_press;
}
void ConstDensityThermo::setPressure(doublereal p) {
m_press = p;
}
void ConstDensityThermo::getActivityConcentrations(doublereal* c) const {
getConcentrations(c);
}
void ConstDensityThermo::getActivityCoefficients(doublereal* ac) const {
for (int k = 0; k < m_kk; k++) {
ac[k] = 1.0;
}
}
doublereal ConstDensityThermo::standardConcentration(int k) const {
return molarDensity();
}
doublereal ConstDensityThermo::logStandardConc(int k) const {
return log(molarDensity());
}
void ConstDensityThermo::getChemPotentials(doublereal* mu) const {
doublereal vdp = (pressure() - m_spthermo->refPressure())/
molarDensity();
doublereal xx;
doublereal rt = temperature() * GasConstant;
const array_fp& g_RT = gibbs_RT();
for (int k = 0; k < m_kk; k++) {
xx = fmaxx(SmallNumber, moleFraction(k));
mu[k] = rt*(g_RT[k] + log(xx)) + vdp;
}
}
void ConstDensityThermo::getStandardChemPotentials(doublereal* mu0) const {
getPureGibbs(mu0);
}
void ConstDensityThermo::initThermo() {
m_kk = nSpecies();
m_mm = nElements();
doublereal tmin = m_spthermo->minTemp();
doublereal tmax = m_spthermo->maxTemp();
if (tmin > 0.0) m_tmin = tmin;
if (tmax > 0.0) m_tmax = tmax;
m_p0 = refPressure();
int leng = m_kk;
m_h0_RT.resize(leng);
m_g0_RT.resize(leng);
m_expg0_RT.resize(leng);
m_cp0_R.resize(leng);
m_s0_R.resize(leng);
m_pe.resize(leng, 0.0);
m_pp.resize(leng);
}
void ConstDensityThermo::setToEquilState(const doublereal* lambda_RT) {
throw CanteraError("setToEquilState","not yet impl.");
}
void ConstDensityThermo::_updateThermo() const {
doublereal tnow = temperature();
if (m_tlast != tnow) {
m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0],
&m_s0_R[0]);
m_tlast = tnow;
int k;
for (k = 0; k < m_kk; k++) {
m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
}
m_tlast = tnow;
}
}
void ConstDensityThermo::setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","Incompressible");
doublereal rho = getFloat(eosdata, "density", "-");
setDensity(rho);
}
}

View file

@ -0,0 +1,451 @@
/**
* @file ConstDensityThermo.h
* Header for a Thermo manager for incompressible ThermoPhases
* (see \ref thermoprops and \link Cantera::ConstDensityThermo ConstDensityThermo\endlink).
*/
/*
* $Author$
* $Date$
* $Revision$
*
* Copyright 2002 California Institute of Technology
*
*/
#ifndef CT_CONSTRHOTHERMO_H
#define CT_CONSTRHOTHERMO_H
#include "ct_defs.h"
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
#include "utilities.h"
namespace Cantera {
//! Overloads the virtual methods of class ThermoPhase to implement the
//! incompressible equation of state.
/**
*
*
* <b> Specification of Species Standard State Properties </b>
*
*
* <b> Specification of Solution Thermodynamic Properties </b>
*
* The density is assumed to be constant, no matter what the concentration of the solution.
*
*
* <b> Application within %Kinetics Managers </b>
*
*
* <b> XML Example </b>
*
* An example of an XML Element named phase setting up a SurfPhase object named diamond_100
* is given below.
*
* @ingroup thermoprops
*/
class ConstDensityThermo : public ThermoPhase {
public:
//! Constructor.
/*!
*
*/
ConstDensityThermo() : m_tlast(0.0) {}
//! Destructor
virtual ~ConstDensityThermo() {}
// overloaded methods of class ThermoPhase
virtual int eosType() const;
//! Return the Molar Enthalpy. Units: J/kmol.
/*!
*
*/
/// Molar enthalpy. Units: J/kmol.
virtual doublereal enthalpy_mole() const;
/// Molar internal energy. Units: J/kmol.
virtual doublereal intEnergy_mole() const;
/// Molar entropy. Units: J/kmol/K.
virtual doublereal entropy_mole() const;
/// Molar Gibbs function. Units: J/kmol.
virtual doublereal gibbs_mole() const;
/// Molar heat capacity at constant pressure. Units: J/kmol/K.
virtual doublereal cp_mole() const;
/// Molar heat capacity at constant volume. Units: J/kmol/K.
virtual doublereal cv_mole() const;
//! Return the thermodynamic pressure (Pa).
/*!
* This method must be overloaded in derived classes. Since the
* mass density, temperature, and mass fractions are stored,
* this method should use these values to implement the
* mechanical equation of state \f$ P(T, \rho, Y_1, \dots,
* Y_K) \f$.
*/
virtual doublereal pressure() const;
//! Set the internally storred pressure (Pa) at constant
//! temperature and composition
/*!
* This method must be reimplemented in derived classes, where it
* may involve the solution of a nonlinear equation. Within %Cantera,
* the independent variable is the density. Therefore, this function
* solves for the density that will yield the desired input pressure.
* The temperature and composition iare held constant during this process.
*
* This base class function will print an error, if not overwritten.
*
* @param p input Pressure (Pa)
*/
virtual void setPressure(doublereal p);
//! This method returns an array of generalized concentrations
/*!
* \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k /
* C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration
* defined below and \f$ a_k \f$ are activities used in the
* thermodynamic functions. These activity (or generalized)
* concentrations are used
* by kinetics manager classes to compute the forward and
* reverse rates of elementary reactions. Note that they may
* or may not have units of concentration --- they might be
* partial pressures, mole fractions, or surface coverages,
* for example.
*
* @param c Output array of generalized concentrations. The
* units depend upon the implementation of the
* reaction rate expressions within the phase.
*/
virtual void getActivityConcentrations(doublereal* c) const;
//! Get the array of non-dimensional molar-based activity coefficients at
//! the current solution temperature, pressure, and solution concentration.
/*!
* @param ac Output vector of activity coefficients. Length: m_kk.
*/
virtual void getActivityCoefficients(doublereal* ac) const;
//! Get the species chemical potentials. Units: J/kmol.
/*!
* This function returns a vector of chemical potentials of the
* species in solution at the current temperature, pressure
* and mole fraction of the solution.
*
* @param mu Output vector of species chemical
* potentials. Length: m_kk. Units: J/kmol
*/
virtual void getChemPotentials(doublereal* mu) const;
//! Get the array of chemical potentials at unit activity for the species
//! at their standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* These are the standard state chemical potentials \f$ \mu^0_k(T,P)
* \f$. The values are evaluated at the current
* temperature and pressure of the solution
*
* @param mu0 Output vector of chemical potentials.
* Length: m_kk.
*/
virtual void getStandardChemPotentials(doublereal* mu0) const;
//! Return the standard concentration for the kth species
/*!
* The standard concentration \f$ C^0_k \f$ used to normalize
* the activity (i.e., generalized) concentration. In many cases, this quantity
* will be the same for all species in a phase - for example,
* for an ideal gas \f$ C^0_k = P/\hat R T \f$. For this
* reason, this method returns a single value, instead of an
* array. However, for phases in which the standard
* concentration is species-specific (e.g. surface species of
* different sizes), this method may be called with an
* optional parameter indicating the species.
*
* @param k Optional parameter indicating the species. The default
* is to assume this refers to species 0.
* @return
* Returns the standard Concentration in units of m3 kmol-1.
*/
virtual doublereal standardConcentration(int k=0) const;
//! Natural logarithm of the standard concentration of the kth species.
/*!
* @param k index of the species (defaults to zero)
*/
virtual doublereal logStandardConc(int k=0) const;
//! Get the Gibbs functions for the standard
//! state of the species at the current <I>T</I> and <I>P</I> of the solution
/*!
* Units are Joules/kmol
* @param gpure Output vector of standard state gibbs free energies
* Length: m_kk.
*/
virtual void getPureGibbs(doublereal* gpure) const {
const array_fp& gibbsrt = gibbs_RT();
scale(gibbsrt.begin(), gibbsrt.end(), gpure, _RT());
}
//! Get the nondimensional Enthalpy functions for the species
//! at their standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param hrt Output vector of nondimensional standard state enthalpies.
* Length: m_kk.
*/
void getEnthalpy_RT(doublereal* hrt) const {
const array_fp& _h = enthalpy_RT();
std::copy(_h.begin(), _h.end(), hrt);
}
//! Get the array of nondimensional Entropy functions for the
//! standard state species at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param sr Output vector of nondimensional standard state entropies.
* Length: m_kk.
*/
void getEntropy_R(doublereal* sr) const {
const array_fp& _s = entropy_R();
std::copy(_s.begin(), _s.end(), sr);
}
//! Get the nondimensional Gibbs functions for the species
//! in their standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param grt Output vector of nondimensional standard state gibbs free energies
* Length: m_kk.
*/
virtual void getGibbs_RT(doublereal* grt) const {
const array_fp& gibbsrt = gibbs_RT();
std::copy(gibbsrt.begin(), gibbsrt.end(), grt);
}
//! Get the nondimensional Heat Capacities at constant
//! pressure for the species standard states
//! at the current <I>T</I> and <I>P</I> of the solution
/*!
* @param cpr Output vector of nondimensional standard state heat capacities
* Length: m_kk.
*/
void getCp_R(doublereal* cpr) const {
const array_fp& _cpr = cp_R();
std::copy(_cpr.begin(), _cpr.end(), cpr);
}
// new methods defined here
//! Returns a reference to the vector of nondimensional
//! enthalpies of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
const array_fp& enthalpy_RT() const {
_updateThermo();
return m_h0_RT;
}
//! Returns a reference to the vector of nondimensional
//! Gibbs Free Energies of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
const array_fp& gibbs_RT() const {
_updateThermo();
return m_g0_RT;
}
//! Returns a reference to the vector of exponentials of the nondimensional
//! Gibbs Free Energies of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
const array_fp& expGibbs_RT() const {
_updateThermo();
int k;
for (k = 0; k != m_kk; k++) m_expg0_RT[k] = std::exp(m_g0_RT[k]);
return m_expg0_RT;
}
//! Returns a reference to the vector of nondimensional
//! entropies of the reference state at the current temperature
//! of the solution and the reference pressure for each species.
const array_fp& entropy_R() const {
_updateThermo();
return m_s0_R;
}
//! Returns a reference to the vector of nondimensional
//! constant pressure heat capacities of the reference state
//! at the current temperature of the solution
//! and reference pressure for each species.
const array_fp& cp_R() const {
_updateThermo();
return m_cp0_R;
}
//! Set the potential energy of species k
/*!
* @param k species index
* @param pe Potential energy (J kmol-1).
*/
virtual void setPotentialEnergy(int k, doublereal pe) {
m_pe[k] = pe;
}
//! Returns the potential energy of species k
/*!
* @param k species index
*/
virtual doublereal potentialEnergy(int k) const {
return m_pe[k];
}
//! Initialize the ThermoPhase object after all species have been set up
/*!
* @internal Initialize.
*
* This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called from ThermoPhase::initThermoXML(),
* which is called from importPhase(),
* just prior to returning from function importPhase().
*
* @see importCTML.cpp
*/
virtual void initThermo();
//!This method is used by the ChemEquil equilibrium solver.
/*!
* It sets the state such that the chemical potentials satisfy
* \f[ \frac{\mu_k}{\hat R T} = \sum_m A_{k,m}
* \left(\frac{\lambda_m} {\hat R T}\right) \f] where
* \f$ \lambda_m \f$ is the element potential of element m. The
* temperature is unchanged. Any phase (ideal or not) that
* implements this method can be equilibrated by ChemEquil.
*
* @param lambda_RT Input vector of dimensionless element potentials
* The length is equal to nElements().
*/
virtual void setToEquilState(const doublereal* lambda_RT);
//! Set the equation of state parameters
/*!
* @internal
* The number and meaning of these depends on the subclass.
*
* @param n number of parameters
* @param c array of \a n coefficients
*/
virtual void setParameters(int n, doublereal* c) {
setDensity(c[0]);
}
//! Get the equation of state parameters in a vector
/*!
* @internal
* The number and meaning of these depends on the subclass.
*
* @param n number of parameters
* @param c array of \a n coefficients
*/
virtual void getParameters(int &n, doublereal * const c) {
double d = density();
c[0] = d;
n = 1;
}
//! Set equation of state parameter values from XML entries.
/*!
*
* This method is called by function importPhase() in
* file importCTML.cpp when processing a phase definition in
* an input file. It should be overloaded in subclasses to set
* any parameters that are specific to that particular phase
* model. Note, this method is called before the phase is
* initialzed with elements and/or species.
*
* @param eosdata An XML_Node object corresponding to
* the "thermo" entry for this phase in the input file.
*/
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:
//! number of elements
int m_mm;
//! Minimum temperature for valid species standard state thermo props
/*!
* This is the minimum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmin;
//! Maximum temperature for valid species standard state thermo props
/*!
* This is the maximum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmax;
//! Reference state pressure
/*!
* Value of the reference state pressure in Pascals.
* All species must have the same reference state pressure.
*/
doublereal m_p0;
//! last value of the temperature processed by reference state
mutable doublereal m_tlast;
//! Temporary storage for dimensionless reference state enthalpies
mutable array_fp m_h0_RT;
//! Temporary storage for dimensionless reference state heat capacities
mutable array_fp m_cp0_R;
//! Temporary storage for dimensionless reference state gibbs energies
mutable array_fp m_g0_RT;
//! Temporary storage for dimensionless reference state entropies
mutable array_fp m_s0_R;
//! currently unsed
/*!
* @deprecated
*/
mutable array_fp m_expg0_RT;
//! Currently unused
/*
* @deprecated
*/
mutable array_fp m_pe;
//! Temporary array containing internally calculated partial pressures
mutable array_fp m_pp;
//! Current pressure (Pa)
doublereal m_press;
private:
//! Function to update the reference state thermo functions
void _updateThermo() const;
};
}
#endif

View file

@ -0,0 +1,490 @@
/**
* @file Constituents.cpp
* Header file Class \link Cantera::Constituents Constitutents\endlink which
* manages a set of elements and species (see \ref phases).
*/
/* $Author$
* $Date$
* $Revision$
*
*/
// Copyright 2001 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "Constituents.h"
#include "Elements.h"
using namespace std;
namespace Cantera {
/*
* Constructor sets all base variable types to zero. Also, it
* sets the pointer to the Elements object for this object to the
* default value of BaseElements. If the BaseElements Elements
* object doesn't exist, it creates it.
*
* Input
* --------
* ptr_Elements: If the Constituents object requires a different
* Elements object than the default one, input
* address here. This argument defaults to null,
* in which case the default Elements Object is
* chosen.
*/
/*
* DGG: I have reversed the role of ptr_Elements. In this version,
* the default is that a new Elements object is created, so this
* Constituents object is independent of any other object. But if
* ptr_Elements is supplied, it will be used. This way, a class
* implementing a multi-phase mixture is responsible for
* maintaining the global elements list for the mixture, and no
* static global element list is required.
*/
Constituents::Constituents(Elements* ptr_Elements) :
m_kk(0),
m_speciesFrozen(false) ,
m_Elements(ptr_Elements) {
if (!m_Elements) m_Elements = new Elements();
// Register subscription to Elements object whether or not we
// created it here.
m_Elements->subscribe();
}
/**
* Destructor for class Constituents.
*
* Some cleanup of of the Global_Elements_List array is
* effected by unsubscribing to m_Elements.
*/
Constituents::~Constituents()
{
int ileft = m_Elements->unsubscribe();
/*
* Here we may delete Elements Objects or not. Right now, we
* will delete them. We also delete the global pointer entry
* to keep everything consistent.
*/
if (ileft <= 0) {
vector<Elements *>::iterator it;
for (it = Elements::Global_Elements_List.begin();
it != Elements::Global_Elements_List.end(); ++it) {
if (*it == m_Elements) {
Elements::Global_Elements_List.erase(it);
break;
}
}
delete m_Elements;
}
}
int Constituents::nElements() const { return m_Elements->nElements(); }
/**
* Return the Atomic weight of element m.
* units = Kg / Kmol
*/
doublereal Constituents::atomicWeight(int m) const {
return m_Elements->atomicWeight(m);
}
/**
* returns a reference to the vector of atomic weights pertinent
* to this constituents object
* units = kg / Kmol
*/
const vector_fp& Constituents::atomicWeights() const {
return m_Elements->atomicWeights();
}
/**
* Return the atomic number of element m.
*/
int Constituents::atomicNumber(int m) const {
return m_Elements->atomicNumber(m);
}
/**
* Add an element to the set.
* @param symbol symbol string
* @param weight atomic weight in kg/mol.
*
* If weight is not given, then a lookup is performed in the
* element object
*
*/
void Constituents::
addElement(const std::string& symbol, doublereal weight)
{
m_Elements->addElement(symbol, weight);
}
void Constituents::
addElement(const XML_Node& e)
{
m_Elements->addElement(e);
}
/*
* Add a unique element to the set. A check on the symbol is made
* If the symbol is already an element, then a new element is
* not created.
*
* @param symbol symbol string
* @param weight atomic weight in kg/mol.
*
* If weight is not given, then a lookup is performed in the
* element object
*
* -> Passthrough to the Element lvl.
*/
void Constituents::
addUniqueElement(const std::string& symbol, doublereal weight)
{
m_Elements->addUniqueElement(symbol, weight);
}
void Constituents::
addUniqueElement(const XML_Node& e)
{
m_Elements->addUniqueElement(e);
}
void Constituents::addElementsFromXML(const XML_Node& phase) {
m_Elements->addElementsFromXML(phase);
}
/*
* -> Passthrough to the Element lvl.
*/
void Constituents::freezeElements() {
m_Elements->freezeElements();
}
/*
* -> Passthrough to the Element lvl.
*/
bool Constituents::elementsFrozen() {
return m_Elements->elementsFrozen();
}
/*
* Index of element named \a name. The index is an integer
* assigned to each element in the order it was added,
* beginning with 0 for the first element. If \a name is not
* the name of an element in the set, then the value -1 is
* returned.
*
*
* -> Passthrough to the Element class.
*/
int Constituents::elementIndex(std::string name) const {
return (m_Elements->elementIndex(name));
}
/*
* Name of the element with index m.
*
* This is a passthrough routine to the Element object.
* @param m @{ Element index. @}
* \exception If m < 0 or m >= nElements(), the
* exception, ElementRangeError, is thrown.
*/
string Constituents::elementName(int m) const {
return (m_Elements->elementName(m));
}
/*******************************************************************
*
* elementNames():
*
* Returns a read-only reference to the vector of element names.
* @code
* Constituents c;
* ...
* const vector<string>& enames = c.elementNames();
* int n = enames.size();
* for (int i = 0; i < n; i++) cout << enames[i] << endl;
* @endcode
*
*
* -> Passthrough to the Element lvl.
*/
const vector<string>& Constituents::elementNames() const {
return m_Elements->elementNames();
}
/**********************************************************************
*
* molecularWeight()
*
* Returns the molecular weight of a species given the species index
*
* units = kg / kmol.
*/
doublereal Constituents::molecularWeight(int k) const {
if (k < 0 || k >= nSpecies()) {
throw SpeciesRangeError("Constituents::molecularWeight",
k, nSpecies());
}
return m_weight[k];
}
/**********************************************************************
*
* molecularWeights()
*
* Returns a const reference to the vector of molecular weights
* for all of the species defined in the object.
*
* units = kg / kmol.
*/
const array_fp& Constituents::molecularWeights() const {
return m_weight;
}
/**********************************************************************
*
* charge():
*
* Electrical charge of one species k molecule, divided by
* \f$ e = 1.602 \times 10^{-19}\f$ Coulombs.
*/
doublereal Constituents::charge(int k) const {
return m_speciesCharge[k];
}
/*
*
* addSpecies()
*
* Add a species to a Constituents object. Note, no check is made
* as to whether the species has a unique name.
*
* Input
* ---------
* name = string containing the name
* comp[]
* charge =
* weight = weight of the species. Default = 0.0.
* Note, the weight is a bit redundent and potentially
* harmful. If weight is less than or equal to zero,
* the weight is calculated from the element composition
* and it need not be supplied on the command line.
*/
void Constituents::
addSpecies(const std::string& name, const doublereal* comp,
doublereal charge, doublereal size) {
m_Elements->freezeElements();
m_speciesNames.push_back(name);
m_speciesCharge.push_back(charge);
m_speciesSize.push_back(size);
double wt = 0.0;
int m_mm = m_Elements->nElements();
const vector_fp &aw = m_Elements->atomicWeights();
for (int m = 0; m < m_mm; m++) {
m_speciesComp.push_back(comp[m]);
wt += comp[m] * aw[m];
}
m_weight.push_back(wt);
m_kk++;
}
/*
*
* addUniqueSpecies():
*
* Add a species to a Constituents object. This routine will
* first check to see if the species is already part of the
* phase. It does this via a string comparison with the
* existing species in the phase.
*/
void Constituents::
addUniqueSpecies(const std::string& name, const doublereal* comp,
doublereal charge, doublereal size) {
vector<string>::const_iterator it = m_speciesNames.begin();
for (int k = 0; k < m_kk; k++) {
if (*it == name) {
/*
* We have found a match. At this point we could do some
* compatibility checks. However, let's just return for the
* moment without specifying any error.
*/
int m_mm = m_Elements->nElements();
for (int i = 0; i < m_mm; i++) {
if (comp[i] != m_speciesComp[m_kk * m_mm + i]) {
throw CanteraError("addUniqueSpecies",
"Duplicate species have different "
"compositions: " + *it);
}
}
if (charge != m_speciesCharge[m_kk]) {
throw CanteraError("addUniqueSpecies",
"Duplicate species have different "
"charges: " + *it);
}
if (size != m_speciesSize[m_kk]) {
throw CanteraError("addUniqueSpecies",
"Duplicate species have different "
"sizes: " + *it);
}
return;
}
++it;
}
addSpecies(name, comp, charge, size);
}
/*
*
* freezeSpecies()
* Set the boolean indicating that we are no longer allowing
* species to be added to the Constituents class object.
*/
void Constituents::freezeSpecies() {
m_speciesFrozen = true;
}
/*
*
* speciesIndex()
*
* Index of species named \c name. The first species added
* will have index 0, and the last one index nSpecies() - 1.
*
* Note, the [] operator shouldn't be used for map's because it
* creates new entries. Here, we use find() to look up entries.
*
* If name isn't in the list, then a -1 is returned.
*/
int Constituents::speciesIndex(std::string name) const {
vector<string>::const_iterator it = m_speciesNames.begin();
for (int k = 0; k < m_kk; k++) {
if (*it == name) {
/*
* We have found a match.
*/
return k;
}
++it;
}
return -1;
}
/*
*
* speciesName()
*
* Name of the species with index k
*/
string Constituents::speciesName(int k) const {
if (k < 0 || k >= nSpecies())
throw SpeciesRangeError("Constituents::speciesName",
k, nSpecies());
return m_speciesNames[k];
}
/*
*
* speciesNames()
*
* Return a const reference to the vector of species names
*/
const vector<string>& Constituents::speciesNames() const {
return m_speciesNames;
}
/*
*
* ready():
* True if both elements and species have been frozen
*/
bool Constituents::ready() const {
return (m_Elements->elementsFrozen() && m_speciesFrozen);
}
/*
* Returns the number of atoms of element \c m in species \c k.
*/
doublereal Constituents::nAtoms(int k, int m) const
{
const int m_mm = m_Elements->nElements();
if (m < 0 || m >=m_mm)
throw ElementRangeError("Constituents::nAtoms",m,nElements());
if (k < 0 || k >= nSpecies())
throw SpeciesRangeError("Constituents::nAtoms",k,nSpecies());
return m_speciesComp[m_mm * k + m];
}
/*
*
* getAtoms()
*
* Get a vector containing the atomic composition
* of species k
*/
void Constituents::getAtoms(int k, double *atomArray) const
{
const int m_mm = m_Elements->nElements();
for (int m = 0; m < m_mm; m++) {
atomArray[m] = (double) m_speciesComp[m_mm * k + m];
}
}
/**
* This copy constructor just calls the assignment operator
* for this class.
* The assignment operator does a deep copy.
*/
Constituents::Constituents(const Constituents& right) {
*this = right;
}
/**
* Assignment operator for the Constituents class.
* Right now we pretty much do a straight uncomplicated
* copy of all of the protected data.
*/
Constituents& Constituents::operator=(const Constituents& right) {
/*
* Check for self assignment.
*/
if (this == &right) return *this;
/*
* We do a straight assignment operator on all of the
* data. The vectors are copied.
*/
m_kk = right.m_kk;
m_weight = right.m_weight;
m_speciesFrozen = right.m_speciesFrozen;
if (m_Elements) {
m_Elements->unsubscribe();
}
m_Elements = right.m_Elements;
if (m_Elements) {
m_Elements->subscribe();
}
m_speciesNames = right.m_speciesNames;
m_speciesComp = right.m_speciesComp;
m_speciesCharge = right.m_speciesCharge;
m_speciesSize = right.m_speciesSize;
/*
* Return the reference to the current object
*/
return *this;
}
}

392
Cantera/src/thermo/Constituents.h Executable file
View file

@ -0,0 +1,392 @@
/**
* @file Constituents.h
* Header file Class \link Cantera::Constituents Constitutents\endlink which
* manages a set of elements and species (see \ref phases).
*/
/* $Author$
* $Date$
* $Revision$
*
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_CONSTIT_H
#define CT_CONSTIT_H
#include "ct_defs.h"
//using namespace std;
#include "SpeciesThermo.h"
#include "ctexceptions.h"
#include "stringUtils.h"
#include "xml.h"
namespace Cantera {
class Elements;
/************** DEFINITIONS OF ERRORS *****************************/
//! Specific fatal error indicating that the index of a species is out of range.
/*!
*
* @ingroup errorhandling
*/
class SpeciesRangeError : public CanteraError {
public:
//! Constructor
/*!
* @param func Function where the error occurred.
* @param k current species index value
* @param kmax Maximum permissible species index value. The
* minimum permissible species index value is assumed to be 0
*
*/
SpeciesRangeError(std::string func, int k, int kmax) :
CanteraError(func, "Species index " + int2str(k) +
" outside valid range of 0 to " + int2str(kmax-1)) {}
};
/******************************************************************/
//! Class %Constituents manages a set of elements and species.
/*!
* Class %Constituents is designed to provide information
* about the elements and species in a phase - names, index
* numbers (location in arrays), atomic or molecular weights,
* etc. No computations are performed by the methods of this
* class. The set of elements must include all those that compose
* the species, but may include additional elements. The species
* all must belong to the same phase.
*
* @ingroup phases
*/
class Constituents {
public:
//! Constructor.
/*!
* Constructor sets all base variable types to zero. Also, it
* sets the pointer to the Elements object for this object.
*
* @param ptr_Elements
* The default is that a new Elements object is created, so this
* Constituents object is independent of any other object. But if
* ptr_Elements is supplied, it will be used. This way, a class
* implementing a multi-phase mixture is responsible for
* maintaining the global elements list for the mixture, and no
* static global element list is required.
*/
Constituents(Elements* ptr_Elements = 0);
/// Destructor.
~Constituents();
/// This copy constructor just calls the assignment operator
/// for this class.
/*!
* @param right reference to the object to be copied.
*/
Constituents(const Constituents& right);
/// Assignment operator
/*!
* @param right Reference to the object to be copied.
*/
Constituents& operator=(const Constituents& right);
/// @name Element Information
// @{
/// Name of the element with index m.
/// This is a passthrough routine to the Element object.
/// \param m Element index.
/// \exception If m < 0 or m >= nElements(), the
/// exception, ElementRangeError, is thrown.
std::string elementName(int m) const;
/// Index of element named 'name'.
/// The index is an integer
/// assigned to each element in the order it was added,
/// beginning with 0 for the first element.
/// @param name name of the element
///
/// If 'name' is not
/// the name of an element in the set, then the value -1 is
/// returned.
int elementIndex(std::string name) const;
/// Atomic weight of element m.
/*!
* @param m Element index
*/
doublereal atomicWeight(int m) const;
/// Atomic number of element m.
/*!
* @param m Element index
*/
int atomicNumber(int m) const;
/// Return a read-only reference to the vector of element names.
const std::vector<std::string>& elementNames() const;
/// Return a read-only reference to the vector of atomic weights.
const vector_fp& atomicWeights() const;
/// Number of elements.
int nElements() const;
// @}
/// @name Adding Elements and Species
/// These methods are used to add new elements or species.
/// These are not usually called by user programs.
///
/// Since species are checked to insure that they are only
/// composed of declared elements, it is necessary to first
/// add all elements before adding any species.
//@{
//! Add an element.
/*!
* @param symbol Atomic symbol std::string.
* @param weight Atomic mass in amu.
*/
void addElement(const std::string& symbol, doublereal weight);
//! Add an element from an XML specification.
/*!
* @param e Reference to the XML_Node where the element is described.
*/
void addElement(const XML_Node& e);
//! Adde an element, checking for uniqueness
/*!
* The uniqueness is checked by comparing the string symbol. If
* not unique, nothing is done.
*
* @param symbol String symbol of the element
* @param weight Atomic weight of the element (kg kmol-1).
*/
void addUniqueElement(const std::string& symbol, doublereal weight);
//! Adde an element, checking for uniqueness
/*!
* The uniqueness is checked by comparing the string symbol. If
* not unique, nothing is done.
*
* @param e Reference to the XML_Node where the element is described.
*/
void addUniqueElement(const XML_Node& e);
//! Add all elements referenced in an XML_Node tree
/*!
* @param phase Reference to the top XML_Node of a phase
*/
void addElementsFromXML(const XML_Node& phase);
/// Prohibit addition of more elements, and prepare to add species.
void freezeElements();
/// True if freezeElements has been called.
bool elementsFrozen();
//@}
/// Returns the number of species in the phase
int nSpecies() const { return m_kk; }
//! Molecular weight of species \c k.
/*!
* @param k index of species \c k
* @return
* Returns the molecular weight of species \c k.
*/
doublereal molecularWeight(int k) const;
//! Return the Molar mass of species \c k
/*!
* Preferred name for molecular weight.
*
* @param k index for species
* @return
* Return the molar mass of species k kg/kmol.
*/
doublereal molarMass(int k) const {
return molecularWeight(k);
}
/**
* Return a const reference to the vector of molecular weights
* of the species
*/
const vector_fp& molecularWeights() const;
/*!
* Electrical charge of one species k molecule, divided by
* the magnitude of the electron charge ( \f$ e = 1.602
* \times 10^{-19}\f$ Coulombs). Dimensionless.
*
* @param k species index
*/
doublereal charge(int k) const;
/**
* @name Adding Species
* These methods are used to add new species.
* They are not usually called by user programs.
*/
//@{
void addSpecies(const std::string& name, const doublereal* comp,
doublereal charge = 0.0, doublereal size = 1.0);
//! Add a species to the phase, checking for uniqueness of the name
/*!
* This routine checks for uniqueness of the string name. It only
* adds the species if it is unique.
*
* @param name String name of the species
* @param comp Double vector containing the elemental composition of the
* species.
* @param charge Charge of the species. Defaults to zero.
* @param size Size of the species (meters). Defaults to 1 meter.
*/
void addUniqueSpecies(const std::string& name, const doublereal* comp,
doublereal charge = 0.0,
doublereal size = 1.0);
//! Index of species named 'name'
/*!
* The first species added
* will have index 0, and the last one index nSpecies() - 1.
*
* @param name String name of the species
* @return
* Returns the index of the species.
*/
int speciesIndex(std::string name) const;
//! Name of the species with index k
/*!
* @param k index of the species
*/
std::string speciesName(int k) const;
/// Return a const referernce to the vector of species names
const std::vector<std::string>& speciesNames() const;
//! This routine returns the size of species k
/*!
* @param k index of the species
* @return
* Returns the size of the species. Units are meters.
*/
doublereal size(int k) const { return m_speciesSize[k]; }
/**
* Prohibit addition of more species, and prepare for
* calculations with this set of elements and species.
*/
void freezeSpecies();
/// True if freezeSpecies has been called.
bool speciesFrozen() { return m_speciesFrozen; }
/// Remove all elements and species
void clear();
//@}
/// True if both elements and species have been frozen
bool ready() const;
//! Number of atoms of element \c m in species \c k.
/*!
* @param k species index
* @param m element index
*/
doublereal nAtoms(int k, int m) const;
//! Get a vector containing the atomic composition of species k
/*!
* @param k species index
* @param atomArray vector containing the atomic number in the species.
* Length: m_mm
*/
void getAtoms(int k, double *atomArray) const;
protected:
//! Number of species in the phase.
int m_kk;
//! Vector of molecular weights of the species
/*!
* This vector has length m_kk.
* The units of the vector are kg kmol-1.
*/
vector_fp m_weight;
//! Boolean indicating whether the number of species has been frozen.
/*!
* During the construction of the phase, this is false. After
* construction of the the phase, this is true.
*/
bool m_speciesFrozen;
/*!
* Pointer to the element object corresponding to this
* phase. Normally, this will be the default Element object
* common to all phases.
*/
Elements * m_Elements;
//! Vector of the species names
std::vector<std::string> m_speciesNames;
//! Atomic composition of the species.
/*!
* the number of atoms of i in species k is equal to
* m_speciesComp[k * m_mm + i]
* The length of this vector is equal to m_kk * m_mm
*/
vector_fp m_speciesComp;
/**
* m_speciesCharge: Vector of species charges
* length = m_kk
*/
vector_fp m_speciesCharge;
/**
* m_speciesSize(): Vector of species sizes.
* length m_kk
* This is used in some equations of state
* which employ the constant partial molar
* volume approximation. It's so fundamental
* we've put it at the Constituents class level
*/
vector_fp m_speciesSize;
private:
};
} // namespace
#endif

View file

@ -0,0 +1,68 @@
/**
* @file Crystal.h
*
* $Author$
* $Date$
* $Revision$
*/
#ifndef CT_CRYSTAL_H
#define CT_CRYSTAL_H
#include "MultiPhase.h"
namespace Cantera {
/// A class for crystals. Each crystal consists of one or more
/// sublattices, each represented by an object of type
/// LatticePhase.
class Crystal : public MultiPhase {
public:
typedef LatticePhase lattice_t;
typedef vector<LatticePhase*> lattice_list;
/// Constructor. The constructor takes no arguments, since
/// phases are added using method addPhase.
Crystal() : MultiPhase() {}
/// Destructor. Does nothing. Class MultiPhase does not take
/// "ownership" (i.e. responsibility for destroying) the
/// phase objects.
virtual ~Crystal() {}
void addLattices(lattice_list& lattices,
const vector_fp& latticeSiteDensity);
/// Add a phase to the mixture.
/// @param p pointer to the phase object
/// @param moles total number of moles of all species in this phase
void addLattice(lattice_t* lattice, doublereal siteDensity) {
MultiPhase::addPhase(lattice, siteDensity);
}
/// Return a reference to phase n. The state of phase n is
/// also updated to match the state stored locally in the
/// mixture object.
lattice_t& lattice(index_t n) {
return *(lattice_t*)&phase(n);
}
protected:
};
inline std::ostream& operator<<(std::ostream& s, Cantera::Crystal& x) {
size_t ip;
for (ip = 0; ip < x.nPhases(); ip++) {
s << "*************** Lattice " << ip << " *****************" << endl;
s << "SiteDensity: " << x.phaseMoles(ip) << endl;
s << report(x.phase(ip)) << endl;
}
return s;
}
}
#endif

View file

@ -21,7 +21,8 @@
#endif
#include "DebyeHuckel.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "WaterProps.h"
#include "WaterPDSS.h"
#include <string.h>

View file

@ -0,0 +1,83 @@
/**
* @file EdgePhase.h
* Declarations for the EdgePhase ThermoPhase object, which models the interface
* between two surfaces (see \ref thermoprops and \link Cantera::EdgePhase EdgePhase\endlink).
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2002 California Institute of Technology
*
*/
#ifndef CT_EDGEPHASE_H
#define CT_EDGEPHASE_H
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SurfPhase.h"
namespace Cantera {
//! A thermodynamic %Phase representing a one dimensional edge between two surfaces
/*!
* This thermodynamic function is largely a wrapper around the SurfPhase
* thermodynamic object.
*
* All of the equations and formulations carry through from SurfPhase to this
* EdgePhase object.
* It should be noted however, that dimensional object with length dimensions,
* have their dimensions reduced by one.
*
* @ingroup thermoprops
*/
class EdgePhase : public SurfPhase {
public:
//! Constructor
/*!
* @param n0 Surface site density (kmol m-1).
*/
EdgePhase(doublereal n0 = 0.0);
//! Destructor
virtual ~EdgePhase() {}
//! returns the equation of state type
virtual int eosType() const { return cEdge; }
//! Set the Equation-of-State parameters by reading an XML Node Input
/*!
*
* The Equation-of-State data consists of one item, the site density.
*
* @param thermoData Reference to an XML_Node named thermo
* containing the equation-of-state data. The
* XML_Node is within the phase XML_Node describing
* the %EdgePhase object.
*
* An example of the contents of the thermoData XML_Node is provided
* below. The units attribute is used to supply the units of the
* site density in any convenient form. Internally it is changed
* into MKS form.
*
* @code
* <thermo model="Edge">
* <site_density units="mol/cm"> 3e-15 </site_density>
* </thermo>
* @endcode
*/
virtual void setParametersFromXML(const XML_Node& thermoData);
};
}
#endif

View file

@ -0,0 +1,601 @@
/**
* @file Elements.cpp
* Declaration file for class, Elements, which contains the elements that
* make up species (see \ref phases and \link Cantera::Elements Elements\endlink).
*
* This file contains the definitions for functions in the class Elements.
* It also contains a database of atomic weights.
*/
/****************************************************************************
* $RCSfile$
* $Author$
* $Date$
* $Revision$
*
*
****************************************************************************/
// Copyright 2003 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "Elements.h"
#include "xml.h"
#include "ctml.h"
#include "ctexceptions.h"
using namespace ctml;
using namespace std;
#ifdef USE_DGG_CODE
#include <map>
#endif
namespace Cantera {
/* awData structure */
/**
* Database for atomic molecular weights
*
* Values are taken from the 1989 Standard Atomic Weights, CRC
*
* awTable[] is a static function with scope limited to this file.
* It can only be referenced via the static Elements class function,
* LookupWtElements().
*
* units = kg / kg-mol (or equivalently gm / gm-mol)
*
* (note: this structure was picked because it's simple, compact,
* and extensible).
*
*/
struct awData {
char name[4]; ///< Null Terminated name, First letter capitalized
double atomicWeight; ///< atomic weight in kg / kg-mol
};
/*!
* @var static struct awData aWTable[]
* \brief aWTable is a vector containing the atomic weights database.
*
* The size of the table is given by the initial instantiation.
*/
static struct awData aWTable[] = {
{"H", 1.00794},
{"D", 2.0 },
{"Tr", 3.0 },
{"He", 4.002602},
{"Li", 6.941 },
{"Be", 9.012182},
{"B", 10.811 },
{"C", 12.011 },
{"N", 14.00674},
{"O", 15.9994 },
{"F", 18.9984032},
{"Ne", 20.1797 },
{"Na", 22.98977},
{"Mg", 24.3050 },
{"Al", 26.98154},
{"Si", 28.0855 },
{"P", 30.97376},
{"S", 32.066 },
{"Cl", 35.4527 },
{"Ar", 39.948 },
{"K", 39.0983 },
{"Ca", 40.078 },
{"Sc", 44.95591},
{"Ti", 47.88 },
{"V", 50.9415 },
{"Cr", 51.9961 },
{"Mn", 54.9381 },
{"Fe", 55.847 },
{"Co", 58.9332 },
{"Ni", 58.69 },
{"Cu", 63.546 },
{"Zn", 65.39 },
{"Ga", 69.723 },
{"Ge", 72.61 },
{"As", 74.92159},
{"Se", 78.96 },
{"Br", 79.904 },
{"Kr", 83.80 },
{"Rb", 85.4678 },
{"Sr", 87.62 },
{"Y", 88.90585},
{"Zr", 91.224 },
{"Nb", 92.90638},
{"Mo", 95.94 },
{"Tc", 97.9072 },
{"Ru", 101.07 },
{"Rh", 102.9055 },
{"Pd", 106.42 },
{"Ag", 107.8682 },
{"Cd", 112.411 },
{"In", 114.82 },
{"Sn", 118.710 },
{"Sb", 121.75 },
{"Te", 127.6 },
{"I", 126.90447},
{"Xe", 131.29 },
{"Cs", 132.90543},
{"Ba", 137.327 },
{"La", 138.9055 },
{"Ce", 140.115 },
{"Pr", 140.90765},
{"Nd", 144.24 },
{"Pm", 144.9127 },
{"Sm", 150.36 },
{"Eu", 151.965 },
{"Gd", 157.25 },
{"Tb", 158.92534},
{"Dy", 162.50 },
{"Ho", 164.93032},
{"Er", 167.26 },
{"Tm", 168.93421},
{"Yb", 173.04 },
{"Lu", 174.967 },
{"Hf", 178.49 },
{"Ta", 180.9479 },
{"W", 183.85 },
{"Re", 186.207 },
{"Os", 190.2 },
{"Ir", 192.22 },
{"Pt", 195.08 },
{"Au", 196.96654},
{"Hg", 200.59 },
{"Ti", 204.3833 },
{"Pb", 207.2 },
{"Bi", 208.98037},
{"Po", 208.9824 },
{"At", 209.9871 },
{"Rn", 222.0176 },
{"Fr", 223.0197 },
{"Ra", 226.0254 },
{"Ac", 227.0279 },
{"Th", 232.0381 },
{"Pa", 231.03588},
{"U", 238.0508 },
{"Np", 237.0482 },
{"Pu", 244.0482 }
};
//! Static function to look up an atomic weight
/*!
*
* This static function looks up the argument string in the
* database above and returns the associated molecular weight.
* The data are from the periodic table.
*
* Note: The idea behind this function is to provide a unified
* source for the element atomic weights. This helps to
* ensure that mass is conserved.
*
* @param
* ElemName String. Only the first 3 characters are significant
*
* @return
* Return value contains the atomic weight of the element
* If a match for the string is not found, a value of -1.0 is
* returned.
*
* @exception CanteraError
* If a match is not found, a CanteraError is thrown as well
*/
double Elements::LookupWtElements(const std::string& s) {
int num = sizeof(aWTable) / sizeof(struct awData);
string s3 = s.substr(0,3);
for (int i = 0; i < num; i++) {
//if (!std::strncmp(s.c_str(), aWTable[i].name, 3)) {
if (s3 == aWTable[i].name) {
return (aWTable[i].atomicWeight);
}
}
throw CanteraError("LookupWtElements", "element not found");
return -1.0;
}
//! Exception class to indicate a fixed set of elements.
/*!
* This class is used to warn the user when the number of elements
* are changed after at least one species is defined.
*/
class ElementsFrozen : public CanteraError {
public:
//! Constructor for class
/*!
* @param func Function where the error occurred.
*/
ElementsFrozen(string func)
: CanteraError(func,
"elements cannot be added after species.") {}
};
/*
* Elements Class Constructor
* We initialize all internal variables to zero here.
*/
Elements::Elements() :
m_mm(0),
m_elementsFrozen(false),
numSubscribers(0)
{
}
/*
* Elements Class Destructor
* If the number of subscribers is not zero, through an error.
* A logic problem has occurred.
*
* @exception CanteraError
*/
Elements::~Elements()
{
if (numSubscribers != 0) {
throw CanteraError("~Elements", "numSubscribers not zero");
}
}
/*
* freezeElements():
*
* Set the freeze flag. This is a prerequesite to other
* activivities, i.e., this is done before species are defined.
*/
void Elements::freezeElements() {
m_elementsFrozen = true;
}
#ifdef INCL_DEPRECATED_METHODS
/*
*
* Returns an ElementData struct that contains the parameters
* for element index m.
*/
ElementData Elements::element(int m) const {
ElementData e;
e.name = m_elementNames[m];
e.atomicWeight = m_atomicWeights[m];
return e;
}
#endif
/*
* elementIndex():
*
* Index of element named \c name. The index is an integer
* assigned to each element in the order it was added,
* beginning with 0 for the first element. If \c name is not
* the name of an element in the set, then the value -1 is
* returned.
*
*/
#ifdef USE_DGG_CODE
int Elements::elementIndex(std::string name) const{
map<string, int>::const_iterator it;
it = m_definedElements.find(name);
if (it != m_definedElements.end()) {
return it->second;
}
return -1;
}
#else
int Elements::elementIndex(std::string name) const {
for (int i = 0; i < m_mm; i++) {
if (m_elementNames[i] == name) return i;
}
return -1;
}
#endif
/*
*
* Name of the element with index \c m. @param m Element
* index. If m < 0 or m >= nElements() an exception is thrown.
*/
string Elements::elementName(int m) const {
if (m >= 0 && m < nElements())
return m_elementNames[m];
else
throw ElementRangeError("Elements::elementName",m,nElements());
}
/*
*
* Add an element to the current set of elements in the current object.
* @param symbol symbol string
* @param weight atomic weight in kg/kmol.
*
* The default weight is a special value, which will cause the
* routine to look up the actual weight via a string lookup.
*
* There are two interfaces to this routine. The XML interface
* looks up the required parameters for the regular interface
* and then calls the base routine.
*/
void Elements::
addElement(const std::string& symbol, doublereal weight)
{
if (weight == -12345.0) {
weight = LookupWtElements(symbol);
if (weight < 0.0) {
throw ElementsFrozen("addElement");
}
}
if (m_elementsFrozen) {
throw ElementsFrozen("addElement");
return;
}
m_atomicWeights.push_back(weight);
m_elementNames.push_back(symbol);
#ifdef USE_DGG_CODE
m_definedElements[symbol] = nElements() + 1;
#endif
m_mm++;
}
void Elements::
addElement(const XML_Node& e) {
doublereal weight = atof(e["atomicWt"].c_str());
string symbol = e["name"];
addElement(symbol, weight);
}
/*
* addUniqueElement():
*
* Add a unique element to the set. This routine will not allow
* duplicate elements to be input.
*
* @param symbol symbol string
* @param weight atomic weight in kg/kmol.
*
*
* The default weight is a special value, which will cause the
* routine to look up the actual weight via a string lookup.
*/
#ifdef USE_DGG_CODE
void Elements::
addUniqueElement(const std::string& symbol, doublereal weight, int atomicNumber)
{
if (m_elementsFrozen)
throw ElementsFrozen("addElement");
if (weight == -12345.0) {
weight = LookupWtElements(symbol);
}
/*
* First decide if this element has been previously added.
* If it unique, add it to the list.
*/
int i = m_definedElements[symbol] - 1;
if (i < 0) {
m_atomicWeights.push_back(weight);
m_elementNames.push_back(symbol);
m_atomicNumbers.push_back(atomicNumber);
m_mm++;
}
else {
if (m_atomicWeights[i] != weight) {
throw CanteraError("AddUniqueElement",
"Duplicate Elements (" + symbol +
") have different weights");
}
}
}
#else
void Elements::
addUniqueElement(const std::string& symbol,
doublereal weight, int atomicNumber)
{
if (weight == -12345.0) {
weight = LookupWtElements(symbol);
if (weight < 0.0) {
throw ElementsFrozen("addElement");
}
}
/*
* First decide if this element has been previously added
* by conducting a string search. If it unique, add it to
* the list.
*/
int ifound = 0;
int i = 0;
for (vector<string>::const_iterator it = m_elementNames.begin();
it < m_elementNames.end(); ++it, ++i) {
if (*it == symbol) {
ifound = 1;
break;
}
}
if (!ifound) {
if (m_elementsFrozen) {
throw ElementsFrozen("addElement");
return;
}
m_atomicWeights.push_back(weight);
m_elementNames.push_back(symbol);
m_atomicNumbers.push_back(atomicNumber);
m_mm++;
} else {
if (m_atomicWeights[i] != weight) {
throw CanteraError("AddUniqueElement",
"Duplicate Elements (" + symbol +
") have different weights");
}
}
}
#endif
/*
* @todo call addUniqueElement(symbol, weight) instead of
* addElement.
*/
void Elements::
addUniqueElement(const XML_Node& e) {
doublereal weight = 0.0;
if (e.hasAttrib("atomicWt"))
weight = atof(stripws(e["atomicWt"]).c_str());
int anum = 0;
if (e.hasAttrib("atomicNumber"))
anum = atoi(stripws(e["atomicNumber"]).c_str());
string symbol = e["name"];
if (weight != 0.0)
addUniqueElement(symbol, weight, anum);
else
addUniqueElement(symbol);
}
/*
* clear()
*
* Remove all elements from the structure.
*/
void Elements::clear() {
m_mm = 0;
m_atomicWeights.resize(0);
m_elementNames.resize(0);
m_elementsFrozen = false;
}
/*
* ready():
*
* True if the elements have been frozen
*/
bool Elements::ready() const {
return (m_elementsFrozen);
}
/*
* Elements(const Elements&) - copy constructor:
*
* This copy constructor just calls the assignment operator for this
* class.
*/
Elements::Elements(const Elements& right)
{
*this = right;
/*
* Set the number of subscribers to zero during a copy constructor
*/
numSubscribers = 0;
}
/*
* Elements& Elements::operator=(const Elements& right):
*
* (assignment operator)
*
* This is the assignment operator for the Elements class.
* Right now we pretty much do a straight uncomplicated
* assignment. However, subscribers are not mucked with, as they
* have to do with the address of the object to be subscribed to
*/
Elements& Elements::operator=(const Elements& right)
{
/*
* Check for self assignment.
*/
if (this == &right) return *this;
/*
* We do a straight assignment operator on all of the
* data. The vectors are copied.
*/
m_mm = right.m_mm;
m_elementsFrozen = right.m_elementsFrozen;
m_atomicWeights = right.m_atomicWeights;
m_elementNames = right.m_elementNames;
/*
* We must not muck with the number of subscribers to this object
* during a straight assignment. This number was set in the
* constructor operation.
*/
/*
* Return the reference to the current object
*/
return *this;
}
void Elements::addElementsFromXML(const XML_Node& phase) {
// get the declared element names
XML_Node& elements = phase.child("elementArray");
vector<string> enames;
getStringArray(elements, enames);
// // element database defaults to elements.xml
string element_database = "elements.xml";
if (elements.hasAttrib("datasrc"))
element_database = elements["datasrc"];
XML_Node* doc = get_XML_File(element_database);
XML_Node* dbe = &doc->child("ctml/elementData");
XML_Node& root = phase.root();
XML_Node* local_db = 0;
if (root.hasChild("ctml")) {
if (root.child("ctml").hasChild("elementData")) {
local_db = &root.child("ctml/elementData");
}
}
int nel = static_cast<int>(enames.size());
int i;
string enm;
XML_Node* e = 0;
for (i = 0; i < nel; i++) {
e = 0;
if (local_db) {
//writelog("looking in local database.");
e = local_db->findByAttr("name",enames[i]);
//if (!e) writelog(enames[i]+" not found.");
}
if (!e)
e = dbe->findByAttr("name",enames[i]);
if (e) {
addUniqueElement(*e);
}
else {
throw CanteraError("addElementsFromXML","no data for element "
+enames[i]);
}
}
}
/*
* subscribe(), unsubscribe(), and reportSubscriptions():
*
* Handles setting and reporting the number of subscriptions to this
* object.
*/
void Elements::subscribe() {
++numSubscribers;
}
int Elements::unsubscribe() {
--numSubscribers;
return numSubscribers;
}
int Elements::reportSubscriptions() const {
return numSubscribers;
}
/********************* GLOBAL STATIC SECTION **************************/
/*
* We keep track of a vector of pointers to element objects.
* Initially there are no Elements objects. Whenever one is created,
* the pointer to that object is added onto this list.
*/
vector<Elements *> Elements::Global_Elements_List;
/***********************************************************************/
}

View file

@ -0,0 +1,266 @@
/**
* @file Elements.h
* Header file for class, Elements, which contains the elements that
* make up species (see \ref phases and \link Cantera::Elements Elements\endlink).
*
* This file contains the declarations for the elements class.
*/
/***********************************************************************
* $RCSfile$
* $Author$
* $Date$
* $Revision$
***********************************************************************/
// Copyright 2001 California Institute of Technology
#ifndef CT_ELEMENTS_H
#define CT_ELEMENTS_H
#undef USE_DGG_CODE
#include "ct_defs.h"
//#include "ctexceptions.h"
namespace Cantera {
class XML_Node;
class ElementRangeError;
//! Object containing the elements that make up species in a phase.
/*!
* Class %Elements manages the elements that are part of a
* chemistry specification. This class may support calculations
* employing Multiple phases. In this case, a single Elements object may
* be shared by more than one Constituents class. Reactions between
* the phases may then be described using stoichiometry base on the
* same Elements class object.
*
* The member functions return information about the elements described
* in a particular instantiation of the class.
*
* @ingroup phases
*/
class Elements {
public:
/// Default constructor for the elements class
Elements();
//! Default destructor for the elements class
~Elements();
//! Function to lookup the atomic weight of an element
/*!
* @param ename Element symbol name.
*/
static double LookupWtElements(const std::string &ename);
/// Atomic weight of element m.
/*!
* @param m element index
*/
doublereal atomicWeight(int m) const { return m_atomicWeights[m]; }
/// Atomic number of element m.
/*!
* @param m element index
*/
int atomicNumber(int m) const { return m_atomicNumbers[m]; }
/// vector of element atomic weights
const vector_fp& atomicWeights() const { return m_atomicWeights; }
/**
* Inline function that returns the number of elements in the object.
*
* @return
* \c int: The number of elements in the object.
*/
int nElements() const { return m_mm; }
//! Function that returns the index of an element.
/*!
* Index of element named \c name. The index is an integer
* assigned to each element in the order it was added,
* beginning with 0 for the first element. If \c name is not
* the name of an element in the set, then the value -1 is
* returned.
*
* @param name String containing the index.
*/
int elementIndex(std::string name) const;
//! Name of the element with index \c m.
/*!
* @param m Element index. If m < 0 or m >= nElements() an exception is thrown.
*/
std::string elementName(int m) const;
//! Returns a string vector containing the element names
/*!
* Returns a read-only reference to the vector of element names.
* @return <tt> const vector<string>& </tt>: The vector contains
* the element names in their indexed order.
*/
const std::vector<std::string>& elementNames() const {
return m_elementNames;
}
//! Add an element to the current set of elements in the current object.
/*!
* The default weight is a special value, which will cause the
* routine to look up the actual weight via a string lookup.
*
* There are two interfaces to this routine. The XML interface
* looks up the required parameters for the regular interface
* and then calls the base routine.
*
* @param symbol string symbol for the element.
* @param weight Atomic weight of the element. If no argument
* is provided, a lookup is attempted.
*/
void addElement(const std::string& symbol,
doublereal weight = -12345.0);
//! Add an element to the current set of elements in the current object.
/*!
* @param e Reference to the XML_Node containing the element information
* The node name is the element symbol and the atomWt attribute
* is used as the atomic weight.
*/
void addElement(const XML_Node& e);
//! Add an element only if the element hasn't been added before.
/*!
* This is accomplished via a string match on symbol.
*
* @param symbol string symbol for the element.
* @param weight Atomic weight of the element. If no argument
* is provided, a lookup is attempted.
* @param atomicNumber defaults to 0
*/
void addUniqueElement(const std::string& symbol,
doublereal weight = -12345.0, int atomicNumber = 0);
//! Add an element to the current set of elements in the current object.
/*!
* @param e Reference to the XML_Node containing the element information
* The node name is the element symbol and the atomWt attribute
* is used as the atomic weight.
*/
void addUniqueElement(const XML_Node& e);
//! Add multiple elements from a XML_Node phase description
/*!
* @param phase XML_Node reference to a phase
*/
void addElementsFromXML(const XML_Node& phase);
//! Prohibit addition of more elements, and prepare to add species.
void freezeElements();
/// True if freezeElements has been called.
bool elementsFrozen() { return m_elementsFrozen; }
/// Remove all elements
void clear();
/// True if both elements and species have been frozen
bool ready() const;
//! copy constructor
/*!
* This copy constructor just calls the assignment operator for this
* class. It sets the number of subscribers to zer0.
*
* @param right Reference to the object to be copied.
*/
Elements(const Elements& right);
//! Assigntment operator
/*!
* This is the assignment operator for the Elements class.
* Right now we pretty much do a straight uncomplicated
* assignment. However, subscribers are not mucked with, as they
* have to do with the address of the object to be subscribed to
*
* @param right Reference to the object to be copied.
*/
Elements& operator=(const Elements& right);
//! subscribe to this object
/*!
* Increment by one the number of subscriptions to this object.
*/
void subscribe();
//! unsubscribe to this object
/*!
* decrement by one the number of subscriptions to this object.
*/
int unsubscribe();
//! report the number of subscriptions
int reportSubscriptions() const;
protected:
/******************************************************************/
/* Description of DATA in the Object */
/******************************************************************/
//! Number of elements.
int m_mm;
/* m_elementsFrozen: */
/** boolean indicating completion of object
*
* If this is true, then no elements may be added to the
* object.
*/
bool m_elementsFrozen;
/**
* Vector of element atomic weights:
*
* units = kg / kmol
*/
vector_fp m_atomicWeights;
/**
* Vector of element atomic numbers:
*
*/
vector_int m_atomicNumbers;
/** Vector of strings containing the names of the elements
*
* Note, a string search is the primary way to identify elements.
*/
std::vector<std::string> m_elementNames;
/**
* Number of Constituents Objects that use this object
*
* Number of Constituents Objects that require this Elements object
* to complete its definition.
* The destructor checks to see that this is equal to zero.
* when the element object is released.
*/
int numSubscribers;
/********* GLOBAL STATIC SECTION *************/
public:
/** Vector of pointers to Elements Objects
*
*/
static std::vector<Elements *> Global_Elements_List;
};
} // namespace
#endif

View file

@ -0,0 +1,243 @@
/**
* @file GeneralSpeciesThermo.cpp
* Declarations for a completely general species thermodynamic property
* manager for a phase (see \ref spthermo and
* \link Cantera::GeneralSpeciesThermo GeneralSpeciesThermo\endlink).
*/
/*
* $Id$
*/
// Copyright 2001-2004 California Institute of Technology
#include "GeneralSpeciesThermo.h"
#include "NasaPoly1.h"
#include "NasaPoly2.h"
#include "ShomatePoly.h"
#include "ConstCpPoly.h"
#include "Mu0Poly.h"
#include "SpeciesThermoFactory.h"
#include <iostream>
using namespace std;
namespace Cantera {
/*
* Constructors
*/
GeneralSpeciesThermo::GeneralSpeciesThermo() :
SpeciesThermo(),
m_tlow_max(0.0),
m_thigh_min(1.0E30),
m_p0(OneAtm),
m_kk(0)
{
m_tlow_max = 0.0;
m_thigh_min = 1.0E30;
}
GeneralSpeciesThermo::
GeneralSpeciesThermo(const GeneralSpeciesThermo &b) :
m_tlow_max(b.m_tlow_max),
m_thigh_min(b.m_thigh_min),
m_kk(b.m_kk) {
m_sp = b.m_sp;
}
const GeneralSpeciesThermo&
GeneralSpeciesThermo::operator=(const GeneralSpeciesThermo &b) {
if (&b != this) {
m_tlow_max = b.m_tlow_max;
m_thigh_min = b.m_thigh_min;
m_kk = b.m_kk;
m_sp = b.m_sp;
}
return *this;
}
GeneralSpeciesThermo::~GeneralSpeciesThermo() {
for (int k = 0; k < m_kk; k++) {
SpeciesThermoInterpType *sp = m_sp[k];
if (sp) {
delete sp;
m_sp[k] = 0;
}
}
}
SpeciesThermo *
GeneralSpeciesThermo::duplMyselfAsSpeciesThermo() const {
GeneralSpeciesThermo *gsth = new GeneralSpeciesThermo(*this);
return (SpeciesThermo *) gsth;
}
/*
* Install parameterization for a species.
* @param index Species index
* @param type parameterization type
* @param c coefficients. The meaning of these depends on
* the parameterization.
*/
void GeneralSpeciesThermo::install(std::string name,
int index,
int type,
const doublereal* c,
doublereal minTemp,
doublereal maxTemp,
doublereal refPressure) {
/*
* Resize the arrays if necessary, filling the empty
* slots with the zero pointer.
*/
if (index > m_kk - 1) {
m_sp.resize(index+1, 0);
m_kk = index+1;
}
/*
* Create the necessary object
*/
switch (type) {
case NASA1:
m_sp[index] = new NasaPoly1(index, minTemp, maxTemp,
refPressure, c);
break;
case SHOMATE1:
m_sp[index] = new ShomatePoly(index, minTemp, maxTemp,
refPressure, c);
break;
case CONSTANT_CP:
case SIMPLE:
m_sp[index] = new ConstCpPoly(index, minTemp, maxTemp,
refPressure, c);
break;
case MU0_INTERP:
m_sp[index] = new Mu0Poly(index, minTemp, maxTemp,
refPressure, c);
break;
case SHOMATE2:
m_sp[index] = new ShomatePoly2(index, minTemp, maxTemp,
refPressure, c);
break;
case NASA2:
m_sp[index] = new NasaPoly2(index, minTemp, maxTemp,
refPressure, c);
break;
default:
throw UnknownSpeciesThermoModel(
"GeneralSpeciesThermo::install",
"unknown species type", int2str(type));
break;
}
m_tlow_max = max(minTemp, m_tlow_max);
m_thigh_min = min(maxTemp, m_thigh_min);
}
/**
* Update the properties for one species.
*/
void GeneralSpeciesThermo::
update_one(int k, doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
SpeciesThermoInterpType * sp_ptr = m_sp[k];
sp_ptr->updatePropertiesTemp(t, cp_R, h_RT, s_R);
}
/**
* Update the properties for all species.
*/
void GeneralSpeciesThermo::
update(doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
vector<SpeciesThermoInterpType *>::const_iterator _begin, _end;
_begin = m_sp.begin();
_end = m_sp.end();
SpeciesThermoInterpType * sp_ptr;
for (; _begin != _end; ++_begin) {
sp_ptr = *(_begin);
sp_ptr->updatePropertiesTemp(t, cp_R, h_RT, s_R);
}
}
/**
* This utility function reports the type of parameterization
* used for the species, index.
*/
int GeneralSpeciesThermo::reportType(int index) const {
SpeciesThermoInterpType *sp = m_sp[index];
return sp->reportType();
}
/**
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
* For the NASA object, there are 15 coefficients.
*/
void GeneralSpeciesThermo::
reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
SpeciesThermoInterpType *sp = m_sp[index];
int n;
sp->reportParameters(n, type, minTemp, maxTemp,
refPressure, c);
if (n != index) {
throw CanteraError(" ", "confused");
}
}
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
void GeneralSpeciesThermo::
modifyParams(int index, doublereal *c) {
SpeciesThermoInterpType *sp = m_sp[index];
sp->modifyParameters(c);
}
/**
* Return the lowest temperature at which the thermodynamic
* parameterization is valid. If no argument is supplied, the
* value is the one for which all species parameterizations
* are valid. Otherwise, if an integer argument is given, the
* value applies only to the species with that index.
*/
doublereal GeneralSpeciesThermo::minTemp(int k) const {
if (k < 0)
return m_tlow_max;
else {
SpeciesThermoInterpType *sp = m_sp[k];
return sp->minTemp();
}
}
doublereal GeneralSpeciesThermo::maxTemp(int k) const {
if (k < 0) {
return m_thigh_min;
} else {
SpeciesThermoInterpType *sp = m_sp[k];
return sp->maxTemp();
}
}
doublereal GeneralSpeciesThermo::refPressure(int k) const {
if (k < 0) {
return m_p0;
} else {
SpeciesThermoInterpType *sp = m_sp[k];
return sp->refPressure();
}
}
}

View file

@ -0,0 +1,230 @@
/**
* @file GeneralSpeciesThermo.h
* Headers for a completely general species thermodynamic property
* manager for a phase (see \ref spthermo and
* \link Cantera::GeneralSpeciesThermo GeneralSpeciesThermo\endlink).
*
* Because it is general, it is slow.
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#ifndef CT_GENERALSPECIESTHERMO_H
#define CT_GENERALSPECIESTHERMO_H
#include <string>
#include "ct_defs.h"
#include "SpeciesThermoMgr.h"
#include "NasaPoly1.h"
#include "speciesThermoTypes.h"
//#include "polyfit.h"
namespace Cantera {
//! A species thermodynamic property manager for a phase.
/*!
* This is a general manager that can handle a wide variety
* of species thermodynamic polynomials for individual species.
* It is slow, however, because it recomputes the functions of
* temperature needed for each species. What it does is to create
* a vector of SpeciesThermoInterpType objects.
*
* @ingroup spthermo
*/
class GeneralSpeciesThermo : public SpeciesThermo {
public:
//! Constructor
GeneralSpeciesThermo();
//! Copy constructor
GeneralSpeciesThermo(const GeneralSpeciesThermo &);
//! Assignment operator
const GeneralSpeciesThermo & operator=(const GeneralSpeciesThermo &);
//! destructor
virtual ~GeneralSpeciesThermo();
//! Duplicator
virtual SpeciesThermo *duplMyselfAsSpeciesThermo() const ;
//! Install a new species thermodynamic property
//! parameterization for one species.
/*!
* Install a SpeciesThermoInterpType object for the species, index.
* This routine contains an internal list of SpeciesThermoInterpType
* objects that it knows about. A factory-type lookup is done
* to create the object.
*
* @param name Name of the species
* @param index The 'update' method will update the property
* values for this species
* at position i index in the property arrays.
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c vector of coefficients for the parameterization.
* This vector is simply passed through to the
* parameterization constructor. It's length depends upon
* the parameterization.
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
* @see speciesThermoTypes.h
*
* @todo Create a factory method for SpeciesThermoInterpType.
* That's basically what we are doing here.
*/
virtual void install(std::string name, int index, int type,
const doublereal* c,
doublereal minTemp, doublereal maxTemp,
doublereal refPressure);
//! Like update(), but only updates the single species k.
/*!
* @param k species index
* @param T Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update_one(int k, doublereal T, doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const;
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param T Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal T, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const;
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k=-1) const;
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k Species Index
*/
virtual doublereal maxTemp(int k=-1) const;
//! The reference-state pressure for species k.
/*!
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k Species Index
*/
virtual doublereal refPressure(int k = -1) const;
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param index Species index
*/
virtual int reportType(int index) const;
//! This utility function reports back the type of
//! parameterization and all of the parameters for the species, index.
/*!
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const;
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c);
protected:
/**
* This is the main unknown in the object. It is
* a list of pointers to type SpeciesThermoInterpType.
* Note, this object owns the objects, so they are deleted
* in the destructor of this object.
*/
std::vector<SpeciesThermoInterpType *> m_sp;
//! Maximum value of the lowest temperature
doublereal m_tlow_max;
//! Minimum value of the highest temperature
doublereal m_thigh_min;
//! reference pressure (Pa)
doublereal m_p0;
/**
* Internal variable indicating the length of the
* number of species in the phase.
*/
int m_kk;
private:
};
}
#endif

View file

@ -17,7 +17,8 @@
#endif
#include "HMWSoln.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "WaterProps.h"
#include "WaterPDSS.h"
#include <math.h>

View file

@ -11,7 +11,8 @@
*/
#include "HMWSoln.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "WaterProps.h"
#include "WaterPDSS.h"
#include <string.h>

View file

@ -17,8 +17,8 @@
#include "xml.h"
#include "ctml.h"
#include "IdealGasPDSS.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "ThermoPhase.h"

View file

@ -0,0 +1,408 @@
/**
*
* @file IdealGasPhase.cpp
* ThermoPhase object for the ideal gas equation of
* state - workhorse for %Cantera (see \ref thermoprops
* and class \link Cantera::IdealGasPhase IdealGasPhase\endlink).
*
*/
/*
* $Id$
*/
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "mix_defs.h"
#include "IdealGasPhase.h"
#include "SpeciesThermo.h"
using namespace std;
namespace Cantera {
// Empty Constructor
IdealGasPhase::IdealGasPhase():
m_mm(0),
m_tmin(0.0),
m_tmax(0.0),
m_p0(-1.0),
m_tlast(0.0),
m_logc0(0.0)
{
}
// Molar Thermodynamic Properties of the Solution ----------
// Mechanical Equation of State ----------------------------
// Chemical Potentials and Activities ----------------------
/*
* Returns the standard concentration \f$ C^0_k \f$, which is used to normalize
* the generalized concentration.
*/
doublereal IdealGasPhase::standardConcentration(int k) const {
double p = pressure();
return p/(GasConstant * temperature());
}
/*
* Returns the natural logarithm of the standard
* concentration of the kth species
*/
doublereal IdealGasPhase::logStandardConc(int k) const {
_updateThermo();
double p = pressure();
double lc = std::log (p / (GasConstant * temperature()));
return lc;
}
/*
* Get the array of non-dimensional activity coefficients
*/
void IdealGasPhase::getActivityCoefficients(doublereal *ac) const {
for (int k = 0; k < m_kk; k++) {
ac[k] = 1.0;
}
}
/*
* Get the array of chemical potentials at unit activity \f$
* \mu^0_k(T,P) \f$.
*/
void IdealGasPhase::getStandardChemPotentials(doublereal* muStar) const {
const array_fp& gibbsrt = gibbs_RT_ref();
scale(gibbsrt.begin(), gibbsrt.end(), muStar, _RT());
double tmp = log (pressure() /m_spthermo->refPressure());
tmp *= GasConstant * temperature();
for (int k = 0; k < m_kk; k++) {
muStar[k] += tmp; // add RT*ln(P/P_0)
}
}
// Partial Molar Properties of the Solution --------------
void IdealGasPhase::getChemPotentials(doublereal* mu) const {
getStandardChemPotentials(mu);
//doublereal logp = log(pressure()/m_spthermo->refPressure());
doublereal xx;
doublereal rt = temperature() * GasConstant;
//const array_fp& g_RT = gibbs_RT_ref();
for (int k = 0; k < m_kk; k++) {
xx = fmaxx(SmallNumber, moleFraction(k));
mu[k] += rt*(log(xx));
}
}
/*
* Get the array of partial molar enthalpies of the species
* units = J / kmol
*/
void IdealGasPhase::getPartialMolarEnthalpies(doublereal* hbar) const {
const array_fp& _h = enthalpy_RT_ref();
doublereal rt = GasConstant * temperature();
scale(_h.begin(), _h.end(), hbar, rt);
}
/*
* Get the array of partial molar entropies of the species
* units = J / kmol / K
*/
void IdealGasPhase::getPartialMolarEntropies(doublereal* sbar) const {
const array_fp& _s = entropy_R_ref();
doublereal r = GasConstant;
scale(_s.begin(), _s.end(), sbar, r);
doublereal logp = log(pressure()/m_spthermo->refPressure());
for (int k = 0; k < m_kk; k++) {
doublereal xx = fmaxx(SmallNumber, moleFraction(k));
sbar[k] += r * (- logp - log(xx));
}
}
/*
* Get the array of partial molar internal energies of the species
* units = J / kmol
*/
void IdealGasPhase::getPartialMolarIntEnergies(doublereal* ubar) const {
const array_fp& _h = enthalpy_RT_ref();
doublereal rt = GasConstant * temperature();
for (int k = 0; k < m_kk; k++) {
ubar[k] = rt * (_h[k] - 1.0);
}
}
/*
* Get the array of partial molar heat capacities
*/
void IdealGasPhase::getPartialMolarCp(doublereal* cpbar) const {
const array_fp& _cp = cp_R_ref();
scale(_cp.begin(), _cp.end(), cpbar, GasConstant);
}
/*
* Get the array of partial molar volumes
* units = m^3 / kmol
*/
void IdealGasPhase::getPartialMolarVolumes(doublereal* vbar) const {
double vol = 1.0 / molarDensity();
for (int k = 0; k < m_kk; k++) {
vbar[k] = vol;
}
}
// Properties of the Standard State of the Species in the Solution --
/*
* Get the nondimensional Enthalpy functions for the species
* at their standard states at the current T and P of the
* solution
*/
void IdealGasPhase::getEnthalpy_RT(doublereal* hrt) const {
const array_fp& _h = enthalpy_RT_ref();
copy(_h.begin(), _h.end(), hrt);
}
/*
* Get the array of nondimensional entropy functions for the
* standard state species
* at the current <I>T</I> and <I>P</I> of the solution.
*/
void IdealGasPhase::getEntropy_R(doublereal* sr) const {
const array_fp& _s = entropy_R_ref();
copy(_s.begin(), _s.end(), sr);
double tmp = log (pressure() /m_spthermo->refPressure());
for (int k = 0; k < m_kk; k++) {
sr[k] -= tmp;
}
}
/*
* Get the nondimensional gibbs function for the species
* standard states at the current T and P of the solution.
*/
void IdealGasPhase::getGibbs_RT(doublereal* grt) const {
const array_fp& gibbsrt = gibbs_RT_ref();
copy(gibbsrt.begin(), gibbsrt.end(), grt);
double tmp = log (pressure() /m_spthermo->refPressure());
for (int k = 0; k < m_kk; k++) {
grt[k] += tmp;
}
}
/*
* get the pure Gibbs free energies of each species assuming
* it is in its standard state. This is the same as
* getStandardChemPotentials().
*/
void IdealGasPhase::getPureGibbs(doublereal* gpure) const {
const array_fp& gibbsrt = gibbs_RT_ref();
scale(gibbsrt.begin(), gibbsrt.end(), gpure, _RT());
double tmp = log (pressure() /m_spthermo->refPressure());
tmp *= _RT();
for (int k = 0; k < m_kk; k++) {
gpure[k] += tmp;
}
}
/*
* Returns the vector of nondimensional
* internal Energies of the standard state at the current temperature
* and pressure of the solution for each species.
*/
void IdealGasPhase::getIntEnergy_RT(doublereal *urt) const {
const array_fp& _h = enthalpy_RT_ref();
for (int k = 0; k < m_kk; k++) {
urt[k] = _h[k] - 1.0;
}
}
/*
* Get the nondimensional heat capacity at constant pressure
* function for the species
* standard states at the current T and P of the solution.
*/
void IdealGasPhase::getCp_R(doublereal* cpr) const {
const array_fp& _cpr = cp_R_ref();
copy(_cpr.begin(), _cpr.end(), cpr);
}
/*
* Get the molar volumes of the species standard states at the current
* <I>T</I> and <I>P</I> of the solution.
* units = m^3 / kmol
*
* @param vol Output vector containing the standard state volumes.
* Length: m_kk.
*/
void IdealGasPhase::getStandardVolumes(doublereal *vol) const {
double tmp = 1.0 / molarDensity();
for (int k = 0; k < m_kk; k++) {
vol[k] = tmp;
}
}
// Thermodynamic Values for the Species Reference States ---------
/*
* Returns the vector of nondimensional
* enthalpies of the reference state at the current temperature
* and reference presssure.
*/
void IdealGasPhase::getEnthalpy_RT_ref(doublereal *hrt) const {
const array_fp& _h = enthalpy_RT_ref();
copy(_h.begin(), _h.end(), hrt);
}
/*
* Returns the vector of nondimensional
* enthalpies of the reference state at the current temperature
* and reference pressure.
*/
void IdealGasPhase::getGibbs_RT_ref(doublereal *grt) const {
const array_fp& gibbsrt = gibbs_RT_ref();
copy(gibbsrt.begin(), gibbsrt.end(), grt);
}
/*
* Returns the vector of the
* gibbs function of the reference state at the current temperature
* and reference pressure.
* units = J/kmol
*/
void IdealGasPhase::getGibbs_ref(doublereal *g) const {
const array_fp& gibbsrt = gibbs_RT_ref();
scale(gibbsrt.begin(), gibbsrt.end(), g, _RT());
}
/*
* Returns the vector of nondimensional
* entropies of the reference state at the current temperature
* and reference pressure.
*/
void IdealGasPhase::getEntropy_R_ref(doublereal *er) const {
const array_fp& _s = entropy_R_ref();
copy(_s.begin(), _s.end(), er);
}
/*
* Returns the vector of nondimensional
* internal Energies of the reference state at the current temperature
* of the solution and the reference pressure for each species.
*/
void IdealGasPhase::getIntEnergy_RT_ref(doublereal *urt) const {
const array_fp& _h = enthalpy_RT_ref();
for (int k = 0; k < m_kk; k++) {
urt[k] = _h[k] - 1.0;
}
}
/*
* Returns the vector of nondimensional
* constant pressure heat capacities of the reference state
* at the current temperature and reference pressure.
*/
void IdealGasPhase::getCp_R_ref(doublereal *cprt) const {
const array_fp& _cpr = cp_R_ref();
copy(_cpr.begin(), _cpr.end(), cprt);
}
void IdealGasPhase::getStandardVolumes_ref(doublereal *vol) const {
doublereal tmp = _RT() / m_p0;
for (int k = 0; k < m_kk; k++) {
vol[k] = tmp;
}
}
// new methods defined here -------------------------------
void IdealGasPhase::initThermo() {
m_mm = nElements();
doublereal tmin = m_spthermo->minTemp();
doublereal tmax = m_spthermo->maxTemp();
if (tmin > 0.0) m_tmin = tmin;
if (tmax > 0.0) m_tmax = tmax;
m_p0 = refPressure();
int leng = m_kk;
m_h0_RT.resize(leng);
m_g0_RT.resize(leng);
m_expg0_RT.resize(leng);
m_cp0_R.resize(leng);
m_s0_R.resize(leng);
m_pe.resize(leng, 0.0);
m_pp.resize(leng);
}
/*
* Set mixture to an equilibrium state consistent with specified
* chemical potentials and temperature. This method is needed by
* the ChemEquil equillibrium solver.
*/
void IdealGasPhase::setToEquilState(const doublereal* mu_RT)
{
double tmp, tmp2;
const array_fp& grt = gibbs_RT_ref();
/*
* Within the method, we protect against inf results if the
* exponent is too high.
*
* If it is too low, we set
* the partial pressure to zero. This capability is needed
* by the elemental potential method.
*/
doublereal pres = 0.0;
for (int k = 0; k < m_kk; k++) {
tmp = -grt[k] + mu_RT[k];
if (tmp < -600.) {
m_pp[k] = 0.0;
} else if (tmp > 500.0) {
tmp2 = tmp / 500.;
tmp2 *= tmp2;
m_pp[k] = m_p0 * exp(500.) * tmp2;
} else {
m_pp[k] = m_p0 * exp(tmp);
}
pres += m_pp[k];
}
// set state
setState_PX(pres, &m_pp[0]);
}
/// This method is called each time a thermodynamic property is
/// requested, to check whether the internal species properties
/// within the object need to be updated.
/// Currently, this updates the species thermo polynomial values
/// for the current value of the temperature. A check is made
/// to see if the temperature has changed since the last
/// evaluation. This object does not contain any persistent
/// data that depends on the concentration, that needs to be
/// updated. The state object modifies its concentration
/// dependent information at the time the setMoleFractions()
/// (or equivalent) call is made.
void IdealGasPhase::_updateThermo() const {
doublereal tnow = temperature();
// If the temperature has changed since the last time these
// properties were computed, recompute them.
if (m_tlast != tnow) {
m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0],
&m_s0_R[0]);
m_tlast = tnow;
// update the species Gibbs functions
int k;
for (k = 0; k < m_kk; k++) {
m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
}
m_logc0 = log(m_p0/(GasConstant * tnow));
m_tlast = tnow;
}
}
}

View file

@ -0,0 +1,930 @@
/**
* @file IdealGasPhase.h
* ThermoPhase object for the ideal gas equation of
* state - workhorse for %Cantera (see \ref thermoprops
* and class \link Cantera::IdealGasPhase IdealGasPhase\endlink).
*
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2001 California Institute of Technology
*
*/
#ifndef CT_IDEALGASPHASE_H
#define CT_IDEALGASPHASE_H
//#include "ct_defs.h"
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
#include "utilities.h"
namespace Cantera {
//! Class %IdealGasPhase represents low-density gases that obey the
//! ideal gas equation of state.
/*!
*
* %IdealGasPhase derives from class ThermoPhase,
* and overloads the virtual methods defined there with ones that
* use expressions appropriate for ideal gas mixtures.
*
* The independent unknowns are density, mass fraction, and temperature.
* the #setPressure() function will calculate the density consistent with
* the current mass fraction vector and temperature and the desired pressure,
* and then set the density in the derived State object.
*
* <HR>
* <H2> Specification of Species Standard %State Properties </H2>
* <HR>
*
* It is assumed that the reference state thermodynamics may be
* obtained by a pointer to a populated species thermodynamic property
* manager class in the base class, ThermoPhase::m_spthermo
* (see the base class \link Cantera#SpeciesThermo SpeciesThermo \endlink for a
* description of the specification of reference state species thermodynamics functions).
* The reference state,
* where the pressure is fixed at a single pressure,
* is a key species property calculation for the Ideal Gas Equation
* of state.
*
* This class is optimized for speed of execution. All calls to thermodynamic functions
* first call internal routines (aka #enthalpy_RT_ref()) which return references
* the reference state thermodynamics functions. Within these internal reference
* state functions, the function #_updateThermo() is called, that first checks to see
* whether the temperature has changed. If it has, it updates the internal reference
* state thermo functions by calling the SpeciesThermo object.
*
* Functions for the calculation of standard state properties for species
* at arbitray pressure are provided in %IdealGasPhase. However, they
* are all derived from their reference state conterparts.
*
* The standard state enthalpy is independent of pressure:
*
* \f[
* h^o_k(T,P) = h^{ref}_k(T)
* \f]
*
* The standard state constant-pressure heat capacity is independent of pressure:
*
* \f[
* Cp^o_k(T,P) = Cp^{ref}_k(T)
* \f]
*
* The standard state entropy depends in the following fashion on pressure:
*
* \f[
* S^o_k(T,P) = S^{ref}_k(T) - R \ln(\frac{P}{P_{ref}})
* \f]
* The standard state gibbs free energy is obtained from the enthalpy and entropy
* functions:
*
* \f[
* \mu^o_k(T,P) = h^o_k(T,P) - S^o_k(T,P) T
* \f]
*
* \f[
* \mu^o_k(T,P) = \mu^{ref}_k(T) + R T \ln( \frac{P}{P_{ref}})
* \f]
*
* where
* \f[
* \mu^{ref}_k(T) = h^{ref}_k(T) - T S^{ref}_k(T)
* \f]
*
* The standard state internal energy is obtained from the enthalpy function also
*
* \f[
* u^o_k(T,P) = h^o_k(T) - R T
* \f]
*
* The molar volume of a species is given by the ideal gas law
*
* \f[
* V^o_k(T,P) = \frac{R T}{P} \mbox{\quad where}
* \f]
*
* R = 8314.47215 Joules kmol<SUP>-1</SUP> K<SUP>-1</SUP>, from the 1999 CODATA convention.
* For a complete list of physical constants used within %Cantera, see \ref physConstants .
*
* <HR>
* <H2> Specification of Solution Thermodynamic Properties </H2>
* <HR>
*
* The activity of a species defined in the phase is given by the ideal gas law:
* \f[
* a_k = X_k
* \f]
* where \f$ X_k \f$ is the mole fraction of species <I>k</I>.
* The chemical potential for species <I>k</I> is equal to
*
* \f[
* \mu_k(T,P) = \mu^o_k(T, P) + R T \log(X_k)
* \f]
*
* In terms of the reference state, the above can be rewritten
*
*
* \f[
* \mu_k(T,P) = \mu^{ref}_k(T, P) + R T \log(\frac{P X_k}{P_{ref}})
* \f]
*
* The partial molar entropy for species <I>k</I> is given by the following relation,
*
* \f[
* \tilde{s}_k(T,P) = s^o_k(T,P) - R \log(X_k) = s^{ref}_k(T) - R \log(\frac{P X_k}{P_{ref}})
* \f]
*
* The partial molar enthalpy for species <I>k</I> is
*
* \f[
* \tilde{h}_k(T,P) = h^o_k(T,P) = h^{ref}_k(T)
* \f]
*
* The partial molar Internal Energy for species <I>k</I> is
*
* \f[
* \tilde{u}_k(T,P) = u^o_k(T,P) = u^{ref}_k(T)
* \f]
*
* The partial molar Heat Capacity for species <I>k</I> is
*
* \f[
* \tilde{Cp}_k(T,P) = Cp^o_k(T,P) = Cp^{ref}_k(T)
* \f]
*
*
* <HR>
* <H2> %Application within %Kinetics Managers </H2>
* <HR>
*
* \f$ C^a_k\f$ are defined such that \f$ a_k = C^a_k /
* C^s_k, \f$ where \f$ C^s_k \f$ is a standard concentration
* defined below and \f$ a_k \f$ are activities used in the
* thermodynamic functions. These activity (or generalized)
* concentrations are used
* by kinetics manager classes to compute the forward and
* reverse rates of elementary reactions.
* The activity concentration,\f$ C^a_k \f$,is given by the following expression.
*
* \f[
* C^a_k = C^s_k X_k = \frac{P}{R T} X_k
* \f]
*
* The standard concentration for species <I>k</I> is independent of <I>k</I> and equal to
*
* \f[
* C^s_k = C^s = \frac{P}{R T}
* \f]
*
* For example, a bulk-phase binary gas reaction between species j and k, producing
* a new gas species l would have the
* following equation for its rate of progress variable, \f$ R^1 \f$, which has
* units of kmol m-3 s-1.
*
* \f[
* R^1 = k^1 C_j^a C_k^a = k^1 (C^s a_j) (C^s a_k)
* \f]
* where
* \f[
* C_j^a = C^s a_j \mbox{\quad and \quad} C_k^a = C^s a_k
* \f]
*
* \f$ C_j^a \f$ is the activity concentration of species j, and
* \f$ C_k^a \f$ is the activity concentration of species k. \f$ C^s \f$
* is the standard concentration. \f$ a_j \f$ is
* the activity of species j which is equal to the mole fraction of j.
*
* The reverse rate constant can then be obtained from the law of microscopic reversibility
* and the equilibrium expression for the system.
*
* \f[
* \frac{a_j a_k}{ a_l} = K_a^{o,1} = \exp(\frac{\mu^o_l - \mu^o_j - \mu^o_k}{R T} )
* \f]
*
* \f$ K_a^{o,1} \f$ is the dimensionless form of the equilibrium constant, associated with
* the pressure dependent standard states \f$ \mu^o_l(T,P) \f$ and their associated activities,
* \f$ a_l \f$, repeated here:
*
* \f[
* \mu_l(T,P) = \mu^o_l(T, P) + R T \log(a_l)
* \f]
*
* We can switch over to expressing the equilibrium constant in terms of the reference
* state chemical potentials
*
* \f[
* K_a^{o,1} = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{P}
* \f]
*
* The concentration equilibrium constant, \f$ K_c \f$, may be obtained by changing over
* to activity concentrations. When this is done:
*
* \f[
* \frac{C^a_j C^a_k}{ C^a_l} = C^o K_a^{o,1} = K_c^1 =
* \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} ) * \frac{P_{ref}}{RT}
* \f]
*
* %Kinetics managers will calculate the concentration equilibrium constant, \f$ K_c \f$,
* using the second and third part of the above expression as a definition for the concentration
* equilibrium constant.
*
* For completeness, the pressure equilibrium constant may be obtained as well
*
* \f[
* \frac{P_j P_k}{ P_l P_{ref}} = K_p^1 = \exp(\frac{\mu^{ref}_l - \mu^{ref}_j - \mu^{ref}_k}{R T} )
* \f]
*
* \f$ K_p \f$ is the simplest form of the equilibrium constant for ideal gases. However, it isn't
* necessarily the simplest form of the equilibrium constant for other types of phases; \f$ K_c \f$ is
* used instead because it is completely general.
*
* The reverse rate of progress may be written down as
* \f[
* R^{-1} = k^{-1} C_l^a = k^{-1} (C^o a_l)
* \f]
*
* where we can use the concept of microscopic reversibility to write the reverse rate constant in terms of the
* forward reate constant and the concentration equilibrium constant, \f$ K_c \f$.
*
* \f[
* k^{-1} = k^1 K^1_c
* \f]
*
* \f$k^{-1} \f$ has units of s-1.
*
* <HR>
* <H2> Instantiation of the Class </H2>
* <HR>
*
*
* The constructor for this phase is located in the default ThermoFactory
* for %Cantera. A new %IdealGasPhase may be created by the following code snippet:
*
* @code
* XML_Node *xc = get_XML_File("silane.xml");
* XML_Node * const xs = xc->findNameID("phase", "silane");
* ThermoPhase *silane_tp = newPhase(*xs);
* IdealGasPhase *silaneGas = dynamic_cast <IdealGasPhase *>(silane_tp);
* @endcode
*
* or by the following constructor:
*
* @code
* XML_Node *xc = get_XML_File("silane.xml");
* XML_Node * const xs = xc->findNameID("phase", "silane");
* IdealGasPhase *silaneGas = new IdealGasPhase(*xs);
* @endcode
*
* <HR>
* <H2> XML Example </H2>
* <HR>
* An example of an XML Element named phase setting up a IdealGasPhase object named silane
* is given below.
*
* @verbatim
<!-- phase silane -->
<phase dim="3" id="silane">
<elementArray datasrc="elements.xml"> Si H He </elementArray>
<speciesArray datasrc="#species_data">
H2 H HE SIH4 SI SIH SIH2 SIH3 H3SISIH SI2H6
H2SISIH2 SI3H8 SI2 SI3
</speciesArray>
<reactionArray datasrc="#reaction_data"/>
<thermo model="IdealGas"/>
<kinetics model="GasKinetics"/>
<transport model="None"/>
</phase>
@endverbatim
*
* The model attribute "IdealGas" of the thermo XML element identifies the phase as
* being of the type handled by the IdealGasPhase object.
*
* @ingroup thermoprops
*
*/
class IdealGasPhase : public ThermoPhase {
public:
//! Empty Constructor
IdealGasPhase();
//! Destructor
virtual ~IdealGasPhase() {}
//! Equation of state flag.
/*!
* Returns the value cIdealGas, defined in mix_defs.h.
*/
virtual int eosType() const { return cIdealGas; }
/**
* @name Molar Thermodynamic Properties of the Solution ------------------------------
* @{
*/
//! Return the Molar enthalpy. Units: J/kmol.
/*!
* For an ideal gas mixture,
* \f[
* \hat h(T) = \sum_k X_k \hat h^0_k(T),
* \f]
* and is a function only of temperature.
* The standard-state pure-species enthalpies
* \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic
* property manager.
*
* \see SpeciesThermo
*/
virtual doublereal enthalpy_mole() const {
return GasConstant * temperature() *
mean_X(&enthalpy_RT_ref()[0]);
}
/**
* Molar internal energy. J/kmol. For an ideal gas mixture,
* \f[
* \hat u(T) = \sum_k X_k \hat h^0_k(T) - \hat R T,
* \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
*/
virtual doublereal intEnergy_mole() const {
return GasConstant * temperature()
* ( mean_X(&enthalpy_RT_ref()[0]) - 1.0);
}
/**
* Molar entropy. Units: J/kmol/K.
* For an ideal gas mixture,
* \f[
* \hat s(T, P) = \sum_k X_k \hat s^0_k(T) - \hat R \log (P/P^0).
* \f]
* The reference-state pure-species entropies
* \f$ \hat s^0_k(T) \f$ are computed by the species thermodynamic
* property manager.
* @see SpeciesThermo
*/
virtual doublereal entropy_mole() const {
return GasConstant * (mean_X(&entropy_R_ref()[0]) -
sum_xlogx() - std::log(pressure()/m_spthermo->refPressure()));
}
/**
* Molar Gibbs free Energy for an ideal gas.
* Units = J/kmol.
*/
virtual doublereal gibbs_mole() const {
return enthalpy_mole() - temperature() * entropy_mole();
}
/**
* Molar heat capacity at constant pressure. Units: J/kmol/K.
* For an ideal gas mixture,
* \f[
* \hat c_p(t) = \sum_k \hat c^0_{p,k}(T).
* \f]
* 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
*/
virtual doublereal cp_mole() const {
return GasConstant * mean_X(&cp_R_ref()[0]);
}
/**
* Molar heat capacity at constant volume. Units: J/kmol/K.
* For an ideal gas mixture,
* \f[ \hat c_v = \hat c_p - \hat R. \f]
*/
virtual doublereal cv_mole() const {
return cp_mole() - GasConstant;
}
//@}
/**
* @name Mechanical Equation of State ------------------------------------------------
* @{
*/
/**
* Pressure. Units: Pa.
* For an ideal gas mixture,
* \f[ P = n \hat R T. \f]
*/
virtual doublereal pressure() const {
return GasConstant * molarDensity() * temperature();
}
//! Set the pressure at constant temperature and composition.
/*!
* Units: Pa.
* This method is implemented by setting the mass density to
* \f[
* \rho = \frac{P \overline W}{\hat R T }.
* \f]
*
* @param p Pressure (Pa)
*/
virtual void setPressure(doublereal p) {
setDensity(p * meanMolecularWeight()
/(GasConstant * temperature()));
}
//! Returns the isothermal compressibility. Units: 1/Pa.
/**
* The isothermal compressibility is defined as
* \f[
* \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T
* \f]
* For ideal gases it's equal to the negative of the inverse of the pressure
*/
virtual doublereal isothermalCompressibility() const {
return -1.0/pressure();
}
//! Return the volumetric thermal expansion coefficient. Units: 1/K.
/*!
* The thermal expansion coefficient is defined as
* \f[
* \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
* \f]
* For ideal gases, it's equal to the inverse of the temperature.
*/
virtual doublereal thermalExpansionCoeff() const {
return 1.0/temperature();
}
//@}
/**
* @name Chemical Potentials and Activities ------------------------------------------
*
*
* The activity \f$a_k\f$ of a species in solution is
* related to the chemical potential by
* \f[
* \mu_k(T,P,X_k) = \mu_k^0(T,P)
* + \hat R T \log a_k.
* \f]
* The quantity \f$\mu_k^0(T,P)\f$ is
* the standard state chemical potential at unit activity.
* It may depend on the pressure and the temperature. However,
* it may not depend on the mole fractions of the species
* in the solution.
*
* The activities are related to the generalized
* concentrations, \f$\tilde C_k\f$, and standard
* concentrations, \f$C^0_k\f$, by the following formula:
*
* \f[
* a_k = \frac{\tilde C_k}{C^0_k}
* \f]
* The generalized concentrations are used in the kinetics classes
* to describe the rates of progress of reactions involving the
* species. Their formulation depends upons the specification
* of the rate constants for reaction, especially the units used
* in specifying the rate constants. The bridge between the
* thermodynamic equilibrium expressions that use a_k and the
* kinetics expressions which use the generalized concentrations
* is provided by the multiplicative factor of the
* standard concentrations.
* @{
*/
//! This method returns the array of generalized concentrations.
/*!
* For an ideal gas mixture, these are simply the actual concentrations.
*
* @param c Output array of generalized concentrations. The
* units depend upon the implementation of the
* reaction rate expressions within the phase.
*/
virtual void getActivityConcentrations(doublereal* c) const {
getConcentrations(c);
}
//! Returns the standard concentration \f$ C^0_k \f$, which is used to normalize
//! the generalized concentration.
/*!
* This is defined as the concentration by which the generalized
* concentration is normalized to produce the activity.
* In many cases, this quantity will be the same for all species in a phase.
* Since the activity for an ideal gas mixture is
* simply the mole fraction, for an ideal gas \f$ C^0_k = P/\hat R T \f$.
*
* @param k Optional parameter indicating the species. The default
* is to assume this refers to species 0.
* @return
* Returns the standard Concentration in units of m3 kmol-1.
*/
virtual doublereal standardConcentration(int k=0) const;
//! Returns the natural logarithm of the standard
//! concentration of the kth species
/*!
* @param k index of the species. (defaults to zero)
*/
virtual doublereal logStandardConc(int k=0) const;
//! Get the array of non-dimensional activity coefficients at
//! the current solution temperature, pressure, and solution concentration.
/*!
* For ideal gases, the activity coefficients are all equal to one.
*
* @param ac Output vector of activity coefficients. Length: m_kk.
*/
virtual void getActivityCoefficients(doublereal* ac) const;
//@}
/// @name Partial Molar Properties of the Solution ----------------------------------
//@{
//! Get the species chemical potentials. Units: J/kmol.
/*!
* This function returns a vector of chemical potentials of the
* species in solution at the current temperature, pressure
* and mole fraction of the solution.
*
* @param mu Output vector of species chemical
* potentials. Length: m_kk. Units: J/kmol
*/
virtual void getChemPotentials(doublereal* mu) const;
//! Get the species partial molar enthalpies. Units: J/kmol.
/*!
* @param hbar Output vector of species partial molar enthalpies.
* Length: m_kk. units are J/kmol.
*/
virtual void getPartialMolarEnthalpies(doublereal* hbar) const;
//! Get the species partial molar entropies. Units: J/kmol/K.
/*!
* @param sbar Output vector of species partial molar entropies.
* Length = m_kk. units are J/kmol/K.
*/
virtual void getPartialMolarEntropies(doublereal* sbar) const;
//! Get the species partial molar enthalpies. Units: J/kmol.
/*!
* @param ubar Output vector of speciar partial molar internal energies.
* Length = m_kk. units are J/kmol.
*/
virtual void getPartialMolarIntEnergies(doublereal* ubar) const;
//! Get the partial molar heat capacities Units: J/kmol/K
/*!
* @param cpbar Output vector of species partial molar heat capacities at constant pressure.
* Length = m_kk. units are J/kmol/K.
*/
virtual void getPartialMolarCp(doublereal* cpbar) const;
//! Get the species partial molar volumes. Units: m^3/kmol.
/*!
* @param vbar Output vector of speciar partial molar volumes.
* Length = m_kk. units are m^3/kmol.
*/
virtual void getPartialMolarVolumes(doublereal* vbar) const;
//@}
/// @name Properties of the Standard State of the Species in the Solution ----------
//@{
//! Get the array of chemical potentials at unit activity for the
//! species standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* These are the standard state chemical potentials \f$ \mu^0_k(T,P)
* \f$. The values are evaluated at the current
* temperature and pressure of the solution
*
* @param mu Output vector of chemical potentials.
* Length: m_kk.
*/
virtual void getStandardChemPotentials(doublereal* mu) const;
//! Get the nondimensional Enthalpy functions for the species standard states
//! at their standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param hrt Output vector of nondimensional standard state enthalpies.
* Length: m_kk.
*/
virtual void getEnthalpy_RT(doublereal* hrt) const;
//! Get the array of nondimensional Entropy functions for the
//! species standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param sr Output vector of nondimensional standard state entropies.
* Length: m_kk.
*/
virtual void getEntropy_R(doublereal* sr) const;
//! Get the nondimensional Gibbs functions for the species
//! standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param grt Output vector of nondimensional standard state gibbs free energies
* Length: m_kk.
*/
virtual void getGibbs_RT(doublereal* grt) const;
//! Get the Gibbs functions for the standard
//! state of the species at the current <I>T</I> and <I>P</I> of the solution
/*!
* Units are Joules/kmol
* @param gpure Output vector of standard state gibbs free energies
* Length: m_kk.
*/
virtual void getPureGibbs(doublereal* gpure) const;
//! Returns the vector of nondimensional Internal Energies of the standard
//! state species at the current <I>T</I> and <I>P</I> of the solution
/*!
* @param urt output vector of nondimensional standard state internal energies
* of the species. Length: m_kk.
*/
virtual void getIntEnergy_RT(doublereal *urt) const;
//! Get the nondimensional Heat Capacities at constant
//! pressure for the species standard states
//! at the current <I>T</I> and <I>P</I> of the solution
/*!
* @param cpr Output vector of nondimensional standard state heat capacities
* Length: m_kk.
*/
virtual void getCp_R(doublereal* cpr) const;
//! Get the molar volumes of the species standard states at the current
//! <I>T</I> and <I>P</I> of the solution.
/*!
* units = m^3 / kmol
*
* @param vol Output vector containing the standard state volumes.
* Length: m_kk.
*/
virtual void getStandardVolumes(doublereal *vol) const;
//@}
/// @name Thermodynamic Values for the Species Reference States ---------------------
//@{
//! Returns the vector of nondimensional
//! enthalpies of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
/*!
* @param hrt Output vector containing the nondimensional reference state
* enthalpies. Length: m_kk.
*/
virtual void getEnthalpy_RT_ref(doublereal *hrt) const;
//! Returns the vector of nondimensional
//! Gibbs Free Energies of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
/*!
* @param grt Output vector containing the nondimensional reference state
* Gibbs Free energies. Length: m_kk.
*/
virtual void getGibbs_RT_ref(doublereal *grt) const;
//! Returns the vector of the
//! gibbs function of the reference state at the current temperature
//! of the solution and the reference pressure for the species.
/*!
* units = J/kmol
*
* @param g Output vector containing the reference state
* Gibbs Free energies. Length: m_kk. Units: J/kmol.
*/
virtual void getGibbs_ref(doublereal *g) const;
//! Returns the vector of nondimensional
//! entropies of the reference state at the current temperature
//! of the solution and the reference pressure for each species.
/*!
* @param er Output vector containing the nondimensional reference state
* entropies. Length: m_kk.
*/
virtual void getEntropy_R_ref(doublereal *er) const;
//! Returns the vector of nondimensional
//! internal Energies of the reference state at the current temperature
//! of the solution and the reference pressure for each species.
/*!
* @param urt Output vector of nondimensional reference state
* internal energies of the species.
* Length: m_kk
*/
virtual void getIntEnergy_RT_ref(doublereal *urt) const;
//! Returns the vector of nondimensional
//! constant pressure heat capacities of the reference state
//! at the current temperature of the solution
//! and reference pressure for each species.
/*!
* @param cprt Output vector of nondimensional reference state
* heat capacities at constant pressure for the species.
* Length: m_kk
*/
virtual void getCp_R_ref(doublereal *cprt) const;
//! Get the molar volumes of the species standard states at the current
//! <I>T</I> and <I>P_ref</I> of the solution.
/*!
* units = m^3 / kmol
*
* @param vol Output vector containing the standard state volumes.
* Length: m_kk.
*/
virtual void getStandardVolumes_ref(doublereal *vol) const;
//@}
/// @name NonVirtual Internal methods to Return References to Reference State Thermo
//@{
//! Returns a reference to the dimensionless reference state enthalpy vector.
/*!
* This function is part of the layer that checks/recalculates the reference
* state thermo functions.
*/
const array_fp& enthalpy_RT_ref() const {
_updateThermo();
return m_h0_RT;
}
//! Returns a reference to the dimensionless reference state Gibbs free energy vector.
/*!
* This function is part of the layer that checks/recalculates the reference
* state thermo functions.
*/
const array_fp& gibbs_RT_ref() const {
_updateThermo();
return m_g0_RT;
}
//! Returns a reference to the exponent of the dimensionless reference state Gibbs Free energy vector.
/*!
* This function is part of the layer that checks/recalculates the reference
* state thermo functions.
*/
const array_fp& expGibbs_RT_ref() const {
_updateThermo();
int k;
for (k = 0; k != m_kk; k++) m_expg0_RT[k] = std::exp(m_g0_RT[k]);
return m_expg0_RT;
}
//! Returns a reference to the dimensionless reference state Entropy vector.
/*!
* This function is part of the layer that checks/recalculates the reference
* state thermo functions.
*/
const array_fp& entropy_R_ref() const {
_updateThermo();
return m_s0_R;
}
//! Returns a reference to the dimensionless reference state Heat Capacity vector.
/*!
* This function is part of the layer that checks/recalculates the reference
* state thermo functions.
*/
const array_fp& cp_R_ref() const {
_updateThermo();
return m_cp0_R;
}
//@}
//! Initialize the ThermoPhase object after all species have been set up
/*!
* @internal Initialize.
*
* This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called from ThermoPhase::initThermoXML(),
* which is called from importPhase(),
* just prior to returning from function importPhase().
*
* @see importCTML.cpp
*/
virtual void initThermo();
//!This method is used by the ChemEquil equilibrium solver.
/*!
* @internal
* @name Chemical Equilibrium
* @{
*
* Set mixture to an equilibrium state consistent with specified
* element potentials and temperature.
* It sets the state such that the chemical potentials satisfy
* \f[ \frac{\mu_k}{\hat R T} = \sum_m A_{k,m}
* \left(\frac{\lambda_m} {\hat R T}\right) \f] where
* \f$ \lambda_m \f$ is the element potential of element m. The
* temperature is unchanged. Any phase (ideal or not) that
* implements this method can be equilibrated by ChemEquil.
*
* @param lambda_RT vector of non-dimensional element potentials
* \f[ \lambda_m/RT \f].
*/
virtual void setToEquilState(const doublereal* lambda_RT);
//@}
protected:
//! Number of Elements in the phase
/*!
* This member is defined here, from a call to the Elements ojbect, for speed.
*/
int m_mm;
//! Minimum temperature for valid species standard state thermo props
/*!
* This is the minimum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmin;
//! Maximum temperature for valid species standard state thermo props
/*!
* This is the maximum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmax;
//! Reference state pressure
/*!
* Value of the reference state pressure in Pascals.
* All species must have the same reference state pressure.
*/
doublereal m_p0;
//! last value of the temperature processed by reference state
mutable doublereal m_tlast;
//! Temporary storage for log of p/rt
mutable doublereal m_logc0;
//! Temporary storage for dimensionless reference state enthalpies
mutable array_fp m_h0_RT;
//! Temporary storage for dimensionless reference state heat capacities
mutable array_fp m_cp0_R;
//! Temporary storage for dimensionless reference state gibbs energies
mutable array_fp m_g0_RT;
//! Temporary storage for dimensionless reference state entropies
mutable array_fp m_s0_R;
//! currently unsed
/*!
* @deprecated
*/
mutable array_fp m_expg0_RT;
//! Currently unused
/*
* @deprecated
*/
mutable array_fp m_pe;
//! Temporary array containing internally calculated partial pressures
mutable array_fp m_pp;
private:
//! Update the species reference state thermodynamic functions
/*!
* The polynomials for the standard state functions are only
* reevalulated if the temperature has changed.
*
*/
void _updateThermo() const;
};
}
#endif

View file

@ -25,7 +25,8 @@
*/
#include "IdealMolalSoln.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include <math.h>
namespace Cantera {

View file

@ -25,7 +25,8 @@
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "SpeciesThermo.h"

View file

@ -0,0 +1,129 @@
/**
*
* @file LatticePhase.cpp
*
* $Id$
*/
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "mix_defs.h"
#include "LatticePhase.h"
#include "SpeciesThermo.h"
#include <math.h>
namespace Cantera {
doublereal LatticePhase::
enthalpy_mole() const {
doublereal p0 = m_spthermo->refPressure();
return GasConstant * temperature() *
mean_X(&enthalpy_RT()[0])
+ (pressure() - p0)/molarDensity();
}
doublereal LatticePhase::intEnergy_mole() const {
doublereal p0 = m_spthermo->refPressure();
return GasConstant * temperature() *
mean_X(&enthalpy_RT()[0])
- p0/molarDensity();
}
doublereal LatticePhase::entropy_mole() const {
return GasConstant * (mean_X(&entropy_R()[0]) -
sum_xlogx());
}
doublereal LatticePhase::gibbs_mole() const {
return enthalpy_mole() - temperature() * entropy_mole();
}
doublereal LatticePhase::cp_mole() const {
return GasConstant * mean_X(&cp_R()[0]);
}
void LatticePhase::getActivityConcentrations(doublereal* c) const {
getMoleFractions(c);
}
void LatticePhase::getActivityCoefficients(doublereal* ac) const {
for (int k = 0; k < m_kk; k++) {
ac[k] = 1.0;
}
}
doublereal LatticePhase::standardConcentration(int k) const {
return 1.0;
}
doublereal LatticePhase::logStandardConc(int k) const {
return 0.0;
}
void LatticePhase::getChemPotentials(doublereal* mu) const {
doublereal vdp = (pressure() - m_spthermo->refPressure())/
molarDensity();
doublereal xx;
doublereal rt = temperature() * GasConstant;
const array_fp& g_RT = gibbs_RT();
for (int k = 0; k < m_kk; k++) {
xx = fmaxx(SmallNumber, moleFraction(k));
mu[k] = rt*(g_RT[k] + log(xx)) + vdp;
}
}
void LatticePhase::getStandardChemPotentials(doublereal* mu0) const {
const array_fp& gibbsrt = gibbs_RT();
scale(gibbsrt.begin(), gibbsrt.end(), mu0, _RT());
}
void LatticePhase::initThermo() {
m_kk = nSpecies();
m_mm = nElements();
doublereal tmin = m_spthermo->minTemp();
doublereal tmax = m_spthermo->maxTemp();
if (tmin > 0.0) m_tmin = tmin;
if (tmax > 0.0) m_tmax = tmax;
m_p0 = refPressure();
int leng = m_kk;
m_h0_RT.resize(leng);
m_g0_RT.resize(leng);
m_cp0_R.resize(leng);
m_s0_R.resize(leng);
setMolarDensity(m_molar_density);
}
void LatticePhase::_updateThermo() const {
doublereal tnow = temperature();
if (fabs(molarDensity() - m_molar_density)/m_molar_density > 0.0001) {
throw CanteraError("_updateThermo","molar density changed from "
+fp2str(m_molar_density)+" to "+fp2str(molarDensity()));
}
if (m_tlast != tnow) {
m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0],
&m_s0_R[0]);
m_tlast = tnow;
int k;
for (k = 0; k < m_kk; k++) {
m_g0_RT[k] = m_h0_RT[k] - m_s0_R[k];
}
m_tlast = tnow;
}
}
void LatticePhase::setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","Lattice");
m_molar_density = getFloat(eosdata, "site_density", "-");
m_vacancy = getString(eosdata, "vacancy_species");
}
}

View file

@ -0,0 +1,150 @@
/**
*
* @file LatticePhase.h
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2005 California Institute of Technology
*
*/
#ifndef CT_LATTICE_H
#define CT_LATTICE_H
#include "ct_defs.h"
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
#include "utilities.h"
namespace Cantera {
/**
*/
class LatticePhase : public ThermoPhase {
public:
LatticePhase() : m_tlast(0.0) {}
virtual ~LatticePhase() {}
virtual int eosType() const { return cLattice; }
virtual doublereal enthalpy_mole() const;
virtual doublereal intEnergy_mole() const;
virtual doublereal entropy_mole() const;
virtual doublereal gibbs_mole() const;
virtual doublereal cp_mole() const;
virtual doublereal cv_mole() const {
return cp_mole();
}
virtual doublereal pressure() const {
return m_press;
}
virtual void setPressure(doublereal p) {
m_press = p;
setMolarDensity(m_molar_density);
}
virtual void getActivityConcentrations(doublereal* c) const;
virtual void getActivityCoefficients(doublereal* ac) const;
virtual void getChemPotentials(doublereal* mu) const;
virtual void getStandardChemPotentials(doublereal* mu0) const;
virtual doublereal standardConcentration(int k=0) const;
virtual doublereal logStandardConc(int k=0) const;
virtual void getPureGibbs(doublereal* gpure) const {
const array_fp& gibbsrt = gibbs_RT();
scale(gibbsrt.begin(), gibbsrt.end(), gpure, _RT());
}
void getEnthalpy_RT(doublereal* hrt) const {
const array_fp& _h = enthalpy_RT();
std::copy(_h.begin(), _h.end(), hrt);
}
void getEntropy_R(doublereal* sr) const {
const array_fp& _s = entropy_R();
std::copy(_s.begin(), _s.end(), sr);
}
virtual void getGibbs_RT(doublereal* grt) const {
const array_fp& gibbsrt = gibbs_RT();
std::copy(gibbsrt.begin(), gibbsrt.end(), grt);
}
void getCp_R(doublereal* cpr) const {
const array_fp& _cpr = cp_R();
std::copy(_cpr.begin(), _cpr.end(), cpr);
}
// new methods defined here
const array_fp& enthalpy_RT() const {
_updateThermo();
return m_h0_RT;
}
const array_fp& gibbs_RT() const {
_updateThermo();
return m_g0_RT;
}
const array_fp& entropy_R() const {
_updateThermo();
return m_s0_R;
}
const array_fp& cp_R() const {
_updateThermo();
return m_cp0_R;
}
virtual void initThermo();
// set the site density of sublattice n
virtual void setParameters(int n, doublereal* c) {}
virtual void getParameters(int &n, doublereal * const c) {
double d = molarDensity();
c[0] = d;
n = 1;
}
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:
int m_mm;
doublereal m_tmin, m_tmax, m_p0;
mutable doublereal m_tlast;
mutable array_fp m_h0_RT;
mutable array_fp m_cp0_R;
mutable array_fp m_g0_RT;
mutable array_fp m_s0_R;
doublereal m_press;
std::string m_vacancy;
doublereal m_molar_density;
private:
void _updateThermo() const;
};
}
#endif

View file

@ -0,0 +1,235 @@
/**
*
* @file LatticeSolidPhase.cpp
*
* $Id$
*/
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "mix_defs.h"
#include "LatticeSolidPhase.h"
#include "LatticePhase.h"
#include "SpeciesThermo.h"
#include "ThermoFactory.h"
//#include "importCTML.h"
#include <string>
using namespace std;
namespace Cantera {
doublereal LatticeSolidPhase::
enthalpy_mole() const {
_updateThermo();
doublereal ndens, sum = 0.0;
int n;
for (n = 0; n < m_nlattice; n++) {
ndens = m_lattice[n]->molarDensity();
sum += ndens * m_lattice[n]->enthalpy_mole();
}
return sum/molarDensity();
}
doublereal LatticeSolidPhase::intEnergy_mole() const {
_updateThermo();
doublereal ndens, sum = 0.0;
int n;
for (n = 0; n < m_nlattice; n++) {
ndens = m_lattice[n]->molarDensity();
sum += ndens * m_lattice[n]->intEnergy_mole();
}
return sum/molarDensity();
}
doublereal LatticeSolidPhase::entropy_mole() const {
_updateThermo();
doublereal ndens, sum = 0.0;
int n;
for (n = 0; n < m_nlattice; n++) {
ndens = m_lattice[n]->molarDensity();
sum += ndens * m_lattice[n]->entropy_mole();
}
return sum/molarDensity();
}
doublereal LatticeSolidPhase::gibbs_mole() const {
_updateThermo();
doublereal ndens, sum = 0.0;
int n;
for (n = 0; n < m_nlattice; n++) {
ndens = m_lattice[n]->molarDensity();
sum += ndens * m_lattice[n]->gibbs_mole();
}
return sum/molarDensity();
}
doublereal LatticeSolidPhase::cp_mole() const {
_updateThermo();
doublereal ndens, sum = 0.0;
int n;
for (n = 0; n < m_nlattice; n++) {
ndens = m_lattice[n]->molarDensity();
sum += ndens * m_lattice[n]->cp_mole();
}
return sum/molarDensity();
}
void LatticeSolidPhase::getActivityConcentrations(doublereal* c) const {
_updateThermo();
int n;
int strt = 0;
for (n = 0; n < m_nlattice; n++) {
m_lattice[n]->getMoleFractions(c+strt);
strt += m_lattice[n]->nSpecies();
}
}
void LatticeSolidPhase::getActivityCoefficients(doublereal* ac) const {
for (int k = 0; k < m_kk; k++) {
ac[k] = 1.0;
}
}
doublereal LatticeSolidPhase::standardConcentration(int k) const {
return 1.0;
}
doublereal LatticeSolidPhase::logStandardConc(int k) const {
return 0.0;
}
void LatticeSolidPhase::getChemPotentials(doublereal* mu) const {
_updateThermo();
int n;
int strt = 0;
double dratio;
for (n = 0; n < m_nlattice; n++) {
dratio = m_lattice[n]->molarDensity()/molarDensity();
m_lattice[n]->getChemPotentials(mu+strt);
scale(mu + strt, mu + strt + m_lattice[n]->nSpecies(), mu + strt, dratio);
strt += m_lattice[n]->nSpecies();
}
}
void LatticeSolidPhase::getStandardChemPotentials(doublereal* mu0) const {
_updateThermo();
int n;
int strt = 0;
double dratio;
for (n = 0; n < m_nlattice; n++) {
dratio = m_lattice[n]->molarDensity()/molarDensity();
m_lattice[n]->getStandardChemPotentials(mu0+strt);
scale(mu0 + strt, mu0 + strt + m_lattice[n]->nSpecies(), mu0 + strt, dratio);
strt += m_lattice[n]->nSpecies();
}
}
void LatticeSolidPhase::initThermo() {
m_kk = nSpecies();
m_mm = nElements();
m_x.resize(m_kk);
int n, nsp, k, loc = 0;
doublereal ndens;
m_molar_density = 0.0;
for (n = 0; n < m_nlattice; n++) {
nsp = m_lattice[n]->nSpecies();
ndens = m_lattice[n]->molarDensity();
for (k = 0; k < nsp; k++) {
m_x[loc] = ndens * m_lattice[n]->moleFraction(k);
loc++;
}
m_molar_density += ndens;
}
setMoleFractions(DATA_PTR(m_x));
// const vector<string>& spnames = speciesNames();
// int n, k, kl, namesize;
// int nl = m_sitedens.size();
// string s;
// m_lattice.resize(m_kk,-1);
// vector_fp conc(m_kk, 0.0);
// compositionMap xx;
// for (n = 0; n < nl; n++) {
// for (k = 0; k < m_kk; k++) {
// xx[speciesName(k)] = -1.0;
// }
// parseCompString(m_sp[n], xx);
// for (k = 0; k < m_kk; k++) {
// if (xx[speciesName(k)] != -1.0) {
// conc[k] = m_sitedens[n]*xx[speciesName(k)];
// m_lattice[k] = n;
// }
// }
// }
// for (k = 0; k < m_kk; k++) {
// if (m_lattice[k] == -1) {
// throw CanteraError("LatticeSolidPhase::"
// "setParametersFromXML","Species "+speciesName(k)
// +" not a member of any lattice.");
// }
// }
// setMoleFractions(DATA_PTR(conc));
}
void LatticeSolidPhase::_updateThermo() const {
doublereal tnow = temperature();
// if (fabs(molarDensity() - m_molar_density)/m_molar_density > 0.0001) {
// throw CanteraError("_updateThermo","molar density changed from "
// +fp2str(m_molar_density)+" to "+fp2str(molarDensity()));
//}
if (m_tlast != tnow) {
int n;
getMoleFractions(DATA_PTR(m_x));
int strt = 0;
for (n = 0; n < m_nlattice; n++) {
m_lattice[n]->setTemperature(tnow);
m_lattice[n]->setMoleFractions(DATA_PTR(m_x) + strt);
m_lattice[n]->setPressure(m_press);
strt += m_lattice[n]->nSpecies();
}
m_tlast = tnow;
}
}
void LatticeSolidPhase::setLatticeMoleFractions(int nn,
string x) {
m_lattice[nn]->setMoleFractionsByName(x);
int n, k, loc=0, nsp;
doublereal ndens;
for (n = 0; n < m_nlattice; n++) {
nsp = m_lattice[n]->nSpecies();
ndens = m_lattice[n]->molarDensity();
for (k = 0; k < nsp; k++) {
m_x[loc] = ndens * m_lattice[n]->moleFraction(k);
loc++;
}
}
setMoleFractions(DATA_PTR(m_x));
}
void LatticeSolidPhase::setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","LatticeSolid");
XML_Node& la = eosdata.child("LatticeArray");
vector<XML_Node*> lattices;
la.getChildren("phase",lattices);
int n;
int nl = lattices.size();
m_nlattice = nl;
for (n = 0; n < nl; n++) {
XML_Node& i = *lattices[n];
m_lattice.push_back((LatticePhase*)newPhase(i));
}
}
}

View file

@ -0,0 +1,92 @@
/**
*
* @file LatticeSolidPhase.h
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2005 California Institute of Technology
*
*/
#ifndef CT_LATTICESOLID_H
#define CT_LATTICESOLID_H
#include "ct_defs.h"
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
#include "utilities.h"
namespace Cantera {
class LatticePhase;
class LatticeSolidPhase : public ThermoPhase {
public:
LatticeSolidPhase() : m_tlast(0.0) {}
virtual ~LatticeSolidPhase() {}
virtual int eosType() const { return cLatticeSolid; }
virtual doublereal enthalpy_mole() const;
virtual doublereal intEnergy_mole() const;
virtual doublereal entropy_mole() const;
virtual doublereal gibbs_mole() const;
virtual doublereal cp_mole() const;
virtual doublereal cv_mole() const {
return cp_mole();
}
virtual doublereal pressure() const {
return m_press;
}
virtual void setPressure(doublereal p) {
m_press = p;
setMolarDensity(m_molar_density);
}
virtual void getActivityConcentrations(doublereal* c) const;
virtual void getActivityCoefficients(doublereal* ac) const;
virtual void getChemPotentials(doublereal* mu) const;
virtual void getStandardChemPotentials(doublereal* mu0) const;
virtual doublereal standardConcentration(int k=0) const;
virtual doublereal logStandardConc(int k=0) const;
virtual void initThermo();
virtual void setParametersFromXML(const XML_Node& eosdata);
void setLatticeMoleFractions(int n, std::string x);
protected:
int m_mm;
int m_kk;
mutable doublereal m_tlast;
doublereal m_press;
doublereal m_molar_density;
int m_nlattice;
std::vector<LatticePhase*> m_lattice;
mutable vector_fp m_x;
private:
void _updateThermo() const;
};
}
#endif

View file

@ -11,7 +11,7 @@
.SUFFIXES :
.SUFFIXES : .cpp .d .o .h
INCDIR = ../../../build/include/cantera/kernel/thermo
INCDIR = ../../../build/include/cantera/kernel
INSTALL_TSC = ../../../bin/install_tsc
do_ranlib = @DO_RANLIB@
do_electro = @COMPILE_ELECTROLYTES@
@ -29,6 +29,26 @@ PIC_FLAG=@PIC@
CXX_FLAGS = @CXXFLAGS@ $(LOCAL_DEFS) $(CXX_OPT) $(PIC_FLAG) $(DEBUG_FLAG)
# Basic Cantera Thermodynamics Object Files
THERMO_OBJ = State.o Elements.o Constituents.o Phase.o \
ThermoPhase.o IdealGasPhase.o ConstDensityThermo.o \
SpeciesThermoFactory.o ConstCpPoly.o \
Mu0Poly.o GeneralSpeciesThermo.o SurfPhase.o \
ThermoFactory.o phasereport.o @phase_object_files@
THERMO_H = State.h Elements.h Constituents.h Phase.h mix_defs.h \
ThermoPhase.h IdealGasPhase.h ConstDensityThermo.h \
SpeciesThermoFactory.h ThermoFactory.h \
NasaPoly1.h NasaPoly2.h NasaThermo.h \
ShomateThermo.h ShomatePoly.h ConstCpPoly.h \
SimpleThermo.h SpeciesThermoMgr.h \
SpeciesThermoInterpType.h \
GeneralSpeciesThermo.h Mu0Poly.h \
speciesThermoTypes.h SpeciesThermo.h SurfPhase.h \
EdgePhase.h \
@phase_header_files@
# Extended Cantera Thermodynamics Object Files
ifeq ($(do_electro),1)
@ -51,13 +71,13 @@ ISSP_OBJ = IdealSolidSolnPhase.o StoichSubstanceSSTP.o SingleSpeciesTP.o
ISSP_H = IdealSolidSolnPhase.h StoichSubstanceSSTP.h SingleSpeciesTP.h
endif
CATHERMO_OBJ = $(ELECTRO_OBJ) $(ISSP_OBJ)
CATHERMO_OBJ = $(THERMO_OBJ) $(ELECTRO_OBJ) $(ISSP_OBJ)
CATHERMO_H = $(ELECTRO_H) $(ISSP_H)
CATHERMO_H = $(THERMO_H) $(ELECTRO_H) $(ISSP_H)
CXX_INCLUDES = -I.. @CXX_INCLUDES@
LIB = @buildlib@/libcaThermo.a
CXX_INCLUDES = -I../base @CXX_INCLUDES@
LIB = @buildlib@/libthermo.a
DEPENDS = $(CATHERMO_OBJ:.o=.d)

View file

@ -0,0 +1,95 @@
/**
*
* @file MetalPhase.h
*
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2003 California Institute of Technology
*
*/
#ifndef CT_METALPHASE_H
#define CT_METALPHASE_H
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
namespace Cantera {
/**
* @ingroup thermoprops
*
* Class MetalPhase represents electrons in a metal.
*
*/
class MetalPhase : public ThermoPhase {
public:
MetalPhase() {}
virtual ~MetalPhase() {}
// Overloaded methoods of class ThermoPhase
virtual int eosType() const { return cMetal; }
virtual doublereal enthalpy_mole() const { return 0.0; }
virtual doublereal intEnergy_mole() const { return 0.0; }
virtual doublereal entropy_mole() const { return 0.0; }
virtual doublereal gibbs_mole() const { return 0.0; }
virtual doublereal cp_mole() const { return 0.0; }
virtual doublereal cv_mole() const { return 0.0; }
virtual void setPressure(doublereal pres) { m_press = pres; }
virtual doublereal pressure() const { return m_press; }
virtual void getChemPotentials(doublereal* mu) const {
int n, nsp = nSpecies();
for (n = 0; n < nsp; n++) mu[n] = 0.0;
}
virtual void getStandardChemPotentials(doublereal* mu0) const {
int n, nsp = nSpecies();
for (n = 0; n < nsp; n++) mu0[n] = 0.0;
}
virtual void getActivityConcentrations(doublereal* c) const {
int n, nsp = nSpecies();
for (n = 0; n < nsp; n++) c[n] = 1.0;
}
virtual doublereal standardConcentration(int k=0) const {
return 1.0;
}
virtual doublereal logStandardConc(int k=0) const {
return 0.0;
}
virtual void setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","Metal");
doublereal rho = getFloat(eosdata, "density", "-");
setDensity(rho);
}
protected:
private:
doublereal m_press;
};
}
#endif

View file

@ -0,0 +1,414 @@
/**
* @file Mu0Poly.cpp
* Definitions for a single-species standard state object derived
* from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based
* on a piecewise constant mu0 interpolation
* (see \ref spthermo and class \link Cantera::Mu0Poly Mu0Poly\endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#include "Mu0Poly.h"
#include "ctexceptions.h"
#include "speciesThermoTypes.h"
#include "SpeciesThermo.h"
#include "xml.h"
#include "ctml.h"
using namespace std;
using namespace ctml;
namespace Cantera {
Mu0Poly::Mu0Poly() : m_numIntervals(0),
m_H298(0.0),
m_lowT(0.0),
m_highT(0.0),
m_Pref(0.0),
m_index(0) {
}
/*
* Mu0Poly():
*
* In the constructor, we calculate and store the
* piecewise linear approximation to the thermodynamic
* functions.
*
* coeffs[0] = number of points (integer)
* 1 = H298(J/kmol)
* 2 = T1 (Kelvin)
* 3 = mu1 (J/kmol)
* 4 = T2 (Kelvin)
* 5 = mu2 (J/kmol)
* 6 = T3 (Kelvin)
* 7 = mu3 (J/kmol)
* ........
*/
Mu0Poly::Mu0Poly(int n, doublereal tlow, doublereal thigh,
doublereal pref,
const doublereal* coeffs) :
m_numIntervals(0),
m_H298(0.0),
m_lowT (tlow),
m_highT (thigh),
m_Pref (pref),
m_index (n) {
processCoeffs(coeffs);
}
Mu0Poly::Mu0Poly(const Mu0Poly &b)
: m_numIntervals (b.m_numIntervals),
m_H298 (b.m_H298),
m_t0_int (b.m_t0_int),
m_mu0_R_int (b.m_mu0_R_int),
m_h0_R_int (b.m_h0_R_int),
m_s0_R_int (b.m_s0_R_int),
m_cp0_R_int (b.m_cp0_R_int),
m_lowT (b.m_lowT),
m_highT (b.m_highT),
m_Pref (b.m_Pref),
m_index (b.m_index) {
}
Mu0Poly& Mu0Poly::operator=(const Mu0Poly& b) {
if (&b != this) {
m_numIntervals = b.m_numIntervals;
m_H298 = b.m_H298;
m_t0_int = b.m_t0_int;
m_mu0_R_int = b.m_mu0_R_int;
m_h0_R_int = b.m_h0_R_int;
m_s0_R_int = b.m_s0_R_int;
m_cp0_R_int = b.m_cp0_R_int;
m_lowT = b.m_lowT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
}
return *this;
}
/**
* Destructor:
*/
Mu0Poly::~Mu0Poly(){
}
SpeciesThermoInterpType *
Mu0Poly::duplMyselfAsSpeciesThermoInterpType() const {
Mu0Poly* mp = new Mu0Poly(*this);
return (SpeciesThermoInterpType *) mp;
}
doublereal Mu0Poly::minTemp() const { return m_lowT;}
doublereal Mu0Poly::maxTemp() const { return m_highT;}
doublereal Mu0Poly::refPressure() const { return m_Pref; }
/**
* updateProperties is the main workhorse program.
* Given a temperature (*tt), it calculates the thermodynamic
* functions H/RT, S_R, and cp_R, and returns the answer.
*
* Note, it returns an answer by inserting the values into the
* index position, m_index in vectors of H/RT, S_R, and cp_R.
*
*
* Input
* -------
* *tt = Temperature (Kelvin)
*
*/
void Mu0Poly::
updateProperties(const doublereal* tt, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
int j = m_numIntervals;
double T = *tt;
for (int i = 0; i < m_numIntervals; i++) {
double T2 = m_t0_int[i+1];
if (T <=T2) {
j = i;
break;
}
}
double T1 = m_t0_int[j];
double cp_Rj = m_cp0_R_int[j];
doublereal rt = 1.0/T;
cp_R[m_index] = cp_Rj;
h_RT[m_index] = rt*(m_h0_R_int[j] + (T - T1) * cp_Rj);
s_R[m_index] = m_s0_R_int[j] + cp_Rj * (log(T/T1));
}
void Mu0Poly::
updatePropertiesTemp(const doublereal T,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
updateProperties(&T, cp_R, h_RT, s_R);
}
/*
* report all of the parameters that make up this
* interpolation.
*
*
*/
void Mu0Poly::reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = MU0_INTERP;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
coeffs[0] = m_numIntervals+1;
coeffs[1] = m_H298 * GasConstant;
int j = 2;
for (int i = 0; i < m_numIntervals+1; i++) {
coeffs[j] = m_t0_int[i];
coeffs[j+1] = m_mu0_R_int[i] * GasConstant;
j += 2;
}
}
void Mu0Poly::modifyParameters(doublereal* coeffs) {
processCoeffs(coeffs);
}
/*
* Install a Mu0 polynomial thermodynamic reference state property
* parameterization for species k into a SpeciesThermo instance,
* getting the information from an XML database.
*/
void installMu0ThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* Mu0Node_ptr) {
doublereal tmin, tmax;
bool dimensionlessMu0Values = false;
const XML_Node& Mu0Node = *Mu0Node_ptr;
tmin = fpValue(Mu0Node["Tmin"]);
tmax = fpValue(Mu0Node["Tmax"]);
doublereal pref = fpValue(Mu0Node["Pref"]);
doublereal h298 = 0.0;
if (Mu0Node.hasChild("H298")) {
h298 = getFloat(Mu0Node, "H298", "actEnergy");
}
int numPoints = 1;
if (Mu0Node.hasChild("numPoints")) {
numPoints = getInteger(Mu0Node, "numPoints");
}
vector_fp cValues(numPoints);
const XML_Node *valNode_ptr =
getByTitle(const_cast<XML_Node&>(Mu0Node), "Mu0Values");
if (!valNode_ptr) {
throw CanteraError("installMu0ThermoFromXML",
"missing required while processing "
+ speciesName);
}
getFloatArray(*valNode_ptr, cValues, true, "actEnergy");
/*
* Check to see whether the Mu0's were input in a dimensionless
* form. If they were, then the assumed temperature needs to be
* adjusted from the assumed T = 273.15
*/
string uuu = (*valNode_ptr)["units"];
if (uuu == "Dimensionless") {
dimensionlessMu0Values = true;
}
int ns = cValues.size();
if (ns != numPoints) {
throw CanteraError("installMu0ThermoFromXML",
"numPoints inconsistent while processing "
+ speciesName);
}
vector_fp cTemperatures(numPoints);
const XML_Node *tempNode_ptr =
getByTitle(const_cast<XML_Node&>(Mu0Node), "Mu0Temperatures");
if (!tempNode_ptr) {
throw CanteraError("installMu0ThermoFromXML",
"missing required while processing + "
+ speciesName);
}
getFloatArray(*tempNode_ptr, cTemperatures, false);
ns = cTemperatures.size();
if (ns != numPoints) {
throw CanteraError("installMu0ThermoFromXML",
"numPoints inconsistent while processing "
+ speciesName);
}
/*
* Fix up dimensionless Mu0 values if input
*/
if (dimensionlessMu0Values) {
for (int i = 0; i < numPoints; i++) {
cValues[i] *= cTemperatures[i] / 273.15;
}
}
vector_fp c(2 + 2 * numPoints);
c[0] = numPoints;
c[1] = h298;
for (int i = 0; i < numPoints; i++) {
c[2+i*2] = cTemperatures[i];
c[2+i*2+1] = cValues[i];
}
sp.install(speciesName, k, MU0_INTERP, &c[0], tmin, tmax, pref);
}
/*
* Mu0Poly():
*
* In the constructor, we calculate and store the
* piecewise linear approximation to the thermodynamic
* functions.
*
* coeffs[0] = number of points (integer)
* 1 = H298(J/kmol)
* 2 = T1 (Kelvin)
* 3 = mu1 (J/kmol)
* 4 = T2 (Kelvin)
* 5 = mu2 (J/kmol)
* 6 = T3 (Kelvin)
* 7 = mu3 (J/kmol)
* ........
*/
void Mu0Poly::processCoeffs(const doublereal* coeffs) {
int i, iindex;
double T1, T2;
int nPoints = (int) coeffs[0];
if (nPoints < 2) {
throw CanteraError("Mu0Poly",
"nPoints must be >= 2");
}
m_numIntervals = nPoints - 1;
m_H298 = coeffs[1] / GasConstant;
int iT298 = 0;
/*
* Resize according to the number of points
*/
m_t0_int.resize(nPoints);
m_h0_R_int.resize(nPoints);
m_s0_R_int.resize(nPoints);
m_cp0_R_int.resize(nPoints);
m_mu0_R_int.resize(nPoints);
/*
* Calculate the T298 interval and make sure that
* the temperatures are strictly monotonic.
* Also distribute the data into the internal arrays.
*/
bool ifound = false;
for (i = 0, iindex = 2; i < nPoints; i++) {
T1 = coeffs[iindex];
m_t0_int[i] = T1;
m_mu0_R_int[i] = coeffs[iindex+1] / GasConstant;
if (T1 == 298.15) {
iT298 = i;
ifound = true;
}
if (i < nPoints - 1) {
T2 = coeffs[iindex+2];
if (T2 <= T1) {
throw CanteraError("Mu0Poly",
"Temperatures are not monotonic increasing");
}
}
iindex += 2;
}
if (!ifound) {
throw CanteraError("Mu0Poly",
"One temperature has to be 298.15");
}
/*
* Starting from the interval with T298, we go up
*/
doublereal mu2, s1, s2, h1, h2, cpi, deltaMu, deltaT;
T1 = m_t0_int[iT298];
doublereal mu1 = m_mu0_R_int[iT298];
m_h0_R_int[iT298] = m_H298;
m_s0_R_int[iT298] = - (mu1 - m_h0_R_int[iT298]) / T1;
for (i = iT298; i < m_numIntervals; i++) {
T1 = m_t0_int[i];
s1 = m_s0_R_int[i];
h1 = m_h0_R_int[i];
mu1 = m_mu0_R_int[i];
T2 = m_t0_int[i+1];
mu2 = m_mu0_R_int[i+1];
deltaMu = mu2 - mu1;
deltaT = T2 - T1;
cpi = (deltaMu - T1 * s1 + T2 * s1) / (deltaT - T2 * log(T2/T1));
h2 = h1 + cpi * deltaT;
s2 = s1 + cpi * log(T2/T1);
m_cp0_R_int[i] = cpi;
m_h0_R_int[i+1] = h2;
m_s0_R_int[i+1] = s2;
m_cp0_R_int[i+1] = cpi;
}
/*
* Starting from the interval with T298, we go down
*/
if (iT298 > 0) {
T2 = m_t0_int[iT298];
mu2 = m_mu0_R_int[iT298];
m_h0_R_int[iT298] = m_H298;
m_s0_R_int[iT298] = - (mu2 - m_h0_R_int[iT298]) / T2;
for (i = iT298 - 1; i >= 0; i--) {
T1 = m_t0_int[i];
mu1 = m_mu0_R_int[i];
T2 = m_t0_int[i+1];
mu2 = m_mu0_R_int[i+1];
s2 = m_s0_R_int[i+1];
h2 = m_h0_R_int[i+1];
deltaMu = mu2 - mu1;
deltaT = T2 - T1;
cpi = (deltaMu - T1 * s2 + T2 * s2) / (deltaT - T1 * log(T2/T1));
h1 = h2 - cpi * deltaT;
s1 = s2 - cpi * log(T2/T1);
m_cp0_R_int[i] = cpi;
m_h0_R_int[i] = h1;
m_s0_R_int[i] = s1;
if (i == (m_numIntervals-1)) {
m_cp0_R_int[i+1] = cpi;
}
}
}
#ifdef DEBUG_HKM_NOT
printf(" Temp mu0(J/kmol) cp0(J/kmol/K) "
" h0(J/kmol) s0(J/kmol/K) \n");
for (i = 0; i < nPoints; i++) {
printf("%12.3g %12.5g %12.5g %12.5g %12.5g\n",
m_t0_int[i], m_mu0_R_int[i] * GasConstant,
m_cp0_R_int[i]* GasConstant,
m_h0_R_int[i]* GasConstant,
m_s0_R_int[i]* GasConstant);
fflush(stdout);
}
#endif
}
}

View file

@ -0,0 +1,307 @@
/**
* @file Mu0Poly.h
* Header for a single-species standard state object derived
* from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based
* on a piecewise constant mu0 interpolation
* (see \ref spthermo and class \link Cantera::Mu0Poly Mu0Poly\endlink).
*/
/* $Author$
* $Revision$
* $Date$
*/
#ifndef CT_MU0POLY_H
#define CT_MU0POLY_H
#include "SpeciesThermoInterpType.h"
namespace Cantera {
class SpeciesThermo;
class XML_Node;
//! The %Mu0Poly class implements an interpolation of the Gibbs free energy based on a
//! piecewise constant heat capacity approximation.
/*!
* The %Mu0Poly class implements a piecewise constant heat capacity approximation.
* of the standard state chemical potential of one
* species at a single reference pressure.
* The chemical potential is input as a series of (\f$T\f$, \f$ \mu^o(T)\f$)
* values. The first temperature is assumed to be equal
* to 298.15 K; however, this may be relaxed in the future.
* This information, and an assumption of a constant
* heat capacity within each interval is enough to
* calculate all thermodynamic functions.
*
* The piece-wise constant heat capacity is calculated from the change in the chemical potential over each interval.
* Once the heat capacity is known, the other thermodynamic functions may be determined.
* The basic equation for going from temperature point 1 to temperature point 2
* are as follows for \f$ T \f$, \f$ T_1 <= T <= T_2 \f$
*
* \f[
* \mu^o(T_1) = h^o(T_1) - T_1 * s^o(T_1)
* \f]
* \f[
* \mu^o(T_2) - \mu^o(T_1) = Cp^o(T_1)(T_2 - T_1) - Cp^o(T_1)(T_2)ln(\frac{T_2}{T_1}) - s^o(T_1)(T_2 - T_1)
* \f]
* \f[
* s^o(T_2) = s^o(T_1) + Cp^o(T_1)ln(\frac{T_2}{T_1})
* \f]
* \f[
* h^o(T_2) = h^o(T_1) + Cp^o(T_1)(T_2 - T_1)
* \f]
*
* Within each interval the following relations are used. For \f$ T \f$, \f$ T_1 <= T <= T_2 \f$
*
* \f[
* \mu^o(T) = \mu^o(T_1) + Cp^o(T_1)(T - T_1) - Cp^o(T_1)(T_2)ln(\frac{T}{T_1}) - s^o(T_1)(T - T_1)
* \f]
* \f[
* s^o(T) = s^o(T_1) + Cp^o(T_1)ln(\frac{T}{T_1})
* \f]
* \f[
* h^o(T) = h^o(T_1) + Cp^o(T_1)(T - T_1)
* \f]
*
* Notes about temperature interpolation for \f$ T < T_1 \f$ and \f$ T > T_{npoints} \f$.
* These are achieved by assuming a constant heat capacity
* equal to the value in the closest temperature interval.
* No error is thrown.
*
* @note In the future, a better assumption about the heat
* capacity may be employed, so that it can be continuous.
*
* @ingroup spthermo
*/
class Mu0Poly: public SpeciesThermoInterpType {
public:
//! Constructor
Mu0Poly();
//! Constructor used in templated instantiations
/*!
*
* In the constructor, we calculate and store the
* piecewise linear approximation to the thermodynamic
* functions.
*
* @param n Species index
* @param tlow Minimum temperature
* @param thigh Maximum temperature
* @param pref reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state for species n.
* There are \f$ 2+npoints*2 \f$ coefficients, where
* \f$ npoints \f$ are the number of temperature points.
* Their identity is further broken down:
* - coeffs[0] = number of points (integer)
* - coeffs[1] = \f$ h^o(298.15 K) \f$ (J/kmol)
* - coeffs[2] = \f$ T_1 \f$ (Kelvin)
* - coeffs[3] = \f$ \mu^o(T_1) \f$ (J/kmol)
* - coeffs[4] = \f$ T_2 \f$ (Kelvin)
* - coeffs[5] = \f$ \mu^o(T_2) \f$ (J/kmol)
* - coeffs[6] = \f$ T_3 \f$ (Kelvin)
* - coeffs[7] = \f$ \mu^o(T_3) \f$ (J/kmol)
* - ........
* .
*/
Mu0Poly(int n, doublereal tlow, doublereal thigh,
doublereal pref, const doublereal* coeffs);
//! Copy constructor
Mu0Poly(const Mu0Poly &);
//! Assignment operator
Mu0Poly& operator=(const Mu0Poly&);
//! Destructor
virtual ~Mu0Poly();
//! Duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const;
//! Returns the minimum temperature that the thermo
//! parameterization is valid
virtual doublereal minTemp() const;
//! Returns the maximum temperature that the thermo
//! parameterization is valid
virtual doublereal maxTemp() const;
//! Returns the reference pressure (Pa)
virtual doublereal refPressure() const;
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return MU0_INTERP; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* Temperature Polynomial:
*
* tPoly[0] = temp (Kelvin)
*
* @param tPoly vector of temperature polynomials. Length = 1
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updateProperties(const doublereal* tPoly,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const ;
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const ;
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const;
//! Modify parameters for the standard state
/*!
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs);
protected:
/**
* Number of intervals in the interpolating linear
* approximation. Number of points is one more than the
* number of intervals.
*/
int m_numIntervals;
/**
* Value of the enthalpy at T = 298.15.
* This value is tied to the Heat of formation of
* the species at 298.15.
*/
doublereal m_H298;
/**
* Points at which the standard state chemical potential
* are given.
*/
vector_fp m_t0_int;
/**
* Mu0's are primary input data. They aren't strictly
* needed, but are kept here for convenience.
*/
vector_fp m_mu0_R_int;
//! Dimensionless Enthalpies at the temperature points
vector_fp m_h0_R_int;
//! Entropy at the points
vector_fp m_s0_R_int;
//! Heat capacity at the points
vector_fp m_cp0_R_int;
//! Limiting low temperature
doublereal m_lowT;
//! Limiting high temperature
doublereal m_highT;
//! Reference pressure
doublereal m_Pref;
//! Species index
int m_index;
private:
//! process the coefficients
/*!
* Mu0Poly():
*
* In the constructor, we calculate and store the
* piecewise linear approximation to the thermodynamic
* functions.
*
* @param coeffs coefficients. These are defined as follows:
*
* coeffs[0] = number of points (integer)
* 1 = H298(J/kmol)
* 2 = T1 (Kelvin)
* 3 = mu1 (J/kmol)
* 4 = T2 (Kelvin)
* 5 = mu2 (J/kmol)
* 6 = T3 (Kelvin)
* 7 = mu3 (J/kmol)
* ........
*/
void processCoeffs(const doublereal * coeffs);
};
//! Install a Mu0 polynomial thermodynamic reference state
/*!
* Install a Mu0 polynomial thermodynamic reference state property
* parameterization for species k into a SpeciesThermo instance,
* getting the information from an XML database.
*
* @param speciesName Name of the species
* @param sp Owning SpeciesThermo object
* @param k Species index
* @param Mu0Node_ptr Pointer to the XML element containing the
* Mu0 information.
*
* @ingroup spthermo
*/
void installMu0ThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* Mu0Node_ptr);
}
#endif

286
Cantera/src/thermo/NasaPoly1.h Executable file
View file

@ -0,0 +1,286 @@
/**
* @file NasaPoly1.h
* Header for a single-species standard state object derived
* from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based
* on the NASA temperature polynomial form applied to one temperature region
* (see \ref spthermo and class \link Cantera::NasaPoly1 NasaPoly1\endlink).
*
* This parameterization has one NASA temperature region.
*/
#ifndef CT_NASAPOLY1_H
#define CT_NASAPOLY1_H
/* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#include "global.h"
#include "SpeciesThermoInterpType.h"
namespace Cantera {
/**
* The NASA polynomial parameterization for one temperature range.
* This parameterization expresses the heat capacity as a
* fourth-order polynomial. Note that this is the form used in the
* 1971 NASA equilibrium program and by the Chemkin software
* package, but differs from the form used in the more recent NASA
* equilibrium program.
*
* Seven coefficients \f$(a_0,\dots,a_6)\f$ are used to represent
* \f$ c_p^0(T)\f$, \f$ h^0(T)\f$, and \f$ s^0(T) \f$ as
* polynomials in \f$ T \f$ :
* \f[
* \frac{c_p(T)}{R} = a_0 + a_1 T + a_2 T^2 + a_3 T^3 + a_4 T^4
* \f]
* \f[
* \frac{h^0(T)}{RT} = a_0 + \frac{a_1}{2} T + \frac{a_2}{3} T^2
* + \frac{a_3}{4} T^3 + \frac{a_4}{5} T^4 + \frac{a_5}{T}.
* \f]
* \f[
* \frac{s^0(T)}{R} = a_0\ln T + a_1 T + \frac{a_2}{2} T^2
+ \frac{a_3}{3} T^3 + \frac{a_4}{4} T^4 + a_6.
* \f]
*
* This class is designed specifically for use by class NasaThermo.
* @ingroup spthermo
*/
class NasaPoly1 : public SpeciesThermoInterpType {
public:
//! Empty constructor
NasaPoly1()
: m_lowT(0.0), m_highT (0.0),
m_Pref(0.0), m_index (0), m_coeff(array_fp(7)) {}
//! constructor used in templated instantiations
/*!
* @param n Species index
* @param tlow Minimum temperature
* @param thigh Maximum temperature
* @param pref reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
NasaPoly1(int n, doublereal tlow, doublereal thigh, doublereal pref,
const doublereal* coeffs) :
m_lowT (tlow),
m_highT (thigh),
m_Pref (pref),
m_index (n),
m_coeff (array_fp(7)) {
std::copy(coeffs, coeffs + 7, m_coeff.begin());
}
//! copy constructor
/*!
* @param b object to be copied
*/
NasaPoly1(const NasaPoly1& b) :
m_lowT (b.m_lowT),
m_highT (b.m_highT),
m_Pref (b.m_Pref),
m_index (b.m_index),
m_coeff (array_fp(7)) {
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 7,
m_coeff.begin());
}
//! assignment operator
/*!
* @param b object to be copied
*/
NasaPoly1& operator=(const NasaPoly1& b) {
if (&b != this) {
m_lowT = b.m_lowT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 7,
m_coeff.begin());
}
return *this;
}
//! Destructor
virtual ~NasaPoly1(){}
//! duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const {
NasaPoly1* np = new NasaPoly1(*this);
return (SpeciesThermoInterpType *) np;
}
//! Returns the minimum temperature that the thermo
//! parameterization is valid
virtual doublereal minTemp() const { return m_lowT;}
//! Returns the maximum temperature that the thermo
//! parameterization is valid
virtual doublereal maxTemp() const { return m_highT;}
//! Returns the reference pressure (Pa)
virtual doublereal refPressure() const { return m_Pref; }
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return NASA1; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* Temperature Polynomial:
* tt[0] = t;
* tt[1] = t*t;
* tt[2] = m_t[1]*t;
* tt[3] = m_t[2]*t;
* tt[4] = 1.0/t;
* tt[5] = std::log(t);
*
* @param tt vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updateProperties(const doublereal* tt,
doublereal* cp_R, doublereal* h_RT, doublereal* s_R) const {
doublereal ct0 = m_coeff[2]; // a0
doublereal ct1 = m_coeff[3]*tt[0]; // a1 * T
doublereal ct2 = m_coeff[4]*tt[1]; // a2 * T^2
doublereal ct3 = m_coeff[5]*tt[2]; // a3 * T^3
doublereal ct4 = m_coeff[6]*tt[3]; // a4 * T^4
doublereal cp, h, s;
cp = ct0 + ct1 + ct2 + ct3 + ct4;
h = ct0 + 0.5*ct1 + OneThird*ct2 + 0.25*ct3 + 0.2*ct4
+ m_coeff[0]*tt[4]; // last term is a5/T
s = ct0*tt[5] + ct1 + 0.5*ct2 + OneThird*ct3
+0.25*ct4 + m_coeff[1]; // last term is a6
// return the computed properties in the location in the output
// arrays for this species
cp_R[m_index] = cp;
h_RT[m_index] = h;
s_R[m_index] = s;
//writelog("NASA1: for species "+int2str(m_index)+", h_RT = "+
// fp2str(h)+"\n");
}
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const {
double tPoly[6];
tPoly[0] = temp;
tPoly[1] = temp * temp;
tPoly[2] = tPoly[1] * temp;
tPoly[3] = tPoly[2] * temp;
tPoly[4] = 1.0 / temp;
tPoly[5] = std::log(temp);
updateProperties(tPoly, cp_R, h_RT, s_R);
}
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = NASA1;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
coeffs[5] = m_coeff[0];
coeffs[6] = m_coeff[1];
for (int i = 2; i < 7; i++) {
coeffs[i-2] = m_coeff[i];
}
#ifdef WARN_ABOUT_CHANGES_FROM_VERSION_1_6
cout << "************************************************\n"
cout << "Warning: NasaPoly1::reportParameters now returns \n"
<< "the coefficient array in the same order as in\n"
<< "the input file. See file NasaPoly1.h" << endl;
cout << "************************************************\n"
#endif
}
//! Modify parameters for the standard state
/*!
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs) {
m_coeff[0] = coeffs[5];
m_coeff[1] = coeffs[6];
for (int i = 0; i < 5; i++) {
m_coeff[i+2] = coeffs[i];
}
}
protected:
//! lowest valid temperature
doublereal m_lowT;
//! highest valid temperature
doublereal m_highT;
//! standard-state pressure
doublereal m_Pref;
//! species index
int m_index;
//! array of polynomial coefficients
array_fp m_coeff;
};
}
#endif

View file

@ -0,0 +1,288 @@
/**
* @file NasaPoly2.h
* Header for a single-species standard state object derived
* from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based
* on the NASA temperature polynomial form applied to two temperature regions
* (see \ref spthermo and class \link Cantera::NasaPoly2 NasaPoly2\endlink).
*
* Two zoned Nasa polynomial parameterization
*/
/* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_NASAPOLY2_H
#define CT_NASAPOLY2_H
#include "SpeciesThermoInterpType.h"
namespace Cantera {
/**
*
*
* The NASA polynomial parameterization for two temperature ranges.
* This parameterization expresses the heat capacity as a
* fourth-order polynomial. Note that this is the form used in the
* 1971 NASA equilibrium program and by the Chemkin software
* package, but differs from the form used in the more recent NASA
* equilibrium program.
*
* Seven coefficients \f$(a_0,\dots,a_6)\f$ are used to represent
* \f$ c_p^0(T)\f$, \f$ h^0(T)\f$, and \f$ s^0(T) \f$ as
* polynomials in \f$ T \f$ :
* \f[
* \frac{c_p(T)}{R} = a_0 + a_1 T + a_2 T^2 + a_3 T^3 + a_4 T^4
* \f]
* \f[
* \frac{h^0(T)}{RT} = a_0 + \frac{a_1}{2} T + \frac{a_2}{3} T^2
* + \frac{a_3}{4} T^3 + \frac{a_4}{5} T^4 + \frac{a_5}{T}.
* \f]
* \f[
* \frac{s^0(T)}{R} = a_0\ln T + a_1 T + \frac{a_2}{2} T^2
+ \frac{a_3}{3} T^3 + \frac{a_4}{4} T^4 + a_6.
* \f]
*
* This class is designed specifically for use by the class
* GeneralSpeciesThermo.
*
* @ingroup spthermo
*/
class NasaPoly2 : public SpeciesThermoInterpType {
public:
//! Empty constructor
NasaPoly2()
: m_lowT(0.0),
m_midT(0.0),
m_highT (0.0),
m_Pref(0.0),
mnp_low(0),
mnp_high(0),
m_index(0),
m_coeff(array_fp(15)) {
}
//! Full Constructor
/*!
* @param n Species index
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
NasaPoly2(int n, doublereal tlow, doublereal thigh, doublereal pref,
const doublereal* coeffs) :
m_lowT(tlow),
m_highT(thigh),
m_Pref(pref),
mnp_low(0),
mnp_high(0),
m_index(n),
m_coeff(array_fp(15)) {
std::copy(coeffs, coeffs + 15, m_coeff.begin());
m_midT = coeffs[0];
mnp_low = new NasaPoly1(m_index, m_lowT, m_midT,
m_Pref, &m_coeff[1]);
mnp_high = new NasaPoly1(m_index, m_midT, m_highT,
m_Pref, &m_coeff[8]);
}
//! Copy Constructor
/*!
* @param b objecto to be copied.
*/
NasaPoly2(const NasaPoly2& b) :
m_lowT(b.m_lowT),
m_midT(b.m_midT),
m_highT(b.m_highT),
m_Pref(b.m_Pref),
mnp_low(0),
mnp_high(0),
m_index(b.m_index),
m_coeff(array_fp(15)) {
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 15,
m_coeff.begin());
mnp_low = new NasaPoly1(m_index, m_lowT, m_midT,
m_Pref, &m_coeff[1]);
mnp_high = new NasaPoly1(m_index, m_midT, m_highT,
m_Pref, &m_coeff[8]);
}
//! Assignment operator
/*!
* @param b objecto to be copied.
*/
NasaPoly2& operator=(const NasaPoly2& b) {
if (&b != this) {
m_lowT = b.m_lowT;
m_midT = b.m_midT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 15,
m_coeff.begin());
if (mnp_low) delete mnp_low;
if (mnp_high) delete mnp_high;
mnp_low = new NasaPoly1(m_index, m_lowT, m_midT,
m_Pref, &m_coeff[1]);
mnp_high = new NasaPoly1(m_index, m_midT, m_highT,
m_Pref, &m_coeff[8]);
}
return *this;
}
//! destructor
virtual ~NasaPoly2(){
delete mnp_low;
delete mnp_high;
}
//! duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const {
NasaPoly2* np = new NasaPoly2(*this);
return (SpeciesThermoInterpType *) np;
}
//! Returns the minimum temperature that the thermo
//! parameterization is valid
doublereal minTemp() const { return m_lowT;}
//! Returns the maximum temperature that the thermo
//! parameterization is valid
doublereal maxTemp() const { return m_highT;}
//! Returns the reference pressure (Pa)
doublereal refPressure() const { return m_Pref; }
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return NASA2; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* Temperature Polynomial:
* tt[0] = t;
* tt[1] = t*t;
* tt[2] = m_t[1]*t;
* tt[3] = m_t[2]*t;
* tt[4] = 1.0/t;
* tt[5] = std::log(t);
*
* @param tt vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
void updateProperties(const doublereal* tt,
doublereal* cp_R, doublereal* h_RT, doublereal* s_R) const {
double T = tt[0];
if (T <= m_midT) {
mnp_low->updateProperties(tt, cp_R, h_RT, s_R);
} else {
mnp_high->updateProperties(tt, cp_R, h_RT, s_R);
}
}
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
if (temp <= m_midT) {
mnp_low->updatePropertiesTemp(temp, cp_R, h_RT, s_R);
} else {
mnp_high->updatePropertiesTemp(temp, cp_R, h_RT, s_R);
}
}
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = NASA2;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
for (int i = 0; i < 15; i++) {
coeffs[i] = m_coeff[i];
}
}
protected:
//! lowest valid temperature
doublereal m_lowT;
//! Midrange temperature
doublereal m_midT;
//! Highest valid temperatre
doublereal m_highT;
//! Reference state pressure
doublereal m_Pref;
//! pointer to the NasaPoly1 object for the low temperature region.
NasaPoly1 *mnp_low;
//! pointer to the NasaPoly1 object for the high temperature region.
NasaPoly1 *mnp_high;
//! species index
int m_index;
//! array of polynomial coefficients
array_fp m_coeff;
};
}
#endif

508
Cantera/src/thermo/NasaThermo.h Executable file
View file

@ -0,0 +1,508 @@
/**
* @file NasaThermo.h
* Header for the 2 regime 7 coefficient Nasa thermodynamic
* polynomials for multiple species in a phase, derived from the
* \link Cantera::SpeciesThermo SpeciesThermo\endlink base class (see \ref spthermo and
* \link Cantera::NasaThermo NasaThermo\endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
#ifndef CT_NASATHERMO_H
#define CT_NASATHERMO_H
#include <string>
#include "SpeciesThermoMgr.h"
#include "NasaPoly1.h"
#include "speciesThermoTypes.h"
//#include "polyfit.h"
#include "global.h"
namespace Cantera {
/**
* A species thermodynamic property manager for the NASA
* polynomial parameterization with two temperature ranges.
*
* This class is designed to efficiently evaluate the properties
* of a large number of species with the NASA parameterization.
*
* The original NASA polynomial parameterization expressed the
* heat capacity as a fourth-order polynomial in temperature, with
* separate coefficients for each of two temperature ranges. (The
* newer NASA format adds coefficients for 1/T and 1/T^2, and
* allows multiple temperature ranges.) This class is designed for
* use with the original parameterization, which is used, for
* example, by the Chemkin software package.
*
* In many cases, the midpoint temperature is the same for many
* species. To take advantage of this, class NasaThermo groups
* species with a common midpoint temperature, so that checking
* which range the desired temperature is in need be done only
* once for each group.
*
* @note There is a special CTML element for entering the
* coefficients of this parameterization.
* @see importCTML
*
* @ingroup spthermo
*/
class NasaThermo : public SpeciesThermo {
public:
//! Initialized to the type of parameterization
/*!
* Note, this value is used in some template functions
*/
const int ID;
//! constructor
NasaThermo() :
ID(NASA),
m_tlow_max(0.0),
m_thigh_min(1.e30),
m_p0(-1.0),
m_ngroups(0)
{
m_t.resize(6);
}
//! destructor
virtual ~NasaThermo() {}
//! install a new species thermodynamic property
//! parameterization for one species.
/*!
*
* @param name Name of the species
* @param index The 'update' method will update the property
* values for this species
* at position i index in the property arrays.
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c vector of coefficients for the parameterization.
* - c[0] midpoint temperature
* - c[1] - c[7] coefficients for low T range
* - c[8] - c[14] coefficients for high T range
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
* @see speciesThermoTypes.h
*/
virtual void install(string name, int index, int type,
const doublereal* c,
doublereal minTemp, doublereal maxTemp,
doublereal refPressure) {
m_name[index] = name;
int imid = int(c[0]); // midpoint temp converted to integer
int igrp = m_index[imid]; // has this value been seen before?
if (igrp == 0) { // if not, prepare new group
vector<NasaPoly1> v;
m_high.push_back(v);
m_low.push_back(v);
m_tmid.push_back(c[0]);
m_index[imid] = igrp = static_cast<int>(m_high.size());
m_ngroups++;
}
m_group_map[index] = igrp;
m_posInGroup_map[index] = (int) m_low[igrp-1].size();
doublereal tlow = minTemp;
doublereal tmid = c[0];
doublereal thigh = maxTemp;
const doublereal* clow = c + 1;
vector_fp chigh(7);
copy(c + 8, c + 15, chigh.begin());
m_high[igrp-1].push_back(NasaPoly1(index, tmid, thigh,
refPressure, &chigh[0]));
m_low[igrp-1].push_back(NasaPoly1(index, tlow, tmid,
refPressure, clow));
vector_fp clu(7), chu(7);
clu[5] = clow[0];
clu[6] = clow[1];
copy(clow+2, clow+7, clu.begin());
chu[5] = chigh[0];
chu[6] = chigh[1];
copy(chigh.begin()+2, chigh.begin()+7, chu.begin());
checkContinuity(name, tmid, &clu[0], &chu[0]);
if (tlow > m_tlow_max) m_tlow_max = tlow;
if (thigh < m_thigh_min) m_thigh_min = thigh;
if ((int) m_tlow.size() < index + 1) {
m_tlow.resize(index + 1, tlow);
m_thigh.resize(index + 1, thigh);
}
m_tlow[index] = tlow;
m_thigh[index] = thigh;
if (m_p0 < 0.0) {
m_p0 = refPressure;
} else if (fabs(m_p0 - refPressure) > 0.1) {
string logmsg = " WARNING NasaThermo: New Species, " + name + ", has a different reference pressure, "
+ fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n";
writelog(logmsg);
logmsg = " This may become a fatal error in the future \n";
writelog(logmsg);
}
m_p0 = refPressure;
}
//! Like update(), but only updates the single species k.
/*!
* @param k species index
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*
*/
virtual void update_one(int k, doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
m_t[0] = t;
m_t[1] = t*t;
m_t[2] = m_t[1]*t;
m_t[3] = m_t[2]*t;
m_t[4] = 1.0/t;
m_t[5] = log(t);
int grp = m_group_map[k];
int pos = m_posInGroup_map[k];
const vector<NasaPoly1> &mlg = m_low[grp-1];
const NasaPoly1 *nlow = &(mlg[pos]);
doublereal tmid = nlow->maxTemp();
if (t < tmid) {
nlow->updateProperties(&m_t[0], cp_R, h_RT, s_R);
} else {
const vector<NasaPoly1> &mhg = m_high[grp-1];
const NasaPoly1 *nhigh = &(mhg[pos]);
nhigh->updateProperties(&m_t[0], cp_R, h_RT, s_R);
}
}
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
int i;
// load functions of temperature into m_t vector
m_t[0] = t;
m_t[1] = t*t;
m_t[2] = m_t[1]*t;
m_t[3] = m_t[2]*t;
m_t[4] = 1.0/t;
m_t[5] = log(t);
// iterate over the groups
vector<NasaPoly1>::const_iterator _begin, _end;
for (i = 0; i != m_ngroups; i++) {
if (t > m_tmid[i]) {
_begin = m_high[i].begin();
_end = m_high[i].end();
}
else {
_begin = m_low[i].begin();
_end = m_low[i].end();
}
for (; _begin != _end; ++_begin)
_begin->updateProperties(&m_t[0], cp_R, h_RT, s_R);
}
}
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k=-1) const {
if (k < 0)
return m_tlow_max;
else
return m_tlow[k];
}
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k Species index
*/
virtual doublereal maxTemp(int k=-1) const {
if (k < 0)
return m_thigh_min;
else
return m_thigh[k];
}
//! The reference-state pressure for species k.
/*!
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k Species index
*/
virtual doublereal refPressure(int k = -1) const {
return m_p0;
}
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param index Species index
*/
virtual int reportType(int index) const { return NASA; }
/*!
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
*
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* For the NASA object, there are 15 coefficients.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
type = reportType(index);
if (type == NASA) {
int grp = m_group_map[index];
int pos = m_posInGroup_map[index];
const vector<NasaPoly1> &mlg = m_low[grp-1];
const vector<NasaPoly1> &mhg = m_high[grp-1];
const NasaPoly1 *lowPoly = &(mlg[pos]);
const NasaPoly1 *highPoly = &(mhg[pos]);
int itype = NASA;
doublereal tmid = lowPoly->maxTemp();
c[0] = tmid;
int n;
double ttemp;
lowPoly->reportParameters(n, itype, minTemp, ttemp, refPressure,
c + 1);
if (n != index) {
throw CanteraError(" ", "confused");
}
if (itype != NASA1) {
throw CanteraError(" ", "confused");
}
highPoly->reportParameters(n, itype, ttemp, maxTemp, refPressure,
c + 8);
if (n != index) {
throw CanteraError(" ", "confused");
}
if (itype != NASA1) {
throw CanteraError(" ", "confused");
}
} else {
throw CanteraError(" ", "confused");
}
}
//! Modify parameters for the standard state
/*!
* This utility function modifies the array of coefficients.
* The array is the same as that returned by reportParams, so
* a call can first be made to reportParams to populate the
* array, and then modifyParams can be called to alter
* selected values. For the NASA object, there are 15
* coefficients.
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c) {
int type = reportType(index);
if (type == NASA) {
int grp = m_group_map[index];
int pos = m_posInGroup_map[index];
vector<NasaPoly1> &mlg = m_low[grp-1];
vector<NasaPoly1> &mhg = m_high[grp-1];
NasaPoly1 *lowPoly = &(mlg[pos]);
NasaPoly1 *highPoly = &(mhg[pos]);
doublereal tmid = lowPoly->maxTemp();
if (c[0] != tmid) {
throw CanteraError(" ", "Tmid cannot be changed");
}
lowPoly->modifyParameters(c + 1);
highPoly->modifyParameters(c + 8);
checkContinuity(m_name[index], c[0], c + 1, c + 8);
} else {
throw CanteraError(" ", "confused");
}
}
protected:
//! Vector of vector of NasaPoly1's for the high temp region.
/*!
* This is the high temp region representation.
* The first Length is equal to the number of groups.
* The second vector is equal to the number of species
* in that particular group.
*/
vector<vector<NasaPoly1> > m_high;
//! Vector of vector of NasaPoly1's for the low temp region.
/*!
* This is the low temp region representation.
* The first Length is equal to the number of groups.
* The second vector is equal to the number of species
* in that particular group.
*/
vector<vector<NasaPoly1> > m_low;
//! Map between the midpoint temperature, as an int, to the group number
/*!
* Length is equal to the number of groups. Only used in the setup.
*/
map<int, int> m_index;
//! Vector of log temperature limits
/*!
* Length is equal to the number of groups.
*/
vector_fp m_tmid;
//! Maximum value of the low temperature limit
doublereal m_tlow_max;
//! Minimum value of the high temperature limit
doublereal m_thigh_min;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of species
*/
vector_fp m_tlow;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of species
*/
vector_fp m_thigh;
//! Reference pressure (Pa)
/*!
* all species must have the same reference pressure.
*/
doublereal m_p0;
//! number of groups
int m_ngroups;
//! Vector of temperature polynomials
mutable vector_fp m_t;
/*!
* This map takes as its index, the species index in the phase.
* It returns the group index, where the temperature polynomials
* for that species are stored. group indecises start at 1,
* so a decrement is always performed to access vectors.
*/
mutable map<int, int> m_group_map;
/*!
* This map takes as its index, the species index in the phase.
* It returns the position index within the group, where the
* temperature polynomials for that species are storred.
*/
mutable map<int, int> m_posInGroup_map;
//! Species name as a function of the species index
mutable map<int, string> m_name;
private:
//! see SpeciesThermoFactory.cpp for the definition
/*!
* @param name string name of species
* @param tmid Mid temperature, between the two temperature regions
* @param clow coefficients for lower temperature region
* @param chigh coefficients for higher temperature region
*/
void checkContinuity(std::string name, double tmid, const doublereal* clow,
doublereal* chigh);
//! for internal use by checkContinuity
/*!
* @param t temperature
* @param c coefficient array
*/
doublereal enthalpy_RT(double t, const doublereal* c) {
return c[0] + 0.5*c[1]*t + OneThird*c[2]*t*t
+ 0.25*c[3]*t*t*t + 0.2*c[4]*t*t*t*t
+ c[5]/t;
}
//! for internal use by checkContinuity
/*!
* @param t temperature
* @param c coefficient array
*/
doublereal entropy_R(double t, const doublereal* c) {
return c[0]*log(t) + c[1]*t + 0.5*c[2]*t*t
+ OneThird*c[3]*t*t*t + 0.25*c[4]*t*t*t*t
+ c[6];
}
};
}
#endif

View file

@ -17,7 +17,8 @@
#include "xml.h"
#include "ctml.h"
#include "PDSS.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include "SpeciesThermo.h"
#include "ThermoPhase.h"

328
Cantera/src/thermo/Phase.cpp Executable file
View file

@ -0,0 +1,328 @@
/**
* @file Phase.cpp
* Definition file for class, Phase, which contains functions for setting the
* state of a phase, and for referencing species by name
* (see \ref phases and class \link Cantera::Phase Phase\endlink).
*/
// Copyright 2001 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "Phase.h"
#include "vec_functions.h"
#include "ctexceptions.h"
using namespace std;
namespace Cantera {
/*
* Copy Constructor
*
* This function just does the default initialization, and
* then calls the assignment operator.
*/
Phase::Phase(const Phase &right) :
m_kk(-1),
m_ndim(3),
m_index(-1),
m_xml(new XML_Node("phase")),
m_id("<phase>"),
m_name("")
{
/*
* Call the assignment operator.
*/
*this = operator=(right);
}
/*
* Assignment operator
*
* This operation is sort of complicated. We have to
* call the assignment operator for the Constituents and
* State operators that Phase inherits from. Then,
* we have to copy our own data, making sure to do a
* deep copy on the XML_Node data owned by this object.
*/
const Phase &Phase::operator=(const Phase &right) {
/*
* Check for self assignment.
*/
if (this == &right) return *this;
/*
* Now call the inherited-classes assignment operators.
*/
(void) Constituents::operator=(right);
(void) State::operator=(right);
/*
* Handle its own data
*/
m_kk = right.m_kk;
m_ndim = right.m_ndim;
m_index = right.m_index;
m_data = right.m_data;
/*
* This is a little complicated. -> Because we delete m_xml
* in the destructor, we own m_xml completely, and we need
* to have our own individual copies of the XML data tree
* in each object
*/
m_xml = new XML_Node(*(right.m_xml));
m_id = right.m_id;
m_name = right.m_name;
return *this;
}
void Phase::saveState(vector_fp& state) const {
state.resize(nSpecies() + 2);
saveState(state.size(),&(state[0]));
}
void Phase::saveState(int lenstate, doublereal* state) const {
state[0] = temperature();
state[1] = density();
getMassFractions(state + 2);
}
void Phase::restoreState(const vector_fp& state) {
restoreState(state.size(),&state[0]);
}
void Phase::restoreState(int lenstate, const doublereal* state) {
if (int(lenstate) >= nSpecies() + 2) {
setMassFractions_NoNorm(state + 2);
setTemperature(state[0]);
setDensity(state[1]);
}
else {
throw ArraySizeError("Phase::restoreState",
lenstate,nSpecies()+2);
}
}
void Phase::setMoleFractionsByName(compositionMap& xMap) {
int kk = nSpecies();
doublereal x;
vector_fp mf(kk, 0.0);
for (int k = 0; k < kk; k++) {
x = xMap[speciesName(k)];
if (x > 0.0) mf[k] = x;
}
setMoleFractions(&mf[0]);
}
void Phase::setMoleFractionsByName(const std::string& x) {
compositionMap xx;
int kk = nSpecies();
for (int k = 0; k < kk; k++) {
xx[speciesName(k)] = -1.0;
}
parseCompString(x, xx);
setMoleFractionsByName(xx);
//int kk = nSpecies();
//vector_fp mf(kk);
//for (int k = 0; k < kk; k++) {
// mf[k] = xx[speciesName(k)];
//}
//setMoleFractions(mf.begin());
}
void Phase::setMassFractionsByName(compositionMap& yMap) {
int kk = nSpecies();
doublereal y;
vector_fp mf(kk, 0.0);
for (int k = 0; k < kk; k++) {
y = yMap[speciesName(k)];
if (y > 0.0) mf[k] = y;
}
setMassFractions(&mf[0]);
}
void Phase::setMassFractionsByName(const std::string& y) {
compositionMap yy;
int kk = nSpecies();
for (int k = 0; k < kk; k++) {
yy[speciesName(k)] = -1.0;
}
parseCompString(y, yy);
setMassFractionsByName(yy);
}
/** Set the temperature (K), density (kg/m^3), and mole fractions. */
void Phase::setState_TRX(doublereal t, doublereal dens,
const doublereal* x) {
setMoleFractions(x); setTemperature(t); setDensity(dens);
}
void Phase::setState_TNX(doublereal t, doublereal n,
const doublereal* x) {
setMoleFractions(x); setTemperature(t); setMolarDensity(n);
}
/** Set the temperature (K), density (kg/m^3), and mole fractions. */
void Phase::setState_TRX(doublereal t, doublereal dens,
compositionMap& x) {
setMoleFractionsByName(x); setTemperature(t); setDensity(dens);
}
/** Set the temperature (K), density (kg/m^3), and mass fractions. */
void Phase::setState_TRY(doublereal t, doublereal dens,
const doublereal* y) {
setMassFractions(y); setTemperature(t); setDensity(dens);
}
/** Set the temperature (K), density (kg/m^3), and mass fractions. */
void Phase::setState_TRY(doublereal t, doublereal dens,
compositionMap& y) {
setMassFractionsByName(y); setTemperature(t); setDensity(dens);
}
/** Set the temperature (K) and density (kg/m^3) */
void Phase::setState_TR(doublereal t, doublereal rho) {
setTemperature(t); setDensity(rho);
}
/** Set the temperature (K) and mole fractions. */
void Phase::setState_TX(doublereal t, doublereal* x) {
setTemperature(t); setMoleFractions(x);
}
/** Set the temperature (K) and mass fractions. */
void Phase::setState_TY(doublereal t, doublereal* y) {
setTemperature(t); setMassFractions(y);
}
/** Set the density (kg/m^3) and mole fractions. */
void Phase::setState_RX(doublereal rho, doublereal* x) {
setMoleFractions(x); setDensity(rho);
}
/** Set the density (kg/m^3) and mass fractions. */
void Phase::setState_RY(doublereal rho, doublereal* y) {
setMassFractions(y); setDensity(rho);
}
/*
* Copy the vector of molecular weights into vector weights.
*/
void Phase::getMolecularWeights(vector_fp& weights) {
const array_fp& mw = Constituents::molecularWeights();
if (weights.size() < mw.size()) weights.resize(mw.size());
copy(mw.begin(), mw.end(), weights.begin());
}
/*
* Copy the vector of molecular weights into array weights.
* @deprecated
*/
void Phase::getMolecularWeights(int iwt, doublereal* weights) {
const array_fp& mw = Constituents::molecularWeights();
copy(mw.begin(), mw.end(), weights);
}
/*
* Copy the vector of molecular weights into array weights.
*/
void Phase::getMolecularWeights(doublereal* weights) {
const array_fp& mw = Constituents::molecularWeights();
copy(mw.begin(), mw.end(), weights);
}
/**
* Return a const reference to the internal vector of
* molecular weights.
*/
const array_fp& Phase::molecularWeights() {
return Constituents::molecularWeights();
}
/**
* Get the mole fractions by name.
*/
void Phase::getMoleFractionsByName(compositionMap& x) {
x.clear();
int kk = nSpecies();
for (int k = 0; k < kk; k++) {
x[speciesName(k)] = State::moleFraction(k);
}
}
doublereal Phase::moleFraction(int k) const {
return State::moleFraction(k);
}
doublereal Phase::moleFraction(std::string name) const {
int iloc = speciesIndex(name);
if (iloc >= 0) return State::moleFraction(iloc);
else return 0.0;
}
doublereal Phase::massFraction(int k) const {
return State::massFraction(k);
}
doublereal Phase::massFraction(std::string name) const {
int iloc = speciesIndex(name);
if (iloc >= 0) return massFractions()[iloc];
else return 0.0;
}
doublereal Phase::chargeDensity() const {
int k;
int nsp = nSpecies();
doublereal cdens = 0.0;
for (k = 0; k < nsp; k++)
cdens += charge(k)*State::moleFraction(k);
cdens *= Faraday;
return cdens;
}
// void Phase::update_T(int n) const {
// m_T_updater.update(n);
// }
// void Phase::update_C(int n) const {
// m_C_updater.update(n);
// }
/**
* Finished adding species, prepare to use them for calculation
* of mixture properties.
*/
void Phase::freezeSpecies() {
Constituents::freezeSpecies();
init(Constituents::molecularWeights());
int kk = nSpecies();
int nv = kk + 2;
m_data.resize(nv,0.0);
m_data[0] = 300.0;
m_data[1] = 0.001;
m_data[2] = 1.0;
//setState_TRY(300.0, density(), &m_data[2]);
m_kk = nSpecies();
}
bool Phase::ready() const {
return (m_kk > 0 && Constituents::ready() && State::ready());
}
// int Phase::installUpdater_T(Updater* u) {
// return m_T_updater.install(u);
// }
// int Phase::installUpdater_C(Updater* u) {
// return m_C_updater.install(u);
// }
}

512
Cantera/src/thermo/Phase.h Executable file
View file

@ -0,0 +1,512 @@
/**
* @file Phase.h
* Header file for class, Phase, which contains functions for setting the
* state of a phase, and for referencing species by name, and also contains text for the module phases
* (see \ref phases and class \link Cantera::Phase Phase\endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_PHASE_H
#define CT_PHASE_H
#include "State.h"
#include "Constituents.h"
#include "vec_functions.h"
#include "ctml.h"
using namespace ctml;
namespace Cantera {
/**
* @defgroup phases Phases of Matter
*
* These classes are used to represent the composition and state of a
* single phase of matter.
* Together these classes form the basis for describing the species and
* element compositions of a phase as well as the stoichiometry
* of each species, and for describing the current state of the
* phase. They do not in themselves contain Thermodynamic equation of
* state information. However, they do comprise all of the necessary
* background functionality to support thermodynamic calculations, and the
* class ThermoPhase inherits from the class Phase (see \ref thermoprops).
*
* Class Elements manages the elements that are part of a
* chemistry specification for a phase. This class may support calculations
* employing Multiple phases. In this case, a single Elements object may
* be shared by more than one Constituents class. Reactions between
* the phases may then be described using stoichiometry base on the
* same Elements class object.
*
* The member functions of class %Elements return information about the elements described
* in a particular instantiation of the class.
*
* Class %Constituents is designed to provide information
* about the elements and species in a phase - names, index
* numbers (location in arrays), atomic or molecular weights,
* etc. No computations are performed by the methods of this
* class. The set of elements must include all those that compose
* the species, but may include additional elements.
*
* %Constituents contains a pointer to the Elements object, and
* it contains wrapper functions for all of the functionality
* of the %Elements object, i.e., atomic weights, number and identity
* of the elements. %Elements may be added to a phase by using
* the function Constituents::addUniqueElement(). The %Elements
* object may be shared amongst different Phases.
*
* %Constituents also contains utilities retrieving the index of
* a species in the phase given its name, Constituents::speciesIndex().
*
* Class State manages the independent variables of temperature, mass density,
* and species mass/mole fraction that define the thermodynamic
* state.
*
* Class %State stores just enough information about a
* multicomponent solution to specify its intensive thermodynamic
* state. It stores values for the temperature, mass density, and
* an array of species mass fractions. It also stores an array of
* species molecular weights, which are used to convert between
* mole and mass representations of the composition. These are the
* \e only properties of the species that class %State knows about.
*
* Class %State is not usually used directly in application
* programs. Its primary use is as a base class for class
* Phase. Class %State has no virtual methods, and none of its
* methods are meant to be overloaded. However, this is one exception.
* If the phase is incompressible, then the density must be replaced
* by the pressure as the independent variable. In this case, functions
* such as State::setMassFractions() within the class %State must actually now
* calculate the density (at constant <I>T</I> and <I>P</I>) instead of leaving
* it alone as befits an independent variable. Therefore, these types
* of functions are virtual functions and need to be overloaded
* for incompressible phases. Note, for nearly incompressible phases
* (or phases which utilize standard states based on a <I>T</I> and <I>P</I>) this
* change in independent variables may be advantageous as well,
* and these functions in %State need to overload as well so that the
* storred density within State doesn't become out of date.
*
* Class Phase derives from both clases
* Constituents and State. In addition to the methods of those two
* classes, it implements methods that allow referencing a species
* by name. And, it contains a lot of utility functions that will
* set the %State of the phase in its entirety, by first setting
* the composition, then the temperature and then the density.
* An example of this is the function,
* Phase::setState_TRY(doublereal t, doublereal dens, const doublereal* y).
*
* Class Phase contains method for saving and restoring the
* full internal states of each phase. These are called Phase::saveState()
* and Phase::restoreState(). These functions operate on a state
* vector, which is in general of length (2 + nSpecies()). The first
* two entries of the state vector is temperature and density.
*
*/
//! Base class for phases of mater
/*!
* Base class for phases of matter. Class Phase derives from both
* Constituents and State. In addition to the methods of those two
* classes, it implements methods that allow referencing a species
* by name.
*
* Class Phase derives from both clases
* Constituents and State. In addition to the methods of those two
* classes, it implements methods that allow referencing a species
* by name. And, it contains a lot of utility functions that will
* set the %State of the phase in its entirety, by first setting
* the composition, then the temperature and then the density.
* An example of this is the function,
* Phase::setState_TRY(doublereal t, doublereal dens, const doublereal* y).
*
* Class Phase contains method for saving and restoring the
* full internal states of each phase. These are called Phase::saveState()
* and Phase::restoreState(). These functions operate on a state
* vector, which is in general of length (2 + nSpecies()). The first
* two entries of the state vector is temperature and density.
*
*
* @todo
* Make the concept of saving state vectors more general, so that
* it can handle other cases where there are additional internal state
* variables, such as the voltage, a potential energy, or a strain field.
*
* @ingroup phases
*/
class Phase : public Constituents, public State {
public:
/// Default constructor.
Phase() : m_kk(-1), m_ndim(3), m_index(-1),
m_xml(new XML_Node("phase")),
m_id("<phase>"), m_name("") {}
/// Destructor.
virtual ~Phase(){
delete m_xml;
m_xml = 0;
}
/**
* Copy Constructor
*
* @param c Reference to the class to be used in the copy
*/
Phase(const Phase &c);
/**
* Assignment operator
*
* @param c Reference to the class to be used in the copy
*/
const Phase &operator=(const Phase &c);
//! Returns a reference to the XML_Node storred for the phase
/*!
* The XML_Node for the phase contains all of the input data used
* to set up the model for the phase, during its initialization.
*/
XML_Node& xml() { return *m_xml; }
//! Return the string id for the phase
std::string id() const { return m_id; }
//! Set the string id for the phase
/*!
* @param id String id of the phase
*/
void setID(std::string id) {m_id = id;}
//! Return the name of the phase
std::string name() const { return m_name; }
//! Sets the string name for the phase
/*!
* @param nm String name of the phase
*/
void setName(std::string nm) { m_name = nm; }
//! Returns the index of the phase
int index() const { return m_index; }
//! Sets the index of the phase
/*!
* @param m Integer index of the phase
*/
void setIndex(int m) { m_index = m; }
//! Save the current internal state of the phase
/*!
* Write to vector 'state' the current internal state.
*
* @param state output vector. Will be resized to nSpecies() + 2 on return.
*/
void saveState(vector_fp& state) const;
//! Write to array 'state' the current internal state.
/*!
* @param lenstate length of the state array. Must be >= nSpecies() + 2
* @param state output vector. Must be of length nSpecies() + 2 or
* greater.
*/
void saveState(int lenstate, doublereal* state) const;
//!Restore a state saved on a previous call to saveState.
/*!
* @param state State vector containing the previously saved state.
*/
void restoreState(const vector_fp& state);
//! Restore the state of the phase from a previously saved state vector.
/*!
* @param lenstate Length of the state vector
* @param state Vector of state conditions.
*/
void restoreState(int lenstate, const doublereal* state);
/**
* Set the species mole fractions by name.
* @param xMap map from species names to mole fraction values.
* Species not listed by name in \c xMap are set to zero.
*/
void setMoleFractionsByName(compositionMap& xMap);
//! Set the mole fractions of a group of species by name
/*!
* The string x is in the form of a composition map
* Species which are not listed by name in the composition
* map are set to zero.
*
* @param x string x in the form of a composition map
*/
void setMoleFractionsByName(const std::string& x);
/**
* Set the species mass fractions by name.
* @param yMap map from species names to mass fraction values.
* Species not listed by name in \c yMap are set to zero.
*/
void setMassFractionsByName(compositionMap& yMap);
//! Set the species mass fractions by name.
/*!
* Species not listed by name in \c x are set to zero.
*
* @param x String containing a composition map
*/
void setMassFractionsByName(const std::string& x);
//! Set the internally storred temperature (K), density, and mole fractions.
/*!
* Note, the mole fractions are always set first, before the density
*
* @param t Temperature in kelvin
* @param dens Density (kg/m^3)
* @param x vector of species mole fractions.
* Length is equal to m_kk
*/
void setState_TRX(doublereal t, doublereal dens, const doublereal* x);
//! Set the internally storred temperature (K), density, and mole fractions.
/*!
* Note, the mole fractions are always set first, before the density
*
* @param t Temperature in kelvin
* @param dens Density (kg/m^3)
* @param x Composition Map containing the mole fractions.
* Species not included in the map are assumed to have
* a zero mole fraction.
*/
void setState_TRX(doublereal t, doublereal dens, compositionMap& x);
//! Set the internally storred temperature (K), density, and mass fractions.
/*!
* Note, the mass fractions are always set first, before the density
*
* @param t Temperature in kelvin
* @param dens Density (kg/m^3)
* @param y vector of species mass fractions.
* Length is equal to m_kk
*/
void setState_TRY(doublereal t, doublereal dens, const doublereal* y);
//! Set the internally storred temperature (K), density, and mass fractions.
/*!
* Note, the mass fractions are always set first, before the density
*
* @param t Temperature in kelvin
* @param dens Density (kg/m^3)
* @param y Composition Map containing the mass fractions.
* Species not included in the map are assumed to have
* a zero mass fraction.
*/
void setState_TRY(doublereal t, doublereal dens, compositionMap& y);
//! Set the internally storred temperature (K), molar density (kmol/m^3), and mole fractions.
/*!
* Note, the mole fractions are always set first, before the molar density
*
* @param t Temperature in kelvin
* @param n molar density (kmol/m^3)
* @param x vector of species mole fractions.
* Length is equal to m_kk
*/
void setState_TNX(doublereal t, doublereal n, const doublereal* x);
//! Set the internally storred temperature (K) and density (kg/m^3)
/*!
* @param t Temperature in kelvin
* @param rho Density (kg/m^3)
*/
void setState_TR(doublereal t, doublereal rho);
//! Set the internally storred temperature (K) and mole fractions.
/*!
* @param t Temperature in kelvin
* @param x vector of species mole fractions.
* Length is equal to m_kk
*/
void setState_TX(doublereal t, doublereal* x);
//! Set the internally storred temperature (K) and mass fractions.
/*!
* @param t Temperature in kelvin
* @param y vector of species mass fractions.
* Length is equal to m_kk
*/
void setState_TY(doublereal t, doublereal* y);
//! Set the density (kg/m^3) and mole fractions.
/*!
* @param rho Density (kg/m^3)
* @param x vector of species mole fractions.
* Length is equal to m_kk
*/
void setState_RX(doublereal rho, doublereal* x);
//! Set the density (kg/m^3) and mass fractions.
/*!
* @param rho Density (kg/m^3)
* @param y vector of species mass fractions.
* Length is equal to m_kk
*/
void setState_RY(doublereal rho, doublereal* y);
/**
* Copy the vector of molecular weights into vector weights.
*
* @param weights Output vector of molecular weights (kg/kmol)
*/
void getMolecularWeights(vector_fp& weights);
/**
* Copy the vector of molecular weights into array weights.
*
* @param iwt Unused.
* @param weights Output array of molecular weights (kg/kmol)
*
* @deprecated
*/
void getMolecularWeights(int iwt, doublereal* weights);
/**
* Copy the vector of molecular weights into array weights.
*
* @param weights Output array of molecular weights (kg/kmol)
*/
void getMolecularWeights(doublereal* weights);
/**
* Return a const reference to the internal vector of
* molecular weights.
*/
const array_fp& molecularWeights();
/**
* Get the mole fractions by name.
*
* @param x Output composition map containing the
* species mole fractions.
*/
void getMoleFractionsByName(compositionMap& x);
//! Return the mole fraction of a single species
/*!
* @param k String name of the species
*
* @return Mole fraction of the species
*/
doublereal moleFraction(int k) const;
//! Return the mole fraction of a single species
/*!
* @param name String name of the species
*
* @return Mole fraction of the species
*/
doublereal moleFraction(std::string name) const;
//! Return the mass fraction of a single species
/*!
* @param k String name of the species
*
* @return Mass Fraction of the species
*/
doublereal massFraction(int k) const;
//! Return the mass fraction of a single species
/*!
* @param name String name of the species
*
* @return Mass Fraction of the species
*/
doublereal massFraction(std::string name) const;
/**
* Charge density [C/m^3].
*/
doublereal chargeDensity() const;
/// Returns the number of spatial dimensions (1, 2, or 3)
int nDim() {return m_ndim;}
//! Set the number of spatial dimensions (1, 2, or 3)
/*!
* The number of spatial dimensions is used for vector involving
* directions.
*
* @param ndim Input number of dimensions.
*/
void setNDim(int ndim) {m_ndim = ndim;}
/**
* Finished adding species, prepare to use them for calculation
* of mixture properties.
*/
virtual void freezeSpecies();
virtual bool ready() const;
protected:
/**
* m_kk = Number of species in the phase. @internal m_kk is a
* member of both the State and Constituents classes.
* Therefore, to avoid multiple inheritance problems, we need
* to restate it in here, so that the declarations in the two
* base classes become hidden.
*/
int m_kk;
/**
* m_ndim is the dimensionality of the phase. Volumetric
* phases have dimensionality 3 and surface phases have
* dimensionality 2.
*/
int m_ndim;
/**
* m_index is the index of the phase
*
*/
int m_index;
private:
//! This stores the initial state of the system
/*!
* @deprecated
* This doesn't seem to be used much anymore.
*/
vector_fp m_data;
//! Pointer to the XML node containing the XML info for this phase
XML_Node* m_xml;
//! ID of the phase.
/*!
* This is the value of the ID attribute of the XML phase node.
*/
std::string m_id;
//! Name of the phase.
/*!
* Initially, this is the value of the ID attribute of the XML phase node.
*/
std::string m_name;
};
//! typedef for the base Phase class
typedef Phase phase_t;
}
#endif

View file

@ -0,0 +1,253 @@
/**
* @file PureFluidPhase.cpp
* Definitions for a ThermoPhase object for a pure fluid phase consisting of gas, liquid, mixed-gas-liquid
* and supercritical fluid (see \ref thermoprops
* and class \link Cantera::PureFluidPhase PureFluidPhase\endlink).
*/
/*
* $Id$
*/
#include "xml.h"
#include "PureFluidPhase.h"
#include "../../../ext/tpx/Sub.h"
#include "../../../ext/tpx/utils.h"
namespace Cantera {
PureFluidPhase::~PureFluidPhase() { delete m_sub; }
void PureFluidPhase::
initThermo() {
if (m_sub) delete m_sub;
m_sub = tpx::GetSub(m_subflag);
if (m_sub == 0) {
throw CanteraError("PureFluidPhase::initThermo",
"could not create new substance object.");
}
m_mw = m_sub->MolWt();
m_weight[0] = m_mw;
setMolecularWeight(0,m_mw);
double one = 1.0;
setMoleFractions(&one);
double cp0_R, h0_RT, s0_R, T0, p;
T0 = 298.15;
if (T0 < m_sub->Tcrit()) {
m_sub->Set(tpx::TX, T0, 1.0);
p = 0.01*m_sub->P();
}
else {
p = 0.001*m_sub->Pcrit();
}
m_sub->Set(tpx::TP, T0, p);
m_spthermo->update_one(0, T0, &cp0_R, &h0_RT, &s0_R);
double s_R = s0_R - log(p/refPressure());
m_sub->setStdState(h0_RT*GasConstant*298.15/m_mw,
s_R*GasConstant/m_mw, T0, p);
if (m_verbose) {
writelog("PureFluidPhase::initThermo: initialized phase "
+id()+"\n");
}
}
void PureFluidPhase::
setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","PureFluid");
m_subflag = atoi(eosdata["fluid_type"].c_str());
if (m_subflag < 0)
throw CanteraError("PureFluidPhase::setParametersFromXML",
"missing or negative substance flag");
}
doublereal PureFluidPhase::
enthalpy_mole() const {
setTPXState();
doublereal h = m_sub->h() * m_mw;
check(h);
return h;
}
doublereal PureFluidPhase::
intEnergy_mole() const {
setTPXState();
doublereal u = m_sub->u() * m_mw;
check(u);
return u;
}
doublereal PureFluidPhase::
entropy_mole() const {
setTPXState();
doublereal s = m_sub->s() * m_mw;
check(s);
return s;
}
doublereal PureFluidPhase::
gibbs_mole() const {
setTPXState();
doublereal g = m_sub->g() * m_mw;
check(g);
return g;
}
doublereal PureFluidPhase::
cp_mole() const {
setTPXState();
doublereal cp = m_sub->cp() * m_mw;
check(cp);
return cp;
}
doublereal PureFluidPhase::
cv_mole() const {
setTPXState();
doublereal cv = m_sub->cv() * m_mw;
check(cv);
return cv;
}
doublereal PureFluidPhase::
pressure() const {
setTPXState();
doublereal p = m_sub->P();
check(p);
return p;
}
void PureFluidPhase::
setPressure(doublereal p) {
Set(tpx::TP, temperature(), p);
setDensity(1.0/m_sub->v());
check();
}
void PureFluidPhase::Set(int n, double x, double y) const {
try {
m_sub->Set(n, x, y);
}
catch(tpx::TPX_Error) {
reportTPXError();
}
}
void PureFluidPhase::setTPXState() const {
Set(tpx::TV, temperature(), 1.0/density());
}
void PureFluidPhase::check(doublereal v) const {
if (m_sub->Error() || v == tpx::Undef) {
throw CanteraError("PureFluidPhase",string(tpx::errorMsg(
m_sub->Error())));
}
}
void PureFluidPhase::reportTPXError() const {
string msg = tpx::TPX_Error::ErrorMessage;
string proc = "tpx::"+tpx::TPX_Error::ErrorProcedure;
throw CanteraError(proc,msg);
}
doublereal PureFluidPhase::isothermalCompressibility() const {
return m_sub->isothermalCompressibility();
}
doublereal PureFluidPhase::thermalExpansionCoeff() const {
return m_sub->thermalExpansionCoeff();
}
tpx::Substance& PureFluidPhase::TPX_Substance() { return *m_sub; }
/// critical temperature
doublereal PureFluidPhase::critTemperature() const { return m_sub->Tcrit(); }
/// critical pressure
doublereal PureFluidPhase::critPressure() const { return m_sub->Pcrit(); }
/// critical density
doublereal PureFluidPhase::critDensity() const { return 1.0/m_sub->Vcrit(); }
/// saturation temperature
doublereal PureFluidPhase::satTemperature(doublereal p) const {
try {
doublereal ts = m_sub->Tsat(p);
return ts;
}
catch(tpx::TPX_Error) {
reportTPXError();
return -1.0;
}
}
void PureFluidPhase::setState_HP(doublereal h, doublereal p,
doublereal tol) {
Set(tpx::HP, h, p);
setState_TR(m_sub->Temp(), 1.0/m_sub->v());
check();
}
void PureFluidPhase::setState_UV(doublereal u, doublereal v,
doublereal tol) {
Set(tpx::UV, u, v);
setState_TR(m_sub->Temp(), 1.0/m_sub->v());
check();
}
void PureFluidPhase::setState_SV(doublereal s, doublereal v,
doublereal tol) {
Set(tpx::SV, s, v);
setState_TR(m_sub->Temp(), 1.0/m_sub->v());
check();
}
void PureFluidPhase::setState_SP(doublereal s, doublereal p,
doublereal tol) {
Set(tpx::SP, s, p);
setState_TR(m_sub->Temp(), 1.0/m_sub->v());
check();
}
/// saturation pressure
doublereal PureFluidPhase::satPressure(doublereal t) const {
doublereal vsv = m_sub->v();
try {
Set(tpx::TV,t,vsv);
doublereal ps = m_sub->Ps();
return ps;
}
catch(tpx::TPX_Error) {
reportTPXError();
return -1.0;
}
}
doublereal PureFluidPhase::vaporFraction() const {
setTPXState();
doublereal x = m_sub->x();
check(x);
return x;
}
void PureFluidPhase::setState_Tsat(doublereal t, doublereal x) {
setTemperature(t);
setTPXState();
Set(tpx::TX, t, x);
setDensity(1.0/m_sub->v());
check();
}
void PureFluidPhase::setState_Psat(doublereal p, doublereal x) {
setTPXState();
Set(tpx::PX, p, x);
setTemperature(m_sub->Temp());
setDensity(1.0/m_sub->v());
check();
}
}

View file

@ -0,0 +1,317 @@
/**
* @file PureFluidPhase.h
* Header for a ThermoPhase object for a pure fluid phase consisting of gas, liquid, mixed-gas-liquid
* and supercrit fluid (see \ref thermoprops
* and class \link Cantera::PureFluidPhase PureFluidPhase\endlink).
*
*
* This object is only available if the WITH_PURE_FLUIDS optional compile
* capability has been turned on in Cantera's makefile system.
* It inherits from ThermoPhase, but is built on top of the tpx package.
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2003 California Institute of Technology
*/
#ifndef CT_EOS_TPX_H
#define CT_EOS_TPX_H
#include "ThermoPhase.h"
/**
* This object is only available if the WITH_PURE_FLUIDS optional compile
* capability has been turned on in Cantera's makefile system.
*/
#ifdef WITH_PURE_FLUIDS
#include "mix_defs.h"
namespace tpx {
class Substance;
}
namespace Cantera {
//! This phase object consists of a single component that can be a gas, a liquid,
//! a mixed gas-liquid fluid, or a fluid beyond its critical point
/*!
* The object inherits from ThermoPhase. However, its build on top of the
* tpx package.
*
*
* <H2> Specification of Species Standard State Properties </H2>
*
*
* <H2> Application within %Kinetics Managers </H2>
*
*
* <H2> XML Example </H2>
*
*
* <H2> Instantiation of the Class </H2>
*
* @ingroup thermoprops
*/
class PureFluidPhase : public ThermoPhase {
public:
//! Base Constructor
PureFluidPhase() : ThermoPhase(), m_sub(0), m_subflag(0),
m_mw(-1.0), m_verbose(false) {}
//! Destructor
virtual ~PureFluidPhase();
//! Equation of state type
virtual int eosType() const { return cPureFluid; }
/// Molar enthalpy. Units: J/kmol.
virtual doublereal enthalpy_mole() const;
/// Molar internal energy. Units: J/kmol.
virtual doublereal intEnergy_mole() const;
/// Molar entropy. Units: J/kmol/K.
virtual doublereal entropy_mole() const;
/// Molar Gibbs function. Units: J/kmol.
virtual doublereal gibbs_mole() const;
/// Molar heat capacity at constant pressure. Units: J/kmol/K.
virtual doublereal cp_mole() const;
/// Molar heat capacity at constant volume. Units: J/kmol/K.
virtual doublereal cv_mole() const;
//! Return the thermodynamic pressure (Pa).
/*!
* This method calculates the current pressure consistent with the
* independent variables, T, rho.
*/
virtual doublereal pressure() const;
//! sets the thermodynamic pressure (Pa).
/*!
* This method calculates the density that is consistent with the
* desired pressure, given the temperature.
*
* @param p Pressure (Pa)
*/
virtual void setPressure(doublereal p);
//! Get the species chemical potentials. Units: J/kmol.
/*!
* This function returns a vector of chemical potentials of the
* species in solution at the current temperature, pressure
* and mole fraction of the solution.
*
* @param mu Output vector of species chemical
* potentials. Length: m_kk. Units: J/kmol
*/
virtual void getChemPotentials(doublereal* mu) const {
mu[0] = gibbs_mole();
}
//! Returns the isothermal compressibility. Units: 1/Pa.
/*!
* The isothermal compressibility is defined as
* \f[
* \kappa_T = -\frac{1}{v}\left(\frac{\partial v}{\partial P}\right)_T
* \f]
*/
virtual doublereal isothermalCompressibility() const;
//! Return the volumetric thermal expansion coefficient. Units: 1/K.
/*!
* The thermal expansion coefficient is defined as
* \f[
* \beta = \frac{1}{v}\left(\frac{\partial v}{\partial T}\right)_P
* \f]
*/
virtual doublereal thermalExpansionCoeff() const;
//! Returns a reference to the substance object
tpx::Substance& TPX_Substance();
/// critical temperature
virtual doublereal critTemperature() const;
/// critical pressure
virtual doublereal critPressure() const;
/// critical density
virtual doublereal critDensity() const;
/// saturation temperature
/*!
* @param p Pressure (Pa)
*/
virtual doublereal satTemperature(doublereal p) const;
//! Set the internally storred specific enthalpy (J/kg) and pressure (Pa) of the phase.
/*!
* @param h Specific enthalpy (J/kg)
* @param p Pressure (Pa)
* @param tol Optional parameter setting the tolerance of the
* calculation.
*/
virtual void setState_HP(doublereal h, doublereal p,
doublereal tol = 1.e-8);
//! Set the specific internal energy (J/kg) and specific volume (m^3/kg).
/*!
* This function fixes the internal state of the phase so that
* the specific internal energy and specific volume have the value of the input parameters.
*
* @param u specific internal energy (J/kg)
* @param v specific volume (m^3/kg).
* @param tol Optional parameter setting the tolerance of the
* calculation.
*/
virtual void setState_UV(doublereal u, doublereal v,
doublereal tol = 1.e-8);
//! Set the specific entropy (J/kg/K) and specific volume (m^3/kg).
/*!
* This function fixes the internal state of the phase so that
* the specific entropy and specific volume have the value of the input parameters.
*
* @param s specific entropy (J/kg/K)
* @param v specific volume (m^3/kg).
* @param tol Optional parameter setting the tolerance of the
* calculation.
*/
virtual void setState_SV(doublereal s, doublereal v,
doublereal tol = 1.e-8);
//! Set the specific entropy (J/kg/K) and pressure (Pa).
/*!
* This function fixes the internal state of the phase so that
* the specific entropy and the pressure have the value of the input parameters.
*
* @param s specific entropy (J/kg/K)
* @param p specific pressure (Pa).
* @param tol Optional parameter setting the tolerance of the
* calculation.
*/
virtual void setState_SP(doublereal s, doublereal p,
doublereal tol = 1.e-8);
//! @name Saturation properties.
/*!
* These methods are only implemented by subclasses that
* implement full liquid-vapor equations of state. They may be
* moved out of ThermoPhase at a later date.
*/
//@{
//! Return the saturation pressure given the temperatur
/*!
* @param t Temperature (Kelvin)
*/
virtual doublereal satPressure(doublereal t) const;
//! Return the fraction of vapor at the current conditions
virtual doublereal vaporFraction() const;
//! Set the state to a saturated system at a particular temperature
/*!
* @param t Temperature (kelvin)
* @param x Fraction of vapor
*/
virtual void setState_Tsat(doublereal t, doublereal x);
//! Set the state to a saturated system at a particular pressure
/*!
* @param p Pressure (Pa)
* @param x Fraction of vapor
*/
virtual void setState_Psat(doublereal p, doublereal x);
//@}
//! Initialize the ThermoPhase object after all species have been set up
/*!
* @internal Initialize.
*
* This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called from ThermoPhase::initThermoXML(),
* which is called from importPhase(),
* just prior to returning from function importPhase().
*
* @see importCTML.cpp
*/
virtual void initThermo();
//! Set equation of state parameter values from XML entries.
/*!
*
* This method is called by function importPhase() in
* file importCTML.cpp when processing a phase definition in
* an input file. It should be overloaded in subclasses to set
* any parameters that are specific to that particular phase
* model. Note, this method is called before the phase is
* initialzed with elements and/or species.
*
* @param eosdata An XML_Node object corresponding to
* the "thermo" entry for this phase in the input file.
*/
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:
//! Main call to the tpx level to set the state of the system
/*!
* @param n Integer indicating which 2 thermo components are held constant
* @param x Value of the first component
* @param y Value of the second component
*/
void Set(int n, double x, double y) const;
//! Sets the state using a TPX::TV call
void setTPXState() const;
//! Carry out a internal check on tpx, it may have thrown an error.
/*!
* @param v Defaults to zero
*/
void check(doublereal v = 0.0) const;
//! Report errors in the TPX level
void reportTPXError() const;
private:
//! Pointer to the underlying tpx object Substance that does the work
mutable tpx::Substance* m_sub;
//! Int indicating the type of the fluid
/*!
* The tpx package uses an int to indicate what fluid is being sought.
*/
int m_subflag;
//! Molecular weight of the substance (kg kmol-1)
doublereal m_mw;
//! flag to turn on some printing.
bool m_verbose;
};
}
#endif
#endif

594
Cantera/src/thermo/ShomatePoly.h Executable file
View file

@ -0,0 +1,594 @@
/**
* @file ShomatePoly.h
* Header for a single-species standard state object derived
* from \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based
* on the Shomate temperature polynomial form applied to one temperature region
* (see \ref spthermo and class \link Cantera::ShomatePoly ShomatePoly\endlink and
* \link Cantera::ShomatePoly2 ShomatePoly2\endlink).
* Shomate polynomial expressions.
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_SHOMATEPOLY1_H
#define CT_SHOMATEPOLY1_H
#include "SpeciesThermoInterpType.h"
namespace Cantera {
//! The Shomate polynomial parameterization for one temperature range
//! for one species
/*!
*
* Seven coefficients \f$(A,\dots,G)\f$ are used to represent
* \f$ c_p^0(T)\f$, \f$ h^0(T)\f$, and \f$ s^0(T) \f$ as
* polynomials in the temperature, \f$ T \f$ :
*
* \f[
* \tilde{c}_p^0(T) = A + B t + C t^2 + D t^3 + \frac{E}{t^2}
* \f]
* \f[
* \tilde{h}^0(T) = A t + \frac{B t^2}{2} + \frac{C t^3}{3}
+ \frac{D t^4}{4} - \frac{E}{t} + F.
* \f]
* \f[
* \tilde{s}^0(T) = A\ln t + B t + \frac{C t^2}{2}
+ \frac{D t^3}{3} - \frac{E}{2t^2} + G.
* \f]
*
* In the above expressions, the thermodynamic polynomials are expressed
* in dimensional units, but the temperature,\f$ t \f$, is divided by 1000. The
* following dimensions are assumed in the above expressions:
*
* - \f$ \tilde{c}_p^0(T)\f$ = Heat Capacity (J/gmol*K)
* - \f$ \tilde{h}^0(T) \f$ = standard Enthalpy (kJ/gmol)
* - \f$ \tilde{s}^0(T) \f$= standard Entropy (J/gmol*K)
* - \f$ t \f$= temperature (K) / 1000.
*
* For more information about Shomate polynomials, see the NIST website,
* http://webbook.nist.gov/
*
* Before being used within Cantera, the dimensions must be adjusted to those
* used by Cantera (i.e., Joules and kmol).
*
* @ingroup spthermo
*/
class ShomatePoly : public SpeciesThermoInterpType {
public:
//! Empty constructor
ShomatePoly()
: m_lowT(0.0), m_highT (0.0),
m_Pref(0.0), m_index (0) {}
//! Constructor used in templated instantiations
/*!
* @param n Species index
* @param tlow Minimum temperature
* @param thigh Maximum temperature
* @param pref reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state for species n.
* There are 7 coefficients for the Shomate polynomial:
* - c[0] = \f$ A \f$
* - c[1] = \f$ B \f$
* - c[2] = \f$ C \f$
* - c[3] = \f$ D \f$
* - c[4] = \f$ E \f$
* - c[5] = \f$ F \f$
* - c[6] = \f$ G \f$
*
* See the class description for the polynomial representation of the
* thermo functions in terms of \f$ A, \dots, G \f$.
*/
ShomatePoly(int n, doublereal tlow, doublereal thigh, doublereal pref,
const doublereal* coeffs) :
m_lowT (tlow),
m_highT (thigh),
m_Pref (pref),
m_index (n) {
m_coeff.resize(7);
std::copy(coeffs, coeffs + 7, m_coeff.begin());
}
//! copy constructor
/*!
* @param b object to be copied
*/
ShomatePoly(const ShomatePoly& b) :
m_lowT (b.m_lowT),
m_highT (b.m_highT),
m_Pref (b.m_Pref),
m_coeff (array_fp(7)),
m_index (b.m_index) {
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 7,
m_coeff.begin());
}
//! Assignment operator
/*!
* @param b
*/
ShomatePoly& operator=(const ShomatePoly& b) {
if (&b != this) {
m_lowT = b.m_lowT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
m_coeff.resize(7);
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 7,
m_coeff.begin());
}
return *this;
}
//! Destructor
virtual ~ShomatePoly(){}
//! Duplicator from the base class
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const {
ShomatePoly* sp = new ShomatePoly(*this);
return (SpeciesThermoInterpType *) sp;
}
//! Returns the minimum temperature that the thermo
//! parameterization is valid
virtual doublereal minTemp() const { return m_lowT;}
//! Returns the maximum temperature that the thermo
//! parameterization is valid
virtual doublereal maxTemp() const { return m_highT;}
//! Returns the reference pressure (Pa)
virtual doublereal refPressure() const { return m_Pref; }
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return SHOMATE; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* tt is T/1000.
* m_t[0] = tt;
* m_t[1] = tt*tt;
* m_t[2] = m_t[1]*tt;
* m_t[3] = 1.0/m_t[1];
* m_t[4] = log(tt);
* m_t[5] = 1.0/GasConstant;
* m_t[6] = 1.0/(GasConstant * T);
*
* @param tt Vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updateProperties(const doublereal* tt,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const {
doublereal A = m_coeff[0];
doublereal Bt = m_coeff[1]*tt[0];
doublereal Ct2 = m_coeff[2]*tt[1];
doublereal Dt3 = m_coeff[3]*tt[2];
doublereal Etm2 = m_coeff[4]*tt[3];
doublereal F = m_coeff[5];
doublereal G = m_coeff[6];
doublereal cp, h, s;
cp = A + Bt + Ct2 + Dt3 + Etm2;
h = tt[0]*(A + 0.5*Bt + OneThird*Ct2 + 0.25*Dt3 - Etm2) + F;
s = A*tt[4] + Bt + 0.5*Ct2 + OneThird*Dt3 - 0.5*Etm2 + G;
/*
* Shomate polynomials parameterizes assuming units of
* J/(gmol*K) for cp_r and s_R and kJ/(gmol) for h.
* However, Cantera assumes default MKS units of
* J/(kmol*K). This requires us to multiply cp and s
* by 1.e3 and h by 1.e6, before we then nondimensionlize
* the results by dividing by (GasConstant * T),
* where GasConstant has units of J/(kmol * K).
*/
cp_R[m_index] = 1.e3 * cp * tt[5];
h_RT[m_index] = 1.e6 * h * tt[6];
s_R[m_index] = 1.e3 * s * tt[5];
}
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const {
double tPoly[7];
doublereal tt = 1.e-3*temp;
tPoly[0] = tt;
tPoly[1] = tt * tt;
tPoly[2] = tPoly[1] * tt;
tPoly[3] = 1.0/tPoly[1];
tPoly[4] = std::log(tt);
tPoly[5] = 1.0/GasConstant;
tPoly[6] = 1.0/(GasConstant * temp);
updateProperties(tPoly, cp_R, h_RT, s_R);
}
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = SHOMATE;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
for (int i = 0; i < 7; i++) {
coeffs[i] = m_coeff[i];
}
}
//! Modify parameters for the standard state
/*!
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs) {
if (m_coeff.size() != 7) {
throw CanteraError("modifyParameters",
"modifying something that hasn't been initialized");
}
std::copy(coeffs, coeffs + 7, m_coeff.begin());
}
protected:
//! Minimum temperature for which the parameterization is valid (Kelvin)
doublereal m_lowT;
//! Maximum temperature for which the parameterization is valid (Kelvin)
doublereal m_highT;
//! Reference pressure (Pa)
doublereal m_Pref;
//! Array of coeffcients
array_fp m_coeff;
//! Species Index
int m_index;
private:
};
//! The Shomate polynomial parameterization for two temperature ranges
//! for one species
/*!
*
* Seven coefficients \f$(A,\dots,G)\f$ are used to represent
* \f$ c_p^0(T)\f$, \f$ h^0(T)\f$, and \f$ s^0(T) \f$ as
* polynomials in the temperature, \f$ T \f$, in one temperature region:
*
* \f[
* \tilde{c}_p^0(T) = A + B t + C t^2 + D t^3 + \frac{E}{t^2}
* \f]
* \f[
* \tilde{h}^0(T) = A t + \frac{B t^2}{2} + \frac{C t^3}{3}
+ \frac{D t^4}{4} - \frac{E}{t} + F.
* \f]
* \f[
* \tilde{s}^0(T) = A\ln t + B t + \frac{C t^2}{2}
+ \frac{D t^3}{3} - \frac{E}{2t^2} + G.
* \f]
*
* In the above expressions, the thermodynamic polynomials are expressed
* in dimensional units, but the temperature,\f$ t \f$, is divided by 1000. The
* following dimensions are assumed in the above expressions:
*
* - \f$ \tilde{c}_p^0(T)\f$ = Heat Capacity (J/gmol*K)
* - \f$ \tilde{h}^0(T) \f$ = standard Enthalpy (kJ/gmol)
* - \f$ \tilde{s}^0(T) \f$= standard Entropy (J/gmol*K)
* - \f$ t \f$= temperature (K) / 1000.
*
* For more information about Shomate polynomials, see the NIST website,
* http://webbook.nist.gov/
*
* Before being used within Cantera, the dimensions must be adjusted to those
* used by Cantera (i.e., Joules and kmol).
*
* This function uses two temperature regions, each with a Shomate polynomial
* representation to represent the thermo functions. There are 15 coefficients,
* therefore, in this representation. The first coefficient is the midrange
* temperature.
*
*
* @ingroup spthermo
*/
class ShomatePoly2 : public SpeciesThermoInterpType {
public:
//! Empty constructor
ShomatePoly2()
: m_lowT(0.0),
m_midT(0.0),
m_highT (0.0),
m_Pref(0.0),
msp_low(0),
msp_high(0),
m_index(0) {
m_coeff.resize(15);
}
//! Constructor used in templated instantiations
/*!
* @param n Species index
* @param tlow Minimum temperature
* @param thigh Maximum temperature
* @param pref reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
* There are 15 coefficients for the 2-zone Shomate polynomial.
* The first coefficient is the value of Tmid. The next 7
* coefficients are the low temperature range Shomate coefficients.
* The last 7 are the high temperature range Shomate coefficients.
*/
ShomatePoly2(int n, doublereal tlow, doublereal thigh, doublereal pref,
const doublereal* coeffs) :
m_lowT (tlow),
m_midT(0.0),
m_highT (thigh),
m_Pref (pref),
msp_low(0),
msp_high(0),
m_index (n) {
m_coeff.resize(15);
std::copy(coeffs, coeffs + 15, m_coeff.begin());
m_midT = coeffs[0];
msp_low = new ShomatePoly(n, tlow, m_midT, pref, coeffs+1);
msp_high = new ShomatePoly(n, m_midT, thigh, pref, coeffs+8);
}
//! Copy constructor
/*!
* @param b object to be copied.
*/
ShomatePoly2(const ShomatePoly2& b) :
m_lowT (b.m_lowT),
m_midT (b.m_midT),
m_highT (b.m_highT),
m_Pref (b.m_Pref),
msp_low(0),
msp_high(0),
m_coeff (array_fp(15)),
m_index (b.m_index) {
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 15,
m_coeff.begin());
msp_low = new ShomatePoly(m_index, m_lowT, m_midT,
m_Pref, &m_coeff[1]);
msp_high = new ShomatePoly(m_index, m_midT, m_highT,
m_Pref, &m_coeff[8]);
}
//! Assignment operator
/*!
* @param b object to be copied.
*/
ShomatePoly2& operator=(const ShomatePoly2& b) {
if (&b != this) {
m_lowT = b.m_lowT;
m_midT = b.m_midT;
m_highT = b.m_highT;
m_Pref = b.m_Pref;
m_index = b.m_index;
std::copy(b.m_coeff.begin(),
b.m_coeff.begin() + 15,
m_coeff.begin());
if (msp_low) delete msp_low;
if (msp_high) delete msp_high;
msp_low = new ShomatePoly(m_index, m_lowT, m_midT,
m_Pref, &m_coeff[1]);
msp_high = new ShomatePoly(m_index, m_midT, m_highT,
m_Pref, &m_coeff[8]);
}
return *this;
}
//! Destructor
virtual ~ShomatePoly2(){
delete msp_low;
delete msp_high;
}
//! duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const {
ShomatePoly2* sp = new ShomatePoly2(*this);
return (SpeciesThermoInterpType *) sp;
}
//! Returns the minimum temperature that the thermo
//! parameterization is valid
virtual doublereal minTemp() const { return m_lowT;}
//! Returns the maximum temperature that the thermo
//! parameterization is valid
virtual doublereal maxTemp() const { return m_highT;}
//! Returns the reference pressure (Pa)
virtual doublereal refPressure() const { return m_Pref; }
//! Returns an integer representing the type of parameterization
virtual int reportType() const { return SHOMATE2; }
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* Temperature Polynomial:
* tt[0] = t;
* tt[1] = t*t;
* tt[2] = m_t[1]*t;
* tt[3] = m_t[2]*t;
* tt[4] = 1.0/t;
* tt[5] = std::log(t);
*
* @param tt vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updateProperties(const doublereal* tt,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const {
double T = 1000 * tt[0];
if (T <= m_midT) {
msp_low->updateProperties(tt, cp_R, h_RT, s_R);
} else {
msp_high->updateProperties(tt, cp_R, h_RT, s_R);
}
}
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
if (temp <= m_midT) {
msp_low->updatePropertiesTemp(temp, cp_R, h_RT, s_R);
} else {
msp_high->updatePropertiesTemp(temp, cp_R, h_RT, s_R);
}
}
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param n Species index
* @param type Integer type of the standard type
* @param tlow output - Minimum temperature
* @param thigh output - Maximum temperature
* @param pref output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void reportParameters(int &n, int &type,
doublereal &tlow, doublereal &thigh,
doublereal &pref,
doublereal* const coeffs) const {
n = m_index;
type = SHOMATE2;
tlow = m_lowT;
thigh = m_highT;
pref = m_Pref;
for (int i = 0; i < 15; i++) {
coeffs[i] = m_coeff[i];
}
}
//! Modify parameters for the standard state
/*!
* Here, we take the tact that we will just regenerate the
* object.
*
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs) {
delete msp_low;
delete msp_high;
std::copy(coeffs, coeffs + 15, m_coeff.begin());
m_midT = coeffs[0];
msp_low = new ShomatePoly(m_index, m_lowT, m_midT, m_Pref, coeffs+1);
msp_high = new ShomatePoly(m_index, m_midT, m_highT, m_Pref, coeffs+8);
}
protected:
//! Minimum temperature the representation is valid(kelvin)
doublereal m_lowT;
//! Midrange temperature (kelvin)
doublereal m_midT;
//! Maximum temperature the representation is valid (kelvin)
doublereal m_highT;
//! Reference pressure (Pascal)
doublereal m_Pref;
//! Pointer to the Shomate polynomial for the low temperature region.
ShomatePoly *msp_low;
//! Pointer to the Shomate polynomial for the high temperature region.
ShomatePoly *msp_high;
//! Array of the original coefficients.
array_fp m_coeff;
//! Species index
int m_index;
};
}
#endif

View file

@ -0,0 +1,465 @@
/**
* @file ShomateThermo.h
* Header for the 2 regions Shomate polynomial
* for multiple species in a phase, derived from the
* \link Cantera::SpeciesThermo SpeciesThermo\endlink base class (see \ref spthermo and
* \link Cantera::ShomateThermo ShomateThermo\endlink).
*/
/*
* $Id$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_SHOMATETHERMO_H
#define CT_SHOMATETHERMO_H
#include "SpeciesThermoMgr.h"
#include "ShomatePoly.h"
#include "speciesThermoTypes.h"
namespace Cantera {
//! A species thermodynamic property manager for the Shomate polynomial parameterization.
/*!
* This is the parameterization used
* in the NIST Chemistry WebBook (http://webbook.nist.gov/chemistry)
* The parameterization assumes there are two temperature regions
* each with its own Shomate polynomial representation, for each
* species in the phase.
*
* \f[
* \tilde{c}_p^0(T) = A + B t + C t^2 + D t^3 + \frac{E}{t^2}
* \f]
* \f[
* \tilde{h}^0(T) = A t + \frac{B t^2}{2} + \frac{C t^3}{3}
+ \frac{D t^4}{4} - \frac{E}{t} + F.
* \f]
* \f[
* \tilde{s}^0(T) = A\ln t + B t + \frac{C t^2}{2}
+ \frac{D t^3}{3} - \frac{E}{2t^2} + G.
* \f]
*
* In the above expressions, the thermodynamic polynomials are expressed
* in dimensional units, but the temperature,\f$ t \f$, is divided by 1000. The
* following dimensions are assumed in the above expressions:
*
* - \f$ \tilde{c}_p^0(T)\f$ = Heat Capacity (J/gmol*K)
* - \f$ \tilde{h}^0(T) \f$ = standard Enthalpy (kJ/gmol)
* - \f$ \tilde{s}^0(T) \f$= standard Entropy (J/gmol*K)
* - \f$ t \f$= temperature (K) / 1000.
*
* Note, the polynomial data (i.e., A, ... , G) is entered in dimensional
* form.
*
* This is in contrast to the NASA database polynomials which are entered in
* nondimensional form (i.e., NASA parameterizes C_p/R, while Shomate
* parameterizes C_p assuming units of J/gmol*K - and kJ/gmol*K for H).
* Note, also that the H - H_298.15 equation has units of kJ/gmol, because of
* the implicit integration of (t = T 1000), which provides a
* multiplier of 1000 to the Enthalpy equation.
*
* @ingroup spthermo
*/
class ShomateThermo : public SpeciesThermo {
public:
//! Initialized to the type of parameterization
/*!
* Note, this value is used in some template functions
*/
const int ID;
//! constructor
ShomateThermo() :
ID(SHOMATE),
m_tlow_max(0.0),
m_thigh_min(1.e30),
m_p0(-1.0),
m_ngroups(0)
{ m_t.resize(7); }
//! destructor
virtual ~ShomateThermo() {}
//! Install a new species thermodynamic property
//! parameterization for one species using Shomate polynomials
//!
/*!
* Two temperature regions are assumed.
*
* @param name Name of the species
* @param index Species index
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c Vector of coefficients for the parameterization.
* There are 15 coefficients for the 2-zone Shomate polynomial.
* The first coefficient is the value of Tmid. The next 7
* coefficients are the low temperature range Shomate coefficients.
* The last 7 are the high temperature range Shomate coefficients.
*
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
*
* @see ShomatePoly
* @see ShomatePoly2
*/
virtual void install(string name, int index, int type,
const doublereal* c,
doublereal minTemp, doublereal maxTemp,
doublereal refPressure) {
int imid = int(c[0]); // midpoint temp converted to integer
int igrp = m_index[imid]; // has this value been seen before?
if (igrp == 0) { // if not, prepare new group
vector<ShomatePoly> v;
m_high.push_back(v);
m_low.push_back(v);
m_tmid.push_back(c[0]);
m_index[imid] = igrp = static_cast<int>(m_high.size());
m_ngroups++;
}
m_group_map[index] = igrp;
m_posInGroup_map[index] = (int) m_low[igrp-1].size();
doublereal tlow = minTemp;
doublereal tmid = c[0];
doublereal thigh = maxTemp;
const doublereal* clow = c + 1;
const doublereal* chigh = c + 8;
m_high[igrp-1].push_back(ShomatePoly(index, tmid, thigh,
refPressure, chigh));
m_low[igrp-1].push_back(ShomatePoly(index, tlow, tmid,
refPressure, clow));
if (tlow > m_tlow_max) m_tlow_max = tlow;
if (thigh < m_thigh_min) m_thigh_min = thigh;
if ((int) m_tlow.size() < index + 1) {
m_tlow.resize(index + 1, tlow);
m_thigh.resize(index + 1, thigh);
}
m_tlow[index] = tlow;
m_thigh[index] = thigh;
if (m_p0 < 0.0) {
m_p0 = refPressure;
} else if (fabs(m_p0 - refPressure) > 0.1) {
string logmsg = " WARNING ShomateThermo: New Species, " + name
+ ", has a different reference pressure, "
+ fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n";
writelog(logmsg);
logmsg = " This may become a fatal error in the future \n";
writelog(logmsg);
}
m_p0 = refPressure;
}
//! Like update(), but only updates the single species k.
/*!
* @param k species index
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update_one(int k, doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
doublereal tt = 1.e-3*t;
m_t[0] = tt;
m_t[1] = tt*tt;
m_t[2] = m_t[1]*tt;
m_t[3] = 1.0/m_t[1];
m_t[4] = log(tt);
m_t[5] = 1.0/GasConstant;
m_t[6] = 1.0/(GasConstant * t);
int grp = m_group_map[k];
int pos = m_posInGroup_map[k];
const vector<ShomatePoly> &mlg = m_low[grp-1];
const ShomatePoly *nlow = &(mlg[pos]);
doublereal tmid = nlow->maxTemp();
if (t < tmid) {
nlow->updateProperties(&m_t[0], cp_R, h_RT, s_R);
} else {
const vector<ShomatePoly> &mhg = m_high[grp-1];
const ShomatePoly *nhigh = &(mhg[pos]);
nhigh->updateProperties(&m_t[0], cp_R, h_RT, s_R);
}
}
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
int i;
doublereal tt = 1.e-3*t;
m_t[0] = tt;
m_t[1] = tt*tt;
m_t[2] = m_t[1]*tt;
m_t[3] = 1.0/m_t[1];
m_t[4] = log(tt);
m_t[5] = 1.0/GasConstant;
m_t[6] = 1.0/(GasConstant * t);
vector<ShomatePoly>::const_iterator _begin, _end;
for (i = 0; i != m_ngroups; i++) {
if (t > m_tmid[i]) {
_begin = m_high[i].begin();
_end = m_high[i].end();
}
else {
_begin = m_low[i].begin();
_end = m_low[i].end();
}
for (; _begin != _end; ++_begin) {
_begin->updateProperties(&m_t[0], cp_R, h_RT, s_R);
}
}
}
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k=-1) const {
if (k < 0)
return m_tlow_max;
else
return m_tlow[k];
}
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k species index
*/
virtual doublereal maxTemp(int k=-1) const {
if (k < 0)
return m_thigh_min;
else
return m_thigh[k];
}
//! The reference-state pressure for species k.
/*!
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k species index
*/
virtual doublereal refPressure(int k=-1) const {
return m_p0;
}
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param index Species index
*/
virtual int reportType(int index) const { return SHOMATE; }
/*!
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
*
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
type = reportType(index);
if (type == SHOMATE) {
int grp = m_group_map[index];
int pos = m_posInGroup_map[index];
int itype = SHOMATE;
const vector<ShomatePoly> &mlg = m_low[grp-1];
const vector<ShomatePoly> &mhg = m_high[grp-1];
const ShomatePoly *lowPoly = &(mlg[pos]);
const ShomatePoly *highPoly = &(mhg[pos]);
doublereal tmid = lowPoly->maxTemp();
c[0] = tmid;
int n;
double ttemp;
lowPoly->reportParameters(n, itype, minTemp, ttemp, refPressure,
c + 1);
if (n != index) {
throw CanteraError(" ", "confused");
}
if (itype != SHOMATE && itype != SHOMATE1) {
throw CanteraError(" ", "confused");
}
highPoly->reportParameters(n, itype, ttemp, maxTemp,
refPressure, c + 8);
if (n != index) {
throw CanteraError(" ", "confused");
}
if (itype != SHOMATE && itype != SHOMATE1) {
throw CanteraError(" ", "confused");
}
} else {
throw CanteraError(" ", "confused");
}
}
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c) {
int type = reportType(index);
if (type == SHOMATE) {
int grp = m_group_map[index];
int pos = m_posInGroup_map[index];
vector<ShomatePoly> &mlg = m_low[grp-1];
vector<ShomatePoly> &mhg = m_high[grp-1];
ShomatePoly *lowPoly = &(mlg[pos]);
ShomatePoly *highPoly = &(mhg[pos]);
doublereal tmid = lowPoly->maxTemp();
if (fabs(c[0] - tmid) > 0.001) {
throw CanteraError("modifyParams", "can't change mid temp");
}
lowPoly->modifyParameters(c + 1);
highPoly->modifyParameters(c + 8);
} else {
throw CanteraError(" ", "confused");
}
}
protected:
//! Vector of vector of NasaPoly1's for the high temp region.
/*!
* This is the high temp region representation.
* The first Length is equal to the number of groups.
* The second vector is equal to the number of species
* in that particular group.
*/
vector<vector<ShomatePoly> > m_high;
//! Vector of vector of NasaPoly1's for the low temp region.
/*!
* This is the low temp region representation.
* The first Length is equal to the number of groups.
* The second vector is equal to the number of species
* in that particular group.
*/
vector<vector<ShomatePoly> > m_low;
//! Map between the midpoint temperature, as an int, to the group number
/*!
* Length is equal to the number of groups. Only used in the setup.
*/
map<int, int> m_index;
//! Vector of log temperature limits
/*!
* Length is equal to the number of groups.
*/
vector_fp m_tmid;
//! Maximum value of the low temperature limit
doublereal m_tlow_max;
//! Minimum value of the high temperature limit
doublereal m_thigh_min;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of species
*/
vector_fp m_tlow;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of species
*/
vector_fp m_thigh;
//! Reference pressure (Pa)
/*!
* all species must have the same reference pressure.
*/
doublereal m_p0;
//! number of groups
int m_ngroups;
//! Vector of temperature polynomials
mutable vector_fp m_t;
/*!
* This map takes as its index, the species index in the phase.
* It returns the group index, where the temperature polynomials
* for that species are stored. group indecises start at 1,
* so a decrement is always performed to access vectors.
*/
mutable map<int, int> m_group_map;
/*!
* This map takes as its index, the species index in the phase.
* It returns the position index within the group, where the
* temperature polynomials for that species are storred.
*/
mutable map<int, int> m_posInGroup_map;
};
}
#endif

View file

@ -0,0 +1,379 @@
/**
* @file SimpleThermo.h
* Header for the SimpleThermo (constant heat capacity) species reference-state model
* for multiple species in a phase, derived from the
* \link Cantera::SpeciesThermo SpeciesThermo\endlink base class (see \ref spthermo and
* \link Cantera::SimpleThermo SimpleThermo\endlink).
*/
/*
* $Id$
*/
#ifndef CT_SIMPLETHERMO_H
#define CT_SIMPLETHERMO_H
#include "SpeciesThermoMgr.h"
namespace Cantera {
/*!
* A constant-heat capacity species thermodynamic property manager class.
* This makes the
* assumption that the heat capacity is a constant. Then, the following
* relations are used to complete the specification of the thermodynamic
* functions for each species in the phase.
*
* \f[
* \frac{c_p(T)}{R} = Cp0\_R
* \f]
* \f[
* \frac{h^0(T)}{RT} = \frac{1}{T} * (h0\_R + (T - T_0) * Cp0\_R)
* \f]
* \f[
* \frac{s^0(T)}{R} = (s0\_R + (log(T) - log(T_0)) * Cp0\_R)
* \f]
*
* This parameterization takes 4 input values. These are:
* - c[0] = \f$ T_0 \f$(Kelvin)
* - c[1] = \f$ H_k^o(T_0, p_{ref}) \f$ (J/kmol)
* - c[2] = \f$ S_k^o(T_0, p_{ref}) \f$ (J/kmol K)
* - c[3] = \f$ {Cp}_k^o(T_0, p_{ref}) \f$ (J(kmol K)
*
* All species must have the same reference pressure.
* The single-species standard-state property Manager ConstCpPoly has the same
* parameterization as the SimpleThermo class does.
*
* @see ConstCpPoly
*
* @ingroup spthermo
*/
class SimpleThermo : public SpeciesThermo {
public:
//! Initialized to the type of parameterization
/*!
* Note, this value is used in some template functions. For this object the
* value is SIMPLE.
*/
const int ID;
//! Constructor
SimpleThermo() :
ID(SIMPLE),
m_tlow_max(0.0),
m_thigh_min(1.e30),
m_p0(-1.0),
m_nspData(0) {}
//! Destructor
virtual ~SimpleThermo() {}
//! Install a new species thermodynamic property
//! parameterization for one species.
/*!
*
* @param name String name of the species
* @param index Species index, k
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c Vector of coefficients for the parameterization.
* There are 4 coefficients. The values (and units) are the following
* - c[0] = \f$ T_0 \f$(Kelvin)
* - c[1] = \f$ H_k^o(T_0, p_{ref}) \f$ (J/kmol)
* - c[2] = \f$ S_k^o(T_0, p_{ref}) \f$ (J/kmol K)
* - c[3] = \f$ {Cp}_k^o(T_0, p_{ref}) \f$ (J(kmol K)
*
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
*
* @see ConstCpPoly
*/
virtual void install(string name, int index, int type,
const doublereal* c,
doublereal minTemp, doublereal maxTemp, doublereal refPressure) {
//writelog("installing const_cp for species "+name+"\n");
m_logt0.push_back(log(c[0]));
m_t0.push_back(c[0]);
m_h0_R.push_back(c[1]/GasConstant);
m_s0_R.push_back(c[2]/GasConstant);
m_cp0_R.push_back(c[3]/GasConstant);
m_index.push_back(index);
m_loc[index] = m_nspData;
m_nspData++;
doublereal tlow = minTemp;
doublereal thigh = maxTemp;
if (tlow > m_tlow_max) m_tlow_max = tlow;
if (thigh < m_thigh_min) m_thigh_min = thigh;
if ((int) m_tlow.size() < index + 1) {
m_tlow.resize(index + 1, tlow);
m_thigh.resize(index + 1, thigh);
}
m_tlow[index] = tlow;
m_thigh[index] = thigh;
if (m_p0 < 0.0) {
m_p0 = refPressure;
} else if (fabs(m_p0 - refPressure) > 0.1) {
string logmsg = " WARNING SimpleThermo: New Species, " + name +
", has a different reference pressure, "
+ fp2str(refPressure) + ", than existing reference pressure, " + fp2str(m_p0) + "\n";
writelog(logmsg);
logmsg = " This may become a fatal error in the future \n";
writelog(logmsg);
}
m_p0 = refPressure;
}
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
int k, ki;
doublereal logt = log(t);
doublereal rt = 1.0/t;
for (k = 0; k < m_nspData; k++) {
ki = m_index[k];
cp_R[ki] = m_cp0_R[k];
h_RT[ki] = rt*(m_h0_R[k] + (t - m_t0[k]) * m_cp0_R[k]);
s_R[ki] = m_s0_R[k] + m_cp0_R[k] * (logt - m_logt0[k]);
}
}
//! Like update(), but only updates the single species k.
/*!
* @param k species index
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update_one(int k, doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
doublereal logt = log(t);
doublereal rt = 1.0/t;
int loc = m_loc[k];
cp_R[k] = m_cp0_R[loc];
h_RT[k] = rt*(m_h0_R[loc] + (t - m_t0[loc]) * m_cp0_R[loc]);
s_R[k] = m_s0_R[loc] + m_cp0_R[loc] * (logt - m_logt0[loc]);
}
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k=-1) const {
if (k < 0)
return m_tlow_max;
else
return m_tlow[m_loc[k]];
}
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k Species Index
*/
virtual doublereal maxTemp(int k=-1) const {
if (k < 0)
return m_thigh_min;
else
return m_thigh[m_loc[k]];
}
//! The reference-state pressure for species k.
/*!
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k Species Index
*/
virtual doublereal refPressure(int k=-1) const {return m_p0;}
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param index Species index
*/
virtual int reportType(int index) const { return SIMPLE; }
/*!
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
*
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* For the SimpleThermo object, there are 4 coefficients.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
type = reportType(index);
int loc = m_loc[index];
if (type == SIMPLE) {
c[0] = m_t0[loc];
c[1] = m_h0_R[loc] * GasConstant;
c[2] = m_s0_R[loc] * GasConstant;
c[3] = m_cp0_R[loc] * GasConstant;
minTemp = m_tlow[loc];
maxTemp = m_thigh[loc];
refPressure = m_p0;
}
}
//! Modify parameters for the standard state
/*!
* The thermo parameterization for a single species is overwritten.
*
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* Must be length >= 4.
*/
virtual void modifyParams(int index, doublereal *c) {
int loc = m_loc[index];
if (loc < 0) {
throw CanteraError("SimpleThermo::modifyParams",
"modifying parameters for species which hasn't been set yet");
}
/*
* Change the data
*/
m_t0[loc] = c[0];
m_h0_R[loc] = c[1] / GasConstant;
m_s0_R[loc] = c[2] / GasConstant;
m_cp0_R[loc] = c[3] / GasConstant;
}
protected:
//! Mapping between the species index and the vector index where the coefficients are kept
/*!
* This object doesn't have a one-to one correspondence between the species index, kspec,
* and the data location index,indexData, m_cp0_R[indexData].
* This index keeps track of it.
* indexData = m_loc[kspec]
*/
mutable map<int, int> m_loc;
//! Map between the vector index where the coefficients are kept and the species index
/*!
* Length is equal to the number of dataPoints.
* kspec = m_index[indexData]
*/
vector_int m_index;
//! Maximum value of the low temperature limit
doublereal m_tlow_max;
//! Minimum value of the high temperature limit
doublereal m_thigh_min;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of data points
*/
vector_fp m_tlow;
//! Vector of low temperature limits (species index)
/*!
* Length is equal to number of data points
*/
vector_fp m_thigh;
//! Vector of base temperatures (kelvin)
/*!
* Length is equal to the number of species data points
*/
vector_fp m_t0;
//! Vector of base log temperatures (kelvin)
/*!
* Length is equal to the number of species data points
*/
vector_fp m_logt0;
//! Vector of base dimensionless Enthalpies
/*!
* Length is equal to the number of species data points
*/
vector_fp m_h0_R;
//! Vector of base dimensionless Entropies
/*!
* Length is equal to the number of species data points
*/
vector_fp m_s0_R;
//! Vector of base dimensionless heat capacities
/*!
* Length is equal to the number of species data points
*/
vector_fp m_cp0_R;
//! Reference pressure (Pa)
/*!
* all species must have the same reference pressure.
*/
doublereal m_p0;
//! Number of species data points in the object.
/*!
* This is less than or equal to the number of species in the phase.
*/
int m_nspData;
};
}
#endif

View file

@ -0,0 +1,298 @@
/**
* @file SpeciesThermo.h
* Virtual base class for the calculation of multiple-species thermodynamic
* property managers and text for the spthermo module (see \ref spthermo
* and class \link Cantera::SpeciesThermo SpeciesThermo\endlink).
*
* We also describe the doxygen module spthermo (see \ref spthermo )
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_SPECIESTHERMO_H
#define CT_SPECIESTHERMO_H
#include "ct_defs.h"
namespace Cantera {
/**
* @defgroup spthermo Species Standard-State Thermodynamic Properties
*
* To compute the thermodynamic properties of multicomponent
* solutions, it is necessary to know something about the
* thermodynamic properties of the individual species present in
* the solution. Exactly what sort of species properties are
* required depends on the thermodynamic model for the
* solution. For a gaseous solution (i.e., a gas mixture), the
* species properties required are usually ideal gas properties at
* the mixture temperature and at a reference pressure (often 1
* atm or 1 bar). For other types of solutions, however, it may
* not be possible to isolate the species in a "pure" state. For
* example, the thermodynamic properties of, say, Na+ and Cl- in
* saltwater are not easily determined from data on the properties
* of solid NaCl, or solid Na metal, or chlorine gas. In this
* case, the solvation in water is fundamental to the identity of
* the species, and some other reference state must be used. One
* common convention for liquid solutions is to use thermodynamic
* data for the solutes for the limit of infinite dilution in the
* pure solvent; another convention is to reference all properties
* to unit molality.
*
* In defining these standard states for species in a phase, we make
* the following definition. A reference state is a standard state
* of a species in a phase limited to one pressure, the reference
* pressure. The reference state specifies the dependence of all
* thermodynamic functions as a function of the temperature, in
* between a minimum temperature and a maximum temperature. The
* reference state also specifies the molar volume of the species
* as a function of temperature. The molar volume is a thermodynamic
* function.
* A full standard state does the same thing as a reference state,
* but specifies the thermodynamics functions at all pressures.
*
* Whatever the conventions used by a particular solution model,
* means need to be provided to compute the species properties in
* the reference state. Class SpeciesThermo is the base class
* for a family of classes that compute properties of all
* species in a phase in their reference states, for a range of temperatures.
* Note, the pressure dependence of the species thermodynamic functions is not
* handled by this particular species thermodynamic model. %SpeciesThermo
* calculates the thermodynamic values of all species in a single
* phase during each call.
*
*
* The following classes inherit from %SpeciesThermo. Each of these classes
* handle multiple species, usually all of the species in a phase.
*
* - NasaThermo in file NasaThermo.h
* - This is a two zone model, with each zone consisting of a 7
* coefficient Nasa Polynomial format.
* .
* - ShomateThermo in file ShomateThermo.h
* - This is a two zone model, with each zone consisting of a 7
* coefficient Shomate Polynomial format.
* .
* - SimpleThermo in file SimpleThermo.h
* - This is a one-zone constant heat capacity model.
* .
* - GeneralSpeciesThermo in file GeneralSpeciesThermo.h
* - This is a general model. Each species is handled separately
* via a vector over SpeciesThermoInterpType classes.
* .
* - SpeciesThermo1 in file SpeciesThermoMgr.h
* - SpeciesThermoDuo in file SpeciesThermoMgr.h
* - This is a combination of two SpeciesThermo types.
* .
* .
*
* The class SpeciesThermoInterpType is a pure virtual base class for
* calculation of thermodynamic functions for a single species
* in its reference state.
* The following classes inherit from %SpeciesThermoInterpType
* - NasaPoly1 in file NasaPoly1.h
* - This is a one zone model, consisting of a 7
* coefficient Nasa Polynomial format.
* .
* - NasaPoly2 in file NasaPoly2.h
* - This is a two zone model, with each zone consisting of a 7
* coefficient Nasa Polynomial format.
* .
* - ShomatePoly in file ShomatePoly.h
* - This is a one zone model, consisting of a 7
* coefficient Shomate Polynomial format.
* .
* - ShomatePoly2 in file ShomatePoly.h
* - This is a two zone model, with each zone consisting of a 7
* coefficient Shomate Polynomial format.
* .
* - ConstCpPoly in file ConstCpPoly.h
* - This is a one-zone constant heat capacity model.
* .
* - Mu0Poly in file Mu0Poly.h
* - This is a multizoned model. The chemical potential is given
* at a set number of temperatures. Between each temperature
* the heat capacity is treated as a constant.
* .
* .
*/
//@{
//////////////////////// class SpeciesThermo ////////////////////
//! Pure Virtual base class for the species thermo manager classes.
/*!
* This class defines the interface which all subclasses must implement.
*
* Class %SpeciesThermo is the base class
* for a family of classes that compute properties of a set of
* species in their reference state at a range of temperatures.
* Note, the pressure dependence of the reference state is not
* handled by this particular species standard state model.
*/
class SpeciesThermo {
public:
//! Constructor
SpeciesThermo() {}
//! Destructor
virtual ~SpeciesThermo() {}
//! Install a new species thermodynamic property
//! parameterization for one species.
/*!
*
* @param name Name of the species
* @param index The 'update' method will update the property
* values for this species
* at position i index in the property arrays.
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c vector of coefficients for the parameterization.
* This vector is simply passed through to the
* parameterization constructor.
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
* @see speciesThermoTypes.h
*/
virtual void install(std::string name, int index, int type,
const doublereal* c,
doublereal minTemp,
doublereal maxTemp,
doublereal refPressure)=0;
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param T Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal T,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const=0;
//! Like update(), but only updates the single species k.
/*!
* @param k species index
* @param T Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*
*/
virtual void update_one(int k, doublereal T,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const {
update(T, cp_R, h_RT, s_R);
}
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k=-1) const =0;
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k Species Index
*/
virtual doublereal maxTemp(int k=-1) const =0;
//! The reference-state pressure for species k.
/*!
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k Species Index
*/
virtual doublereal refPressure(int k=-1) const =0;
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param index Species index
*/
virtual int reportType(int index = -1) const = 0;
//! This utility function reports back the type of
//! parameterization and all of the parameters for the species, index.
/*!
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const =0;
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c) = 0;
};
//@}
}
#endif

View file

@ -0,0 +1,488 @@
/**
* @file SpeciesThermoFactory.cpp
* Definitions for factory to build instances of classes that manage the
* standard-state thermodynamic properties of a set of species
* (see \ref spthermo and class \link Cantera::SpeciesThermoFactory SpeciesThermoFactory\endlink);
*/
/*
* $Id$
*/
// Copyright 2001 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "SpeciesThermoFactory.h"
using namespace std;
#include "SpeciesThermo.h"
#include "NasaThermo.h"
#include "ShomateThermo.h"
#include "SimpleThermo.h"
#include "GeneralSpeciesThermo.h"
#include "Mu0Poly.h"
#include "SpeciesThermoMgr.h"
#include "speciesThermoTypes.h"
#include "xml.h"
#include "ctml.h"
using namespace ctml;
namespace Cantera {
SpeciesThermoFactory* SpeciesThermoFactory::s_factory = 0;
/**
* Examine the types of species thermo parameterizations,
* and return a flag indicating the type of parameterization
* needed by the species.
*
* @param spData_node Species Data XML node. This node contains a list
* of species XML nodes underneath it.
*
* @todo Make sure that spDadta_node is species Data XML node by checking its name is speciesData
*/
static void getSpeciesThermoTypes(XML_Node* spData_node,
int& has_nasa, int& has_shomate, int& has_simple,
int &has_other) {
const XML_Node& sparray = *spData_node;
std::vector<XML_Node*> sp;
// get all of the species nodes
sparray.getChildren("species",sp);
size_t n, ns = sp.size();
for (n = 0; n < ns; n++) {
XML_Node* spNode = sp[n];
if (spNode->hasChild("thermo")) {
const XML_Node& th = sp[n]->child("thermo");
if (th.hasChild("NASA")) has_nasa = 1;
if (th.hasChild("Shomate")) has_shomate = 1;
if (th.hasChild("const_cp")) has_simple = 1;
if (th.hasChild("poly")) {
if (th.child("poly")["order"] == "1") has_simple = 1;
else throw CanteraError("newSpeciesThermo",
"poly with order > 1 not yet supported");
}
if (th.hasChild("Mu0")) has_other = 1;
} else {
throw UnknownSpeciesThermoModel("getSpeciesThermoTypes:",
spNode->attrib("name"), "missing");
}
}
}
/**
* Return a species thermo manager to handle the parameterizations
* specified in a CTML phase specification.
*/
SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(XML_Node* spData_node) {
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
try {
getSpeciesThermoTypes(spData_node, inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
popError();
}
if (iother) {
writelog("returning new GeneralSpeciesThermo");
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
SpeciesThermo* SpeciesThermoFactory::
newSpeciesThermo(std::vector<XML_Node*> spData_nodes) {
int n = static_cast<int>(spData_nodes.size());
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
for (int j = 0; j < n; j++) {
try {
getSpeciesThermoTypes(spData_nodes[j], inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
popError();
}
}
if (iother) {
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
/*
* @todo is this used?
*/
SpeciesThermo* SpeciesThermoFactory::
newSpeciesThermoOpt(std::vector<XML_Node*> nodes) {
int n = static_cast<int>(nodes.size());
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
for (int j = 0; j < n; j++) {
try {
getSpeciesThermoTypes(nodes[j], inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
popError();
}
}
if (iother) {
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(int type) {
switch (type) {
case NASA:
return new NasaThermo;
case SHOMATE:
return new ShomateThermo;
case SIMPLE:
return new SimpleThermo;
case NASA + SHOMATE:
return new SpeciesThermoDuo<NasaThermo, ShomateThermo>;
case NASA + SIMPLE:
return new SpeciesThermoDuo<NasaThermo, SimpleThermo>;
case SHOMATE + SIMPLE:
return new SpeciesThermoDuo<ShomateThermo, SimpleThermo>;
default:
throw UnknownSpeciesThermo(
"SpeciesThermoFactory::newSpeciesThermo",type);
return 0;
}
}
/*
* Check the continuity of properties at the midpoint
* temperature.
*/
void NasaThermo::checkContinuity(std::string name, double tmid, const doublereal* clow,
doublereal* chigh) {
// heat capacity
doublereal cplow = poly4(tmid, clow);
doublereal cphigh = poly4(tmid, chigh);
doublereal delta = cplow - cphigh;
if (fabs(delta/cplow) > 0.001) {
writelog("\n\n**** WARNING ****\nFor species "+name+
", discontinuity in cp/R detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "
+fp2str(cplow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "
+fp2str(cphigh)+".\n");
}
// enthalpy
doublereal hrtlow = enthalpy_RT(tmid, clow);
doublereal hrthigh = enthalpy_RT(tmid, chigh);
delta = hrtlow - hrthigh;
if (fabs(delta/hrtlow) > 0.001) {
writelog("\n\n**** WARNING ****\nFor species "+name+
", discontinuity in h/RT detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "
+fp2str(hrtlow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "
+fp2str(hrthigh)+".\n");
}
// entropy
doublereal srlow = entropy_R(tmid, clow);
doublereal srhigh = entropy_R(tmid, chigh);
delta = srlow - srhigh;
if (fabs(delta/srlow) > 0.001) {
writelog("\n\n**** WARNING ****\nFor species "+name+
", discontinuity in s/R detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "
+fp2str(srlow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "
+fp2str(srhigh)+".\n");
}
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k into a SpeciesThermo instance.
* This is called by method installThermoForSpecies if a NASA
* block is found in the XML input.
*/
static void installNasaThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
// default to a single temperature range
bool dualRange = false;
// but if f1ptr is suppled, then it is a two-range
// parameterization
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
// f0 has the lower T data, and f1 the higher T data
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
// if there is no higher range data, then copy c0 to c1.
c1.resize(7,0.0);
copy(c0.begin(), c0.end(), c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
// f1 has the lower T data, and f0 the higher T data
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
// The NasaThermo species property manager expects the
// coefficients in a different order, so rearrange them.
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0);
}
#ifdef INCL_NASA96
/**
* Install a NASA96 polynomial thermodynamic property
* parameterization for species k into a SpeciesThermo instance.
*/
static void installNasa96ThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
c1.resize(7,0.0);
copy(c0.begin(), c0.end(), c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(speciesName, k, NASA, &c[0], tmin, tmax, p0);
}
#endif
/**
* Install a Shomate polynomial thermodynamic property
* parameterization for species k.
*/
static void installShomateThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
c1.resize(7,0.0);
copy(c0.begin(), c0.begin()+7, c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installShomateThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
copy(c0.begin(), c0.begin()+7, c.begin() + 1);
copy(c1.begin(), c1.begin()+7, c.begin() + 8);
sp.install(speciesName, k, SHOMATE, &c[0], tmin, tmax, p0);
}
/**
* Install a constant-cp thermodynamic property
* parameterization for species k.
*/
static void installSimpleThermoFromXML(std::string speciesName,
SpeciesThermo& sp, int k,
const XML_Node& f) {
doublereal tmin, tmax;
tmin = fpValue(f["Tmin"]);
tmax = fpValue(f["Tmax"]);
if (tmax == 0.0) tmax = 1.0e30;
vector_fp c(4);
c[0] = getFloat(f, "t0", "-");
c[1] = getFloat(f, "h0", "-");
c[2] = getFloat(f, "s0", "-");
c[3] = getFloat(f, "cp0", "-");
doublereal p0 = OneAtm;
sp.install(speciesName, k, SIMPLE, &c[0], tmin, tmax, p0);
}
/**
* Install a species thermodynamic property parameterization
* for one species into a species thermo manager.
* @param k species number
* @param s XML node specifying species
* @param spthermo species thermo manager
*/
void SpeciesThermoFactory::
installThermoForSpecies(int k, const XML_Node& s,
SpeciesThermo& spthermo) {
/*
* Check to see that the species block has a thermo block
* before processing. Throw an error if not there.
*/
if (!(s.hasChild("thermo"))) {
throw UnknownSpeciesThermoModel("installSpecies",
s["name"], "<nonexistent>");
}
const XML_Node& thermo = s.child("thermo");
const std::vector<XML_Node*>& tp = thermo.children();
int nc = static_cast<int>(tp.size());
if (nc == 1) {
const XML_Node* f = tp[0];
if (f->name() == "Shomate") {
installShomateThermoFromXML(s["name"], spthermo, k, f, 0);
}
else if (f->name() == "const_cp") {
installSimpleThermoFromXML(s["name"], spthermo, k, *f);
}
else if (f->name() == "NASA") {
installNasaThermoFromXML(s["name"], spthermo, k, f, 0);
}
else if (f->name() == "Mu0") {
installMu0ThermoFromXML(s["name"], spthermo, k, f);
}
else {
throw UnknownSpeciesThermoModel("installSpecies",
s["name"], f->name());
}
}
else if (nc == 2) {
const XML_Node* f0 = tp[0];
const XML_Node* f1 = tp[1];
if (f0->name() == "NASA" && f1->name() == "NASA") {
installNasaThermoFromXML(s["name"], spthermo, k, f0, f1);
}
else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
installShomateThermoFromXML(s["name"], spthermo, k, f0, f1);
}
else {
throw UnknownSpeciesThermoModel("installSpecies", s["name"],
f0->name() + " and "
+ f1->name());
}
}
else {
throw UnknownSpeciesThermoModel("installSpecies", s["name"],
"multiple");
}
}
}

View file

@ -0,0 +1,252 @@
/**
* @file SpeciesThermoFactory.h
* Header for factory to build instances of classes that manage the
* standard-state thermodynamic properties of a set of species
* (see \ref spthermo and class \link Cantera::SpeciesThermoFactory SpeciesThermoFactory\endlink);
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef SPECIESTHERMO_FACTORY_H
#define SPECIESTHERMO_FACTORY_H
#include "SpeciesThermo.h"
#include "ctexceptions.h"
namespace Cantera {
class XML_Node;
/**
* Throw a named error for an unknown or missing species thermo model.
*
* @ingroup thermoprops
*/
class UnknownSpeciesThermoModel: public CanteraError {
public:
//! constructor
/*!
* @param proc Function name error occurred.
* @param spName Species Name that caused the error
* @param speciesThermoModel Unrecognized species thermo model name
*/
UnknownSpeciesThermoModel(std::string proc, std::string spName,
std::string speciesThermoModel) :
CanteraError(proc, "species " + spName +
": Specified speciesThermoPhase model "
+ speciesThermoModel +
" does not match any known type.") {}
//! destructor
virtual ~UnknownSpeciesThermoModel() {}
};
//! Factory to build instances of classes that manage the
//! standard-state thermodynamic properties of a set of species.
/*!
* This class is implemented as a singleton -- one in which
* only one instance is needed. The recommended way to access
* the factory is to call this static method, which
* instantiates the class if it is the first call, but
* otherwise simply returns the pointer to the existing
* instance.
*
* @ingroup thermoprops
*/
class SpeciesThermoFactory {
public:
//! Static method to return an instance of this class
/*!
* This class is implemented as a singleton -- one in which
* only one instance is needed. The recommended way to access
* the factory is to call this static method, which
* instantiates the class if it is the first call, but
* otherwise simply returns the pointer to the existing
* instance.
*/
static SpeciesThermoFactory* factory() {
if (!s_factory) s_factory = new SpeciesThermoFactory;
return s_factory;
}
//! Delete static instance of this class
/**
* If it is necessary to explicitly delete the factory before
* the process terminates (for example, when checking for
* memory leaks) then this method can be called to delete it.
*/
static void deleteFactory() {
if (s_factory) {
delete s_factory;
s_factory = 0;
}
}
//! Destructor
/**
* Doesn't do anything. We do not delete statically
* created single instance of this class here, because it would
* create an infinite loop if destructor is called for that
* single instance.
*/
virtual ~SpeciesThermoFactory() {
}
//! Create a new species property manager.
/*!
* @param type the integer type to be created.
*/
virtual SpeciesThermo* newSpeciesThermo(int type);
//! Create a new species property manager.
/*!
* This routine will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
* @param spData_node Pointer to a speciesData XML Node.
* Each speciesData node contains a list of XML species elements
* e.g., \<speciesData id="Species_Data"\>
*/
virtual SpeciesThermo* newSpeciesThermo(XML_Node* spData_node);
//! Create a new species property manager for a group of species
/*!
* This routine will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
* @param spData_nodes Vector of XML_Nodes, each of which is a speciesData XML Node.
* Each speciesData node contains a list of XML species elements
* e.g., \<speciesData id="Species_Data"\>
*/
virtual SpeciesThermo* newSpeciesThermo(std::vector<XML_Node*> spData_nodes);
//! Create a new species property manager.
/*!
* This routine will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
*
* @param spData_nodes Vector of XML_Nodes, each of which is a speciesData XML Node.
* Each %speciesData node contains a list of XML species elements
* e.g., \<speciesData id="Species_Data"\>
*
* @todo is this used?
*/
virtual SpeciesThermo* newSpeciesThermoOpt(std::vector<XML_Node*> spData_nodes);
virtual void installThermoForSpecies(int k, const XML_Node& s,
SpeciesThermo& spthermo);
private:
//! pointer to the sole instance of this class
static SpeciesThermoFactory* s_factory;
//! Constructor. This is made private, so that only the static
//! method factory() can instantiate the class.
SpeciesThermoFactory(){}
};
////////////////////// Convenience functions ////////////////////
//
// These functions allow using a different factory class that
// derives from SpeciesThermoFactory.
//
//////////////////////////////////////////////////////////////////
//! Create a new species thermo manager instance, by specifying
//!the type and (optionally) a pointer to the factory to use to create it.
/*!
* This utility program will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
* These functions allow using a different factory class that
* derives from SpeciesThermoFactory.
*
* @param type Species thermo type.
* @param f Pointer to a SpeciesThermoFactory. optional parameter.
* Defautls to NULL.
*/
inline SpeciesThermo* newSpeciesThermoMgr(int type,
SpeciesThermoFactory* f=0) {
if (f == 0) {
f = SpeciesThermoFactory::factory();
}
SpeciesThermo* sptherm = f->newSpeciesThermo(type);
return sptherm;
}
//! Function to return SpeciesThermo manager
/*!
* This utility program will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
* These functions allow using a different factory class that
* derives from SpeciesThermoFactory.
*
* @param spData_node Vector of XML_Nodes, each of which is a speciesData XML Node.
* Each %speciesData node contains a list of XML species elements
* e.g., \<speciesData id="Species_Data"\>
* @param f Pointer to a SpeciesThermoFactory. optional parameter.
* Defautls to NULL.
*/
inline SpeciesThermo* newSpeciesThermoMgr(XML_Node* spData_node,
SpeciesThermoFactory* f=0) {
if (f == 0) {
f = SpeciesThermoFactory::factory();
}
SpeciesThermo* sptherm = f->newSpeciesThermo(spData_node);
return sptherm;
}
//! Function to return SpeciesThermo manager
/*!
* This utility program will look through species nodes. It will discover what
* each species needs for its species property managers. Then,
* it will malloc and return the proper species property manager to use.
*
* These functions allow using a different factory class that
* derives from SpeciesThermoFactory.
*
* @param spData_nodes Vector of XML_Nodes, each of which is a speciesData XML Node.
* Each %speciesData node contains a list of XML species elements
* e.g., \<speciesData id="Species_Data"\>
* @param f Pointer to a SpeciesThermoFactory. optional parameter.
* Defautls to NULL.
* @param opt Boolean defaults to false.
*/
inline SpeciesThermo* newSpeciesThermoMgr(std::vector<XML_Node*> spData_nodes,
SpeciesThermoFactory* f=0, bool opt=false) {
if (f == 0) {
f = SpeciesThermoFactory::factory();
}
SpeciesThermo* sptherm;
if (opt) {
sptherm = f->newSpeciesThermoOpt(spData_nodes);
} else {
sptherm = f->newSpeciesThermo(spData_nodes);
}
return sptherm;
}
}
#endif

View file

@ -0,0 +1,150 @@
/**
* @file SpeciesThermoInterpType.h
* Pure Virtual Base class for individual species reference state
* themodynamic managers (see \ref spthermo and class \link Cantera::SpeciesThermoInterpType SpeciesThermoInterpType \endlink).
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#include "speciesThermoTypes.h"
#ifndef CT_SPECIESTHERMOINTERPTYPE_H
#define CT_SPECIESTHERMOINTERPTYPE_H
namespace Cantera {
//! Pure Virtual Base class for individual species reference state
//! themodynamic managers.
/*!
* This differs from the SpeciesThermo virtual
* base class in the sense that this class is meant to handle only
* one species. The speciesThermo class is meant to handle the
* calculation of all the species (or a large subset) in a phase.
*
* One key feature is that the update routines use the same
* form as the update routines in the speciesThermo class. They update
* into a vector of cp_R, s_R, and H_R that spans all of the species in
* a phase. Therefore, this class must carry along a species index into that
* vector.
*
* These routine may be templated. A key requirement of the template is that
* there is a constructor with the following form:
*
* @code
* SpeciesThermoInterpType(int index, doublereal tlow, doublereal thigh,
* doublereal pref, const doublereal* coeffs)
* @endcode
*
* The constructor is used to instantiate the object.
*
* @ingroup spthermo
*/
class SpeciesThermoInterpType {
public:
//! Constructor
SpeciesThermoInterpType() {};
//! Destructor
virtual ~SpeciesThermoInterpType() {};
//! duplicator
virtual SpeciesThermoInterpType *
duplMyselfAsSpeciesThermoInterpType() const = 0;
//! Returns the minimum temperature that the thermo
//! parameterization is valid
virtual doublereal minTemp() const = 0;
//! Returns the maximum temperature that the thermo
//! parameterization is valid
virtual doublereal maxTemp() const = 0;
//! Returns the reference pressure (Pa)
virtual doublereal refPressure() const = 0;
//! Returns an integer representing the type of parameterization
virtual int reportType() const = 0;
//! Update the properties for this species, given a temperature polynomial
/*!
* This method is called with a pointer to an array containing the functions of
* temperature needed by this parameterization, and three pointers to arrays where the
* computed property values should be written. This method updates only one value in
* each array.
*
* The form and length of the Temperature Polynomial may vary depending on the
* parameterization.
*
* @param tempPoly vector of temperature polynomials
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updateProperties(const doublereal* tempPoly,
doublereal* cp_R, doublereal* h_RT,
doublereal* s_R) const = 0;
//! Compute the reference-state property of one species
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of one of the species. The species index is used
* to reference into the cp_R, h_RT, and s_R arrays.
*
* @param temp Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void updatePropertiesTemp(const doublereal temp,
doublereal* cp_R,
doublereal* h_RT,
doublereal* s_R) const = 0;
//!This utility function reports back the type of
//! parameterization and all of the parameters for the
//! species, index.
/*!
* All parameters are output variables
*
* @param index Species index
* @param type Integer type of the standard type
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void reportParameters(int &index, int &type,
doublereal &minTemp, doublereal &maxTemp,
doublereal &refPressure,
doublereal* const coeffs) const = 0;
//! Modify parameters for the standard state
/*!
* @param coeffs Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParameters(doublereal* coeffs) {}
};
}
#endif

View file

@ -0,0 +1,500 @@
/**
* @file SpeciesThermoMgr.h
* This file contains descriptions of templated subclasses of
* the virtual base class, SpeciesThermo, which
* include SpeciesThermoDuo and SpeciesThermo1
* (see \ref spthermo and classes
* \link Cantera::SpeciesThermoDuo SpeciesThermoDuo\endlink and
* \link Cantera::SpeciesThermo1 SpeciesThermo1\endlink)
*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef CT_SPECIESTHERMO_MGR_H
#define CT_SPECIESTHERMO_MGR_H
#include "ct_defs.h"
#include "ctexceptions.h"
#include "stringUtils.h"
#include "SpeciesThermo.h"
#include <map>
namespace Cantera {
//! Invokes the 'updateProperties' method of all objects in the list.
/*!
* This templated function has one template, InputIter. It should
* point to a class such as one that inherits from the virtual
* base class, SpeciesThermoInterpType, which has
* an updateProperties(T, Cp_R, h_RT, s)R) function
*
* @param begin Beginning iterator
* @param end end iterator
* @param T Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*
* @ingroup spthermo
*/
template<class InputIter>
inline void _updateAll(InputIter begin,
InputIter end,
doublereal T,
vector_fp& cp_R,
vector_fp& h_RT,
vector_fp& s_R)
{
for (; begin != end; ++begin)
begin->updateProperties(T, cp_R, h_RT, s_R);
}
//! Iterates through a list of objects which implement a method
//! 'minTemp()', and returns the largest 'minTemp' value.
/*!
* This templated function has one template, InputIter. It should
* point to a class such as one that inherits from either
* SpeciesThermoInterpType or SpeciesThermo, which have a minTemp() function
*
* @param begin Beginning iterator
* @param end end iterator
*
* @ingroup spthermo
*/
template<class InputIter>
doublereal _minTemp(InputIter begin, InputIter end) {
doublereal _minT = 0.0;
for (; begin != end; ++begin)
_minT = fmaxx(_minT, begin->minTemp());
return _minT;
}
//! Iterates through a list of objects which implement a method
//! 'maxTemp()', and returns the smallest 'maxTemp' value.
/*!
* This templated function has one template, InputIter. It should
* point to a class such as one that inherits from either
* SpeciesThermoInterpType or SpeciesThermo which have a minTemp() function
*
* @param begin Beginning iterator
* @param end end iterator
*
* @ingroup spthermo
*/
template<class _InputIter>
doublereal _maxTemp(_InputIter begin, _InputIter end) {
doublereal _maxT = 1.e10;
for (; begin != end; ++begin)
_maxT = fminn(_maxT, begin->maxTemp());
return _maxT;
}
/////////////////////// Exceptions //////////////////////////////
//! Exception thrown if species reference pressures don't match.
/*!
* @ingroup spthermo
*/
class RefPressureMismatch : public CanteraError {
public:
//! constructor
/*!
* @param proc name of the procecdure
* @param prnew reference pressure
* @param prold old reference pressure
*/
RefPressureMismatch(std::string proc, doublereal prnew,
doublereal prold) : CanteraError(proc,
"Species reference pressure ("
+ fp2str(prnew) + ") does not match previously-defined "
+ "reference pressure (" + fp2str(prold) + ")") {}
//! destructor
virtual ~RefPressureMismatch() {}
};
//! Unknown species thermo manager string error
/*!
* @ingroup spthermo
*/
class UnknownSpeciesThermo : public CanteraError {
public:
//! constructor
/*!
* @param proc name of the procecdure
* @param type unknown type
*/
UnknownSpeciesThermo(std::string proc, int type) :
CanteraError(proc, "Specified species parameterization type (" + int2str(type)
+ ") does not match any known type.") {}
//! destructor
virtual ~UnknownSpeciesThermo() {}
};
/**
* This species thermo manager requires that all species have one
* of two parameterizations.
*
* Note this seems to be a slow way to do things, and it may be on its way out.
*
* @ingroup spthermo
*/
template<class T1, class T2>
class SpeciesThermoDuo : public SpeciesThermo {
public:
//! Constructor
SpeciesThermoDuo() {}
//! Destructor
virtual ~SpeciesThermoDuo(){}
/**
* install a new species thermodynamic property
* parameterization for one species.
*
* @param name Name of the species
* @param sp The 'update' method will update the property
* values for this species
* at position i index in the property arrays.
* @param type int flag specifying the type of parameterization to be
* installed.
* @param c vector of coefficients for the parameterization.
* This vector is simply passed through to the
* parameterization constructor.
* @param minTemp minimum temperature for which this parameterization
* is valid.
* @param maxTemp maximum temperature for which this parameterization
* is valid.
* @param refPressure standard-state pressure for this
* parameterization.
* @see speciesThermoTypes.h
*/
virtual void install(std::string name, int sp, int type,
const doublereal* c,
doublereal minTemp,
doublereal maxTemp,
doublereal refPressure) {
m_p0 = refPressure;
if (type == m_thermo1.ID) {
m_thermo1.install(name, sp, 0, c, minTemp, maxTemp,
refPressure);
speciesToType[sp] = m_thermo1.ID;
} else if (type == m_thermo2.ID) {
m_thermo2.install(name, sp, 0, c, minTemp, maxTemp,
refPressure);
speciesToType[sp] = m_thermo2.ID;
} else {
throw UnknownSpeciesThermo("SpeciesThermoDuo:install",type);
}
}
//! Compute the reference-state properties for all species.
/*!
* Given temperature T in K, this method updates the values of
* the non-dimensional heat capacity at constant pressure,
* enthalpy, and entropy, at the reference pressure, Pref
* of each of the standard states.
*
* @param t Temperature (Kelvin)
* @param cp_R Vector of Dimensionless heat capacities.
* (length m_kk).
* @param h_RT Vector of Dimensionless enthalpies.
* (length m_kk).
* @param s_R Vector of Dimensionless entropies.
* (length m_kk).
*/
virtual void update(doublereal t, doublereal* cp_R,
doublereal* h_RT, doublereal* s_R) const {
m_thermo1.update(t, cp_R, h_RT, s_R);
m_thermo2.update(t, cp_R, h_RT, s_R);
}
//! Minimum temperature.
/*!
* If no argument is supplied, this
* method returns the minimum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the minimum
* temperature for species k in the phase.
*
* @param k Species index
*/
virtual doublereal minTemp(int k = -1) const {
doublereal tm1 = m_thermo1.minTemp();
doublereal tm2 = m_thermo2.minTemp();
return (tm1 < tm2 ? tm2 : tm1);
}
//! Maximum temperature.
/*!
* If no argument is supplied, this
* method returns the maximum temperature for which \e all
* parameterizations are valid. If an integer index k is
* supplied, then the value returned is the maximum
* temperature for parameterization k.
*
* @param k index for parameterization k
*/
virtual doublereal maxTemp(int k = -1) const {
doublereal tm1 = m_thermo1.maxTemp();
doublereal tm2 = m_thermo2.maxTemp();
return (tm1 < tm2 ? tm1 : tm2);
}
/**
* The reference-state pressure for species k.
*
* returns the reference state pressure in Pascals for
* species k. If k is left out of the argument list,
* it returns the reference state pressure for the first
* species.
* Note that some SpeciesThermo implementations, such
* as those for ideal gases, require that all species
* in the same phase have the same reference state pressures.
*
* @param k index for parameterization k
*/
virtual doublereal refPressure(int k = -1) const {
return m_p0;
}
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
*
* @param k Species index
*/
virtual int reportType(int k) const {
std::map<int, int>::const_iterator p = speciesToType.find(k);
if (p != speciesToType.end()) {
const int type = p->second;
return type;
}
return -1;
}
/*!
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
*
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
int ctype = reportType(index);
if (ctype == m_thermo1.ID) {
m_thermo1.reportParams(index, type, c, minTemp, maxTemp,
refPressure);
} else if (ctype == m_thermo2.ID) {
m_thermo2.reportParams(index, type, c, minTemp, maxTemp,
refPressure);
} else {
throw CanteraError(" ", "confused");
}
}
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c) {
int ctype = reportType(index);
if (ctype == m_thermo1.ID) {
m_thermo1.modifyParams(index, c);
} else if (ctype == m_thermo2.ID) {
m_thermo2.modifyParams(index, c);
} else {
throw CanteraError("modifyParams", "confused");
}
}
private:
//! Thermo Type 1
T1 m_thermo1;
//! Thermo Type 2
T2 m_thermo2;
//! Reference pressure
doublereal m_p0;
//! map from species to type
std::map<int, int> speciesToType;
};
//! This species thermo manager requires that all species have the
//! same parameterization.
/*!
*
* This is a templated class. The first template is called SPM. SPM
* is an object that calculates the thermo for one species. This
* class contains a vector of SPM's, one for each
* species. Together, the vector of SPM's is itself a SpeciesThermo
* class.
*
* @todo The form of the template class, SPM, is basically
* unspecified. it needs to be nailed down to a specific
* form. One way to do this is with a virtual base class
* formulation. Note, that the specification could be that it
* inherits from the class SpeciesThermo, itself.
*
* @deprecated Note this is currently unused and it may be on its way out.
*
* @ingroup spthermo
*/
template<class SPM>
class SpeciesThermo1 : public SpeciesThermo {
public:
//! base constructor
SpeciesThermo1() : m_pref(0.0) {}
//! destructor
virtual ~SpeciesThermo1(){}
//! Install one species into this Species Thermo Manager
/*!
* @param name Name of the species
* @param sp Species index
* @param type species type in terms of an int
* @param c Parameters for the species thermo
*/
virtual void install(std::string name, int sp, int type, const vector_fp& c) {
m_thermo.push_back(SPM(sp, c));
if (m_pref) {
if (m_thermo.begin()->refPressure() != m_pref) {
throw RefPressureMismatch("SpeciesThermo1:install",
refPressure(), m_pref);
}
}
else m_pref = m_thermo.begin()->refPressure();
}
//! update the object, because the temperature changed
/*!
* @param t temperature(Kelvin)
* @param cp_R vector of dimensionless heat capacity
* @param h_RT vector of dimensionless enthalpy
* @param s_R vector of dimensionless entropy
*/
virtual void update(doublereal t, vector_fp& cp_R,
vector_fp& h_RT, vector_fp& s_R) const {
_updateAll(m_thermo.begin(),m_thermo.end(),
t, cp_R, h_RT, s_R);
}
//! update the object for one species, because the temperature changed
/*!
* @param k species index
* @param t temperature(Kelvin)
* @param cp_R vector of dimensionless heat capacity
* @param h_RT vector of dimensionless enthalpy
* @param s_R vector of dimensionless entropy
*/
virtual void update_one(int k, doublereal t, vector_fp& cp_R,
vector_fp& h_RT, vector_fp& s_R) const {
m_thermo[k]->update(t, cp_R, h_RT, s_R);
}
//! returns the minimum temperature
/*!
* @param k species index. Defaults to -1.
*/
virtual doublereal minTemp(int k = -1) const {
if (k < 0)
return _minTemp(m_thermo.begin(), m_thermo.end());
else
return m_thermo[k].minTemp();
}
//! returns the maximum temperature
/*!
* @param k species index. Defaults to -1.
*/
virtual doublereal maxTemp(int k = -1) const {
if (k < 0)
return _maxTemp(m_thermo.begin(), m_thermo.end());
else
return m_thermo[k].maxTemp();
}
//! returns the reference pressure
/*!
* @param k species index. Defaults to -1.
*/
virtual doublereal refPressure(int k = -1) const {
return m_pref;
}
//! This utility function reports the type of parameterization
//! used for the species with index number index.
/*!
* Note, all parameterizations are the same, by definition, here
*
* @param k Species index
*/
virtual int reportType(int k) const {
return m_thermo[k]->reportType(-1);
}
/*!
* This utility function reports back the type of
* parameterization and all of the parameters for the
* species, index.
*
* @param index Species index
* @param type Integer type of the standard type
* @param c Vector of coefficients used to set the
* parameters for the standard state.
* @param minTemp output - Minimum temperature
* @param maxTemp output - Maximum temperature
* @param refPressure output - reference pressure (Pa).
*/
virtual void reportParams(int index, int &type,
doublereal * const c,
doublereal &minTemp,
doublereal &maxTemp,
doublereal &refPressure) const {
m_thermo[index]->reportParameters(index, type, c, minTemp, maxTemp, refPressure);
}
//! Modify parameters for the standard state
/*!
* @param index Species index
* @param c Vector of coefficients used to set the
* parameters for the standard state.
*/
virtual void modifyParams(int index, doublereal *c) {
m_thermo[index]->modifyParameters(index, c);
}
private:
//! Vector of SPM objects. There are m_kk of them
std::vector<SPM> m_thermo;
//! Reference pressure (Pa)
doublereal m_pref;
};
//#endif
}
#endif

View file

@ -0,0 +1,227 @@
/**
*
* @file State.cpp
* Definitions for the class State, that manages the independent variables of temperature, mass density,
* and species mass/mole fraction that define the thermodynamic state (see \ref phases and
* class \link Cantera::State State\endlink).
*
*/
/*
* $Author$
* $Date$
* $Revision$
*
* Copyright 2003-2004 California Institute of Technology
* See file License.txt for licensing information
*
*/
#include "utilities.h"
#include "ctexceptions.h"
#include "stringUtils.h"
#include "State.h"
//#ifdef DARWIN
//#include <Accelerate.h>
//#endif
using namespace std;
namespace Cantera {
State::State() : m_kk(0), m_temp(0.0), m_dens(0.001), m_mmw(0.0) {}
State::~State() {}
State::State(const State& right) :
m_kk(0),
m_temp(0.0),
m_dens(0.001),
m_mmw(0.0) {
/*
* Call the assignment operator.
*/
*this = operator=(right);
}
/*
* Assignment operator for the State Class
*/
State& State::operator=(const State& right) {
/*
* Check for self assignment.
*/
if (this == &right) return *this;
/*
* We do a straight assignment operator on all of the
* data. The vectors are copied.
*/
m_temp = right.m_temp;
m_dens = right.m_dens;
m_mmw = right.m_mmw;
m_y = right.m_y;
m_molwts = right.m_molwts;
m_rmolwts = right.m_rmolwts;
/*
* Return the reference to the current object
*/
return *this;
}
doublereal State::moleFraction(int k) const {
if (k >= 0 && k < m_kk) {
return m_ym[k] * m_mmw;
}
else {
throw CanteraError("State:moleFraction",
"illegal species index number");
}
}
void State::setMoleFractions(const doublereal* x) {
int k;
doublereal sum = 0.0, norm = 0.0;
sum = dot(x, x + m_kk, m_molwts.begin());
for (k = 0; k != m_kk; ++k) {
m_ym[k] = x[k] / sum;
m_y[k] = m_molwts[k]*m_ym[k];
norm += x[k];
}
m_mmw = sum/norm;
}
void State::setMoleFractions_NoNorm(const doublereal* x) {
int k;
m_mmw = dot(x, x + m_kk, m_molwts.begin());
doublereal rmmw = 1.0/m_mmw;
for (k = 0; k != m_kk; ++k) {
m_ym[k] = x[k]*rmmw;
m_y[k] = m_ym[k] * m_molwts[k];
}
}
doublereal State::massFraction(int k) const {
if (k >= 0 && k < m_kk) {
return m_y[k];
}
else {
throw CanteraError("State:massFraction",
"illegal species index number");
}
}
doublereal State::concentration(int k) const {
if (k >= 0 && k < m_kk) {
return m_y[k] * m_dens * m_rmolwts[k] ;
}
else {
throw CanteraError("State:massFraction",
"illegal species index number");
}
}
void State::setMassFractions(const doublereal* y) {
doublereal norm = 0.0, sum = 0.0;
int k;
//cblas_dcopy(m_kk, y, 1, m_y.begin(), 1);
for (k = 0; k != m_kk; ++k) {
norm += y[k];
m_y[k] = y[k];
}
//scale(y, y + m_kk, m_y.begin(), 1.0/norm);
scale(m_kk, 1.0/norm, m_y.begin());
for (k = 0; k != m_kk; ++k) {
m_ym[k] = m_y[k] * m_rmolwts[k];
sum += m_ym[k];
}
m_mmw = 1.0/sum;
}
void State::setMassFractions_NoNorm(const doublereal* y) {
int k;
doublereal sum = 0.0;
for (k = 0; k != m_kk; ++k) {
m_y[k] = y[k];
m_ym[k] = m_y[k] * m_rmolwts[k];
sum += m_ym[k];
}
m_mmw = 1.0/sum;
}
doublereal State::sum_xlogx() const {
return m_mmw* Cantera::sum_xlogx(m_ym.begin(), m_ym.end()) + log(m_mmw);
}
doublereal State::sum_xlogQ(doublereal* Q) const {
return m_mmw * Cantera::sum_xlogQ(m_ym.begin(), m_ym.end(), Q);
}
void State::setConcentrations(const doublereal* c) {
int k;
doublereal sum = 0.0, norm = 0.0;
for (k = 0; k != m_kk; ++k) {
sum += c[k]*m_molwts[k];
norm += c[k];
}
m_mmw = sum/norm;
setDensity(sum);
doublereal rsum = 1.0/sum;
for (k = 0; k != m_kk; ++k) {
m_ym[k] = c[k] * rsum;
m_y[k] = m_ym[k] * m_molwts[k];
}
}
void State::getConcentrations(doublereal* c) const {
scale(m_ym.begin(), m_ym.end(), c, m_dens);
}
doublereal State::mean_Y(const doublereal* Q) const {
return dot(m_y.begin(), m_y.end(), Q);
}
void State::getMoleFractions(doublereal* x) const {
scale(m_ym.begin(), m_ym.end(), x, m_mmw);
}
void State::getMassFractions(doublereal* y) const {
copy(m_y.begin(), m_y.end(), y);
}
void State::init(const array_fp& mw) {
m_kk = mw.size();
m_molwts.resize(m_kk);
m_rmolwts.resize(m_kk);
m_y.resize(m_kk, 0.0);
m_ym.resize(m_kk, 0.0);
copy(mw.begin(), mw.end(), m_molwts.begin());
for (int k = 0; k < m_kk; k++) {
if (m_molwts[k] < 0.0) {
throw CanteraError("State::init",
"negative molecular weight for species number "+int2str(k));
}
/*
* Some surface phases may define species representing
* empty sites that have zero molecular weight. Give them
* a very small molecular weight to avoid dividing by
* zero.
*/
if (m_molwts[k] < Tiny) m_molwts[k] = Tiny;
m_rmolwts[k] = 1.0/m_molwts[k];
}
/*
* Now that we have resized the State object, let's fill it with
* a valid mass fraction vector that sums to one. The State object
* should never have a mass fraction vector that doesn't sum to one.
* We will assume that species 0 has a mass fraction of 1.0 and
* mass fraction of all other species is 0.0.
*/
m_y[0] = 1.0;
m_ym[0] = m_y[0] * m_rmolwts[0];
m_mmw = 1.0 / m_ym[0];
}
}

415
Cantera/src/thermo/State.h Executable file
View file

@ -0,0 +1,415 @@
/**
* @file State.h
* Header for the class State, that manages the independent variables of temperature, mass density,
* and species mass/mole fraction that define the thermodynamic state (see \ref phases and
* class \link Cantera::State State\endlink).
*/
/*
* $Author$
* $Date$
* $Revision$
*
* Copyright 2001-2003 California Institute of Technology
* See file License.txt for licensing information
*
*/
#ifndef CT_STATE2_H
#define CT_STATE2_H
#include "ct_defs.h"
namespace Cantera {
//! Manages the independent variables of temperature, mass density,
//! and species mass/mole fraction that define the thermodynamic
//! state.
/*!
* Class State stores just enough information about a
* multicomponent solution to specify its intensive thermodynamic
* state. It stores values for the temperature, mass density, and
* an array of species mass fractions. It also stores an array of
* species molecular weights, which are used to convert between
* mole and mass representations of the composition. These are the
* \e only properties of the species that class State knows about.
* For efficiency in mass/mole conversion, the vector of mass
* fractions divided by molecular weight \f$ Y_k/M_k \f$ is also
* stored.
*
* Class State is not usually used directly in application
* programs. Its primary use is as a base class for class
* Phase. Class State has no virtual methods, and none of its
* methods are meant to be overloaded. However, this is one exception.
* If the phase is incompressible, then the density must be replaced
* by the pressure as the independent variable. In this case, functions
* such as setMassFraction within the class %State must actually now
* calculate the density (at constant T and P) instead of leaving
* it alone as befits an independent variable. Threfore, these type
* of functions are virtual functions and need to be overloaded
* for incompressible phases. Note, for almost incompressible phases
* (or phases which utilize standard states based on a T and P) this
* may be advantageous as well, and they need to overload these functions
* too.
*
* @ingroup phases
*/
class State {
public:
/**
* Constructor.
*/
State();
/**
* Destructor. Since no memory is allocated by methods of this
* class, the destructor does nothing.
*/
virtual ~State();
/**
* Copy Constructor for the State Class
*
* @param right Reference to the class to be copied.
*/
State(const State& right);
/**
* Assignment operator for the state class.
*
* @param right Reference to the class to be copied.
*/
State& operator=(const State& right);
/// @name Species Information
///
/// The only thing class State knows about the species is their
/// molecular weights.
//@{
/// Return a read-only reference to the array of molecular
/// weights.
const array_fp& molecularWeights() const { return m_molwts; }
//@}
/// @name Composition
//@{
//! Get the species mole fraction vector.
/*!
* @param x On return, x contains the mole fractions. Must have a
* length greater than or equal to the number of species.
*/
void getMoleFractions(doublereal* x) const;
//! The mole fraction of species k.
/*!
* If k is ouside the valid
* range, an exception will be thrown. Note that it is
* somewhat more efficent to call getMoleFractions if the
* mole fractions of all species are desired.
* @param k species index
*/
doublereal moleFraction(int k) const;
/**
* Set the mole fractions to the specified values, and then
* normalize them so that they sum to 1.0.
* @param x Array of unnormalized mole fraction values (input).
* Must have a length greater than or equal to the number of
* species.
*
* @param x Input vector of mole fractions.
* Length is m_kk.
*/
virtual void setMoleFractions(const doublereal* x);
/**
* Set the mole fractions to the specified values without
* normalizing. This is useful when the normalization
* condition is being handled by some other means, for example
* by a constraint equation as part of a larger set of
* equations.
*
* @param x Input vector of mole fractions.
* Length is m_kk.
*/
virtual void setMoleFractions_NoNorm(const doublereal* x);
/**
* Get the species mass fractions.
* @param y On return, y
* contains the mass fractions. Array \a y must have a length
* greater than or equal to the number of species.
*
* @param y Output vector of mass fractions.
* Length is m_kk.
*/
void getMassFractions(doublereal* y) const;
//! Mass fraction of species k.
/*!
* If k is outside the valid
* range, an exception will be thrown. Note that it is
* somewhat more efficent to call getMassFractions if the
* mass fractions of all species are desired.
*
* @param k species index
*/
doublereal massFraction(int k) const;
/**
* Set the mass fractions to the specified values, and then
* normalize them so that they sum to 1.0.
* @param y Array of unnormalized mass fraction values (input).
* Must have a length greater than or equal to the number of
* species.
*
* @param y Input vector of mass fractions.
* Length is m_kk.
*/
virtual void setMassFractions(const doublereal* y);
/**
* Set the mass fractions to the specified values without
* normalizing. This is useful when the normalization
* condition is being handled by some other means, for example
* by a constraint equation as part of a larger set of
* equations.
*
* @param y Input vector of mass fractions.
* Length is m_kk.
*/
virtual void setMassFractions_NoNorm(const doublereal* y);
/**
* Get the species concentrations (kmol/m^3). @param c On
* return, \a c contains the concentrations for all species.
* Array \a c must have a length greater than or equal to the
* number of species.
*/
void getConcentrations(doublereal* c) const;
/**
* Concentration of species k. If k is outside the valid
* range, an exception will be thrown.
*
* @param k Index of species
*/
doublereal concentration(int k) const;
/**
* Set the concentrations to the specified values within the
* phase.
*
* @param c The input vector to this routine is in dimensional
* units. For volumetric phases c[k] is the
* concentration of the kth species in kmol/m3.
* For surface phases, c[k] is the concentration
* in kmol/m2. The length of the vector is the number
* of species in the phase.
*/
virtual void setConcentrations(const doublereal* c);
/**
* Returns a read-only pointer to the start of the
* massFraction array
*/
const doublereal* massFractions() const { return &m_y[0]; }
/**
* Returns a read-only pointer to the start of the
* moleFraction/MW array. This array is the array of mole
* fractions, each divided by the mean molecular weight.
*/
const doublereal* moleFractdivMMW() const { return &m_ym[0];}
//@}
/// @name Mean Properties
//@{
/**
* Evaluate the mole-fraction-weighted mean of Q:
* \f[ \sum_k X_k Q_k. \f]
* Array Q should contain pure-species molar property
* values.
*
* @param Q input vector of length m_kk that is to be averaged.
* @return
* mole-freaction-weighted mean of Q
*/
doublereal mean_X(const doublereal* Q) const {
return m_mmw*std::inner_product(m_ym.begin(), m_ym.end(), Q, 0.0);
}
/**
* Evaluate the mass-fraction-weighted mean of Q:
* \f[ \sum_k Y_k Q_k \f]
*
* @param Q Array Q contains a vector of species property values in mass units.
* @return
* Return value containing the mass-fraction-weighted mean of Q.
*/
doublereal mean_Y(const doublereal* Q) const;
/**
* The mean molecular weight. Units: (kg/kmol)
*/
doublereal meanMolecularWeight() const {
return m_mmw;
}
//! Evaluate \f$ \sum_k X_k \log X_k \f$.
/*!
* @return
* returns the indicated sum. units are dimensionless.
*/
doublereal sum_xlogx() const;
//! Evaluate \f$ \sum_k X_k \log Q_k \f$.
/*!
* @param Q Vector of length m_kk to take the log average of
* @return Returns the indicated sum.
*/
doublereal sum_xlogQ(doublereal* Q) const;
//@}
/// @name Thermodynamic Properties
/// Class State only stores enough thermodynamic data to
/// specify the state. In addition to composition information,
/// it stores the temperature and
/// mass density.
//@{
/// Temperature (K).
doublereal temperature() const { return m_temp; }
/// Density (kg/m^3).
doublereal density() const { return m_dens; }
/// Molar density (kmol/m^3).
doublereal molarDensity() const {
return m_dens/meanMolecularWeight();
}
//! Set the internally storred density (kg/m^3) of the phase
/*!
* Note the density of a phase is an indepedent variable.
*
* @param density Input density (kg/m^3).
*/
virtual void setDensity(doublereal density) {
m_dens = density;
}
//! Set the internally storred molar density (kmol/m^3) of the phase.
/*!
* @param molarDensity Input molar density (kmol/m^3).
*/
virtual void setMolarDensity(doublereal molarDensity) {
m_dens = molarDensity*meanMolecularWeight();
}
//! Set the temperature (K).
/*!
* This function sets the internally storred temperature of the phase.
*
* @param temp Temperature in kelvin
*
* @todo Make State::setTemperature a virtual function
*/
void setTemperature(doublereal temp) {
m_temp = temp;
}
//@}
//! True if the number species has been set
bool ready() const { return (m_kk > 0); }
protected:
/**
* @internal
* Initialize. Make a local copy of the vector of
* molecular weights, and resize the composition arrays to
* the appropriate size. The only information an instance of
* State has about the species is their molecular weights.
*
* @param mw Vector of molecular weights of the species.
*/
void init(const array_fp& mw); //, density_is_independent = true);
/**
* m_kk is the number of species in the phase
*/
int m_kk;
//! Set the molecular weight of a single species to a given value
/*!
* @param k id of the species
* @param mw Molecular Weight (kg kmol-1)
*/
void setMolecularWeight(int k, double mw) {
m_molwts[k] = mw;
m_rmolwts[k] = 1.0/mw;
}
private:
/**
* Temperature. This is an independent variable
* units = Kelvin
*/
doublereal m_temp;
/**
* Density. This is an independent variable except in
* the incompressible degenerate case. Thus,
* the pressure is determined from this variable
* not the other way round.
* units = kg m-3
*/
doublereal m_dens;
/**
* m_mmw is the mean molecular weight of the mixture
* (kg kmol-1)
*/
doublereal m_mmw;
/**
* m_ym[k] = mole fraction of species k divided by the
* mean molecular weight of mixture.
*/
mutable array_fp m_ym;
/**
* m_y[k] = mass fraction of species k
*/
mutable array_fp m_y;
/**
* m_molwts[k] = molecular weight of species k (kg kmol-1)
*/
array_fp m_molwts;
/**
* m_rmolwts[k] = inverse of the molecular weight of species k
* units = kmol kg-1.
*/
array_fp m_rmolwts;
};
}
#endif

View file

@ -0,0 +1,74 @@
/**
*
* @file StoichSubstance.cpp
*
*/
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ct_defs.h"
#include "mix_defs.h"
#include "StoichSubstance.h"
#include "SpeciesThermo.h"
namespace Cantera {
void StoichSubstance::initThermo() {
m_kk = nSpecies();
if (m_kk > 1) {
throw CanteraError("initThermo",
"stoichiometric substances may only contain one species.");
}
doublereal tmin = m_spthermo->minTemp();
doublereal tmax = m_spthermo->maxTemp();
if (tmin > 0.0) m_tmin = tmin;
if (tmax > 0.0) m_tmax = tmax;
m_p0 = refPressure();
int leng = m_kk;
m_h0_RT.resize(leng);
m_cp0_R.resize(leng);
m_s0_R.resize(leng);
}
void StoichSubstance::_updateThermo() const {
doublereal tnow = temperature();
if (m_tlast != tnow) {
m_spthermo->update(tnow, &m_cp0_R[0], &m_h0_RT[0],
&m_s0_R[0]);
m_tlast = tnow;
}
}
void StoichSubstance::
getUnitsStandardConc(double *uA, int k, int sizeUA) {
for (int i = 0; i < sizeUA; i++) {
uA[i] = 0.0;
}
}
void StoichSubstance::setParameters(int n, double * c) {
double rho = c[0];
setDensity(rho);
}
void StoichSubstance::getParameters(int &n, double * const c) {
double rho = density();
c[0] = rho;
}
void StoichSubstance::setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","StoichSubstance");
doublereal rho = getFloat(eosdata, "density", "-");
setDensity(rho);
}
}

View file

@ -0,0 +1,429 @@
/**
*
* @file StoichSubstance.h
*
* This file contains the class declarations for the StoichSubstance
* ThermoPhase class.
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2001 California Institute of Technology
*
*/
#ifndef CT_STOICHSUBSTANCE_H
#define CT_STOICHSUBSTANCE_H
#include "mix_defs.h"
#include "ThermoPhase.h"
#include "SpeciesThermo.h"
namespace Cantera {
/**
* @ingroup thermoprops
*
* Class StoichSubstance represents a stoichiometric (fixed composition)
* incompressible substance.
* \nosubgrouping
*
*/
class StoichSubstance : public ThermoPhase {
public:
StoichSubstance():
m_kk(0),
m_tmin(0.0),
m_tmax(0.0),
m_press(OneAtm),
m_p0(OneAtm),
m_tlast(-1.0) {}
virtual ~StoichSubstance() {}
/**
*
* @name Utilities
* @{
*/
/**
* Equation of state flag. Returns the value cStoichSubstance,
* defined in mix_defs.h.
*/
virtual int eosType() const { return cStoichSubstance; }
/**
* @}
* @name Molar Thermodynamic Properties of the Solution ---------
* @{
*/
/**
* Molar enthalpy. Units: J/kmol. For an incompressible,
* stoichiometric substance, the internal energy is
* independent of pressure, and therefore the molar enthalpy
* is \f[ \hat h(T, P) = \hat u(T) + P \hat v \f], where the
* molar specific volume is constant.
*/
virtual doublereal enthalpy_mole() const {
double hh = intEnergy_mole() + m_press / molarDensity();
return hh;
}
/**
* Molar internal energy. J/kmol. For an incompressible,
* stoichiometric substance, the molar internal energy is
* independent of pressure. Since the thermodynamic properties
* are specified by giving the standard-state enthalpy, the
* term \f$ P_0 \hat v\f$ is subtracted from the specified molar
* enthalpy to compute the molar internal energy.
*/
virtual doublereal intEnergy_mole() const {
_updateThermo();
return GasConstant * temperature() * m_h0_RT[0]
- m_p0 / molarDensity();
}
/**
* Molar entropy. Units: J/kmol/K. For an incompressible,
* stoichiometric substance, the molar entropy depends only on
* the temperature.
*/
virtual doublereal entropy_mole() const {
_updateThermo();
return GasConstant * m_s0_R[0];
}
/**
* Molar gibbs Function. Units: J/kmol. This is determined
* from the molar enthalpy and entropy functions.
*/
virtual doublereal gibbs_mole() const {
return enthalpy_mole() - temperature() * entropy_mole();
}
/**
* Molar heat capacity at constant pressure. Units: J/kmol/K.
* For an incompressible substance, \f$ \hat c_p = \hat c_v\f$.
*/
virtual doublereal cp_mole() const {
_updateThermo();
return GasConstant * m_cp0_R[0];
}
/**
* Molar heat capacity at constant volume. Units: J/kmol/K.
* For an incompressible substance, \f$ \hat c_p = \hat c_v\f$.
*/
virtual doublereal cv_mole() const {
return cp_mole();
}
//@}
/**
* @name Mechanical Equation of State
* @{
*/
//! Report the Pressure. Units: Pa.
/*!
* For an incompressible substance, the density is independent
* of pressure. This method simply returns the storred
* pressure value.
*/
virtual doublereal pressure() const {
return m_press;
}
//! Set the pressure at constant temperature. Units: Pa.
/*!
* For an incompressible substance, the density is
* independent of pressure. Therefore, this method only
* stores the specified pressure value. It does not
* modify the density.
*
* @param p Pressure (units - Pa)
*/
virtual void setPressure(doublereal p) {
m_press = p;
}
//@}
/**
* @name Chemical Potentials and Activities
*@{
*/
/**
* This method returns the array of generalized
* concentrations. For a stoichiometric substance, there is
* only one species, and the generalized concentration is 1.0.
*/
virtual void getActivityConcentrations(doublereal* c) const {
c[0] = 1.0;
}
/**
* The standard concentration. This is defined as the concentration
* by which the generalized concentration is normalized to produce
* the activity.
*/
virtual doublereal standardConcentration(int k=0) const {
return 1.0;
}
/**
* Returns the natural logarithm of the standard
* concentration of the kth species
*/
virtual doublereal logStandardConc(int k=0) const {
return 0.0;
}
/**
* Get the array of chemical potentials at unit activity
* \f$ \mu^0_k \f$.
*
* For a stoichiometric substance, there is no activity term in
* the chemical potential expression, and therefore the
* standard chemical potential and the chemical potential
* are both equal to the molar Gibbs function.
*/
virtual void getStandardChemPotentials(doublereal* mu0) const {
mu0[0] = gibbs_mole();
}
/**
* Returns the units of the standard and generalized
* concentrations Note they have the same units, as their
* ratio 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 = 0
* uA[1] = m units - default = 0
* 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
*/
virtual void getUnitsStandardConc(double *uA, int k = 0,
int sizeUA = 6);
//@}
/// @name Partial Molar Properties of the Solution ----------------------------------
//@{
/**
* Get the array of non-dimensional chemical potentials
* \f$ \mu_k / \hat R T \f$.
*/
virtual void getChemPotentials_RT(doublereal* mu) const {
mu[0] = gibbs_mole() / (GasConstant * temperature());
}
/**
* For a stoichiometric substance, there is only one species.
* This method returns the molar gibbs function in the
* first element of array \c mu.
*/
virtual void getChemPotentials(doublereal* mu) const {
mu[0] = gibbs_mole();
}
/**
* Get the species electrochemical potentials. Units: J/kmol.
* This method adds a term \f$ Fz_k \phi_k \f$ to the
* to each chemical potential.
*/
void getElectrochemPotentials(doublereal* mu) const {
getChemPotentials(mu);
}
/**
* Returns an array of partial molar enthalpies for the species
* in the mixture.
* Units (J/kmol)
*/
virtual void getPartialMolarEnthalpies(doublereal* hbar) const {
hbar[0] = enthalpy_mole();
}
/**
* Returns an array of partial molar entropies of the species in the
* solution. Units: J/kmol/K.
*/
virtual void getPartialMolarEntropies(doublereal* sbar) const {
sbar[0] = entropy_mole();
}
/**
* returns an array of partial molar volumes of the species
* in the solution. Units: m^3 kmol-1.
*/
virtual void getPartialMolarVolumes(doublereal* vbar) const {
vbar[0] = 1.0 / molarDensity();
}
//@}
/// @name Properties of the Standard State of the Species in the Solution -------------------------------------
//@{
/**
* Get the nondimensional Enthalpy functions for the species
* at their standard states at the current
* <I>T</I> and <I>P</I> of the solution.
*/
virtual void getEnthalpy_RT(doublereal* hrt) const {
hrt[0] = enthalpy_mole() / (GasConstant * temperature());
}
/**
* Get the array of nondimensional Enthalpy functions for the
* standard state species
* at the current <I>T</I> and <I>P</I> of the solution.
*/
virtual void getEntropy_R(doublereal* sr) const {
sr[0] = entropy_mole() / GasConstant;
}
/**
* Get the nondimensional Gibbs functions for the species
* at their standard states of solution at the current T and P
* of the solution.
*/
virtual void getGibbs_RT(doublereal* grt) const {
grt[0] = gibbs_mole() / (GasConstant * temperature());
}
/**
* Get the nondimensional Heat Capacities at constant
* pressure for the standard state of the species
* at the current T and P.
*/
virtual void getCp_R(doublereal* cpr) const {
cpr[0] = cp_mole() / GasConstant;
}
/**
* Get the standard volumes for the standard state of the species
* at the current T and P
*/
virtual void getStandardVolumes(doublereal*vol) const {
vol[0] = 1.0 / molarDensity();
}
//@}
/// @name Thermodynamic Values for the Species Reference States --------------------
//@{
/**
* Returns the vector of nondimensional
* enthalpies of the reference state at the current temperature
* of the solution and the reference pressure for the species.
*
* This function fills in its one entry in hrt[] by calling
* the underlying species thermo function for the
* dimensionless enthalpy.
*/
virtual void getEnthalpy_RT_ref(doublereal *hrt) const {
_updateThermo();
hrt[0] = m_h0_RT[0];
}
/**
* Returns the vector of nondimensional
* enthalpies of the reference state at the current temperature
* of the solution and the reference pressure for the species.
*
* This function fills in its one entry in hrt[] by calling
* the underlying species thermo function for the
* dimensionless gibbs free energy, calculated from the
* dimensionless enthalpy and entropy.
*/
virtual void getGibbs_RT_ref(doublereal *grt) const {
_updateThermo();
grt[0] = m_h0_RT[0] - m_s0_R[0];
}
/**
* Returns the vector of the
* gibbs function of the reference state at the current temperature
* of the solution and the reference pressure for the species.
* units = J/kmol
*
* This function fills in its one entry in g[] by calling
* the underlying species thermo functions for the
* gibbs free energy, calculated from enthalpy and the
* entropy, and the multiplying by RT.
*/
virtual void getGibbs_ref(doublereal *g) const {
getGibbs_RT_ref(g);
g[0] *= GasConstant * temperature();
}
/**
* Returns the vector of nondimensional
* entropies of the reference state at the current temperature
* of the solution and the reference pressure for the species.
*
* This function fills in its one entry in hrt[] by calling
* the underlying species thermo function for the
* dimensionless entropy.
*/
virtual void getEntropy_R_ref(doublereal *er) const {
_updateThermo();
er[0] = m_s0_R[0];
}
virtual void initThermo();
virtual void setParameters(int n, double *c);
virtual void getParameters(int &n, double * const c);
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:
int m_kk;
doublereal m_tmin, m_tmax, m_press, m_p0;
mutable doublereal m_tlast;
mutable array_fp m_h0_RT;
mutable array_fp m_cp0_R;
mutable array_fp m_s0_R;
private:
void _updateThermo() const;
};
}
#endif

View file

@ -22,7 +22,8 @@
#include "StoichSubstanceSSTP.h"
#include "SpeciesThermo.h"
#include <string>
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
namespace Cantera {

View file

@ -0,0 +1,303 @@
/**
* @file SurfPhase.cpp
* Definitions for a simple thermoydnamics model of a surface phase derived from ThermoPhase,
* assuming an ideal solution model
* (see \ref thermoprops and class \link Cantera::SurfPhase SurfPhase\endlink).
*/
// Copyright 2002 California Institute of Technology
// turn off warnings under Windows
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "SurfPhase.h"
#include "EdgePhase.h"
#include "utilities.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include <iostream>
using namespace std;
///////////////////////////////////////////////////////////
//
// class SurfPhase methods
//
///////////////////////////////////////////////////////////
namespace Cantera {
SurfPhase::
SurfPhase(doublereal n0):
ThermoPhase(),
m_n0(n0),
m_logn0(0.0),
m_tmin(0.0),
m_tmax(0.0),
m_press(OneAtm),
m_tlast(0.0)
{
if (n0 > 0.0) m_logn0 = log(n0);
setNDim(2);
}
SurfPhase::SurfPhase(XML_Node& xmlphase) {
const XML_Node& th = xmlphase.child("thermo");
string model = th["model"];
if (model != "Surface") {
throw CanteraError("SurfPhase::SurfPhase",
"thermo model attribute must be Surface");
}
importPhase(xmlphase, this);
}
doublereal SurfPhase::
enthalpy_mole() const {
if (m_n0 <= 0.0) return 0.0;
_updateThermo();
return mean_X(DATA_PTR(m_h0));
}
SurfPhase::
~SurfPhase() { }
/*
* For a surface phase, the pressure is not a relevant
* thermodynamic variable, and so the Enthalpy is equal to the
* internal energy.
*/
doublereal SurfPhase::
intEnergy_mole() const { return enthalpy_mole(); }
void SurfPhase::
getStandardChemPotentials(doublereal* mu0) const {
_updateThermo();
copy(m_mu0.begin(), m_mu0.end(), mu0);
}
void SurfPhase::
getChemPotentials(doublereal* mu) const {
_updateThermo();
copy(m_mu0.begin(), m_mu0.end(), mu);
int k;
getActivityConcentrations(DATA_PTR(m_work));
for (k = 0; k < m_kk; k++) {
mu[k] += GasConstant * temperature() * (log(m_work[k]) - logStandardConc(k));
}
}
void SurfPhase::
getActivityConcentrations(doublereal* c) const {
getConcentrations(c);
}
doublereal SurfPhase::
standardConcentration(int k) const {
return m_n0/size(k);
}
doublereal SurfPhase::
logStandardConc(int k) const {
return m_logn0 - m_logsize[k];
}
/// The only parameter that can be set is the site density.
void SurfPhase::
setParameters(int n, doublereal* c) {
if (n != 1) {
throw CanteraError("SurfPhase::setParameters",
"Bad value for number of parameter");
}
m_n0 = c[0];
if (m_n0 <= 0.0) {
throw CanteraError("SurfPhase::setParameters",
"Bad value for parameter");
}
m_logn0 = log(m_n0);
}
void SurfPhase::
getEnthalpy_RT(doublereal* hrt) const {
_updateThermo();
double rrt = 1.0/(GasConstant*temperature());
scale(m_h0.begin(), m_h0.end(), hrt, rrt);
}
void SurfPhase::
getEntropy_R(doublereal* sr) const {
_updateThermo();
double rr = 1.0/GasConstant;
scale(m_s0.begin(), m_s0.end(), sr, rr);
}
void SurfPhase::
initThermo() {
m_h0.resize(m_kk);
m_s0.resize(m_kk);
m_cp0.resize(m_kk);
m_mu0.resize(m_kk);
m_work.resize(m_kk);
m_pe.resize(m_kk, 0.0);
vector_fp cov(m_kk, 0.0);
cov[0] = 1.0;
setCoverages(DATA_PTR(cov));
m_logsize.resize(m_kk);
for (int k = 0; k < m_kk; k++)
m_logsize[k] = log(size(k));
}
void SurfPhase::
setPotentialEnergy(int k, doublereal pe) {
m_pe[k] = pe;
_updateThermo(true);
}
void SurfPhase::
setSiteDensity(doublereal n0) {
doublereal x = n0;
setParameters(1, &x);
}
//void SurfPhase::
//setElectricPotential(doublereal V) {
// for (int k = 0; k < m_kk; k++) {
// m_pe[k] = charge(k)*Faraday*V;
// }
// _updateThermo(true);
//}
/**
* Set the coverage fractions to a specified
* state. This routine converts to concentrations
* in kmol/m2, using m_n0, the surface site density,
* and size(k), which is defined to be the number of
* surface sites occupied by the kth molecule.
* It then calls State::setConcentrations to set the
* internal concentration in the object.
*/
void SurfPhase::
setCoverages(const doublereal* theta) {
double sum = 0.0;
int k;
for (k = 0; k < m_kk; k++) sum += theta[k];
for (k = 0; k < m_kk; k++) {
m_work[k] = m_n0*theta[k]/(sum*size(k));
}
/*
* Call the State:: class function
* setConcentrations.
*/
setConcentrations(DATA_PTR(m_work));
}
void SurfPhase::
setCoveragesNoNorm(const doublereal* theta) {
for (int k = 0; k < m_kk; k++) {
m_work[k] = m_n0*theta[k]/(size(k));
}
/*
* Call the State:: class function
* setConcentrations.
*/
setConcentrations(DATA_PTR(m_work));
}
void SurfPhase::
getCoverages(doublereal* theta) const {
getConcentrations(theta);
for (int k = 0; k < m_kk; k++) {
theta[k] *= size(k)/m_n0;
}
}
void SurfPhase::
setCoveragesByName(std::string cov) {
int kk = nSpecies();
int k;
compositionMap cc;
for (k = 0; k < kk; k++) {
cc[speciesName(k)] = -1.0;
}
parseCompString(cov, cc);
doublereal c;
vector_fp cv(kk, 0.0);
for (k = 0; k < kk; k++) {
c = cc[speciesName(k)];
if (c > 0.0) cv[k] = c;
}
setCoverages(DATA_PTR(cv));
}
void SurfPhase::
_updateThermo(bool force) const {
doublereal tnow = temperature();
if (m_tlast != tnow || force) {
m_spthermo->update(tnow, DATA_PTR(m_cp0), DATA_PTR(m_h0),
DATA_PTR(m_s0));
m_tlast = tnow;
doublereal rt = GasConstant * tnow;
int k;
for (k = 0; k < m_kk; k++) {
m_h0[k] *= rt;
m_s0[k] *= GasConstant;
m_cp0[k] *= GasConstant;
m_mu0[k] = m_h0[k] - tnow*m_s0[k];
}
m_tlast = tnow;
}
}
void SurfPhase::
setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","Surface");
doublereal n = getFloat(eosdata, "site_density", "-");
if (n <= 0.0)
throw CanteraError("SurfPhase::setParametersFromXML",
"missing or negative site density");
m_n0 = n;
m_logn0 = log(m_n0);
}
void SurfPhase::setStateFromXML(const XML_Node& state) {
if (state.hasChild("temperature")) {
double t = getFloat(state, "temperature", "temperature");
setTemperature(t);
}
if (state.hasChild("coverages")) {
string comp = getString(state,"coverages");
setCoveragesByName(comp);
}
}
EdgePhase::EdgePhase(doublereal n0) : SurfPhase(n0) {
setNDim(1);
}
void EdgePhase::
setParametersFromXML(const XML_Node& eosdata) {
eosdata._require("model","Edge");
doublereal n = getFloat(eosdata, "site_density", "-");
if (n <= 0.0)
throw CanteraError("EdgePhase::setParametersFromXML",
"missing or negative site density");
m_n0 = n;
m_logn0 = log(m_n0);
}
}

View file

@ -0,0 +1,559 @@
/**
* @file SurfPhase.h
* Header for a simple thermoydnamics model of a surface phase derived from ThermoPhase,
* assuming an ideal solution model
* (see \ref thermoprops and class \link Cantera::SurfPhase SurfPhase\endlink).
*/
/* $Author$
* $Date$
* $Revision$
*
* Copyright 2002 California Institute of Technology
*
*/
#ifndef CT_SURFPHASE_H
#define CT_SURFPHASE_H
#include "mix_defs.h"
#include "ThermoPhase.h"
namespace Cantera {
//! A simple thermoydnamics model for a surface phase, assuming an ideal solution model.
/*!
* The surface consists of a grid of equivalent sites. Surface species may be defined to
* occupy one or more sites. The surface species are assumed to be
* independent, and thus the species form an ideal solution.
*
* The density of surface sites is given by the variable \f$ n_0 \f$, which has MKS units
* of kmol m-2.
*
*
* <b> Specification of Species Standard State Properties </b>
*
* It is assumed that the reference state thermodynamics may be
* obtained by a pointer to a populated species thermodynamic property
* manager class (see ThermoPhase::m_spthermo). How to relate pressure
* changes to the reference state thermodynamics is resolved at this level.
*
* Pressure is defined as an independent variable in this phase. However, it has
* no effect on any quantities, as the molar concentration is a constant.
*
* Therefore, The standard state internal energy for species <I>k</I> is
* equal to the enthalpy for species <I>k</I>.
*
* \f[
* u^o_k = h^o_k
* \f]
*
* Also, the standard state chemical potentials, entropy, and heat capacities
* are independent of pressure. The standard state gibbs free energy is obtained
* from the enthalpy and entropy functions.
*
* <b> Specification of Solution Thermodynamic Properties </b>
*
* The activity of species defined in the phase is given by
* \f[
* a_k = \theta_k
* \f]
*
* The chemical potential for species <I>k</I> is equal to
* \f[
* \mu_k(T,P) = \mu^o_k(T) + R T \log(\theta_k)
* \f]
*
* Pressure is defined as an independent variable in this phase. However, it has
* no effect on any quantities, as the molar concentration is a constant.
*
* The internal energy for species k is equal to the enthalpy for species <I>k</I>
* \f[
* u_k = h_k
* \f]
*
* The entropy for the phase is given by the following relation, which is
* independent of the pressure:
*
* \f[
* s_k(T,P) = s^o_k(T) - R \log(\theta_k)
* \f]
*
* <b> Application within %Kinetics Managers </b>
*
* The activity concentration,\f$ C^a_k \f$, used by the kinetics manager, is equal to
* the actual concentration, \f$ C^s_k \f$, and is given by the following
* expression.
* \f[
* C^a_k = C^s_k = \frac{\theta_k n_0}{s_k}
* \f]
*
* The standard concentration for species <I>k</I> is:
* \f[
* C^0_k = \frac{n_0}{s_k}
* \f]
*
* <b> Instantiation of the Class </b>
*
* The constructor for this phase is located in the default ThermoFactory
* for Cantera. A new SurfPhase may be created by the following code snippet:
*
* @code
* XML_Node *xc = get_XML_File("diamond.xml");
* XML_Node * const xs = xc->findNameID("phase", "diamond_100");
* ThermoPhase *diamond100TP_tp = newPhase(*xs);
* SurfPhase *diamond100TP = dynamic_cast <SurfPhase *>(diamond100TP_tp);
* @endcode
*
* or by the following constructor:
*
* @code
* XML_Node *xc = get_XML_File("diamond.xml");
* XML_Node * const xs = xc->findNameID("phase", "diamond_100");
* SurfPhase *diamond100TP = new SurfPhase(*xs);
* @endcode
*
* <b> XML Example </b>
*
* An example of an XML Element named phase setting up a SurfPhase object named diamond_100
* is given below.
*
* @verbatim
* <phase dim="2" id="diamond_100">
* <elementArray datasrc="elements.xml">H C</elementArray>
* <speciesArray datasrc="#species_data">c6HH c6H* c6*H c6** c6HM c6HM* c6*M c6B </speciesArray>
* <reactionArray datasrc="#reaction_data"/>
* <state>
* <temperature units="K">1200.0</temperature>
* <coverages>c6H*:0.1, c6HH:0.9</coverages>
* </state>
* <thermo model="Surface">
* <site_density units="mol/cm2">3e-09</site_density>
* </thermo>
* <kinetics model="Interface"/>
* <transport model="None"/>
* <phaseArray>
* gas_phase diamond_bulk
* </phaseArray>
* </phase>
*
* @endverbatim
*
* The model attribute, "Surface", on the thermo element identifies the phase as being
* a SurfPhase object.
*
* @ingroup thermoprops
*/
class SurfPhase : public ThermoPhase {
public:
//! Constructor.
/*!
* @param n0 Site Density of the Surface Phase
* Units: kmol m-2.
*/
SurfPhase(doublereal n0 = 0.0);
//! Constructor.
/*!
* @param xmlphase XML node pointing to a SurfPhase description
*/
SurfPhase(XML_Node& xmlphase);
//! Destructor.
virtual ~SurfPhase();
//----- reimplimented methods of class ThermoPhase ------
//! Equation of state type flag.
/*!
* Redefine this to return cSurf, listed in mix_defs.h.
*/
virtual int eosType() const { return cSurf; }
//! Return the Molar Enthalpy. Units: J/kmol.
/*!
* For an ideal solution,
* \f[
* \hat h(T,P) = \sum_k X_k \hat h^0_k(T),
* \f]
* and is a function only of temperature.
* The standard-state pure-species Enthalpies
* \f$ \hat h^0_k(T) \f$ are computed by the species thermodynamic
* property manager.
*
* \see SpeciesThermo
*/
virtual doublereal enthalpy_mole() const;
//! Return the Molar Internal Energy. Units: J/kmol
/**
* For a surface phase, the pressure is not a relevant
* thermodynamic variable, and so the Enthalpy is equal to the
* Internal Energy.
*/
virtual doublereal intEnergy_mole() const;
//! Get the array of chemical potentials at unit activity for the
//! standard state species at the current <I>T</I> and <I>P</I> of the solution.
/*!
* These are the standard state chemical potentials \f$ \mu^0_k(T,P)
* \f$. The values are evaluated at the current
* temperature and pressure of the solution
*
* @param mu0 Output vector of chemical potentials.
* Length: m_kk.
*/
virtual void getStandardChemPotentials(doublereal* mu0) const;
//! Get the species chemical potentials. Units: J/kmol.
/*!
* This function returns a vector of chemical potentials of the
* species in solution at the current temperature, pressure
* and mole fraction of the solution.
*
* @param mu Output vector of species chemical
* potentials. Length: m_kk. Units: J/kmol
*/
virtual void getChemPotentials(doublereal* mu) const;
//! Return a vector of activity concentrations for each species
/*!
* For this phase the activity concentrations,\f$ C^a_k \f$, are defined to be
* equal to the actual concentrations, \f$ C^s_k \f$.
* Activity concentrations are
*
* \f[
* C^a_k = C^s_k = \frac{\theta_k n_0}{s_k}
* \f]
*
* where \f$ \theta_k \f$ is the surface site fraction for species k,
* \f$ n_0 \f$ is the surface site density for the phase, and
* \f$ s_k \f$ is the surface size of species k.
*
* \f$ C^a_k\f$ that are defined such that \f$ a_k = C^a_k /
* C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration
* defined below and \f$ a_k \f$ are activities used in
* the thermodynamic functions. These activity concentrations are used
* by kinetics manager classes to compute the forward and
* reverse rates of elementary reactions. Note that they may
* or may not have units of concentration --- they might be
* partial pressures, mole fractions, or surface coverages,
*
* @param c vector of activity concentration (kmol m-2).
*/
virtual void getActivityConcentrations(doublereal* c) const;
//! Return the standard concentration for the kth species
/*!
* The standard concentration \f$ C^0_k \f$ used to normalize
* the activity (i.e., generalized) concentration.
* For this phase, the standard concentration is species-
* specific
*
* \f[
* C^0_k = \frac{n_0}{s_k}
* \f]
*
* This definition implies that the activity is equal to \f$ \theta_k \f$.
*
* @param k Optional parameter indicating the species. The default
* is to assume this refers to species 0.
* @return
* Returns the standard Concentration in units of m3 kmol-1.
*/
virtual doublereal standardConcentration(int k = 0) const;
//! Return the log of the standard concentration for the kth species
/*!
* @param k species index (default 0)
*/
virtual doublereal logStandardConc(int k=0) const;
//! Set the equation of state parameters from the argument list
/*!
* @internal
* Set equation of state parameters.
*
* @param n number of parameters. Must be one
* @param c array of \a n coefficients
* c[0] = The site density (kmol m-2)
*/
virtual void setParameters(int n, doublereal* c);
//! Set the Equation-of-State parameters by reading an XML Node Input
/*!
*
* The Equation-of-State data consists of one item, the site density.
*
* @param thermoData Reference to an XML_Node named thermo
* containing the equation-of-state data. The
* XML_Node is within the phase XML_Node describing
* the %SurfPhase object.
*
* An example of the contents of the thermoData XML_Node is provided
* below. The units attribute is used to supply the units of the
* site density in any convenient form. Internally it is changed
* into MKS form.
*
* @verbatim
* <thermo model="Surface">
* <site_density units="mol/cm2"> 3e-09 </site_density>
* </thermo>
* @endverbatim
*/
virtual void setParametersFromXML(const XML_Node& thermoData);
//! Initialize the SurfPhase object after all species have been set up
/*!
* @internal Initialize.
*
* This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called from ThermoPhase::initThermoXML(),
* which is called from importPhase(),
* just prior to returning from function importPhase().
*
* @see importCTML.cpp
*/
virtual void initThermo();
//! Set the initial state of the Surface Phase from an XML_Node
/*!
* State variables that can be set by this routine are
* the temperature and the surface site coverages.
*
* @param state XML_Node containing the state information
*
* An example of the XML code block is given below.
*
* @verbatim
* <state>
* <temperature units="K">1200.0</temperature>
* <coverages>c6H*:0.1, c6HH:0.9</coverages>
* </state>
* @endverbatim
*/
virtual void setStateFromXML(const XML_Node& state);
//! Returns the site density
/*!
* Site density kmol m-2
*/
doublereal siteDensity(){ return m_n0; }
//! Sets the potential energy of species k.
/*!
*
* @param k Species index
* @param pe Value of the potential energy (J kmol-1)
*/
void setPotentialEnergy(int k, doublereal pe);
//! Return the potential energy of species k.
/*!
* Returns the potential energy of species, k,
* J kmol-1
*
* @param k Species index
*/
doublereal potentialEnergy(int k) {return m_pe[k];}
//! Set the site density of the surface phase (kmol m-2)
/*!
* @param n0 Site density of the surface phase (kmol m-2)
*/
void setSiteDensity(doublereal n0);
//! Get the nondimensional Enthalpy functions for the species standard states
//! at their standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param hrt Output vector of nondimensional standard state enthalpies.
* Length: m_kk.
*/
void getEnthalpy_RT(doublereal* hrt) const;
//! Get the array of nondimensional Entropy functions for the
//! species standard states at the current <I>T</I> and <I>P</I> of the solution.
/*!
* @param sr Output vector of nondimensional standard state entropies.
* Length: m_kk.
*/
void getEntropy_R(doublereal* sr) const;
//! Return the thermodynamic pressure (Pa).
/*!
* This method must be overloaded in derived classes. Since the
* mass density, temperature, and mass fractions are stored,
* this method should use these values to implement the
* mechanical equation of state \f$ P(T, \rho, Y_1, \dots,
* Y_K) \f$.
*/
virtual doublereal pressure() const {
return m_press;
}
//! Set the internally storred pressure (Pa) at constant
//! temperature and composition
/*!
* This method must be reimplemented in derived classes, where it
* may involve the solution of a nonlinear equation. Within %Cantera,
* the independent variable is the density. Therefore, this function
* solves for the density that will yield the desired input pressure.
* The temperature and composition iare held constant during this process.
*
* This base class function will print an error, if not overwritten.
*
* @param p input Pressure (Pa)
*/
virtual void setPressure(doublereal p) {
m_press = p;
}
//------- new methods defined in this class ----------
//! Set the surface site fractions to a specified state.
/*!
* This routine converts to concentrations
* in kmol/m2, using m_n0, the surface site density,
* and size(k), which is defined to be the number of
* surface sites occupied by the kth molecule.
* It then calls State::setConcentrations to set the
* internal concentration in the object.
*
* @param theta This is the surface site fraction
* for the kth species in the surface phase.
* This is a dimensionless quantity.
*
* This routine normalizes the theta's to 1, before application
*/
void setCoverages(const doublereal* theta);
//! Set the surface site fractions to a specified state.
/*!
* This routine converts to concentrations
* in kmol/m2, using m_n0, the surface site density,
* and size(k), which is defined to be the number of
* surface sites occupied by the kth molecule.
* It then calls State::setConcentrations to set the
* internal concentration in the object.
*
* @param theta This is the surface site fraction
* for the kth species in the surface phase.
* This is a dimensionless quantity.
*/
void setCoveragesNoNorm(const doublereal* theta);
//! Set the coverages from a string of colon-separated name:value pairs.
/*!
* @param cov String containing colon-separated name:value pairs
*/
void setCoveragesByName(std::string cov);
//! Return a vector of surface coverages
/*!
* Get the coverages.
*
* @param theta Array theta must be at least as long as
* the number of species.
*/
void getCoverages(doublereal* theta) const;
protected:
//! Surface site density (kmol m-2)
doublereal m_n0;
//! log of the surface site density
doublereal m_logn0;
//! Minimum temperature for valid species standard state thermo props
/*!
* This is the minimum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmin;
//! Maximum temperature for valid species standard state thermo props
/*!
* This is the maximum temperature at which all species have valid standard
* state thermo props defined.
*/
doublereal m_tmax;
//! Current value of the pressure (Pa)
doublereal m_press;
//! Current value of the temperature (Kelvin)
mutable doublereal m_tlast;
//! Temporary storage for the reference state enthalpies
mutable array_fp m_h0;
//! Temporary storage for the reference state entropies
mutable array_fp m_s0;
//! Temporary storage for the reference state heat capacities
mutable array_fp m_cp0;
//! Temporary storage for the reference state gibbs energies
mutable array_fp m_mu0;
//! Temporary work array
mutable array_fp m_work;
//! Potential energy of each species in the surface phase
/*!
* @todo Fix potential energy
* Note, the potential energy terms seem to be orphaned at the moment.
* They are not connected to the Gibbs free energy calculation in
* this object
*
* @deprecated
*/
mutable array_fp m_pe;
//! vector storring the log of the size of each species.
/*!
* The size of each species is defined as the number of surface
* sites each species occupies.
*/
mutable array_fp m_logsize;
private:
//! Update the species reference state thermodynamic functions
/*!
* The polynomials for the standard state functions are only
* reevalulated if the temperature has changed.
*
* @param force Boolean, which if true, forces a reevalulation
* of the thermo polynomials.
* default = false.
*/
void _updateThermo(bool force=false) const;
};
}
#endif

View file

@ -0,0 +1,578 @@
/**
* @file ThermoFactory.cpp
* Definitions for the factory class that can create known %ThermoPhase objects
* (see \ref thermoprops and class \link Cantera::ThermoFactory ThermoFactory\endlink).
*
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "ThermoFactory.h"
#include "speciesThermoTypes.h"
#include "SpeciesThermoFactory.h"
#include "IdealGasPhase.h"
#ifdef WITH_PURE_FLUIDS
#include "PureFluidPhase.h"
#endif
#include "ConstDensityThermo.h"
#include "SurfPhase.h"
#include "EdgePhase.h"
#ifdef WITH_METAL
#include "MetalPhase.h"
#endif
#undef USE_SSTP
#ifdef WITH_STOICH_SUBSTANCE
#ifdef USE_SSTP
#include "StoichSubstanceSSTP.h"
#else
#include "StoichSubstance.h"
#endif
#endif
//#include "importCTML.h"
#ifdef WITH_LATTICE_SOLID
#include "LatticeSolidPhase.h"
#include "LatticePhase.h"
#endif
using namespace std;
namespace Cantera {
ThermoFactory* ThermoFactory::s_factory = 0;
static int ntypes = 9;
static string _types[] = {"IdealGas", "Incompressible",
"Surface", "Edge", "Metal", "StoichSubstance",
"PureFluid", "LatticeSolid", "Lattice"};
static int _itypes[] = {cIdealGas, cIncompressible,
cSurf, cEdge, cMetal, cStoichSubstance,
cPureFluid, cLatticeSolid, cLattice};
/*
* This method returns a new instance of a subclass of ThermoPhase
*/
ThermoPhase* ThermoFactory::newThermoPhase(std::string model) {
int ieos=-1;
for (int n = 0; n < ntypes; n++) {
if (model == _types[n]) ieos = _itypes[n];
}
ThermoPhase* th=0;
// map<string, double> d;
switch (ieos) {
case cIdealGas:
th = new IdealGasPhase;
break;
case cIncompressible:
th = new ConstDensityThermo;
break;
case cSurf:
th = new SurfPhase;
break;
case cEdge:
th = new EdgePhase;
break;
#ifdef WITH_METAL
case cMetal:
th = new MetalPhase;
break;
#endif
#ifdef WITH_STOICH_SUBSTANCE
case cStoichSubstance:
#ifdef USE_SSTP
th = new StoichSubstanceSSTP;
#else
th = new StoichSubstance;
#endif
break;
#endif
#ifdef WITH_LATTICE_SOLID
case cLatticeSolid:
th = new LatticeSolidPhase;
break;
case cLattice:
th = new LatticePhase;
break;
#endif
#ifdef WITH_PURE_FLUIDS
case cPureFluid:
th = new PureFluidPhase;
break;
#endif
default:
throw UnknownThermoPhaseModel("ThermoFactory::newThermoPhase",
model);
}
return th;
}
/*
* Create a new ThermoPhase object and initializes it according to
* the XML tree database. This routine first looks up the
* identity of the model for the solution thermodynamics in the
* model attribute of the thermo child of the xml phase
* node. Then, it does a string lookup on the model to figure out
* what ThermoPhase derived class is assigned. It creates a new
* instance of that class, and then calls importPhase() to
* populate that class with the correct parameters from the XML
* tree.
*/
ThermoPhase* newPhase(XML_Node& xmlphase) {
const XML_Node& th = xmlphase.child("thermo");
string model = th["model"];
ThermoPhase* t = newThermoPhase(model);
importPhase(xmlphase, t);
return t;
}
ThermoPhase* newPhase(std::string infile, std::string id) {
XML_Node* root = get_XML_File(infile);
if (id == "-") id = "";
XML_Node* x = get_XML_Node(string("#")+id, root);
if (x)
return newPhase(*x);
else
return 0;
}
/*
* Import a phase specification.
* 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, and finally call initThermoXML(phase, id)
* a member function of the ThermoPhase object to "finish"
* the description.
*
*
* @param phase 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 th Pointer to the ThermoPhase object which will
* handle the thermodynamics for this phase.
* We initialize part of the Thermophase object
* here, especially for those objects which are
* part of the Cantera Kernel.
*/
bool importPhase(XML_Node& phase, ThermoPhase* th,
SpeciesThermoFactory* spfactory) {
// Check the the supplied XML node in fact represents a
// phase.
if (phase.name() != "phase")
throw CanteraError("importPhase",
"Current const XML_Node is not a phase element.");
// if no species thermo factory was supplied,
// use the default one.
if (!spfactory)
spfactory = SpeciesThermoFactory::factory();
// set the id attribute of the phase to the 'id' attribute
// in the XML tree.
th->setID(phase.id());
th->setName(phase.id());
// Number of spatial dimensions. Defaults to 3 (bulk phase)
if (phase.hasAttrib("dim")) {
int idim = intValue(phase["dim"]);
if (idim < 1 || idim > 3)
throw CanteraError("importPhase",
"unphysical number of dimensions: "+phase["dim"]);
th->setNDim(idim);
}
else
th->setNDim(3); // default
// Set equation of state parameters. The parameters are
// specific to each subclass of ThermoPhase, so this is done
// by method setParametersFromXML in each subclass.
if (phase.hasChild("thermo")) {
const XML_Node& eos = phase.child("thermo");
th->setParametersFromXML(eos);
}
/***************************************************************
* Add the elements.
***************************************************************/
th->addElementsFromXML(phase);
/***************************************************************
* Add the species.
*
* Species definitions may be imported from multiple
* sources. For each one, a speciesArray element must be
* present.
***************************************************************/
XML_Node* db = 0;
vector<XML_Node*> sparrays;
phase.getChildren("speciesArray", sparrays);
int jsp, nspa = static_cast<int>(sparrays.size());
vector<XML_Node*> dbases;
vector_int sprule(nspa,0);
// loop over the speciesArray elements
for (jsp = 0; jsp < nspa; jsp++) {
const XML_Node& species = *sparrays[jsp];
// If the speciesArray element has a child element
// <skip element="undeclared">
// then set sprule[jsp] to 1, so
// that any species with an undeclared element will be
// quietly skipped when importing species.
if (species.hasChild("skip")) {
const XML_Node& sk = species.child("skip");
string eskip = sk["element"];
if (eskip == "undeclared") {
sprule[jsp] = 1;
}
string dskip = sk["species"];
if (dskip == "duplicate") {
sprule[jsp] += 10;
}
}
string fname, idstr;
// get a pointer to the node containing the species
// definitions for the species declared in this
// speciesArray element. This may be in the local file
// containing the phase element, or may be in another
// file.
db = get_XML_Node(species["datasrc"], &phase.root());
// add this node to the list of species database nodes.
dbases.push_back(db);
}
// if the phase has a species thermo manager already installed,
// delete it since we are adding new species.
delete &th->speciesThermo();
// create a new species thermo manager. Function
// 'newSpeciesThermoMgr' looks at the species in the database
// to see what thermodynamic property parameterizations are
// used, and selects a class that can handle the
// parameterizations found.
SpeciesThermo* spth = newSpeciesThermoMgr(dbases);
// install it in the phase object
th->setSpeciesThermo(spth);
SpeciesThermo& spthermo = th->speciesThermo();
// used to check that each species is declared only once
map<string,bool> declared;
int i, k = 0;
// loop over the species arrays
for (jsp = 0; jsp < nspa; jsp++) {
const XML_Node& species = *sparrays[jsp];
db = dbases[jsp];
// Get the array of species name strings.
vector<string> spnames;
getStringArray(species, spnames);
int nsp = static_cast<int>(spnames.size());
// if 'all' is specified, then add all species
// defined in this database to the phase
if (nsp == 1 && spnames[0] == "all") {
vector<XML_Node*> allsp;
db->getChildren("species",allsp);
nsp = static_cast<int>(allsp.size());
spnames.resize(nsp);
for (int nn = 0; nn < nsp; nn++) {
spnames[nn] = (*allsp[nn])["name"];
}
}
else if (nsp == 1 && spnames[0] == "unique") {
vector<XML_Node*> uniquesp;
db->getChildren("species",uniquesp);
nsp = static_cast<int>(uniquesp.size());
spnames.clear();
spnames.resize(nsp);
string spnm;
for (int nn = 0; nn < nsp; nn++) {
spnm = (*uniquesp[nn])["name"];
if (!declared[spnm]) spnames[nn] = spnm;
}
}
string name;
bool skip;
for (i = 0; i < nsp; i++) {
name = spnames[i];
skip = false;
if (name == "") skip = true;
// Check that every species is only declared once
if (declared[name]) {
if (sprule[jsp] >= 10)
skip = true;
else
throw CanteraError("importPhase",
"duplicate species: "+name);
}
if (!skip) {
declared[name] = true;
// Find the species in the database by name.
XML_Node* s = db->findByAttr("name",spnames[i]);
if (s) {
if (installSpecies(k, *s, *th, spthermo, sprule[jsp],
spfactory))
++k;
}
else {
throw CanteraError("importPhase","no data for species "
+name);
}
}
}
}
// done adding species.
th->freezeSpecies();
th->saveSpeciesData(db);
// Perform any required subclass-specific initialization.
string id = "";
th->initThermoXML(phase, id);
return true;
}
// void setEOSParameters(const XML_Node& xmlphase, ThermoPhase* th) {
// // if no thermo model is specified for the phase, simply
// // return
// if (!phase.hasChild("thermo")) return;
// const XML_Node& eos = phase.child("thermo");
// // set the parameters for the particular equation of state type,
// // and
// if (eos["model"] == "Incompressible") {
// if (th->eosType() == cIncompressible) {
// doublereal rho = getFloat(eos, "density", "-");
// th->setParameters(1, &rho);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "StoichSubstance") {
// if (th->eosType() == cStoichSubstance) {
// doublereal rho = getFloat(eos, "density", "-");
// th->setDensity(rho);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "Surface") {
// if (th->eosType() == cSurf) {
// doublereal n = getFloat(eos, "site_density", "-");
// if (n <= 0.0)
// throw CanteraError("importCTML",
// "missing or negative site density");
// th->setParameters(1, &n);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "Edge") {
// if (th->eosType() == cEdge) {
// doublereal n = getFloat(eos, "site_density", "-");
// if (n <= 0.0)
// throw CanteraError("importCTML",
// "missing or negative site density");
// th->setParameters(1, &n);
// }
// else {
// eoserror = true;
// }
// }
// #ifdef INCL_PURE_FLUIDS
// else if (eos["model"] == "PureFluid") {
// if (th->eosType() == cPureFluid) {
// subflag = atoi(eos["fluid_type"].c_str());
// if (subflag < 0)
// throw CanteraError("importCTML",
// "missing fluid type flag");
// }
// else {
// eoserror = true;
// }
// }
// #endif
// if (eoserror) {
// string msg = "Wrong equation of state type for phase "+phase["id"]+"\n";
// msg += eos["model"]+" is not consistent with eos type "+int2str(th->eosType());
// throw CanteraError("importCTML",msg);
// }
/*
* Install a species into a ThermoPhase object, which defines
* the phase thermodynamics and speciation.
*
* This routine first gathers the information from the Species XML
* tree and calls addUniqueSpecies() to add it to the
* ThermoPhase object, p.
* This information consists of:
* ecomp[] = element composition of species.
* chgr = electric charge of species
* name = string name of species
* sz = size of the species
* (option double used a lot in thermo)
*
* Then, the routine processes the "thermo" XML element and
* calls underlying utility routines to read the XML elements
* containing the thermodynamic information for the reference
* state of the species. Failures or lack of information trigger
* an "UnknownSpeciesThermoModel" exception being thrown.
*/
bool installSpecies(int k, const XML_Node& s, thermo_t& p,
SpeciesThermo& spthermo, int rule,
SpeciesThermoFactory* factory) {
// get the composition of the species
const XML_Node& a = s.child("atomArray");
map<string,string> comp;
getMap(a, comp);
// check that all elements in the species
// exist in 'p'. If rule != 0, quietly skip
// this species if some elements are undeclared;
// otherwise, throw an exception
map<string,string>::const_iterator _b = comp.begin();
for (; _b != comp.end(); ++_b) {
if (p.elementIndex(_b->first) < 0) {
if (rule == 0) {
throw CanteraError("installSpecies",
"Species " + s["name"] +
" contains undeclared element " + _b->first);
}
else
return false;
}
}
// construct a vector of atom numbers for each
// element in phase p. Elements not declared in the
// species (i.e., not in map comp) will have zero
// entries in the vector.
int m, nel = p.nElements();
vector_fp ecomp(nel, 0.0);
for (m = 0; m < nel; m++) {
ecomp[m] = atoi(comp[p.elementName(m)].c_str());
}
// get the species charge, if any. Note that the charge need
// not be explicitly specified if special element 'E'
// (electron) is one of the elements.
doublereal chrg = 0.0;
if (s.hasChild("charge")) chrg = getFloat(s, "charge");
// get the species size, if any. (This is used by surface
// phases to represent how many sites a species occupies.)
doublereal sz = 1.0;
if (s.hasChild("size")) sz = getFloat(s, "size");
// add the species to phase p.
p.addUniqueSpecies(s["name"], &ecomp[0], chrg, sz);
// install the thermo parameterization for this species into
// the species thermo manager for phase p.
factory->installThermoForSpecies(k, s, spthermo);
return true;
}
/*
* Search an XML tree for species data.
*
* This utility routine will search the XML tree for the species
* named by the string, kname. It will return the XML_Node
* pointer.
* Failures of any kind return the null pointer.
*/
const XML_Node *speciesXML_Node(std::string kname,
const XML_Node *phaseSpeciesData) {
/*
* First look at the species database.
* -> Look for the subelement "stoichIsMods"
* in each of the species SS databases.
*/
if (!phaseSpeciesData) return ((const XML_Node *) 0);
string jname;
vector<XML_Node*> xspecies;
phaseSpeciesData->getChildren("species", xspecies);
int jj = xspecies.size();
for (int j = 0; j < jj; j++) {
const XML_Node& sp = *xspecies[j];
jname = sp["name"];
if (jname == kname) {
return &sp;
}
}
return ((const XML_Node *) 0);
}
}

View file

@ -0,0 +1,229 @@
/**
* @file ThermoFactory.h
* Headers for the factory class that can create known %ThermoPhase objects
* (see \ref thermoprops and class \link Cantera::ThermoFactory ThermoFactory\endlink).
*
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef THERMO_FACTORY_H
#define THERMO_FACTORY_H
#include "ThermoPhase.h"
#include "xml.h"
#include "SpeciesThermoFactory.h"
namespace Cantera {
/*!
* @addtogroup thermoprops
*
* Standard %ThermoPhase objects may be instantiated by calling
* the main %Cantera factory class for %ThermoPhase objects; This class is called ThermoFactory.
*/
//@{
//! Specific error to be thrown if the type of Thermo mananger is unrecognized.
/*!
* This particular error class may be caught, if the application may have other
* models that the main Cantera appliation doesn't know about.
*/
class UnknownThermoPhaseModel : public CanteraError {
public:
//! Constructor
/*!
* @param proc Function name where the error occurred.
* @param thermoModel Sting name of ThermoPhase which didn't match
*/
UnknownThermoPhaseModel(std::string proc, std::string thermoModel) :
CanteraError(proc, "Specified ThermoPhase model "
+ thermoModel +
" does not match any known type.") {}
//! destructor
virtual ~UnknownThermoPhaseModel() {}
};
//! Factory class for thermodynamic property managers.
/*!
* This class keeps a list of the known ThermoPhase classes, and is used
* to create new instances of these classes.
*/
class ThermoFactory {
public:
//! Static function that creates a static instance of the factor.
static ThermoFactory* factory() {
if (!s_factory) s_factory = new ThermoFactory;
return s_factory;
}
//! delete the static instance of this factory
static void deleteFactory() {
if (s_factory) {
delete s_factory;
s_factory = 0;
}
}
//! Destructor doesn't do anything.
/*!
* We do not delete statically
* created single instance of this class here, because it would
* create an infinite loop if destructor is called for that
* single instance.
*/
virtual ~ThermoFactory() { }
//! Create a new thermodynamic property manager.
/*!
* @param model String to look up the model against
*
* @return
* Returns a pointer to a new ThermoPhase instance matching the
* model string. Returns NULL if something went wrong.
* Throws an exception UnknownThermoPhaseModel if the string
* wasn't matched.
*/
virtual ThermoPhase* newThermoPhase(std::string model);
private:
//! static member of a single instance
static ThermoFactory* s_factory;
//! Private constructor prevents usage
ThermoFactory(){}
};
//! Create a new thermo manager instance.
/*!
* @param model String to look up the model against
* @param f ThermoFactor instance to use in matching the string
*
* @return
* Returns a pointer to a new ThermoPhase instance matching the
* model string. Returns NULL if something went wrong.
* Throws an exception UnknownThermoPhaseModel if the string
* wasn't matched.
*/
inline ThermoPhase* newThermoPhase(std::string model,
ThermoFactory* f=0) {
if (f == 0) {
f = ThermoFactory::factory();
}
return f->newThermoPhase(model);
}
/*!
* This routine first looks up the
* identity of the model for the solution thermodynamics in the
* model attribute of the thermo child of the xml phase
* node. Then, it does a string lookup using Cantera's internal ThermoPhase Factory routines
* on the model to figure out
* what ThermoPhase derived class should be assigned. It creates a new
* instance of that class, and then calls importPhase() to
* populate that class with the correct parameters from the XML
* tree.
*
* @param phase XML_Node reference pointing to the phase XML element.
*
* @return
* Returns a pointer to the completed and initialized ThermoPhase object.
*
* @ingroup inputfiles
*/
ThermoPhase* newPhase(XML_Node& phase);
ThermoPhase* newPhase(std::string infile, std::string id);
//! Import a phase information into an empty thermophase object
/*!
* Here we read an XML description of the thermodynamic information
* for a phase. At the end of this routine, the phase should
* be ready to be used within applications. This routine contains
* some key routines that are used as pass back routines so that
* the phase (and the contents of the XML file) may contain
* variable paramerizations for the specification of the
* species standard states, the equation of state, and the
* specification of other nonidealities. Below, a description
* is presented of the main algorithm for bringing up a %ThermoPhase
* object, with care to present points where customizations
* occur.
*
* Before invoking this routine, either the ThermoPhase Factory routines
* are called or direct constructor routines are called that
* instantiate an inherited ThermoPhase object. This object is input
* to this routine, and therefore contains inherited routines that
* drive the custimation of the initialization process.
*
* At the start of the routine, we import descriptions of the elements
* that make up the species in a phase.
*
* We call setParametersFromXML(eos) to read parameters about
* the thermo phase before the species are read in.
*
* We call addElementsFromXML() to add elements into the
* description of the phase.
*
* We create a new species thermo manager. Function
* 'newSpeciesThermoMgr' looks at the species in the database
* to see what thermodynamic property parameterizations are
* used, and selects a class that can handle the
* parameterizations found.
*
* We import information about the species, including their
* reference state thermodynamic polynomials. We then freeze
* the state of the species in the element.
*
* Finally, we call initThermoXML(),
* a member function of the ThermoPhase object, to "finish"
* the description. Now that the species are known,
* additional information may be read in about the thermodynamics
* of the phase, (e.g., virial coefficients, which are
* binary or ternary interaction parameters between species).
*
* @param phase 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 th Pointer to the ThermoPhase object which will
* handle the thermodynamics for this phase.
* We initialize part of the Thermophase object
* here, especially for those objects which are
* part of the Cantera Kernel.
*
* @param spfactory species Thermo factory pointer, if
* available. If not available, one will be
* created.
*
* @ingroup thermoprops
*/
bool importPhase(XML_Node& phase, ThermoPhase* th,
SpeciesThermoFactory* spfactory = 0);
bool installSpecies(int k, const XML_Node& s, thermo_t& p,
SpeciesThermo& spthermo, int rule,
SpeciesThermoFactory* factory = 0);
const XML_Node *speciesXML_Node(std::string kname,
const XML_Node *phaseSpeciesData);
//@}
}
#endif

View file

@ -0,0 +1,464 @@
/**
* @file ThermoPhase.cpp
* Definition file for class ThermoPhase, the base class for phases with
* thermodynamic properties
* (see class \link Cantera::ThermoPhase ThermoPhase\endlink).
*/
/*
* $Author$
* $Date$
* $Revision$
*
* Copyright 2002 California Institute of Technology
*
*/
// turn off warnings under Windows
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ThermoPhase.h"
using namespace std;
namespace Cantera {
/**
* Copy Constructor for the ThermoPhase object.
*
* Currently, this is implemented, but not tested. If called it will
* throw an exception until fully tested.
*/
ThermoPhase::ThermoPhase(const ThermoPhase &right) :
Phase(),
m_spthermo(0),
m_speciesData(0),
m_index(-1),
m_phi(0.0),
m_hasElementPotentials(false)
{
/*
* Call the assignment operator
*/
*this = operator=(right);
}
/*
* operator=()
*
* Note this stuff will not work until the underlying phase
* has a working assignment operator
*/
ThermoPhase& ThermoPhase::
operator=(const ThermoPhase &right) {
/*
* Check for self assignment.
*/
if (this == &right) return *this;
(void)Phase::operator=(right);
/*
* Pointer to the species thermodynamic property manager
* We own this, so we need to do a deep copy
*/
if (m_spthermo) {
delete m_spthermo;
}
//m_spthermo = (right.m_spthermo)->duplMyselfAsSpeciesThermo();
throw CanteraError("ThermoPhase assignment", "not implemented");
/// Pointer to the XML tree containing the species
/// data for this phase. This is used to access data needed to
/// construct the transport manager and other properties
/// later in the initialization process.
m_speciesData = right.m_speciesData;
m_index = right.m_index;
m_phi = right.m_phi;
m_lambdaRRT = right.m_lambdaRRT;
m_hasElementPotentials = right.m_hasElementPotentials;
return *this;
}
/*
* Duplication routine for objects which inherit from
* ThermoPhase.
*
* This virtual routine can be used to duplicate thermophase objects
* inherited from ThermoPhase even if the application only has
* a pointer to ThermoPhase to work with.
*
* Currently, this is not fully implemented. If called, an
* exception will be called by the ThermoPhase copy constructor.
*/
ThermoPhase *ThermoPhase::duplMyselfAsThermoPhase() {
ThermoPhase* tp = new ThermoPhase(*this);
return tp;
}
int ThermoPhase::activityConvention() const {
return cAC_CONVENTION_MOLAR;
}
void ThermoPhase::getActivities(doublereal* a) const {
getActivityConcentrations(a);
int nsp = nSpecies();
int k;
for (k = 0; k < nsp; k++) a[k] /= standardConcentration(k);
}
void ThermoPhase::setState_TPX(doublereal t, doublereal p,
const doublereal* x) {
setMoleFractions(x); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TPX(doublereal t, doublereal p,
compositionMap& x) {
setMoleFractionsByName(x); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TPX(doublereal t, doublereal p,
const std::string& x) {
compositionMap xx;
int kk = nSpecies();
for (int k = 0; k < kk; k++) xx[speciesName(k)] = -1.0;
try {
parseCompString(x, xx);
}
catch (CanteraError) {
throw CanteraError("setState_TPX",
"Unknown species in composition map: "+ x);
}
setMoleFractionsByName(xx); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TPY(doublereal t, doublereal p,
const doublereal* y) {
setMassFractions(y); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TPY(doublereal t, doublereal p,
compositionMap& y) {
setMassFractionsByName(y); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TPY(doublereal t, doublereal p,
const std::string& y) {
compositionMap yy;
int kk = nSpecies();
for (int k = 0; k < kk; k++) yy[speciesName(k)] = -1.0;
try {
parseCompString(y, yy);
}
catch (CanteraError) {
throw CanteraError("setState_TPY",
"Unknown species in composition map: "+ y);
}
setMassFractionsByName(yy); setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_TP(doublereal t, doublereal p) {
setTemperature(t); setPressure(p);
}
void ThermoPhase::setState_PX(doublereal p, doublereal* x) {
setMoleFractions(x); setPressure(p);
}
void ThermoPhase::setState_PY(doublereal p, doublereal* y) {
setMassFractions(y); setPressure(p);
}
void ThermoPhase::setState_HP(doublereal h, doublereal p,
doublereal tol) {
doublereal dt;
setPressure(p);
// Newton iteration
for (int n = 0; n < 500; n++) {
double h0 = enthalpy_mass();
dt = (h - h0)/cp_mass();
// limit step size to 100 K
if (dt > 100.0) dt = 100.0;
else if (dt < -100.0) dt = -100.0;
setState_TP(temperature() + dt, p);
if (fabs(dt) < tol) {
return;
}
}
throw CanteraError("setState_HP","No convergence. dt = " + fp2str(dt));
}
void ThermoPhase::setState_UV(doublereal u, doublereal v,
doublereal tol) {
doublereal dt;
setDensity(1.0/v);
for (int n = 0; n < 500; n++) {
dt = (u - intEnergy_mass())/cv_mass();
if (dt > 100.0) dt = 100.0;
else if (dt < -100.0) dt = -100.0;
if (fabs(dt) < tol) {
setTemperature(temperature() + dt);
return;
}
setTemperature(temperature() + 0.5*dt);
}
throw CanteraError("setState_UV",
"no convergence. dt = " + fp2str(dt)+"\n"
+"tol = "+fp2str(tol)+"\n"
+"u = "+fp2str(u)+" v = "+fp2str(v)+"\n");
}
void ThermoPhase::setState_SP(doublereal s, doublereal p,
doublereal tol) {
doublereal dt;
setPressure(p);
for (int n = 0; n < 500; n++) {
dt = (s - entropy_mass())*temperature()/cp_mass();
if (dt > 100.0) dt = 100.0;
else if (dt < -100.0) dt = -100.0;
if (fabs(dt) < tol) {
setState_TP(temperature() + dt, p);
return;
}
setState_TP(temperature() + 0.5*dt, p);
}
throw CanteraError("setState_SP","no convergence. dt = " + fp2str(dt));
}
void ThermoPhase::setState_SV(doublereal s, doublereal v,
doublereal tol) {
doublereal dt;
setDensity(1.0/v);
for (int n = 0; n < 500; n++) {
dt = (s - entropy_mass())*temperature()/cv_mass();
if (dt > 100.0) dt = 100.0;
else if (dt < -100.0) dt = -100.0;
if (fabs(dt) < tol) {
setTemperature(temperature() + dt);
return;
}
setTemperature(temperature() + 0.5*dt);
}
throw CanteraError("setState_SV","no convergence. dt = " + fp2str(dt));
}
doublereal ThermoPhase::err(std::string msg) const {
throw CanteraError("ThermoPhase","Base class method "
+msg+" called. Equation of state type: "+int2str(eosType()));
return 0;
}
/*
* 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.
*
* On return uA contains the powers of the units (MKS assumed)
* of the standard concentrations and generalized concentrations
* for the kth species.
*
* The base %ThermoPhase class assigns thedefault quantities
* of (kmol/m3).
* Inherited classes are responsible for overriding the default
* values if necessary.
*
* 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
*/
void ThermoPhase::getUnitsStandardConc(double *uA, int k, int sizeUA) {
for (int i = 0; i < sizeUA; i++) {
if (i == 0) uA[0] = 1.0;
if (i == 1) uA[1] = -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;
}
}
/*
* initThermoFile():
*
* Initialization of a phase using an xml file.
*
* This routine is a precursor to initThermoXML(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 ThermoPhase::initThermoFile(std::string inputFile, std::string id) {
if (inputFile.size() == 0) {
throw CanteraError("ThermoPhase::initThermoFile",
"input file is null");
}
string path = findInputFile(inputFile);
ifstream fin(path.c_str());
if (!fin) {
throw CanteraError("initThermoFile","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("ThermoPhase::initThermo",
"ERROR: Can not find phase named " +
id + " in file named " + inputFile);
}
fxml_phase->copy(&phaseNode_XML);
initThermoXML(*fxml_phase, id);
delete fxml;
}
/*
* Import and initialize a ThermoPhase object
*
* 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 ThermoPhase::initThermoXML(XML_Node& phaseNode, std::string id) {
/*
* The default implementation just calls initThermo(), which
* inheriting classes may override.
*/
initThermo();
/*
* and sets the state
*/
if (phaseNode.hasChild("state")) {
XML_Node& stateNode = phaseNode.child("state");
setStateFromXML(stateNode);
}
}
/*
* Initialize.
*
* This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called just prior to returning
* from function importPhase.
*
* @see importCTML.cpp
*/
void ThermoPhase::initThermo() {
}
/**
* Set the thermodynamic state.
*/
void ThermoPhase::setStateFromXML(const XML_Node& state) {
string comp = getString(state,"moleFractions");
if (comp != "")
setMoleFractionsByName(comp);
else {
comp = getString(state,"massFractions");
if (comp != "")
setMassFractionsByName(comp);
}
if (state.hasChild("temperature")) {
double t = getFloat(state, "temperature", "temperature");
setTemperature(t);
}
if (state.hasChild("pressure")) {
double p = getFloat(state, "pressure", "pressure");
setPressure(p);
}
if (state.hasChild("density")) {
double rho = getFloat(state, "density", "density");
setDensity(rho);
}
}
/*
* Called by function 'equilibrate' in ChemEquil.h to transfer
* the element potentials to this object after every successful
* equilibration routine.
* The element potentials are storred in their dimensionless
* forms, calculated by dividing by RT.
* @param lambda vector containing the element potentials.
* Length = nElements. Units are Joules/kmol.
*/
void ThermoPhase::setElementPotentials(const vector_fp& lambda) {
doublereal rrt = 1.0/(GasConstant* temperature());
int mm = nElements();
if (lambda.size() < (size_t) mm) {
throw CanteraError("setElementPotentials", "lambda too small");
}
if (!m_hasElementPotentials) {
m_lambdaRRT.resize(mm);
}
for (int m = 0; m < mm; m++) {
m_lambdaRRT[m] = lambda[m] * rrt;
}
m_hasElementPotentials = true;
}
/*
* Returns the storred element potentials.
* The element potentials are retrieved from their storred
* dimensionless forms by multiplying by RT.
* @param lambda Vector containing the element potentials.
* Length = nElements. Units are Joules/kmol.
*/
bool ThermoPhase::getElementPotentials(doublereal* lambda) const {
doublereal rt = GasConstant* temperature();
int mm = nElements();
if (m_hasElementPotentials) {
for (int m = 0; m < mm; m++) {
lambda[m] = m_lambdaRRT[m] * rt;
}
}
return (m_hasElementPotentials);
}
}

1460
Cantera/src/thermo/ThermoPhase.h Executable file

File diff suppressed because it is too large Load diff

View file

@ -15,7 +15,8 @@
#include "ctml.h"
#include "WaterPDSS.h"
#include "WaterPropsIAPWS.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include <math.h>

View file

@ -15,7 +15,8 @@
#include "xml.h"
#include "WaterSSTP.h"
#include "WaterPropsIAPWS.h"
#include "importCTML.h"
//#include "importCTML.h"
#include "ThermoFactory.h"
#include <math.h>
namespace Cantera {

62
Cantera/src/thermo/mix_defs.h Executable file
View file

@ -0,0 +1,62 @@
#ifndef CT_MIX_DEFS_H
#define CT_MIX_DEFS_H
namespace Cantera {
/**
* This generic id is used as the default in virtual base
* classes that employ id's. It is used to indicate the lack
* of an inherited class that would define the id.
*/
const int cNone = 0;
// species thermo types
const int cNASA = 1;
const int cShomate = 2;
const int cNASA96 = 3;
/**
* Equation of state types:
*
* These types are used in the member function eosType() of
* the virtual base class ThermoPhase. They are used to
* distinguish different types of equation of states. Also, they
* may be used for upcasting from the ThermoPhase class. Their
* id's should be distinct.
*
* Users who wish to define their own equation of states which
* derive from ThermoPhase should define a unique id which
* doesn't conflict with those listed below. The Cantera Kernel
* however, will not be know about the class and will therefore
* not be able to initialize the class within its "factory"
* routines.
*/
const int cIdealGas = 1; // IdealGasPhase in IdealGasPhase.h
const int cIncompressible = 2; // ConstDensityThermo in ConstDensityThermo.h
/// A surface phase. Used by class SurfPhase.
const int cSurf = 3;
/// A metal phase.
const int cMetal = 4; // MetalPhase in MetalPhase.h
// const int cSolidCompound = 5; // SolidCompound in SolidCompound.h
const int cStoichSubstance = 5; // StoichSubstance.h
const int cLatticeSolid = 20; // LatticeSolidPhase.h
const int cLattice = 21;
// pure fluids with liquid/vapor eqs of state
const int cPureFluid = 10;
/// An edge between two 2D surfaces
const int cEdge = 6;
// kinetic manager types
const int cGasKinetics = 2;
const int cGRI30 = 3;
const int cInterfaceKinetics = 4;
const int cLineKinetics = 5;
const int cEdgeKinetics = 6;
const int cSolidKinetics = 7;
}
#endif

View file

@ -0,0 +1,170 @@
// turn off warnings under Windows
#ifdef WIN32
#pragma warning(disable:4786)
#pragma warning(disable:4503)
#endif
#include "ThermoPhase.h"
#include "PureFluidPhase.h"
#include <stdio.h>
#include "mix_defs.h"
using namespace std;
namespace Cantera {
/**
* Format a summary of the mixture state for output.
*/
string report(const ThermoPhase& th, bool show_thermo) {
char p[200];
string s = "";
try {
if (th.name() != "") {
sprintf(p, " \n %s:\n", th.name().c_str());
s += p;
}
sprintf(p, " \n temperature %12.6g K\n", th.temperature());
s += p;
sprintf(p, " pressure %12.6g Pa\n", th.pressure());
s += p;
sprintf(p, " density %12.6g kg/m^3\n", th.density());
s += p;
sprintf(p, " mean mol. weight %12.6g amu\n", th.meanMolecularWeight());
s += p;
#ifdef WITH_PURE_FLUIDS
if (th.eosType() == cPureFluid) {
double xx = ((PureFluidPhase*)(&th))->vaporFraction();
// if (th.temperature() < th.critTemperature()) {
sprintf(p, " vapor fraction %12.6g \n",
xx); //th.vaporFraction());
s += p;
//}
}
#endif
doublereal phi = th.electricPotential();
if (phi != 0.0) {
sprintf(p, " potential %12.6g V\n", phi);
s += p;
}
if (show_thermo) {
sprintf(p, " \n");
s += p;
sprintf(p, " 1 kg 1 kmol\n");
s += p;
sprintf(p, " ----------- ------------\n");
s += p;
sprintf(p, " enthalpy %12.6g %12.4g J\n",
th.enthalpy_mass(), th.enthalpy_mole());
s += p;
sprintf(p, " internal energy %12.6g %12.4g J\n",
th.intEnergy_mass(), th.intEnergy_mole());
s += p;
sprintf(p, " entropy %12.6g %12.4g J/K\n",
th.entropy_mass(), th.entropy_mole());
s += p;
sprintf(p, " Gibbs function %12.6g %12.4g J\n",
th.gibbs_mass(), th.gibbs_mole());
s += p;
sprintf(p, " heat capacity c_p %12.6g %12.4g J/K\n",
th.cp_mass(), th.cp_mole());
s += p;
sprintf(p, " heat capacity c_v %12.6g %12.4g J/K\n",
th.cv_mass(), th.cv_mole());
s += p;
}
int kk = th.nSpecies();
array_fp x(kk);
array_fp y(kk);
array_fp mu(kk);
th.getMoleFractions(&x[0]);
th.getMassFractions(&y[0]);
th.getChemPotentials(&mu[0]);
doublereal rt = GasConstant * th.temperature();
int k;
if (th.nSpecies() > 1) {
if (show_thermo) {
sprintf(p, " \n X "
" Y Chem. Pot. / RT \n");
s += p;
sprintf(p, " ------------- "
"------------ ------------\n");
s += p;
for (k = 0; k < kk; k++) {
if (x[k] > SmallNumber) {
sprintf(p, "%18s %12.6g %12.6g %12.6g\n",
th.speciesName(k).c_str(), x[k], y[k], mu[k]/rt);
}
else {
sprintf(p, "%18s %12.6g %12.6g \n",
th.speciesName(k).c_str(), x[k], y[k]);
}
s += p;
}
}
else {
sprintf(p, " \n X"
"Y\n");
s += p;
sprintf(p, " -------------"
" ------------\n");
s += p;
for (k = 0; k < kk; k++) {
sprintf(p, "%18s %12.6g %12.6g\n",
th.speciesName(k).c_str(), x[k], y[k]);
s += p;
}
}
}
}
catch (CanteraError) {
;
}
return s;
}
void writephase(const ThermoPhase& th, bool show_thermo) {
string s = report(th, show_thermo);
writelog(s+"\n");
}
/**
* Format a composition list for output.
*/
string formatCompList(const Phase& mix, int xyc) {
const doublereal Threshold = 1.e-20;
char p[200];
string s = "";
int kk = mix.nSpecies();
array_fp zz(kk);
switch (xyc) {
case 0: mix.getMoleFractions(&zz[0]); break;
case 1: mix.getMassFractions(&zz[0]); break;
case 2: mix.getConcentrations(&zz[0]); break;
default: return "error: xyc must be 0, 1, or 2";
}
doublereal z;
int k;
for (k = 0; k < kk; k++) {
z = fabs(zz[k]);
if (z < Threshold) zz[k] = 0.0;
}
for (k = 0; k < kk; k++) {
sprintf(p, "%18s\t %12.6e\n", mix.speciesName(k).c_str(),
zz[k]);
s += p;
}
return s;
}
}

View file

@ -0,0 +1,105 @@
/**
* @file speciesThermoTypes.h
* Contains const definitions for types of species
* reference-state thermodynamics managers (see \ref spthermo)
*/
/*
* $Author$
* $Revision$
* $Date$
*/
// Copyright 2001 California Institute of Technology
#ifndef SPECIES_THERMO_TYPES_H
#define SPECIES_THERMO_TYPES_H
//! Constant Cp
#define CONSTANT_CP 1
//! Polynomial
#define POLYNOMIAL_4 2
//! Two regions of 7 coefficient NASA Polynomials
//! This is implemented in the class NasaPoly2 in NasaPoly2.h
#define NASA 4
//! Two regions of 7 coefficient NASA Polynomials
//! This is implemented in the class NasaPoly2 in NasaPoly2.h
#define NASA2 4
//! Two regions of Shomate Polynomials.
#define SHOMATE 8
//! Two regions of Shomate Polynomials.
#define SHOMATE2 8
//! Tiger Polynomials. Not implemented here.
#define TIGER 16
//! Constant Cp thermo.
//! This is implemented in ConstCpPoly in constCpPoly.h for one species.
//! If the whole phase is constcp, SimpleThermo in SimpleThermo.h
//! implements this for the whole phase.
#define SIMPLE 32
//! piecewise interpolation of mu0.
//! This is implemented in Mu0Poly in Mu0Poly.h
#define MU0_INTERP 64
//! one region of Shomate Polynomials used in NIST database
//! This is implemented in the NIST database.
//! This is implemented in ShomatePoly in ShomatePoly.h
#define SHOMATE1 128
//! 7 coefficient NASA Polynomials
//! This is implemented in the class NasaPoly1 in NasaPoly1.h
#define NASA1 256
#include "ct_defs.h"
#include "stringUtils.h"
#include "global.h"
namespace Cantera {
//! Error for unknown thermo parameterization
struct UnknownThermoParam {
//! Constructor
/*!
* @param thermotype Integer specifying the thermo parameterization
*
* @todo Is this used?
*/
UnknownThermoParam(int thermotype) {
writelog(std::string("\n ### ERROR ### \n") +
"Unknown species thermo parameterization ("
+ int2str(thermotype) + ")\n\n");
}
};
//! holds parameterization-dependent index information
/*!
* These are all integers.
* @todo Is this used?
*/
struct ThermoIndexData {
//! param
int param;
//! number of coefficients
int nCoefficients;
//! coefficient for Tmin
int Tmin_coeff;
//! coefficient for Tmax
int Tmax_coeff;
//! reference pressure coefficient
int Pref_coeff;
};
}
#endif