cantera/src/thermo/IdealSolnGasVPSS.cpp

436 lines
11 KiB
C++

/**
* @file IdealSolnGasVPSS.cpp
* Definition file for a derived class of ThermoPhase that assumes either
* an ideal gas or ideal solution approximation and handles
* variable pressure standard state methods for calculating
* thermodynamic properties (see \ref thermoprops and
* class \link Cantera::IdealSolnGasVPSS IdealSolnGasVPSS\endlink).
*/
/*
* Copyright (2005) Sandia Corporation. Under the terms of
* Contract DE-AC04-94AL85000 with Sandia Corporation, the
* U.S. Government retains certain rights in this software.
*/
#include "cantera/thermo/IdealSolnGasVPSS.h"
#include "cantera/thermo/VPSSMgr.h"
#include "cantera/thermo/PDSS.h"
#include "cantera/thermo/mix_defs.h"
#include "cantera/thermo/ThermoFactory.h"
#include "cantera/base/stringUtils.h"
using namespace std;
namespace Cantera
{
IdealSolnGasVPSS::IdealSolnGasVPSS() :
VPStandardStateTP(),
m_idealGas(0),
m_formGC(0)
{
}
IdealSolnGasVPSS::IdealSolnGasVPSS(const std::string& infile, std::string id_) :
VPStandardStateTP(),
m_idealGas(0),
m_formGC(0)
{
XML_Node* root = get_XML_File(infile);
if (id_ == "-") {
id_ = "";
}
XML_Node* xphase = get_XML_NameID("phase", std::string("#")+id_, root);
if (!xphase) {
throw CanteraError("newPhase",
"Couldn't find phase named \"" + id_ + "\" in file, " + infile);
}
importPhase(*xphase, this);
}
IdealSolnGasVPSS::IdealSolnGasVPSS(const IdealSolnGasVPSS& b) :
VPStandardStateTP(),
m_idealGas(0),
m_formGC(0)
{
*this = b;
}
IdealSolnGasVPSS& IdealSolnGasVPSS::
operator=(const IdealSolnGasVPSS& b)
{
if (&b != this) {
/*
* Mostly, this is a passthrough to the underlying
* assignment operator for the ThermoPhae parent object.
*/
VPStandardStateTP::operator=(b);
/*
* However, we have to handle data that we own.
*/
m_idealGas = b.m_idealGas;
m_formGC = b.m_formGC;
}
return *this;
}
ThermoPhase* IdealSolnGasVPSS::duplMyselfAsThermoPhase() const
{
return new IdealSolnGasVPSS(*this);
}
int IdealSolnGasVPSS::eosType() const
{
if (m_idealGas) {
return cIdealSolnGasVPSS;
}
return cIdealSolnGasVPSS_iscv;
}
/*
* ------------Molar Thermodynamic Properties -------------------------
*/
doublereal IdealSolnGasVPSS::enthalpy_mole() const
{
updateStandardStateThermo();
const vector_fp& enth_RT = m_VPSS_ptr->enthalpy_RT();
return (GasConstant * temperature() *
mean_X(DATA_PTR(enth_RT)));
}
doublereal IdealSolnGasVPSS::intEnergy_mole() const
{
doublereal p0 = pressure();
doublereal md = molarDensity();
return enthalpy_mole() - p0 / md;
}
doublereal IdealSolnGasVPSS::entropy_mole() const
{
updateStandardStateThermo();
const vector_fp& entrop_R = m_VPSS_ptr->entropy_R();
return GasConstant * (mean_X(DATA_PTR(entrop_R)) - sum_xlogx());
}
doublereal IdealSolnGasVPSS::gibbs_mole() const
{
return enthalpy_mole() - temperature() * entropy_mole();
}
doublereal IdealSolnGasVPSS::cp_mole() const
{
updateStandardStateThermo();
const vector_fp& cp_R = m_VPSS_ptr->cp_R();
return GasConstant * (mean_X(DATA_PTR(cp_R)));
}
doublereal IdealSolnGasVPSS::cv_mole() const
{
return cp_mole() - GasConstant;
}
void IdealSolnGasVPSS::setPressure(doublereal p)
{
m_Pcurrent = p;
updateStandardStateThermo();
calcDensity();
}
void IdealSolnGasVPSS::calcDensity()
{
/*
* Calculate the molarVolume of the solution (m**3 kmol-1)
*/
if (m_idealGas) {
double dens = (m_Pcurrent * meanMolecularWeight()
/(GasConstant * temperature()));
Phase::setDensity(dens);
} else {
const doublereal* const dtmp = moleFractdivMMW();
const vector_fp& vss = m_VPSS_ptr->standardVolumes();
double invDens = dot(vss.begin(), vss.end(), dtmp);
/*
* Set the density in the parent State object directly,
* by calling the Phase::setDensity() function.
*/
double dens = 1.0/invDens;
Phase::setDensity(dens);
}
}
doublereal IdealSolnGasVPSS::isothermalCompressibility() const
{
if (m_idealGas) {
return 1.0 / m_Pcurrent;
} else {
throw CanteraError("IdealSolnGasVPSS::isothermalCompressibility() ",
"not implemented");
}
return 0.0;
}
void IdealSolnGasVPSS::getActivityConcentrations(doublereal* c) const
{
if (m_idealGas) {
getConcentrations(c);
} else {
const vector_fp& vss = m_VPSS_ptr->standardVolumes();
switch (m_formGC) {
case 0:
for (size_t k = 0; k < m_kk; k++) {
c[k] = moleFraction(k);
}
break;
case 1:
for (size_t k = 0; k < m_kk; k++) {
c[k] = moleFraction(k) / vss[k];
}
break;
case 2:
for (size_t k = 0; k < m_kk; k++) {
c[k] = moleFraction(k) / vss[0];
}
break;
}
}
}
doublereal IdealSolnGasVPSS::standardConcentration(size_t k) const
{
if (m_idealGas) {
double p = pressure();
return p/(GasConstant * temperature());
} else {
const vector_fp& vss = m_VPSS_ptr->standardVolumes();
switch (m_formGC) {
case 0:
return 1.0;
case 1:
return 1.0 / vss[k];
case 2:
return 1.0/ vss[0];
}
return 0.0;
}
}
doublereal IdealSolnGasVPSS::logStandardConc(size_t k) const
{
double c = standardConcentration(k);
return std::log(c);
}
void IdealSolnGasVPSS::getUnitsStandardConc(double* uA, int, int sizeUA) const
{
int eos = eosType();
if (eos == cIdealSolnGasPhase0) {
for (int i = 0; i < sizeUA; i++) {
uA[i] = 0.0;
}
} else {
for (int i = 0; i < sizeUA; i++) {
if (i == 0) {
uA[0] = 1.0;
}
if (i == 1) {
uA[1] = -int(nDim());
}
if (i == 2) {
uA[2] = 0.0;
}
if (i == 3) {
uA[3] = 0.0;
}
if (i == 4) {
uA[4] = 0.0;
}
if (i == 5) {
uA[5] = 0.0;
}
}
}
}
void IdealSolnGasVPSS::getActivityCoefficients(doublereal* ac) const
{
for (size_t k = 0; k < m_kk; k++) {
ac[k] = 1.0;
}
}
/*
* ---- Partial Molar Properties of the Solution -----------------
*/
void IdealSolnGasVPSS::getChemPotentials_RT(doublereal* muRT) const
{
getChemPotentials(muRT);
doublereal invRT = 1.0 / _RT();
for (size_t k = 0; k < m_kk; k++) {
muRT[k] *= invRT;
}
}
void IdealSolnGasVPSS::getChemPotentials(doublereal* mu) const
{
getStandardChemPotentials(mu);
doublereal xx;
doublereal rt = temperature() * GasConstant;
for (size_t k = 0; k < m_kk; k++) {
xx = std::max(SmallNumber, moleFraction(k));
mu[k] += rt*(log(xx));
}
}
void IdealSolnGasVPSS::getPartialMolarEnthalpies(doublereal* hbar) const
{
getEnthalpy_RT(hbar);
doublereal rt = GasConstant * temperature();
scale(hbar, hbar+m_kk, hbar, rt);
}
void IdealSolnGasVPSS::getPartialMolarEntropies(doublereal* sbar) const
{
getEntropy_R(sbar);
doublereal r = GasConstant;
scale(sbar, sbar+m_kk, sbar, r);
for (size_t k = 0; k < m_kk; k++) {
doublereal xx = std::max(SmallNumber, moleFraction(k));
sbar[k] += r * (- log(xx));
}
}
void IdealSolnGasVPSS::getPartialMolarIntEnergies(doublereal* ubar) const
{
getIntEnergy_RT(ubar);
doublereal rt = GasConstant * temperature();
scale(ubar, ubar+m_kk, ubar, rt);
}
void IdealSolnGasVPSS::getPartialMolarCp(doublereal* cpbar) const
{
getCp_R(cpbar);
doublereal r = GasConstant;
scale(cpbar, cpbar+m_kk, cpbar, r);
}
void IdealSolnGasVPSS::getPartialMolarVolumes(doublereal* vbar) const
{
getStandardVolumes(vbar);
}
void IdealSolnGasVPSS::initThermo()
{
initLengths();
VPStandardStateTP::initThermo();
}
void IdealSolnGasVPSS::setToEquilState(const doublereal* mu_RT)
{
double tmp, tmp2;
updateStandardStateThermo();
const vector_fp& grt = m_VPSS_ptr->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;
double m_p0 = m_VPSS_ptr->refPressure();
for (size_t 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]);
}
void IdealSolnGasVPSS::initLengths()
{
m_kk = nSpecies();
m_pp.resize(m_kk, 0.0);
}
void IdealSolnGasVPSS::initThermoXML(XML_Node& phaseNode, const std::string& id_)
{
IdealSolnGasVPSS::initLengths();
if (phaseNode.hasChild("thermo")) {
XML_Node& thermoNode = phaseNode.child("thermo");
std::string model = thermoNode["model"];
if (model == "IdealGasVPSS") {
m_idealGas = 1;
} else if (model == "IdealSolnVPSS") {
m_idealGas = 0;
} else {
throw CanteraError("IdealSolnGasVPSS::initThermoXML",
"Unknown thermo model : " + model);
}
}
/*
* Form of the standard concentrations. Must have one of:
*
* <standardConc model="unity" />
* <standardConc model="molar_volume" />
* <standardConc model="solvent_volume" />
*/
if (phaseNode.hasChild("standardConc")) {
if (m_idealGas) {
throw CanteraError("IdealSolnGasVPSS::initThermoXML",
"standardConc node for ideal gas");
}
XML_Node& scNode = phaseNode.child("standardConc");
string formStringa = scNode.attrib("model");
string formString = lowercase(formStringa);
if (formString == "unity") {
m_formGC = 0;
} else if (formString == "molar_volume") {
m_formGC = 1;
} else if (formString == "solvent_volume") {
m_formGC = 2;
} else {
throw CanteraError("initThermoXML",
"Unknown standardConc model: " + formStringa);
}
} else {
if (!m_idealGas) {
throw CanteraError("initThermoXML",
"Unspecified standardConc model");
}
}
VPStandardStateTP::initThermoXML(phaseNode, id_);
}
void IdealSolnGasVPSS::setParametersFromXML(const XML_Node& thermoNode)
{
VPStandardStateTP::setParametersFromXML(thermoNode);
std::string model = thermoNode["model"];
if (model == "IdealGasVPSS") {
m_idealGas = 1;
} else if (model == "IdealSolnVPSS") {
m_idealGas = 0;
} else {
throw CanteraError("IdealSolnGasVPSS::initThermoXML",
"Unknown thermo model : " + model);
}
}
}