Remove code deprecated in Cantera 2.4

This commit is contained in:
Ray Speth
2018-11-14 14:49:49 -05:00
parent 0257c4868e
commit 6f45b241b5
61 changed files with 5 additions and 12304 deletions

View File

@@ -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',

View File

@@ -80,9 +80,6 @@ Thermodynamic Properties
.. autoclass:: Shomate
:no-undoc-members:
.. autoclass:: Adsorbate
:no-undoc-members:
.. autoclass:: const_cp
:no-undoc-members:

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
//@{

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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;
};

View File

@@ -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
{

View File

@@ -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":

View File

@@ -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."""

View File

@@ -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.

View File

@@ -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"""

View File

@@ -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);

View File

@@ -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 {

View File

@@ -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);

View File

@@ -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;
}
}

View File

@@ -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)

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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];
}
}
}
}

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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
{

View File

@@ -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];
}
}
}
}

View File

@@ -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 + "'.");

View File

@@ -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";

View File

@@ -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++) {

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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);
}
}
}
}

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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;
}
}

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}

View File

@@ -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();

View File

@@ -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>

View File

@@ -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();