mirror of
https://github.com/Cantera/cantera.git
synced 2025-02-25 18:55:29 -06:00
Remove code deprecated in Cantera 2.4
This commit is contained in:
@@ -144,8 +144,7 @@ if localenv['sphinx_docs']:
|
||||
'1D/@Domain1D': ['1D/AxiStagnFlow.m', '1D/AxisymmetricFlow.m',
|
||||
'1D/Inlet.m', '1D/Outlet.m', '1D/OutletRes.m',
|
||||
'1D/Surface.m', '1D/SymmPlane.m'],
|
||||
'1D/@Stack': ['1D/FreeFlame.m', '1D/npflame_init.m',
|
||||
'1D/CounterFlowDiffusionFlame.m'],
|
||||
'1D/@Stack': ['1D/FreeFlame.m', '1D/CounterFlowDiffusionFlame.m'],
|
||||
'@Interface': ['importEdge.m', 'importInterface.m'],
|
||||
'@Data': ['gasconstant.m', 'oneatm.m'],
|
||||
'@Utilities': ['adddir.m', 'ck2cti.m', 'cleanup.m', 'geterr.m',
|
||||
|
||||
@@ -80,9 +80,6 @@ Thermodynamic Properties
|
||||
.. autoclass:: Shomate
|
||||
:no-undoc-members:
|
||||
|
||||
.. autoclass:: Adsorbate
|
||||
:no-undoc-members:
|
||||
|
||||
.. autoclass:: const_cp
|
||||
:no-undoc-members:
|
||||
|
||||
|
||||
@@ -72,7 +72,6 @@ extern "C" {
|
||||
CANTERA_CAPI double thermo_thermalExpansionCoeff(int n);
|
||||
CANTERA_CAPI double thermo_isothermalCompressibility(int n);
|
||||
CANTERA_CAPI int thermo_chemPotentials(int n, size_t lenm, double* murt);
|
||||
CANTERA_CAPI int thermo_elementPotentials(int n, size_t lenm, double* lambda);
|
||||
CANTERA_CAPI int thermo_getEnthalpies_RT(int n, size_t lenm, double* h_rt);
|
||||
CANTERA_CAPI int thermo_getEntropies_R(int n, size_t lenm, double* s_r);
|
||||
CANTERA_CAPI int thermo_getCp_R(int n, size_t lenm, double* cp_r);
|
||||
|
||||
@@ -124,11 +124,6 @@ public:
|
||||
int equilibrate(thermo_t& s, const char* XY, vector_fp& elMoles,
|
||||
int loglevel = 0);
|
||||
|
||||
//! @deprecated To be removed after Cantera 2.4.
|
||||
const vector_fp& elementPotentials() const {
|
||||
return m_lambda;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options controlling how the calculation is carried out.
|
||||
* @see EquilOptions
|
||||
@@ -267,10 +262,6 @@ protected:
|
||||
//! Current value of the mole fractions in the single phase. length = #m_kk.
|
||||
vector_fp m_molefractions;
|
||||
|
||||
//! Current value of the dimensional element potentials. length = #m_mm
|
||||
//! @deprecated To be removed after Cantera 2.4.
|
||||
vector_fp m_lambda;
|
||||
|
||||
//! Current value of the sum of the element abundances given the current
|
||||
//! element potentials.
|
||||
doublereal m_elementTotalSum;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
/**
|
||||
* @file AqueousKinetics.h
|
||||
* @ingroup chemkinetics
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_AQUEOUSKINETICS_H
|
||||
#define CT_AQUEOUSKINETICS_H
|
||||
|
||||
#include "BulkKinetics.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
/**
|
||||
* Kinetics manager for elementary aqueous-phase chemistry. This kinetics
|
||||
* manager implements standard mass-action reaction rate expressions for liquids
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* @ingroup kinetics
|
||||
*/
|
||||
class AqueousKinetics : public BulkKinetics
|
||||
{
|
||||
public:
|
||||
/// Constructor. Creates an empty reaction mechanism.
|
||||
AqueousKinetics(thermo_t* thermo = 0);
|
||||
|
||||
virtual std::string kineticsType() const {
|
||||
return "Aqueous";
|
||||
}
|
||||
|
||||
virtual void getEquilibriumConstants(doublereal* kc);
|
||||
virtual void getFwdRateConstants(doublereal* kfwd);
|
||||
void updateROP();
|
||||
|
||||
//! Update temperature-dependent portions of reaction rates
|
||||
void _update_rates_T();
|
||||
|
||||
//! Update properties that depend on concentrations.
|
||||
void _update_rates_C();
|
||||
|
||||
//! Update the equilibrium constants in molar units.
|
||||
void updateKc();
|
||||
|
||||
virtual bool addReaction(shared_ptr<Reaction> r);
|
||||
virtual void modifyReaction(size_t i, shared_ptr<Reaction> rNew);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -466,46 +466,6 @@ private:
|
||||
vector_fp m_ybar;
|
||||
};
|
||||
|
||||
/**
|
||||
* A class for axisymmetric stagnation flows.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4. Use class StFlow with the
|
||||
* StFlow::setAxisymmetricFlow() method instead.
|
||||
*
|
||||
* @ingroup onedim
|
||||
*/
|
||||
class AxiStagnFlow : public StFlow
|
||||
{
|
||||
public:
|
||||
AxiStagnFlow(IdealGasPhase* ph = 0, size_t nsp = 1, size_t points = 1) :
|
||||
StFlow(ph, nsp, points) {
|
||||
m_dovisc = true;
|
||||
m_type = cAxisymmetricStagnationFlow;
|
||||
warn_deprecated("Class AxiStagnFlow is deprecated",
|
||||
"Use StFlow with setAxisymmetricFlow() instead. To be removed after Cantera 2.4.");
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class for freely-propagating premixed flames.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4. Use class StFlow with the
|
||||
* StFlow::setFreeFlow() method instead.
|
||||
*
|
||||
* @ingroup onedim
|
||||
*/
|
||||
class FreeFlame : public StFlow
|
||||
{
|
||||
public:
|
||||
FreeFlame(IdealGasPhase* ph = 0, size_t nsp = 1, size_t points = 1) :
|
||||
StFlow(ph, nsp, points) {
|
||||
m_dovisc = false;
|
||||
m_type = cFreeFlow;
|
||||
warn_deprecated("Class FreeFlame is deprecated",
|
||||
"Use StFlow with setFreeFlow() instead. To be removed after Cantera 2.4.");
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
/**
|
||||
* @file AdsorbateThermo.h
|
||||
*
|
||||
* Header for a single-species standard state object derived from \link
|
||||
* Cantera::SpeciesThermoInterpType SpeciesThermoInterpType\endlink based on the
|
||||
* expressions for the thermo properties of a species with several vibrational
|
||||
* models.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_ADSORBATE_H
|
||||
#define CT_ADSORBATE_H
|
||||
|
||||
#include "SpeciesThermoInterpType.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
/**
|
||||
* An adsorbed surface species.
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* This class is designed specifically for use by the class MultiSpeciesThermo.
|
||||
* It implements a model for the thermodynamic properties of a molecule that can
|
||||
* be modeled as a set of independent quantum harmonic oscillators.
|
||||
*
|
||||
* @ingroup spthermo
|
||||
*/
|
||||
class Adsorbate : public SpeciesThermoInterpType
|
||||
{
|
||||
public:
|
||||
//! Full Constructor
|
||||
/*!
|
||||
* @param tlow output - Minimum temperature
|
||||
* @param thigh output - Maximum temperature
|
||||
* @param pref output - reference pressure (Pa).
|
||||
* @param coeffs Coefficients for the parameterization
|
||||
*/
|
||||
Adsorbate(double tlow, double thigh, double pref, const double* coeffs)
|
||||
: SpeciesThermoInterpType(tlow, thigh, pref)
|
||||
{
|
||||
warn_deprecated("Class Adsorbate", "To be removed after Cantera 2.4");
|
||||
m_freq.resize(int(coeffs[0]));
|
||||
m_be = coeffs[1];
|
||||
std::copy(coeffs+2, coeffs + 2 + m_freq.size(), m_freq.begin());
|
||||
}
|
||||
|
||||
virtual int reportType() const {
|
||||
return ADSORBATE;
|
||||
}
|
||||
|
||||
void updatePropertiesTemp(const doublereal temp,
|
||||
doublereal* cp_R,
|
||||
doublereal* h_RT,
|
||||
doublereal* s_R) const {
|
||||
*h_RT = _energy_RT(temp);
|
||||
*cp_R = (temp**h_RT - (temp-0.01)*_energy_RT(temp-0.01))/0.01;
|
||||
*s_R = *h_RT - _free_energy_RT(temp);
|
||||
}
|
||||
|
||||
void reportParameters(size_t& n, int& type,
|
||||
doublereal& tlow, doublereal& thigh,
|
||||
doublereal& pref,
|
||||
doublereal* const coeffs) const {
|
||||
n = 0;
|
||||
type = ADSORBATE;
|
||||
tlow = m_lowT;
|
||||
thigh = m_highT;
|
||||
pref = m_Pref;
|
||||
coeffs[0] = static_cast<double>(m_freq.size());
|
||||
coeffs[1] = m_be;
|
||||
for (size_t i = 2; i < m_freq.size()+2; i++) {
|
||||
coeffs[i] = m_freq[i-2];
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
//! array of vib frequencies
|
||||
vector_fp m_freq;
|
||||
doublereal m_be;
|
||||
|
||||
doublereal _energy_RT(double T) const {
|
||||
doublereal x, hnu_kt, hnu, sum = 0.0;
|
||||
doublereal kt = T*Boltzmann;
|
||||
for (size_t i = 0; i < m_freq.size(); i++) {
|
||||
hnu = Planck * m_freq[i];
|
||||
hnu_kt = hnu/kt;
|
||||
x = exp(-hnu_kt);
|
||||
sum += hnu_kt * x/(1.0 - x);
|
||||
}
|
||||
return sum + m_be/(GasConstant*T);
|
||||
}
|
||||
|
||||
doublereal _free_energy_RT(double T) const {
|
||||
doublereal x, hnu_kt, sum = 0.0;
|
||||
doublereal kt = T*Boltzmann;
|
||||
for (size_t i = 0; i < m_freq.size(); i++) {
|
||||
hnu_kt = Planck * m_freq[i] / kt;
|
||||
x = exp(-hnu_kt);
|
||||
sum += log(1.0 - x);
|
||||
}
|
||||
return sum + m_be/(GasConstant*T);
|
||||
}
|
||||
|
||||
doublereal _entropy_R(double T) const {
|
||||
return _energy_RT(T) - _free_energy_RT(T);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -606,32 +606,6 @@ public:
|
||||
//! Set the density of lattice sites [kmol/m^3]
|
||||
void setSiteDensity(double sitedens);
|
||||
|
||||
//! Set the equation of state parameters from the argument list
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4.
|
||||
* @internal
|
||||
* Set equation of state parameters.
|
||||
*
|
||||
* @param n number of parameters. Must be one
|
||||
* @param c array of \a n coefficients
|
||||
* c[0] = The bulk lattice density (kmol m-3)
|
||||
*/
|
||||
virtual void setParameters(int n, doublereal* const c);
|
||||
|
||||
//! Get the equation of state parameters in a vector
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4.
|
||||
* @internal
|
||||
*
|
||||
* @param n number of parameters
|
||||
* @param c array of \a n coefficients
|
||||
*
|
||||
* For this phase:
|
||||
* - n = 1
|
||||
* - c[0] = molar density of phase [ kmol/m^3 ]
|
||||
*/
|
||||
virtual void getParameters(int& n, doublereal* const c) const;
|
||||
|
||||
//! Set equation of state parameter values from XML entries.
|
||||
/*!
|
||||
* This method is called by function importPhase() when processing a phase
|
||||
|
||||
@@ -1,373 +0,0 @@
|
||||
/**
|
||||
* @file MetalSHEelectrons.h
|
||||
* Header file for the MetalSHEElectrons class, which represents the
|
||||
* electrons in a metal that are consistent with the
|
||||
* SHE electrode (see \ref thermoprops and
|
||||
* class \link Cantera::MetalSHEelectrons MetalSHEelectrons\endlink)
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_METALSHEELECTRONS_H
|
||||
#define CT_METALSHEELECTRONS_H
|
||||
|
||||
#include "SingleSpeciesTP.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Class MetalSHEelectrons represents electrons within a metal, adjacent to an
|
||||
//! aqueous electrolyte, that are consistent with the SHE reference electrode.
|
||||
/*!
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* The class is based on the electron having a chemical potential equal to one-
|
||||
* half of the entropy of the H2 gas at the system pressure
|
||||
*
|
||||
* ## Specification of Species Standard State Properties
|
||||
*
|
||||
* This class inherits from SingleSpeciesTP. 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.
|
||||
*
|
||||
* The enthalpy function is given by the following relation.
|
||||
*
|
||||
* \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]
|
||||
*
|
||||
* ## Specification of Solution Thermodynamic Properties
|
||||
*
|
||||
* All solution properties are obtained from the standard state species
|
||||
* functions, since there is only one species in the phase.
|
||||
*
|
||||
* ## %Application within Kinetics Managers
|
||||
*
|
||||
* The standard concentration is equal to 1.0. This means that the kinetics
|
||||
* operator works on an activities basis. Since this is a stoichiometric
|
||||
* substance, this means that the concentration of this phase drops out of
|
||||
* kinetics expressions since the activity is always equal to one.
|
||||
*
|
||||
* This is what is expected of electrons. The only effect that this class will
|
||||
* have on reactions is in terms of the standard state chemical potential, which
|
||||
* is equal to 1/2 of the H2 gas chemical potential, and the voltage assigned to
|
||||
* the electron, which is the voltage of the metal.
|
||||
*
|
||||
* ## Instantiation of the Class
|
||||
*
|
||||
* The constructor for this phase is located in the default ThermoFactory for
|
||||
* %Cantera. A new MetalSHEelectrons object may be created by the following code
|
||||
* snippets, where the file metalSHEelectrons.xml exists in a local directory:
|
||||
*
|
||||
* @code
|
||||
* MetalSHEelectrons *eMetal = new MetalSHEelectrons("metalSHEelectrons.xml", "");
|
||||
* @endcode
|
||||
*
|
||||
* or by the following call to importPhase():
|
||||
*
|
||||
* @code
|
||||
* XML_Node *xm = get_XML_NameID("phase", iFile + "#MetalSHEelectrons", 0);
|
||||
* MetalSHEelectrons eMetal;
|
||||
* importPhase(*xm, &eMetal);
|
||||
* @endcode
|
||||
*
|
||||
* @code
|
||||
* ThermoPhase *eMetal = newPhase("MetalSHEelectrons.xml", "MetalSHEelectrons");
|
||||
* @endcode
|
||||
*
|
||||
* Additionally, this phase may be created without including an XML file with
|
||||
* the special command, where the default file is embedded into this object.
|
||||
*
|
||||
* @code
|
||||
* MetalSHEelectrons *eMetal = new MetalSHEelectrons("MetalSHEelectrons_default.xml", "");
|
||||
* @endcode
|
||||
*
|
||||
* ## XML Example
|
||||
*
|
||||
* The phase model name for this is called MetalSHEelectrons. It must be
|
||||
* supplied as the model attribute of the thermo XML element entry. Within the
|
||||
* phase XML block, the density of the phase must be specified though it's not
|
||||
* used. An example of an XML file this phase is given below.
|
||||
*
|
||||
* @code
|
||||
* <?xml version="1.0"?>
|
||||
* <ctml>
|
||||
* <validate reactions="yes" species="yes"/>
|
||||
*
|
||||
* <phase dim="3" id="MetalSHEelectrons">
|
||||
* <elementArray datasrc="elements.xml">
|
||||
* E
|
||||
* </elementArray>
|
||||
* <speciesArray datasrc="#species_Metal_SHEelectrons"> she_electron </speciesArray>
|
||||
* <thermo model="metalSHEelectrons">
|
||||
* <density units="g/cm3">2.165</density>
|
||||
* </thermo>
|
||||
* <transport model="None"/>
|
||||
* <kinetics model="none"/>
|
||||
* </phase>
|
||||
*
|
||||
* <!-- species definitions -->
|
||||
* <speciesData id="species_Metal_SHEelectrons">
|
||||
* <species name="she_electron">
|
||||
* <atomArray> E:1 </atomArray>
|
||||
* <charge> -1 </charge>
|
||||
* <thermo>
|
||||
* <NASA Tmax="1000.0" Tmin="200.0" P0="100000.0">
|
||||
* <floatArray name="coeffs" size="7">
|
||||
* 1.172165560E+00, 3.990260375E-03, -9.739075500E-06, 1.007860470E-08,
|
||||
* -3.688058805E-12, -4.589675865E+02, 3.415051190E-01
|
||||
* </floatArray>
|
||||
* </NASA>
|
||||
* <NASA Tmax="6000.0" Tmin="1000.0" P0="100000.0">
|
||||
* <floatArray name="coeffs" size="7">
|
||||
* 1.466432895E+00, 4.133039835E-04, -7.320116750E-08, 7.705017950E-12,
|
||||
* -3.444022160E-16, -4.065327985E+02, -5.121644350E-01
|
||||
* </floatArray>
|
||||
* </NASA>
|
||||
* </thermo>
|
||||
* <density units="g/cm3">2.165</density>
|
||||
* </species>
|
||||
* </speciesData>
|
||||
* </ctml>
|
||||
* @endcode
|
||||
*
|
||||
* The model attribute, "MetalSHEelectrons", on the thermo element identifies
|
||||
* the phase as being a MetalSHEelectrons object.
|
||||
*
|
||||
* @ingroup thermoprops
|
||||
*/
|
||||
class MetalSHEelectrons : public SingleSpeciesTP
|
||||
{
|
||||
public:
|
||||
//! Default constructor for the MetalSHEelectrons class
|
||||
MetalSHEelectrons();
|
||||
|
||||
//! Construct and initialize a MetalSHEelectrons ThermoPhase object
|
||||
//! directly from an ASCII input file
|
||||
/*!
|
||||
* @param infile name of the input file
|
||||
* @param id name of the phase id in the file.
|
||||
* If this is blank, the first phase in the file is used.
|
||||
*/
|
||||
MetalSHEelectrons(const std::string& infile, const std::string& id = "");
|
||||
|
||||
//! Construct and initialize a MetalSHEelectrons ThermoPhase object
|
||||
//! directly from an XML database
|
||||
/*!
|
||||
* @param phaseRef XML node pointing to a MetalSHEelectrons description
|
||||
* @param id Id of the phase.
|
||||
*/
|
||||
MetalSHEelectrons(XML_Node& phaseRef, const std::string& id = "");
|
||||
|
||||
//! @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 stored pressure value.
|
||||
*/
|
||||
virtual doublereal pressure() const;
|
||||
|
||||
//! 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);
|
||||
|
||||
virtual doublereal isothermalCompressibility() const;
|
||||
virtual doublereal thermalExpansionCoeff() const;
|
||||
|
||||
//! @}
|
||||
//! @name Activities, Standard States, and Activity Concentrations
|
||||
//!
|
||||
//! This section is largely handled by parent classes, since there
|
||||
//! is only one species. Therefore, the activity is equal to one.
|
||||
//! @{
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* For a stoichiometric substance, there is only one species, and the
|
||||
* generalized concentration is 1.0.
|
||||
*
|
||||
* @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;
|
||||
|
||||
//! 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. This phase assumes that the kinetics
|
||||
* operator works on an dimensionless basis. Thus, the standard
|
||||
* concentration is equal to 1.0.
|
||||
*
|
||||
* @param k Optional parameter indicating the species. The default
|
||||
* is to assume this refers to species 0.
|
||||
* @return
|
||||
* Returns The standard Concentration as 1.0
|
||||
*/
|
||||
virtual doublereal standardConcentration(size_t 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(size_t k=0) const;
|
||||
|
||||
//! Get the array of chemical potentials at unit activity for the species at
|
||||
//! their standard states at the current *T* and *P* of the solution.
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
//@}
|
||||
/// @name Properties of the Standard State of the Species in the Solution
|
||||
//@{
|
||||
|
||||
virtual void getEnthalpy_RT(doublereal* hrt) const;
|
||||
virtual void getEntropy_R(doublereal* sr) const;
|
||||
virtual void getGibbs_RT(doublereal* grt) const;
|
||||
virtual void getCp_R(doublereal* cpr) const;
|
||||
|
||||
//! Returns the vector of nondimensional Internal Energies of the standard
|
||||
//! state species at the current *T* and *P* of the solution
|
||||
/*!
|
||||
* 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_{ref}
|
||||
* \hat v\f$ is subtracted from the specified reference molar enthalpy to
|
||||
* compute the standard state molar internal energy.
|
||||
*
|
||||
* @param urt output vector of nondimensional standard state
|
||||
* internal energies of the species. Length: m_kk.
|
||||
*/
|
||||
virtual void getIntEnergy_RT(doublereal* urt) const;
|
||||
|
||||
//@}
|
||||
/// @name Thermodynamic Values for the Species Reference States
|
||||
//@{
|
||||
|
||||
virtual void getIntEnergy_RT_ref(doublereal* urt) const;
|
||||
// @}
|
||||
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
|
||||
|
||||
//! Make the default XML tree
|
||||
/*!
|
||||
* @returns a new XML tree containing the default info.
|
||||
*/
|
||||
static XML_Node* makeDefaultXMLTree();
|
||||
|
||||
//! Set the equation of state parameters
|
||||
/*!
|
||||
* @internal
|
||||
*
|
||||
* @param n number of parameters
|
||||
* @param c array of \a n coefficients
|
||||
* c[0] = density of phase [ kg/m3 ]
|
||||
*/
|
||||
virtual void setParameters(int n, doublereal* const c);
|
||||
|
||||
//! Get the equation of state parameters in a vector
|
||||
/*!
|
||||
* @internal
|
||||
*
|
||||
* @param n number of parameters
|
||||
* @param c array of \a n coefficients
|
||||
*
|
||||
* For this phase:
|
||||
* - n = 1
|
||||
* - c[0] = density of phase [ kg/m3 ]
|
||||
*/
|
||||
virtual void getParameters(int& n, doublereal* const c) const;
|
||||
|
||||
//! Set equation of state parameter values from XML entries.
|
||||
/*!
|
||||
* For this phase, the density of the phase is specified in this block.
|
||||
*
|
||||
* @param eosdata An XML_Node object corresponding to
|
||||
* the "thermo" entry for this phase in the input file.
|
||||
*
|
||||
* eosdata points to the thermo block, and looks like this:
|
||||
*
|
||||
* @code
|
||||
* <phase id="stoichsolid" >
|
||||
* <thermo model="StoichSubstance">
|
||||
* <density units="g/cm3">3.52</density>
|
||||
* </thermo>
|
||||
* </phase>
|
||||
* @endcode
|
||||
*/
|
||||
virtual void setParametersFromXML(const XML_Node& eosdata);
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,325 +0,0 @@
|
||||
/**
|
||||
* @file MineralEQ3.h
|
||||
* Header file for the MineralEQ3 class, which represents a fixed-composition
|
||||
* incompressible substance based on EQ3's parameterization (see \ref thermoprops and
|
||||
* class \link Cantera::MineralEQ3 MineralEQ3\endlink)
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_MINERALEQ3_H
|
||||
#define CT_MINERALEQ3_H
|
||||
|
||||
#include "StoichSubstance.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Class MineralEQ3 represents a stoichiometric (fixed composition)
|
||||
//! incompressible substance based on EQ3's parameterization
|
||||
/*!
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* This class inherits from SingleSpeciesTP class. EQ's parameterization is
|
||||
* mapped onto the Shomate polynomial class.
|
||||
*
|
||||
* ## Specification of Species Standard State Properties
|
||||
*
|
||||
* This class inherits from SingleSpeciesTP. 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.
|
||||
*
|
||||
* 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. The
|
||||
* entropy is assumed to be independent of the pressure.
|
||||
*
|
||||
* The enthalpy function is given by the following relation.
|
||||
*
|
||||
* \f[
|
||||
* h^o_k(T,P) =
|
||||
* h^{ref}_k(T) + \tilde v \left( P - P_{ref} \right)
|
||||
* \f]
|
||||
*
|
||||
* 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_{ref} \tilde v\f$ is
|
||||
* subtracted from the specified reference molar enthalpy to compute the molar
|
||||
* internal energy.
|
||||
*
|
||||
* \f[
|
||||
* u^o_k(T,P) = h^{ref}_k(T) - P_{ref} \tilde v
|
||||
* \f]
|
||||
*
|
||||
* The standard state heat capacity and entropy are independent of pressure. The
|
||||
* standard state Gibbs free energy is obtained from the enthalpy and entropy
|
||||
* functions.
|
||||
*
|
||||
* ## Specification of Solution Thermodynamic Properties
|
||||
*
|
||||
* All solution properties are obtained from the standard state species
|
||||
* functions, since there is only one species in the phase.
|
||||
*
|
||||
* ## %Application within Kinetics Managers
|
||||
*
|
||||
* The standard concentration is equal to 1.0. This means that the kinetics
|
||||
* operator works on an (activities basis). Since this is a stoichiometric
|
||||
* substance, this means that the concentration of this phase drops out of
|
||||
* kinetics expressions.
|
||||
*
|
||||
* An example of a reaction using this is a sticking coefficient reaction of a
|
||||
* substance in an ideal gas phase on a surface with a bulk phase species in
|
||||
* this phase. In this case, the rate of progress for this reaction,
|
||||
* \f$ R_s \f$, may be expressed via the following equation:
|
||||
* \f[
|
||||
* R_s = k_s C_{gas}
|
||||
* \f]
|
||||
* where the units for \f$ R_s \f$ are kmol m-2 s-1. \f$ C_{gas} \f$ has units
|
||||
* of kmol m-3. Therefore, the kinetic rate constant, \f$ k_s \f$, has units of
|
||||
* m s-1. Nowhere does the concentration of the bulk phase appear in the rate
|
||||
* constant expression, since it's a stoichiometric phase and the activity is
|
||||
* always equal to 1.0.
|
||||
*
|
||||
* @ingroup thermoprops
|
||||
*/
|
||||
class MineralEQ3 : public StoichSubstance
|
||||
{
|
||||
public:
|
||||
//! Default constructor for the MineralEQ3 class
|
||||
MineralEQ3() {
|
||||
warn_deprecated("Class MineralEQ3", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
//! Construct and initialize a MineralEQ3 ThermoPhase object
|
||||
//! directly from an ASCII input file
|
||||
/*!
|
||||
* @param infile name of the input file
|
||||
* @param id name of the phase id in the file.
|
||||
* If this is blank, the first phase in the file is used.
|
||||
*/
|
||||
MineralEQ3(const std::string& infile, const std::string& id = "");
|
||||
|
||||
//! Construct and initialize a MineralEQ3 ThermoPhase object
|
||||
//! directly from an XML database
|
||||
/*!
|
||||
* @param phaseRef XML node pointing to a MineralEQ3 description
|
||||
* @param id Id of the phase.
|
||||
*/
|
||||
MineralEQ3(XML_Node& phaseRef, const std::string& id = "");
|
||||
|
||||
virtual std::string type() const {
|
||||
return "MineralEQ3";
|
||||
}
|
||||
|
||||
//! @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 stored pressure value.
|
||||
*/
|
||||
virtual doublereal pressure() const;
|
||||
|
||||
//! 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);
|
||||
|
||||
virtual doublereal isothermalCompressibility() const;
|
||||
virtual doublereal thermalExpansionCoeff() const;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @name Activities, Standard States, and Activity Concentrations
|
||||
*
|
||||
* This section is largely handled by parent classes, since there is only
|
||||
* one species. Therefore, the activity is equal to one.
|
||||
* @{
|
||||
*/
|
||||
|
||||
//! 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.
|
||||
*
|
||||
* For a stoichiometric substance, there is only one species, and the
|
||||
* generalized concentration is 1.0.
|
||||
*
|
||||
* @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;
|
||||
|
||||
//! 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. This phase assumes that the kinetics
|
||||
* operator works on an dimensionless basis. Thus, the standard
|
||||
* concentration is equal to 1.0.
|
||||
*
|
||||
* @param k Optional parameter indicating the species. The default
|
||||
* is to assume this refers to species 0.
|
||||
* @return
|
||||
* Returns The standard Concentration as 1.0
|
||||
*/
|
||||
virtual doublereal standardConcentration(size_t k=0) const;
|
||||
virtual doublereal logStandardConc(size_t k=0) const;
|
||||
|
||||
//! Get the array of chemical potentials at unit activity for the species at
|
||||
//! their standard states at the current *T* and *P* of the solution.
|
||||
/*!
|
||||
* 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.
|
||||
*
|
||||
* 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;
|
||||
|
||||
//@}
|
||||
/// @name Properties of the Standard State of the Species in the Solution
|
||||
//@{
|
||||
|
||||
virtual void getEnthalpy_RT(doublereal* hrt) const;
|
||||
virtual void getEntropy_R(doublereal* sr) const;
|
||||
virtual void getGibbs_RT(doublereal* grt) const;
|
||||
virtual void getCp_R(doublereal* cpr) const;
|
||||
|
||||
//! Returns the vector of nondimensional Internal Energies of the standard
|
||||
//! state species at the current *T* and *P* of the solution
|
||||
/*!
|
||||
* 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_{ref} \hat v\f$ is subtracted from the specified reference molar
|
||||
* enthalpy to compute the standard state molar internal energy.
|
||||
*
|
||||
* @param urt output vector of nondimensional standard state internal
|
||||
* energies of the species. Length: m_kk.
|
||||
*/
|
||||
virtual void getIntEnergy_RT(doublereal* urt) const;
|
||||
|
||||
//@}
|
||||
/// @name Thermodynamic Values for the Species Reference States
|
||||
//@{
|
||||
|
||||
virtual void getIntEnergy_RT_ref(doublereal* urt) const;
|
||||
//! @}
|
||||
|
||||
//! @copydoc ThermoPhase::initThermoXML
|
||||
/*!
|
||||
* This is the main routine for reading in activity coefficient parameters.
|
||||
*/
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
|
||||
|
||||
//! Set the equation of state parameters
|
||||
/*!
|
||||
* @internal
|
||||
*
|
||||
* @param n number of parameters
|
||||
* @param c array of \a n coefficients
|
||||
* c[0] = density of phase [ kg/m3 ]
|
||||
*/
|
||||
virtual void setParameters(int n, doublereal* const c);
|
||||
|
||||
//! Get the equation of state parameters in a vector
|
||||
/*!
|
||||
* @internal
|
||||
*
|
||||
* @param n number of parameters
|
||||
* @param c array of \a n coefficients
|
||||
*
|
||||
* For this phase:
|
||||
* - n = 1
|
||||
* - c[0] = density of phase [ kg/m3 ]
|
||||
*/
|
||||
virtual void getParameters(int& n, doublereal* const c) const;
|
||||
|
||||
//! @copydoc ThermoPhase::setParametersFromXML
|
||||
/*!
|
||||
* For this phase, the density of the phase is specified in this block.
|
||||
*/
|
||||
virtual void setParametersFromXML(const XML_Node& eosdata);
|
||||
doublereal LookupGe(const std::string& elemName);
|
||||
void convertDGFormation();
|
||||
|
||||
protected:
|
||||
//! Value of the Absolute Gibbs Free Energy NIST scale at T_r and P_r
|
||||
/*!
|
||||
* This is the NIST scale value of Gibbs free energy at T_r = 298.15
|
||||
* and P_r = 1 atm.
|
||||
*
|
||||
* J kmol-1
|
||||
*/
|
||||
doublereal m_Mu0_pr_tr;
|
||||
|
||||
//! Input value of S_j at Tr and Pr (cal gmol-1 K-1)
|
||||
/*!
|
||||
* Tr = 298.15 Pr = 1 atm
|
||||
*/
|
||||
doublereal m_Entrop_pr_tr;
|
||||
|
||||
//! Input Value of deltaG of Formation at Tr and Pr (cal gmol-1)
|
||||
/*!
|
||||
* Tr = 298.15 Pr = 1 atm
|
||||
*
|
||||
* This is the delta G for the formation reaction of the ion from elements
|
||||
* in their stable state at Tr, Pr.
|
||||
*/
|
||||
doublereal m_deltaG_formation_pr_tr;
|
||||
|
||||
//! Input Value of deltaH of Formation at Tr and Pr (cal gmol-1)
|
||||
/*!
|
||||
* Tr = 298.15 Pr = 1 atm
|
||||
*
|
||||
* This is the delta H for the formation reaction of the ion from elements
|
||||
* in their stable state at Tr, Pr.
|
||||
*/
|
||||
doublereal m_deltaH_formation_pr_tr;
|
||||
|
||||
//! Input Value of the molar volume at T_r and P_r
|
||||
/*!
|
||||
* cm^3 / gmol
|
||||
*/
|
||||
doublereal m_V0_pr_tr;
|
||||
|
||||
//! a coefficient (cal gmol-1 K-1)
|
||||
doublereal m_a;
|
||||
|
||||
//! b coefficient (cal gmol-1 K-2) x 10^3
|
||||
doublereal m_b;
|
||||
|
||||
//! c coefficient (cal K gmol-1 K) x 10^-5
|
||||
doublereal m_c;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,469 +0,0 @@
|
||||
/**
|
||||
* @file MixedSolventElectrolyte.h (see \ref thermoprops and class \link
|
||||
* Cantera::MixedSolventElectrolyte MixedSolventElectrolyte \endlink).
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_MIXEDSOLVENTELECTROLYTEVPSSTP_H
|
||||
#define CT_MIXEDSOLVENTELECTROLYTEVPSSTP_H
|
||||
|
||||
#include "MolarityIonicVPSSTP.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
//! MixedSolventElectrolyte is a derived class of GibbsExcessVPSSTP that employs
|
||||
//! the DH and local Margules approximations for the excess Gibbs free energy
|
||||
/*!
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* MixedSolventElectrolyte derives from class GibbsExcessVPSSTP which is derived
|
||||
* from VPStandardStateTP.
|
||||
*
|
||||
* The independent unknowns are pressure, temperature, and mass fraction.
|
||||
*
|
||||
* ## Specification of Species Standard State Properties
|
||||
*
|
||||
* All species are defined to have standard states that depend upon both the
|
||||
* temperature and the pressure. The Margules approximation assumes symmetric
|
||||
* standard states, where all of the standard state assume that the species are
|
||||
* in pure component states at the temperature and pressure of the solution. I
|
||||
* don't think it prevents, however, some species from being dilute in the
|
||||
* solution.
|
||||
*
|
||||
* ## Specification of Solution Thermodynamic Properties
|
||||
*
|
||||
* The molar excess Gibbs free energy is given by the following formula which is
|
||||
* a sum over interactions *i*. Each of the interactions are binary interactions
|
||||
* involving two of the species in the phase, denoted, *Ai* and *Bi*. This is
|
||||
* the generalization of the Margules formulation for a phase that has more than
|
||||
* 2 species.
|
||||
*
|
||||
* \f[
|
||||
* G^E = \sum_i \left( H_{Ei} - T S_{Ei} \right)
|
||||
* \f]
|
||||
* \f[
|
||||
* H^E_i = n X_{Ai} X_{Bi} \left( h_{o,i} + h_{1,i} X_{Bi} \right)
|
||||
* \f]
|
||||
* \f[
|
||||
* S^E_i = n X_{Ai} X_{Bi} \left( s_{o,i} + s_{1,i} X_{Bi} \right)
|
||||
* \f]
|
||||
*
|
||||
* where n is the total moles in the solution.
|
||||
*
|
||||
* The activity of a species defined in the phase is given by an excess Gibbs
|
||||
* free energy formulation.
|
||||
*
|
||||
* \f[
|
||||
* a_k = \gamma_k X_k
|
||||
* \f]
|
||||
*
|
||||
* where
|
||||
*
|
||||
* \f[
|
||||
* R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i}
|
||||
* \f]
|
||||
*
|
||||
* Taking the derivatives results in the following expression
|
||||
*
|
||||
* \f[
|
||||
* R T \ln( \gamma_k )= \sum_i \left( \left( \delta_{Ai,k} X_{Bi} + \delta_{Bi,k} X_{Ai} - X_{Ai} X_{Bi} \right)
|
||||
* \left( g^E_{o,i} + g^E_{1,i} X_{Bi} \right) +
|
||||
* \left( \delta_{Bi,k} - X_{Bi} \right) X_{Ai} X_{Bi} g^E_{1,i} \right)
|
||||
* \f]
|
||||
* where \f$ g^E_{o,i} = h_{o,i} - T s_{o,i} \f$ and
|
||||
* \f$ g^E_{1,i} = h_{1,i} - T s_{1,i} \f$ and where \f$ X_k \f$ is the mole
|
||||
* fraction of species *k*.
|
||||
*
|
||||
* This object inherits from the class VPStandardStateTP. Therefore, the
|
||||
* specification and calculation of all standard state and reference state
|
||||
* values are handled at that level. Various functional forms for the standard
|
||||
* state are permissible. The chemical potential for species *k* is equal to
|
||||
*
|
||||
* \f[
|
||||
* \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k)
|
||||
* \f]
|
||||
*
|
||||
* The partial molar entropy for species *k* is given by the following relation,
|
||||
*
|
||||
* \f[
|
||||
* \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k )
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar enthalpy for species *k* is given by
|
||||
*
|
||||
* \f[
|
||||
* \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar volume for species *k* is
|
||||
*
|
||||
* \f[
|
||||
* \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar Heat Capacity for species *k* is
|
||||
*
|
||||
* \f[
|
||||
* \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT}
|
||||
* - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2}
|
||||
* \f]
|
||||
*
|
||||
* ## %Application within Kinetics Managers
|
||||
*
|
||||
* \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 *k* is independent of *k* 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.
|
||||
*
|
||||
* @ingroup thermoprops
|
||||
* @deprecated To be removed after Cantera 2.4.
|
||||
*/
|
||||
class MixedSolventElectrolyte : public MolarityIonicVPSSTP
|
||||
{
|
||||
public:
|
||||
MixedSolventElectrolyte();
|
||||
|
||||
//! Construct and initialize a MixedSolventElectrolyte ThermoPhase object
|
||||
//! directly from an XML input file
|
||||
/*!
|
||||
* @param inputFile Name of the input file containing the phase XML data
|
||||
* to set up the object
|
||||
* @param id ID of the phase in the input file. Defaults to the
|
||||
* empty string.
|
||||
*/
|
||||
MixedSolventElectrolyte(const std::string& inputFile,
|
||||
const std::string& id = "");
|
||||
|
||||
//! Construct and initialize a MixedSolventElectrolyte ThermoPhase object
|
||||
//! directly from an XML database
|
||||
/*!
|
||||
* @param phaseRef XML phase node containing the description of the phase
|
||||
* @param id id attribute containing the name of the phase.
|
||||
* (default is the empty string)
|
||||
*/
|
||||
MixedSolventElectrolyte(XML_Node& phaseRef, const std::string& id = "");
|
||||
|
||||
virtual std::string type() const {
|
||||
return "MixedSolventElectrolyte";
|
||||
}
|
||||
|
||||
//! @name Molar Thermodynamic Properties
|
||||
//! @{
|
||||
|
||||
virtual doublereal enthalpy_mole() const;
|
||||
virtual doublereal entropy_mole() const;
|
||||
virtual doublereal cp_mole() const;
|
||||
virtual doublereal cv_mole() const;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @name Activities, Standard States, and Activity Concentrations
|
||||
*
|
||||
* The activity \f$a_k\f$ of a species in solution is related to the
|
||||
* chemical potential by \f[ \mu_k = \mu_k^0(T) + \hat R T \log a_k. \f] The
|
||||
* quantity \f$\mu_k^0(T,P)\f$ is the chemical potential at unit activity,
|
||||
* which depends only on temperature and pressure.
|
||||
* @{
|
||||
*/
|
||||
|
||||
virtual void getActivityCoefficients(doublereal* ac) const;
|
||||
|
||||
//@}
|
||||
/// @name Partial Molar Properties of the Solution
|
||||
//@{
|
||||
|
||||
virtual void getChemPotentials(doublereal* mu) const;
|
||||
virtual void getPartialMolarEnthalpies(doublereal* hbar) const;
|
||||
virtual void getPartialMolarEntropies(doublereal* sbar) const;
|
||||
virtual void getPartialMolarCp(doublereal* cpbar) const;
|
||||
virtual void getPartialMolarVolumes(doublereal* vbar) const;
|
||||
|
||||
//! Get the array of temperature second derivatives of the log activity
|
||||
//! coefficients
|
||||
/*!
|
||||
* units = 1/Kelvin
|
||||
*
|
||||
* @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of
|
||||
* the log Activity Coefficients. length = m_kk
|
||||
*
|
||||
*/
|
||||
virtual void getd2lnActCoeffdT2(doublereal* d2lnActCoeffdT2) const;
|
||||
|
||||
//! Get the array of temperature derivatives of the log activity coefficients
|
||||
/*!
|
||||
* This is a virtual function, which first appears in GibbsExcessVPSSTP.
|
||||
*
|
||||
* units = 1/Kelvin
|
||||
*
|
||||
* @param dlnActCoeffdT Output vector of temperature derivatives of the
|
||||
* log Activity Coefficients. length = m_kk
|
||||
*/
|
||||
virtual void getdlnActCoeffdT(doublereal* dlnActCoeffdT) const;
|
||||
|
||||
//! @}
|
||||
//! @name Initialization
|
||||
/// The following methods are used in the process of constructing the phase
|
||||
/// and setting its parameters from a specification in an input file. They
|
||||
/// are not normally used in application programs. To see how they are used,
|
||||
/// see importPhase().
|
||||
/// @{
|
||||
|
||||
virtual void initThermo();
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @name Derivatives of Thermodynamic Variables needed for Applications
|
||||
* @{
|
||||
*/
|
||||
|
||||
virtual void getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds, doublereal* dlnActCoeffds) const;
|
||||
virtual void getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const;
|
||||
virtual void getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const;
|
||||
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN);
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Process an XML node called "binaryNeutralSpeciesParameters"
|
||||
/*!
|
||||
* This node contains all of the parameters necessary to describe the
|
||||
* Margules model for a particular binary interaction. This function reads
|
||||
* the XML file and writes the coefficients it finds to an internal data
|
||||
* structures.
|
||||
*
|
||||
* @param xmlBinarySpecies Reference to the XML_Node named
|
||||
* "binaryNeutralSpeciesParameters" containing the binary interaction
|
||||
*/
|
||||
void readXMLBinarySpecies(XML_Node& xmlBinarySpecies);
|
||||
|
||||
//! Resize internal arrays within the object that depend upon the number
|
||||
//! of binary Margules interaction terms
|
||||
/*!
|
||||
* @param num Number of binary Margules interaction terms
|
||||
*/
|
||||
void resizeNumInteractions(const size_t num);
|
||||
|
||||
//! Initialize lengths of local variables after all species have been
|
||||
//! identified.
|
||||
void initLengths();
|
||||
|
||||
//! Update the activity coefficients
|
||||
/*!
|
||||
* This function will be called to update the internally stored natural
|
||||
* logarithm of the activity coefficients
|
||||
*/
|
||||
void s_update_lnActCoeff() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt T
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt temperature.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dT() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients
|
||||
//! wrt log(mole fraction)
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt logarithm of
|
||||
* the mole fractions.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnX_diag() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients
|
||||
//! wrt log(moles) - diagonal only
|
||||
/*!
|
||||
* This function will be called to update the internally stored diagonal
|
||||
* entries for the derivative of the natural logarithm of the activity
|
||||
* coefficients wrt logarithm of the moles.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnN_diag() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt log(moles_m)
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt logarithm of
|
||||
* the mole number of species
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnN() const;
|
||||
|
||||
protected:
|
||||
//! number of binary interaction expressions
|
||||
size_t numBinaryInteractions_;
|
||||
|
||||
//! Enthalpy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_b_ij;
|
||||
|
||||
//! Enthalpy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_c_ij;
|
||||
|
||||
//! Enthalpy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_d_ij;
|
||||
|
||||
//! Entropy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_b_ij;
|
||||
|
||||
//! Entropy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_c_ij;
|
||||
|
||||
//! Entropy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_d_ij;
|
||||
|
||||
//! Enthalpy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_b_ij;
|
||||
|
||||
//! Enthalpy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_c_ij;
|
||||
|
||||
//! Enthalpy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_d_ij;
|
||||
|
||||
//! Entropy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_b_ij;
|
||||
|
||||
//! Entropy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_c_ij;
|
||||
|
||||
//! Entropy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_d_ij;
|
||||
|
||||
//! vector of species indices representing species A in the interaction
|
||||
/*!
|
||||
* Each Margules excess Gibbs free energy term involves two species, A and
|
||||
* B. This vector identifies species A.
|
||||
*/
|
||||
std::vector<size_t> m_pSpecies_A_ij;
|
||||
|
||||
//! vector of species indices representing species B in the interaction
|
||||
/*!
|
||||
* Each Margules excess Gibbs free energy term involves two species, A and
|
||||
* B. This vector identifies species B.
|
||||
*/
|
||||
std::vector<size_t> m_pSpecies_B_ij;
|
||||
|
||||
//! form of the Margules interaction expression
|
||||
/*!
|
||||
* Currently there is only one form.
|
||||
*/
|
||||
int formMargules_;
|
||||
|
||||
//! form of the temperature dependence of the Margules interaction expression
|
||||
/*!
|
||||
* Currently there is only one form -> constant wrt temperature.
|
||||
*/
|
||||
int formTempModel_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -218,23 +218,6 @@ public:
|
||||
//! @name Utilities for Solvent ID and Molality
|
||||
//! @{
|
||||
|
||||
/**
|
||||
* This routine sets the index number of the solvent for the phase.
|
||||
*
|
||||
* Note, having a solvent is a precursor to many things having to do with
|
||||
* molality.
|
||||
*
|
||||
* @param k the solvent index number
|
||||
* @deprecated The solvent is always the first species in the phase. To be
|
||||
* removed after Cantera 2.4.
|
||||
*/
|
||||
void setSolvent(size_t k);
|
||||
|
||||
//! Returns the solvent index.
|
||||
//! @deprecated The solvent is always the first species in the phase. To be
|
||||
//! removed after Cantera 2.4.
|
||||
size_t solventIndex() const;
|
||||
|
||||
/**
|
||||
* Sets the minimum mole fraction in the molality formulation. Note the
|
||||
* molality formulation is singular in the limit that the solvent mole
|
||||
|
||||
@@ -1,262 +0,0 @@
|
||||
/**
|
||||
* @file MolarityIonicVPSSTP.h (see \ref thermoprops and class \link
|
||||
* Cantera::MolarityIonicVPSSTP MolarityIonicVPSSTP\endlink).
|
||||
*
|
||||
* Header file for a derived class of ThermoPhase that handles variable pressure
|
||||
* standard state methods for calculating thermodynamic properties that are
|
||||
* further based upon activities based on the molarity scale. In this class, we
|
||||
* expect that there are ions, but they are treated on the molarity scale.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_MOLARITYIONICVPSSTP_H
|
||||
#define CT_MOLARITYIONICVPSSTP_H
|
||||
|
||||
#include "GibbsExcessVPSSTP.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
/*!
|
||||
* MolarityIonicVPSSTP is a derived class of GibbsExcessVPSSTP that handles
|
||||
* variable pressure standard state methods for calculating thermodynamic
|
||||
* properties that are further based on expressing the Excess Gibbs free energy
|
||||
* as a function of the mole fractions (or pseudo mole fractions) of the
|
||||
* constituents. This category is the workhorse for describing ionic systems
|
||||
* which are not on the molality scale.
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* This class adds additional functions onto the ThermoPhase interface that
|
||||
* handles the calculation of the excess Gibbs free energy. The ThermoPhase
|
||||
* class includes a member function, ThermoPhase::activityConvention() that
|
||||
* indicates which convention the activities are based on. The default is to
|
||||
* assume activities are based on the molar convention. That default is used
|
||||
* here.
|
||||
*
|
||||
* All of the Excess Gibbs free energy formulations in this area employ
|
||||
* symmetrical formulations.
|
||||
*
|
||||
* This layer will massage the mole fraction vector to implement cation and
|
||||
* anion based mole numbers in an optional manner, such that it is expected that
|
||||
* there exists a charge balance at all times. One of the ions must be a
|
||||
* "special ion" in the sense that its' thermodynamic functions are set to zero,
|
||||
* and the thermo functions of all other ions are based on a valuation relative
|
||||
* to that special ion.
|
||||
*/
|
||||
class MolarityIonicVPSSTP : public GibbsExcessVPSSTP
|
||||
{
|
||||
public:
|
||||
MolarityIonicVPSSTP();
|
||||
|
||||
//! Construct and initialize a MolarityIonicVPSSTP ThermoPhase object
|
||||
//! directly from an XML input file
|
||||
/*!
|
||||
* @param inputFile Name of the input file containing the phase XML data
|
||||
* to set up the object
|
||||
* @param id ID of the phase in the input file. Defaults to the
|
||||
* empty string.
|
||||
*/
|
||||
MolarityIonicVPSSTP(const std::string& inputFile, const std::string& id = "");
|
||||
|
||||
//! Construct and initialize a MolarityIonicVPSSTP ThermoPhase object
|
||||
//! directly from an XML database
|
||||
/*!
|
||||
* @param phaseRef XML phase node containing the description of the phase
|
||||
* @param id id attribute containing the name of the phase.
|
||||
* (default is the empty string)
|
||||
*/
|
||||
MolarityIonicVPSSTP(XML_Node& phaseRef, const std::string& id = "");
|
||||
|
||||
virtual std::string type() const {
|
||||
return "MolarityIonic";
|
||||
}
|
||||
|
||||
/**
|
||||
* @name Activities, Standard States, and Activity Concentrations
|
||||
*
|
||||
* The activity \f$a_k\f$ of a species in solution is
|
||||
* related to the chemical potential by \f[ \mu_k = \mu_k^0(T)
|
||||
* + \hat R T \log a_k. \f] The quantity \f$\mu_k^0(T,P)\f$ is
|
||||
* the chemical potential at unit activity, which depends only
|
||||
* on temperature and pressure.
|
||||
* @{
|
||||
*/
|
||||
|
||||
virtual void getLnActivityCoefficients(doublereal* lnac) const;
|
||||
|
||||
//@}
|
||||
/// @name Partial Molar Properties of the Solution
|
||||
//@{
|
||||
|
||||
virtual void getChemPotentials(doublereal* mu) const;
|
||||
|
||||
//! Returns an array of partial molar enthalpies for the species
|
||||
//! in the mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the molality-based
|
||||
* activity coefficient wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* \f]
|
||||
*
|
||||
* @param hbar Vector of returned partial molar enthalpies
|
||||
* (length m_kk, units = J/kmol)
|
||||
*/
|
||||
virtual void getPartialMolarEnthalpies(doublereal* hbar) const;
|
||||
|
||||
//! Returns an array of partial molar entropies for the species in the
|
||||
//! mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the activity coefficient
|
||||
* wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* - R \ln( \gamma_k X_k)
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* \f]
|
||||
*
|
||||
* @param sbar Vector of returned partial molar entropies
|
||||
* (length m_kk, units = J/kmol/K)
|
||||
*/
|
||||
virtual void getPartialMolarEntropies(doublereal* sbar) const;
|
||||
|
||||
//! Returns an array of partial molar entropies for the species
|
||||
//! in the mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the activity coefficient
|
||||
* wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* ???????????????
|
||||
* \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* - R \ln( \gamma_k X_k)
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* ???????????????
|
||||
* \f]
|
||||
*
|
||||
* @param cpbar Vector of returned partial molar heat capacities
|
||||
* (length m_kk, units = J/kmol/K)
|
||||
*/
|
||||
virtual void getPartialMolarCp(doublereal* cpbar) const;
|
||||
|
||||
virtual void getPartialMolarVolumes(doublereal* vbar) const;
|
||||
|
||||
//@}
|
||||
|
||||
//! Calculate pseudo binary mole fractions
|
||||
virtual void calcPseudoBinaryMoleFractions() const;
|
||||
|
||||
/// @name Initialization
|
||||
/// The following methods are used in the process of constructing
|
||||
/// the phase and setting its parameters from a specification in an
|
||||
/// input file. They are not normally used in application programs.
|
||||
/// To see how they are used, see importPhase().
|
||||
/// @{
|
||||
|
||||
virtual void initThermo();
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
|
||||
//! @}
|
||||
|
||||
virtual std::string report(bool show_thermo=true,
|
||||
doublereal threshold=1e-14) const;
|
||||
|
||||
private:
|
||||
//! Initialize lengths of local variables after all species have been
|
||||
//! identified.
|
||||
void initLengths();
|
||||
|
||||
//! Process an XML node called "binaryNeutralSpeciesParameters"
|
||||
/*!
|
||||
* This node contains all of the parameters necessary to describe the
|
||||
* Redlich-Kister model for a particular binary interaction. This function
|
||||
* reads the XML file and writes the coefficients it finds to an internal
|
||||
* data structures.
|
||||
*
|
||||
* @param xmlBinarySpecies Reference to the XML_Node named
|
||||
* "binaryNeutralSpeciesParameters" containing the binary interaction
|
||||
*/
|
||||
void readXMLBinarySpecies(XML_Node& xmlBinarySpecies);
|
||||
|
||||
//! Update the activity coefficients
|
||||
/*!
|
||||
* This function will be called to update the internally stored natural
|
||||
* logarithm of the activity coefficients
|
||||
*/
|
||||
void s_update_lnActCoeff() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt T
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt temperature.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dT() const;
|
||||
|
||||
//! Internal routine that calculates the derivative of the activity
|
||||
//! coefficients wrt the mole fractions.
|
||||
/*!
|
||||
* This routine calculates the the derivative of the activity coefficients
|
||||
* wrt to mole fraction with all other mole fractions held constant. This is
|
||||
* strictly not permitted. However, if the resulting matrix is multiplied by
|
||||
* a permissible deltaX vector then everything is ok.
|
||||
*
|
||||
* This is the natural way to handle concentration derivatives in this
|
||||
* routine.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dX_() const;
|
||||
|
||||
protected:
|
||||
// Pseudobinary type
|
||||
/*!
|
||||
* - `PBTYPE_PASSTHROUGH` - All species are passthrough species
|
||||
* - `PBTYPE_SINGLEANION` - there is only one anion in the mixture
|
||||
* - `PBTYPE_SINGLECATION` - there is only one cation in the mixture
|
||||
* - `PBTYPE_MULTICATIONANION` - Complex mixture
|
||||
*/
|
||||
int PBType_;
|
||||
|
||||
//! Number of pseudo binary species
|
||||
size_t numPBSpecies_;
|
||||
|
||||
mutable vector_fp PBMoleFractions_;
|
||||
|
||||
//! Vector of cation indices in the mixture
|
||||
std::vector<size_t> cationList_;
|
||||
|
||||
std::vector<size_t> anionList_;
|
||||
|
||||
std::vector<size_t> passThroughList_;
|
||||
size_t neutralPBindexStart;
|
||||
|
||||
mutable vector_fp moleFractionsTmp_;
|
||||
};
|
||||
|
||||
#define PBTYPE_PASSTHROUGH 0
|
||||
#define PBTYPE_SINGLEANION 1
|
||||
#define PBTYPE_SINGLECATION 2
|
||||
#define PBTYPE_MULTICATIONANION 3
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -72,20 +72,6 @@ public:
|
||||
virtual void modifySpecies(size_t index,
|
||||
shared_ptr<SpeciesThermoInterpType> spec);
|
||||
|
||||
//! 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).
|
||||
* @deprecated Use update_single() instead.
|
||||
* To be removed after Cantera 2.4.
|
||||
*/
|
||||
virtual void update_one(size_t k, doublereal T, doublereal* cp_R,
|
||||
doublereal* h_RT,
|
||||
doublereal* s_R) const;
|
||||
|
||||
//! Like update_one, but without applying offsets to the output pointers
|
||||
/*!
|
||||
* @param k species index
|
||||
|
||||
@@ -406,15 +406,6 @@ public:
|
||||
//! units = kg / kmol
|
||||
const vector_fp& molecularWeights() const;
|
||||
|
||||
//! @deprecated To be removed after Cantera 2.4
|
||||
//! @see SurfPhase::size
|
||||
virtual double size(size_t k) const {
|
||||
warn_deprecated("Phase::size", "Unused except for SurfPhase. "
|
||||
"To be removed from class Phase after Cantera 2.4. "
|
||||
"Cast object as SurfPhase to resolve this warning.");
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
/// @name Composition
|
||||
//@{
|
||||
|
||||
|
||||
@@ -1,624 +0,0 @@
|
||||
/**
|
||||
* @file PhaseCombo_Interaction.h
|
||||
* Header for intermediate ThermoPhase object for phases which
|
||||
* employ the Margules Gibbs free energy formulation and eliminates the ideal mixing term.
|
||||
* (see \ref thermoprops
|
||||
* and class \link Cantera::PhaseCombo_Interaction PhaseCombo_Interaction\endlink).
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_PHASECOMBO_INTERACTION_H
|
||||
#define CT_PHASECOMBO_INTERACTION_H
|
||||
|
||||
#include "GibbsExcessVPSSTP.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! PhaseCombo_Interaction is a derived class of GibbsExcessVPSSTP that employs
|
||||
//! the Margules approximation for the excess Gibbs free energy while
|
||||
//! eliminating the entropy of mixing term.
|
||||
/*!
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* PhaseCombo_Interaction derives from class GibbsExcessVPSSTP which is derived
|
||||
* from VPStandardStateTP, and overloads the virtual methods defined there with
|
||||
* ones that use expressions appropriate for the Margules Excess Gibbs free
|
||||
* energy approximation. The reader should refer to the MargulesVPSSTP class for
|
||||
* information on that class. This class in addition adds a term to the activity
|
||||
* coefficient that eliminates the ideal solution mixing term within the
|
||||
* chemical potential. This is a very radical thing to do, but it is supported
|
||||
* by experimental evidence under some conditions.
|
||||
*
|
||||
* The independent unknowns are pressure, temperature, and mass fraction.
|
||||
*
|
||||
* This class is introduced to represent specific conditions observed in thermal
|
||||
* batteries. HOwever, it may be physically motivated to represent conditions
|
||||
* where there may be a mixture of compounds that are not "mixed" at the
|
||||
* molecular level. Therefore, there is no mixing term.
|
||||
*
|
||||
* The lack of a mixing term has profound effects. First, the mole fraction of a
|
||||
* species can now be identically zero due to thermodynamic considerations. The
|
||||
* phase behaves more like a series of phases. That's why we named it
|
||||
* PhaseCombo.
|
||||
*
|
||||
* ## Specification of Species Standard State Properties
|
||||
*
|
||||
* All species are defined to have standard states that depend upon both the
|
||||
* temperature and the pressure. The Margules approximation assumes symmetric
|
||||
* standard states, where all of the standard state assume that the species are
|
||||
* in pure component states at the temperature and pressure of the solution. I
|
||||
* don't think it prevents, however, some species from being dilute in the
|
||||
* solution.
|
||||
*
|
||||
* ## Specification of Solution Thermodynamic Properties
|
||||
*
|
||||
* The molar excess Gibbs free energy is given by the following formula which is
|
||||
* a sum over interactions *i*. Each of the interactions are binary interactions
|
||||
* involving two of the species in the phase, denoted, *Ai* and *Bi*. This is
|
||||
* the generalization of the Margules formulation for a phase that has more than
|
||||
* 2 species. The second term in the excess Gibbs free energy is a negation of
|
||||
* the ideal solution's mixing term.
|
||||
*
|
||||
* \f[
|
||||
* G^E = \sum_i \left( H_{Ei} - T S_{Ei} \right) - \sum_i \left( n_i R T \ln{X_i} \right)
|
||||
* \f]
|
||||
* \f[
|
||||
* H^E_i = n X_{Ai} X_{Bi} \left( h_{o,i} + h_{1,i} X_{Bi} \right)
|
||||
* \f]
|
||||
* \f[
|
||||
* S^E_i = n X_{Ai} X_{Bi} \left( s_{o,i} + s_{1,i} X_{Bi} \right)
|
||||
* \f]
|
||||
*
|
||||
* where n is the total moles in the solution. The activity of a species defined
|
||||
* in the phase is given by an excess Gibbs free energy formulation.
|
||||
*
|
||||
* \f[
|
||||
* a_k = \gamma_k X_k
|
||||
* \f]
|
||||
*
|
||||
* where
|
||||
*
|
||||
* \f[
|
||||
* R T \ln( \gamma_k )= \frac{d(n G^E)}{d(n_k)}\Bigg|_{n_i}
|
||||
* \f]
|
||||
*
|
||||
* Taking the derivatives results in the following expression
|
||||
*
|
||||
* \f[
|
||||
* R T \ln( \gamma_k )= \sum_i \left( \left( \delta_{Ai,k} X_{Bi} + \delta_{Bi,k} X_{Ai} - X_{Ai} X_{Bi} \right)
|
||||
* \left( g^E_{o,i} + g^E_{1,i} X_{Bi} \right) +
|
||||
* \left( \delta_{Bi,k} - X_{Bi} \right) X_{Ai} X_{Bi} g^E_{1,i} \right) - RT \ln{X_k}
|
||||
* \f]
|
||||
*
|
||||
* where \f$ g^E_{o,i} = h_{o,i} - T s_{o,i} \f$ and
|
||||
* \f$ g^E_{1,i} = h_{1,i} - T s_{1,i} \f$ and where \f$ X_k \f$ is the mole
|
||||
* fraction of species *k*.
|
||||
*
|
||||
* This object inherits from the class VPStandardStateTP. Therefore, the
|
||||
* specification and calculation of all standard state and reference state
|
||||
* values are handled at that level. Various functional forms for the standard
|
||||
* state are permissible. The chemical potential for species *k* is equal to
|
||||
*
|
||||
* \f[
|
||||
* \mu_k(T,P) = \mu^o_k(T, P) + R T \ln(\gamma_k X_k)
|
||||
* \f]
|
||||
*
|
||||
* The partial molar entropy for species *k* is given by the following relation,
|
||||
*
|
||||
* \f[
|
||||
* \tilde{s}_k(T,P) = s^o_k(T,P) - R \ln( \gamma_k X_k )
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar enthalpy for species *k* is given by
|
||||
*
|
||||
* \f[
|
||||
* \tilde{h}_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar volume for species *k* is
|
||||
*
|
||||
* \f[
|
||||
* \tilde V_k(T,P) = V^o_k(T,P) + R T \frac{d \ln(\gamma_k) }{dP}
|
||||
* \f]
|
||||
*
|
||||
* The partial molar Heat Capacity for species *k* is
|
||||
*
|
||||
* \f[
|
||||
* \tilde{C}_{p,k}(T,P) = C^o_{p,k}(T,P) - 2 R T \frac{d \ln( \gamma_k )}{dT}
|
||||
* - R T^2 \frac{d^2 \ln(\gamma_k) }{{dT}^2}
|
||||
* \f]
|
||||
*
|
||||
* ## %Application within Kinetics Managers
|
||||
*
|
||||
* \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 *k* is independent of *k* 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.
|
||||
*
|
||||
* ## Instantiation of the Class
|
||||
*
|
||||
* The constructor for this phase is located in the default ThermoFactory for
|
||||
* %Cantera. A new PhaseCombo_Interaction object may be created by the following
|
||||
* code snippet:
|
||||
*
|
||||
* @code
|
||||
* XML_Node *xc = get_XML_File("LiFeS_X_combo.xml");
|
||||
* XML_Node * const xs = xc->findNameID("phase", "LiFeS_X");
|
||||
* ThermoPhase *l_tp = newPhase(*xs);
|
||||
* PhaseCombo_Interaction *LiFeS_X_solid = dynamic_cast <PhaseCombo_Interaction *>(l_tp);
|
||||
* @endcode
|
||||
*
|
||||
* or by the following code
|
||||
*
|
||||
* @code
|
||||
* std::string id = "LiFeS_X";
|
||||
* Cantera::ThermoPhase *LiFeS_X_Phase = Cantera::newPhase("LiFeS_X_combo.xml", id);
|
||||
* PhaseCombo_Interaction *LiFeS_X_solid = dynamic_cast <PhaseCombo_Interaction *>(l_tp);
|
||||
* @endcode
|
||||
*
|
||||
* or by the following constructor:
|
||||
*
|
||||
* @code
|
||||
* XML_Node *xc = get_XML_File("LiFeS_X_combo.xml");
|
||||
* XML_Node * const xs = xc->findNameID("phase", "LiFeS_X");
|
||||
* PhaseCombo_Interaction *LiFeS_X_solid = new PhaseCombo_Interaction(*xs);
|
||||
* @endcode
|
||||
*
|
||||
* ## XML Example
|
||||
*
|
||||
* An example of an XML Element named phase setting up a PhaseCombo_Interaction
|
||||
* object named LiFeS_X is given below.
|
||||
*
|
||||
* @code
|
||||
* <phase dim="3" id="LiFeS_X">
|
||||
* <elementArray datasrc="elements.xml">
|
||||
* Li Fe S
|
||||
* </elementArray>
|
||||
* <speciesArray datasrc="#species_LiFeS">
|
||||
* LiTFe1S2(S) Li2Fe1S2(S)
|
||||
* </speciesArray>
|
||||
* <thermo model="PhaseCombo_Interaction">
|
||||
* <activityCoefficients model="Margules" TempModel="constant">
|
||||
* <binaryNeutralSpeciesParameters speciesA="LiTFe1S2(S)" speciesB="Li2Fe1S2(S)">
|
||||
* <excessEnthalpy model="poly_Xb" terms="2" units="kJ/mol">
|
||||
* 84.67069219, -269.1959421
|
||||
* </excessEnthalpy>
|
||||
* <excessEntropy model="poly_Xb" terms="2" units="J/mol/K">
|
||||
* 100.7511565, -361.4222659
|
||||
* </excessEntropy>
|
||||
* <excessVolume_Enthalpy model="poly_Xb" terms="2" units="ml/mol">
|
||||
* 0, 0
|
||||
* </excessVolume_Enthalpy>
|
||||
* <excessVolume_Entropy model="poly_Xb" terms="2" units="ml/mol/K">
|
||||
* 0, 0
|
||||
* </excessVolume_Entropy>
|
||||
* </binaryNeutralSpeciesParameters>
|
||||
* </activityCoefficients>
|
||||
* </thermo>
|
||||
* <transport model="none"/>
|
||||
* <kinetics model="none"/>
|
||||
* </phase>
|
||||
* @endcode
|
||||
*
|
||||
* The model attribute "PhaseCombo_Interaction" of the thermo XML element
|
||||
* identifies the phase as being of the type handled by the
|
||||
* PhaseCombo_Interaction object.
|
||||
*
|
||||
* @ingroup thermoprops
|
||||
*/
|
||||
class PhaseCombo_Interaction : public GibbsExcessVPSSTP
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
PhaseCombo_Interaction();
|
||||
|
||||
//! Construct and initialize a PhaseCombo_Interaction ThermoPhase object
|
||||
//! directly from an XML input file
|
||||
/*!
|
||||
* @param inputFile Name of the input file containing the phase XML data
|
||||
* to set up the object
|
||||
* @param id ID of the phase in the input file. Defaults to the
|
||||
* empty string.
|
||||
*/
|
||||
PhaseCombo_Interaction(const std::string& inputFile, const std::string& id = "");
|
||||
|
||||
//! Construct and initialize a PhaseCombo_Interaction ThermoPhase object
|
||||
//! directly from an XML database
|
||||
/*!
|
||||
* @param phaseRef XML phase node containing the description of the phase
|
||||
* @param id id attribute containing the name of the phase.
|
||||
* (default is the empty string)
|
||||
*/
|
||||
PhaseCombo_Interaction(XML_Node& phaseRef, const std::string& id = "");
|
||||
|
||||
//! @name Utilities
|
||||
//! @{
|
||||
|
||||
virtual std::string type() const {
|
||||
return "PhaseCombo_Interaction";
|
||||
}
|
||||
|
||||
//! @}
|
||||
//! @name Molar Thermodynamic Properties
|
||||
//! @{
|
||||
|
||||
virtual doublereal enthalpy_mole() const;
|
||||
virtual doublereal entropy_mole() const;
|
||||
virtual doublereal cp_mole() const;
|
||||
virtual doublereal cv_mole() const;
|
||||
|
||||
/**
|
||||
* @}
|
||||
* @name Activities, Standard States, and Activity Concentrations
|
||||
*
|
||||
* The activity \f$a_k\f$ of a species in solution is related to the
|
||||
* chemical potential by \f[ \mu_k = \mu_k^0(T) + \hat R T \log a_k. \f] The
|
||||
* quantity \f$\mu_k^0(T,P)\f$ is the chemical potential at unit activity,
|
||||
* which depends only on temperature and pressure.
|
||||
* @{
|
||||
*/
|
||||
|
||||
virtual void getActivityCoefficients(doublereal* ac) const;
|
||||
|
||||
//@}
|
||||
/// @name Partial Molar Properties of the Solution
|
||||
//@{
|
||||
|
||||
virtual void getChemPotentials(doublereal* mu) const;
|
||||
|
||||
//! Returns an array of partial molar enthalpies for the species in the
|
||||
//! mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the molality-based
|
||||
* activity coefficient wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* \bar h_k(T,P) = h^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* \f]
|
||||
*
|
||||
* @param hbar Vector of returned partial molar enthalpies
|
||||
* (length m_kk, units = J/kmol)
|
||||
*/
|
||||
virtual void getPartialMolarEnthalpies(doublereal* hbar) const;
|
||||
|
||||
//! Returns an array of partial molar entropies for the species in the
|
||||
//! mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the activity coefficient
|
||||
* wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* - R \ln( \gamma_k X_k)
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* \f]
|
||||
*
|
||||
* @param sbar Vector of returned partial molar entropies
|
||||
* (length m_kk, units = J/kmol/K)
|
||||
*/
|
||||
virtual void getPartialMolarEntropies(doublereal* sbar) const;
|
||||
|
||||
//! Returns an array of partial molar entropies for the species in the
|
||||
//! mixture.
|
||||
/*!
|
||||
* Units (J/kmol)
|
||||
*
|
||||
* For this phase, the partial molar enthalpies are equal to the standard
|
||||
* state enthalpies modified by the derivative of the activity coefficient
|
||||
* wrt temperature
|
||||
*
|
||||
* \f[
|
||||
* ???????????????
|
||||
* \bar s_k(T,P) = s^o_k(T,P) - R T^2 \frac{d \ln(\gamma_k)}{dT}
|
||||
* - R \ln( \gamma_k X_k)
|
||||
* - R T \frac{d \ln(\gamma_k) }{dT}
|
||||
* ???????????????
|
||||
* \f]
|
||||
*
|
||||
* @param cpbar Vector of returned partial molar heat capacities
|
||||
* (length m_kk, units = J/kmol/K)
|
||||
*/
|
||||
virtual void getPartialMolarCp(doublereal* cpbar) const;
|
||||
|
||||
//! Return an array of partial molar volumes for the species in the mixture.
|
||||
//! Units: m^3/kmol.
|
||||
/*!
|
||||
* Frequently, for this class of thermodynamics representations, the excess
|
||||
* Volume due to mixing is zero. Here, we set it as a default. It may be
|
||||
* overridden in derived classes.
|
||||
*
|
||||
* @param vbar Output vector of species partial molar volumes.
|
||||
* Length = m_kk. units are m^3/kmol.
|
||||
*/
|
||||
virtual void getPartialMolarVolumes(doublereal* vbar) const;
|
||||
|
||||
//! Get the array of temperature second derivatives of the log activity
|
||||
//! coefficients
|
||||
/*!
|
||||
* units = 1/Kelvin
|
||||
*
|
||||
* @param d2lnActCoeffdT2 Output vector of temperature 2nd derivatives of
|
||||
* the log Activity Coefficients. length = m_kk
|
||||
*/
|
||||
virtual void getd2lnActCoeffdT2(doublereal* d2lnActCoeffdT2) const;
|
||||
|
||||
virtual void getdlnActCoeffdT(doublereal* dlnActCoeffdT) const;
|
||||
|
||||
/// @}
|
||||
/// @name Initialization
|
||||
/// The following methods are used in the process of constructing
|
||||
/// the phase and setting its parameters from a specification in an
|
||||
/// input file. They are not normally used in application programs.
|
||||
/// To see how they are used, see importPhase().
|
||||
/// @{
|
||||
|
||||
virtual void initThermo();
|
||||
virtual void initThermoXML(XML_Node& phaseNode, const std::string& id);
|
||||
|
||||
//! @}
|
||||
//! @name Derivatives of Thermodynamic Variables needed for Applications
|
||||
//! @{
|
||||
|
||||
virtual void getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds, doublereal* dlnActCoeffds) const;
|
||||
virtual void getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const;
|
||||
virtual void getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const;
|
||||
virtual void getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN);
|
||||
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! Process an XML node called "binaryNeutralSpeciesParameters"
|
||||
/*!
|
||||
* This node contains all of the parameters necessary to describe the
|
||||
* Margules model for a particular binary interaction. This function reads
|
||||
* the XML file and writes the coefficients it finds to an internal data
|
||||
* structures.
|
||||
*
|
||||
* @param xmlBinarySpecies Reference to the XML_Node named
|
||||
* "binaryNeutralSpeciesParameters" containing the binary interaction
|
||||
*/
|
||||
void readXMLBinarySpecies(XML_Node& xmlBinarySpecies);
|
||||
|
||||
//! Resize internal arrays within the object that depend upon the number of
|
||||
//! binary Margules interaction terms
|
||||
/*!
|
||||
* @param num Number of binary Margules interaction terms
|
||||
*/
|
||||
void resizeNumInteractions(const size_t num);
|
||||
|
||||
//! Initialize lengths of local variables after all species have been
|
||||
//! identified.
|
||||
void initLengths();
|
||||
|
||||
//! Update the activity coefficients
|
||||
/*!
|
||||
* This function will be called to update the internally stored natural
|
||||
* logarithm of the activity coefficients
|
||||
*/
|
||||
void s_update_lnActCoeff() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt T
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt temperature.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dT() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt
|
||||
//! log(mole fraction)
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt logarithm of
|
||||
* the mole fractions.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnX_diag() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt
|
||||
//! log(moles) - diagonal only
|
||||
/*!
|
||||
* This function will be called to update the internally stored diagonal
|
||||
* entries for the derivative of the natural logarithm of the activity
|
||||
* coefficients wrt logarithm of the moles.
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnN_diag() const;
|
||||
|
||||
//! Update the derivative of the log of the activity coefficients wrt
|
||||
//! log(moles_m)
|
||||
/*!
|
||||
* This function will be called to update the internally stored derivative
|
||||
* of the natural logarithm of the activity coefficients wrt logarithm of
|
||||
* the mole number of species
|
||||
*/
|
||||
void s_update_dlnActCoeff_dlnN() const;
|
||||
|
||||
protected:
|
||||
//! number of binary interaction expressions
|
||||
size_t numBinaryInteractions_;
|
||||
|
||||
//! Enthalpy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_b_ij;
|
||||
|
||||
//! Enthalpy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_c_ij;
|
||||
|
||||
//! Enthalpy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_HE_d_ij;
|
||||
|
||||
//! Entropy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_b_ij;
|
||||
|
||||
//! Entropy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_c_ij;
|
||||
|
||||
//! Entropy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_SE_d_ij;
|
||||
|
||||
//! Enthalpy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_b_ij;
|
||||
|
||||
//! Enthalpy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_c_ij;
|
||||
|
||||
//! Enthalpy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VHE_d_ij;
|
||||
|
||||
//! Entropy term for the binary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_b_ij;
|
||||
|
||||
//! Entropy term for the ternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_c_ij;
|
||||
|
||||
//! Entropy term for the quaternary mole fraction interaction of the excess
|
||||
//! Gibbs free energy expression
|
||||
mutable vector_fp m_VSE_d_ij;
|
||||
|
||||
//! vector of species indices representing species A in the interaction
|
||||
/*!
|
||||
* Each Margules excess Gibbs free energy term involves two species, A and
|
||||
* B. This vector identifies species A.
|
||||
*/
|
||||
std::vector<size_t> m_pSpecies_A_ij;
|
||||
|
||||
//! vector of species indices representing species B in the interaction
|
||||
/*!
|
||||
* Each Margules excess Gibbs free energy term involves two species, A and
|
||||
* B. This vector identifies species B.
|
||||
*/
|
||||
std::vector<size_t> m_pSpecies_B_ij;
|
||||
|
||||
//! form of the Margules interaction expression
|
||||
/*!
|
||||
* Currently there is only one form.
|
||||
*/
|
||||
int formMargules_;
|
||||
|
||||
//! form of the temperature dependence of the Margules interaction expression
|
||||
/*!
|
||||
* Currently there is only one form -> constant wrt temperature.
|
||||
*/
|
||||
int formTempModel_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1228,31 +1228,6 @@ public:
|
||||
throw NotImplementedError("ThermoPhase::setToEquilState");
|
||||
}
|
||||
|
||||
//! Stores the element potentials in the ThermoPhase object
|
||||
/*!
|
||||
* Called by the ChemEquil equilibrium solver to transfer the element
|
||||
* potentials to this object after every successful equilibration routine.
|
||||
* The element potentials are stored in their dimensionless forms,
|
||||
* calculated by dividing by RT.
|
||||
*
|
||||
* @param lambda Input vector containing the element potentials.
|
||||
* Length = nElements. Units are Joules/kmol.
|
||||
*/
|
||||
void setElementPotentials(const vector_fp& lambda);
|
||||
|
||||
//! Returns the element potentials stored in the ThermoPhase object
|
||||
/*!
|
||||
* Returns the stored element potentials. The element potentials are
|
||||
* retrieved from their stored dimensionless forms by multiplying by RT.
|
||||
* @param lambda Output vector containing the element potentials.
|
||||
* Length = nElements. Units are Joules/kmol.
|
||||
* @return bool indicating whether there are any valid stored element
|
||||
* potentials. The calling routine should check this
|
||||
* bool. In the case that there aren't any, lambda is not
|
||||
* touched.
|
||||
*/
|
||||
bool getElementPotentials(doublereal* lambda) const;
|
||||
|
||||
//! Indicates whether this phase type can be used with class MultiPhase for
|
||||
//! equilibrium calculations. Returns `false` for special phase types which
|
||||
//! already represent multi-phase mixtures, namely PureFluidPhase.
|
||||
@@ -1617,15 +1592,6 @@ protected:
|
||||
//! Stored value of the electric potential for this phase. Units are Volts.
|
||||
doublereal m_phi;
|
||||
|
||||
//! Vector of element potentials. Length equal to number of elements.
|
||||
//! @deprecated To be removed after Cantera 2.4.
|
||||
vector_fp m_lambdaRRT;
|
||||
|
||||
//! Boolean indicating whether there is a valid set of saved element
|
||||
//! potentials for this phase
|
||||
//! @deprecated To be removed after Cantera 2.4.
|
||||
bool m_hasElementPotentials;
|
||||
|
||||
//! Boolean indicating whether a charge neutrality condition is a necessity
|
||||
/*!
|
||||
* Note, the charge neutrality condition is not a necessity for ideal gas
|
||||
|
||||
@@ -59,10 +59,6 @@
|
||||
//! This is implemented in the class Nasa9PolyMultiTempRegion in Nasa9Poly1MultiTempRegion
|
||||
#define NASA9MULTITEMP 513
|
||||
|
||||
//! Surface Adsorbate Model for a species on a surface.
|
||||
//! This is implemented in the class Adsorbate.
|
||||
#define ADSORBATE 1024
|
||||
|
||||
//! Type of reference state thermo which is a wrapper around a pressure dependent
|
||||
//! standard state object. Basically, the reference state pressure isn't special.
|
||||
//! A general object is called with the pressure set at the reference state.
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/**
|
||||
* @file LTPspecies.h
|
||||
* Header file defining class LTPspecies and its child classes
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_LTPSPECIES_H
|
||||
#define CT_LTPSPECIES_H
|
||||
|
||||
#include "TransportBase.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Enumeration of the types of transport properties that can be
|
||||
//! handled by the variables in the various Transport classes.
|
||||
/*!
|
||||
* Not all of these are handled by each class and each class
|
||||
* should handle exceptions where the transport property is not handled.
|
||||
*
|
||||
* Transport properties currently on the list
|
||||
*
|
||||
* 0 - viscosity
|
||||
* 1 - Ionic conductivity
|
||||
* 2 - Mobility Ratio
|
||||
* 3 - Self Diffusion coefficient
|
||||
* 4 - Thermal conductivity
|
||||
* 5 - species diffusivity
|
||||
* 6 - hydrodynamic radius
|
||||
* 7 - electrical conductivity
|
||||
*/
|
||||
enum TransportPropertyType {
|
||||
TP_UNKNOWN = -1,
|
||||
TP_VISCOSITY = 0,
|
||||
TP_IONCONDUCTIVITY,
|
||||
TP_MOBILITYRATIO,
|
||||
TP_SELFDIFFUSION,
|
||||
TP_THERMALCOND,
|
||||
TP_DIFFUSIVITY,
|
||||
TP_HYDRORADIUS,
|
||||
TP_ELECTCOND,
|
||||
TP_DEFECTCONC,
|
||||
TP_DEFECTDIFF
|
||||
};
|
||||
|
||||
//! Temperature dependence type for standard state species properties
|
||||
/*!
|
||||
* Types of temperature dependencies:
|
||||
* 0 - Independent of temperature
|
||||
* 1 - extended arrhenius form
|
||||
* 2 - polynomial in temperature form
|
||||
* 3 - exponential temperature polynomial
|
||||
*/
|
||||
enum LTPTemperatureDependenceType {
|
||||
LTP_TD_NOTSET=-1,
|
||||
LTP_TD_CONSTANT,
|
||||
LTP_TD_ARRHENIUS,
|
||||
LTP_TD_POLY,
|
||||
LTP_TD_EXPT
|
||||
};
|
||||
|
||||
//! Class LTPspecies holds transport parameterizations for a specific liquid-
|
||||
//! phase species.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* Subclasses handle different means of specifying transport properties like
|
||||
* constant, %Arrhenius or polynomial temperature fits. In its current state,
|
||||
* it is primarily suitable for specifying temperature dependence, but the
|
||||
* adjustCoeffsForComposition() method can be implemented to adjust for the
|
||||
* composition dependence.
|
||||
*
|
||||
* Mixing rules for computing mixture transport properties are handled
|
||||
* separately in the LiquidTranInteraction subclasses.
|
||||
*/
|
||||
class LTPspecies
|
||||
{
|
||||
public:
|
||||
LTPspecies();
|
||||
virtual ~LTPspecies() {}
|
||||
|
||||
//! Duplication routine
|
||||
/*!
|
||||
* (virtual from LTPspecies)
|
||||
*
|
||||
* @returns a copy of this routine as a pointer to LTPspecies
|
||||
*/
|
||||
virtual LTPspecies* duplMyselfAsLTPspecies() const;
|
||||
|
||||
//! Set the ThermoPhase object, which is used to find the temperature
|
||||
void setThermo(thermo_t* thermo) {
|
||||
m_thermo = thermo;
|
||||
}
|
||||
|
||||
//! Set the species name
|
||||
void setName(const std::string& name) {
|
||||
m_speciesName = name;
|
||||
}
|
||||
|
||||
//! TransportPropertyType containing the property id that this object is
|
||||
//! creating a parameterization for (e.g., viscosity)
|
||||
void setTransportPropertyType(TransportPropertyType tp_ind) {
|
||||
m_property = tp_ind;
|
||||
}
|
||||
|
||||
//! Set up the species transport property from the XML node, `<propNode>`
|
||||
//! that is a child of the `<transport>` node in the species block and
|
||||
//! specifies a type of transport property (like viscosity)
|
||||
virtual void setupFromXML(const XML_Node& propNode) {}
|
||||
|
||||
//! Returns the vector of standard state species transport property
|
||||
/*!
|
||||
* The standard state species transport property is returned. Any
|
||||
* temperature and composition dependence will be adjusted internally
|
||||
* according to the information provided by the subclass object.
|
||||
*
|
||||
* @returns a single double containing the property evaluation at the
|
||||
* current ThermoPhase temperature.
|
||||
*/
|
||||
virtual doublereal getSpeciesTransProp();
|
||||
|
||||
//! Check to see if the property evaluation will be positive
|
||||
virtual bool checkPositive() const;
|
||||
|
||||
//! Return the weight mixture
|
||||
doublereal getMixWeight() const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
//! Internal model to adjust species-specific properties for the composition.
|
||||
/*!
|
||||
* Currently just a place holder, but this method could take the composition
|
||||
* from the thermo object and adjust coefficients according to some yet
|
||||
* unspecified model.
|
||||
*/
|
||||
virtual void adjustCoeffsForComposition();
|
||||
|
||||
protected:
|
||||
//! Species Name for the property that is being described
|
||||
std::string m_speciesName;
|
||||
|
||||
//! Model type for the temperature dependence
|
||||
LTPTemperatureDependenceType m_model;
|
||||
|
||||
//! enum indicating which property this is (i.e viscosity)
|
||||
TransportPropertyType m_property;
|
||||
|
||||
//! Model temperature-dependence ceofficients
|
||||
vector_fp m_coeffs;
|
||||
|
||||
//! Pointer to a const thermo object to get current temperature
|
||||
const thermo_t* m_thermo;
|
||||
|
||||
//! Weighting used for mixing.
|
||||
/*!
|
||||
* This weighting can be employed to allow salt transport properties to be
|
||||
* represented by specific ions. For example, to have Li+ and Ca+ represent
|
||||
* the mixing transport properties of LiCl and CaCl2, the weightings for Li+
|
||||
* would be 2.0, for K+ would be 3.0 and for Cl- would be 0.0. The transport
|
||||
* properties for Li+ would be those for LiCl and the transport properties
|
||||
* for Ca+ would be those for CaCl2. The transport properties for Cl- should
|
||||
* be something innoccuous like 1.0--note that 0.0 is not innocuous if there
|
||||
* are logarithms involved.
|
||||
*/
|
||||
doublereal m_mixWeight;
|
||||
};
|
||||
|
||||
//! Class LTPspecies_Const holds transport parameters for a specific liquid-
|
||||
//! phase species (LTPspecies) when the transport property is just a constant
|
||||
//! value.
|
||||
/*!
|
||||
* As an example of the input required for LTPspecies_Const consider the
|
||||
* following XML fragment
|
||||
*
|
||||
* \verbatim
|
||||
* <species>
|
||||
* <!-- thermodynamic properties -->
|
||||
* <transport>
|
||||
* <hydrodynamicRadius model="Constant" units="A">
|
||||
* 1.000
|
||||
* </hydrodynamicRadius>
|
||||
* <!-- other transport properties -->
|
||||
* </transport>
|
||||
* </species>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTPspecies_Const : public LTPspecies
|
||||
{
|
||||
public:
|
||||
LTPspecies_Const();
|
||||
|
||||
virtual LTPspecies* duplMyselfAsLTPspecies() const;
|
||||
virtual void setupFromXML(const XML_Node& propNode);
|
||||
|
||||
// Set the (constant) property value
|
||||
void setCoeff(double C);
|
||||
|
||||
doublereal getSpeciesTransProp();
|
||||
};
|
||||
|
||||
//! Class LTPspecies_Arrhenius holds transport parameters for a specific liquid-
|
||||
//! phase species (LTPspecies) when the transport property is expressed in
|
||||
//! Arrhenius form.
|
||||
/*!
|
||||
* Used for standard state species properties with equations of the form
|
||||
* \f[
|
||||
* x = A T^b \exp( - E / RT )
|
||||
* \f]
|
||||
* where A, b, and E are passed in the XML input file.
|
||||
*
|
||||
* As an example of the input required for LTPspecies_Arrhenius consider the
|
||||
* following XML fragment
|
||||
*
|
||||
* \verbatim
|
||||
* <species>
|
||||
* <!-- thermodynamic properties -->
|
||||
* <transport>
|
||||
* <viscosity model="Arrhenius">
|
||||
* <!-- Janz, JPCRD, 17, supplement 2, 1988 -->
|
||||
* <A>6.578e-5</A>
|
||||
* <b>0.0</b>
|
||||
* <E units="J/kmol">23788.e3</E>
|
||||
* </viscosity>
|
||||
* <!-- other transport properties -->
|
||||
* </transport>
|
||||
* </species>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTPspecies_Arrhenius : public LTPspecies
|
||||
{
|
||||
public:
|
||||
LTPspecies_Arrhenius();
|
||||
virtual LTPspecies* duplMyselfAsLTPspecies() const;
|
||||
virtual void setupFromXML(const XML_Node& propNode);
|
||||
|
||||
//! Return the standard state species value for this transport property
|
||||
//! evaluated from the Arrhenius expression
|
||||
/*!
|
||||
* In general the Arrhenius expression is
|
||||
*
|
||||
* \f[
|
||||
* \mu = A T^n \exp( - E / R T ).
|
||||
* \f]
|
||||
*
|
||||
* Note that for viscosity, the convention is such that a positive
|
||||
* activation energy corresponds to the typical case of a positive
|
||||
* argument to the exponential so that the Arrhenius expression is
|
||||
*
|
||||
* \f[
|
||||
* \mu = A T^n \exp( + E / R T ).
|
||||
* \f]
|
||||
*
|
||||
* Any temperature and composition dependence will be adjusted internally
|
||||
* according to the information provided.
|
||||
*/
|
||||
doublereal getSpeciesTransProp();
|
||||
|
||||
// Set the coefficients in the Arrhenius expression
|
||||
void setCoeffs(double A, double n, double Tact);
|
||||
|
||||
protected:
|
||||
//! temperature from thermo object
|
||||
doublereal m_temp;
|
||||
|
||||
//! logarithm of current temperature
|
||||
doublereal m_logt;
|
||||
|
||||
//! most recent evaluation of transport property
|
||||
doublereal m_prop;
|
||||
|
||||
//! logarithm of most recent evaluation of transport property
|
||||
doublereal m_logProp;
|
||||
};
|
||||
|
||||
//! Class LTPspecies_Poly holds transport parameters for a specific liquid-phase
|
||||
//! species (LTPspecies) when the transport property is expressed as a
|
||||
//! polynomial in temperature.
|
||||
/*!
|
||||
* Used for standard state species properties with equations of the form
|
||||
* \f[
|
||||
* x = f[0] + f[1] T + ... + f[N] T^N
|
||||
* \f]
|
||||
* where f[i] are elements of the float array passed in.
|
||||
*
|
||||
* As an example of the input required for LTPspecies_Poly consider the
|
||||
* following XML fragment
|
||||
*
|
||||
* \verbatim
|
||||
* <species>
|
||||
* <!-- thermodynamic properties -->
|
||||
* <transport>
|
||||
* <thermalConductivity model="coeffs">
|
||||
* <floatArray size="2"> 0.6, -15.0e-5 </floatArray>
|
||||
* </thermalConductivity>
|
||||
* <!-- other transport properties -->
|
||||
* </transport>
|
||||
* </species>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTPspecies_Poly : public LTPspecies
|
||||
{
|
||||
public:
|
||||
LTPspecies_Poly();
|
||||
|
||||
virtual LTPspecies* duplMyselfAsLTPspecies() const;
|
||||
virtual void setupFromXML(const XML_Node& propNode);
|
||||
doublereal getSpeciesTransProp();
|
||||
|
||||
// Set the coefficients in the polynomial expression
|
||||
void setCoeffs(size_t N, const double* coeffs);
|
||||
|
||||
protected:
|
||||
//! temperature from thermo object
|
||||
doublereal m_temp;
|
||||
|
||||
//! most recent evaluation of transport property
|
||||
doublereal m_prop;
|
||||
};
|
||||
|
||||
//! Class LTPspecies_ExpT holds transport parameters for a specific liquid-
|
||||
//! phase species (LTPspecies) when the transport property is expressed as an
|
||||
//! exponential in temperature.
|
||||
/*!
|
||||
* Used for standard state species properties with equations of the form
|
||||
*
|
||||
* \f[
|
||||
* x = f[0] \exp( f[1] T + ... + f[N] T^{N} )
|
||||
* \f]
|
||||
*
|
||||
* where f[i] are elements of the float array passed in.
|
||||
*
|
||||
* As an example of the input required for LTPspecies_ExpT consider the
|
||||
* following XML fragment
|
||||
*
|
||||
* \verbatim
|
||||
* <species>
|
||||
* <!-- thermodynamic properties -->
|
||||
* <transport>
|
||||
* <thermalConductivity model="expT">
|
||||
* <floatArray size="2"> 0.6, -15.0e-5 </floatArray>
|
||||
* </thermalConductivity>
|
||||
* <!-- other transport properties -->
|
||||
* </transport>
|
||||
* </species>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTPspecies_ExpT : public LTPspecies
|
||||
{
|
||||
public:
|
||||
LTPspecies_ExpT();
|
||||
|
||||
virtual LTPspecies* duplMyselfAsLTPspecies() const;
|
||||
virtual void setupFromXML(const XML_Node& propNode);
|
||||
|
||||
// Set the coefficients in the polynomial expression
|
||||
void setCoeffs(size_t N, const double* coeffs);
|
||||
|
||||
doublereal getSpeciesTransProp();
|
||||
|
||||
protected:
|
||||
//! temperature from thermo object
|
||||
doublereal m_temp;
|
||||
|
||||
//! most recent evaluation of the transport property
|
||||
doublereal m_prop;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,559 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTranInteraction.h
|
||||
* Header file defining the class LiquidTranInteraction and classes which
|
||||
* derive from LiquidTranInteraction.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_LIQUIDTRANINTERACTION_H
|
||||
#define CT_LIQUIDTRANINTERACTION_H
|
||||
|
||||
#include "TransportParams.h"
|
||||
#include "LiquidTransportData.h"
|
||||
#include "cantera/base/xml.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
//! Composition dependence type for liquid mixture transport properties
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* Types of temperature dependencies:
|
||||
* - 0 - Mixture calculations with this property are not allowed
|
||||
* - 1 - Use solvent (species 0) properties
|
||||
* - 2 - Properties weighted linearly by mole fractions
|
||||
* - 3 - Properties weighted linearly by mass fractions
|
||||
* - 4 - Properties weighted logarithmically by mole fractions (interaction energy weighting)
|
||||
* - 5 - Interactions given pairwise between each possible species (i.e. D_ij)
|
||||
*
|
||||
* \verbatim
|
||||
* <transport model="Liquid">
|
||||
* <viscosity>
|
||||
* <compositionDependence model="logMoleFractions">
|
||||
* <interaction>
|
||||
* <speciesA> LiCl(L) </speciesA>
|
||||
* <speciesB> KCl(L) </speciesB>
|
||||
* <Eij units="J/kmol"> -1.0 </Eij>
|
||||
* <Sij units="J/kmol/K"> 1.0E-1 </Sij>
|
||||
* -or- <Sij>
|
||||
* <floatArray units="J/kmol/K"> 1.0E-1, 0.001 0.01 </floatArray>
|
||||
* </Sij>
|
||||
* -same form for Hij,Aij,Bij-
|
||||
* </interaction>
|
||||
* </compositionDependence>
|
||||
* </viscosity>
|
||||
* <speciesDiffusivity>
|
||||
* <compositionDependence model="pairwiseInteraction">
|
||||
* <interaction>
|
||||
* <speciesA> Li+ </speciesA>
|
||||
* <speciesB> K+ </speciesB>
|
||||
* <Dij units="m2/s"> 1.5 </Dij>
|
||||
* </interaction>
|
||||
* <interaction>
|
||||
* <speciesA> K+ </speciesA>
|
||||
* <speciesB> Cl- </speciesB>
|
||||
* <Dij units="m2/s"> 1.0 </Dij>
|
||||
* </interaction>
|
||||
* <interaction>
|
||||
* <speciesA> Li+ </speciesA>
|
||||
* <speciesB> Cl- </speciesB>
|
||||
* <Dij units="m2/s"> 1.2 </Dij>
|
||||
* </interaction>
|
||||
* </compositionDependence>
|
||||
* </speciesDiffusivity>
|
||||
* <thermalConductivity>
|
||||
* <compositionDependence model="massFractions"/>
|
||||
* </thermalConductivity>
|
||||
* <hydrodynamicRadius>
|
||||
* <compositionDependence model="none"/>
|
||||
* </hydrodynamicRadius>
|
||||
* </transport>
|
||||
* \endverbatim
|
||||
*/
|
||||
enum LiquidTranMixingModel {
|
||||
LTI_MODEL_NOTSET=-1,
|
||||
LTI_MODEL_SOLVENT,
|
||||
LTI_MODEL_MOLEFRACS,
|
||||
LTI_MODEL_MASSFRACS,
|
||||
LTI_MODEL_LOG_MOLEFRACS,
|
||||
LTI_MODEL_PAIRWISE_INTERACTION,
|
||||
LTI_MODEL_STEFANMAXWELL_PPN,
|
||||
LTI_MODEL_STOKES_EINSTEIN,
|
||||
LTI_MODEL_MOLEFRACS_EXPT,
|
||||
LTI_MODEL_NONE,
|
||||
LTI_MODEL_MULTIPLE
|
||||
};
|
||||
|
||||
//! Base class to handle transport property evaluation in a mixture.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* In a mixture, the mixture transport properties will generally depend on the
|
||||
* contributions of each of the standard state species transport properties.
|
||||
* Many composition dependencies are possible. This class,
|
||||
* LiquidTranInteraction, is designed to be a base class for the implementation
|
||||
* of various models for the mixing of standard state species transport
|
||||
* properties.
|
||||
*
|
||||
* There are two very broad types of transport properties to consider. First,
|
||||
* there are properties for which a mixture value can be obtained through some
|
||||
* mixing rule. These are obtained using the method getMixTransProp().
|
||||
* Viscosity is typical of this. Second, there are properties for which a matrix
|
||||
* of properties may exist. This matrix of properties is obtained from the
|
||||
* method getMatrixTransProp(). Diffusion coefficients are of this type.
|
||||
* Subclasses should implement the appropriate one or both of these methods.
|
||||
*/
|
||||
class LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
//! Constructor
|
||||
/**
|
||||
* @param tp_ind Index indicating the transport property type (e.g., viscosity)
|
||||
*/
|
||||
LiquidTranInteraction(TransportPropertyType tp_ind = TP_UNKNOWN);
|
||||
|
||||
virtual ~LiquidTranInteraction();
|
||||
|
||||
//! initialize LiquidTranInteraction objects with thermo and XML node
|
||||
/**
|
||||
* @param compModelNode `<compositionDependence>` XML node
|
||||
* @param thermo Pointer to thermo object
|
||||
*/
|
||||
virtual void init(const XML_Node& compModelNode = XML_Node(),
|
||||
thermo_t* thermo = 0);
|
||||
|
||||
virtual void setParameters(LiquidTransportParams& trParam) {}
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
//! (Must be implemented in subclasses.)
|
||||
virtual doublereal getMixTransProp(doublereal* speciesValues, doublereal* weightSpecies = 0) {
|
||||
throw NotImplementedError("LiquidTranInteraction::getMixTransProp");
|
||||
}
|
||||
|
||||
virtual doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs) {
|
||||
throw NotImplementedError("LiquidTranInteraction::getMixTransProp");
|
||||
}
|
||||
|
||||
virtual void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0) {
|
||||
throw NotImplementedError("LiquidTranInteraction::getMixTransProp");
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Model for species interaction effects. Takes enum LiquidTranMixingModel
|
||||
LiquidTranMixingModel m_model;
|
||||
|
||||
//! enum indicating what property this is (i.e viscosity)
|
||||
TransportPropertyType m_property;
|
||||
|
||||
//! pointer to thermo object to get current temperature
|
||||
thermo_t* m_thermo;
|
||||
|
||||
//! Matrix of interaction coefficients for polynomial in molefraction*weight
|
||||
//! of speciesA (no temperature dependence, dimensionless)
|
||||
std::vector<DenseMatrix*> m_Aij;
|
||||
|
||||
//! Matrix of interaction coefficients for polynomial in molefraction*weight
|
||||
//! of speciesA (linear temperature dependence, units 1/K)
|
||||
std::vector<DenseMatrix*> m_Bij;
|
||||
|
||||
//! Matrix of interactions (in energy units, 1/RT temperature dependence)
|
||||
DenseMatrix m_Eij;
|
||||
|
||||
//! Matrix of interaction coefficients for polynomial in molefraction*weight
|
||||
//! of speciesA (in energy units, 1/RT temperature dependence)
|
||||
std::vector<DenseMatrix*> m_Hij;
|
||||
|
||||
//! Matrix of interaction coefficients for polynomial in molefraction*weight
|
||||
//! of speciesA (in entropy units, divided by R)
|
||||
std::vector<DenseMatrix*> m_Sij;
|
||||
|
||||
//! Matrix of interactions
|
||||
DenseMatrix m_Dij;
|
||||
};
|
||||
|
||||
class LTI_Solvent : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_Solvent(TransportPropertyType tp_ind = TP_UNKNOWN);
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point).
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them: Not implemented for this mixing rule.
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0);
|
||||
};
|
||||
|
||||
//! Simple mole fraction weighting of transport properties
|
||||
/**
|
||||
* This model weights the transport property by the mole fractions. The
|
||||
* overall formula for the mixture viscosity is
|
||||
*
|
||||
* \f[
|
||||
* \eta_{mix} = \sum_i X_i \eta_i + \sum_i \sum_j X_i X_j A_{i,j}
|
||||
* \f]
|
||||
*/
|
||||
class LTI_MoleFracs : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_MoleFracs(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_MOLEFRACS;
|
||||
}
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them: Not Implemented for this Mixing rule;
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0) {
|
||||
mat = (*m_Aij[0]);
|
||||
}
|
||||
};
|
||||
|
||||
//! Simple mass fraction weighting of transport properties
|
||||
/*!
|
||||
* This model weights the transport property by the mass fractions. The
|
||||
* overall formula for the mixture viscosity is
|
||||
*
|
||||
* \f[
|
||||
* \eta_{mix} = \sum_i Y_i \eta_i
|
||||
* + \sum_i \sum_j Y_i Y_j A_{i,j}
|
||||
* \f].
|
||||
*/
|
||||
class LTI_MassFracs : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_MassFracs(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_MASSFRACS;
|
||||
}
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them: Not implemented for this mixing rule.
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0) {
|
||||
mat = (*m_Aij[0]);
|
||||
}
|
||||
};
|
||||
|
||||
//! Mixing rule using logarithms of the mole fractions
|
||||
/**
|
||||
* This model is based on the idea that liquid molecules are generally
|
||||
* interacting with some energy and entropy of interaction. For transport
|
||||
* properties that depend on these energies of interaction, the mixture
|
||||
* transport property can be written in terms of its logarithm
|
||||
*
|
||||
* \f[ \ln \eta_{mix} = \sum_i X_i \ln \eta_i
|
||||
* + \sum_i \sum_j X_i X_j ( S_{i,j} + E_{i,j} / T )
|
||||
* \f].
|
||||
*
|
||||
* These additional interaction terms multiply the mixture property by
|
||||
* \f[ \exp( \sum_{i} \sum_{j} X_i X_j ( S_{i,j} + E_{i,j} / T ) ) \f]
|
||||
* so that the self-interaction terms \f$ S_{i,j} \f$ and
|
||||
* \f$ E_{i,j} \f$ should be zero.
|
||||
*
|
||||
* Note that the energies and entropies of interaction should be
|
||||
* a function of the composition themselves, but this is not yet
|
||||
* implemented. (We might follow the input of Margules model
|
||||
* thermodynamic data for the purpose of implementing this.)
|
||||
*
|
||||
* Sample input for this method is
|
||||
* \verbatim
|
||||
* <transport model="Liquid">
|
||||
* <viscosity>
|
||||
* <compositionDependence model="logMoleFractions">
|
||||
* <interaction speciesA="Li+" speciesB="K+">
|
||||
* <!--
|
||||
* interactions are from speciesA = LiCl(L)
|
||||
* and speciesB = KCl(L).
|
||||
* -->
|
||||
* <Eij units="J/kmol"> -1.0e3 </Eij>
|
||||
* <Sij units="J/kmol/K"> 80.0e-5 </Sij>
|
||||
* </interaction>
|
||||
* </compositionDependence>
|
||||
* </viscosity>
|
||||
* </transport>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTI_Log_MoleFracs : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_Log_MoleFracs(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_LOG_MOLEFRACS;
|
||||
}
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them: Not implemented for this mixing rule.
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0) {
|
||||
mat = m_Eij;
|
||||
}
|
||||
};
|
||||
|
||||
//! Transport properties that act like pairwise interactions
|
||||
//! as in binary diffusion coefficients.
|
||||
/**
|
||||
* This class holds parameters for transport properties expressed as a matrix
|
||||
* of pairwise interaction parameters. Input can be provided for constant or
|
||||
* Arrhenius forms of the separate parameters.
|
||||
*
|
||||
* Sample input for this method is
|
||||
* \verbatim
|
||||
* <transport model="Liquid">
|
||||
* <speciesDiffusivity>
|
||||
* <compositionDependence model="pairwiseInteraction">
|
||||
* <interaction speciesA="LiCl(L)" speciesB="KCl(L)">
|
||||
* <Dij units="m/s"> 1.0e-8 </Dij>
|
||||
* <Eij units="J/kmol"> 24.0e6 </Eij>
|
||||
* </interaction>
|
||||
* </compositionDependence>
|
||||
* </speciesDiffusivity>
|
||||
* </transport>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTI_Pairwise_Interaction : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_Pairwise_Interaction(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_PAIRWISE_INTERACTION;
|
||||
}
|
||||
|
||||
void setParameters(LiquidTransportParams& trParam);
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0);
|
||||
protected:
|
||||
|
||||
std::vector<LTPspecies*> m_diagonals;
|
||||
};
|
||||
|
||||
|
||||
//! Stefan Maxwell Diffusion Coefficients can be solved for given
|
||||
//! ion conductivity, mobility ratios, and self diffusion coeffs.
|
||||
//! This class is only valid for a common anion mixture of two
|
||||
//! salts with cations of equal charge. Hence the name _PPN.
|
||||
/**
|
||||
* This class requres you specify
|
||||
*
|
||||
* 1 - ion conductivity
|
||||
*
|
||||
* 2 - mobility ratio of the two cations (set all other ratios to zero)
|
||||
*
|
||||
* 3 - Self diffusion coefficients of the cations (set others to zero)
|
||||
* is used to calculate the "mutual diffusion coefficient". The
|
||||
* approximation needed to do so requires the cations have equal charge.
|
||||
*
|
||||
* We than calculate the Stefan Maxwell Diffusion Coefficients by
|
||||
* \f[
|
||||
* \frac{1}{D_{12}} = (1-\epsilon X_A)(1+\epsilon X_B)
|
||||
* \frac{\nu_- + \nu_+}{\nu_-\nu_+^2D}
|
||||
* + \frac{z_-z_+ F^2}{\kappa V R T}
|
||||
* \f]
|
||||
* \f[
|
||||
* \frac{1}{D_{12}} = -\epsilon X_B(1-\epsilon X_A)
|
||||
* \frac{\nu_- + \nu_+}{\nu_-^2\nu_+D}
|
||||
* - \frac{z_-z_+ F^2}{\kappa V R T}
|
||||
* \f]
|
||||
* \f[
|
||||
* \frac{1}{D_{23}} = \epsilon X_A(1+\epsilon X_B)
|
||||
* \frac{\nu_- + \nu_+}{\nu_-^2\nu_+D}
|
||||
* - \frac{z_-z_+ F^2}{\kappa V R T}
|
||||
* \f]
|
||||
* where F is Faraday's constant, RT is the gas constant times the
|
||||
* tempurature, and V is the molar volume (basis is moles of ions) that is
|
||||
* calculated by the ThermoPhase member. X_A and X_B are the mole fractions
|
||||
* of the salts composed of cation(1) and cation(2), respectively, that share
|
||||
* a common anion(3). \f$\nu_{+,-}\f$ are the stoichiometric coefficients in
|
||||
* the dissociation reaction of the salts to the ions with charges of
|
||||
* \f$z_{+,-}\f$. Assuming that the cations have equal charge, the "mutual
|
||||
* diffusion coefficient" is calculated using the cation self diffusion
|
||||
* coefficients.
|
||||
* \f[
|
||||
* \frac{1}{\nu_-\nu_+D} = \left(1+\frac{\partial \gamma_B}{\partial N_B}
|
||||
* \right)\frac{X_A}{D_2^*}+\left(1+\frac{\partial \gamma_A}{\partial N_A}
|
||||
* \right)\frac{X_B}{D_1^*}
|
||||
* \f]
|
||||
* where the self diffusion coefficients, \f$D_i^*\f$, are temperature and
|
||||
* composition parameterized inputs and the derivative of the activity
|
||||
* coefficient, \f$\frac{\partial \gamma_B}{\partial N_B}\f$, is calculated
|
||||
* by the ThermoPhase member using the excess enthalpy and entropy upon mixing.
|
||||
*
|
||||
* Finally, the deviation of the transferrence numbers from ideality,
|
||||
* \f$\epsilon\f$, is calculated from the mobility ratio of the cations.
|
||||
* \f[
|
||||
* \epsilon = \frac{1-b_2/b_1}{X_A+X_Bb_2/b_1}
|
||||
* \f]
|
||||
* Where \f$b_i\f$ are the mobilities of the two cations. Everywhere,
|
||||
* cation 1 corresponds with salt A and cation 2 with salt B.
|
||||
*
|
||||
* Sample input for this method is
|
||||
* \verbatim
|
||||
* <transport model="Liquid">
|
||||
* <speciesDiffusivity>
|
||||
* <compositionDependence model="stefanMaxwell_PPN">
|
||||
* </compositionDependence>
|
||||
* </speciesDiffusivity>
|
||||
* </transport>
|
||||
* \endverbatim
|
||||
*/
|
||||
class LTI_StefanMaxwell_PPN : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_StefanMaxwell_PPN(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_STEFANMAXWELL_PPN;
|
||||
}
|
||||
|
||||
void setParameters(LiquidTransportParams& trParam);
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0);
|
||||
|
||||
protected:
|
||||
doublereal m_ionCondMix;
|
||||
LiquidTranInteraction* m_ionCondMixModel;
|
||||
std::vector<LTPspecies*> m_ionCondSpecies;
|
||||
typedef std::vector<LTPspecies*> LTPvector;
|
||||
DenseMatrix m_mobRatMix;
|
||||
std::vector<LiquidTranInteraction*> m_mobRatMixModel;
|
||||
std::vector<LTPvector> m_mobRatSpecies;
|
||||
|
||||
std::vector<LiquidTranInteraction*> m_selfDiffMixModel;
|
||||
vector_fp m_selfDiffMix;
|
||||
std::vector<LTPvector> m_selfDiffSpecies;
|
||||
};
|
||||
|
||||
|
||||
class LTI_StokesEinstein : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_StokesEinstein(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_STOKES_EINSTEIN;
|
||||
}
|
||||
|
||||
void setParameters(LiquidTransportParams& trParam);
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties
|
||||
* as input (this method does not know what
|
||||
* transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0);
|
||||
|
||||
protected:
|
||||
std::vector<LTPspecies*> m_viscosity;
|
||||
std::vector<LTPspecies*> m_hydroRadius;
|
||||
};
|
||||
|
||||
//! Simple mole fraction weighting of transport properties
|
||||
/**
|
||||
* This model weights the transport property by the mole fractions. The
|
||||
* overall formula for the mixture viscosity is
|
||||
*
|
||||
* \f[ \eta_{mix} = \sum_i X_i \eta_i
|
||||
* + \sum_i \sum_j X_i X_j A_{i,j} \f].
|
||||
*/
|
||||
class LTI_MoleFracs_ExpT : public LiquidTranInteraction
|
||||
{
|
||||
public:
|
||||
LTI_MoleFracs_ExpT(TransportPropertyType tp_ind = TP_UNKNOWN) :
|
||||
LiquidTranInteraction(tp_ind) {
|
||||
m_model = LTI_MODEL_MOLEFRACS_EXPT;
|
||||
}
|
||||
|
||||
//! Return the mixture transport property value.
|
||||
/**
|
||||
* Takes the separate species transport properties as input (this method
|
||||
* does not know what transport property it is at this point.
|
||||
*/
|
||||
doublereal getMixTransProp(doublereal* valueSpecies, doublereal* weightSpecies = 0);
|
||||
doublereal getMixTransProp(std::vector<LTPspecies*> LTPptrs);
|
||||
|
||||
//! Return the matrix of binary interaction parameters.
|
||||
/**
|
||||
* Takes the proper mixing rule for the binary interaction parameters
|
||||
* and calculates them: Not Implemented for this mixing rule
|
||||
*/
|
||||
void getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues = 0) {
|
||||
mat = (*m_Aij[0]);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,74 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTransportData.h
|
||||
* Header file defining class LiquidTransportData
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_LIQUIDTRANSPORTDATA_H
|
||||
#define CT_LIQUIDTRANSPORTDATA_H
|
||||
|
||||
#include "TransportBase.h"
|
||||
#include "LTPspecies.h"
|
||||
#include "TransportData.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Class LiquidTransportData holds transport parameters for a
|
||||
//! specific liquid-phase species.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* A LiquidTransportData object is created for each species.
|
||||
*
|
||||
* This class is mainly used to collect transport properties from the parse
|
||||
* phase in the TransportFactory and transfer them to the Transport class.
|
||||
* Transport properties are expressed by subclasses of LTPspecies. One may
|
||||
* need to be careful about deleting pointers to LTPspecies objects created in
|
||||
* the TransportFactory.
|
||||
*
|
||||
* All of the pointers in this class are shallow pointers. Therefore, this
|
||||
* is a passthrough class, which keeps track of pointer ownership by zeroing
|
||||
* pointers as we go. Yes, Yes, yes, this is not good.
|
||||
*/
|
||||
class LiquidTransportData : public TransportData
|
||||
{
|
||||
public:
|
||||
LiquidTransportData();
|
||||
LiquidTransportData(const LiquidTransportData& right);
|
||||
LiquidTransportData& operator=(const LiquidTransportData& right);
|
||||
~LiquidTransportData();
|
||||
|
||||
//! A LiquidTransportData object is instantiated for each species.
|
||||
//! This is the species name for which this object is instantiated.
|
||||
std::string speciesName;
|
||||
|
||||
//! Model type for the hydroradius
|
||||
LTPspecies* hydroRadius;
|
||||
|
||||
//! Model type for the viscosity
|
||||
LTPspecies* viscosity;
|
||||
|
||||
//! Model type for the ionic conductivity
|
||||
LTPspecies* ionConductivity;
|
||||
|
||||
//! Model type for the mobility ratio
|
||||
std::vector<LTPspecies*> mobilityRatio;
|
||||
|
||||
//! Model type for the self diffusion coefficients
|
||||
std::vector<LTPspecies*> selfDiffusion;
|
||||
|
||||
//! Model type for the thermal conductivity
|
||||
LTPspecies* thermalCond;
|
||||
|
||||
//! Model type for the electrical conductivity
|
||||
LTPspecies* electCond;
|
||||
|
||||
//! Model type for the speciesDiffusivity
|
||||
LTPspecies* speciesDiffusivity;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTransportParams.h
|
||||
* Header file defining class LiquidTransportParams
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_LIQUIDTRANSPORTPARAMS_H
|
||||
#define CT_LIQUIDTRANSPORTPARAMS_H
|
||||
|
||||
#include "TransportParams.h"
|
||||
#include "LiquidTranInteraction.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Class LiquidTransportParams holds transport model parameters relevant to
|
||||
//! transport in mixtures.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* This class is used by TransportFactory to initialize transport objects.
|
||||
*/
|
||||
class LiquidTransportParams : public TransportParams
|
||||
{
|
||||
public:
|
||||
LiquidTransportParams();
|
||||
~LiquidTransportParams();
|
||||
LiquidTransportParams(const LiquidTransportParams& right) = delete;
|
||||
LiquidTransportParams& operator=(const LiquidTransportParams& right) = delete;
|
||||
|
||||
//! Species transport parameters
|
||||
std::vector<LiquidTransportData> LTData;
|
||||
|
||||
//! Object that specifies the viscosity interaction for the mixture
|
||||
LiquidTranInteraction* viscosity;
|
||||
|
||||
//! Object that specifies the ionic Conductivity of the mixture
|
||||
LiquidTranInteraction* ionConductivity;
|
||||
|
||||
//! Vector of pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of the mobility ratios for the phase
|
||||
/*!
|
||||
* The mobility ratio is defined via the following quantity where i and j
|
||||
* are species indices.
|
||||
*
|
||||
* mobRat(i,j) = mu_i / mu_j
|
||||
*
|
||||
* It is returned in fortran-ordering format. i.e. it is returned as
|
||||
* mobRat[k], where
|
||||
*
|
||||
* k = j * nsp + i
|
||||
*
|
||||
* Length = nsp * nsp
|
||||
*/
|
||||
std::vector<LiquidTranInteraction*> mobilityRatio;
|
||||
|
||||
//! Vector of pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of each species' self diffusion coefficient for the phase
|
||||
std::vector<LiquidTranInteraction*> selfDiffusion;
|
||||
|
||||
//! Pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of the mixture thermal conductivity for the phase
|
||||
LiquidTranInteraction* thermalCond;
|
||||
|
||||
//! Pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of the species diffusivity for the phase
|
||||
LiquidTranInteraction* speciesDiffusivity;
|
||||
|
||||
//! Pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of the electrical conductivity for the phase
|
||||
LiquidTranInteraction* electCond;
|
||||
|
||||
//! Pointer to the LiquidTranInteraction object which handles the
|
||||
//! calculation of the hydrodynamic radius for the phase
|
||||
/*!
|
||||
* @note I don't understand at the moment how one can define a
|
||||
* hydrodynamic radius for the phase
|
||||
*/
|
||||
LiquidTranInteraction* hydroRadius;
|
||||
|
||||
//! Model for species interaction effects for viscosity
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
LiquidTranMixingModel model_viscosity;
|
||||
|
||||
//! Model for species interaction effects for ionic conductivity
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
LiquidTranMixingModel model_ionConductivity;
|
||||
|
||||
//! Model for species interaction effects for mobility ratio
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
std::vector<LiquidTranMixingModel*> model_mobilityRatio;
|
||||
|
||||
//! Model for species interaction effects for mobility ratio
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
std::vector<LiquidTranMixingModel*> model_selfDiffusion;
|
||||
|
||||
//! Interaction associated with linear weighting of
|
||||
//! thermal conductivity.
|
||||
/**
|
||||
* This is used for either LTI_MODEL_MASSFRACS or LTI_MODEL_MOLEFRACS. The
|
||||
* overall formula for the mixture viscosity is
|
||||
*
|
||||
* \f[ \eta_{mix} = \sum_i X_i \eta_i + \sum_i \sum_j X_i X_j A_{i,j} \f].
|
||||
*/
|
||||
DenseMatrix thermalCond_Aij;
|
||||
|
||||
//! Model for species interaction effects for mass diffusivity
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
LiquidTranMixingModel model_speciesDiffusivity;
|
||||
|
||||
//! Interaction associated with linear weighting of
|
||||
//! thermal conductivity.
|
||||
/**
|
||||
* This is used for either LTI_MODEL_PAIRWISE_INTERACTION or
|
||||
* LTI_MODEL_STEFANMAXWELL_PPN. These provide species interaction
|
||||
* coefficients associated with the Stefan-Maxwell formulation.
|
||||
*/
|
||||
DenseMatrix diff_Dij;
|
||||
|
||||
//! Model for species interaction effects for hydrodynamic radius
|
||||
//! Takes enum LiquidTranMixingModel
|
||||
LiquidTranMixingModel model_hydroradius;
|
||||
|
||||
//! Interaction associated with hydrodynamic radius.
|
||||
/**
|
||||
* Not yet implemented
|
||||
*/
|
||||
DenseMatrix radius_Aij;
|
||||
|
||||
//! Default composition dependence of the transport properties
|
||||
/*!
|
||||
* Permissible types of composition dependencies
|
||||
* 0 - Solvent values (i.e., species 0) contributes only
|
||||
* 1 - linear combination of mole fractions;
|
||||
*/
|
||||
LiquidTranMixingModel compositionDepTypeDefault_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,694 +0,0 @@
|
||||
/**
|
||||
* @file SimpleTransport.h
|
||||
* Header file for the class SimpleTransport which provides simple
|
||||
* transport properties for liquids and solids
|
||||
* (see \ref tranprops and \link Cantera::SimpleTransport SimpleTransport \endlink) .
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_SIMPLETRAN_H
|
||||
#define CT_SIMPLETRAN_H
|
||||
|
||||
#include "LiquidTransportParams.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
//! Class SimpleTransport implements mixture-averaged transport properties for
|
||||
//! liquid phases.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* The model is based on that described by Newman, Electrochemical Systems
|
||||
*
|
||||
* The velocity of species i may be described by the following equation p. 297
|
||||
* (12.1)
|
||||
*
|
||||
* \f[
|
||||
* c_i \nabla \mu_i = R T \sum_j \frac{c_i c_j}{c_T D_{ij}}
|
||||
* (\mathbf{v}_j - \mathbf{v}_i)
|
||||
* \f]
|
||||
*
|
||||
* This as written is degenerate by 1 dof.
|
||||
*
|
||||
* To fix this we must add in the definition of the mass averaged velocity of
|
||||
* the solution. We will call the simple bold-faced \f$\mathbf{v} \f$ symbol the
|
||||
* mass-averaged velocity. Then, the relation between \f$\mathbf{v}\f$ and the
|
||||
* individual species velocities is \f$\mathbf{v}_i\f$
|
||||
*
|
||||
* \f[
|
||||
* \rho_i \mathbf{v}_i = \rho_i \mathbf{v} + \mathbf{j}_i
|
||||
* \f]
|
||||
* where \f$\mathbf{j}_i\f$ are the diffusional fluxes of species i with respect
|
||||
* to the mass averaged velocity and
|
||||
*
|
||||
* \f[
|
||||
* \sum_i \mathbf{j}_i = 0
|
||||
* \f]
|
||||
*
|
||||
* and
|
||||
*
|
||||
* \f[
|
||||
* \sum_i \rho_i \mathbf{v}_i = \rho \mathbf{v}
|
||||
* \f]
|
||||
*
|
||||
* Using these definitions, we can write
|
||||
*
|
||||
* \f[
|
||||
* \mathbf{v}_i = \mathbf{v} + \frac{\mathbf{j}_i}{\rho_i}
|
||||
* \f]
|
||||
*
|
||||
* \f[
|
||||
* c_i \nabla \mu_i = R T \sum_j \frac{c_i c_j}{c_T D_{ij}}
|
||||
* (\frac{\mathbf{j}_j}{\rho_j} - \frac{\mathbf{j}_i}{\rho_i})
|
||||
* = R T \sum_j \frac{1}{D_{ij}}
|
||||
* (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i})
|
||||
* \f]
|
||||
*
|
||||
* The equations that we actually solve are
|
||||
*
|
||||
* \f[
|
||||
* c_i \nabla \mu_i =
|
||||
* = R T \sum_j \frac{1}{D_{ij}}
|
||||
* (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i})
|
||||
* \f]
|
||||
* and we replace the 0th equation with the following:
|
||||
*
|
||||
* \f[
|
||||
* \sum_i \mathbf{j}_i = 0
|
||||
* \f]
|
||||
*
|
||||
* When there are charged species, we replace the RHS with the gradient of the
|
||||
* electrochemical potential to obtain the modified equation
|
||||
*
|
||||
* \f[
|
||||
* c_i \nabla \mu_i + c_i F z_i \nabla \Phi
|
||||
* = R T \sum_j \frac{1}{D_{ij}}
|
||||
* (\frac{x_i \mathbf{j}_j}{M_j} - \frac{x_j \mathbf{j}_i}{M_i})
|
||||
* \f]
|
||||
*
|
||||
* With this formulation we may solve for the diffusion velocities, without
|
||||
* having to worry about what the mass averaged velocity is.
|
||||
*
|
||||
* ## Viscosity Calculation
|
||||
*
|
||||
* The viscosity calculation may be broken down into two parts. In the first
|
||||
* part, the viscosity of the pure species are calculated In the second part, a
|
||||
* mixing rule is applied. There are two mixing rules. Solvent-only and mixture-
|
||||
* averaged.
|
||||
*
|
||||
* For the solvent-only mixing rule, we use the pure species viscosity
|
||||
* calculated for the solvent as the viscosity of the entire mixture. For the
|
||||
* mixture averaged rule we do a mole fraction based average of the pure species
|
||||
* viscosities:
|
||||
*
|
||||
* Solvent-only:
|
||||
* \f[
|
||||
* \mu = \mu_0
|
||||
* \f]
|
||||
* Mixture-average:
|
||||
* \f[
|
||||
* \mu = \sum_k {\mu_k X_k}
|
||||
* \f]
|
||||
*
|
||||
* ## Calculate of the Binary Diffusion Coefficients
|
||||
*
|
||||
* The binary diffusion coefficients are obtained from the pure species
|
||||
* diffusion coefficients using an additive process
|
||||
*
|
||||
* \f[
|
||||
* D_{i,j} = \frac{1}{2} \left( D^0_i(T) + D^0_j(T) \right)
|
||||
* \f]
|
||||
*
|
||||
* ## Electrical Mobilities
|
||||
*
|
||||
* The mobility \f$ \mu^e_k \f$ is calculated from the diffusion coefficient
|
||||
* using the Einstein relation.
|
||||
*
|
||||
* \f[
|
||||
* \mu^e_k = \frac{F D_k}{R T}
|
||||
* \f]
|
||||
*
|
||||
* The diffusion coefficients, \f$ D_k \f$ , is calculated from a call to the
|
||||
* mixture diffusion coefficient routine.
|
||||
*
|
||||
* ## Species Diffusive Fluxes
|
||||
*
|
||||
* The diffusive mass flux of species \e k is computed from the following
|
||||
* formula
|
||||
*
|
||||
* Usually the specified solution average velocity is the mass averaged
|
||||
* velocity. This is changed in some subclasses, however.
|
||||
*
|
||||
* \f[
|
||||
* j_k = - c^T M_k D_k \nabla X_k - \rho Y_k V_c
|
||||
* \f]
|
||||
*
|
||||
* where V_c is the correction velocity
|
||||
*
|
||||
* \f[
|
||||
* \rho V_c = - \sum_j {c^T M_j D_j \nabla X_j}
|
||||
* \f]
|
||||
*
|
||||
* In the above equation, \f$ D_k \f$ is the mixture diffusivity for species k
|
||||
* calculated for the current conditions, which may depend on T, P, and X_k. \f$
|
||||
* C^T \f$ is the total concentration of the phase.
|
||||
*
|
||||
* When this is electrical migration, the formulas above are enhanced to
|
||||
*
|
||||
* \f[
|
||||
* j_k = - C^T M_k D_k \nabla X_k + F C^T M_k \frac{D_k}{ R T } X_k z_k \nabla V - \rho Y_k V_c
|
||||
* \f]
|
||||
*
|
||||
* where V_c is the correction velocity
|
||||
*
|
||||
* \f[
|
||||
* \rho V_c = - \sum_j {c^T M_j D_j \nabla X_j} + \sum_j F C^T M_j \frac{D_j}{ R T } X_j z_j \nabla V
|
||||
* \f]
|
||||
*
|
||||
* ## Species Diffusional Velocities
|
||||
*
|
||||
* Species diffusional velocities are calculated from the species diffusional
|
||||
* fluxes, within this object, using the following formula for the diffusional
|
||||
* velocity of the kth species, \f$ V_k^d \f$
|
||||
*
|
||||
* \f[
|
||||
* j_k = \rho Y_k V_k^d
|
||||
* \f]
|
||||
*
|
||||
* TODO: This object has to be made compatible with different types of reference
|
||||
* velocities. Right now, elements of the formulas are only compatible with the
|
||||
* mass-averaged velocity.
|
||||
*
|
||||
* @ingroup tranprops
|
||||
*/
|
||||
class SimpleTransport : public Transport
|
||||
{
|
||||
public:
|
||||
//! Default constructor.
|
||||
/*!
|
||||
* This requires call to initLiquid(LiquidTransportParams& tr) after filling
|
||||
* LiquidTransportParams to complete instantiation. The filling of
|
||||
* LiquidTransportParams is currently carried out in the TransportFactory
|
||||
* class, but might be moved at some point.
|
||||
*
|
||||
* @param thermo ThermoPhase object holding species information.
|
||||
* @param ndim Number of spatial dimensions.
|
||||
*/
|
||||
SimpleTransport(thermo_t* thermo = 0, int ndim = 1);
|
||||
|
||||
virtual ~SimpleTransport();
|
||||
|
||||
//! Initialize the transport object
|
||||
/*!
|
||||
* Here we change all of the internal dimensions to be sufficient.
|
||||
* We get the object ready to do property evaluations.
|
||||
*
|
||||
* @param tr Transport parameters for all of the species in the phase.
|
||||
*/
|
||||
virtual bool initLiquid(LiquidTransportParams& tr);
|
||||
|
||||
void setCompositionDependence(LiquidTranMixingModel model) {
|
||||
compositionDepType_ = model;
|
||||
}
|
||||
|
||||
virtual std::string transportType() const {
|
||||
return "Simple";
|
||||
}
|
||||
|
||||
//! Returns the mixture viscosity of the solution
|
||||
/*!
|
||||
* The viscosity is computed using the general mixture rules
|
||||
* specified in the variable compositionDepType_.
|
||||
*
|
||||
* Solvent-only:
|
||||
* \f[
|
||||
* \mu = \mu_0
|
||||
* \f]
|
||||
* Mixture-average:
|
||||
* \f[
|
||||
* \mu = \sum_k {\mu_k X_k}
|
||||
* \f]
|
||||
*
|
||||
* Here \f$ \mu_k \f$ is the viscosity of pure species \e k.
|
||||
*
|
||||
* units are Pa s or kg/m/s
|
||||
*
|
||||
* @see updateViscosity_T();
|
||||
*/
|
||||
virtual doublereal viscosity();
|
||||
|
||||
//! Returns the pure species viscosities
|
||||
/*!
|
||||
* The pure species viscosities are to be given in an Arrhenius form in
|
||||
* accordance with activated-jump-process dominated transport.
|
||||
*
|
||||
* units are Pa s or kg/m/s
|
||||
*
|
||||
* @param visc Return the species viscosities as a vector of length m_nsp
|
||||
*/
|
||||
virtual void getSpeciesViscosities(doublereal* const visc);
|
||||
|
||||
//! Returns the binary diffusion coefficients
|
||||
virtual void getBinaryDiffCoeffs(const size_t ld, doublereal* const d);
|
||||
|
||||
//! Get the Mixture diffusion coefficients
|
||||
/*!
|
||||
* @param d vector of mixture diffusion coefficients
|
||||
* units = m2 s-1. length = number of species
|
||||
*/
|
||||
virtual void getMixDiffCoeffs(doublereal* const d);
|
||||
|
||||
//! Return the thermal diffusion coefficients
|
||||
/*!
|
||||
* These are all zero for this simple implementation
|
||||
*
|
||||
* @param dt thermal diffusion coefficients
|
||||
*/
|
||||
virtual void getThermalDiffCoeffs(doublereal* const dt);
|
||||
|
||||
//! Returns the mixture thermal conductivity of the solution
|
||||
/*!
|
||||
* The thermal is computed using the general mixture rules
|
||||
* specified in the variable compositionDepType_.
|
||||
*
|
||||
* Controlling update boolean = m_condmix_ok
|
||||
*
|
||||
* Units are in W/m/K or equivalently kg m / s3 / K
|
||||
*
|
||||
* Solvent-only:
|
||||
* \f[
|
||||
* \lambda = \lambda_0
|
||||
* \f]
|
||||
* Mixture-average:
|
||||
* \f[
|
||||
* \lambda = \sum_k {\lambda_k X_k}
|
||||
* \f]
|
||||
*
|
||||
* Here \f$ \lambda_k \f$ is the thermal conductivity of pure species \e k.
|
||||
*
|
||||
* @see updateCond_T();
|
||||
*/
|
||||
virtual doublereal thermalConductivity();
|
||||
|
||||
virtual void getMobilities(doublereal* const mobil_e);
|
||||
|
||||
virtual void getFluidMobilities(doublereal* const mobil_f);
|
||||
|
||||
//! Specify the value of the gradient of the voltage
|
||||
/*!
|
||||
* @param grad_V Gradient of the voltage (length num dimensions);
|
||||
*/
|
||||
virtual void set_Grad_V(const doublereal* const grad_V);
|
||||
|
||||
//! Specify the value of the gradient of the temperature
|
||||
/*!
|
||||
* @param grad_T Gradient of the temperature (length num dimensions);
|
||||
*/
|
||||
virtual void set_Grad_T(const doublereal* const grad_T);
|
||||
|
||||
//! Specify the value of the gradient of the MoleFractions
|
||||
/*!
|
||||
* @param grad_X Gradient of the mole fractions(length nsp * num dimensions);
|
||||
*/
|
||||
virtual void set_Grad_X(const doublereal* const grad_X);
|
||||
|
||||
//! Get the species diffusive velocities wrt to the averaged velocity,
|
||||
//! given the gradients in mole fraction and temperature
|
||||
/*!
|
||||
* The average velocity can be computed on a mole-weighted
|
||||
* or mass-weighted basis, or the diffusion velocities may
|
||||
* be specified as relative to a specific species (i.e. a
|
||||
* solvent) all according to the velocityBasis input parameter.
|
||||
*
|
||||
* Units for the returned velocities are m s-1.
|
||||
*
|
||||
* @param ndim Number of dimensions in the flux expressions
|
||||
* @param grad_T Gradient of the temperature (length = ndim)
|
||||
* @param ldx Leading dimension of the grad_X array (usually equal to
|
||||
* m_nsp but not always)
|
||||
* @param grad_X Gradients of the mole fraction. Flat vector with the m_nsp
|
||||
* in the inner loop. length = ldx * ndim
|
||||
* @param ldf Leading dimension of the fluxes array (usually equal to
|
||||
* m_nsp but not always)
|
||||
* @param Vdiff Output of the diffusive velocities. Flat vector with the
|
||||
* m_nsp in the inner loop. length = ldx * ndim
|
||||
*/
|
||||
virtual void getSpeciesVdiff(size_t ndim,
|
||||
const doublereal* grad_T,
|
||||
int ldx,
|
||||
const doublereal* grad_X,
|
||||
int ldf,
|
||||
doublereal* Vdiff);
|
||||
|
||||
//! Get the species diffusive velocities wrt to the averaged velocity, given
|
||||
//! the gradients in mole fraction, temperature and electrostatic potential.
|
||||
/*!
|
||||
* The average velocity can be computed on a mole-weighted
|
||||
* or mass-weighted basis, or the diffusion velocities may
|
||||
* be specified as relative to a specific species (i.e. a
|
||||
* solvent) all according to the velocityBasis input parameter.
|
||||
*
|
||||
* Units for the returned velocities are m s-1.
|
||||
*
|
||||
* @param ndim Number of dimensions in the flux expressions
|
||||
* @param grad_T Gradient of the temperature (length = ndim)
|
||||
* @param ldx Leading dimension of the grad_X array (usually equal
|
||||
* to m_nsp but not always)
|
||||
* @param grad_X Gradients of the mole fraction. Flat vector with the
|
||||
* m_nsp in the inner loop. length = ldx * ndim
|
||||
* @param ldf Leading dimension of the fluxes array (usually equal to
|
||||
* m_nsp but not always)
|
||||
* @param grad_Phi Gradients of the electrostatic potential (length =
|
||||
* ndim)
|
||||
* @param Vdiff Output of the species diffusion velocities. Flat vector
|
||||
* with the m_nsp in the inner loop. length = ldx * ndim
|
||||
*/
|
||||
virtual void getSpeciesVdiffES(size_t ndim, const doublereal* grad_T,
|
||||
int ldx, const doublereal* grad_X,
|
||||
int ldf, const doublereal* grad_Phi,
|
||||
doublereal* Vdiff);
|
||||
|
||||
//! Get the species diffusive mass fluxes wrt to the specified solution
|
||||
//! averaged velocity, given the gradients in mole fraction and temperature
|
||||
/*!
|
||||
* units = kg/m2/s
|
||||
*
|
||||
* The diffusive mass flux of species \e k is computed from the following
|
||||
* formula
|
||||
*
|
||||
* Usually the specified solution average velocity is the mass averaged
|
||||
* velocity. This is changed in some subclasses, however.
|
||||
*
|
||||
* \f[
|
||||
* j_k = - \rho M_k D_k \nabla X_k - Y_k V_c
|
||||
* \f]
|
||||
*
|
||||
* where V_c is the correction velocity
|
||||
*
|
||||
* \f[
|
||||
* V_c = - \sum_j {\rho M_j D_j \nabla X_j}
|
||||
* \f]
|
||||
*
|
||||
* @param ndim The number of spatial dimensions (1, 2, or 3).
|
||||
* @param grad_T The temperature gradient (ignored in this model).
|
||||
* @param ldx Leading dimension of the grad_X array.
|
||||
* @param grad_X Gradient of the mole fractions(length nsp * num dimensions);
|
||||
* @param ldf Leading dimension of the fluxes array.
|
||||
* @param fluxes Output fluxes of species.
|
||||
*/
|
||||
virtual void getSpeciesFluxes(size_t ndim, const doublereal* const grad_T,
|
||||
size_t ldx, const doublereal* const grad_X,
|
||||
size_t ldf, doublereal* const fluxes);
|
||||
|
||||
//! Return the species diffusive mass fluxes wrt to the mass averaged
|
||||
//! velocity,
|
||||
/*!
|
||||
* units = kg/m2/s
|
||||
*
|
||||
* Internally, gradients in the in mole fraction, temperature
|
||||
* and electrostatic potential contribute to the diffusive flux
|
||||
*
|
||||
* The diffusive mass flux of species \e k is computed from the following
|
||||
* formula
|
||||
*
|
||||
* \f[
|
||||
* j_k = - \rho M_k D_k \nabla X_k - Y_k V_c
|
||||
* \f]
|
||||
*
|
||||
* where V_c is the correction velocity
|
||||
*
|
||||
* \f[
|
||||
* V_c = - \sum_j {\rho M_j D_j \nabla X_j}
|
||||
* \f]
|
||||
*
|
||||
* @param ldf stride of the fluxes array. Must be equal to or greater
|
||||
* than the number of species.
|
||||
* @param fluxes Vector of calculated fluxes
|
||||
*/
|
||||
virtual void getSpeciesFluxesExt(size_t ldf, doublereal* fluxes);
|
||||
|
||||
protected:
|
||||
//! Handles the effects of changes in the Temperature, internally within the
|
||||
//! object.
|
||||
/*!
|
||||
* This is called whenever a transport property is requested. The first task
|
||||
* is to check whether the temperature has changed since the last call to
|
||||
* update_T(). If it hasn't then an immediate return is carried out.
|
||||
*
|
||||
* @returns true if the temperature has changed, and false otherwise
|
||||
*/
|
||||
virtual bool update_T();
|
||||
|
||||
//! Handles the effects of changes in the mixture concentration
|
||||
/*!
|
||||
* This is called for every interface call to check whether the
|
||||
* concentrations have changed. Concentrations change whenever the pressure
|
||||
* or the mole fraction has changed. If it has changed, the recalculations
|
||||
* should be done.
|
||||
*
|
||||
* Note this should be a lightweight function since it's part of all of the
|
||||
* interfaces.
|
||||
*/
|
||||
virtual bool update_C();
|
||||
|
||||
//! Update the temperature-dependent viscosity terms. Updates the array of
|
||||
//! pure species viscosities, and the weighting functions in the viscosity
|
||||
//! mixture rule.
|
||||
/*!
|
||||
* The flag m_visc_temp_ok is set to true.
|
||||
*/
|
||||
void updateViscosity_T();
|
||||
|
||||
//! Update the temperature-dependent parts of the mixture-averaged
|
||||
//! thermal conductivity.
|
||||
void updateCond_T();
|
||||
|
||||
//! Update the binary diffusion coefficients wrt T.
|
||||
/*!
|
||||
* These are evaluated from the polynomial fits at unit pressure (1 Pa).
|
||||
*/
|
||||
void updateDiff_T();
|
||||
|
||||
private:
|
||||
//! Composition dependence of the transport properties
|
||||
/*!
|
||||
* The following coefficients are allowed to have simple composition
|
||||
* dependencies:
|
||||
* - mixture viscosity
|
||||
* - mixture thermal conductivity
|
||||
*
|
||||
* Permissible types of composition dependencies
|
||||
* 0 - Solvent values (i.e., species 0) contributes only
|
||||
* 1 - linear combination of mole fractions;
|
||||
*/
|
||||
enum LiquidTranMixingModel compositionDepType_;
|
||||
|
||||
//! Boolean indicating whether to use the hydrodynamic radius formulation
|
||||
/*!
|
||||
* If true, then the diffusion coefficient is calculated from the
|
||||
* hydrodynamic radius.
|
||||
*/
|
||||
bool useHydroRadius_;
|
||||
|
||||
//! Boolean indicating whether electro-migration term should be added
|
||||
bool doMigration_;
|
||||
|
||||
//! Local Copy of the molecular weights of the species
|
||||
/*!
|
||||
* Length is Equal to the number of species in the mechanism.
|
||||
*/
|
||||
vector_fp m_mw;
|
||||
|
||||
//! Pure species viscosities in Arrhenius temperature-dependent form.
|
||||
std::vector<LTPspecies*> m_coeffVisc_Ns;
|
||||
|
||||
//! Pure species thermal conductivities in Arrhenius temperature-dependent form.
|
||||
std::vector<LTPspecies*> m_coeffLambda_Ns;
|
||||
|
||||
//! Pure species viscosities in Arrhenius temperature-dependent form.
|
||||
std::vector<LTPspecies*> m_coeffDiff_Ns;
|
||||
|
||||
//! Hydrodynamic radius in LTPspecies form
|
||||
std::vector<LTPspecies*> m_coeffHydroRadius_Ns;
|
||||
|
||||
//! Internal value of the gradient of the mole fraction vector
|
||||
/*!
|
||||
* Note, this is the only gradient value that can and perhaps should reflect
|
||||
* the true state of the mole fractions in the application solution vector.
|
||||
* In other words no cropping or massaging of the values to make sure they
|
||||
* are above zero should occur. - developing ....
|
||||
*
|
||||
* m_nsp is the number of species in the fluid
|
||||
* k is the species index
|
||||
* n is the dimensional index (x, y, or z). It has a length equal to m_nDim
|
||||
*
|
||||
* m_Grad_X[n*m_nsp + k]
|
||||
*/
|
||||
vector_fp m_Grad_X;
|
||||
|
||||
//! Internal value of the gradient of the Temperature vector
|
||||
/*!
|
||||
* Generally, if a transport property needs this in its evaluation it
|
||||
* will look to this place to get it.
|
||||
*
|
||||
* No internal property is precalculated based on gradients. Gradients
|
||||
* are assumed to be freshly updated before every property call.
|
||||
*/
|
||||
vector_fp m_Grad_T;
|
||||
|
||||
//! Internal value of the gradient of the Pressure vector
|
||||
/*!
|
||||
* Generally, if a transport property needs this in its evaluation it
|
||||
* will look to this place to get it.
|
||||
*
|
||||
* No internal property is precalculated based on gradients. Gradients
|
||||
* are assumed to be freshly updated before every property call.
|
||||
*/
|
||||
vector_fp m_Grad_P;
|
||||
|
||||
//! Internal value of the gradient of the Electric Voltage
|
||||
/*!
|
||||
* Generally, if a transport property needs this in its evaluation it
|
||||
* will look to this place to get it.
|
||||
*
|
||||
* No internal property is precalculated based on gradients. Gradients
|
||||
* are assumed to be freshly updated before every property call.
|
||||
*/
|
||||
vector_fp m_Grad_V;
|
||||
|
||||
// property values
|
||||
|
||||
//! Vector of Species Diffusivities
|
||||
/*!
|
||||
* Depends on the temperature. We have set the pressure dependence to zero
|
||||
* for this liquid phase constituitve model
|
||||
*
|
||||
* units m2/s
|
||||
*/
|
||||
vector_fp m_diffSpecies;
|
||||
|
||||
//! Species viscosities
|
||||
/*!
|
||||
* Viscosity of the species
|
||||
* Length = number of species
|
||||
*
|
||||
* Depends on the temperature. We have set the pressure dependence to zero
|
||||
* for this model
|
||||
*
|
||||
* controlling update boolean -> m_visc_temp_ok
|
||||
*/
|
||||
vector_fp m_viscSpecies;
|
||||
|
||||
//! Internal value of the species individual thermal conductivities
|
||||
/*!
|
||||
* Then a mixture rule is applied to get the solution conductivities
|
||||
*
|
||||
* Depends on the temperature and perhaps pressure, but
|
||||
* not the species concentrations
|
||||
*
|
||||
* controlling update boolean -> m_cond_temp_ok
|
||||
*/
|
||||
vector_fp m_condSpecies;
|
||||
|
||||
//! State of the mole fraction vector.
|
||||
int m_iStateMF;
|
||||
|
||||
//! Local copy of the mole fractions of the species in the phase
|
||||
/*!
|
||||
* The mole fractions here are assumed to be bounded by 0.0 and 1.0 and they
|
||||
* are assumed to add up to one exactly. This mole fraction vector comes
|
||||
* from the ThermoPhase object. Derivative quantities from this are referred
|
||||
* to as bounded.
|
||||
*
|
||||
* Update info?
|
||||
* length = m_nsp
|
||||
*/
|
||||
vector_fp m_molefracs;
|
||||
|
||||
//! Local copy of the concentrations of the species in the phase
|
||||
/*!
|
||||
* The concentrations are consistent with the m_molefracs vector which is
|
||||
* bounded and sums to one.
|
||||
*
|
||||
* Update info?
|
||||
* length = m_nsp
|
||||
*/
|
||||
vector_fp m_concentrations;
|
||||
|
||||
//! Local copy of the total concentration.
|
||||
/*!
|
||||
* This is consistent with the m_concentrations[] and m_molefracs[] vector.
|
||||
*/
|
||||
doublereal concTot_;
|
||||
|
||||
//! Mean molecular weight
|
||||
doublereal meanMolecularWeight_;
|
||||
|
||||
//! Density
|
||||
doublereal dens_;
|
||||
|
||||
//! Local copy of the charge of each species
|
||||
/*!
|
||||
* Contains the charge of each species (length m_nsp)
|
||||
*/
|
||||
vector_fp m_chargeSpecies;
|
||||
|
||||
//! Current Temperature -> locally stored
|
||||
/*!
|
||||
* This is used to test whether new temperature computations should be
|
||||
* performed.
|
||||
*/
|
||||
doublereal m_temp;
|
||||
|
||||
//! Current value of the pressure
|
||||
doublereal m_press;
|
||||
|
||||
//! Saved value of the mixture thermal conductivity
|
||||
doublereal m_lambda;
|
||||
|
||||
//! Saved value of the mixture viscosity
|
||||
doublereal m_viscmix;
|
||||
|
||||
//! work space
|
||||
/*!
|
||||
* Length is equal to m_nsp
|
||||
*/
|
||||
vector_fp m_spwork;
|
||||
|
||||
vector_fp m_fluxes;
|
||||
|
||||
//! Boolean indicating that the top-level mixture viscosity is current
|
||||
/*!
|
||||
* This is turned false for every change in T, P, or C.
|
||||
*/
|
||||
bool m_visc_mix_ok;
|
||||
|
||||
//! Boolean indicating that weight factors wrt viscosity is current
|
||||
bool m_visc_temp_ok;
|
||||
|
||||
//! Boolean indicating that mixture diffusion coeffs are current
|
||||
bool m_diff_mix_ok;
|
||||
|
||||
//! Boolean indicating that binary diffusion coeffs are current
|
||||
bool m_diff_temp_ok;
|
||||
|
||||
//! Flag to indicate that the pure species conductivities
|
||||
//! are current wrt the temperature
|
||||
bool m_cond_temp_ok;
|
||||
|
||||
//! Boolean indicating that mixture conductivity is current
|
||||
bool m_cond_mix_ok;
|
||||
|
||||
//! Number of dimensions
|
||||
/*!
|
||||
* Either 1, 2, or 3
|
||||
*/
|
||||
size_t m_nDim;
|
||||
|
||||
//! Temporary variable that stores the rho Vc value
|
||||
double rhoVc[3];
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,188 +0,0 @@
|
||||
/**
|
||||
* @file SolidTransport.h
|
||||
* Header file for defining the class SolidTransport, which handles transport
|
||||
* of ions within solid phases
|
||||
* (see \ref tranprops and \link Cantera::SolidTransport SolidTransport \endlink).
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_SOLIDTRAN_H
|
||||
#define CT_SOLIDTRAN_H
|
||||
|
||||
#include "LTPspecies.h"
|
||||
#include "TransportBase.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
//! Class SolidTransport implements transport properties for solids.
|
||||
//! @ingroup tranprops
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*/
|
||||
class SolidTransport : public Transport
|
||||
{
|
||||
public:
|
||||
SolidTransport();
|
||||
|
||||
virtual std::string transportType() const {
|
||||
return "Solid";
|
||||
}
|
||||
|
||||
//! Returns the ionic conductivity of the phase
|
||||
/*!
|
||||
* The thermo phase needs to be updated (temperature) prior to calling this.
|
||||
* The ionConductivity calculation is handled by subclasses of LTPspecies as
|
||||
* specified in the input file.
|
||||
*/
|
||||
virtual doublereal ionConductivity();
|
||||
|
||||
//! Returns the thermal conductivity of the phase
|
||||
/*!
|
||||
* The thermo phase needs to be updated (temperature) prior to calling this.
|
||||
* The thermalConductivity calculation is handled by subclasses of
|
||||
* LTPspecies as specified in the input file.
|
||||
*
|
||||
* There is also a legacy method to evaluate
|
||||
* \f[
|
||||
* \lambda = A T^n \exp(-E/RT)
|
||||
* \f]
|
||||
*/
|
||||
virtual doublereal thermalConductivity();
|
||||
|
||||
//! Returns the electron conductivity of the phase
|
||||
/*!
|
||||
* The thermo phase needs to be updated (temperature) prior to calling
|
||||
* this. The ionConductivity calculation is handled by subclasses of
|
||||
* LTPspecies as specified in the input file.
|
||||
*
|
||||
* There is also a legacy multicomponent diffusion approach to electrical
|
||||
* conductivity.
|
||||
*/
|
||||
virtual doublereal electricalConductivity();
|
||||
|
||||
/*!
|
||||
* The diffusivity of defects in the solid (m^2/s). The thermo phase needs
|
||||
* to be updated (temperature) prior to calling this. The defectDiffusivity
|
||||
* calculation is handled by subclasses of LTPspecies as specified in the
|
||||
* input file.
|
||||
*/
|
||||
virtual doublereal defectDiffusivity();
|
||||
|
||||
/**
|
||||
* The activity of defects in the solid. At some point this should be
|
||||
* variable and the diffusion coefficient should depend on it.
|
||||
*
|
||||
* The thermo phase needs to be updated (temperature) prior to calling this.
|
||||
* The defectActivity calculation is handled by subclasses of
|
||||
* LTPspecies as specified in the input file.
|
||||
*/
|
||||
virtual doublereal defectActivity();
|
||||
|
||||
/*
|
||||
* The diffusion coefficients are computed from
|
||||
*
|
||||
* \f[
|
||||
* D_k = A_k T^{n_k} \exp(-E_k/RT).
|
||||
* \f]
|
||||
*
|
||||
* The diffusion coefficients are only non-zero for species for which
|
||||
* parameters have been specified using method setParameters.
|
||||
* @todo HEWSON WONDERS IF THE FOLLOWING ARE RELEVANT??
|
||||
*/
|
||||
virtual void getMixDiffCoeffs(doublereal* const d);
|
||||
|
||||
virtual void getMobilities(doublereal* const mobil);
|
||||
|
||||
virtual void setParameters(const int n, const int k, const doublereal* const p);
|
||||
|
||||
friend class TransportFactory;
|
||||
|
||||
protected:
|
||||
//! Initialize the transport object
|
||||
/*!
|
||||
* Here we change all of the internal dimensions to be sufficient. We get
|
||||
* the object ready to do property evaluations. A lot of the input
|
||||
* required to do property evaluations is contained in the
|
||||
* SolidTransportParams class that is filled in TransportFactory.
|
||||
*
|
||||
* @param tr Transport parameters for all of the species in the phase.
|
||||
*/
|
||||
virtual bool initSolid(SolidTransportData& tr);
|
||||
|
||||
private:
|
||||
//! Model type for the ionic conductivity
|
||||
LTPspecies* m_ionConductivity;
|
||||
|
||||
//! Model type for the thermal conductivity
|
||||
LTPspecies* m_thermalConductivity;
|
||||
|
||||
//! Model type for the electrical conductivity
|
||||
LTPspecies* m_electConductivity;
|
||||
|
||||
//! Model type for the defectDiffusivity -- or more like a defect
|
||||
//! diffusivity in the context of the solid phase.
|
||||
LTPspecies* m_defectDiffusivity;
|
||||
|
||||
//! Model type for the defectActivity
|
||||
LTPspecies* m_defectActivity;
|
||||
|
||||
//! number of mobile species
|
||||
size_t m_nmobile;
|
||||
|
||||
//! Coefficient for the diffusivity of species within a solid
|
||||
/*!
|
||||
* This is with respect to the lattice
|
||||
* units = m**2 / s
|
||||
* vector of length m_nmobile
|
||||
*/
|
||||
vector_fp m_Adiff;
|
||||
|
||||
//! Temperature power coefficient for the diffusivity of species in a solid
|
||||
/*!
|
||||
* vector of length m_nmobile
|
||||
*/
|
||||
vector_fp m_Ndiff;
|
||||
|
||||
//! Arrhenius factor for the species diffusivities of a solid
|
||||
/*!
|
||||
* units = temperature
|
||||
* vector of length m_nmobile
|
||||
*/
|
||||
vector_fp m_Ediff;
|
||||
|
||||
//! Index of mobile species to global species
|
||||
/*!
|
||||
* vector of length m_nmobile
|
||||
*/
|
||||
vector_int m_sp;
|
||||
|
||||
//! Coefficient for the thermal conductivity of a solid
|
||||
/*!
|
||||
* units = kg m / s3 /K = W/m/K
|
||||
*/
|
||||
doublereal m_Alam;
|
||||
|
||||
//! Temperature power coefficient for the thermal conductivity of a solid
|
||||
doublereal m_Nlam;
|
||||
|
||||
//! Arrhenius factor for the thermal conductivity of a solid
|
||||
/*!
|
||||
* units = temperature
|
||||
*/
|
||||
doublereal m_Elam;
|
||||
|
||||
//! extra fp array of length nSpecies()
|
||||
vector_fp m_work;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
@@ -1,68 +0,0 @@
|
||||
/**
|
||||
* @file SolidTransportData.h
|
||||
* Header file defining class SolidTransportData
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_SOLIDTRANSPORTDATA_H
|
||||
#define CT_SOLIDTRANSPORTDATA_H
|
||||
|
||||
#include "cantera/transport/TransportParams.h"
|
||||
#include "cantera/transport/LTPspecies.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Class SolidTransportData holds transport parameters for a specific solid-
|
||||
//! phase species.
|
||||
/*!
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* A SolidTransportData object is created for a solid phase
|
||||
* (not for each species as happens for the analogous LiquidTransportData).
|
||||
*
|
||||
* This class is mainly used to collect transport properties from the parse
|
||||
* phase in the TranportFactory and transfer them to the Transport class.
|
||||
* Transport properties are expressed by subclasses of LTPspecies. Note that we
|
||||
* use the liquid phase species model for the solid phases. That is, for the
|
||||
* time being at least, we ignore mixing models for solid phases and just
|
||||
* specify a transport property at the level that we specify the transport
|
||||
* property for a species in the liquid phase. One may need to be careful about
|
||||
* deleting pointers to LTPspecies objects created in the TransportFactory.
|
||||
*
|
||||
* All of the pointers in this class are shallow pointers. Therefore, this is
|
||||
* a passthrough class, which keeps track of pointer ownership by zeroing
|
||||
* pointers as we go. Yes, Yes, yes, this is not good.
|
||||
*/
|
||||
class SolidTransportData : public TransportParams
|
||||
{
|
||||
public:
|
||||
SolidTransportData();
|
||||
SolidTransportData(const SolidTransportData& right);
|
||||
SolidTransportData& operator=(const SolidTransportData& right);
|
||||
~SolidTransportData();
|
||||
|
||||
//! A SolidTransportData object is instantiated for each species.
|
||||
//! This is the species name for which this object is instantiated.
|
||||
std::string speciesName;
|
||||
|
||||
//! Model type for the ionic conductivity
|
||||
LTPspecies* ionConductivity;
|
||||
|
||||
//! Model type for the thermal conductivity
|
||||
LTPspecies* thermalConductivity;
|
||||
|
||||
//! Model type for the electrical conductivity
|
||||
LTPspecies* electConductivity;
|
||||
|
||||
//! Model type for the defectDiffusivity -- or more like a defect diffusivity in the context of the solid phase.
|
||||
LTPspecies* defectDiffusivity;
|
||||
|
||||
//! Model type for the defectActivity
|
||||
LTPspecies* defectActivity;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -1,170 +0,0 @@
|
||||
/**
|
||||
* @file Tortuosity.h
|
||||
* Class to compute the increase in diffusive path length in porous media
|
||||
* assuming the Bruggeman exponent relation
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#ifndef CT_TORTUOSITY_H
|
||||
#define CT_TORTUOSITY_H
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
//! Specific Class to handle tortuosity corrections for diffusive transport
|
||||
//! in porous media using the Bruggeman exponent
|
||||
/*!
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*
|
||||
* @deprecated To be removed after Cantera 2.4
|
||||
*
|
||||
* Class to compute the increase in diffusive path length associated with
|
||||
* tortuous path diffusion through, for example, porous media. This base class
|
||||
* implementation relates tortuosity to volume fraction through a power-law
|
||||
* relationship that goes back to Bruggeman. The exponent is referred to as the
|
||||
* Bruggeman exponent.
|
||||
*
|
||||
* Note that the total diffusional flux is generally written as
|
||||
*
|
||||
* \f[
|
||||
* \frac{ \phi C_T D_i \nabla X_i }{ \tau^2 }
|
||||
* \f]
|
||||
*
|
||||
* where \f$ \phi \f$ is the volume fraction of the transported phase,
|
||||
* \f$ \tau \f$ is referred to as the tortuosity. (Other variables are
|
||||
* \f$ C_T \f$, the total concentration, \f$ D_i \f$, the diffusion coefficient,
|
||||
* and \f$ X_i \f$, the mole fraction with Fickian transport assumed.)
|
||||
*/
|
||||
class Tortuosity
|
||||
{
|
||||
public:
|
||||
//! Default constructor uses Bruggeman exponent of 1.5
|
||||
Tortuosity(double setPower = 1.5) : expBrug_(setPower) {
|
||||
}
|
||||
|
||||
//! The tortuosity factor models the effective increase in the
|
||||
//! diffusive transport length.
|
||||
/**
|
||||
* This method returns \f$ 1/\tau^2 \f$ in the description of the
|
||||
* flux \f$ \phi C_T D_i \nabla X_i / \tau^2 \f$.
|
||||
*/
|
||||
virtual double tortuosityFactor(double porosity) {
|
||||
return pow(porosity, expBrug_ - 1.0);
|
||||
}
|
||||
|
||||
//! The McMillan number is the ratio of the flux-like
|
||||
//! variable to the value it would have without porous flow.
|
||||
/**
|
||||
* The McMillan number combines the effect of tortuosity and volume fraction
|
||||
* of the transported phase. The net flux observed is then the product of
|
||||
* the McMillan number and the non-porous transport rate. For a
|
||||
* conductivity in a non-porous media, \f$ \kappa_0 \f$, the conductivity in
|
||||
* the porous media would be \f$ \kappa = (\rm McMillan) \kappa_0 \f$.
|
||||
*/
|
||||
virtual double McMillan(double porosity) {
|
||||
return pow(porosity, expBrug_);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Bruggeman exponent: power to which the tortuosity depends on the volume
|
||||
//! fraction
|
||||
double expBrug_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class implements transport coefficient corrections appropriate for
|
||||
* porous media where percolation theory applies.
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*/
|
||||
class TortuosityPercolation : public Tortuosity
|
||||
{
|
||||
public:
|
||||
//! Default constructor uses Bruggeman exponent of 1.5
|
||||
TortuosityPercolation(double percolationThreshold = 0.4, double conductivityExponent = 2.0) : percolationThreshold_(percolationThreshold), conductivityExponent_(conductivityExponent) {
|
||||
}
|
||||
|
||||
double tortuosityFactor(double porosity) {
|
||||
return McMillan(porosity) / porosity;
|
||||
}
|
||||
|
||||
double McMillan(double porosity) {
|
||||
return pow((porosity - percolationThreshold_)
|
||||
/ (1.0 - percolationThreshold_),
|
||||
conductivityExponent_);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Critical volume fraction / site density for percolation
|
||||
double percolationThreshold_;
|
||||
//! Conductivity exponent
|
||||
/**
|
||||
* The McMillan number (ratio of effective conductivity
|
||||
* to non-porous conductivity) is
|
||||
* \f[
|
||||
* \kappa/\kappa_0 = ( \phi - \phi_c )^\mu
|
||||
* \f]
|
||||
* where \f$ \mu \f$ is the conductivity exponent (typical values range from
|
||||
* 1.6 to 2.0) and \f$ \phi_c \f$ is the percolation threshold.
|
||||
*/
|
||||
double conductivityExponent_;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* This class implements transport coefficient corrections appropriate for
|
||||
* porous media with a dispersed phase. This model goes back to Maxwell. The
|
||||
* formula for the conductivity is expressed in terms of the volume fraction of
|
||||
* the continuous phase, \f$ \phi \f$, and the relative conductivities of the
|
||||
* dispersed and continuous phases, \f$ r = \kappa_d / \kappa_0 \f$. For dilute
|
||||
* particle suspensions the effective conductivity is
|
||||
* \f[
|
||||
* \kappa / \kappa_0 = 1 + 3 ( 1 - \phi ) ( r - 1 ) / ( r + 2 ) + O(\phi^2)
|
||||
* \f]
|
||||
*
|
||||
* @attention This class currently does not have any test cases or examples. Its
|
||||
* implementation may be incomplete, and future changes to Cantera may
|
||||
* unexpectedly cause this class to stop working. If you use this class,
|
||||
* please consider contributing examples or test cases. In the absence of
|
||||
* new tests or examples, this class may be deprecated and removed in a
|
||||
* future version of Cantera. See
|
||||
* https://github.com/Cantera/cantera/issues/267 for additional information.
|
||||
*/
|
||||
class TortuosityMaxwell : public Tortuosity
|
||||
{
|
||||
public:
|
||||
//! Default constructor uses Bruggeman exponent of 1.5
|
||||
TortuosityMaxwell(double relativeConductivites = 0.0) : relativeConductivites_(relativeConductivites) {
|
||||
}
|
||||
|
||||
double tortuosityFactor(double porosity) {
|
||||
return McMillan(porosity) / porosity;
|
||||
}
|
||||
|
||||
double McMillan(double porosity) {
|
||||
return 1 + 3 * (1.0 - porosity) * (relativeConductivites_ - 1.0) / (relativeConductivites_ + 2);
|
||||
}
|
||||
|
||||
protected:
|
||||
//! Relative conductivities of the dispersed and continuous phases,
|
||||
//! `relativeConductivites_` \f$ = \kappa_d / \kappa_0 \f$.
|
||||
double relativeConductivites_;
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -24,9 +24,6 @@
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
class LiquidTransportParams;
|
||||
class SolidTransportData;
|
||||
|
||||
/*!
|
||||
* \addtogroup tranprops
|
||||
*/
|
||||
@@ -270,47 +267,6 @@ public:
|
||||
throw NotImplementedError("Transport::getSpeciesMobilityRatio");
|
||||
}
|
||||
|
||||
//! Returns the self diffusion coefficients of the species in the phase
|
||||
/*!
|
||||
* The self diffusion coefficient is the diffusion coefficient of a tracer
|
||||
* species at the current temperature and composition of the species.
|
||||
* Therefore, the dilute limit of transport is assumed for the tracer
|
||||
* species. The effective formula may be calculated from the Stefan-Maxwell
|
||||
* formulation by adding another row for the tracer species, assigning all
|
||||
* D's to be equal to the respective species D's, and then taking the limit
|
||||
* as the tracer species mole fraction goes to zero. The corresponding flux
|
||||
* equation for the tracer species k in units of kmol m-2 s-1 is.
|
||||
*
|
||||
* \f[
|
||||
* J_k = - D^{sd}_k \frac{C_k}{R T} \nabla \mu_k
|
||||
* \f]
|
||||
*
|
||||
* The derivative is taken at constant T and P.
|
||||
*
|
||||
* The self diffusion calculation is handled by subclasses of
|
||||
* LiquidTranInteraction as specified in the input file. These in turn
|
||||
* employ subclasses of LTPspecies to determine the individual species self
|
||||
* diffusion coeffs.
|
||||
*
|
||||
* @param selfDiff Vector of self-diffusion coefficients. Length = number
|
||||
* of species in phase. units = m**2 s-1.
|
||||
*/
|
||||
virtual void selfDiffusion(doublereal* const selfDiff) {
|
||||
throw NotImplementedError("Transport::selfDiffusion");
|
||||
}
|
||||
|
||||
//! Returns the pure species self diffusion in solution of each species
|
||||
/*!
|
||||
* The pure species molar volumes are evaluated using the appropriate
|
||||
* subclasses of LTPspecies as specified in the input file.
|
||||
*
|
||||
* @param selfDiff array of length "number of species"
|
||||
* to hold returned self diffusion coeffs.
|
||||
*/
|
||||
virtual void getSpeciesSelfDiffusion(double** selfDiff) {
|
||||
throw NotImplementedError("Transport::getSpeciesSelfDiffusion");
|
||||
}
|
||||
|
||||
//! Returns the mixture thermal conductivity in W/m/K.
|
||||
/*!
|
||||
* Units are in W / m K or equivalently kg m / s3 K
|
||||
@@ -683,30 +639,6 @@ public:
|
||||
*/
|
||||
virtual void init(thermo_t* thermo, int mode=0, int log_level=0) {}
|
||||
|
||||
//! Called by TransportFactory to set parameters.
|
||||
/*!
|
||||
* This is called by classes that use the liquid phase parameter list to
|
||||
* initialize themselves.
|
||||
*
|
||||
* @param tr Reference to the parameter list that will be used to initialize
|
||||
* the class
|
||||
*/
|
||||
virtual bool initLiquid(LiquidTransportParams& tr) {
|
||||
throw NotImplementedError("Transport::initLiquid");
|
||||
}
|
||||
|
||||
//! Called by TransportFactory to set parameters.
|
||||
/*!
|
||||
* This is called by classes that use the solid phase parameter list to
|
||||
* initialize themselves.
|
||||
*
|
||||
* @param tr Reference to the parameter list that will be used to initialize
|
||||
* the class
|
||||
*/
|
||||
virtual bool initSolid(SolidTransportData& tr) {
|
||||
throw NotImplementedError("Transport::initSolid");
|
||||
}
|
||||
|
||||
//! Specifies the ThermoPhase object.
|
||||
/*!
|
||||
* We have relaxed this operation so that it will succeed when the
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
// Cantera includes
|
||||
#include "TransportBase.h"
|
||||
#include "cantera/base/FactoryBase.h"
|
||||
#include "LiquidTransportParams.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
@@ -54,35 +53,6 @@ public:
|
||||
//! Deletes the statically allocated factory instance.
|
||||
virtual void deleteFactory();
|
||||
|
||||
//! Make one of several transport models, and return a base class pointer to it.
|
||||
/*!
|
||||
* This method operates at the level of a single transport property as a
|
||||
* function of temperature and possibly composition. It's a factory for
|
||||
* LTPspecies classes.
|
||||
*
|
||||
* @param trNode XML node
|
||||
* @param name reference to the name
|
||||
* @param tp_ind TransportPropertyType class
|
||||
* @param thermo Pointer to the ThermoPhase class
|
||||
*/
|
||||
virtual LTPspecies* newLTP(const XML_Node& trNode, const std::string& name,
|
||||
TransportPropertyType tp_ind, thermo_t* thermo);
|
||||
|
||||
//! Factory function for the construction of new LiquidTranInteraction
|
||||
//! objects, which are transport models.
|
||||
/*!
|
||||
* This method operates at the level of a single mixture transport property.
|
||||
* Individual species transport properties are addressed by the LTPspecies
|
||||
* returned by newLTP.
|
||||
*
|
||||
* @param trNode XML_Node containing the information for the interaction
|
||||
* @param tp_ind TransportPropertyType object
|
||||
* @param trParam reference to the LiquidTransportParams object
|
||||
*/
|
||||
virtual LiquidTranInteraction* newLTI(const XML_Node& trNode,
|
||||
TransportPropertyType tp_ind,
|
||||
LiquidTransportParams& trParam);
|
||||
|
||||
//! Build a new transport manager using a transport manager
|
||||
//! that may not be the same as in the phase description
|
||||
//! and return a base class pointer to it
|
||||
@@ -102,31 +72,7 @@ public:
|
||||
*/
|
||||
virtual Transport* newTransport(thermo_t* thermo, int log_level=0);
|
||||
|
||||
//! Initialize an existing transport manager for liquid phase
|
||||
/*!
|
||||
* This routine sets up an existing liquid-phase transport manager. It is
|
||||
* similar to initTransport except that it uses the LiquidTransportParams
|
||||
* class and calls setupLiquidTransport().
|
||||
*
|
||||
* @param tr Pointer to the Transport manager
|
||||
* @param thermo Pointer to the ThermoPhase object
|
||||
* @param log_level Defaults to zero, no logging
|
||||
*/
|
||||
virtual void initLiquidTransport(Transport* tr, thermo_t* thermo, int log_level=0);
|
||||
|
||||
private:
|
||||
//! Initialize an existing transport manager for solid phase
|
||||
/*!
|
||||
* This routine sets up an existing solid-phase transport manager. It is
|
||||
* similar to initTransport except that it uses the SolidTransportData class
|
||||
* and calls setupSolidTransport().
|
||||
*
|
||||
* @param tr Pointer to the Transport manager
|
||||
* @param thermo Pointer to the ThermoPhase object
|
||||
* @param log_level Defaults to zero, no logging
|
||||
*/
|
||||
virtual void initSolidTransport(Transport* tr, thermo_t* thermo, int log_level=0);
|
||||
|
||||
//! Static instance of the factor -> This is the only instance of this
|
||||
//! object allowed
|
||||
static TransportFactory* s_factory;
|
||||
@@ -143,94 +89,6 @@ private:
|
||||
*/
|
||||
TransportFactory();
|
||||
|
||||
//! Read transport property data from a file for a list of species that
|
||||
//! comprise the phase.
|
||||
/*!
|
||||
* Given a vector of pointers to species XML data bases and a list of
|
||||
* species names, this method constructs the LiquidTransport Params object
|
||||
* containing the transport data for these species.
|
||||
*
|
||||
* It is an error to not find a "transport" XML element within each of the
|
||||
* species XML elements listed in the names vector.
|
||||
*
|
||||
* @param db Reference to a vector of XML_Node pointers containing the
|
||||
* species XML nodes.
|
||||
* @param log Reference to an XML log file. (currently unused)
|
||||
* @param names Vector of names of species. On output, tr will contain
|
||||
* transport data for each of of these names in the order
|
||||
* determined by this vector.
|
||||
* @param tr Reference to the LiquidTransportParams object that will
|
||||
* contain the results.
|
||||
*/
|
||||
void getLiquidSpeciesTransportData(const std::vector<const XML_Node*> &db,
|
||||
XML_Node& log, const std::vector<std::string>& names,
|
||||
LiquidTransportParams& tr);
|
||||
|
||||
//! Read transport property data from a file for interactions between species.
|
||||
/*!
|
||||
* Given the XML_Node database for transport interactions defined within the
|
||||
* current phase and a list of species names within the phase, this method
|
||||
* returns an instance of TransportParams containing the transport data for
|
||||
* these species read from the file.
|
||||
*
|
||||
* This routine reads interaction parameters between species within the phase.
|
||||
*
|
||||
* @param phaseTran_db Reference to the transport XML field for the phase
|
||||
* @param log Reference to an XML log file. (currently unused)
|
||||
* @param names Vector of names of species. On output, tr will
|
||||
* contain transport data for each of of these names in
|
||||
* the order determined by this vector.
|
||||
* @param tr Reference to the LiquidTransportParams object that
|
||||
* will contain the results.
|
||||
*/
|
||||
void getLiquidInteractionsTransportData(const XML_Node& phaseTran_db, XML_Node& log,
|
||||
const std::vector<std::string>& names, LiquidTransportParams& tr);
|
||||
|
||||
//! Read transport property data from a file for a solid phase
|
||||
/*!
|
||||
* Given a phase XML data base, this method constructs the
|
||||
* SolidTransportData object containing the transport data for the phase.
|
||||
*
|
||||
* @param transportNode Reference to XML_Node containing the phase.
|
||||
* @param log Reference to an XML log file. (currently unused)
|
||||
* @param phaseName name of the corresponding phase
|
||||
* @param tr Reference to the SolidTransportData object that will
|
||||
* contain the results.
|
||||
*/
|
||||
void getSolidTransportData(const XML_Node& transportNode,
|
||||
XML_Node& log,
|
||||
const std::string phaseName,
|
||||
SolidTransportData& tr);
|
||||
|
||||
//! Prepare to build a new transport manager for liquids assuming that
|
||||
//! viscosity transport data is provided in Arrhenius form.
|
||||
/*!
|
||||
* @param thermo Pointer to the ThermoPhase object
|
||||
* @param log_level log level
|
||||
* @param trParam LiquidTransportParams structure to be filled up with information
|
||||
*/
|
||||
void setupLiquidTransport(thermo_t* thermo, int log_level, LiquidTransportParams& trParam);
|
||||
|
||||
//! Prepare to build a new transport manager for solids
|
||||
/*!
|
||||
* @param thermo Pointer to the ThermoPhase object
|
||||
* @param log_level log level
|
||||
* @param trParam SolidTransportData structure to be filled up with information
|
||||
*/
|
||||
void setupSolidTransport(thermo_t* thermo, int log_level, SolidTransportData& trParam);
|
||||
|
||||
//! Mapping between between the string name
|
||||
//! for a transport property and the integer name.
|
||||
std::map<std::string, TransportPropertyType> m_tranPropMap;
|
||||
|
||||
//! Mapping between between the string name for a
|
||||
//! species-specific transport property model and the integer name.
|
||||
std::map<std::string, LTPTemperatureDependenceType> m_LTRmodelMap;
|
||||
|
||||
//! Mapping between between the string name for a
|
||||
//! liquid mixture transport property model and the integer name.
|
||||
std::map<std::string, LiquidTranMixingModel> m_LTImodelMap;
|
||||
|
||||
//! Models included in this map are initialized in CK compatibility mode
|
||||
std::map<std::string, bool> m_CK_mode;
|
||||
};
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#ifndef CT_WATERTRAN_H
|
||||
#define CT_WATERTRAN_H
|
||||
|
||||
#include "LiquidTransportParams.h"
|
||||
#include "cantera/thermo/WaterPropsIAPWS.h"
|
||||
#include "cantera/transport/TransportBase.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
@@ -690,12 +690,6 @@ cdef extern from "cantera/oneD/StFlow.h":
|
||||
void setFreeFlow()
|
||||
void setAxisymmetricFlow()
|
||||
|
||||
cdef cppclass CxxFreeFlame "Cantera::FreeFlame":
|
||||
CxxFreeFlame(CxxIdealGasPhase*, int, int)
|
||||
|
||||
cdef cppclass CxxAxiStagnFlow "Cantera::AxiStagnFlow":
|
||||
CxxAxiStagnFlow(CxxIdealGasPhase*, int, int)
|
||||
|
||||
|
||||
cdef extern from "cantera/oneD/IonFlow.h":
|
||||
cdef cppclass CxxIonFlow "Cantera::IonFlow":
|
||||
|
||||
@@ -887,41 +887,6 @@ class Shomate(thermo):
|
||||
u["name"] = "coeffs"
|
||||
|
||||
|
||||
class Adsorbate(thermo):
|
||||
"""Adsorbed species characterized by a binding energy and a set of
|
||||
vibrational frequencies."""
|
||||
|
||||
def __init__(self, Trange = (0.0, 0.0),
|
||||
binding_energy = 0.0,
|
||||
frequencies = [], p0 = -1.0):
|
||||
self._t = Trange
|
||||
self._pref = p0
|
||||
self._freqs = frequencies
|
||||
self._be = binding_energy
|
||||
|
||||
|
||||
def build(self, t):
|
||||
n = t.addChild("adsorbate")
|
||||
n['Tmin'] = repr(self._t[0])
|
||||
n['Tmax'] = repr(self._t[1])
|
||||
if self._pref <= 0.0:
|
||||
n['P0'] = repr(_pref)
|
||||
else:
|
||||
n['P0'] = repr(self._pref)
|
||||
|
||||
energy_units = _uenergy+'/'+_umol
|
||||
addFloat(n,'binding_energy',self._be, defunits = energy_units)
|
||||
s = ""
|
||||
nfreq = len(self._freqs)
|
||||
for i in range(nfreq):
|
||||
s += '%17.9E, ' % self._freqs[i]
|
||||
s += '\n'
|
||||
u = n.addChild("floatArray", s)
|
||||
u["size"] = repr(nfreq)
|
||||
u["name"] = "freqs"
|
||||
|
||||
|
||||
|
||||
class const_cp(thermo):
|
||||
"""Constant specific heat."""
|
||||
|
||||
|
||||
@@ -533,34 +533,6 @@ cdef class IdealGasFlow(_FlowBase):
|
||||
self.flow = new CxxStFlow(gas, thermo.n_species, 2)
|
||||
|
||||
|
||||
cdef class FreeFlow(IdealGasFlow):
|
||||
"""
|
||||
.. deprecated:: 2.4
|
||||
To be removed after Cantera 2.4. Use class `IdealGasFlow` instead and
|
||||
call the ``set_free_flow()`` method.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn("Class FreeFlow is deprecated and will be removed after"
|
||||
" Cantera 2.4. Use class IdealGasFlow instead and call the"
|
||||
" ``set_free_flow()`` method.")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.set_free_flow()
|
||||
|
||||
|
||||
cdef class AxisymmetricStagnationFlow(IdealGasFlow):
|
||||
"""
|
||||
.. deprecated:: 2.4
|
||||
To be removed after Cantera 2.4. Use class `IdealGasFlow` instead and
|
||||
call the ``set_axisymmetric_flow()`` method.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
warnings.warn("Class AxisymmetricStagnationFlow is deprecated and will"
|
||||
" be removed after Cantera 2.4. Use class IdealGasFlow instead and"
|
||||
" call the set_axisymmetric_flow() method.")
|
||||
super().__init__(*args, **kwargs)
|
||||
self.set_free_flow()
|
||||
|
||||
|
||||
cdef class IonFlow(_FlowBase):
|
||||
"""
|
||||
An ion flow domain.
|
||||
|
||||
@@ -1327,21 +1327,6 @@ cdef class ThermoPhase(_SolutionBase):
|
||||
def __set__(self, double value):
|
||||
self.thermo.setElectricPotential(value)
|
||||
|
||||
def element_potentials(self):
|
||||
"""
|
||||
Get the array of element potentials. The element potentials are only
|
||||
defined for equilibrium states. This method first sets the composition
|
||||
to a state of equilibrium at constant T and P, then computes the
|
||||
element potentials for this equilibrium state.
|
||||
|
||||
.. deprecated:: 2.3
|
||||
To be removed after Cantera 2.4.
|
||||
"""
|
||||
self.equilibrate('TP')
|
||||
cdef np.ndarray[np.double_t, ndim=1] data = np.zeros(self.n_elements)
|
||||
self.thermo.getElementPotentials(&data[0])
|
||||
return data
|
||||
|
||||
|
||||
cdef class InterfacePhase(ThermoPhase):
|
||||
""" A class representing a surface or edge phase"""
|
||||
|
||||
@@ -1,142 +0,0 @@
|
||||
function flame = npflame_init(gas, left, flow, right, fuel, oxidizer, nuox)
|
||||
% NPFLAME_INIT Create a non-premixed flame stack.
|
||||
% flame = npflame_init(gas, left, flow, right, fuel, oxidizer, nuox)
|
||||
%
|
||||
% This function is deprecated in favor of :mat:func:`CounterFlowDiffusionFlame`
|
||||
% and will be removed after Cantera 2.4.
|
||||
%
|
||||
% :param gas:
|
||||
% Object representing the gas, instance of class
|
||||
% :mat:func:`Solution`, and an ideal gas. This object will be used
|
||||
% to compute all required thermodynamic, kinetic, and transport
|
||||
% properties. The state of this object should be set
|
||||
% to an estimate of the gas state emerging from the
|
||||
% burner before calling StagnationFlame.
|
||||
% :param left:
|
||||
% Object representing the left inlet, which must be
|
||||
% created using function :mat:func:`Inlet`.
|
||||
% :param flow:
|
||||
% Object representing the flow, created with
|
||||
% function :mat:func:`AxisymmetricFlow`.
|
||||
% :param right:
|
||||
% Object representing the right inlet, which must be
|
||||
% created using function :mat:func:`Inlet`.
|
||||
% :param fuel:
|
||||
% String representing the fuel species
|
||||
% :param ox:
|
||||
% String representing the oxidizer species
|
||||
% :param nuox:
|
||||
% Number of oxidizer molecules required to completely combust
|
||||
% one fuel molecule.
|
||||
% :return:
|
||||
% Instance of :mat:func:`Stack` object representing the left
|
||||
% inlet, flow, and right inlet.
|
||||
%
|
||||
|
||||
warning('This function is deprecated and will be removed after Cantera 2.4. Use CounterFlowDiffusionFlame instead');
|
||||
|
||||
% Check input parameters
|
||||
if nargin ~= 7
|
||||
error('npflame_init expects seven input arguments.');
|
||||
end
|
||||
|
||||
if ~isIdealGas(gas)
|
||||
error('gas object must represent an ideal gas mixture.');
|
||||
end
|
||||
if ~isInlet(left)
|
||||
error('left inlet object of wrong type.');
|
||||
end
|
||||
if ~isFlow(flow)
|
||||
error('flow object of wrong type.');
|
||||
end
|
||||
if ~isInlet(right)
|
||||
error('right inlet object of wrong type.');
|
||||
end
|
||||
|
||||
% create the container object
|
||||
flame = Stack([left flow right]);
|
||||
|
||||
% set default initial profiles.
|
||||
rho0 = density(gas);
|
||||
|
||||
wt = molecularWeights(gas);
|
||||
|
||||
% find the fuel and oxidizer
|
||||
ifuel = speciesIndex(gas, fuel);
|
||||
ioxidizer = speciesIndex(gas, oxidizer);
|
||||
|
||||
s = nuox*wt(ioxidizer)/wt(ifuel);
|
||||
y0f = massFraction(left, ifuel);
|
||||
y0ox = massFraction(right, ioxidizer);
|
||||
phi = s*y0f/y0ox;
|
||||
zst = 1.0/(1.0 + phi);
|
||||
|
||||
% compute stoichiometric adiabatic flame temperature
|
||||
nsp = nSpecies(gas);
|
||||
tf = temperature(left);
|
||||
tox = temperature(right);
|
||||
|
||||
yox = zeros(1, nsp);
|
||||
yf = zeros(1, nsp);
|
||||
ystoich = zeros(1, nsp);
|
||||
for n = 1:nsp
|
||||
yox(n) = massFraction(right, n);
|
||||
yf(n) = massFraction(left, n);
|
||||
ystoich(n) = zst*yf(n) + (1.0 - zst)*yox(n);
|
||||
end
|
||||
|
||||
set(gas, 'T', temperature(left), 'P', pressure(gas), 'Y', ystoich);
|
||||
equilibrate(gas, 'HP');
|
||||
teq = temperature(gas);
|
||||
yeq = massFractions(gas);
|
||||
|
||||
% estimated strain rate
|
||||
zz = gridPoints(flow);
|
||||
dz = zz(end) - zz(1);
|
||||
vleft = massFlux(left)/rho0;
|
||||
vright = massFlux(right)/rho0;
|
||||
a = (abs(vleft) + abs(vright))/dz;
|
||||
diff = mixDiffCoeffs(gas);
|
||||
f = sqrt(a/(2.0*diff(ioxidizer)));
|
||||
|
||||
x0 = massFlux(left)*dz/(massFlux(left) + massFlux(right));
|
||||
|
||||
nz = nPoints(flow);
|
||||
zm = zeros(1, nz);
|
||||
u = zeros(1, nz);
|
||||
v = zeros(1, nz);
|
||||
y = zeros(nz, nsp);
|
||||
t = zeros(1, nz);
|
||||
for j = 1:nz
|
||||
x = zz(j);
|
||||
zeta = f*(x - x0);
|
||||
zmix = 0.5*(1.0 - erf(zeta));
|
||||
zm(j) = zmix;
|
||||
u(j) = a*(x0 - zz(j));
|
||||
v(j) = a;
|
||||
if zmix > zst
|
||||
for n = 1:nsp
|
||||
y(j,n) = yeq(n) + (zmix - zst)*(yf(n) - yeq(n))/(1.0 - zst);
|
||||
end
|
||||
t(j) = teq + (tf - teq)*(zmix - zst)/(1.0 - zst);
|
||||
else
|
||||
for n = 1:nsp
|
||||
y(j,n) = yox(n) + zmix*(yeq(n) - yox(n))/zst;
|
||||
end
|
||||
t(j) = tox + zmix*(teq - tox)/zst;
|
||||
end
|
||||
end
|
||||
|
||||
zrel = zz/dz;
|
||||
|
||||
setProfile(flame, 2, {'u', 'V'}, [zrel; u; v]);
|
||||
|
||||
setProfile(flame, 2, 'T', [zrel; t] );
|
||||
|
||||
for n = 1:nsp
|
||||
nm = speciesName(gas, n);
|
||||
setProfile(flame, 2, nm, [zrel; transpose(y(:,n))])
|
||||
end
|
||||
|
||||
% set minimal grid refinement criteria
|
||||
setRefineCriteria(flame, 2, 10.0, 0.99, 0.99);
|
||||
@@ -501,19 +501,6 @@ extern "C" {
|
||||
}
|
||||
}
|
||||
|
||||
int thermo_elementPotentials(int n, size_t lenm, double* lambda)
|
||||
{
|
||||
try {
|
||||
ThermoPhase& thrm = ThermoCabinet::item(n);
|
||||
thrm.checkElementArraySize(lenm);
|
||||
thrm.equilibrate("TP", "element_potential");
|
||||
thrm.getElementPotentials(lambda);
|
||||
return 0;
|
||||
} catch (...) {
|
||||
return handleAllExceptions(-1, ERR);
|
||||
}
|
||||
}
|
||||
|
||||
int thermo_setPressure(int n, double p)
|
||||
{
|
||||
try {
|
||||
|
||||
@@ -72,7 +72,6 @@ void ChemEquil::initialize(thermo_t& s)
|
||||
|
||||
// allocate space in internal work arrays within the ChemEquil object
|
||||
m_molefractions.resize(m_kk);
|
||||
m_lambda.resize(m_mm, -100.0);
|
||||
m_elementmolefracs.resize(m_mm);
|
||||
m_comp.resize(m_mm * m_kk);
|
||||
m_jwork1.resize(m_mm+2);
|
||||
@@ -577,9 +576,6 @@ int ChemEquil::equilibrate(thermo_t& s, const char* XYstr,
|
||||
if (iter > 0 && passThis && fabs(deltax) < options.relTolerance
|
||||
&& fabs(deltay) < options.relTolerance) {
|
||||
options.iterations = iter;
|
||||
for (size_t m = 0; m < m_mm; m++) {
|
||||
m_lambda[m] = x[m]* s.RT();
|
||||
}
|
||||
|
||||
if (m_eloc != npos) {
|
||||
adjustEloc(s, elMolesGoal);
|
||||
|
||||
@@ -1,163 +0,0 @@
|
||||
/**
|
||||
* @file AqueousKinetics.cpp
|
||||
*
|
||||
* Homogeneous kinetics in an aqueous phase, either condensed or dilute in salts
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/kinetics/AqueousKinetics.h"
|
||||
#include "cantera/kinetics/Reaction.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
AqueousKinetics::AqueousKinetics(thermo_t* thermo) :
|
||||
BulkKinetics(thermo)
|
||||
{
|
||||
warn_deprecated("Class AqueousKinetics", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
void AqueousKinetics::_update_rates_T()
|
||||
{
|
||||
doublereal T = thermo().temperature();
|
||||
m_rates.update(T, log(T), m_rfn.data());
|
||||
|
||||
m_temp = T;
|
||||
updateKc();
|
||||
m_ROP_ok = false;
|
||||
}
|
||||
|
||||
void AqueousKinetics::_update_rates_C()
|
||||
{
|
||||
thermo().getActivityConcentrations(m_conc.data());
|
||||
m_ROP_ok = false;
|
||||
}
|
||||
|
||||
void AqueousKinetics::updateKc()
|
||||
{
|
||||
thermo().getStandardChemPotentials(m_grt.data());
|
||||
fill(m_rkcn.begin(), m_rkcn.end(), 0.0);
|
||||
for (size_t k = 0; k < thermo().nSpecies(); k++) {
|
||||
doublereal logStandConc_k = thermo().logStandardConc(k);
|
||||
m_grt[k] -= GasConstant * m_temp * logStandConc_k;
|
||||
}
|
||||
|
||||
// compute Delta G^0 for all reversible reactions
|
||||
getRevReactionDelta(m_grt.data(), m_rkcn.data());
|
||||
|
||||
doublereal rrt = 1.0 / thermo().RT();
|
||||
for (size_t i = 0; i < m_revindex.size(); i++) {
|
||||
size_t irxn = m_revindex[i];
|
||||
m_rkcn[irxn] = exp(m_rkcn[irxn]*rrt);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i != m_irrev.size(); ++i) {
|
||||
m_rkcn[ m_irrev[i] ] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void AqueousKinetics::getEquilibriumConstants(doublereal* kc)
|
||||
{
|
||||
_update_rates_T();
|
||||
|
||||
thermo().getStandardChemPotentials(m_grt.data());
|
||||
fill(m_rkcn.begin(), m_rkcn.end(), 0.0);
|
||||
for (size_t k = 0; k < thermo().nSpecies(); k++) {
|
||||
doublereal logStandConc_k = thermo().logStandardConc(k);
|
||||
m_grt[k] -= GasConstant * m_temp * logStandConc_k;
|
||||
}
|
||||
|
||||
// compute Delta G^0 for all reactions
|
||||
getReactionDelta(m_grt.data(), m_rkcn.data());
|
||||
|
||||
doublereal rrt = 1.0 / thermo().RT();
|
||||
for (size_t i = 0; i < nReactions(); i++) {
|
||||
kc[i] = exp(-m_rkcn[i]*rrt);
|
||||
}
|
||||
|
||||
// force an update of T-dependent properties, so that m_rkcn will
|
||||
// be updated before it is used next.
|
||||
m_temp = 0.0;
|
||||
}
|
||||
|
||||
void AqueousKinetics::updateROP()
|
||||
{
|
||||
_update_rates_T();
|
||||
_update_rates_C();
|
||||
|
||||
if (m_ROP_ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
// copy rate coefficients into ropf
|
||||
m_ropf = m_rfn;
|
||||
|
||||
// multiply by perturbation factor
|
||||
multiply_each(m_ropf.begin(), m_ropf.end(), m_perturb.begin());
|
||||
|
||||
// copy the forward rates to the reverse rates
|
||||
m_ropr = m_ropf;
|
||||
|
||||
// for reverse rates computed from thermochemistry, multiply the forward
|
||||
// rates copied into m_ropr by the reciprocals of the equilibrium constants
|
||||
multiply_each(m_ropr.begin(), m_ropr.end(), m_rkcn.begin());
|
||||
|
||||
// multiply ropf by concentration products
|
||||
m_reactantStoich.multiply(m_conc.data(), m_ropf.data());
|
||||
|
||||
// for reversible reactions, multiply ropr by concentration products
|
||||
m_revProductStoich.multiply(m_conc.data(), m_ropr.data());
|
||||
|
||||
for (size_t j = 0; j != nReactions(); ++j) {
|
||||
m_ropnet[j] = m_ropf[j] - m_ropr[j];
|
||||
}
|
||||
|
||||
m_ROP_ok = true;
|
||||
}
|
||||
|
||||
void AqueousKinetics::getFwdRateConstants(doublereal* kfwd)
|
||||
{
|
||||
_update_rates_T();
|
||||
_update_rates_C();
|
||||
|
||||
// copy rate coefficients into ropf
|
||||
m_ropf = m_rfn;
|
||||
|
||||
// multiply by perturbation factor
|
||||
multiply_each(m_ropf.begin(), m_ropf.end(), m_perturb.begin());
|
||||
|
||||
for (size_t i = 0; i < nReactions(); i++) {
|
||||
kfwd[i] = m_ropf[i];
|
||||
}
|
||||
}
|
||||
|
||||
bool AqueousKinetics::addReaction(shared_ptr<Reaction> r)
|
||||
{
|
||||
bool added = BulkKinetics::addReaction(r);
|
||||
if (!added) {
|
||||
return false;
|
||||
}
|
||||
if (r->reaction_type == ELEMENTARY_RXN) {
|
||||
addElementaryReaction(dynamic_cast<ElementaryReaction&>(*r));
|
||||
} else {
|
||||
throw CanteraError("AqueousKinetics::addReaction",
|
||||
"Invalid reaction type: {}", r->reaction_type);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void AqueousKinetics::modifyReaction(size_t i, shared_ptr<Reaction> rNew)
|
||||
{
|
||||
BulkKinetics::modifyReaction(i, rNew);
|
||||
modifyElementaryReaction(i, dynamic_cast<ElementaryReaction&>(*rNew));
|
||||
|
||||
// invalidate all cached data
|
||||
m_ROP_ok = false;
|
||||
m_temp += 0.1234;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,7 +10,6 @@
|
||||
#include "cantera/kinetics/InterfaceKinetics.h"
|
||||
#include "cantera/kinetics/EdgeKinetics.h"
|
||||
#include "cantera/kinetics/importKinetics.h"
|
||||
#include "cantera/kinetics/AqueousKinetics.h"
|
||||
#include "cantera/base/xml.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -44,7 +43,6 @@ KineticsFactory::KineticsFactory() {
|
||||
reg("gaskinetics", []() { return new GasKinetics(); });
|
||||
reg("interface", []() { return new InterfaceKinetics(); });
|
||||
reg("edge", []() { return new EdgeKinetics(); });
|
||||
reg("aqueouskinetics", []() { return new AqueousKinetics(); });
|
||||
}
|
||||
|
||||
Kinetics* KineticsFactory::newKinetics(const string& model)
|
||||
|
||||
@@ -264,22 +264,6 @@ void LatticePhase::_updateThermo() const
|
||||
}
|
||||
}
|
||||
|
||||
void LatticePhase::setParameters(int n, doublereal* const c)
|
||||
{
|
||||
warn_deprecated("LatticePhase::setParameters",
|
||||
"To be removed after Cantera 2.4.");
|
||||
m_site_density = c[0];
|
||||
setMolarDensity(m_site_density);
|
||||
}
|
||||
|
||||
void LatticePhase::getParameters(int& n, doublereal* const c) const
|
||||
{
|
||||
warn_deprecated("LatticePhase::getParameters",
|
||||
"To be removed after Cantera 2.4.");
|
||||
c[0] = molarDensity();
|
||||
n = 1;
|
||||
}
|
||||
|
||||
void LatticePhase::setParametersFromXML(const XML_Node& eosdata)
|
||||
{
|
||||
eosdata._require("model", "Lattice");
|
||||
|
||||
@@ -1,216 +0,0 @@
|
||||
/**
|
||||
* @file MetalSHEelectrons.cpp
|
||||
* Definition file for the MetalSHEElectrons class, which represents the
|
||||
* electrons in a metal that are consistent with the
|
||||
* SHE electrode (see \ref thermoprops and
|
||||
* class \link Cantera::MetalSHEelectrons MetalSHEelectrons\endlink)
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/base/ctml.h"
|
||||
#include "cantera/thermo/MetalSHEelectrons.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
// ---- Constructors -------
|
||||
|
||||
MetalSHEelectrons::MetalSHEelectrons()
|
||||
{
|
||||
warn_deprecated("Class MetalSHEelectrons", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
MetalSHEelectrons::MetalSHEelectrons(const std::string& infile, const std::string& id_)
|
||||
{
|
||||
warn_deprecated("Class MetalSHEelectrons", "To be removed after Cantera 2.4");
|
||||
initThermoFile(infile, id_);
|
||||
}
|
||||
|
||||
MetalSHEelectrons::MetalSHEelectrons(XML_Node& xmlphase, const std::string& id_)
|
||||
{
|
||||
warn_deprecated("Class MetalSHEelectrons", "To be removed after Cantera 2.4");
|
||||
importPhase(xmlphase, this);
|
||||
}
|
||||
|
||||
// ----- Mechanical Equation of State ------
|
||||
|
||||
doublereal MetalSHEelectrons::pressure() const
|
||||
{
|
||||
return m_press;
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::setPressure(doublereal p)
|
||||
{
|
||||
m_press = p;
|
||||
}
|
||||
|
||||
doublereal MetalSHEelectrons::isothermalCompressibility() const
|
||||
{
|
||||
return 1.0/pressure();
|
||||
}
|
||||
|
||||
doublereal MetalSHEelectrons::thermalExpansionCoeff() const
|
||||
{
|
||||
return 1.0/temperature();
|
||||
}
|
||||
|
||||
// ---- Chemical Potentials and Activities ----
|
||||
|
||||
void MetalSHEelectrons::getActivityConcentrations(doublereal* c) const
|
||||
{
|
||||
c[0] = 1.0;
|
||||
}
|
||||
|
||||
doublereal MetalSHEelectrons::standardConcentration(size_t k) const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
doublereal MetalSHEelectrons::logStandardConc(size_t k) const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Properties of the Standard State of the Species in the Solution
|
||||
|
||||
void MetalSHEelectrons::getStandardChemPotentials(doublereal* mu0) const
|
||||
{
|
||||
getGibbs_RT(mu0);
|
||||
mu0[0] *= RT();
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getEnthalpy_RT(doublereal* hrt) const
|
||||
{
|
||||
getEnthalpy_RT_ref(hrt);
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getEntropy_R(doublereal* sr) const
|
||||
{
|
||||
getEntropy_R_ref(sr);
|
||||
doublereal tmp = log(pressure() / m_p0);
|
||||
sr[0] -= tmp;
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getGibbs_RT(doublereal* grt) const
|
||||
{
|
||||
getGibbs_RT_ref(grt);
|
||||
doublereal tmp = log(pressure() / m_p0);
|
||||
grt[0] += tmp;
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getCp_R(doublereal* cpr) const
|
||||
{
|
||||
_updateThermo();
|
||||
cpr[0] = m_cp0_R;
|
||||
}
|
||||
void MetalSHEelectrons::getIntEnergy_RT(doublereal* urt) const
|
||||
{
|
||||
getEnthalpy_RT(urt);
|
||||
urt[0] -= 1.0;
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getIntEnergy_RT_ref(doublereal* urt) const
|
||||
{
|
||||
_updateThermo();
|
||||
urt[0] = m_h0_RT - m_p0 / molarDensity() / RT();
|
||||
}
|
||||
|
||||
// ---- Initialization and Internal functions
|
||||
|
||||
void MetalSHEelectrons::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
||||
{
|
||||
// Find the Thermo XML node
|
||||
if (!phaseNode.hasChild("thermo")) {
|
||||
throw CanteraError("MetalSHEelectrons::initThermoXML",
|
||||
"no thermo XML node");
|
||||
}
|
||||
XML_Node& tnode = phaseNode.child("thermo");
|
||||
doublereal dens = 2.65E3;
|
||||
if (tnode.hasChild("density")) {
|
||||
dens = getFloat(tnode, "density", "toSI");
|
||||
}
|
||||
setDensity(dens);
|
||||
SingleSpeciesTP::initThermoXML(phaseNode, id_);
|
||||
}
|
||||
|
||||
XML_Node* MetalSHEelectrons::makeDefaultXMLTree()
|
||||
{
|
||||
XML_Node* xtop = new XML_Node("ctml", 0);
|
||||
XML_Node& xv = xtop->addChild("validate");
|
||||
xv.addAttribute("reactions", "yes");
|
||||
xv.addAttribute("species", "yes");
|
||||
|
||||
XML_Node& xp = xtop->addChild("phase");
|
||||
xp.addAttribute("dim", "3");
|
||||
xp.addAttribute("id", "MetalSHEelectrons");
|
||||
XML_Node& xe = xp.addChild("elementArray", "E");
|
||||
xe.addAttribute("datasrc", "elements.xml");
|
||||
XML_Node& xs = xp.addChild("speciesArray", "she_electron");
|
||||
xs.addAttribute("datasrc", "#species_Metal_SHEelectrons");
|
||||
XML_Node& xt = xp.addChild("thermo");
|
||||
xt.addAttribute("model", "metalSHEelectrons");
|
||||
XML_Node& xtr = xp.addChild("transport");
|
||||
xtr.addAttribute("model", "none");
|
||||
XML_Node& xk = xp.addChild("kinetics");
|
||||
xk.addAttribute("model", "none");
|
||||
|
||||
XML_Node& xsd = xtop->addChild("speciesData");
|
||||
xsd.addAttribute("id", "species_Metal_SHEelectrons");
|
||||
|
||||
XML_Node& xsp = xsd.addChild("species");
|
||||
xsp.addAttribute("name", "she_electron");
|
||||
xsp.addChild("atomArray", "E:1");
|
||||
xsp.addChild("charge", "-1");
|
||||
XML_Node& xspt = xsp.addChild("thermo");
|
||||
|
||||
XML_Node& xN1 = xspt.addChild("NASA");
|
||||
xN1.addAttribute("Tmax", "1000.");
|
||||
xN1.addAttribute("Tmin", "200.");
|
||||
xN1.addAttribute("P0", "100000.0");
|
||||
XML_Node& xF1 = xsd.addChild("floatArray",
|
||||
"1.172165560E+00, 3.990260375E-03, -9.739075500E-06, "
|
||||
"1.007860470E-08, -3.688058805E-12, -4.589675865E+02, 3.415051190E-01");
|
||||
xF1.addAttribute("name", "coeffs");
|
||||
xF1.addAttribute("size", "7");
|
||||
|
||||
XML_Node& xN2 = xspt.addChild("NASA");
|
||||
xN2.addAttribute("Tmax", "6000.");
|
||||
xN2.addAttribute("Tmin", "1000.");
|
||||
xN2.addAttribute("P0", "100000.0");
|
||||
XML_Node& xF2 = xsd.addChild("floatArray",
|
||||
"1.466432895E+00, 4.133039835E-04, -7.320116750E-08, 7.705017950E-12,"
|
||||
"-3.444022160E-16, -4.065327985E+02, -5.121644350E-01");
|
||||
xF2.addAttribute("name", "coeffs");
|
||||
xF2.addAttribute("size", "7");
|
||||
|
||||
return xtop;
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::setParameters(int n, doublereal* const c)
|
||||
{
|
||||
setDensity(c[0]);
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::getParameters(int& n, doublereal* const c) const
|
||||
{
|
||||
n = 1;
|
||||
c[0] = density();
|
||||
}
|
||||
|
||||
void MetalSHEelectrons::setParametersFromXML(const XML_Node& eosdata)
|
||||
{
|
||||
if ( eosdata["model"] != "MetalSHEelectrons") {
|
||||
throw CanteraError("MetalSHEelectrons::setParametersFromXML",
|
||||
"thermo model attribute must be MetalSHEelectrons");
|
||||
}
|
||||
doublereal rho = 2.65E3;
|
||||
if (eosdata.hasChild("density")) {
|
||||
rho = getFloat(eosdata, "density", "toSI");
|
||||
}
|
||||
setDensity(rho);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,233 +0,0 @@
|
||||
/**
|
||||
* @file MineralEQ3.cpp
|
||||
* Definition file for the MineralEQ3 class, which represents a fixed-composition
|
||||
* incompressible substance (see \ref thermoprops and
|
||||
* class \link Cantera::MineralEQ3 MineralEQ3\endlink)
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/base/ctml.h"
|
||||
#include "cantera/thermo/MineralEQ3.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
// ---- Constructors -------
|
||||
|
||||
MineralEQ3::MineralEQ3(const std::string& infile, const std::string& id_)
|
||||
{
|
||||
warn_deprecated("Class MineralEQ3", "To be removed after Cantera 2.4");
|
||||
initThermoFile(infile, id_);
|
||||
}
|
||||
|
||||
MineralEQ3::MineralEQ3(XML_Node& xmlphase, const std::string& id_)
|
||||
{
|
||||
warn_deprecated("Class MineralEQ3", "To be removed after Cantera 2.4");
|
||||
importPhase(xmlphase, this);
|
||||
}
|
||||
|
||||
// ----- Mechanical Equation of State ------
|
||||
|
||||
doublereal MineralEQ3::pressure() const
|
||||
{
|
||||
return m_press;
|
||||
}
|
||||
|
||||
void MineralEQ3::setPressure(doublereal p)
|
||||
{
|
||||
m_press = p;
|
||||
}
|
||||
|
||||
doublereal MineralEQ3::isothermalCompressibility() const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
doublereal MineralEQ3::thermalExpansionCoeff() const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// ---- Chemical Potentials and Activities ----
|
||||
|
||||
void MineralEQ3::getActivityConcentrations(doublereal* c) const
|
||||
{
|
||||
c[0] = 1.0;
|
||||
}
|
||||
|
||||
doublereal MineralEQ3::standardConcentration(size_t k) const
|
||||
{
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
doublereal MineralEQ3::logStandardConc(size_t k) const
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Properties of the Standard State of the Species in the Solution
|
||||
|
||||
void MineralEQ3::getStandardChemPotentials(doublereal* mu0) const
|
||||
{
|
||||
getGibbs_RT(mu0);
|
||||
mu0[0] *= RT();
|
||||
}
|
||||
|
||||
void MineralEQ3::getEnthalpy_RT(doublereal* hrt) const
|
||||
{
|
||||
getEnthalpy_RT_ref(hrt);
|
||||
doublereal presCorrect = (m_press - m_p0) / molarDensity();
|
||||
hrt[0] += presCorrect / RT();
|
||||
}
|
||||
|
||||
void MineralEQ3::getEntropy_R(doublereal* sr) const
|
||||
{
|
||||
getEntropy_R_ref(sr);
|
||||
}
|
||||
|
||||
void MineralEQ3::getGibbs_RT(doublereal* grt) const
|
||||
{
|
||||
getEnthalpy_RT(grt);
|
||||
grt[0] -= m_s0_R;
|
||||
}
|
||||
|
||||
void MineralEQ3::getCp_R(doublereal* cpr) const
|
||||
{
|
||||
_updateThermo();
|
||||
cpr[0] = m_cp0_R;
|
||||
}
|
||||
|
||||
void MineralEQ3::getIntEnergy_RT(doublereal* urt) const
|
||||
{
|
||||
_updateThermo();
|
||||
urt[0] = m_h0_RT - m_p0 / molarDensity() / RT();
|
||||
}
|
||||
|
||||
// ---- Thermodynamic Values for the Species Reference States ----
|
||||
|
||||
void MineralEQ3::getIntEnergy_RT_ref(doublereal* urt) const
|
||||
{
|
||||
_updateThermo();
|
||||
urt[0] = m_h0_RT - m_p0 / molarDensity() / RT();
|
||||
}
|
||||
|
||||
// ---- Initialization and Internal functions
|
||||
|
||||
void MineralEQ3::setParameters(int n, doublereal* const c)
|
||||
{
|
||||
setDensity(c[0]);
|
||||
}
|
||||
|
||||
void MineralEQ3::getParameters(int& n, doublereal* const c) const
|
||||
{
|
||||
n = 1;
|
||||
c[0] = density();
|
||||
}
|
||||
|
||||
void MineralEQ3::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
||||
{
|
||||
// Find the Thermo XML node
|
||||
if (!phaseNode.hasChild("thermo")) {
|
||||
throw CanteraError("HMWSoln::initThermoXML",
|
||||
"no thermo XML node");
|
||||
}
|
||||
|
||||
const XML_Node* xsp = speciesData()[0];
|
||||
|
||||
XML_Node* aStandardState = 0;
|
||||
if (xsp->hasChild("standardState")) {
|
||||
aStandardState = &xsp->child("standardState");
|
||||
} else {
|
||||
throw CanteraError("MineralEQ3::initThermoXML",
|
||||
"no standard state mode");
|
||||
}
|
||||
doublereal volVal = 0.0;
|
||||
if (aStandardState->attrib("model") != "constantVolume") {
|
||||
throw CanteraError("MineralEQ3::initThermoXML",
|
||||
"wrong standard state mode");
|
||||
}
|
||||
if (aStandardState->hasChild("V0_Pr_Tr")) {
|
||||
XML_Node& aV = aStandardState->child("V0_Pr_Tr");
|
||||
double Afactor = toSI("cm3/gmol");
|
||||
if (aV.hasAttrib("units")) {
|
||||
Afactor = toSI(aV.attrib("units"));
|
||||
}
|
||||
volVal = getFloat(*aStandardState, "V0_Pr_Tr");
|
||||
m_V0_pr_tr= volVal;
|
||||
volVal *= Afactor;
|
||||
} else {
|
||||
throw CanteraError("MineralEQ3::initThermoXML",
|
||||
"wrong standard state mode");
|
||||
}
|
||||
setDensity(molecularWeight(0) / volVal);
|
||||
|
||||
const XML_Node& MinEQ3node = xsp->child("thermo").child("MinEQ3");
|
||||
|
||||
m_deltaG_formation_pr_tr =
|
||||
getFloat(MinEQ3node, "DG0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
|
||||
m_deltaH_formation_pr_tr =
|
||||
getFloat(MinEQ3node, "DH0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
|
||||
m_Entrop_pr_tr = getFloat(MinEQ3node, "S0_Pr_Tr", "toSI") / toSI("cal/gmol/K");
|
||||
m_a = getFloat(MinEQ3node, "a", "toSI") / toSI("cal/gmol/K");
|
||||
m_b = getFloat(MinEQ3node, "b", "toSI") / toSI("cal/gmol/K2");
|
||||
m_c = getFloat(MinEQ3node, "c", "toSI") / toSI("cal-K/gmol");
|
||||
|
||||
convertDGFormation();
|
||||
}
|
||||
|
||||
void MineralEQ3::setParametersFromXML(const XML_Node& eosdata)
|
||||
{
|
||||
if (eosdata["model"] != "MineralEQ3") {
|
||||
throw CanteraError("MineralEQ3::MineralEQ3",
|
||||
"thermo model attribute must be MineralEQ3");
|
||||
}
|
||||
}
|
||||
|
||||
doublereal MineralEQ3::LookupGe(const std::string& elemName)
|
||||
{
|
||||
size_t iE = elementIndex(elemName);
|
||||
if (iE == npos) {
|
||||
throw CanteraError("PDSS_HKFT::LookupGe", "element " + elemName + " not found");
|
||||
}
|
||||
doublereal geValue = entropyElement298(iE);
|
||||
if (geValue == ENTROPY298_UNKNOWN) {
|
||||
throw CanteraError("PDSS_HKFT::LookupGe",
|
||||
"element " + elemName + " does not have a supplied entropy298");
|
||||
}
|
||||
geValue *= (-298.15);
|
||||
return geValue;
|
||||
}
|
||||
|
||||
void MineralEQ3::convertDGFormation()
|
||||
{
|
||||
// Ok let's get the element compositions and conversion factors.
|
||||
doublereal totalSum = 0.0;
|
||||
for (size_t m = 0; m < nElements(); m++) {
|
||||
double na = nAtoms(0, m);
|
||||
if (na > 0.0) {
|
||||
totalSum += na * LookupGe(elementName(m));
|
||||
}
|
||||
}
|
||||
// Ok, now do the calculation. Convert to joules kmol-1
|
||||
doublereal dg = m_deltaG_formation_pr_tr * toSI("cal/gmol");
|
||||
//! Store the result into an internal variable.
|
||||
m_Mu0_pr_tr = dg + totalSum;
|
||||
|
||||
double Hcalc = m_Mu0_pr_tr + 298.15 * m_Entrop_pr_tr * toSI("cal/gmol");
|
||||
double DHjmol = m_deltaH_formation_pr_tr * toSI("kal/gmol");
|
||||
|
||||
// If the discrepancy is greater than 100 cal gmol-1, print an error
|
||||
if (fabs(Hcalc -DHjmol) > 100 * toSI("cal/gmol")) {
|
||||
throw CanteraError("installMinEQ3asShomateThermoFromXML()",
|
||||
"DHjmol is not consistent with G and S: {} vs {}",
|
||||
Hcalc, DHjmol);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,587 +0,0 @@
|
||||
/**
|
||||
* @file MixedSolventElectrolyte.cpp see \ref thermoprops and class \link
|
||||
* Cantera::MixedSolventElectrolyte MixedSolventElectrolyte \endlink).
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/thermo/MixedSolventElectrolyte.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
MixedSolventElectrolyte::MixedSolventElectrolyte() :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("class MixedSolventElectrolyte",
|
||||
"To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
MixedSolventElectrolyte::MixedSolventElectrolyte(const std::string& inputFile,
|
||||
const std::string& id_) :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("class MixedSolventElectrolyte",
|
||||
"To be removed after Cantera 2.4");
|
||||
initThermoFile(inputFile, id_);
|
||||
}
|
||||
|
||||
MixedSolventElectrolyte::MixedSolventElectrolyte(XML_Node& phaseRoot,
|
||||
const std::string& id_) :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("class MixedSolventElectrolyte",
|
||||
"To be removed after Cantera 2.4");
|
||||
importPhase(phaseRoot, this);
|
||||
}
|
||||
|
||||
// - Activities, Standard States, Activity Concentrations -----------
|
||||
|
||||
void MixedSolventElectrolyte::getActivityCoefficients(doublereal* ac) const
|
||||
{
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
|
||||
// take the exp of the internally stored coefficients.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
ac[k] = exp(lnActCoeff_Scaled_[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------ Partial Molar Properties of the Solution ------------
|
||||
|
||||
void MixedSolventElectrolyte::getChemPotentials(doublereal* mu) const
|
||||
{
|
||||
// First get the standard chemical potentials in molar form. This requires
|
||||
// updates of standard state as a function of T and P
|
||||
getStandardChemPotentials(mu);
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
mu[k] += RT() * (log(xx) + lnActCoeff_Scaled_[k]);
|
||||
}
|
||||
}
|
||||
|
||||
doublereal MixedSolventElectrolyte::enthalpy_mole() const
|
||||
{
|
||||
double h = 0;
|
||||
vector_fp hbar(m_kk);
|
||||
getPartialMolarEnthalpies(&hbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
h += moleFractions_[i]*hbar[i];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
doublereal MixedSolventElectrolyte::entropy_mole() const
|
||||
{
|
||||
double s = 0;
|
||||
vector_fp sbar(m_kk);
|
||||
getPartialMolarEntropies(&sbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
s += moleFractions_[i]*sbar[i];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
doublereal MixedSolventElectrolyte::cp_mole() const
|
||||
{
|
||||
double cp = 0;
|
||||
vector_fp cpbar(m_kk);
|
||||
getPartialMolarCp(&cpbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
cp += moleFractions_[i]*cpbar[i];
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
doublereal MixedSolventElectrolyte::cv_mole() const
|
||||
{
|
||||
return cp_mole() - GasConstant;
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getPartialMolarEnthalpies(doublereal* hbar) const
|
||||
{
|
||||
// Get the nondimensional standard state enthalpies
|
||||
getEnthalpy_RT(hbar);
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] *= RT();
|
||||
}
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] -= RT() * temperature() * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getPartialMolarCp(doublereal* cpbar) const
|
||||
{
|
||||
getCp_R(cpbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k];
|
||||
}
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getPartialMolarEntropies(doublereal* sbar) const
|
||||
{
|
||||
// Get the nondimensional standard state entropies
|
||||
getEntropy_R(sbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the
|
||||
// internally stored molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
sbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getPartialMolarVolumes(doublereal* vbar) const
|
||||
{
|
||||
double T = temperature();
|
||||
|
||||
// Get the standard state values in m^3 kmol-1
|
||||
getStandardVolumes(vbar);
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
|
||||
double g0 = (m_VHE_b_ij[i] - T * m_VSE_b_ij[i]);
|
||||
double g1 = (m_VHE_c_ij[i] - T * m_VSE_c_ij[i]);
|
||||
|
||||
vbar[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::initThermo()
|
||||
{
|
||||
initLengths();
|
||||
MolarityIonicVPSSTP::initThermo();
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::initLengths()
|
||||
{
|
||||
dlnActCoeffdlnN_.resize(m_kk, m_kk);
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::initThermoXML(XML_Node& phaseNode, const std::string& id_)
|
||||
{
|
||||
if ((int) id_.size() > 0 && phaseNode.id() != id_) {
|
||||
throw CanteraError("MixedSolventElectrolyte::initThermoXML",
|
||||
"phasenode and Id are incompatible");
|
||||
}
|
||||
|
||||
// Check on the thermo field. Must have:
|
||||
// <thermo model="MixedSolventElectrolyte" />
|
||||
if (!phaseNode.hasChild("thermo")) {
|
||||
throw CanteraError("MixedSolventElectrolyte::initThermoXML",
|
||||
"no thermo XML node");
|
||||
}
|
||||
XML_Node& thermoNode = phaseNode.child("thermo");
|
||||
string mString = thermoNode["model"];
|
||||
if (!caseInsensitiveEquals(thermoNode["model"], "mixedsolventelectrolyte")) {
|
||||
throw CanteraError("MixedSolventElectrolyte::initThermoXML",
|
||||
"Unknown thermo model: " + thermoNode["model"]);
|
||||
}
|
||||
|
||||
// Go get all of the coefficients and factors in the activityCoefficients
|
||||
// XML block
|
||||
if (thermoNode.hasChild("activityCoefficients")) {
|
||||
XML_Node& acNode = thermoNode.child("activityCoefficients");
|
||||
if (!caseInsensitiveEquals(acNode["model"], "margules")) {
|
||||
throw CanteraError("MixedSolventElectrolyte::initThermoXML",
|
||||
"Unknown activity coefficient model: " + acNode["model"]);
|
||||
}
|
||||
for (size_t i = 0; i < acNode.nChildren(); i++) {
|
||||
XML_Node& xmlACChild = acNode.child(i);
|
||||
|
||||
// Process a binary salt field, or any of the other XML fields that
|
||||
// make up the Pitzer Database. Entries will be ignored if any of
|
||||
// the species in the entry isn't in the solution.
|
||||
if (caseInsensitiveEquals(xmlACChild.name(), "binaryneutralspeciesparameters")) {
|
||||
readXMLBinarySpecies(xmlACChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go down the chain
|
||||
MolarityIonicVPSSTP::initThermoXML(phaseNode, id_);
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::s_update_lnActCoeff() const
|
||||
{
|
||||
double T = temperature();
|
||||
lnActCoeff_Scaled_.assign(m_kk, 0.0);
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT();
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT();
|
||||
lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::s_update_dlnActCoeff_dT() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
doublereal RTT = GasConstant*T*T;
|
||||
dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
|
||||
d2lnActCoeffdT2_Scaled_.assign(m_kk, 0.0);
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = -m_HE_b_ij[i] / RTT;
|
||||
double g1 = -m_HE_c_ij[i] / RTT;
|
||||
double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
|
||||
dlnActCoeffdT_Scaled_[iK] += temp;
|
||||
d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getdlnActCoeffdT(doublereal* dlnActCoeffdT) const
|
||||
{
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getd2lnActCoeffdT2(doublereal* d2lnActCoeffdT2) const
|
||||
{
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds,
|
||||
doublereal* dlnActCoeffds) const
|
||||
{
|
||||
double T = temperature();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
dlnActCoeffds[iK] = 0.0;
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double dXA = dXds[iA];
|
||||
double dXB = dXds[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT();
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT();
|
||||
dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB
|
||||
+ dlnActCoeffdT_Scaled_[iK]*dTds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnN_diag() const
|
||||
{
|
||||
double T = temperature();
|
||||
dlnActCoeffdlnN_diag_.assign(m_kk, 0);
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
double XK = moleFractions_[iK];
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT();
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT();
|
||||
|
||||
dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB)));
|
||||
}
|
||||
dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK];//-XK;
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnN() const
|
||||
{
|
||||
double T = temperature();
|
||||
dlnActCoeffdlnN_.zero();
|
||||
|
||||
// Loop over the activity coefficient gamma_k
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
for (size_t iM = 0; iM < m_kk; iM++) {
|
||||
double XM = moleFractions_[iM];
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
double delAK = 0.0;
|
||||
double delBK = 0.0;
|
||||
double delAM = 0.0;
|
||||
double delBM = 0.0;
|
||||
if (iA==iK) {
|
||||
delAK = 1.0;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1.0;
|
||||
}
|
||||
if (iA==iM) {
|
||||
delAM = 1.0;
|
||||
} else if (iB==iM) {
|
||||
delBM = 1.0;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT();
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT();
|
||||
dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB));
|
||||
dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA);
|
||||
}
|
||||
dlnActCoeffdlnN_(iK,iM) = XM*dlnActCoeffdlnN_(iK,iM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::s_update_dlnActCoeff_dlnX_diag() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
dlnActCoeffdlnX_diag_.assign(m_kk, 0);
|
||||
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / RT();
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / RT();
|
||||
dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB);
|
||||
dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB);
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const
|
||||
{
|
||||
s_update_dlnActCoeff_dlnN_diag();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const
|
||||
{
|
||||
s_update_dlnActCoeff_dlnX_diag();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::getdlnActCoeffdlnN(const size_t ld, doublereal* dlnActCoeffdlnN)
|
||||
{
|
||||
s_update_dlnActCoeff_dlnN();
|
||||
double* data = & dlnActCoeffdlnN_(0,0);
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
for (size_t m = 0; m < m_kk; m++) {
|
||||
dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::resizeNumInteractions(const size_t num)
|
||||
{
|
||||
numBinaryInteractions_ = num;
|
||||
m_HE_b_ij.resize(num, 0.0);
|
||||
m_HE_c_ij.resize(num, 0.0);
|
||||
m_HE_d_ij.resize(num, 0.0);
|
||||
m_SE_b_ij.resize(num, 0.0);
|
||||
m_SE_c_ij.resize(num, 0.0);
|
||||
m_SE_d_ij.resize(num, 0.0);
|
||||
m_VHE_b_ij.resize(num, 0.0);
|
||||
m_VHE_c_ij.resize(num, 0.0);
|
||||
m_VHE_d_ij.resize(num, 0.0);
|
||||
m_VSE_b_ij.resize(num, 0.0);
|
||||
m_VSE_c_ij.resize(num, 0.0);
|
||||
m_VSE_d_ij.resize(num, 0.0);
|
||||
m_pSpecies_A_ij.resize(num, npos);
|
||||
m_pSpecies_B_ij.resize(num, npos);
|
||||
}
|
||||
|
||||
void MixedSolventElectrolyte::readXMLBinarySpecies(XML_Node& xmLBinarySpecies)
|
||||
{
|
||||
string xname = xmLBinarySpecies.name();
|
||||
if (xname != "binaryNeutralSpeciesParameters") {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies",
|
||||
"Incorrect name for processing this routine: " + xname);
|
||||
}
|
||||
vector_fp vParams;
|
||||
string iName = xmLBinarySpecies.attrib("speciesA");
|
||||
if (iName == "") {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesA attrib");
|
||||
}
|
||||
string jName = xmLBinarySpecies.attrib("speciesB");
|
||||
if (jName == "") {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "no speciesB attrib");
|
||||
}
|
||||
|
||||
// Find the index of the species in the current phase. It's not an error to
|
||||
// not find the species
|
||||
size_t iSpecies = speciesIndex(iName);
|
||||
if (iSpecies == npos) {
|
||||
return;
|
||||
}
|
||||
string ispName = speciesName(iSpecies);
|
||||
if (charge(iSpecies) != 0) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesA charge problem");
|
||||
}
|
||||
size_t jSpecies = speciesIndex(jName);
|
||||
if (jSpecies == npos) {
|
||||
return;
|
||||
}
|
||||
string jspName = speciesName(jSpecies);
|
||||
if (charge(jSpecies) != 0) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies", "speciesB charge problem");
|
||||
}
|
||||
|
||||
resizeNumInteractions(numBinaryInteractions_ + 1);
|
||||
size_t iSpot = numBinaryInteractions_ - 1;
|
||||
m_pSpecies_A_ij[iSpot] = iSpecies;
|
||||
m_pSpecies_B_ij[iSpot] = jSpecies;
|
||||
|
||||
for (size_t iChild = 0; iChild < xmLBinarySpecies.nChildren(); iChild++) {
|
||||
XML_Node& xmlChild = xmLBinarySpecies.child(iChild);
|
||||
string nodeName = toLowerCopy(xmlChild.name());
|
||||
|
||||
// Process the binary species interaction child elements
|
||||
if (nodeName == "excessenthalpy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEnthalpy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_HE_b_ij[iSpot] = vParams[0];
|
||||
m_HE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessentropy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessEntropy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_SE_b_ij[iSpot] = vParams[0];
|
||||
m_SE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessvolume_enthalpy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_VHE_b_ij[iSpot] = vParams[0];
|
||||
m_VHE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessvolume_entropy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("MixedSolventElectrolyte::readXMLBinarySpecies::excessVolume_Entropy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_VSE_b_ij[iSpot] = vParams[0];
|
||||
m_VSE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -50,19 +50,6 @@ int MolalityVPSSTP::pHScale() const
|
||||
return m_pHScalingType;
|
||||
}
|
||||
|
||||
void MolalityVPSSTP::setSolvent(size_t k)
|
||||
{
|
||||
warn_deprecated("MolalityVPSSTP::setSolvent", "Solvent is always the first"
|
||||
" species. To be removed after Cantera 2.4.");
|
||||
}
|
||||
|
||||
size_t MolalityVPSSTP::solventIndex() const
|
||||
{
|
||||
warn_deprecated("MolalityVPSSTP::solventIndex", "Solvent is always the"
|
||||
" first species. To be removed after Cantera 2.4.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MolalityVPSSTP::setMoleFSolventMin(doublereal xmolSolventMIN)
|
||||
{
|
||||
if (xmolSolventMIN <= 0.0) {
|
||||
|
||||
@@ -1,371 +0,0 @@
|
||||
/**
|
||||
* @file MolarityIonicVPSSTP.cpp
|
||||
* Definitions for intermediate ThermoPhase object for phases which
|
||||
* employ excess Gibbs free energy formulations
|
||||
* (see \ref thermoprops
|
||||
* and class \link Cantera::MolarityIonicVPSSTP MolarityIonicVPSSTP\endlink).
|
||||
*
|
||||
* Header file for a derived class of ThermoPhase that handles variable pressure
|
||||
* standard state methods for calculating thermodynamic properties that are
|
||||
* further based upon expressions for the excess Gibbs free energy expressed as
|
||||
* a function of the mole fractions.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/thermo/MolarityIonicVPSSTP.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
MolarityIonicVPSSTP::MolarityIonicVPSSTP() :
|
||||
PBType_(PBTYPE_PASSTHROUGH),
|
||||
numPBSpecies_(m_kk),
|
||||
neutralPBindexStart(0)
|
||||
{
|
||||
warn_deprecated("Class MolarityIonicVPSSTP", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
MolarityIonicVPSSTP::MolarityIonicVPSSTP(const std::string& inputFile,
|
||||
const std::string& id_) :
|
||||
PBType_(PBTYPE_PASSTHROUGH),
|
||||
numPBSpecies_(m_kk),
|
||||
neutralPBindexStart(0)
|
||||
{
|
||||
warn_deprecated("Class MolarityIonicVPSSTP", "To be removed after Cantera 2.4");
|
||||
initThermoFile(inputFile, id_);
|
||||
}
|
||||
|
||||
MolarityIonicVPSSTP::MolarityIonicVPSSTP(XML_Node& phaseRoot,
|
||||
const std::string& id_) :
|
||||
PBType_(PBTYPE_PASSTHROUGH),
|
||||
numPBSpecies_(m_kk),
|
||||
neutralPBindexStart(0)
|
||||
{
|
||||
warn_deprecated("Class MolarityIonicVPSSTP", "To be removed after Cantera 2.4");
|
||||
importPhase(phaseRoot, this);
|
||||
}
|
||||
|
||||
// - Activities, Standard States, Activity Concentrations -----------
|
||||
|
||||
void MolarityIonicVPSSTP::getLnActivityCoefficients(doublereal* lnac) const
|
||||
{
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
|
||||
// take the exp of the internally stored coefficients.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
lnac[k] = lnActCoeff_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::getChemPotentials(doublereal* mu) const
|
||||
{
|
||||
// First get the standard chemical potentials in molar form. This requires
|
||||
// updates of standard state as a function of T and P
|
||||
getStandardChemPotentials(mu);
|
||||
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
mu[k] += RT() * (log(xx) + lnActCoeff_Scaled_[k]);
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::getPartialMolarEnthalpies(doublereal* hbar) const
|
||||
{
|
||||
// Get the nondimensional standard state enthalpies
|
||||
getEnthalpy_RT(hbar);
|
||||
|
||||
// dimensionalize it.
|
||||
double T = temperature();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] *= GasConstant * T;
|
||||
}
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] -= GasConstant * T * T * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::getPartialMolarCp(doublereal* cpbar) const
|
||||
{
|
||||
// Get the nondimensional standard state entropies
|
||||
getCp_R(cpbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k];
|
||||
}
|
||||
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::getPartialMolarEntropies(doublereal* sbar) const
|
||||
{
|
||||
// Get the nondimensional standard state entropies
|
||||
getEntropy_R(sbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
sbar[k] += - lnActCoeff_Scaled_[k] -log(xx) - T * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
sbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::getPartialMolarVolumes(doublereal* vbar) const
|
||||
{
|
||||
// Get the standard state values in m^3 kmol-1
|
||||
getStandardVolumes(vbar);
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
vbar[iK] += 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::calcPseudoBinaryMoleFractions() const
|
||||
{
|
||||
switch (PBType_) {
|
||||
case PBTYPE_PASSTHROUGH:
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
PBMoleFractions_[k] = moleFractions_[k];
|
||||
}
|
||||
break;
|
||||
case PBTYPE_SINGLEANION:
|
||||
{
|
||||
double sumCat = 0.0;
|
||||
double sumAnion = 0.0;
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
moleFractionsTmp_[k] = moleFractions_[k];
|
||||
}
|
||||
size_t kMax = npos;
|
||||
double sumMax = 0.0;
|
||||
for (size_t k = 0; k < cationList_.size(); k++) {
|
||||
size_t kCat = cationList_[k];
|
||||
double chP = m_speciesCharge[kCat];
|
||||
if (moleFractions_[kCat] > sumMax) {
|
||||
kMax = k;
|
||||
sumMax = moleFractions_[kCat];
|
||||
}
|
||||
sumCat += chP * moleFractions_[kCat];
|
||||
}
|
||||
size_t ka = anionList_[0];
|
||||
sumAnion = moleFractions_[ka] * m_speciesCharge[ka];
|
||||
double sum = sumCat - sumAnion;
|
||||
if (fabs(sum) > 1.0E-16) {
|
||||
moleFractionsTmp_[cationList_[kMax]] -= sum / m_speciesCharge[kMax];
|
||||
sum = 0.0;
|
||||
for (size_t k = 0; k < cationList_.size(); k++) {
|
||||
sum += moleFractionsTmp_[k];
|
||||
}
|
||||
for (size_t k = 0; k < cationList_.size(); k++) {
|
||||
moleFractionsTmp_[k]/= sum;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < cationList_.size(); k++) {
|
||||
PBMoleFractions_[k] = moleFractionsTmp_[cationList_[k]];
|
||||
}
|
||||
for (size_t k = 0; k < passThroughList_.size(); k++) {
|
||||
PBMoleFractions_[neutralPBindexStart + k] = moleFractions_[passThroughList_[k]];
|
||||
}
|
||||
|
||||
sum = std::max(0.0, PBMoleFractions_[0]);
|
||||
for (size_t k = 1; k < numPBSpecies_; k++) {
|
||||
sum += PBMoleFractions_[k];
|
||||
}
|
||||
for (size_t k = 0; k < numPBSpecies_; k++) {
|
||||
PBMoleFractions_[k] /= sum;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PBTYPE_SINGLECATION:
|
||||
throw CanteraError("eosType", "Unknown type");
|
||||
case PBTYPE_MULTICATIONANION:
|
||||
throw CanteraError("eosType", "Unknown type");
|
||||
default:
|
||||
throw CanteraError("eosType", "Unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::s_update_lnActCoeff() const
|
||||
{
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
lnActCoeff_Scaled_[k] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::s_update_dlnActCoeff_dT() const
|
||||
{
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::s_update_dlnActCoeff_dX_() const
|
||||
{
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::initThermo()
|
||||
{
|
||||
GibbsExcessVPSSTP::initThermo();
|
||||
initLengths();
|
||||
|
||||
// Go find the list of cations and anions
|
||||
cationList_.clear();
|
||||
anionList_.clear();
|
||||
passThroughList_.clear();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double ch = m_speciesCharge[k];
|
||||
if (ch > 0.0) {
|
||||
cationList_.push_back(k);
|
||||
} else if (ch < 0.0) {
|
||||
anionList_.push_back(k);
|
||||
} else {
|
||||
passThroughList_.push_back(k);
|
||||
}
|
||||
}
|
||||
numPBSpecies_ = cationList_.size() + anionList_.size() - 1;
|
||||
neutralPBindexStart = numPBSpecies_;
|
||||
PBType_ = PBTYPE_MULTICATIONANION;
|
||||
if (anionList_.size() == 1) {
|
||||
PBType_ = PBTYPE_SINGLEANION;
|
||||
} else if (cationList_.size() == 1) {
|
||||
PBType_ = PBTYPE_SINGLECATION;
|
||||
}
|
||||
if (anionList_.size() == 0 && cationList_.size() == 0) {
|
||||
PBType_ = PBTYPE_PASSTHROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::initLengths()
|
||||
{
|
||||
moleFractionsTmp_.resize(m_kk);
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::initThermoXML(XML_Node& phaseNode, const std::string& id)
|
||||
{
|
||||
if ((int) id.size() > 0 && phaseNode.id() != id) {
|
||||
throw CanteraError("MolarityIonicVPSSTP::initThermoXML",
|
||||
"phasenode and Id are incompatible");
|
||||
}
|
||||
|
||||
// Check on the thermo field. Must have one of:
|
||||
// <thermo model="MolarityIonicVPSS" />
|
||||
// <thermo model="MolarityIonicVPSSTP" />
|
||||
if (!phaseNode.hasChild("thermo")) {
|
||||
throw CanteraError("MolarityIonicVPSSTP::initThermoXML",
|
||||
"no thermo XML node");
|
||||
}
|
||||
XML_Node& thermoNode = phaseNode.child("thermo");
|
||||
if (!caseInsensitiveEquals(thermoNode["model"], "molarityionicvpss")
|
||||
&& !caseInsensitiveEquals(thermoNode["model"], "molarityionicvpsstp")) {
|
||||
throw CanteraError("MolarityIonicVPSSTP::initThermoXML",
|
||||
"Unknown thermo model: " + thermoNode["model"]
|
||||
+ " - This object only knows \"MolarityIonicVPSSTP\" ");
|
||||
}
|
||||
|
||||
// Go get all of the coefficients and factors in the activityCoefficients
|
||||
// XML block
|
||||
if (thermoNode.hasChild("activityCoefficients")) {
|
||||
XML_Node& acNode = thermoNode.child("activityCoefficients");
|
||||
for (size_t i = 0; i < acNode.nChildren(); i++) {
|
||||
XML_Node& xmlACChild = acNode.child(i);
|
||||
// Process a binary interaction
|
||||
if (caseInsensitiveEquals(xmlACChild.name(), "binaryneutralspeciesparameters")) {
|
||||
readXMLBinarySpecies(xmlACChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go down the chain
|
||||
GibbsExcessVPSSTP::initThermoXML(phaseNode, id);
|
||||
}
|
||||
|
||||
void MolarityIonicVPSSTP::readXMLBinarySpecies(XML_Node& xmLBinarySpecies)
|
||||
{
|
||||
std::string xname = xmLBinarySpecies.name();
|
||||
}
|
||||
|
||||
std::string MolarityIonicVPSSTP::report(bool show_thermo, doublereal threshold) const
|
||||
{
|
||||
fmt::memory_buffer b;
|
||||
try {
|
||||
if (name() != "") {
|
||||
format_to(b, "\n {}:\n", name());
|
||||
}
|
||||
format_to(b, "\n");
|
||||
format_to(b, " temperature {:12.6g} K\n", temperature());
|
||||
format_to(b, " pressure {:12.6g} Pa\n", pressure());
|
||||
format_to(b, " density {:12.6g} kg/m^3\n", density());
|
||||
format_to(b, " mean mol. weight {:12.6g} amu\n", meanMolecularWeight());
|
||||
|
||||
doublereal phi = electricPotential();
|
||||
format_to(b, " potential {:12.6g} V\n", phi);
|
||||
|
||||
vector_fp x(m_kk);
|
||||
vector_fp molal(m_kk);
|
||||
vector_fp mu(m_kk);
|
||||
vector_fp muss(m_kk);
|
||||
vector_fp acMolal(m_kk);
|
||||
vector_fp actMolal(m_kk);
|
||||
getMoleFractions(&x[0]);
|
||||
|
||||
getChemPotentials(&mu[0]);
|
||||
getStandardChemPotentials(&muss[0]);
|
||||
getActivities(&actMolal[0]);
|
||||
|
||||
if (show_thermo) {
|
||||
format_to(b, "\n");
|
||||
format_to(b, " 1 kg 1 kmol\n");
|
||||
format_to(b, " ----------- ------------\n");
|
||||
format_to(b, " enthalpy {:12.6g} {:12.4g} J\n",
|
||||
enthalpy_mass(), enthalpy_mole());
|
||||
format_to(b, " internal energy {:12.6g} {:12.4g} J\n",
|
||||
intEnergy_mass(), intEnergy_mole());
|
||||
format_to(b, " entropy {:12.6g} {:12.4g} J/K\n",
|
||||
entropy_mass(), entropy_mole());
|
||||
format_to(b, " Gibbs function {:12.6g} {:12.4g} J\n",
|
||||
gibbs_mass(), gibbs_mole());
|
||||
format_to(b, " heat capacity c_p {:12.6g} {:12.4g} J/K\n",
|
||||
cp_mass(), cp_mole());
|
||||
try {
|
||||
format_to(b, " heat capacity c_v {:12.6g} {:12.4g} J/K\n",
|
||||
cv_mass(), cv_mole());
|
||||
} catch (NotImplementedError&) {
|
||||
format_to(b, " heat capacity c_v <not implemented>\n");
|
||||
}
|
||||
}
|
||||
} catch (CanteraError& e) {
|
||||
return to_string(b) + e.what();
|
||||
}
|
||||
return to_string(b);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -78,17 +78,6 @@ void MultiSpeciesThermo::modifySpecies(size_t index,
|
||||
m_sp[type][m_speciesLoc[index].second] = {index, spthermo};
|
||||
}
|
||||
|
||||
void MultiSpeciesThermo::update_one(size_t k, doublereal t, doublereal* cp_R,
|
||||
doublereal* h_RT, doublereal* s_R) const
|
||||
{
|
||||
warn_deprecated("MultiSpeciesThermo::update_one",
|
||||
"Use update_single instead. To be removed after Cantera 2.4");
|
||||
const SpeciesThermoInterpType* sp_ptr = provideSTIT(k);
|
||||
if (sp_ptr) {
|
||||
sp_ptr->updatePropertiesTemp(t, cp_R+k, h_RT+k, s_R+k);
|
||||
}
|
||||
}
|
||||
|
||||
void MultiSpeciesThermo::update_single(size_t k, double t, double* cp_R,
|
||||
double* h_RT, double* s_R) const
|
||||
{
|
||||
|
||||
@@ -1,620 +0,0 @@
|
||||
/**
|
||||
* @file PhaseCombo_Interaction.cpp
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/thermo/PhaseCombo_Interaction.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
PhaseCombo_Interaction::PhaseCombo_Interaction() :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("Class PhaseCombo_Interaction", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
PhaseCombo_Interaction::PhaseCombo_Interaction(const std::string& inputFile,
|
||||
const std::string& id_) :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("Class PhaseCombo_Interaction", "To be removed after Cantera 2.4");
|
||||
initThermoFile(inputFile, id_);
|
||||
}
|
||||
|
||||
PhaseCombo_Interaction::PhaseCombo_Interaction(XML_Node& phaseRoot,
|
||||
const std::string& id_) :
|
||||
numBinaryInteractions_(0),
|
||||
formMargules_(0),
|
||||
formTempModel_(0)
|
||||
{
|
||||
warn_deprecated("Class PhaseCombo_Interaction", "To be removed after Cantera 2.4");
|
||||
importPhase(phaseRoot, this);
|
||||
}
|
||||
|
||||
// - Activities, Standard States, Activity Concentrations -----------
|
||||
|
||||
void PhaseCombo_Interaction::getActivityCoefficients(doublereal* ac) const
|
||||
{
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
|
||||
// take the exp of the internally stored coefficients.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
ac[k] = exp(lnActCoeff_Scaled_[k]);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------ Partial Molar Properties of the Solution ------------
|
||||
|
||||
void PhaseCombo_Interaction::getChemPotentials(doublereal* mu) const
|
||||
{
|
||||
// First get the standard chemical potentials in molar form. This requires
|
||||
// updates of standard state as a function of T and P
|
||||
getStandardChemPotentials(mu);
|
||||
// Update the activity coefficients
|
||||
s_update_lnActCoeff();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
mu[k] += RT() * (log(xx) + lnActCoeff_Scaled_[k]);
|
||||
}
|
||||
}
|
||||
|
||||
doublereal PhaseCombo_Interaction::enthalpy_mole() const
|
||||
{
|
||||
double h = 0;
|
||||
vector_fp hbar(m_kk);
|
||||
getPartialMolarEnthalpies(&hbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
h += moleFractions_[i]*hbar[i];
|
||||
}
|
||||
return h;
|
||||
}
|
||||
|
||||
doublereal PhaseCombo_Interaction::entropy_mole() const
|
||||
{
|
||||
double s = 0;
|
||||
vector_fp sbar(m_kk);
|
||||
getPartialMolarEntropies(&sbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
s += moleFractions_[i]*sbar[i];
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
doublereal PhaseCombo_Interaction::cp_mole() const
|
||||
{
|
||||
double cp = 0;
|
||||
vector_fp cpbar(m_kk);
|
||||
getPartialMolarCp(&cpbar[0]);
|
||||
for (size_t i = 0; i < m_kk; i++) {
|
||||
cp += moleFractions_[i]*cpbar[i];
|
||||
}
|
||||
return cp;
|
||||
}
|
||||
|
||||
doublereal PhaseCombo_Interaction::cv_mole() const
|
||||
{
|
||||
return cp_mole() - GasConstant;
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getPartialMolarEnthalpies(doublereal* hbar) const
|
||||
{
|
||||
// Get the nondimensional standard state enthalpies
|
||||
getEnthalpy_RT(hbar);
|
||||
// dimensionalize it.
|
||||
double T = temperature();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] *= GasConstant * T;
|
||||
}
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
hbar[k] -= GasConstant * T * T * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getPartialMolarCp(doublereal* cpbar) const
|
||||
{
|
||||
// Get the nondimensional standard state entropies
|
||||
getCp_R(cpbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] -= 2 * T * dlnActCoeffdT_Scaled_[k] + T * T * d2lnActCoeffdT2_Scaled_[k];
|
||||
}
|
||||
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
cpbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getPartialMolarEntropies(doublereal* sbar) const
|
||||
{
|
||||
// Get the nondimensional standard state entropies
|
||||
getEntropy_R(sbar);
|
||||
double T = temperature();
|
||||
|
||||
// Update the activity coefficients, This also update the internally stored
|
||||
// molalities.
|
||||
s_update_lnActCoeff();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
double xx = std::max(moleFractions_[k], SmallNumber);
|
||||
sbar[k] += - lnActCoeff_Scaled_[k] - log(xx) - T * dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
|
||||
// dimensionalize it.
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
sbar[k] *= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getPartialMolarVolumes(doublereal* vbar) const
|
||||
{
|
||||
double T = temperature();
|
||||
|
||||
// Get the standard state values in m^3 kmol-1
|
||||
getStandardVolumes(vbar);
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_VHE_b_ij[i] - T * m_VSE_b_ij[i]);
|
||||
double g1 = (m_VHE_c_ij[i] - T * m_VSE_c_ij[i]);
|
||||
vbar[iK] += XA*XB*(g0+g1*XB)+((delAK-XA)*XB+XA*(delBK-XB))*(g0+g1*XB)+XA*XB*(delBK-XB)*g1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::initThermo()
|
||||
{
|
||||
initLengths();
|
||||
GibbsExcessVPSSTP::initThermo();
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::initLengths()
|
||||
{
|
||||
dlnActCoeffdlnN_.resize(m_kk, m_kk);
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::initThermoXML(XML_Node& phaseNode, const std::string& id)
|
||||
{
|
||||
if ((int) id.size() > 0 && phaseNode.id() != id) {
|
||||
throw CanteraError("PhaseCombo_Interaction::initThermoXML",
|
||||
"phasenode and Id are incompatible");
|
||||
}
|
||||
|
||||
// Check on the thermo field. Must have:
|
||||
// <thermo model="PhaseCombo_Interaction" />
|
||||
if (!phaseNode.hasChild("thermo")) {
|
||||
throw CanteraError("PhaseCombo_Interaction::initThermoXML",
|
||||
"no thermo XML node");
|
||||
}
|
||||
XML_Node& thermoNode = phaseNode.child("thermo");
|
||||
if (!caseInsensitiveEquals(thermoNode["model"], "phasecombo_interaction")) {
|
||||
throw CanteraError("PhaseCombo_Interaction::initThermoXML",
|
||||
"model name isn't PhaseCombo_Interaction: " + thermoNode["model"]);
|
||||
}
|
||||
|
||||
// Go get all of the coefficients and factors in the activityCoefficients
|
||||
// XML block
|
||||
if (thermoNode.hasChild("activityCoefficients")) {
|
||||
XML_Node& acNode = thermoNode.child("activityCoefficients");
|
||||
if (!caseInsensitiveEquals(acNode["model"], "margules")) {
|
||||
throw CanteraError("PhaseCombo_Interaction::initThermoXML",
|
||||
"Unknown activity coefficient model: " + acNode["model"]);
|
||||
}
|
||||
for (size_t i = 0; i < acNode.nChildren(); i++) {
|
||||
XML_Node& xmlACChild = acNode.child(i);
|
||||
|
||||
// Process a binary salt field, or any of the other XML fields that
|
||||
// make up the Pitzer Database. Entries will be ignored if any of
|
||||
// the species in the entry isn't in the solution.
|
||||
if (caseInsensitiveEquals(xmlACChild.name(), "binaryneutralspeciesparameters")) {
|
||||
readXMLBinarySpecies(xmlACChild);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Go down the chain
|
||||
GibbsExcessVPSSTP::initThermoXML(phaseNode, id);
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::s_update_lnActCoeff() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
lnActCoeff_Scaled_.assign(m_kk, 0.0);
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
// We never sample the end of the mole fraction domains
|
||||
double xx = std::max(moleFractions_[iK], SmallNumber);
|
||||
|
||||
// First wipe out the ideal solution mixing term
|
||||
lnActCoeff_Scaled_[iK] = - log(xx);
|
||||
|
||||
// Then add in the Margules interaction terms. that's it!
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / (GasConstant*T);
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / (GasConstant*T);
|
||||
lnActCoeff_Scaled_[iK] += (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::s_update_dlnActCoeff_dT() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
dlnActCoeffdT_Scaled_.assign(m_kk, 0.0);
|
||||
d2lnActCoeffdT2_Scaled_.assign(m_kk, 0.0);
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = -m_HE_b_ij[i] / (GasConstant*T*T);
|
||||
double g1 = -m_HE_c_ij[i] / (GasConstant*T*T);
|
||||
double temp = (delAK * XB + XA * delBK - XA * XB) * (g0 + g1 * XB) + XA * XB * (delBK - XB) * g1;
|
||||
dlnActCoeffdT_Scaled_[iK] += temp;
|
||||
d2lnActCoeffdT2_Scaled_[iK] -= 2.0 * temp / T;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getdlnActCoeffdT(doublereal* dlnActCoeffdT) const
|
||||
{
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdT[k] = dlnActCoeffdT_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getd2lnActCoeffdT2(doublereal* d2lnActCoeffdT2) const
|
||||
{
|
||||
s_update_dlnActCoeff_dT();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
d2lnActCoeffdT2[k] = d2lnActCoeffdT2_Scaled_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getdlnActCoeffds(const doublereal dTds, const doublereal* const dXds,
|
||||
doublereal* dlnActCoeffds) const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
s_update_dlnActCoeff_dT();
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
// We never sample the end of the mole fraction domains
|
||||
double xx = std::max(moleFractions_[iK], SmallNumber);
|
||||
|
||||
// First wipe out the ideal solution mixing term
|
||||
if (xx > SmallNumber) {
|
||||
dlnActCoeffds[iK] += - 1.0 / xx;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double dXA = dXds[iA];
|
||||
double dXB = dXds[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / (GasConstant*T);
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / (GasConstant*T);
|
||||
dlnActCoeffds[iK] += ((delBK-XB)*dXA + (delAK-XA)*dXB)*(g0+2*g1*XB) + (delBK-XB)*2*g1*XA*dXB
|
||||
+ dlnActCoeffdT_Scaled_[iK]*dTds;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnN_diag() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
dlnActCoeffdlnN_diag_.assign(m_kk, 0.0);
|
||||
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
double XK = moleFractions_[iK];
|
||||
// We never sample the end of the mole fraction domains
|
||||
double xx = std::max(moleFractions_[iK], SmallNumber);
|
||||
|
||||
// First wipe out the ideal solution mixing term
|
||||
if (xx > SmallNumber) {
|
||||
dlnActCoeffdlnN_diag_[iK] = - 1.0 + xx;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
int delAK = 0;
|
||||
int delBK = 0;
|
||||
|
||||
if (iA==iK) {
|
||||
delAK = 1;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / (GasConstant*T);
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / (GasConstant*T);
|
||||
dlnActCoeffdlnN_diag_[iK] += 2*(delBK-XB)*(g0*(delAK-XA)+g1*(2*(delAK-XA)*XB+XA*(delBK-XB)));
|
||||
}
|
||||
dlnActCoeffdlnN_diag_[iK] = XK*dlnActCoeffdlnN_diag_[iK];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnN() const
|
||||
{
|
||||
double T = temperature();
|
||||
dlnActCoeffdlnN_.zero();
|
||||
|
||||
// Loop over the activity coefficient gamma_k
|
||||
for (size_t iK = 0; iK < m_kk; iK++) {
|
||||
// We never sample the end of the mole fraction domains
|
||||
double xx = std::max(moleFractions_[iK], SmallNumber);
|
||||
for (size_t iM = 0; iM < m_kk; iM++) {
|
||||
double XM = moleFractions_[iM];
|
||||
if (xx > SmallNumber) {
|
||||
double delKM = 0.0;
|
||||
if (iK == iM) {
|
||||
delKM = 1.0;
|
||||
}
|
||||
// this gets multiplied by XM at the bottom
|
||||
dlnActCoeffdlnN_(iK,iM) += - delKM/XM + 1.0;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
double delAK = 0.0;
|
||||
double delBK = 0.0;
|
||||
double delAM = 0.0;
|
||||
double delBM = 0.0;
|
||||
if (iA==iK) {
|
||||
delAK = 1.0;
|
||||
} else if (iB==iK) {
|
||||
delBK = 1.0;
|
||||
}
|
||||
if (iA==iM) {
|
||||
delAM = 1.0;
|
||||
} else if (iB==iM) {
|
||||
delBM = 1.0;
|
||||
}
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / (GasConstant*T);
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / (GasConstant*T);
|
||||
dlnActCoeffdlnN_(iK,iM) += g0*((delAM-XA)*(delBK-XB)+(delAK-XA)*(delBM-XB));
|
||||
dlnActCoeffdlnN_(iK,iM) += 2*g1*((delAM-XA)*(delBK-XB)*XB+(delAK-XA)*(delBM-XB)*XB+(delBM-XB)*(delBK-XB)*XA);
|
||||
}
|
||||
dlnActCoeffdlnN_(iK,iM) = XM * dlnActCoeffdlnN_(iK,iM);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::s_update_dlnActCoeff_dlnX_diag() const
|
||||
{
|
||||
doublereal T = temperature();
|
||||
dlnActCoeffdlnX_diag_.assign(m_kk, 0.0);
|
||||
for (size_t i = 0; i < numBinaryInteractions_; i++) {
|
||||
size_t iA = m_pSpecies_A_ij[i];
|
||||
size_t iB = m_pSpecies_B_ij[i];
|
||||
|
||||
double XA = moleFractions_[iA];
|
||||
double XB = moleFractions_[iB];
|
||||
|
||||
double g0 = (m_HE_b_ij[i] - T * m_SE_b_ij[i]) / (GasConstant * T);
|
||||
double g1 = (m_HE_c_ij[i] - T * m_SE_c_ij[i]) / (GasConstant * T);
|
||||
|
||||
dlnActCoeffdlnX_diag_[iA] += XA*XB*(2*g1*-2*g0-6*g1*XB);
|
||||
dlnActCoeffdlnX_diag_[iB] += XA*XB*(2*g1*-2*g0-6*g1*XB);
|
||||
}
|
||||
throw CanteraError("PhaseCombo_Interaction::s_update_dlnActCoeff_dlnX_diag", "unimplemented");
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getdlnActCoeffdlnN_diag(doublereal* dlnActCoeffdlnN_diag) const
|
||||
{
|
||||
s_update_dlnActCoeff_dlnN_diag();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdlnN_diag[k] = dlnActCoeffdlnN_diag_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getdlnActCoeffdlnX_diag(doublereal* dlnActCoeffdlnX_diag) const
|
||||
{
|
||||
s_update_dlnActCoeff_dlnX_diag();
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
dlnActCoeffdlnX_diag[k] = dlnActCoeffdlnX_diag_[k];
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::getdlnActCoeffdlnN(const size_t ld, doublereal* dlnActCoeffdlnN)
|
||||
{
|
||||
s_update_dlnActCoeff_dlnN();
|
||||
double* data = & dlnActCoeffdlnN_(0,0);
|
||||
for (size_t k = 0; k < m_kk; k++) {
|
||||
for (size_t m = 0; m < m_kk; m++) {
|
||||
dlnActCoeffdlnN[ld * k + m] = data[m_kk * k + m];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::resizeNumInteractions(const size_t num)
|
||||
{
|
||||
numBinaryInteractions_ = num;
|
||||
m_HE_b_ij.resize(num, 0.0);
|
||||
m_HE_c_ij.resize(num, 0.0);
|
||||
m_HE_d_ij.resize(num, 0.0);
|
||||
m_SE_b_ij.resize(num, 0.0);
|
||||
m_SE_c_ij.resize(num, 0.0);
|
||||
m_SE_d_ij.resize(num, 0.0);
|
||||
m_VHE_b_ij.resize(num, 0.0);
|
||||
m_VHE_c_ij.resize(num, 0.0);
|
||||
m_VHE_d_ij.resize(num, 0.0);
|
||||
m_VSE_b_ij.resize(num, 0.0);
|
||||
m_VSE_c_ij.resize(num, 0.0);
|
||||
m_VSE_d_ij.resize(num, 0.0);
|
||||
m_pSpecies_A_ij.resize(num, npos);
|
||||
m_pSpecies_B_ij.resize(num, npos);
|
||||
}
|
||||
|
||||
void PhaseCombo_Interaction::readXMLBinarySpecies(XML_Node& xmLBinarySpecies)
|
||||
{
|
||||
string xname = xmLBinarySpecies.name();
|
||||
if (xname != "binaryNeutralSpeciesParameters") {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies",
|
||||
"Incorrect name for processing this routine: " + xname);
|
||||
}
|
||||
vector_fp vParams;
|
||||
string iName = xmLBinarySpecies.attrib("speciesA");
|
||||
if (iName == "") {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "no speciesA attrib");
|
||||
}
|
||||
string jName = xmLBinarySpecies.attrib("speciesB");
|
||||
if (jName == "") {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "no speciesB attrib");
|
||||
}
|
||||
|
||||
// Find the index of the species in the current phase. It's not an error to
|
||||
// not find the species
|
||||
size_t iSpecies = speciesIndex(iName);
|
||||
if (iSpecies == npos) {
|
||||
return;
|
||||
}
|
||||
string ispName = speciesName(iSpecies);
|
||||
if (charge(iSpecies) != 0) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "speciesA charge problem");
|
||||
}
|
||||
size_t jSpecies = speciesIndex(jName);
|
||||
if (jSpecies == npos) {
|
||||
return;
|
||||
}
|
||||
string jspName = speciesName(jSpecies);
|
||||
if (charge(jSpecies) != 0) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies", "speciesB charge problem");
|
||||
}
|
||||
|
||||
resizeNumInteractions(numBinaryInteractions_ + 1);
|
||||
size_t iSpot = numBinaryInteractions_ - 1;
|
||||
m_pSpecies_A_ij[iSpot] = iSpecies;
|
||||
m_pSpecies_B_ij[iSpot] = jSpecies;
|
||||
|
||||
for (size_t iChild = 0; iChild < xmLBinarySpecies.nChildren(); iChild++) {
|
||||
XML_Node& xmlChild = xmLBinarySpecies.child(iChild);
|
||||
string nodeName = toLowerCopy(xmlChild.name());
|
||||
|
||||
// Process the binary species interaction child elements
|
||||
if (nodeName == "excessenthalpy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessEnthalpy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessEnthalpy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_HE_b_ij[iSpot] = vParams[0];
|
||||
m_HE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessentropy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessEntropy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessEntropy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_SE_b_ij[iSpot] = vParams[0];
|
||||
m_SE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessvolume_enthalpy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Enthalpy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessVolume_Enthalpy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_VHE_b_ij[iSpot] = vParams[0];
|
||||
m_VHE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
|
||||
if (nodeName == "excessvolume_entropy") {
|
||||
// Get the string containing all of the values
|
||||
getFloatArray(xmlChild, vParams, true, "toSI", "excessVolume_Entropy");
|
||||
if (vParams.size() != 2) {
|
||||
throw CanteraError("PhaseCombo_Interaction::readXMLBinarySpecies::excessVolume_Entropy for " + ispName
|
||||
+ "::" + jspName,
|
||||
"wrong number of params found");
|
||||
}
|
||||
m_VSE_b_ij[iSpot] = vParams[0];
|
||||
m_VSE_c_ij[iSpot] = vParams[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "cantera/thermo/NasaPoly2.h"
|
||||
#include "cantera/thermo/ShomatePoly.h"
|
||||
#include "cantera/thermo/ConstCpPoly.h"
|
||||
#include "cantera/thermo/AdsorbateThermo.h"
|
||||
#include "cantera/thermo/speciesThermoTypes.h"
|
||||
#include "cantera/thermo/VPStandardStateTP.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
@@ -44,8 +43,6 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(int type, double tlow,
|
||||
return new ShomatePoly2(tlow, thigh, pref, coeffs);
|
||||
case NASA2:
|
||||
return new NasaPoly2(tlow, thigh, pref, coeffs);
|
||||
case ADSORBATE:
|
||||
return new Adsorbate(tlow, thigh, pref, coeffs);
|
||||
default:
|
||||
throw CanteraError("newSpeciesThermoInterpType",
|
||||
"Unknown species thermo type: {}.", type);
|
||||
@@ -73,8 +70,6 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const std::string& stype,
|
||||
itype = NASA9MULTITEMP; // multi-region, 9-coefficient NASA polynomials
|
||||
} else if (type == "mu0") {
|
||||
itype = MU0_INTERP;
|
||||
} else if (type == "adsorbate") {
|
||||
itype = ADSORBATE;
|
||||
} else {
|
||||
throw CanteraError("newSpeciesThermoInterpType",
|
||||
"Unknown species thermo type: '" + stype + "'.");
|
||||
@@ -146,58 +141,6 @@ static SpeciesThermoInterpType* newNasaThermoFromXML(vector<XML_Node*> nodes)
|
||||
return newSpeciesThermoInterpType(NASA, tmin, tmax, p0, &c[0]);
|
||||
}
|
||||
|
||||
//! Create a Shomate polynomial from an XML node giving the 'EQ3' coefficients
|
||||
/*!
|
||||
* This is called if a 'MinEQ3' node is found in the XML input.
|
||||
* @param MinEQ3node The XML_Node containing the MinEQ3 parameterization
|
||||
*/
|
||||
SpeciesThermoInterpType* newShomateForMineralEQ3(const XML_Node& MinEQ3node)
|
||||
{
|
||||
doublereal tmin0 = strSItoDbl(MinEQ3node["Tmin"]);
|
||||
doublereal tmax0 = strSItoDbl(MinEQ3node["Tmax"]);
|
||||
doublereal p0 = strSItoDbl(MinEQ3node["Pref"]);
|
||||
|
||||
doublereal deltaG_formation_pr_tr =
|
||||
getFloat(MinEQ3node, "DG0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
|
||||
doublereal deltaH_formation_pr_tr =
|
||||
getFloat(MinEQ3node, "DH0_f_Pr_Tr", "actEnergy") / actEnergyToSI("cal/gmol");
|
||||
doublereal Entrop_pr_tr = getFloat(MinEQ3node, "S0_Pr_Tr", "toSI") / toSI("cal/gmol/K");
|
||||
doublereal a = getFloat(MinEQ3node, "a", "toSI") / toSI("cal/gmol/K");
|
||||
doublereal b = getFloat(MinEQ3node, "b", "toSI") / toSI("cal/gmol/K2");
|
||||
doublereal c = getFloat(MinEQ3node, "c", "toSI") / toSI("cal-K/gmol");
|
||||
doublereal dg = deltaG_formation_pr_tr * toSI("cal/gmol");
|
||||
doublereal DHjmol = deltaH_formation_pr_tr * toSI("cal/gmol");
|
||||
doublereal fac = DHjmol - dg - 298.15 * Entrop_pr_tr * toSI("cal/gmol");
|
||||
doublereal Mu0_tr_pr = fac + dg;
|
||||
doublereal e = Entrop_pr_tr * toSI("cal/gmol");
|
||||
doublereal Hcalc = Mu0_tr_pr + 298.15 * e;
|
||||
|
||||
// Now calculate the shomate polynomials
|
||||
//
|
||||
// Cp first
|
||||
//
|
||||
// Shomate: (Joules / gmol / K)
|
||||
// Cp = As + Bs * t + Cs * t*t + Ds * t*t*t + Es / (t*t)
|
||||
// where
|
||||
// t = temperature(Kelvin) / 1000
|
||||
double As = a * toSI("cal");
|
||||
double Bs = b * toSI("cal") * 1000.;
|
||||
double Cs = 0.0;
|
||||
double Ds = 0.0;
|
||||
double Es = c * toSI("cal") / (1.0E6);
|
||||
|
||||
double t = 298.15 / 1000.;
|
||||
double H298smFs = As * t + Bs * t * t / 2.0 - Es / t;
|
||||
double HcalcS = Hcalc / 1.0E6;
|
||||
double Fs = HcalcS - H298smFs;
|
||||
double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
|
||||
double ScalcS = e / 1.0E3;
|
||||
double Gs = ScalcS - S298smGs;
|
||||
|
||||
double c0[7] = {As, Bs, Cs, Ds, Es, Fs, Gs};
|
||||
return newSpeciesThermoInterpType(SHOMATE1, tmin0, tmax0, p0, c0);
|
||||
}
|
||||
|
||||
//! Create a Shomate polynomial thermodynamic property parameterization for a
|
||||
//! species
|
||||
/*!
|
||||
@@ -341,41 +284,6 @@ static SpeciesThermoInterpType* newNasa9ThermoFromXML(
|
||||
}
|
||||
}
|
||||
|
||||
//! Create an Adsorbate polynomial thermodynamic property parameterization for a
|
||||
//! species
|
||||
/*!
|
||||
* This is called if a 'Adsorbate' node is found in the XML input.
|
||||
*
|
||||
* @param f XML Node that contains the parameterization
|
||||
*/
|
||||
static SpeciesThermoInterpType* newAdsorbateThermoFromXML(const XML_Node& f)
|
||||
{
|
||||
vector_fp freqs;
|
||||
doublereal pref = OneAtm;
|
||||
double tmin = fpValue(f["Tmin"]);
|
||||
double tmax = fpValue(f["Tmax"]);
|
||||
if (f.hasAttrib("P0")) {
|
||||
pref = fpValue(f["P0"]);
|
||||
}
|
||||
if (f.hasAttrib("Pref")) {
|
||||
pref = fpValue(f["Pref"]);
|
||||
}
|
||||
if (tmax == 0.0) {
|
||||
tmax = 1.0e30;
|
||||
}
|
||||
|
||||
if (f.hasChild("floatArray")) {
|
||||
getFloatArray(f.child("floatArray"), freqs, false);
|
||||
}
|
||||
for (size_t n = 0; n < freqs.size(); n++) {
|
||||
freqs[n] *= 3.0e10;
|
||||
}
|
||||
vector_fp coeffs(freqs.size() + 2);
|
||||
coeffs[0] = static_cast<double>(freqs.size());
|
||||
coeffs[1] = getFloat(f, "binding_energy", "toSI");
|
||||
copy(freqs.begin(), freqs.end(), coeffs.begin() + 2);
|
||||
return new Adsorbate(tmin, tmax, pref, &coeffs[0]);
|
||||
}
|
||||
|
||||
SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo)
|
||||
{
|
||||
@@ -410,19 +318,12 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo)
|
||||
}
|
||||
if ((tp.size() > 2 && thermoType != "nasa9") ||
|
||||
(tp.size() > 1 && (thermoType == "const_cp" ||
|
||||
thermoType == "mu0" ||
|
||||
thermoType == "adsorbate"))) {
|
||||
thermoType == "mu0"))) {
|
||||
throw CanteraError("newSpeciesThermoInterpType",
|
||||
"Too many regions in thermo parameterization.");
|
||||
}
|
||||
|
||||
if (model == "mineraleq3") {
|
||||
if (thermoType != "mineq3") {
|
||||
throw CanteraError("newSpeciesThermoInterpType",
|
||||
"confused: expected MinEQ3");
|
||||
}
|
||||
return newShomateForMineralEQ3(*tp[0]);
|
||||
} else if (thermoType == "shomate") {
|
||||
if (thermoType == "shomate") {
|
||||
return newShomateThermoFromXML(tp);
|
||||
} else if (thermoType == "const_cp") {
|
||||
return newConstCpThermoFromXML(*tp[0]);
|
||||
@@ -432,8 +333,6 @@ SpeciesThermoInterpType* newSpeciesThermoInterpType(const XML_Node& thermo)
|
||||
return newMu0ThermoFromXML(*tp[0]);
|
||||
} else if (thermoType == "nasa9") {
|
||||
return newNasa9ThermoFromXML(tp);
|
||||
} else if (thermoType == "adsorbate") {
|
||||
return newAdsorbateThermoFromXML(*tp[0]);
|
||||
} else {
|
||||
throw CanteraError("newSpeciesThermoInterpType",
|
||||
"Unknown species thermo model '" + thermoType + "'.");
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "cantera/thermo/MargulesVPSSTP.h"
|
||||
#include "cantera/thermo/RedlichKisterVPSSTP.h"
|
||||
#include "cantera/thermo/IonsFromNeutralVPSSTP.h"
|
||||
#include "cantera/thermo/PhaseCombo_Interaction.h"
|
||||
#include "cantera/thermo/PureFluidPhase.h"
|
||||
#include "cantera/thermo/RedlichKwongMFTP.h"
|
||||
#include "cantera/thermo/ConstDensityThermo.h"
|
||||
@@ -29,15 +28,12 @@
|
||||
#include "cantera/thermo/EdgePhase.h"
|
||||
#include "cantera/thermo/MetalPhase.h"
|
||||
#include "cantera/thermo/StoichSubstance.h"
|
||||
#include "cantera/thermo/MineralEQ3.h"
|
||||
#include "cantera/thermo/MetalSHEelectrons.h"
|
||||
#include "cantera/thermo/FixedChemPotSSTP.h"
|
||||
#include "cantera/thermo/LatticeSolidPhase.h"
|
||||
#include "cantera/thermo/LatticePhase.h"
|
||||
#include "cantera/thermo/HMWSoln.h"
|
||||
#include "cantera/thermo/DebyeHuckel.h"
|
||||
#include "cantera/thermo/IdealMolalSoln.h"
|
||||
#include "cantera/thermo/MolarityIonicVPSSTP.h"
|
||||
#include "cantera/thermo/IdealSolnGasVPSS.h"
|
||||
#include "cantera/thermo/WaterSSTP.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
@@ -67,13 +63,9 @@ ThermoFactory::ThermoFactory()
|
||||
reg("IdealMolalSolution", []() { return new IdealMolalSoln(); });
|
||||
reg("IdealGasVPSS", []() { return new IdealSolnGasVPSS(); });
|
||||
m_synonyms["IdealGasVPSS"] = "IdealSolnVPSS";
|
||||
reg("MineralEQ3", []() { return new MineralEQ3(); });
|
||||
reg("MetalSHEelectrons", []() { return new MetalSHEelectrons(); });
|
||||
reg("Margules", []() { return new MargulesVPSSTP(); });
|
||||
reg("PhaseCombo_Interaction", []() { return new PhaseCombo_Interaction(); });
|
||||
reg("IonsFromNeutralMolecule", []() { return new IonsFromNeutralVPSSTP(); });
|
||||
reg("FixedChemPot", []() { return new FixedChemPotSSTP(); });
|
||||
reg("MolarityIonicVPSSTP", []() { return new MolarityIonicVPSSTP(); });
|
||||
reg("Redlich-Kister", []() { return new RedlichKisterVPSSTP(); });
|
||||
reg("RedlichKwong", []() { return new RedlichKwongMFTP(); });
|
||||
m_synonyms["RedlichKwongMFTP"] = "RedlichKwong";
|
||||
|
||||
@@ -27,7 +27,6 @@ namespace Cantera
|
||||
ThermoPhase::ThermoPhase() :
|
||||
m_speciesData(0),
|
||||
m_phi(0.0),
|
||||
m_hasElementPotentials(false),
|
||||
m_chargeNeutralityNecessary(false),
|
||||
m_ssConvention(cSS_CONVENTION_TEMPERATURE),
|
||||
m_tlast(0.0)
|
||||
@@ -702,11 +701,6 @@ void ThermoPhase::equilibrate(const std::string& XY, const std::string& solver,
|
||||
throw CanteraError("ThermoPhase::equilibrate",
|
||||
"ChemEquil solver failed. Return code: {}", ret);
|
||||
}
|
||||
m_lambdaRRT.resize(nElements());
|
||||
for (size_t m = 0; m < nElements(); m++) {
|
||||
m_lambdaRRT[m] = E.elementPotentials()[m] / RT();
|
||||
}
|
||||
m_hasElementPotentials = true;
|
||||
debuglog("ChemEquil solver succeeded\n", log_level);
|
||||
return;
|
||||
} catch (std::exception& err) {
|
||||
@@ -735,31 +729,6 @@ void ThermoPhase::equilibrate(const std::string& XY, const std::string& solver,
|
||||
}
|
||||
}
|
||||
|
||||
void ThermoPhase::setElementPotentials(const vector_fp& lambda)
|
||||
{
|
||||
warn_deprecated("ThermoPhase::setElementPotentials",
|
||||
"To be removed after Cantera 2.4");
|
||||
size_t mm = nElements();
|
||||
if (lambda.size() < mm) {
|
||||
throw CanteraError("setElementPotentials", "lambda too small");
|
||||
}
|
||||
if (!m_hasElementPotentials) {
|
||||
m_lambdaRRT.resize(mm);
|
||||
}
|
||||
scale(lambda.begin(), lambda.end(), m_lambdaRRT.begin(), 1.0/RT());
|
||||
m_hasElementPotentials = true;
|
||||
}
|
||||
|
||||
bool ThermoPhase::getElementPotentials(doublereal* lambda) const
|
||||
{
|
||||
warn_deprecated("ThermoPhase::getElementPotentials",
|
||||
"To be removed after Cantera 2.4");
|
||||
if (m_hasElementPotentials) {
|
||||
scale(m_lambdaRRT.begin(), m_lambdaRRT.end(), lambda, RT());
|
||||
}
|
||||
return m_hasElementPotentials;
|
||||
}
|
||||
|
||||
void ThermoPhase::getdlnActCoeffdlnN(const size_t ld, doublereal* const dlnActCoeffdlnN)
|
||||
{
|
||||
for (size_t m = 0; m < m_kk; m++) {
|
||||
|
||||
@@ -1,246 +0,0 @@
|
||||
/**
|
||||
* @file LTPspecies.cpp
|
||||
* Definitions for the LTPspecies objects and its children, which is the virtual base class
|
||||
* for describing temperature dependence of submodels for transport parameters
|
||||
* (see \ref tranprops and \link Cantera::LTPspecies LTPspecies \endlink) .
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/LTPspecies.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
//! Exception thrown if an error is encountered while reading the transport database.
|
||||
class LTPError : public CanteraError
|
||||
{
|
||||
public:
|
||||
//! Constructor is a wrapper around CanteraError
|
||||
/*!
|
||||
* @param msg Informative message
|
||||
*/
|
||||
explicit LTPError(const std::string& msg) :
|
||||
CanteraError("LTPspecies", "error parsing transport data: " + msg + "\n") {
|
||||
}
|
||||
};
|
||||
|
||||
//! Parses the XML element called Arrhenius.
|
||||
/*!
|
||||
* The Arrhenius expression is
|
||||
* \f[
|
||||
* k = A T^(b) exp (-E_a / RT)
|
||||
* \f]
|
||||
*
|
||||
* @param node XML_Node to be read
|
||||
* @param A Output pre-exponential factor. The units are variable.
|
||||
* @param b output temperature power
|
||||
* @param E Output activation energy in units of Kelvin
|
||||
*/
|
||||
static void getArrhenius(const XML_Node& node,
|
||||
doublereal& A, doublereal& b, doublereal& E)
|
||||
{
|
||||
// parse the children for the A, b, and E components.
|
||||
A = getFloat(node, "A", "toSI");
|
||||
b = getFloat(node, "b");
|
||||
E = getFloat(node, "E", "actEnergy") / GasConstant;
|
||||
}
|
||||
|
||||
LTPspecies::LTPspecies() :
|
||||
m_speciesName("-"),
|
||||
m_model(LTP_TD_NOTSET),
|
||||
m_property(TP_UNKNOWN),
|
||||
m_thermo(0),
|
||||
m_mixWeight(1.0)
|
||||
{
|
||||
warn_deprecated("class LTPspecies", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
LTPspecies* LTPspecies::duplMyselfAsLTPspecies() const
|
||||
{
|
||||
return new LTPspecies(*this);
|
||||
}
|
||||
|
||||
doublereal LTPspecies::getSpeciesTransProp()
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
bool LTPspecies::checkPositive() const
|
||||
{
|
||||
return (m_coeffs[0] > 0);
|
||||
}
|
||||
|
||||
doublereal LTPspecies::getMixWeight() const
|
||||
{
|
||||
return m_mixWeight;
|
||||
}
|
||||
|
||||
void LTPspecies::adjustCoeffsForComposition()
|
||||
{
|
||||
}
|
||||
|
||||
LTPspecies_Const::LTPspecies_Const()
|
||||
{
|
||||
m_model = LTP_TD_CONSTANT;
|
||||
}
|
||||
|
||||
void LTPspecies_Const::setupFromXML(const XML_Node& propNode)
|
||||
{
|
||||
double A_k = getFloatCurrent(propNode, "toSI");
|
||||
if (A_k > 0.0) {
|
||||
setCoeff(A_k);
|
||||
} else {
|
||||
throw LTPError("negative or zero " + propNode.name());
|
||||
}
|
||||
}
|
||||
|
||||
void LTPspecies_Const::setCoeff(double C)
|
||||
{
|
||||
m_coeffs = {C};
|
||||
}
|
||||
|
||||
LTPspecies* LTPspecies_Const::duplMyselfAsLTPspecies() const
|
||||
{
|
||||
return new LTPspecies_Const(*this);
|
||||
}
|
||||
|
||||
doublereal LTPspecies_Const::getSpeciesTransProp()
|
||||
{
|
||||
return m_coeffs[0];
|
||||
}
|
||||
|
||||
LTPspecies_Arrhenius::LTPspecies_Arrhenius()
|
||||
{
|
||||
m_model = LTP_TD_ARRHENIUS;
|
||||
m_temp = 0.0;
|
||||
m_prop = 0.0;
|
||||
}
|
||||
|
||||
LTPspecies* LTPspecies_Arrhenius::duplMyselfAsLTPspecies() const
|
||||
{
|
||||
return new LTPspecies_Arrhenius(*this);
|
||||
}
|
||||
|
||||
void LTPspecies_Arrhenius::setupFromXML(const XML_Node& propNode)
|
||||
{
|
||||
doublereal A_k, n_k, Tact_k;
|
||||
getArrhenius(propNode, A_k, n_k, Tact_k);
|
||||
if (A_k <= 0.0) {
|
||||
throw LTPError("negative or zero " + propNode.name());
|
||||
}
|
||||
setCoeffs(A_k, n_k, Tact_k);
|
||||
}
|
||||
|
||||
void LTPspecies_Arrhenius::setCoeffs(double A, double n, double Tact)
|
||||
{
|
||||
m_coeffs = {A, n, Tact, log(A)};
|
||||
}
|
||||
|
||||
doublereal LTPspecies_Arrhenius::getSpeciesTransProp()
|
||||
{
|
||||
doublereal t = m_thermo->temperature();
|
||||
//m_coeffs[0] holds A
|
||||
//m_coeffs[1] holds n
|
||||
//m_coeffs[2] holds Tact
|
||||
//m_coeffs[3] holds log(A)
|
||||
if (t != m_temp) {
|
||||
m_prop = 0;
|
||||
m_logProp = 0;
|
||||
m_temp = t;
|
||||
m_logt = log(m_temp);
|
||||
//For viscosity the sign convention on positive activation energy is swithced
|
||||
if (m_property == TP_VISCOSITY) {
|
||||
m_logProp = m_coeffs[3] + m_coeffs[1] * m_logt + m_coeffs[2] / m_temp;
|
||||
} else {
|
||||
m_logProp = m_coeffs[3] + m_coeffs[1] * m_logt - m_coeffs[2] / m_temp;
|
||||
}
|
||||
m_prop = exp(m_logProp);
|
||||
}
|
||||
return m_prop;
|
||||
}
|
||||
|
||||
LTPspecies_Poly::LTPspecies_Poly() :
|
||||
m_temp(-1.0),
|
||||
m_prop(0.0)
|
||||
{
|
||||
m_model = LTP_TD_POLY;
|
||||
}
|
||||
|
||||
LTPspecies* LTPspecies_Poly::duplMyselfAsLTPspecies() const
|
||||
{
|
||||
return new LTPspecies_Poly(*this);
|
||||
}
|
||||
|
||||
void LTPspecies_Poly::setupFromXML(const XML_Node& propNode)
|
||||
{
|
||||
vector_fp coeffs;
|
||||
getFloatArray(propNode, coeffs, "true", "toSI");
|
||||
setCoeffs(coeffs.size(), coeffs.data());
|
||||
}
|
||||
|
||||
void LTPspecies_Poly::setCoeffs(size_t N, const double* coeffs)
|
||||
{
|
||||
m_coeffs.assign(coeffs, coeffs+N);
|
||||
}
|
||||
|
||||
doublereal LTPspecies_Poly::getSpeciesTransProp()
|
||||
{
|
||||
doublereal t = m_thermo->temperature();
|
||||
if (t != m_temp) {
|
||||
m_prop = 0.0;
|
||||
m_temp = t;
|
||||
double tempN = 1.0;
|
||||
for (int i = 0; i < (int) m_coeffs.size() ; i++) {
|
||||
m_prop += m_coeffs[i] * tempN;
|
||||
tempN *= m_temp;
|
||||
}
|
||||
}
|
||||
return m_prop;
|
||||
}
|
||||
|
||||
LTPspecies_ExpT::LTPspecies_ExpT() :
|
||||
m_temp(-1.0),
|
||||
m_prop(0.0)
|
||||
{
|
||||
m_model = LTP_TD_EXPT;
|
||||
}
|
||||
|
||||
LTPspecies* LTPspecies_ExpT::duplMyselfAsLTPspecies() const
|
||||
{
|
||||
return new LTPspecies_ExpT(*this);
|
||||
}
|
||||
|
||||
void LTPspecies_ExpT::setupFromXML(const XML_Node& propNode)
|
||||
{
|
||||
vector_fp coeffs;
|
||||
getFloatArray(propNode, coeffs, "true", "toSI");
|
||||
setCoeffs(coeffs.size(), coeffs.data());
|
||||
}
|
||||
|
||||
void LTPspecies_ExpT::setCoeffs(size_t N, const double* coeffs)
|
||||
{
|
||||
m_coeffs.assign(coeffs, coeffs+N);
|
||||
}
|
||||
|
||||
doublereal LTPspecies_ExpT::getSpeciesTransProp()
|
||||
{
|
||||
doublereal t = m_thermo->temperature();
|
||||
if (t != m_temp) {
|
||||
m_temp=t;
|
||||
m_prop = m_coeffs[0];
|
||||
doublereal tempN = 1.0;
|
||||
doublereal tmp = 0.0;
|
||||
for (int i = 1; i < (int) m_coeffs.size() ; i++) {
|
||||
tempN *= m_temp;
|
||||
tmp += m_coeffs[i] * tempN;
|
||||
}
|
||||
m_prop *= exp(tmp);
|
||||
}
|
||||
return m_prop;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,652 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTranInteraction.cpp
|
||||
* Source code for liquid mixture transport property evaluations.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/LiquidTransportParams.h"
|
||||
#include "cantera/thermo/IonsFromNeutralVPSSTP.h"
|
||||
#include "cantera/thermo/MargulesVPSSTP.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
/**
|
||||
* Exception thrown if an error is encountered while reading the
|
||||
* transport database.
|
||||
*/
|
||||
class LTPmodelError : public CanteraError
|
||||
{
|
||||
public:
|
||||
explicit LTPmodelError(const std::string& msg)
|
||||
: CanteraError("LTPspecies",
|
||||
"error parsing transport data: "
|
||||
+ msg + "\n") {}
|
||||
};
|
||||
|
||||
LiquidTranInteraction::LiquidTranInteraction(TransportPropertyType tp_ind) :
|
||||
m_model(LTI_MODEL_NOTSET),
|
||||
m_property(tp_ind)
|
||||
{
|
||||
warn_deprecated("Class LiquidTranInteraction", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
LiquidTranInteraction::~LiquidTranInteraction()
|
||||
{
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
delete m_Aij[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
delete m_Bij[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_Hij.size(); k++) {
|
||||
delete m_Hij[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_Sij.size(); k++) {
|
||||
delete m_Sij[k];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTranInteraction::init(const XML_Node& compModelNode,
|
||||
thermo_t* thermo)
|
||||
{
|
||||
m_thermo = thermo;
|
||||
size_t nsp = thermo->nSpecies();
|
||||
m_Dij.resize(nsp, nsp, 0.0);
|
||||
m_Eij.resize(nsp, nsp, 0.0);
|
||||
|
||||
for (size_t iChild = 0; iChild < compModelNode.nChildren(); iChild++) {
|
||||
XML_Node& xmlChild = compModelNode.child(iChild);
|
||||
std::string nodeName = xmlChild.name();
|
||||
if (!caseInsensitiveEquals(nodeName, "interaction")) {
|
||||
throw CanteraError("TransportFactory::getLiquidInteractionsTransportData",
|
||||
"expected <interaction> element and got <" + nodeName + ">");
|
||||
}
|
||||
string speciesA = xmlChild.attrib("speciesA");
|
||||
string speciesB = xmlChild.attrib("speciesB");
|
||||
size_t iSpecies = m_thermo->speciesIndex(speciesA);
|
||||
if (iSpecies == npos) {
|
||||
throw CanteraError("TransportFactory::getLiquidInteractionsTransportData",
|
||||
"Unknown species " + speciesA);
|
||||
}
|
||||
size_t jSpecies = m_thermo->speciesIndex(speciesB);
|
||||
if (jSpecies == npos) {
|
||||
throw CanteraError("TransportFactory::getLiquidInteractionsTransportData",
|
||||
"Unknown species " + speciesB);
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Eij")) {
|
||||
m_Eij(iSpecies,jSpecies) = getFloat(xmlChild, "Eij", "actEnergy");
|
||||
m_Eij(iSpecies,jSpecies) /= GasConstant;
|
||||
m_Eij(jSpecies,iSpecies) = m_Eij(iSpecies,jSpecies);
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Aij")) {
|
||||
vector_fp poly;
|
||||
getFloatArray(xmlChild, poly, true, "toSI", "Aij");
|
||||
while (m_Aij.size()<poly.size()) {
|
||||
DenseMatrix* aTemp = new DenseMatrix();
|
||||
aTemp->resize(nsp, nsp, 0.0);
|
||||
m_Aij.push_back(aTemp);
|
||||
}
|
||||
for (int i = 0; i < (int)poly.size(); i++) {
|
||||
(*m_Aij[i])(iSpecies,jSpecies) = poly[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Bij")) {
|
||||
vector_fp poly;
|
||||
getFloatArray(xmlChild, poly, true, "toSI", "Bij");
|
||||
while (m_Bij.size() < poly.size()) {
|
||||
DenseMatrix* bTemp = new DenseMatrix();
|
||||
bTemp->resize(nsp, nsp, 0.0);
|
||||
m_Bij.push_back(bTemp);
|
||||
}
|
||||
for (size_t i=0; i<poly.size(); i++) {
|
||||
(*m_Bij[i])(iSpecies,jSpecies) = poly[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Hij")) {
|
||||
vector_fp poly;
|
||||
getFloatArray(xmlChild, poly, true, "actEnergy", "Hij");
|
||||
while (m_Hij.size()<poly.size()) {
|
||||
DenseMatrix* hTemp = new DenseMatrix();
|
||||
hTemp->resize(nsp, nsp, 0.0);
|
||||
m_Hij.push_back(hTemp);
|
||||
}
|
||||
for (size_t i=0; i<poly.size(); i++) {
|
||||
(*m_Hij[i])(iSpecies,jSpecies) = poly[i];
|
||||
(*m_Hij[i])(iSpecies,jSpecies) /= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Sij")) {
|
||||
vector_fp poly;
|
||||
getFloatArray(xmlChild, poly, true, "actEnergy", "Sij");
|
||||
while (m_Sij.size()<poly.size()) {
|
||||
DenseMatrix* sTemp = new DenseMatrix();
|
||||
sTemp->resize(nsp, nsp, 0.0);
|
||||
m_Sij.push_back(sTemp);
|
||||
}
|
||||
for (size_t i=0; i<poly.size(); i++) {
|
||||
(*m_Sij[i])(iSpecies,jSpecies) = poly[i];
|
||||
(*m_Sij[i])(iSpecies,jSpecies) /= GasConstant;
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlChild.hasChild("Dij")) {
|
||||
m_Dij(iSpecies,jSpecies) = getFloat(xmlChild, "Dij", "toSI");
|
||||
m_Dij(jSpecies,iSpecies) = m_Dij(iSpecies,jSpecies);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LTI_Solvent::LTI_Solvent(TransportPropertyType tp_ind) :
|
||||
LiquidTranInteraction(tp_ind)
|
||||
{
|
||||
m_model = LTI_MODEL_SOLVENT;
|
||||
}
|
||||
|
||||
doublereal LTI_Solvent::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0.0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
if (speciesWeight) {
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
// should be: molefracs[k] = molefracs[k]*speciesWeight[k]; for consistency, but weight(solvent)=1?
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LTI_Solvent::getMixTransProp","You should be specifying the speciesWeight");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
//presume that the weighting is set to 1.0 for solvent and 0.0 for everything else.
|
||||
value += speciesValues[i] * speciesWeight[i];
|
||||
if (i == 0) {
|
||||
AssertTrace(speciesWeight[i] == 1.0);
|
||||
} else {
|
||||
AssertTrace(speciesWeight[i] == 0.0);
|
||||
}
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_Solvent::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0.0;
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
// should be: molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight(); for consistency, but weight(solvent)=1?
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
//presume that the weighting is set to 1.0 for solvent and 0.0 for everything else.
|
||||
value += LTPptrs[i]->getSpeciesTransProp() * LTPptrs[i]->getMixWeight();
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void LTI_Solvent::getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues)
|
||||
{
|
||||
mat = (*m_Aij[0]);
|
||||
}
|
||||
|
||||
doublereal LTI_MoleFracs::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
if (speciesWeight) {
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*speciesWeight[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LTI_MoleFracs::getMixTransProp","You should be specifying the speciesWeight");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += speciesValues[i] * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_MoleFracs::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += LTPptrs[i]->getSpeciesTransProp() * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Bij[k])(i,j)*temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_MassFracs::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp massfracs(nsp);
|
||||
m_thermo->getMassFractions(&massfracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
if (speciesWeight) {
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
massfracs[k] = massfracs[k]*speciesWeight[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LTI_MassFracs::getMixTransProp","You should be specifying the speciesWeight");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += speciesValues[i] * massfracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += massfracs[i]*massfracs[j]*(*m_Aij[k])(i,j)*pow(massfracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += massfracs[i]*massfracs[j]*(*m_Bij[k])(i,j)*temp*pow(massfracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_MassFracs::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp massfracs(nsp);
|
||||
m_thermo->getMassFractions(&massfracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
massfracs[k] = massfracs[k]*LTPptrs[k]->getMixWeight();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += LTPptrs[i]->getSpeciesTransProp() * massfracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += massfracs[i]*massfracs[j]*(*m_Aij[k])(i,j)*pow(massfracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Bij.size(); k++) {
|
||||
value += massfracs[i]*massfracs[j]*(*m_Bij[k])(i,j)*temp*pow(massfracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_Log_MoleFracs::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
if (speciesWeight) {
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*speciesWeight[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LTI_Log_MoleFracs::getMixTransProp","You probably should have a speciesWeight when you call getMixTransProp to convert ion mole fractions to molecular mole fractions");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += log(speciesValues[i]) * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Hij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Hij[k])(i,j)/temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Sij.size(); k++) {
|
||||
value -= molefracs[i]*molefracs[j]*(*m_Sij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return exp(value);
|
||||
}
|
||||
|
||||
doublereal LTI_Log_MoleFracs::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += log(LTPptrs[i]->getSpeciesTransProp()) * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Hij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Hij[k])(i,j)/temp*pow(molefracs[i], (int) k);
|
||||
}
|
||||
for (size_t k = 0; k < m_Sij.size(); k++) {
|
||||
value -= molefracs[i]*molefracs[j]*(*m_Sij[k])(i,j)*pow(molefracs[i], (int) k);
|
||||
}
|
||||
}
|
||||
}
|
||||
return exp(value);
|
||||
}
|
||||
|
||||
void LTI_Pairwise_Interaction::setParameters(LiquidTransportParams& trParam)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
m_diagonals.resize(nsp, 0);
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
LiquidTransportData& ltd = trParam.LTData[k];
|
||||
if (ltd.speciesDiffusivity) {
|
||||
m_diagonals[k] = ltd.speciesDiffusivity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doublereal LTI_Pairwise_Interaction::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_Pairwise_Interaction::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
doublereal LTI_Pairwise_Interaction::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_Pairwise_Interaction::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
void LTI_Pairwise_Interaction::getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
|
||||
mat.resize(nsp, nsp, 0.0);
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
for (size_t j = 0; j < i; j++) {
|
||||
mat(i,j) = mat(j,i) = exp(m_Eij(i,j) / temp) / m_Dij(i,j);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
if (mat(i,i) == 0.0 && m_diagonals[i]) {
|
||||
mat(i,i) = 1.0 / m_diagonals[i]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LTI_StefanMaxwell_PPN::setParameters(LiquidTransportParams& trParam)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
m_ionCondMix = 0;
|
||||
m_ionCondMixModel = trParam.ionConductivity;
|
||||
m_ionCondSpecies.resize(nsp,0);
|
||||
m_mobRatMix.resize(nsp,nsp,0.0);
|
||||
m_mobRatMixModel.resize(nsp*nsp);
|
||||
m_mobRatSpecies.resize(nsp*nsp);
|
||||
m_selfDiffMix.resize(nsp,0.0);
|
||||
m_selfDiffMixModel.resize(nsp);
|
||||
m_selfDiffSpecies.resize(nsp);
|
||||
|
||||
for (size_t k = 0; k < nsp*nsp; k++) {
|
||||
m_mobRatMixModel[k] = trParam.mobilityRatio[k];
|
||||
m_mobRatSpecies[k].resize(nsp,0);
|
||||
}
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
m_selfDiffMixModel[k] = trParam.selfDiffusion[k];
|
||||
m_selfDiffSpecies[k].resize(nsp,0);
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
LiquidTransportData& ltd = trParam.LTData[k];
|
||||
m_ionCondSpecies[k] = ltd.ionConductivity;
|
||||
for (size_t j = 0; j < nsp*nsp; j++) {
|
||||
m_mobRatSpecies[j][k] = ltd.mobilityRatio[j];
|
||||
}
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
m_selfDiffSpecies[j][k] = ltd.selfDiffusion[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doublereal LTI_StefanMaxwell_PPN::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_StefanMaxwell_PPN::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
doublereal LTI_StefanMaxwell_PPN::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_StefanMaxwell_PPN::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
void LTI_StefanMaxwell_PPN::getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues)
|
||||
{
|
||||
IonsFromNeutralVPSSTP* ions_thermo = dynamic_cast<IonsFromNeutralVPSSTP*>(m_thermo);
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
if (nsp != 3) {
|
||||
throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Function may only be called with a 3-ion system");
|
||||
}
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
vector_fp neut_molefracs;
|
||||
ions_thermo->getNeutralMolecMoleFractions(neut_molefracs);
|
||||
vector<size_t> cation;
|
||||
vector<size_t> anion;
|
||||
ions_thermo->getCationList(cation);
|
||||
ions_thermo->getAnionList(anion);
|
||||
|
||||
// Reaction Coeffs and Charges
|
||||
vector_fp viS(6);
|
||||
vector_fp charges(3);
|
||||
std::vector<size_t> neutMolIndex(3);
|
||||
ions_thermo->getDissociationCoeffs(viS,charges,neutMolIndex);
|
||||
|
||||
if (anion.size() != 1) {
|
||||
throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Must have one anion only for StefanMaxwell_PPN");
|
||||
}
|
||||
if (cation.size() != 2) {
|
||||
throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Must have two cations of equal charge for StefanMaxwell_PPN");
|
||||
}
|
||||
if (charges[cation[0]] != charges[cation[1]]) {
|
||||
throw CanteraError("LTI_StefanMaxwell_PPN::getMatrixTransProp","Cations must be of equal charge for StefanMaxwell_PPN");
|
||||
}
|
||||
|
||||
m_ionCondMix = m_ionCondMixModel->getMixTransProp(m_ionCondSpecies);
|
||||
MargulesVPSSTP* marg_thermo = dynamic_cast<MargulesVPSSTP*>(ions_thermo->getNeutralMoleculePhase().get());
|
||||
doublereal vol = m_thermo->molarVolume();
|
||||
|
||||
size_t k = 0;
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
if (m_mobRatMixModel[k]) {
|
||||
m_mobRatMix(i,j) = m_mobRatMixModel[k]->getMixTransProp(m_mobRatSpecies[k]);
|
||||
if (m_mobRatMix(i,j) > 0.0) {
|
||||
m_mobRatMix(j,i) = 1.0/m_mobRatMix(i,j);
|
||||
}
|
||||
}
|
||||
k++;
|
||||
}
|
||||
}
|
||||
|
||||
for (k = 0; k < nsp; k++) {
|
||||
m_selfDiffMix[k] = m_selfDiffMixModel[k]->getMixTransProp(m_selfDiffSpecies[k]);
|
||||
}
|
||||
|
||||
double vP = max(viS[cation[0]],viS[cation[1]]);
|
||||
double vM = viS[anion[0]];
|
||||
double zP = charges[cation[0]];
|
||||
double zM = charges[anion[0]];
|
||||
vector_fp dlnActCoeffdlnN_diag(neut_molefracs.size(),0.0);
|
||||
marg_thermo->getdlnActCoeffdlnN_diag(&dlnActCoeffdlnN_diag[0]);
|
||||
|
||||
double xA = neut_molefracs[neutMolIndex[cation[0]]];
|
||||
double xB = neut_molefracs[neutMolIndex[cation[1]]];
|
||||
double eps = (1-m_mobRatMix(cation[1],cation[0]))/(xA+xB*m_mobRatMix(cation[1],cation[0]));
|
||||
double inv_vP_vM_MutualDiff = (xA*(1-xB+dlnActCoeffdlnN_diag[neutMolIndex[cation[1]]])/m_selfDiffMix[cation[1]]+xB*(1-xA+dlnActCoeffdlnN_diag[neutMolIndex[cation[0]]])/m_selfDiffMix[cation[0]]);
|
||||
|
||||
mat.resize(nsp, nsp, 0.0);
|
||||
mat(cation[0],cation[1]) = mat(cation[1],cation[0]) = (1+vM/vP)*(1+eps*xB)*(1-eps*xA)*inv_vP_vM_MutualDiff-zP*zP*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol;
|
||||
mat(cation[0],anion[0]) = mat(anion[0],cation[0]) = (1+vP/vM)*(-eps*xB*(1-eps*xA)*inv_vP_vM_MutualDiff)-zP*zM*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol;
|
||||
mat(cation[1],anion[0]) = mat(anion[0],cation[1]) = (1+vP/vM)*(eps*xA*(1+eps*xB)*inv_vP_vM_MutualDiff)-zP*zM*Faraday*Faraday/GasConstant/temp/m_ionCondMix/vol;
|
||||
}
|
||||
|
||||
doublereal LTI_StokesEinstein::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_StokesEinstein::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
doublereal LTI_StokesEinstein::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
throw LTPmodelError("Calling LTI_StokesEinstein::getMixTransProp does not make sense.");
|
||||
}
|
||||
|
||||
void LTI_StokesEinstein::setParameters(LiquidTransportParams& trParam)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
m_viscosity.resize(nsp, 0);
|
||||
m_hydroRadius.resize(nsp, 0);
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
LiquidTransportData& ltd = trParam.LTData[k];
|
||||
m_viscosity[k] = ltd.viscosity;
|
||||
m_hydroRadius[k] = ltd.hydroRadius;
|
||||
}
|
||||
}
|
||||
|
||||
void LTI_StokesEinstein::getMatrixTransProp(DenseMatrix& mat, doublereal* speciesValues)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp viscSpec(nsp);
|
||||
vector_fp radiusSpec(nsp);
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
viscSpec[k] = m_viscosity[k]->getSpeciesTransProp();
|
||||
radiusSpec[k] = m_hydroRadius[k]->getSpeciesTransProp();
|
||||
}
|
||||
|
||||
mat.resize(nsp,nsp, 0.0);
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
mat(i,j) = (6.0 * Pi * radiusSpec[i] * viscSpec[j]) / GasConstant / temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
doublereal LTI_MoleFracs_ExpT::getMixTransProp(doublereal* speciesValues, doublereal* speciesWeight)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
//if weightings are specified, use those
|
||||
if (speciesWeight) {
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*speciesWeight[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LTI_MoleFracs_ExpT::getMixTransProp","You should be specifying the speciesWeight");
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += speciesValues[i] * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k)*exp((*m_Bij[k])(i,j)*temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
doublereal LTI_MoleFracs_ExpT::getMixTransProp(std::vector<LTPspecies*> LTPptrs)
|
||||
{
|
||||
size_t nsp = m_thermo->nSpecies();
|
||||
doublereal temp = m_thermo->temperature();
|
||||
vector_fp molefracs(nsp);
|
||||
m_thermo->getMoleFractions(&molefracs[0]);
|
||||
doublereal value = 0;
|
||||
|
||||
for (size_t k = 0; k < nsp; k++) {
|
||||
molefracs[k] = molefracs[k]*LTPptrs[k]->getMixWeight();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
value += LTPptrs[i]->getSpeciesTransProp() * molefracs[i];
|
||||
for (size_t j = 0; j < nsp; j++) {
|
||||
for (size_t k = 0; k < m_Aij.size(); k++) {
|
||||
value += molefracs[i]*molefracs[j]*(*m_Aij[k])(i,j)*pow(molefracs[i], (int) k)*exp((*m_Bij[k])(i,j)*temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
} //namespace Cantera
|
||||
@@ -1,974 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTransport.cpp
|
||||
* Mixture-averaged transport properties for ideal gas mixtures.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/LiquidTransport.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
LiquidTransport::LiquidTransport(thermo_t* thermo, int ndim) :
|
||||
Transport(thermo, ndim),
|
||||
m_nsp2(0),
|
||||
m_viscMixModel(0),
|
||||
m_ionCondMixModel(0),
|
||||
m_lambdaMixModel(0),
|
||||
m_diffMixModel(0),
|
||||
m_radiusMixModel(0),
|
||||
m_iStateMF(-1),
|
||||
concTot_(0.0),
|
||||
concTot_tran_(0.0),
|
||||
dens_(0.0),
|
||||
m_temp(-1.0),
|
||||
m_press(-1.0),
|
||||
m_lambda(-1.0),
|
||||
m_viscmix(-1.0),
|
||||
m_ionCondmix(-1.0),
|
||||
m_visc_mix_ok(false),
|
||||
m_visc_temp_ok(false),
|
||||
m_visc_conc_ok(false),
|
||||
m_ionCond_mix_ok(false),
|
||||
m_ionCond_temp_ok(false),
|
||||
m_ionCond_conc_ok(false),
|
||||
m_mobRat_mix_ok(false),
|
||||
m_mobRat_temp_ok(false),
|
||||
m_mobRat_conc_ok(false),
|
||||
m_selfDiff_mix_ok(false),
|
||||
m_selfDiff_temp_ok(false),
|
||||
m_selfDiff_conc_ok(false),
|
||||
m_radi_mix_ok(false),
|
||||
m_radi_temp_ok(false),
|
||||
m_radi_conc_ok(false),
|
||||
m_diff_mix_ok(false),
|
||||
m_diff_temp_ok(false),
|
||||
m_lambda_temp_ok(false),
|
||||
m_lambda_mix_ok(false),
|
||||
m_mode(-1000),
|
||||
m_debug(false)
|
||||
{
|
||||
warn_deprecated("Class LiquidTransport", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
LiquidTransport::~LiquidTransport()
|
||||
{
|
||||
//These are constructed in TransportFactory::newLTP
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
delete m_viscTempDep_Ns[k];
|
||||
delete m_ionCondTempDep_Ns[k];
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
delete m_selfDiffTempDep_Ns[j][k];
|
||||
}
|
||||
for (size_t j=0; j < m_nsp2; j++) {
|
||||
delete m_mobRatTempDep_Ns[j][k];
|
||||
}
|
||||
delete m_lambdaTempDep_Ns[k];
|
||||
delete m_radiusTempDep_Ns[k];
|
||||
delete m_diffTempDep_Ns[k];
|
||||
//These are constructed in TransportFactory::newLTI
|
||||
delete m_selfDiffMixModel[k];
|
||||
}
|
||||
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
delete m_mobRatMixModel[k];
|
||||
}
|
||||
|
||||
delete m_viscMixModel;
|
||||
delete m_ionCondMixModel;
|
||||
delete m_lambdaMixModel;
|
||||
delete m_diffMixModel;
|
||||
}
|
||||
|
||||
bool LiquidTransport::initLiquid(LiquidTransportParams& tr)
|
||||
{
|
||||
// Transfer quantitities from the database to the Transport object
|
||||
m_thermo = tr.thermo;
|
||||
m_velocityBasis = tr.velocityBasis_;
|
||||
m_nsp = m_thermo->nSpecies();
|
||||
m_nsp2 = m_nsp*m_nsp;
|
||||
|
||||
// Resize the local storage according to the number of species
|
||||
m_mw.resize(m_nsp, 0.0);
|
||||
m_viscSpecies.resize(m_nsp, 0.0);
|
||||
m_viscTempDep_Ns.resize(m_nsp, 0);
|
||||
m_ionCondSpecies.resize(m_nsp, 0.0);
|
||||
m_ionCondTempDep_Ns.resize(m_nsp, 0);
|
||||
m_mobRatTempDep_Ns.resize(m_nsp2);
|
||||
m_mobRatMixModel.resize(m_nsp2);
|
||||
m_mobRatSpecies.resize(m_nsp2, m_nsp, 0.0);
|
||||
m_mobRatMix.resize(m_nsp2,0.0);
|
||||
m_selfDiffTempDep_Ns.resize(m_nsp);
|
||||
m_selfDiffMixModel.resize(m_nsp);
|
||||
m_selfDiffSpecies.resize(m_nsp, m_nsp, 0.0);
|
||||
m_selfDiffMix.resize(m_nsp,0.0);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_selfDiffTempDep_Ns[k].resize(m_nsp, 0);
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
m_mobRatTempDep_Ns[k].resize(m_nsp, 0);
|
||||
}
|
||||
m_lambdaSpecies.resize(m_nsp, 0.0);
|
||||
m_lambdaTempDep_Ns.resize(m_nsp, 0);
|
||||
m_hydrodynamic_radius.resize(m_nsp, 0.0);
|
||||
m_radiusTempDep_Ns.resize(m_nsp, 0);
|
||||
|
||||
// Make a local copy of the molecular weights
|
||||
m_mw = m_thermo->molecularWeights();
|
||||
|
||||
// First populate mixing rules and indices (NOTE, we transfer pointers of
|
||||
// manually allocated quantities. We zero out pointers so that we only have
|
||||
// one copy of the pointer)
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_selfDiffMixModel[k] = tr.selfDiffusion[k];
|
||||
tr.selfDiffusion[k] = 0;
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
m_mobRatMixModel[k] = tr.mobilityRatio[k];
|
||||
tr.mobilityRatio[k] = 0;
|
||||
}
|
||||
|
||||
//for each species, assign viscosity model and coefficients
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
LiquidTransportData& ltd = tr.LTData[k];
|
||||
m_viscTempDep_Ns[k] = ltd.viscosity;
|
||||
ltd.viscosity = 0;
|
||||
m_ionCondTempDep_Ns[k] = ltd.ionConductivity;
|
||||
ltd.ionConductivity = 0;
|
||||
for (size_t j = 0; j < m_nsp2; j++) {
|
||||
m_mobRatTempDep_Ns[j][k] = ltd.mobilityRatio[j];
|
||||
ltd.mobilityRatio[j] = 0;
|
||||
}
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
m_selfDiffTempDep_Ns[j][k] = ltd.selfDiffusion[j];
|
||||
ltd.selfDiffusion[j] = 0;
|
||||
}
|
||||
m_lambdaTempDep_Ns[k] = ltd.thermalCond;
|
||||
ltd.thermalCond = 0;
|
||||
m_radiusTempDep_Ns[k] = ltd.hydroRadius;
|
||||
ltd.hydroRadius = 0;
|
||||
}
|
||||
|
||||
// Get the input Species Diffusivities. Note that species diffusivities are
|
||||
// not what is needed. Rather the Stefan Boltzmann interaction parameters
|
||||
// are needed for the current model. This section may, therefore, be
|
||||
// extraneous.
|
||||
m_diffTempDep_Ns.resize(m_nsp, 0);
|
||||
//for each species, assign viscosity model and coefficients
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
LiquidTransportData& ltd = tr.LTData[k];
|
||||
if (ltd.speciesDiffusivity != 0) {
|
||||
cout << "Warning: diffusion coefficient data for "
|
||||
<< m_thermo->speciesName(k)
|
||||
<< endl
|
||||
<< "in the input file is not used for LiquidTransport model."
|
||||
<< endl
|
||||
<< "LiquidTransport model uses Stefan-Maxwell interaction "
|
||||
<< endl
|
||||
<< "parameters defined in the <transport> input block."
|
||||
<< endl;
|
||||
}
|
||||
}
|
||||
|
||||
// Here we get interaction parameters from LiquidTransportParams that were
|
||||
// filled in TransportFactory::getLiquidInteractionsTransportData
|
||||
// Interaction models are provided here for viscosity, thermal conductivity,
|
||||
// species diffusivity and hydrodynamics radius (perhaps not needed in the
|
||||
// present class).
|
||||
m_viscMixModel = tr.viscosity;
|
||||
tr.viscosity = 0;
|
||||
|
||||
m_ionCondMixModel = tr.ionConductivity;
|
||||
tr.ionConductivity = 0;
|
||||
|
||||
m_lambdaMixModel = tr.thermalCond;
|
||||
tr.thermalCond = 0;
|
||||
|
||||
m_diffMixModel = tr.speciesDiffusivity;
|
||||
tr.speciesDiffusivity = 0;
|
||||
if (! m_diffMixModel) {
|
||||
throw CanteraError("LiquidTransport::initLiquid()",
|
||||
"A speciesDiffusivity model is required in the transport block for the phase, but none was provided");
|
||||
}
|
||||
|
||||
m_bdiff.resize(m_nsp,m_nsp, 0.0);
|
||||
|
||||
// Don't really need to update this here. It is updated in updateDiff_T()
|
||||
m_diffMixModel->getMatrixTransProp(m_bdiff);
|
||||
|
||||
m_mode = tr.mode_;
|
||||
m_massfracs.resize(m_nsp, 0.0);
|
||||
m_massfracs_tran.resize(m_nsp, 0.0);
|
||||
m_molefracs.resize(m_nsp, 0.0);
|
||||
m_molefracs_tran.resize(m_nsp, 0.0);
|
||||
m_concentrations.resize(m_nsp, 0.0);
|
||||
m_actCoeff.resize(m_nsp, 0.0);
|
||||
m_chargeSpecies.resize(m_nsp, 0.0);
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
m_chargeSpecies[i] = m_thermo->charge(i);
|
||||
}
|
||||
m_volume_spec.resize(m_nsp, 0.0);
|
||||
m_Grad_lnAC.resize(m_nDim * m_nsp, 0.0);
|
||||
m_spwork.resize(m_nsp, 0.0);
|
||||
|
||||
// resize the internal gradient variables
|
||||
m_Grad_X.resize(m_nDim * m_nsp, 0.0);
|
||||
m_Grad_T.resize(m_nDim, 0.0);
|
||||
m_Grad_V.resize(m_nDim, 0.0);
|
||||
m_Grad_mu.resize(m_nDim * m_nsp, 0.0);
|
||||
m_flux.resize(m_nsp, m_nDim, 0.0);
|
||||
m_Vdiff.resize(m_nsp, m_nDim, 0.0);
|
||||
|
||||
// set all flags to false
|
||||
m_visc_mix_ok = false;
|
||||
m_visc_temp_ok = false;
|
||||
m_visc_conc_ok = false;
|
||||
m_ionCond_mix_ok = false;
|
||||
m_ionCond_temp_ok = false;
|
||||
m_ionCond_conc_ok = false;
|
||||
m_mobRat_mix_ok = false;
|
||||
m_mobRat_temp_ok = false;
|
||||
m_mobRat_conc_ok = false;
|
||||
m_selfDiff_mix_ok = false;
|
||||
m_selfDiff_temp_ok = false;
|
||||
m_selfDiff_conc_ok = false;
|
||||
m_radi_temp_ok = false;
|
||||
m_radi_conc_ok = false;
|
||||
m_lambda_temp_ok = false;
|
||||
m_lambda_mix_ok = false;
|
||||
m_diff_temp_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
doublereal LiquidTransport::viscosity()
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
if (m_visc_mix_ok) {
|
||||
return m_viscmix;
|
||||
}
|
||||
////// LiquidTranInteraction method
|
||||
m_viscmix = m_viscMixModel->getMixTransProp(m_viscTempDep_Ns);
|
||||
return m_viscmix;
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesViscosities(doublereal* const visc)
|
||||
{
|
||||
update_T();
|
||||
if (!m_visc_temp_ok) {
|
||||
updateViscosity_T();
|
||||
}
|
||||
copy(m_viscSpecies.begin(), m_viscSpecies.end(), visc);
|
||||
}
|
||||
|
||||
doublereal LiquidTransport::ionConductivity()
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
if (m_ionCond_mix_ok) {
|
||||
return m_ionCondmix;
|
||||
}
|
||||
////// LiquidTranInteraction method
|
||||
m_ionCondmix = m_ionCondMixModel->getMixTransProp(m_ionCondTempDep_Ns);
|
||||
return m_ionCondmix;
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesIonConductivity(doublereal* ionCond)
|
||||
{
|
||||
update_T();
|
||||
if (!m_ionCond_temp_ok) {
|
||||
updateIonConductivity_T();
|
||||
}
|
||||
copy(m_ionCondSpecies.begin(), m_ionCondSpecies.end(), ionCond);
|
||||
}
|
||||
|
||||
void LiquidTransport::mobilityRatio(doublereal* mobRat)
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
// LiquidTranInteraction method
|
||||
if (!m_mobRat_mix_ok) {
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
if (m_mobRatMixModel[k]) {
|
||||
m_mobRatMix[k] = m_mobRatMixModel[k]->getMixTransProp(m_mobRatTempDep_Ns[k]);
|
||||
if (m_mobRatMix[k] > 0.0) {
|
||||
m_mobRatMix[k / m_nsp + m_nsp * (k % m_nsp)] = 1.0 / m_mobRatMix[k]; // Also must be off diagonal: k%(1+n)!=0, but then m_mobRatMixModel[k] shouldn't be initialized anyway
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
mobRat[k] = m_mobRatMix[k];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesMobilityRatio(doublereal** mobRat)
|
||||
{
|
||||
update_T();
|
||||
if (!m_mobRat_temp_ok) {
|
||||
updateMobilityRatio_T();
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
mobRat[k][j] = m_mobRatSpecies(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::selfDiffusion(doublereal* const selfDiff)
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
if (!m_selfDiff_mix_ok) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_selfDiffMix[k] = m_selfDiffMixModel[k]->getMixTransProp(m_selfDiffTempDep_Ns[k]);
|
||||
}
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
selfDiff[k] = m_selfDiffMix[k];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesSelfDiffusion(doublereal** selfDiff)
|
||||
{
|
||||
update_T();
|
||||
if (!m_selfDiff_temp_ok) {
|
||||
updateSelfDiffusion_T();
|
||||
}
|
||||
for (size_t k=0; k<m_nsp; k++) {
|
||||
for (size_t j=0; j < m_nsp; j++) {
|
||||
selfDiff[k][j] = m_selfDiffSpecies(k,j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesHydrodynamicRadius(doublereal* const radius)
|
||||
{
|
||||
update_T();
|
||||
if (!m_radi_temp_ok) {
|
||||
updateHydrodynamicRadius_T();
|
||||
}
|
||||
copy(m_hydrodynamic_radius.begin(), m_hydrodynamic_radius.end(), radius);
|
||||
}
|
||||
|
||||
doublereal LiquidTransport::thermalConductivity()
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
if (!m_lambda_mix_ok) {
|
||||
m_lambda = m_lambdaMixModel->getMixTransProp(m_lambdaTempDep_Ns);
|
||||
m_cond_mix_ok = true;
|
||||
}
|
||||
return m_lambda;
|
||||
}
|
||||
|
||||
void LiquidTransport::getThermalDiffCoeffs(doublereal* const dt)
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
dt[k] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getBinaryDiffCoeffs(size_t ld, doublereal* d)
|
||||
{
|
||||
if (ld != m_nsp) {
|
||||
throw CanteraError("LiquidTransport::getBinaryDiffCoeffs",
|
||||
"First argument does not correspond to number of species in model.\nDiff Coeff matrix may be misdimensioned");
|
||||
}
|
||||
update_T();
|
||||
// if necessary, evaluate the binary diffusion coefficients
|
||||
// from the polynomial fits
|
||||
if (!m_diff_temp_ok) {
|
||||
updateDiff_T();
|
||||
}
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
d[ld*j + i] = 1.0 / m_bdiff(i,j);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getMobilities(doublereal* const mobil)
|
||||
{
|
||||
getMixDiffCoeffs(m_spwork.data());
|
||||
doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
mobil[k] = c1 * m_spwork[k];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getFluidMobilities(doublereal* const mobil_f)
|
||||
{
|
||||
getMixDiffCoeffs(m_spwork.data());
|
||||
doublereal c1 = 1.0 / (GasConstant * m_temp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
mobil_f[k] = c1 * m_spwork[k];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::set_Grad_T(const doublereal* grad_T)
|
||||
{
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
m_Grad_T[a] = grad_T[a];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::set_Grad_V(const doublereal* grad_V)
|
||||
{
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
m_Grad_V[a] = grad_V[a];
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::set_Grad_X(const doublereal* grad_X)
|
||||
{
|
||||
size_t itop = m_nDim * m_nsp;
|
||||
for (size_t i = 0; i < itop; i++) {
|
||||
m_Grad_X[i] = grad_X[i];
|
||||
}
|
||||
}
|
||||
|
||||
doublereal LiquidTransport::getElectricConduct()
|
||||
{
|
||||
vector_fp gradT(m_nDim,0.0);
|
||||
vector_fp gradX(m_nDim * m_nsp, 0.0);
|
||||
vector_fp gradV(m_nDim, 1.0);
|
||||
|
||||
set_Grad_T(&gradT[0]);
|
||||
set_Grad_X(&gradX[0]);
|
||||
set_Grad_V(&gradV[0]);
|
||||
|
||||
vector_fp fluxes(m_nsp * m_nDim);
|
||||
doublereal current;
|
||||
getSpeciesFluxesExt(m_nDim, &fluxes[0]);
|
||||
|
||||
//sum over species charges, fluxes, Faraday to get current
|
||||
// Since we want the scalar conductivity, we need only consider one-dim
|
||||
for (size_t i = 0; i < 1; i++) {
|
||||
current = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
current += m_chargeSpecies[k] * Faraday * fluxes[k] / m_mw[k];
|
||||
}
|
||||
//divide by unit potential gradient
|
||||
current /= - gradV[i];
|
||||
}
|
||||
return current;
|
||||
}
|
||||
|
||||
void LiquidTransport::getElectricCurrent(int ndim,
|
||||
const doublereal* grad_T,
|
||||
int ldx,
|
||||
const doublereal* grad_X,
|
||||
int ldf,
|
||||
const doublereal* grad_V,
|
||||
doublereal* current)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
set_Grad_V(grad_V);
|
||||
|
||||
vector_fp fluxes(m_nsp * m_nDim);
|
||||
getSpeciesFluxesExt(ldf, &fluxes[0]);
|
||||
|
||||
//sum over species charges, fluxes, Faraday to get current
|
||||
for (size_t i = 0; i < m_nDim; i++) {
|
||||
current[i] = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
current[i] += m_chargeSpecies[k] * Faraday * fluxes[k] / m_mw[k];
|
||||
}
|
||||
//divide by unit potential gradient
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesVdiff(size_t ndim,
|
||||
const doublereal* grad_T,
|
||||
int ldx, const doublereal* grad_X,
|
||||
int ldf, doublereal* Vdiff)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
getSpeciesVdiffExt(ldf, Vdiff);
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesVdiffES(size_t ndim,
|
||||
const doublereal* grad_T,
|
||||
int ldx,
|
||||
const doublereal* grad_X,
|
||||
int ldf,
|
||||
const doublereal* grad_V,
|
||||
doublereal* Vdiff)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
set_Grad_V(grad_V);
|
||||
getSpeciesVdiffExt(ldf, Vdiff);
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesFluxes(size_t ndim,
|
||||
const doublereal* const grad_T,
|
||||
size_t ldx, const doublereal* const grad_X,
|
||||
size_t ldf, doublereal* const fluxes)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
getSpeciesFluxesExt(ldf, fluxes);
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesFluxesES(size_t ndim,
|
||||
const doublereal* grad_T,
|
||||
size_t ldx,
|
||||
const doublereal* grad_X,
|
||||
size_t ldf,
|
||||
const doublereal* grad_V,
|
||||
doublereal* fluxes)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
set_Grad_V(grad_V);
|
||||
getSpeciesFluxesExt(ldf, fluxes);
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesVdiffExt(size_t ldf, doublereal* Vdiff)
|
||||
{
|
||||
stefan_maxwell_solve();
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
Vdiff[n*ldf + k] = m_Vdiff(k,n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getSpeciesFluxesExt(size_t ldf, doublereal* fluxes)
|
||||
{
|
||||
stefan_maxwell_solve();
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] = m_flux(k,n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::getMixDiffCoeffs(doublereal* const d)
|
||||
{
|
||||
stefan_maxwell_solve();
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
if (m_Grad_X[n*m_nsp + k] != 0.0) {
|
||||
d[n*m_nsp + k] = - m_Vdiff(k,n) * m_molefracs[k]
|
||||
/ m_Grad_X[n*m_nsp + k];
|
||||
} else {
|
||||
//avoid divide by zero with nonsensical response
|
||||
d[n*m_nsp + k] = - 1.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool LiquidTransport::update_T()
|
||||
{
|
||||
// First make a decision about whether we need to recalculate
|
||||
doublereal t = m_thermo->temperature();
|
||||
if (t == m_temp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next do a reality check on temperature value
|
||||
if (t < 0.0) {
|
||||
throw CanteraError("LiquidTransport::update_T()",
|
||||
"negative temperature {}", t);
|
||||
}
|
||||
|
||||
// Compute various direct functions of temperature
|
||||
m_temp = t;
|
||||
|
||||
// temperature has changed so temp flags are flipped
|
||||
m_visc_temp_ok = false;
|
||||
m_ionCond_temp_ok = false;
|
||||
m_mobRat_temp_ok = false;
|
||||
m_selfDiff_temp_ok = false;
|
||||
m_radi_temp_ok = false;
|
||||
m_diff_temp_ok = false;
|
||||
m_lambda_temp_ok = false;
|
||||
|
||||
// temperature has changed, so polynomial temperature
|
||||
// interpolations will need to be reevaluated.
|
||||
m_visc_conc_ok = false;
|
||||
m_ionCond_conc_ok = false;
|
||||
m_mobRat_conc_ok = false;
|
||||
m_selfDiff_conc_ok = false;
|
||||
|
||||
// Mixture stuff needs to be evaluated
|
||||
m_visc_mix_ok = false;
|
||||
m_ionCond_mix_ok = false;
|
||||
m_mobRat_mix_ok = false;
|
||||
m_selfDiff_mix_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
m_lambda_mix_ok = false; //(don't need it because a lower lvl flag is set
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LiquidTransport::update_C()
|
||||
{
|
||||
// If the pressure has changed then the concentrations have changed.
|
||||
doublereal pres = m_thermo->pressure();
|
||||
bool qReturn = true;
|
||||
if (pres != m_press) {
|
||||
qReturn = false;
|
||||
m_press = pres;
|
||||
}
|
||||
int iStateNew = m_thermo->stateMFNumber();
|
||||
if (iStateNew != m_iStateMF) {
|
||||
qReturn = false;
|
||||
m_thermo->getMassFractions(m_massfracs.data());
|
||||
m_thermo->getMoleFractions(m_molefracs.data());
|
||||
m_thermo->getConcentrations(m_concentrations.data());
|
||||
concTot_ = 0.0;
|
||||
concTot_tran_ = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_molefracs[k] = std::max(0.0, m_molefracs[k]);
|
||||
m_molefracs_tran[k] = std::max(Tiny, m_molefracs[k]);
|
||||
m_massfracs_tran[k] = std::max(Tiny, m_massfracs[k]);
|
||||
concTot_tran_ += m_molefracs_tran[k];
|
||||
concTot_ += m_concentrations[k];
|
||||
}
|
||||
dens_ = m_thermo->density();
|
||||
meanMolecularWeight_ = m_thermo->meanMolecularWeight();
|
||||
concTot_tran_ *= concTot_;
|
||||
}
|
||||
if (qReturn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// signal that concentration-dependent quantities will need to be recomputed
|
||||
// before use, and update the local mole fractions.
|
||||
m_visc_conc_ok = false;
|
||||
m_ionCond_conc_ok = false;
|
||||
m_mobRat_conc_ok = false;
|
||||
m_selfDiff_conc_ok = false;
|
||||
|
||||
// Mixture stuff needs to be evaluated
|
||||
m_visc_mix_ok = false;
|
||||
m_ionCond_mix_ok = false;
|
||||
m_mobRat_mix_ok = false;
|
||||
m_selfDiff_mix_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
m_lambda_mix_ok = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateCond_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_lambdaSpecies[k] = m_lambdaTempDep_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
m_lambda_temp_ok = true;
|
||||
m_lambda_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateDiff_T()
|
||||
{
|
||||
m_diffMixModel->getMatrixTransProp(m_bdiff);
|
||||
m_diff_temp_ok = true;
|
||||
m_diff_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateViscosities_C()
|
||||
{
|
||||
m_visc_conc_ok = true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateViscosity_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_viscSpecies[k] = m_viscTempDep_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
m_visc_temp_ok = true;
|
||||
m_visc_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateIonConductivity_C()
|
||||
{
|
||||
m_ionCond_conc_ok = true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateIonConductivity_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_ionCondSpecies[k] = m_ionCondTempDep_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
m_ionCond_temp_ok = true;
|
||||
m_ionCond_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateMobilityRatio_C()
|
||||
{
|
||||
m_mobRat_conc_ok = true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateMobilityRatio_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
m_mobRatSpecies(k,j) = m_mobRatTempDep_Ns[k][j]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
m_mobRat_temp_ok = true;
|
||||
m_mobRat_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateSelfDiffusion_C()
|
||||
{
|
||||
m_selfDiff_conc_ok = true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateSelfDiffusion_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp2; k++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
m_selfDiffSpecies(k,j) = m_selfDiffTempDep_Ns[k][j]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
m_selfDiff_temp_ok = true;
|
||||
m_selfDiff_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateHydrodynamicRadius_C()
|
||||
{
|
||||
m_radi_conc_ok = true;
|
||||
}
|
||||
|
||||
void LiquidTransport::updateHydrodynamicRadius_T()
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_hydrodynamic_radius[k] = m_radiusTempDep_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
m_radi_temp_ok = true;
|
||||
m_radi_mix_ok = false;
|
||||
}
|
||||
|
||||
void LiquidTransport::update_Grad_lnAC()
|
||||
{
|
||||
for (size_t k = 0; k < m_nDim; k++) {
|
||||
double grad_T = m_Grad_T[k];
|
||||
size_t start = m_nsp*k;
|
||||
m_thermo->getdlnActCoeffds(grad_T, &m_Grad_X[start], &m_Grad_lnAC[start]);
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
if (m_molefracs[i] < 1.e-15) {
|
||||
m_Grad_lnAC[start+i] = 0;
|
||||
} else {
|
||||
m_Grad_lnAC[start+i] += m_Grad_X[start+i]/m_molefracs[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LiquidTransport::stefan_maxwell_solve()
|
||||
{
|
||||
m_B.resize(m_nsp, m_nDim, 0.0);
|
||||
m_A.resize(m_nsp, m_nsp, 0.0);
|
||||
|
||||
//! grab a local copy of the molecular weights
|
||||
const vector_fp& M = m_thermo->molecularWeights();
|
||||
//! grad a local copy of the ion molar volume (inverse total ion concentration)
|
||||
const doublereal vol = m_thermo->molarVolume();
|
||||
|
||||
//! Update the temperature, concentrations and diffusion coefficients in the
|
||||
//! mixture.
|
||||
update_T();
|
||||
update_C();
|
||||
if (!m_diff_temp_ok) {
|
||||
updateDiff_T();
|
||||
}
|
||||
|
||||
double T = m_thermo->temperature();
|
||||
update_Grad_lnAC();
|
||||
m_thermo->getActivityCoefficients(m_actCoeff.data());
|
||||
|
||||
/*
|
||||
* Calculate the electrochemical potential gradient. This is the
|
||||
* driving force for relative diffusional transport.
|
||||
*
|
||||
* Here we calculate
|
||||
*
|
||||
* X_i * (grad (mu_i) + S_i grad T - M_i / dens * grad P
|
||||
*
|
||||
* This is Eqn. 13-1 p. 318 Newman. The original equation is from
|
||||
* Hershfeld, Curtis, and Bird.
|
||||
*
|
||||
* S_i is the partial molar entropy of species i. This term will cancel
|
||||
* out a lot of the grad T terms in grad (mu_i), therefore simplifying
|
||||
* the expression.
|
||||
*
|
||||
* Ok I think there may be many ways to do this. One way is to do it via basis
|
||||
* functions, at the nodes, as a function of the variables in the problem.
|
||||
*
|
||||
* For calculation of molality based thermo systems, we current get
|
||||
* the molar based values. This may change.
|
||||
*
|
||||
* Note, we have broken the symmetry of the matrix here, due to
|
||||
* considerations involving species concentrations going to zero.
|
||||
*/
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
m_Grad_mu[a*m_nsp + i] =
|
||||
m_chargeSpecies[i] * Faraday * m_Grad_V[a]
|
||||
+ GasConstant * T * m_Grad_lnAC[a*m_nsp+i];
|
||||
}
|
||||
}
|
||||
|
||||
if (m_thermo->activityConvention() == cAC_CONVENTION_MOLALITY) {
|
||||
int iSolvent = 0;
|
||||
double mwSolvent = m_thermo->molecularWeight(iSolvent);
|
||||
double mnaught = mwSolvent/ 1000.;
|
||||
double lnmnaught = log(mnaught);
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
for (size_t i = 1; i < m_nsp; i++) {
|
||||
m_Grad_mu[a*m_nsp + i] -=
|
||||
m_molefracs[i] * GasConstant * m_Grad_T[a] * lnmnaught;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Just for Note, m_A(i,j) refers to the ith row and jth column.
|
||||
// They are still fortran ordered, so that i varies fastest.
|
||||
double condSum1;
|
||||
const doublereal invRT = 1.0 / (GasConstant * T);
|
||||
switch (m_nDim) {
|
||||
case 1: // 1-D approximation
|
||||
m_B(0,0) = 0.0;
|
||||
// equation for the reference velocity
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (m_velocityBasis == VB_MOLEAVG) {
|
||||
m_A(0,j) = m_molefracs_tran[j];
|
||||
} else if (m_velocityBasis == VB_MASSAVG) {
|
||||
m_A(0,j) = m_massfracs_tran[j];
|
||||
} else if ((m_velocityBasis >= 0)
|
||||
&& (m_velocityBasis < static_cast<int>(m_nsp))) {
|
||||
// use species number m_velocityBasis as reference velocity
|
||||
if (m_velocityBasis == static_cast<int>(j)) {
|
||||
m_A(0,j) = 1.0;
|
||||
} else {
|
||||
m_A(0,j) = 0.0;
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LiquidTransport::stefan_maxwell_solve",
|
||||
"Unknown reference velocity provided.");
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < m_nsp; i++) {
|
||||
m_B(i,0) = m_Grad_mu[i] * invRT;
|
||||
m_A(i,i) = 0.0;
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (j != i) {
|
||||
double tmp = m_molefracs_tran[j] * m_bdiff(i,j);
|
||||
m_A(i,i) -= tmp;
|
||||
m_A(i,j) = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invert and solve the system Ax = b. Answer is in m_B
|
||||
solve(m_A, m_B);
|
||||
condSum1 = 0;
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
condSum1 -= Faraday*m_chargeSpecies[i]*m_B(i,0)*m_molefracs_tran[i]/vol;
|
||||
}
|
||||
break;
|
||||
case 2: // 2-D approximation
|
||||
m_B(0,0) = 0.0;
|
||||
m_B(0,1) = 0.0;
|
||||
//equation for the reference velocity
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (m_velocityBasis == VB_MOLEAVG) {
|
||||
m_A(0,j) = m_molefracs_tran[j];
|
||||
} else if (m_velocityBasis == VB_MASSAVG) {
|
||||
m_A(0,j) = m_massfracs_tran[j];
|
||||
} else if ((m_velocityBasis >= 0)
|
||||
&& (m_velocityBasis < static_cast<int>(m_nsp))) {
|
||||
// use species number m_velocityBasis as reference velocity
|
||||
if (m_velocityBasis == static_cast<int>(j)) {
|
||||
m_A(0,j) = 1.0;
|
||||
} else {
|
||||
m_A(0,j) = 0.0;
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LiquidTransport::stefan_maxwell_solve",
|
||||
"Unknown reference velocity provided.");
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < m_nsp; i++) {
|
||||
m_B(i,0) = m_Grad_mu[i] * invRT;
|
||||
m_B(i,1) = m_Grad_mu[m_nsp + i] * invRT;
|
||||
m_A(i,i) = 0.0;
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (j != i) {
|
||||
double tmp = m_molefracs_tran[j] * m_bdiff(i,j);
|
||||
m_A(i,i) -= tmp;
|
||||
m_A(i,j) = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invert and solve the system Ax = b. Answer is in m_B
|
||||
solve(m_A, m_B);
|
||||
break;
|
||||
case 3: // 3-D approximation
|
||||
m_B(0,0) = 0.0;
|
||||
m_B(0,1) = 0.0;
|
||||
m_B(0,2) = 0.0;
|
||||
// equation for the reference velocity
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (m_velocityBasis == VB_MOLEAVG) {
|
||||
m_A(0,j) = m_molefracs_tran[j];
|
||||
} else if (m_velocityBasis == VB_MASSAVG) {
|
||||
m_A(0,j) = m_massfracs_tran[j];
|
||||
} else if ((m_velocityBasis >= 0)
|
||||
&& (m_velocityBasis < static_cast<int>(m_nsp))) {
|
||||
// use species number m_velocityBasis as reference velocity
|
||||
if (m_velocityBasis == static_cast<int>(j)) {
|
||||
m_A(0,j) = 1.0;
|
||||
} else {
|
||||
m_A(0,j) = 0.0;
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("LiquidTransport::stefan_maxwell_solve",
|
||||
"Unknown reference velocity provided.");
|
||||
}
|
||||
}
|
||||
for (size_t i = 1; i < m_nsp; i++) {
|
||||
m_B(i,0) = m_Grad_mu[i] * invRT;
|
||||
m_B(i,1) = m_Grad_mu[m_nsp + i] * invRT;
|
||||
m_B(i,2) = m_Grad_mu[2*m_nsp + i] * invRT;
|
||||
m_A(i,i) = 0.0;
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
if (j != i) {
|
||||
double tmp = m_molefracs_tran[j] * m_bdiff(i,j);
|
||||
m_A(i,i) -= tmp;
|
||||
m_A(i,j) = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// invert and solve the system Ax = b. Answer is in m_B
|
||||
solve(m_A, m_B);
|
||||
break;
|
||||
default:
|
||||
throw CanteraError("routine", "not done");
|
||||
}
|
||||
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
m_Vdiff(j,a) = m_B(j,a);
|
||||
m_flux(j,a) = concTot_ * M[j] * m_molefracs_tran[j] * m_B(j,a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTransportData.cpp
|
||||
* Source code for liquid transport property evaluations.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/LiquidTransportData.h"
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
LiquidTransportData::LiquidTransportData() :
|
||||
speciesName("-"),
|
||||
hydroRadius(0),
|
||||
viscosity(0),
|
||||
ionConductivity(0),
|
||||
thermalCond(0),
|
||||
electCond(0),
|
||||
speciesDiffusivity(0)
|
||||
{
|
||||
warn_deprecated("class LiquidTransportData", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
LiquidTransportData::LiquidTransportData(const LiquidTransportData& right) :
|
||||
speciesName("-"),
|
||||
hydroRadius(0),
|
||||
viscosity(0),
|
||||
ionConductivity(0),
|
||||
thermalCond(0),
|
||||
electCond(0),
|
||||
speciesDiffusivity(0)
|
||||
{
|
||||
*this = right; //use assignment operator to do other work
|
||||
}
|
||||
|
||||
LiquidTransportData& LiquidTransportData::operator=(const LiquidTransportData& right)
|
||||
{
|
||||
if (&right != this) {
|
||||
// These are all shallow pointer copies - yes, yes, yes horrible crime.
|
||||
speciesName = right.speciesName;
|
||||
if (right.hydroRadius) {
|
||||
hydroRadius = (right.hydroRadius)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.viscosity) {
|
||||
viscosity = (right.viscosity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.ionConductivity) {
|
||||
ionConductivity = (right.ionConductivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
|
||||
mobilityRatio = right.mobilityRatio;
|
||||
for (size_t k = 0; k < mobilityRatio.size(); k++) {
|
||||
if (right.mobilityRatio[k]) {
|
||||
mobilityRatio[k] = (right.mobilityRatio[k])->duplMyselfAsLTPspecies();
|
||||
}
|
||||
}
|
||||
|
||||
selfDiffusion = right.selfDiffusion;
|
||||
for (size_t k = 0; k < selfDiffusion.size(); k++) {
|
||||
if (right.selfDiffusion[k]) {
|
||||
selfDiffusion[k] = (right.selfDiffusion[k])->duplMyselfAsLTPspecies();
|
||||
}
|
||||
}
|
||||
|
||||
if (right.thermalCond) {
|
||||
thermalCond = (right.thermalCond)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.electCond) {
|
||||
electCond = (right.electCond)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.speciesDiffusivity) {
|
||||
speciesDiffusivity = (right.speciesDiffusivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
LiquidTransportData::~LiquidTransportData()
|
||||
{
|
||||
delete hydroRadius;
|
||||
delete viscosity;
|
||||
delete ionConductivity;
|
||||
|
||||
for (size_t k = 0; k < mobilityRatio.size(); k++) {
|
||||
delete mobilityRatio[k];
|
||||
}
|
||||
for (size_t k = 0; k < selfDiffusion.size(); k++) {
|
||||
delete selfDiffusion[k];
|
||||
}
|
||||
|
||||
delete thermalCond;
|
||||
delete electCond;
|
||||
delete speciesDiffusivity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
/**
|
||||
* @file LiquidTransportParams.cpp
|
||||
* Source code for liquid mixture transport property evaluations.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/LiquidTransportParams.h"
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
LiquidTransportParams::LiquidTransportParams() :
|
||||
viscosity(0),
|
||||
ionConductivity(0),
|
||||
thermalCond(0),
|
||||
speciesDiffusivity(0),
|
||||
electCond(0),
|
||||
hydroRadius(0),
|
||||
model_viscosity(LTI_MODEL_NOTSET),
|
||||
model_speciesDiffusivity(LTI_MODEL_NOTSET),
|
||||
model_hydroradius(LTI_MODEL_NOTSET),
|
||||
compositionDepTypeDefault_(LTI_MODEL_NOTSET)
|
||||
{
|
||||
warn_deprecated("Class LiquidTransportParams", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
LiquidTransportParams::~LiquidTransportParams()
|
||||
{
|
||||
delete viscosity;
|
||||
delete ionConductivity;
|
||||
delete thermalCond;
|
||||
delete speciesDiffusivity;
|
||||
delete electCond;
|
||||
delete hydroRadius;
|
||||
}
|
||||
|
||||
} //namespace Cantera
|
||||
@@ -1,520 +0,0 @@
|
||||
/**
|
||||
* @file SimpleTransport.cpp
|
||||
* Simple mostly constant transport properties
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/SimpleTransport.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
SimpleTransport::SimpleTransport(thermo_t* thermo, int ndim) :
|
||||
Transport(thermo, ndim),
|
||||
compositionDepType_(LTI_MODEL_SOLVENT),
|
||||
useHydroRadius_(false),
|
||||
doMigration_(0),
|
||||
m_iStateMF(-1),
|
||||
concTot_(0.0),
|
||||
meanMolecularWeight_(-1.0),
|
||||
dens_(-1.0),
|
||||
m_temp(-1.0),
|
||||
m_press(-1.0),
|
||||
m_lambda(-1.0),
|
||||
m_viscmix(-1.0),
|
||||
m_visc_mix_ok(false),
|
||||
m_visc_temp_ok(false),
|
||||
m_diff_mix_ok(false),
|
||||
m_diff_temp_ok(false),
|
||||
m_cond_temp_ok(false),
|
||||
m_cond_mix_ok(false),
|
||||
m_nDim(1)
|
||||
{
|
||||
warn_deprecated("Class SimpleTransport", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
SimpleTransport::~SimpleTransport()
|
||||
{
|
||||
for (size_t k = 0; k < m_coeffVisc_Ns.size() ; k++) {
|
||||
delete m_coeffVisc_Ns[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_coeffLambda_Ns.size(); k++) {
|
||||
delete m_coeffLambda_Ns[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_coeffDiff_Ns.size(); k++) {
|
||||
delete m_coeffDiff_Ns[k];
|
||||
}
|
||||
for (size_t k = 0; k < m_coeffHydroRadius_Ns.size(); k++) {
|
||||
delete m_coeffHydroRadius_Ns[k];
|
||||
}
|
||||
}
|
||||
|
||||
bool SimpleTransport::initLiquid(LiquidTransportParams& tr)
|
||||
{
|
||||
// constant substance attributes
|
||||
m_thermo = tr.thermo;
|
||||
m_nsp = m_thermo->nSpecies();
|
||||
|
||||
// Read the transport block in the phase XML Node
|
||||
// It's not an error if this block doesn't exist. Just use the defaults
|
||||
XML_Node& phaseNode = m_thermo->xml();
|
||||
if (phaseNode.hasChild("transport")) {
|
||||
XML_Node& transportNode = phaseNode.child("transport");
|
||||
string transportModel = transportNode.attrib("model");
|
||||
if (transportModel == "Simple") {
|
||||
compositionDepType_ = tr.compositionDepTypeDefault_;
|
||||
} else {
|
||||
throw CanteraError("SimpleTransport::initLiquid()",
|
||||
"transport model isn't the correct type: " + transportModel);
|
||||
}
|
||||
}
|
||||
|
||||
// make a local copy of the molecular weights
|
||||
m_mw = m_thermo->molecularWeights();
|
||||
|
||||
// Get the input Viscosities
|
||||
m_viscSpecies.resize(m_nsp);
|
||||
m_coeffVisc_Ns.clear();
|
||||
m_coeffVisc_Ns.resize(m_nsp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
LiquidTransportData& ltd = tr.LTData[k];
|
||||
m_coeffVisc_Ns[k] = ltd.viscosity;
|
||||
ltd.viscosity = 0;
|
||||
}
|
||||
|
||||
// Get the input thermal conductivities
|
||||
m_condSpecies.resize(m_nsp);
|
||||
m_coeffLambda_Ns.clear();
|
||||
m_coeffLambda_Ns.resize(m_nsp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
LiquidTransportData& ltd = tr.LTData[k];
|
||||
m_coeffLambda_Ns[k] = ltd.thermalCond;
|
||||
ltd.thermalCond = 0;
|
||||
}
|
||||
|
||||
// Get the input species diffusivities
|
||||
useHydroRadius_ = false;
|
||||
m_diffSpecies.resize(m_nsp);
|
||||
m_coeffDiff_Ns.clear();
|
||||
m_coeffDiff_Ns.resize(m_nsp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
string spName = m_thermo->speciesName(k);
|
||||
LiquidTransportData& ltd = tr.LTData[k];
|
||||
m_coeffDiff_Ns[k] = ltd.speciesDiffusivity;
|
||||
ltd.speciesDiffusivity = 0;
|
||||
if (!m_coeffDiff_Ns[k]) {
|
||||
if (ltd.hydroRadius) {
|
||||
m_coeffHydroRadius_Ns[k] = (ltd.hydroRadius)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (!m_coeffHydroRadius_Ns[k]) {
|
||||
throw CanteraError("SimpleTransport::initLiquid",
|
||||
"Neither diffusivity nor hydroradius is set for species " + spName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_molefracs.resize(m_nsp);
|
||||
m_concentrations.resize(m_nsp);
|
||||
m_chargeSpecies.resize(m_nsp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_chargeSpecies[k] = m_thermo->charge(k);
|
||||
}
|
||||
m_spwork.resize(m_nsp);
|
||||
|
||||
// resize the internal gradient variables
|
||||
m_Grad_X.resize(m_nDim * m_nsp, 0.0);
|
||||
m_Grad_T.resize(m_nDim, 0.0);
|
||||
m_Grad_P.resize(m_nDim, 0.0);
|
||||
m_Grad_V.resize(m_nDim, 0.0);
|
||||
|
||||
// set all flags to false
|
||||
m_visc_mix_ok = false;
|
||||
m_visc_temp_ok = false;
|
||||
m_cond_temp_ok = false;
|
||||
m_cond_mix_ok = false;
|
||||
m_diff_temp_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
doublereal SimpleTransport::viscosity()
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
|
||||
if (m_visc_mix_ok) {
|
||||
return m_viscmix;
|
||||
}
|
||||
|
||||
// update m_viscSpecies[] if necessary
|
||||
if (!m_visc_temp_ok) {
|
||||
updateViscosity_T();
|
||||
}
|
||||
|
||||
if (compositionDepType_ == LTI_MODEL_SOLVENT) {
|
||||
m_viscmix = m_viscSpecies[0];
|
||||
} else if (compositionDepType_ == LTI_MODEL_MOLEFRACS) {
|
||||
m_viscmix = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_viscmix += m_viscSpecies[k] * m_molefracs[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("SimpleTransport::viscosity()",
|
||||
"Unknowns compositionDepType");
|
||||
}
|
||||
m_visc_mix_ok = true;
|
||||
return m_viscmix;
|
||||
}
|
||||
|
||||
void SimpleTransport::getSpeciesViscosities(doublereal* const visc)
|
||||
{
|
||||
update_T();
|
||||
if (!m_visc_temp_ok) {
|
||||
updateViscosity_T();
|
||||
}
|
||||
copy(m_viscSpecies.begin(), m_viscSpecies.end(), visc);
|
||||
}
|
||||
|
||||
void SimpleTransport::getBinaryDiffCoeffs(size_t ld, doublereal* d)
|
||||
{
|
||||
update_T();
|
||||
|
||||
// if necessary, evaluate the species diffusion coefficients
|
||||
// from the polynomial fits
|
||||
if (!m_diff_temp_ok) {
|
||||
updateDiff_T();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_nsp; i++) {
|
||||
for (size_t j = 0; j < m_nsp; j++) {
|
||||
d[i*m_nsp+j] = 0.5 * (m_diffSpecies[i] + m_diffSpecies[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getMobilities(doublereal* const mobil)
|
||||
{
|
||||
getMixDiffCoeffs(m_spwork.data());
|
||||
doublereal c1 = ElectronCharge / (Boltzmann * m_temp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
mobil[k] = c1 * m_spwork[k];
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getFluidMobilities(doublereal* const mobil_f)
|
||||
{
|
||||
getMixDiffCoeffs(m_spwork.data());
|
||||
doublereal c1 = 1.0 / (GasConstant * m_temp);
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
mobil_f[k] = c1 * m_spwork[k];
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::set_Grad_V(const doublereal* const grad_V)
|
||||
{
|
||||
doMigration_ = false;
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
m_Grad_V[a] = grad_V[a];
|
||||
if (fabs(grad_V[a]) > 1.0E-13) {
|
||||
doMigration_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::set_Grad_T(const doublereal* const grad_T)
|
||||
{
|
||||
for (size_t a = 0; a < m_nDim; a++) {
|
||||
m_Grad_T[a] = grad_T[a];
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::set_Grad_X(const doublereal* const grad_X)
|
||||
{
|
||||
size_t itop = m_nDim * m_nsp;
|
||||
for (size_t i = 0; i < itop; i++) {
|
||||
m_Grad_X[i] = grad_X[i];
|
||||
}
|
||||
}
|
||||
|
||||
doublereal SimpleTransport::thermalConductivity()
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
if (!m_cond_temp_ok) {
|
||||
updateCond_T();
|
||||
}
|
||||
if (!m_cond_mix_ok) {
|
||||
if (compositionDepType_ == LTI_MODEL_SOLVENT) {
|
||||
m_lambda = m_condSpecies[0];
|
||||
} else if (compositionDepType_ == LTI_MODEL_MOLEFRACS) {
|
||||
m_lambda = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_lambda += m_condSpecies[k] * m_molefracs[k];
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("SimpleTransport::thermalConductivity()",
|
||||
"Unknown compositionDepType");
|
||||
}
|
||||
m_cond_mix_ok = true;
|
||||
}
|
||||
return m_lambda;
|
||||
}
|
||||
|
||||
void SimpleTransport::getThermalDiffCoeffs(doublereal* const dt)
|
||||
{
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
dt[k] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getSpeciesVdiff(size_t ndim,
|
||||
const doublereal* grad_T,
|
||||
int ldx,
|
||||
const doublereal* grad_X,
|
||||
int ldf,
|
||||
doublereal* Vdiff)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
const doublereal* y = m_thermo->massFractions();
|
||||
const doublereal rho = m_thermo->density();
|
||||
getSpeciesFluxesExt(m_nsp, Vdiff);
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
if (y[k] > 1.0E-200) {
|
||||
Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
|
||||
} else {
|
||||
Vdiff[n * m_nsp + k] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getSpeciesVdiffES(size_t ndim, const doublereal* grad_T,
|
||||
int ldx, const doublereal* grad_X,
|
||||
int ldf, const doublereal* grad_Phi,
|
||||
doublereal* Vdiff)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
set_Grad_V(grad_Phi);
|
||||
const doublereal* y = m_thermo->massFractions();
|
||||
const doublereal rho = m_thermo->density();
|
||||
getSpeciesFluxesExt(m_nsp, Vdiff);
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
if (y[k] > 1.0E-200) {
|
||||
Vdiff[n * m_nsp + k] *= 1.0 / (rho * y[k]);
|
||||
} else {
|
||||
Vdiff[n * m_nsp + k] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getSpeciesFluxes(size_t ndim, const doublereal* const grad_T,
|
||||
size_t ldx, const doublereal* const grad_X,
|
||||
size_t ldf, doublereal* const fluxes)
|
||||
{
|
||||
set_Grad_T(grad_T);
|
||||
set_Grad_X(grad_X);
|
||||
getSpeciesFluxesExt(ldf, fluxes);
|
||||
}
|
||||
|
||||
void SimpleTransport::getSpeciesFluxesExt(size_t ldf, doublereal* fluxes)
|
||||
{
|
||||
AssertThrow(ldf >= m_nsp ,"SimpleTransport::getSpeciesFluxesExt: Stride must be greater than m_nsp");
|
||||
update_T();
|
||||
update_C();
|
||||
|
||||
getMixDiffCoeffs(m_spwork.data());
|
||||
|
||||
const vector_fp& mw = m_thermo->molecularWeights();
|
||||
const doublereal* y = m_thermo->massFractions();
|
||||
doublereal concTotal = m_thermo->molarDensity();
|
||||
|
||||
// Unroll wrt ndim
|
||||
if (doMigration_) {
|
||||
double FRT = ElectronCharge / (Boltzmann * m_temp);
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
rhoVc[n] = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] *
|
||||
(m_Grad_X[n*m_nsp + k] + FRT * m_molefracs[k] * m_chargeSpecies[k] * m_Grad_V[n]);
|
||||
rhoVc[n] += fluxes[n*ldf + k];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
rhoVc[n] = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] = - concTotal * mw[k] * m_spwork[k] * m_Grad_X[n*m_nsp + k];
|
||||
rhoVc[n] += fluxes[n*ldf + k];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_velocityBasis == VB_MASSAVG) {
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
rhoVc[n] = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
rhoVc[n] += fluxes[n*ldf + k];
|
||||
}
|
||||
}
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] -= y[k] * rhoVc[n];
|
||||
}
|
||||
}
|
||||
} else if (m_velocityBasis == VB_MOLEAVG) {
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
rhoVc[n] = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
rhoVc[n] += fluxes[n*ldf + k] / mw[k];
|
||||
}
|
||||
}
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
|
||||
}
|
||||
}
|
||||
} else if (m_velocityBasis >= 0) {
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
rhoVc[n] = - fluxes[n*ldf + m_velocityBasis] / mw[m_velocityBasis];
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
rhoVc[n] += fluxes[n*ldf + k] / mw[k];
|
||||
}
|
||||
}
|
||||
for (size_t n = 0; n < m_nDim; n++) {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
fluxes[n*ldf + k] -= m_molefracs[k] * rhoVc[n] * mw[k];
|
||||
}
|
||||
fluxes[n*ldf + m_velocityBasis] = 0.0;
|
||||
}
|
||||
} else {
|
||||
throw CanteraError("SimpleTransport::getSpeciesFluxesExt()",
|
||||
"unknown velocity basis");
|
||||
}
|
||||
}
|
||||
|
||||
void SimpleTransport::getMixDiffCoeffs(doublereal* const d)
|
||||
{
|
||||
update_T();
|
||||
update_C();
|
||||
// update the binary diffusion coefficients if necessary
|
||||
if (!m_diff_temp_ok) {
|
||||
updateDiff_T();
|
||||
}
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
d[k] = m_diffSpecies[k];
|
||||
}
|
||||
}
|
||||
|
||||
bool SimpleTransport::update_C()
|
||||
{
|
||||
// If the pressure has changed then the concentrations have changed.
|
||||
doublereal pres = m_thermo->pressure();
|
||||
bool qReturn = true;
|
||||
if (pres != m_press) {
|
||||
qReturn = false;
|
||||
m_press = pres;
|
||||
}
|
||||
int iStateNew = m_thermo->stateMFNumber();
|
||||
if (iStateNew != m_iStateMF) {
|
||||
qReturn = false;
|
||||
m_thermo->getMoleFractions(m_molefracs.data());
|
||||
m_thermo->getConcentrations(m_concentrations.data());
|
||||
concTot_ = 0.0;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_molefracs[k] = std::max(0.0, m_molefracs[k]);
|
||||
concTot_ += m_concentrations[k];
|
||||
}
|
||||
dens_ = m_thermo->density();
|
||||
meanMolecularWeight_ = m_thermo->meanMolecularWeight();
|
||||
}
|
||||
if (qReturn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Mixture stuff needs to be evaluated
|
||||
m_visc_mix_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
m_cond_mix_ok = false;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SimpleTransport::updateCond_T()
|
||||
{
|
||||
if (compositionDepType_ == LTI_MODEL_SOLVENT) {
|
||||
m_condSpecies[0] = m_coeffLambda_Ns[0]->getSpeciesTransProp();
|
||||
} else {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_condSpecies[k] = m_coeffLambda_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
m_cond_temp_ok = true;
|
||||
m_cond_mix_ok = false;
|
||||
}
|
||||
|
||||
void SimpleTransport::updateDiff_T()
|
||||
{
|
||||
if (useHydroRadius_) {
|
||||
double visc = viscosity();
|
||||
double RT = GasConstant * m_temp;
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
double rad = m_coeffHydroRadius_Ns[k]->getSpeciesTransProp();
|
||||
m_diffSpecies[k] = RT / (6.0 * Pi * visc * rad);
|
||||
}
|
||||
} else {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_diffSpecies[k] = m_coeffDiff_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
m_diff_temp_ok = true;
|
||||
m_diff_mix_ok = false;
|
||||
}
|
||||
|
||||
void SimpleTransport::updateViscosity_T()
|
||||
{
|
||||
if (compositionDepType_ == LTI_MODEL_SOLVENT) {
|
||||
m_viscSpecies[0] = m_coeffVisc_Ns[0]->getSpeciesTransProp();
|
||||
} else {
|
||||
for (size_t k = 0; k < m_nsp; k++) {
|
||||
m_viscSpecies[k] = m_coeffVisc_Ns[k]->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
m_visc_temp_ok = true;
|
||||
m_visc_mix_ok = false;
|
||||
}
|
||||
|
||||
bool SimpleTransport::update_T()
|
||||
{
|
||||
doublereal t = m_thermo->temperature();
|
||||
if (t == m_temp) {
|
||||
return false;
|
||||
}
|
||||
if (t < 0.0) {
|
||||
throw CanteraError("SimpleTransport::update_T",
|
||||
"negative temperature {}", t);
|
||||
}
|
||||
|
||||
// Compute various functions of temperature
|
||||
m_temp = t;
|
||||
|
||||
// temperature has changed, so polynomial temperature interpolations will
|
||||
// need to be reevaluated. Set all of these flags to false
|
||||
m_visc_mix_ok = false;
|
||||
m_visc_temp_ok = false;
|
||||
m_cond_temp_ok = false;
|
||||
m_cond_mix_ok = false;
|
||||
m_diff_mix_ok = false;
|
||||
m_diff_temp_ok = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/**
|
||||
* @file SolidTransport.cpp
|
||||
* Definition file for the class SolidTransport, which handles transport
|
||||
* of ions within solid phases
|
||||
* (see \ref tranprops and \link Cantera::SolidTransport SolidTransport \endlink).
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/SolidTransport.h"
|
||||
#include "cantera/transport/SolidTransportData.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
|
||||
SolidTransport::SolidTransport() :
|
||||
m_nmobile(0),
|
||||
m_Alam(-1.0),
|
||||
m_Nlam(0),
|
||||
m_Elam(0)
|
||||
{
|
||||
warn_deprecated("Class SolidTransport", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
bool SolidTransport::initSolid(SolidTransportData& tr)
|
||||
{
|
||||
m_thermo = tr.thermo;
|
||||
tr.thermo = 0;
|
||||
m_ionConductivity = tr.ionConductivity;
|
||||
tr.ionConductivity = 0;
|
||||
m_electConductivity = tr.electConductivity;
|
||||
tr.electConductivity = 0;
|
||||
m_thermalConductivity = tr.thermalConductivity;
|
||||
tr.thermalConductivity = 0;
|
||||
m_defectDiffusivity = tr.defectDiffusivity;
|
||||
tr.defectDiffusivity = 0;
|
||||
m_defectActivity = tr.defectActivity;
|
||||
tr.defectActivity = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SolidTransport::setParameters(const int n, const int k, const doublereal* const p)
|
||||
{
|
||||
switch (n) {
|
||||
case 0:
|
||||
// set the Arrhenius parameters for the diffusion coefficient
|
||||
// of species k.
|
||||
m_sp.push_back(k);
|
||||
m_Adiff.push_back(p[0]);
|
||||
m_Ndiff.push_back(p[1]);
|
||||
m_Ediff.push_back(p[2]);
|
||||
m_nmobile = m_sp.size();
|
||||
break;
|
||||
case 1:
|
||||
// set the thermal conductivity Arrhenius parameters.
|
||||
m_Alam = p[0];
|
||||
m_Nlam = p[2];
|
||||
m_Elam = p[2];
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
m_work.resize(m_thermo->nSpecies());
|
||||
}
|
||||
|
||||
doublereal SolidTransport::ionConductivity()
|
||||
{
|
||||
// LTPspecies method
|
||||
return m_ionConductivity->getSpeciesTransProp();
|
||||
}
|
||||
|
||||
doublereal SolidTransport::electricalConductivity()
|
||||
{
|
||||
if (m_nmobile == 0) {
|
||||
// LTPspecies method
|
||||
return m_electConductivity->getSpeciesTransProp();
|
||||
} else {
|
||||
getMobilities(&m_work[0]);
|
||||
doublereal sum = 0.0;
|
||||
for (size_t k = 0; k < m_thermo->nSpecies(); k++) {
|
||||
sum += m_thermo->charge(k) * m_thermo->moleFraction(k) * m_work[k];
|
||||
}
|
||||
return sum * m_thermo->molarDensity();
|
||||
}
|
||||
}
|
||||
|
||||
/****************** thermalConductivity ******************************/
|
||||
|
||||
doublereal SolidTransport::thermalConductivity()
|
||||
{
|
||||
if (m_Alam > 0.0) {
|
||||
//legacy test case?
|
||||
doublereal t = m_thermo->temperature();
|
||||
return m_Alam * pow(t, m_Nlam) * exp(-m_Elam/t);
|
||||
} else {
|
||||
// LTPspecies method
|
||||
return m_thermalConductivity->getSpeciesTransProp();
|
||||
}
|
||||
}
|
||||
|
||||
doublereal SolidTransport::defectDiffusivity()
|
||||
{
|
||||
// LTPspecies method
|
||||
return m_defectDiffusivity->getSpeciesTransProp();
|
||||
}
|
||||
|
||||
doublereal SolidTransport::defectActivity()
|
||||
{
|
||||
// LTPspecies method
|
||||
return m_defectActivity->getSpeciesTransProp();
|
||||
}
|
||||
|
||||
void SolidTransport::getMobilities(doublereal* const mobil)
|
||||
{
|
||||
getMixDiffCoeffs(mobil);
|
||||
doublereal t = m_thermo->temperature();
|
||||
doublereal c1 = ElectronCharge / (Boltzmann * t);
|
||||
for (size_t k = 0; k < m_thermo->nSpecies(); k++) {
|
||||
mobil[k] *= c1;
|
||||
}
|
||||
}
|
||||
|
||||
void SolidTransport::getMixDiffCoeffs(doublereal* const d)
|
||||
{
|
||||
for (size_t k = 0; k < m_thermo->nSpecies(); k++) {
|
||||
d[k] = 0.0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/**
|
||||
* @file SolidTransportData.cpp
|
||||
* Source code for solid transport property evaluations.
|
||||
*/
|
||||
|
||||
// This file is part of Cantera. See License.txt in the top-level directory or
|
||||
// at http://www.cantera.org/license.txt for license and copyright information.
|
||||
|
||||
#include "cantera/transport/SolidTransportData.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace Cantera
|
||||
{
|
||||
SolidTransportData::SolidTransportData() :
|
||||
speciesName("-"),
|
||||
ionConductivity(0),
|
||||
thermalConductivity(0),
|
||||
electConductivity(0),
|
||||
defectDiffusivity(0),
|
||||
defectActivity(0)
|
||||
{
|
||||
warn_deprecated("Class SolidTransportData", "To be removed after Cantera 2.4");
|
||||
}
|
||||
|
||||
SolidTransportData::SolidTransportData(const SolidTransportData& right) :
|
||||
speciesName("-"),
|
||||
ionConductivity(0),
|
||||
thermalConductivity(0),
|
||||
electConductivity(0),
|
||||
defectDiffusivity(0),
|
||||
defectActivity(0)
|
||||
{
|
||||
*this = right; //use assignment operator to do other work
|
||||
}
|
||||
|
||||
SolidTransportData& SolidTransportData::operator=(const SolidTransportData& right)
|
||||
{
|
||||
if (&right != this) {
|
||||
// These are all shallow pointer copies - yes, yes, yes horrible crime.
|
||||
speciesName = right.speciesName;
|
||||
if (right.ionConductivity) {
|
||||
ionConductivity = (right.ionConductivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
|
||||
if (right.thermalConductivity) {
|
||||
thermalConductivity = (right.thermalConductivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.electConductivity) {
|
||||
electConductivity = (right.electConductivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.defectDiffusivity) {
|
||||
defectDiffusivity = (right.defectDiffusivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
if (right.defectActivity) {
|
||||
defectActivity = (right.defectActivity)->duplMyselfAsLTPspecies();
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
SolidTransportData::~SolidTransportData()
|
||||
{
|
||||
delete ionConductivity;
|
||||
delete thermalConductivity;
|
||||
delete electConductivity;
|
||||
delete defectDiffusivity;
|
||||
delete defectActivity;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -9,13 +9,9 @@
|
||||
#include "cantera/transport/UnityLewisTransport.h"
|
||||
#include "cantera/transport/IonGasTransport.h"
|
||||
#include "cantera/transport/WaterTransport.h"
|
||||
#include "cantera/transport/SolidTransport.h"
|
||||
#include "cantera/transport/DustyGasTransport.h"
|
||||
#include "cantera/transport/SimpleTransport.h"
|
||||
#include "cantera/transport/LiquidTransport.h"
|
||||
#include "cantera/transport/HighPressureGasTransport.h"
|
||||
#include "cantera/transport/TransportFactory.h"
|
||||
#include "cantera/transport/SolidTransportData.h"
|
||||
#include "cantera/base/ctml.h"
|
||||
#include "cantera/base/stringUtils.h"
|
||||
#include "cantera/base/utilities.h"
|
||||
@@ -59,34 +55,6 @@ TransportFactory::TransportFactory()
|
||||
reg("HighP", []() { return new HighPressureGasTransport(); });
|
||||
m_CK_mode["CK_Mix"] = true;
|
||||
m_CK_mode["CK_Multi"] = true;
|
||||
|
||||
m_tranPropMap["viscosity"] = TP_VISCOSITY;
|
||||
m_tranPropMap["ionConductivity"] = TP_IONCONDUCTIVITY;
|
||||
m_tranPropMap["mobilityRatio"] = TP_MOBILITYRATIO;
|
||||
m_tranPropMap["selfDiffusion"] = TP_SELFDIFFUSION;
|
||||
m_tranPropMap["thermalConductivity"] = TP_THERMALCOND;
|
||||
m_tranPropMap["speciesDiffusivity"] = TP_DIFFUSIVITY;
|
||||
m_tranPropMap["hydrodynamicRadius"] = TP_HYDRORADIUS;
|
||||
m_tranPropMap["electricalConductivity"] = TP_ELECTCOND;
|
||||
m_tranPropMap["defectDiffusivity"] = TP_DEFECTDIFF;
|
||||
m_tranPropMap["defectActivity"] = TP_DEFECTCONC;
|
||||
|
||||
m_LTRmodelMap[""] = LTP_TD_CONSTANT;
|
||||
m_LTRmodelMap["constant"] = LTP_TD_CONSTANT;
|
||||
m_LTRmodelMap["arrhenius"] = LTP_TD_ARRHENIUS;
|
||||
m_LTRmodelMap["coeffs"] = LTP_TD_POLY;
|
||||
m_LTRmodelMap["exptemp"] = LTP_TD_EXPT;
|
||||
|
||||
m_LTImodelMap[""] = LTI_MODEL_NOTSET;
|
||||
m_LTImodelMap["solvent"] = LTI_MODEL_SOLVENT;
|
||||
m_LTImodelMap["moleFractions"] = LTI_MODEL_MOLEFRACS;
|
||||
m_LTImodelMap["massFractions"] = LTI_MODEL_MASSFRACS;
|
||||
m_LTImodelMap["logMoleFractions"] = LTI_MODEL_LOG_MOLEFRACS;
|
||||
m_LTImodelMap["pairwiseInteraction"] = LTI_MODEL_PAIRWISE_INTERACTION;
|
||||
m_LTImodelMap["stefanMaxwell_PPN"] = LTI_MODEL_STEFANMAXWELL_PPN;
|
||||
m_LTImodelMap["moleFractionsExpT"] = LTI_MODEL_MOLEFRACS_EXPT;
|
||||
m_LTImodelMap["none"] = LTI_MODEL_NONE;
|
||||
m_LTImodelMap["multiple"] = LTI_MODEL_MULTIPLE;
|
||||
}
|
||||
|
||||
void TransportFactory::deleteFactory()
|
||||
@@ -96,89 +64,6 @@ void TransportFactory::deleteFactory()
|
||||
s_factory = 0;
|
||||
}
|
||||
|
||||
LTPspecies* TransportFactory::newLTP(const XML_Node& trNode, const std::string& name,
|
||||
TransportPropertyType tp_ind, thermo_t* thermo)
|
||||
{
|
||||
std::string model = toLowerCopy(trNode["model"]);
|
||||
LTPspecies* sp;
|
||||
switch (m_LTRmodelMap[model]) {
|
||||
case LTP_TD_CONSTANT:
|
||||
sp = new LTPspecies_Const();
|
||||
break;
|
||||
case LTP_TD_ARRHENIUS:
|
||||
sp = new LTPspecies_Arrhenius();
|
||||
break;
|
||||
case LTP_TD_POLY:
|
||||
sp = new LTPspecies_Poly();
|
||||
break;
|
||||
case LTP_TD_EXPT:
|
||||
sp = new LTPspecies_ExpT();
|
||||
break;
|
||||
default:
|
||||
throw CanteraError("TransportFactory::newLTP","unknown transport model: " + model);
|
||||
}
|
||||
sp->setName(name);
|
||||
sp->setThermo(thermo);
|
||||
sp->setTransportPropertyType(tp_ind);
|
||||
sp->setupFromXML(trNode);
|
||||
return sp;
|
||||
}
|
||||
|
||||
LiquidTranInteraction* TransportFactory::newLTI(const XML_Node& trNode,
|
||||
TransportPropertyType tp_ind,
|
||||
LiquidTransportParams& trParam)
|
||||
{
|
||||
LiquidTranInteraction* lti = 0;
|
||||
switch (m_LTImodelMap[trNode["model"]]) {
|
||||
case LTI_MODEL_SOLVENT:
|
||||
lti = new LTI_Solvent(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
case LTI_MODEL_MOLEFRACS:
|
||||
lti = new LTI_MoleFracs(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
case LTI_MODEL_MASSFRACS:
|
||||
lti = new LTI_MassFracs(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
case LTI_MODEL_LOG_MOLEFRACS:
|
||||
lti = new LTI_Log_MoleFracs(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
case LTI_MODEL_PAIRWISE_INTERACTION:
|
||||
lti = new LTI_Pairwise_Interaction(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
lti->setParameters(trParam);
|
||||
break;
|
||||
case LTI_MODEL_STEFANMAXWELL_PPN:
|
||||
lti = new LTI_StefanMaxwell_PPN(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
lti->setParameters(trParam);
|
||||
break;
|
||||
case LTI_MODEL_STOKES_EINSTEIN:
|
||||
lti = new LTI_StokesEinstein(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
lti->setParameters(trParam);
|
||||
break;
|
||||
case LTI_MODEL_MOLEFRACS_EXPT:
|
||||
lti = new LTI_MoleFracs_ExpT(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
case LTI_MODEL_NOTSET:
|
||||
case LTI_MODEL_NONE:
|
||||
case LTI_MODEL_MULTIPLE:
|
||||
lti = new LiquidTranInteraction(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
break;
|
||||
default:
|
||||
// @TODO make sure we can throw an error here with existing datasets and tests before changing code
|
||||
lti = new LiquidTranInteraction(tp_ind);
|
||||
lti->init(trNode, trParam.thermo);
|
||||
}
|
||||
return lti;
|
||||
}
|
||||
|
||||
Transport* TransportFactory::newTransport(const std::string& transportModel,
|
||||
thermo_t* phase, int log_level, int ndim)
|
||||
{
|
||||
@@ -186,24 +71,12 @@ Transport* TransportFactory::newTransport(const std::string& transportModel,
|
||||
Transport* tr = 0;
|
||||
phase->saveState(state);
|
||||
|
||||
if (transportModel == "Solid") {
|
||||
tr = new SolidTransport;
|
||||
initSolidTransport(tr, phase, log_level);
|
||||
tr->setThermo(*phase);
|
||||
} else if (transportModel == "DustyGas") {
|
||||
if (transportModel == "DustyGas") {
|
||||
tr = new DustyGasTransport;
|
||||
Transport* gastr = new MultiTransport;
|
||||
gastr->init(phase, 0, log_level);
|
||||
DustyGasTransport* dtr = (DustyGasTransport*)tr;
|
||||
dtr->initialize(phase, gastr);
|
||||
} else if (transportModel == "Simple") {
|
||||
tr = new SimpleTransport();
|
||||
initLiquidTransport(tr, phase, log_level);
|
||||
tr->setThermo(*phase);
|
||||
} else if (transportModel == "Liquid") {
|
||||
tr = new LiquidTransport(phase, ndim);
|
||||
initLiquidTransport(tr, phase, log_level);
|
||||
tr->setThermo(*phase);
|
||||
} else {
|
||||
tr = create(transportModel);
|
||||
int mode = m_CK_mode[transportModel] ? CK_Mode : 0;
|
||||
@@ -223,368 +96,6 @@ Transport* TransportFactory::newTransport(thermo_t* phase, int log_level)
|
||||
return newTransport(transportModel, phase,log_level);
|
||||
}
|
||||
|
||||
void TransportFactory::setupLiquidTransport(thermo_t* thermo, int log_level,
|
||||
LiquidTransportParams& trParam)
|
||||
{
|
||||
const std::vector<const XML_Node*> & species_database = thermo->speciesData();
|
||||
const XML_Node* phase_database = &thermo->xml();
|
||||
|
||||
// constant mixture attributes
|
||||
trParam.thermo = thermo;
|
||||
trParam.nsp_ = trParam.thermo->nSpecies();
|
||||
size_t nsp = trParam.nsp_;
|
||||
trParam.tmin = thermo->minTemp();
|
||||
trParam.tmax = thermo->maxTemp();
|
||||
trParam.log_level = log_level;
|
||||
|
||||
// Get the molecular weights and load them into trParam
|
||||
trParam.mw = trParam.thermo->molecularWeights();
|
||||
|
||||
// Resize all other vectors in trParam
|
||||
trParam.LTData.resize(nsp);
|
||||
|
||||
// Need to identify a method to obtain interaction matrices.
|
||||
// This will fill LiquidTransportParams members visc_Eij, visc_Sij
|
||||
trParam.thermalCond_Aij.resize(nsp,nsp);
|
||||
trParam.diff_Dij.resize(nsp,nsp);
|
||||
trParam.radius_Aij.resize(nsp,nsp);
|
||||
|
||||
XML_Node log;
|
||||
// Note that getLiquidSpeciesTransportData just populates the pure species transport data.
|
||||
getLiquidSpeciesTransportData(species_database, log, trParam.thermo->speciesNames(), trParam);
|
||||
|
||||
// getLiquidInteractionsTransportData() populates the species-species
|
||||
// interaction models parameters like visc_Eij
|
||||
if (phase_database->hasChild("transport")) {
|
||||
XML_Node& transportNode = phase_database->child("transport");
|
||||
getLiquidInteractionsTransportData(transportNode, log, trParam.thermo->speciesNames(), trParam);
|
||||
}
|
||||
}
|
||||
|
||||
void TransportFactory::setupSolidTransport(thermo_t* thermo, int log_level,
|
||||
SolidTransportData& trParam)
|
||||
{
|
||||
const XML_Node* phase_database = &thermo->xml();
|
||||
|
||||
// constant mixture attributes
|
||||
trParam.thermo = thermo;
|
||||
trParam.nsp_ = trParam.thermo->nSpecies();
|
||||
trParam.tmin = thermo->minTemp();
|
||||
trParam.tmax = thermo->maxTemp();
|
||||
trParam.log_level = log_level;
|
||||
|
||||
// Get the molecular weights and load them into trParam
|
||||
trParam.mw = trParam.thermo->molecularWeights();
|
||||
|
||||
// getSolidTransportData() populates the phase transport models like
|
||||
// electronic conductivity thermal conductivity, interstitial diffusion
|
||||
if (phase_database->hasChild("transport")) {
|
||||
XML_Node log;
|
||||
XML_Node& transportNode = phase_database->child("transport");
|
||||
getSolidTransportData(transportNode, log, thermo->name(), trParam);
|
||||
}
|
||||
}
|
||||
|
||||
void TransportFactory::initLiquidTransport(Transport* tran,
|
||||
thermo_t* thermo,
|
||||
int log_level)
|
||||
{
|
||||
LiquidTransportParams trParam;
|
||||
setupLiquidTransport(thermo, log_level, trParam);
|
||||
// do model-specific initialization
|
||||
tran->initLiquid(trParam);
|
||||
}
|
||||
|
||||
void TransportFactory::initSolidTransport(Transport* tran,
|
||||
thermo_t* thermo,
|
||||
int log_level)
|
||||
{
|
||||
SolidTransportData trParam;
|
||||
setupSolidTransport(thermo, log_level, trParam);
|
||||
// do model-specific initialization
|
||||
tran->initSolid(trParam);
|
||||
}
|
||||
|
||||
void TransportFactory::getLiquidSpeciesTransportData(const std::vector<const XML_Node*> &xspecies,
|
||||
XML_Node& log,
|
||||
const std::vector<std::string> &names,
|
||||
LiquidTransportParams& trParam)
|
||||
{
|
||||
// Create a map of species names versus liquid transport data parameters
|
||||
std::map<std::string, LiquidTransportData> datatable;
|
||||
|
||||
// Store the number of species in the phase
|
||||
size_t nsp = trParam.nsp_;
|
||||
|
||||
// Store the number of off-diagonal symmetric interactions between species in the phase
|
||||
size_t nBinInt = nsp*(nsp-1)/2;
|
||||
|
||||
// read all entries in database into 'datatable' and check for errors. Note
|
||||
// that this procedure validates all entries, not only those for the species
|
||||
// listed in 'names'.
|
||||
for (size_t i = 0; i < nsp; i++) {
|
||||
const XML_Node& sp = *xspecies[i];
|
||||
string name = sp["name"];
|
||||
|
||||
// Species with no 'transport' child are skipped. However, if that
|
||||
// species is in the list, it will throw an exception below.
|
||||
if (sp.hasChild("transport")) {
|
||||
XML_Node& trNode = sp.child("transport");
|
||||
|
||||
// Fill datatable with LiquidTransportData objects for error checking
|
||||
// and then insertion into LiquidTransportData objects below.
|
||||
LiquidTransportData data;
|
||||
data.speciesName = name;
|
||||
data.mobilityRatio.resize(nsp*nsp,0);
|
||||
data.selfDiffusion.resize(nsp,0);
|
||||
size_t num = trNode.nChildren();
|
||||
for (size_t iChild = 0; iChild < num; iChild++) {
|
||||
XML_Node& xmlChild = trNode.child(iChild);
|
||||
std::string nodeName = xmlChild.name();
|
||||
|
||||
switch (m_tranPropMap[nodeName]) {
|
||||
case TP_VISCOSITY:
|
||||
data.viscosity = newLTP(xmlChild, name, m_tranPropMap[nodeName], trParam.thermo);
|
||||
break;
|
||||
case TP_IONCONDUCTIVITY:
|
||||
data.ionConductivity = newLTP(xmlChild, name, m_tranPropMap[nodeName], trParam.thermo);
|
||||
break;
|
||||
case TP_MOBILITYRATIO: {
|
||||
for (size_t iSpec = 0; iSpec< nBinInt; iSpec++) {
|
||||
XML_Node& propSpecNode = xmlChild.child(iSpec);
|
||||
std::string specName = propSpecNode.name();
|
||||
size_t loc = specName.find(":");
|
||||
std::string firstSpec = specName.substr(0,loc);
|
||||
std::string secondSpec = specName.substr(loc+1);
|
||||
size_t index = trParam.thermo->speciesIndex(firstSpec)+nsp*trParam.thermo->speciesIndex(secondSpec);
|
||||
data.mobilityRatio[index] = newLTP(propSpecNode, name, m_tranPropMap[nodeName], trParam.thermo);
|
||||
};
|
||||
};
|
||||
break;
|
||||
case TP_SELFDIFFUSION: {
|
||||
for (size_t iSpec = 0; iSpec< nsp; iSpec++) {
|
||||
XML_Node& propSpecNode = xmlChild.child(iSpec);
|
||||
std::string specName = propSpecNode.name();
|
||||
size_t index = trParam.thermo->speciesIndex(specName);
|
||||
data.selfDiffusion[index] = newLTP(propSpecNode, name, m_tranPropMap[nodeName], trParam.thermo);
|
||||
};
|
||||
};
|
||||
break;
|
||||
case TP_THERMALCOND:
|
||||
data.thermalCond = newLTP(xmlChild,
|
||||
name,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_DIFFUSIVITY:
|
||||
data.speciesDiffusivity = newLTP(xmlChild,
|
||||
name,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_HYDRORADIUS:
|
||||
data.hydroRadius = newLTP(xmlChild,
|
||||
name,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_ELECTCOND:
|
||||
data.electCond = newLTP(xmlChild,
|
||||
name,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
default:
|
||||
throw CanteraError("getLiquidSpeciesTransportData","unknown transport property: " + nodeName);
|
||||
}
|
||||
}
|
||||
datatable[name] = data;
|
||||
}
|
||||
}
|
||||
|
||||
trParam.LTData.clear();
|
||||
for (size_t i = 0; i < trParam.nsp_; i++) {
|
||||
// Check to see that we have a LiquidTransportData object for all of the
|
||||
// species in the phase. If not, throw an error.
|
||||
auto it = datatable.find(names[i]);
|
||||
if (it == datatable.end()) {
|
||||
throw TransportDBError(0,"No transport data found for species " + names[i]);
|
||||
}
|
||||
|
||||
// Now, transfer these objects into LTData in the correct phase index
|
||||
// order by calling the default copy constructor for
|
||||
// LiquidTransportData.
|
||||
trParam.LTData.push_back(it->second);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Read transport property data from a file for interactions between species in
|
||||
* a liquid. Given the name of a file containing transport property parameters
|
||||
* and a list of species names, this method returns an instance of
|
||||
* TransportParams containing the transport data for these species read from the
|
||||
* file.
|
||||
*/
|
||||
void TransportFactory::getLiquidInteractionsTransportData(const XML_Node& transportNode,
|
||||
XML_Node& log,
|
||||
const std::vector<std::string> &names,
|
||||
LiquidTransportParams& trParam)
|
||||
{
|
||||
try {
|
||||
size_t nsp = trParam.nsp_;
|
||||
size_t nBinInt = nsp*(nsp-1)/2;
|
||||
for (size_t iChild = 0; iChild < transportNode.nChildren(); iChild++) {
|
||||
//tranTypeNode is a type of transport property like viscosity
|
||||
XML_Node& tranTypeNode = transportNode.child(iChild);
|
||||
std::string nodeName = tranTypeNode.name();
|
||||
trParam.mobilityRatio.resize(nsp*nsp,0);
|
||||
trParam.selfDiffusion.resize(nsp,0);
|
||||
|
||||
if (tranTypeNode.name() == "compositionDependence") {
|
||||
std::string modelName = tranTypeNode.attrib("model");
|
||||
auto it = m_LTImodelMap.find(modelName);
|
||||
if (it == m_LTImodelMap.end()) {
|
||||
throw CanteraError("TransportFactory::getLiquidInteractionsTransportData",
|
||||
"Unknown compositionDependence string: " + modelName);
|
||||
} else {
|
||||
trParam.compositionDepTypeDefault_ = it->second;
|
||||
}
|
||||
} else {
|
||||
if (tranTypeNode.hasChild("compositionDependence")) {
|
||||
//compDepNode contains the interaction model
|
||||
XML_Node& compDepNode = tranTypeNode.child("compositionDependence");
|
||||
switch (m_tranPropMap[nodeName]) {
|
||||
break;
|
||||
case TP_VISCOSITY:
|
||||
trParam.viscosity = newLTI(compDepNode, m_tranPropMap[nodeName], trParam);
|
||||
break;
|
||||
case TP_IONCONDUCTIVITY:
|
||||
trParam.ionConductivity = newLTI(compDepNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
break;
|
||||
case TP_MOBILITYRATIO: {
|
||||
for (size_t iSpec = 0; iSpec< nBinInt; iSpec++) {
|
||||
XML_Node& propSpecNode = compDepNode.child(iSpec);
|
||||
string specName = propSpecNode.name();
|
||||
size_t loc = specName.find(":");
|
||||
string firstSpec = specName.substr(0,loc);
|
||||
string secondSpec = specName.substr(loc+1);
|
||||
size_t index = trParam.thermo->speciesIndex(firstSpec)+nsp*trParam.thermo->speciesIndex(secondSpec);
|
||||
trParam.mobilityRatio[index] = newLTI(propSpecNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
};
|
||||
};
|
||||
break;
|
||||
case TP_SELFDIFFUSION: {
|
||||
for (size_t iSpec = 0; iSpec< nsp; iSpec++) {
|
||||
XML_Node& propSpecNode = compDepNode.child(iSpec);
|
||||
string specName = propSpecNode.name();
|
||||
size_t index = trParam.thermo->speciesIndex(specName);
|
||||
trParam.selfDiffusion[index] = newLTI(propSpecNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
};
|
||||
};
|
||||
break;
|
||||
case TP_THERMALCOND:
|
||||
trParam.thermalCond = newLTI(compDepNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
break;
|
||||
case TP_DIFFUSIVITY:
|
||||
trParam.speciesDiffusivity = newLTI(compDepNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
break;
|
||||
case TP_HYDRORADIUS:
|
||||
trParam.hydroRadius = newLTI(compDepNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
break;
|
||||
case TP_ELECTCOND:
|
||||
trParam.electCond = newLTI(compDepNode,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam);
|
||||
break;
|
||||
default:
|
||||
throw CanteraError("getLiquidInteractionsTransportData","unknown transport property: " + nodeName);
|
||||
}
|
||||
}
|
||||
/* Allow a switch between mass-averaged, mole-averaged
|
||||
* and solvent specified reference velocities.
|
||||
* XML code within the transportProperty node
|
||||
* (i.e. within <viscosity>) should read as follows
|
||||
* <velocityBasis basis="mass"> <!-- mass averaged -->
|
||||
* <velocityBasis basis="mole"> <!-- mole averaged -->
|
||||
* <velocityBasis basis="H2O"> <!-- H2O solvent -->
|
||||
*/
|
||||
if (tranTypeNode.hasChild("velocityBasis")) {
|
||||
std::string velocityBasis =
|
||||
tranTypeNode.child("velocityBasis").attrib("basis");
|
||||
if (velocityBasis == "mass") {
|
||||
trParam.velocityBasis_ = VB_MASSAVG;
|
||||
} else if (velocityBasis == "mole") {
|
||||
trParam.velocityBasis_ = VB_MOLEAVG;
|
||||
} else if (trParam.thermo->speciesIndex(velocityBasis) > 0) {
|
||||
trParam.velocityBasis_ = static_cast<int>(trParam.thermo->speciesIndex(velocityBasis));
|
||||
} else {
|
||||
int linenum = __LINE__;
|
||||
throw TransportDBError(linenum, "Unknown attribute \"" + velocityBasis + "\" for <velocityBasis> node. ");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (CanteraError& err) {
|
||||
std::cout << err.what() << std::endl;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
void TransportFactory::getSolidTransportData(const XML_Node& transportNode,
|
||||
XML_Node& log,
|
||||
const std::string phaseName,
|
||||
SolidTransportData& trParam)
|
||||
{
|
||||
for (size_t iChild = 0; iChild < transportNode.nChildren(); iChild++) {
|
||||
//tranTypeNode is a type of transport property like viscosity
|
||||
XML_Node& tranTypeNode = transportNode.child(iChild);
|
||||
std::string nodeName = tranTypeNode.name();
|
||||
|
||||
//tranTypeNode contains the interaction model
|
||||
switch (m_tranPropMap[nodeName]) {
|
||||
case TP_IONCONDUCTIVITY:
|
||||
trParam.ionConductivity = newLTP(tranTypeNode, phaseName,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_THERMALCOND:
|
||||
trParam.thermalConductivity = newLTP(tranTypeNode, phaseName,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_DEFECTDIFF:
|
||||
trParam.defectDiffusivity = newLTP(tranTypeNode, phaseName,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_DEFECTCONC:
|
||||
trParam.defectActivity = newLTP(tranTypeNode, phaseName,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
case TP_ELECTCOND:
|
||||
trParam.electConductivity = newLTP(tranTypeNode, phaseName,
|
||||
m_tranPropMap[nodeName],
|
||||
trParam.thermo);
|
||||
break;
|
||||
default:
|
||||
throw CanteraError("getSolidTransportData","unknown transport property: " + nodeName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Transport* newTransportMgr(const std::string& transportModel, thermo_t* thermo, int loglevel, int ndim)
|
||||
{
|
||||
TransportFactory* f = TransportFactory::factory();
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
NaCl modeling Based on the Silvester&Pitzer 1977 treatment:
|
||||
|
||||
(L. F. Silvester, K. S. Pitzer, "Thermodynamics of Electrolytes:
|
||||
8. High-Temperature Properties, including Enthalpy and Heat
|
||||
Capacity, with application to sodium chloride",
|
||||
J. Phys. Chem., 81, 19 1822 - 1828 (1977)
|
||||
-->
|
||||
<ctml>
|
||||
<phase id="NaCl_electrolyte" dim="3">
|
||||
<speciesArray datasrc="#species_waterSolution">
|
||||
H2O(L) Na+ Cl- H+ OH-
|
||||
</speciesArray>
|
||||
<state>
|
||||
<temperature units="K"> 298.15 </temperature>
|
||||
<pressure units="Pa"> 101325.0 </pressure>
|
||||
<soluteMolalities>
|
||||
Na+:6.0954
|
||||
Cl-:6.0954
|
||||
H+:2.1628E-9
|
||||
OH-:1.3977E-6
|
||||
</soluteMolalities>
|
||||
</state>
|
||||
|
||||
<thermo model="HMW">
|
||||
<standardConc model="solvent_volume" />
|
||||
<activityCoefficients model="Pitzer" TempModel="complex1">
|
||||
<!-- Pitzer Coefficients
|
||||
These coefficients are from Pitzer's main
|
||||
paper, in his book.
|
||||
-->
|
||||
<A_Debye model="water" />
|
||||
<ionicRadius default="3.042843" units="Angstroms">
|
||||
</ionicRadius>
|
||||
<binarySaltParameters cation="Na+" anion="Cl-">
|
||||
<beta0> 0.0765, 0.008946, -3.3158E-6,
|
||||
-777.03, -4.4706
|
||||
</beta0>
|
||||
<beta1> 0.2664, 6.1608E-5, 1.0715E-6, 0.0, 0.0 </beta1>
|
||||
<beta2> 0.0, 0.0, 0.0, 0.0, 0.0 </beta2>
|
||||
<Cphi> 0.00127, -4.655E-5, 0.0,
|
||||
33.317, 0.09421
|
||||
</Cphi>
|
||||
<Alpha1> 2.0 </Alpha1>
|
||||
</binarySaltParameters>
|
||||
|
||||
<binarySaltParameters cation="H+" anion="Cl-">
|
||||
<beta0> 0.1775, 0.0, 0.0, 0.0, 0.0 </beta0>
|
||||
<beta1> 0.2945, 0.0, 0.0, 0.0, 0.0 </beta1>
|
||||
<beta2> 0.0, 0.0, 0.0, 0.0, 0.0 </beta2>
|
||||
<Cphi> 0.0008, 0.0, 0.0, 0.0, 0.0 </Cphi>
|
||||
<Alpha1> 2.0 </Alpha1>
|
||||
</binarySaltParameters>
|
||||
|
||||
<binarySaltParameters cation="Na+" anion="OH-">
|
||||
<beta0> 0.0864, 0.0, 0.0, 0.0, 0.0 </beta0>
|
||||
<beta1> 0.253, 0.0, 0.0, 0.0, 0.0 </beta1>
|
||||
<beta2> 0.0, 0.0, 0.0, 0.0, 0.0 </beta2>
|
||||
<Cphi> 0.0044, 0.0, 0.0, 0.0, 0.0 </Cphi>
|
||||
<Alpha1> 2.0 </Alpha1>
|
||||
</binarySaltParameters>
|
||||
|
||||
<thetaAnion anion1="Cl-" anion2="OH-">
|
||||
<Theta> -0.05 </Theta>
|
||||
</thetaAnion>
|
||||
|
||||
<psiCommonCation cation="Na+" anion1="Cl-" anion2="OH-">
|
||||
<Theta> -0.05 </Theta>
|
||||
<Psi> -0.006 </Psi>
|
||||
</psiCommonCation>
|
||||
|
||||
<thetaCation cation1="Na+" cation2="H+">
|
||||
<Theta> 0.036 </Theta>
|
||||
</thetaCation>
|
||||
|
||||
<psiCommonAnion anion="Cl-" cation1="Na+" cation2="H+">
|
||||
<Theta> 0.036 </Theta>
|
||||
<Psi> -0.004 </Psi>
|
||||
</psiCommonAnion>
|
||||
|
||||
</activityCoefficients>
|
||||
<solvent> H2O(L) </solvent>
|
||||
</thermo>
|
||||
<elementArray datasrc="elements.xml"> O H C E Fe Si N Na Cl </elementArray>
|
||||
<kinetics model="none" >
|
||||
</kinetics>
|
||||
<transport model="Simple">
|
||||
<compositionDependence model="solvent"/>
|
||||
<!--
|
||||
<compositionDependence model="Mixture_Averaged"/>
|
||||
-->
|
||||
</transport>
|
||||
</phase>
|
||||
|
||||
<speciesData id="species_waterSolution">
|
||||
|
||||
|
||||
<species name="H2O(L)">
|
||||
<!-- H2O(L) liquid standard state -> pure H2O
|
||||
The origin of the NASA polynomial is a bit murky. It does
|
||||
fit the vapor pressure curve at 298K adequately.
|
||||
-->
|
||||
<atomArray>H:2 O:1 </atomArray>
|
||||
<thermo>
|
||||
<NASA Tmax="600.0" Tmin="273.14999999999998" P0="100000.0">
|
||||
<floatArray name="coeffs" size="7">
|
||||
7.255750050E+01, -6.624454020E-01, 2.561987460E-03, -4.365919230E-06,
|
||||
2.781789810E-09, -4.188654990E+04, -2.882801370E+02
|
||||
</floatArray>
|
||||
</NASA>
|
||||
</thermo>
|
||||
<standardState model="waterIAPWS">
|
||||
<!--
|
||||
Molar volume in m3 kmol-1.
|
||||
(this is from Pitzer, Peiper, and Busey. However,
|
||||
the result can be easily derived from ~ 1gm/cm**3)
|
||||
<molarVolume> 0.018068 </molarVolume>
|
||||
-->
|
||||
</standardState>
|
||||
<transport>
|
||||
<viscosity model="Constant" units="centipoise"> 1.0E0 </viscosity>
|
||||
<thermalConductivity model="Constant"> 0.58 </thermalConductivity>
|
||||
<speciesDiffusivity model="Constant"> 1.0E-5 </speciesDiffusivity>
|
||||
</transport>
|
||||
</species>
|
||||
|
||||
<species name="Na+">
|
||||
<!-- Na+ (aq) standard state based on the unity molality convention
|
||||
xxx
|
||||
-->
|
||||
<atomArray> Na:1 E:-1 </atomArray>
|
||||
<charge> +1 </charge>
|
||||
<thermo model="HKFT">
|
||||
<HKFT Pref="1 atm" Tmax=" 640." Tmin=" 273.15">
|
||||
<!-- <DG0_f_Pr_Tr units="cal/gmol"> -62591. </DG0_f_Pr_Tr> -->
|
||||
<DH0_f_Pr_Tr units="cal/gmol"> -57433. </DH0_f_Pr_Tr>
|
||||
<S0_Pr_Tr units="cal/gmol/K"> 13.96 </S0_Pr_Tr>
|
||||
</HKFT>
|
||||
</thermo>
|
||||
<standardState model="HKFT">
|
||||
<a1 units="cal/gmol/bar"> 0.1839 </a1>
|
||||
<a2 units="cal/gmol"> -228.5 </a2>
|
||||
<a3 units="cal-K/gmol/bar"> 3.256 </a3>
|
||||
<a4 units="cal-K/gmol"> -27260. </a4>
|
||||
<c1 units="cal/gmol/K"> 18.18 </c1>
|
||||
<c2 units="cal-K/gmol"> -29810. </c2>
|
||||
<omega_Pr_Tr units="cal/gmol"> 33060. </omega_Pr_Tr>
|
||||
</standardState>
|
||||
<transport>
|
||||
<speciesDiffusivity model="Constant"> 1.0E-5 </speciesDiffusivity>
|
||||
</transport>
|
||||
<source>
|
||||
ref:G9
|
||||
</source>
|
||||
</species>
|
||||
|
||||
<species name="Cl-">
|
||||
<atomArray> Cl:1 E:1 </atomArray>
|
||||
<charge> -1 </charge>
|
||||
<thermo model="HKFT">
|
||||
<HKFT Pref="1 atm" Tmax=" 623.15" Tmin=" 298.00">
|
||||
<DG0_f_Pr_Tr units="cal/gmol"> -31379. </DG0_f_Pr_Tr>
|
||||
<!-- <DH0_f_Pr_Tr units="cal/gmol"> -39933. </DH0_f_Pr_Tr> -->
|
||||
<S0_Pr_Tr units="cal/gmol/K"> 13.56 </S0_Pr_Tr>
|
||||
</HKFT>
|
||||
</thermo>
|
||||
<standardState model="HKFT">
|
||||
<a1 units="cal/gmol/bar"> 0.4032 </a1>
|
||||
<a2 units="cal/gmol"> 480.1 </a2>
|
||||
<a3 units="cal-K/gmol/bar"> 5.563 </a3>
|
||||
<a4 units="cal-K/gmol"> -28470. </a4>
|
||||
<c1 units="cal/gmol/K"> -4.4 </c1>
|
||||
<c2 units="cal-K/gmol"> -57140. </c2>
|
||||
<omega_Pr_Tr units="cal/gmol"> 145600. </omega_Pr_Tr>
|
||||
</standardState>
|
||||
<transport>
|
||||
<speciesDiffusivity model="Constant"> 1.0E-5 </speciesDiffusivity>
|
||||
</transport>
|
||||
<source>
|
||||
ref:G9
|
||||
</source>
|
||||
</species>
|
||||
|
||||
<species name="H+">
|
||||
<atomArray> H:1 E:-1 </atomArray>
|
||||
<charge> +1 </charge>
|
||||
<thermo model="HKFT">
|
||||
<HKFT Pref="1 atm" Tmax=" 623.15" Tmin=" 298.00">
|
||||
<DG0_f_Pr_Tr units="cal/gmol"> 0.0 </DG0_f_Pr_Tr>
|
||||
<DH0_f_Pr_Tr units="cal/gmol"> 0.0 </DH0_f_Pr_Tr>
|
||||
<!-- <S0_Pr_Tr units="cal/gmol/K"> 0.0 </S0_Pr_Tr> -->
|
||||
</HKFT>
|
||||
</thermo>
|
||||
<standardState model="HKFT">
|
||||
<a1 units="cal/gmol/bar"> 0.0 </a1>
|
||||
<a2 units="cal/gmol"> 0.0 </a2>
|
||||
<a3 units="cal-K/gmol/bar"> 0.0 </a3>
|
||||
<a4 units="cal-K/gmol"> 0.0 </a4>
|
||||
<c1 units="cal/gmol/K"> 0.0 </c1>
|
||||
<c2 units="cal-K/gmol"> 0.0 </c2>
|
||||
<omega_Pr_Tr units="cal/gmol"> 0.0 </omega_Pr_Tr>
|
||||
</standardState>
|
||||
<transport>
|
||||
<speciesDiffusivity model="Constant"> 1.0E-5 </speciesDiffusivity>
|
||||
</transport>
|
||||
<source>
|
||||
ref:G9
|
||||
</source>
|
||||
</species>
|
||||
|
||||
|
||||
<species name="OH-">
|
||||
<atomArray> O:1 H:1 E:1 </atomArray>
|
||||
<charge> -1 </charge>
|
||||
<thermo model="HKFT">
|
||||
<HKFT Pref="1 atm" Tmax=" 623.15" Tmin=" 298.00">
|
||||
<DG0_f_Pr_Tr units="cal/gmol"> -37595. </DG0_f_Pr_Tr>
|
||||
<DH0_f_Pr_Tr units="cal/gmol"> -54977. </DH0_f_Pr_Tr>
|
||||
<S0_Pr_Tr units="cal/gmol/K"> -2.56 </S0_Pr_Tr>
|
||||
</HKFT>
|
||||
</thermo>
|
||||
<standardState model="HKFT">
|
||||
<a1 units="cal/gmol/bar"> 0.12527 </a1>
|
||||
<a2 units="cal/gmol"> 7.38 </a2>
|
||||
<a3 units="cal-K/gmol/bar"> 1.8423 </a3>
|
||||
<a4 units="cal-K/gmol"> -27821 </a4>
|
||||
<c1 units="cal/gmol/K"> 4.15 </c1>
|
||||
<c2 units="cal-K/gmol"> -103460. </c2>
|
||||
<omega_Pr_Tr units="cal/gmol"> 172460. </omega_Pr_Tr>
|
||||
</standardState>
|
||||
<transport>
|
||||
<speciesDiffusivity model="Constant"> 1.0E-5 </speciesDiffusivity>
|
||||
</transport>
|
||||
<source>
|
||||
ref:G9
|
||||
</source>
|
||||
</species>
|
||||
|
||||
</speciesData>
|
||||
|
||||
</ctml>
|
||||
@@ -3,7 +3,6 @@
|
||||
#include "cantera/transport/TransportData.h"
|
||||
#include "cantera/transport/MixTransport.h"
|
||||
#include "cantera/transport/MultiTransport.h"
|
||||
#include "cantera/transport/SimpleTransport.h"
|
||||
#include "cantera/transport/TransportFactory.h"
|
||||
#include "cantera/thermo/ThermoFactory.h"
|
||||
#include "cantera/thermo/IdealGasPhase.h"
|
||||
@@ -167,103 +166,9 @@ TEST_F(TransportFromScratch, thermalConductivityMulti)
|
||||
}
|
||||
}
|
||||
|
||||
class SimpleTransportTest : public testing::Test
|
||||
{
|
||||
public:
|
||||
SimpleTransportTest()
|
||||
: p(newPhase("HMW_NaCl_pdss.xml", "NaCl_electrolyte"))
|
||||
{
|
||||
}
|
||||
|
||||
void check_transport(SimpleTransport& tr) {
|
||||
p->setState_TP(303.13, OneAtm);
|
||||
size_t N = p->nSpecies();
|
||||
EXPECT_NEAR(tr.viscosity(), 0.001, 1e-4);
|
||||
EXPECT_NEAR(tr.thermalConductivity(), 0.58, 1e-3);
|
||||
|
||||
vector_fp spvisc(N), Dmix(N), mobilities(N), fluxes1(N), fluxes2(N);
|
||||
vector_fp gradX(N, 0.0);
|
||||
gradX[1] = 1.0;
|
||||
double gradT = 0.0;
|
||||
double gradV = 1.0;
|
||||
|
||||
vector_fp spvisc_ref = {0.001, 0, 0, 0, 0};
|
||||
vector_fp Dmix_ref = {1e-05, 1e-05, 1e-05, 1e-05, 1e-05};
|
||||
vector_fp mobilities_ref = {0.000382823, 0.000382823, 0.000382823,
|
||||
0.000382823, 0.000382823};
|
||||
vector_fp fluxes1_ref = {0.0102344, -0.0124461, 0.00221167,
|
||||
2.22987e-14, 2.43291e-10};
|
||||
vector_fp fluxes2_ref = {-0.0191255, -0.0505223, 0.0696478,
|
||||
-7.85548e-13, 7.6615e-09};
|
||||
|
||||
tr.getSpeciesViscosities(spvisc.data());
|
||||
tr.getMixDiffCoeffs(Dmix.data());
|
||||
tr.getMobilities(mobilities.data());
|
||||
tr.getSpeciesFluxes(1, &gradT, N, gradX.data(), N, fluxes1.data());
|
||||
gradX[1] = 0.0;
|
||||
tr.set_Grad_T(&gradT);
|
||||
tr.set_Grad_V(&gradV);
|
||||
tr.set_Grad_X(gradX.data());
|
||||
tr.getSpeciesFluxesExt(N, fluxes2.data());
|
||||
|
||||
for (size_t k = 0; k < N; k++) {
|
||||
EXPECT_NEAR(spvisc[k], spvisc_ref[k], 1e-5);
|
||||
EXPECT_NEAR(Dmix[k], Dmix_ref[k], 1e-7);
|
||||
EXPECT_NEAR(mobilities[k], mobilities_ref[k], 1e-9);
|
||||
EXPECT_NEAR(fluxes1[k], fluxes1_ref[k], 1e-5*std::abs(fluxes1_ref[k]));
|
||||
EXPECT_NEAR(fluxes2[k], fluxes2_ref[k], 1e-5*std::abs(fluxes2_ref[k]));
|
||||
}
|
||||
}
|
||||
|
||||
shared_ptr<ThermoPhase> p;
|
||||
};
|
||||
|
||||
TEST_F(SimpleTransportTest, fromScratch)
|
||||
{
|
||||
SimpleTransport tr(p.get(), 3);
|
||||
LiquidTransportParams params;
|
||||
params.LTData.resize(p->nSpecies());
|
||||
|
||||
LTPspecies_Const* ltp = new LTPspecies_Const();
|
||||
ltp->setName(p->speciesName(0));
|
||||
ltp->setTransportPropertyType(TP_VISCOSITY);
|
||||
ltp->setThermo(p.get());
|
||||
ltp->setCoeff(1.0 * toSI("centipoise"));
|
||||
params.LTData[0].viscosity = ltp;
|
||||
|
||||
ltp = new LTPspecies_Const();
|
||||
ltp->setName(p->speciesName(0));
|
||||
ltp->setTransportPropertyType(TP_THERMALCOND);
|
||||
ltp->setThermo(p.get());
|
||||
ltp->setCoeff(0.58);
|
||||
params.LTData[0].thermalCond = ltp;
|
||||
|
||||
for (size_t k = 0; k < p->nSpecies(); k++) {
|
||||
ltp = new LTPspecies_Const();
|
||||
ltp->setName(p->speciesName(k));
|
||||
ltp->setTransportPropertyType(TP_DIFFUSIVITY);
|
||||
ltp->setThermo(p.get());
|
||||
ltp->setCoeff(1e-5);
|
||||
params.LTData[k].speciesDiffusivity = ltp;
|
||||
}
|
||||
|
||||
params.thermo = p.get();
|
||||
tr.initLiquid(params);
|
||||
tr.setCompositionDependence(LTI_MODEL_SOLVENT);
|
||||
check_transport(tr);
|
||||
}
|
||||
|
||||
TEST_F(SimpleTransportTest, fromXML)
|
||||
{
|
||||
shared_ptr<Transport> tr(newDefaultTransportMgr(p.get()));
|
||||
check_transport(dynamic_cast<SimpleTransport&>(*tr.get()));
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
printf("Running main() from transportFromScratch.cpp\n");
|
||||
// Cantera::make_deprecation_warnings_fatal();
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
int result = RUN_ALL_TESTS();
|
||||
appdelete();
|
||||
|
||||
Reference in New Issue
Block a user