moved functions to read XML input files out of importCTML.cpp and into specific classes

This commit is contained in:
Dave Goodwin 2004-06-09 00:59:23 +00:00
parent 3162abcdec
commit 32f865ef26
22 changed files with 797 additions and 689 deletions

View file

@ -111,6 +111,13 @@ namespace Cantera {
m_tlast = tnow;
}
}
void ConstDensityThermo::setParametersFromXML(const XML_Node& eosdata) {
eosdata.require("model","Incompressible");
doublereal rho = getFloat(eosdata, "density", "-");
setDensity(rho);
}
}

View file

@ -170,6 +170,7 @@ namespace Cantera {
setDensity(c[0]);
}
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:

View file

@ -216,6 +216,10 @@ namespace Cantera {
m_Elements->addUniqueElement(e);
}
void Constituents::addElementsFromXML(const XML_Node& phase) {
m_Elements->addElementsFromXML(phase);
}
/*******************************************************************
*
* freezeElements()

View file

@ -8,7 +8,10 @@
* $Revision$
*
* $Log$
* Revision 1.5 2003-11-12 18:58:17 dggoodwin
* Revision 1.6 2004-06-09 00:59:24 dggoodwin
* moved functions to read XML input files out of importCTML.cpp and into specific classes
*
* Revision 1.5 2003/11/12 18:58:17 dggoodwin
* *** empty log message ***
*
* Revision 1.4 2003/09/03 18:15:50 hkmoffa
@ -134,6 +137,7 @@ namespace Cantera {
void addUniqueElement(const XML_Node& e);
void addElementsFromXML(const XML_Node& phase);
/// Prohibit addition of more elements, and prepare to add
/// species.

View file

@ -28,7 +28,7 @@ namespace Cantera {
EdgePhase(doublereal n0 = 0.0);
virtual ~EdgePhase() {}
virtual int eosType() const { return cEdge; }
virtual void setParametersFromXML(const XML_Node& eosdata);
};
}

View file

@ -102,6 +102,8 @@ namespace Cantera {
doublereal weight = -12345.0);
void addUniqueElement(const XML_Node& e);
void addElementsFromXML(const XML_Node& phase);
/**
* Prohibit addition of more elements, and prepare to add
* species.

View file

@ -26,7 +26,7 @@ BASE = State.o Elements.o Constituents.o stringUtils.o misc.o importCTML.o
xml.o Phase.o DenseMatrix.o ctml.o funcs.o ctvector.o phasereport.o ct2ctml.o
# thermodynamic properties
THERMO = $(BASE) ThermoPhase.o IdealGasPhase.o ConstDensityThermo.o StoichSubstance.o SpeciesThermoFactory.o ThermoFactory.o
THERMO = $(BASE) ThermoPhase.o IdealGasPhase.o ConstDensityThermo.o StoichSubstance.o PureFluidPhase.o SpeciesThermoFactory.o ThermoFactory.o
# homogeneous kinetics
KINETICS = GRI_30_Kinetics.o KineticsFactory.o GasKinetics.o FalloffFactory.o \
@ -55,7 +55,7 @@ EVERYTHING = $(KINETICS) $(HETEROKIN) $(ELECTROCHEM) $(EQUIL) $(CK) \
$(TRANSPORT) $(REACTOR) $(RPATH) $(SOLVERS) $(FLOW1D)
PCH = ct_defs.h.gch utilities.h.gch ThermoPhase.h.gch
PCH = ct_defs.h.gch utilities.h.gch ThermoPhase.h.gch Kinetic.h.gch
all: config.h $(PCH) @KERNEL@ lib
@ -71,6 +71,11 @@ else
@echo 'skipping precompiling header file $*.h'
endif
ct_defs.h.gch: ct_defs.h
utilities.h.gch: utilities.h
ThermoPhase.h.gch: ThermoPhase.h
Kinetics.h.gch: Kinetics.h
base: $(BASE)
thermo: $(THERMO)

View file

@ -18,6 +18,7 @@
#ifdef INCL_PURE_FLUIDS
#include "mix_defs.h"
#include "../../ext/tpx/Sub.h"
#include "../../ext/tpx/utils.h"
@ -28,42 +29,11 @@ namespace Cantera {
public:
PureFluid() : ThermoPhase(), m_sub(0) {}
PureFluid() : ThermoPhase(), m_sub(0), m_subflag(0),
m_mw(-1.0), m_verbose(true) {}
virtual ~PureFluid() { delete m_sub; }
virtual void setParameters(int n, doublereal* c) {
if (n == 1) {
int subflag = int(c[0]);
if (m_sub) delete m_sub;
m_sub = tpx::GetSub(subflag);
if (m_sub == 0) {
throw CanteraError("PureFluid::setParameters",
"could not create new substance object.");
}
m_subflag = subflag;
m_mw = m_sub->MolWt();
m_weight[0] = m_mw;
setMolecularWeight(0,m_mw);
double one = 1.0;
setMoleFractions(&one);
double cp0_R, h0_RT, s0_R, T0, p;
T0 = 298.15;
if (T0 < m_sub->Tcrit()) {
m_sub->Set(tpx::TX, T0, 1.0);
p = 0.01*m_sub->P();
}
else {
p = 0.001*m_sub->Pcrit();
}
m_sub->Set(tpx::TP, T0, p);
m_spthermo->update_one(0, T0, &cp0_R, &h0_RT, &s0_R);
double s_R = s0_R - log(p/refPressure());
m_sub->setStdState(h0_RT*GasConstant*298.15/m_mw,
s_R*GasConstant/m_mw, T0, p);
}
}
virtual int eosType() const { return cPureFluid; }
@ -247,6 +217,8 @@ namespace Cantera {
check();
}
virtual void initThermo();
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:
@ -265,6 +237,7 @@ private:
mutable tpx::Substance* m_sub;
int m_subflag;
doublereal m_mw;
bool m_verbose;
};
}

View file

@ -27,6 +27,8 @@
#include "speciesThermoTypes.h"
#include "xml.h"
#include "ctml.h"
using namespace ctml;
namespace Cantera {
@ -161,4 +163,182 @@ namespace Cantera {
}
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k into a SpeciesThermo instance.
*/
static void installNasaThermoFromXML(SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else
c1.resize(7,0.0);
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(k, NASA, c.begin(), tmin, tmax, p0);
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k.
*/
static void installShomateThermoFromXML(SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else
c1.resize(7,0.0);
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installShomateThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
copy(c0.begin(), c0.begin()+7, c.begin() + 1);
copy(c1.begin(), c1.begin()+7, c.begin() + 8);
sp.install(k, SHOMATE, c.begin(), tmin, tmax, p0);
}
/**
* Install a constant-cp thermodynamic property
* parameterization for species k.
*/
static void installSimpleThermoFromXML(SpeciesThermo& sp, int k,
const XML_Node& f) {
doublereal tmin, tmax;
tmin = fpValue(f["Tmin"]);
tmax = fpValue(f["Tmax"]);
if (tmax == 0.0) tmax = 1.0e30;
vector_fp c(4);
c[0] = getFloat(f, "t0", "-");
c[1] = getFloat(f, "h0", "-");
c[2] = getFloat(f, "s0", "-");
c[3] = getFloat(f, "cp0", "-");
doublereal p0 = OneAtm;
sp.install(k, SIMPLE, c.begin(), tmin, tmax, p0);
}
/**
* Install a species thermodynamic property parameterization
* for one species into a species thermo manager.
* @param k species number
* @param s XML node specifying species
* @param spthermo species thermo manager
*/
void SpeciesThermoFactory::
installThermoForSpecies(int k, const XML_Node& s,
SpeciesThermo& spthermo) {
const XML_Node& thermo = s.child("thermo");
const vector<XML_Node*>& tp = thermo.children();
int nc = tp.size();
if (nc == 1) {
const XML_Node* f = tp[0];
if (f->name() == "Shomate") {
installShomateThermoFromXML(spthermo, k, f, 0);
}
else if (f->name() == "const_cp") {
installSimpleThermoFromXML(spthermo, k, *f);
}
else if (f->name() == "NASA") {
installNasaThermoFromXML(spthermo, k, f, 0);
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"], f->name());
}
}
else if (nc == 2) {
const XML_Node* f0 = tp[0];
const XML_Node* f1 = tp[1];
if (f0->name() == "NASA" && f1->name() == "NASA") {
installNasaThermoFromXML(spthermo, k, f0, f1);
}
else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
installShomateThermoFromXML(spthermo, k, f0, f1);
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"],
f0->name() + " and " + f1->name());
}
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"],
"multiple");
}
}
}

View file

@ -73,6 +73,10 @@ namespace Cantera {
virtual SpeciesThermo* newSpeciesThermo(vector<XML_Node*> nodes);
virtual SpeciesThermo* newSpeciesThermoOpt(vector<XML_Node*> nodes);
virtual void installThermoForSpecies(int k, const XML_Node& s,
SpeciesThermo& spthermo);
private:
static SpeciesThermoFactory* __factory;
SpeciesThermoFactory(){}

View file

@ -43,6 +43,13 @@ namespace Cantera {
m_tlast = tnow;
}
}
void StoichSubstance::setParametersFromXML(const XML_Node& eosdata) {
eosdata.require("model","Incompressible");
doublereal rho = getFloat(eosdata, "density", "-");
setDensity(rho);
}
}

View file

@ -189,6 +189,7 @@ namespace Cantera {
virtual void initThermo();
virtual void setParametersFromXML(const XML_Node& eosdata);
protected:

View file

@ -92,6 +92,8 @@ namespace Cantera {
return m_logn0 - m_logsize[k];
}
/// The only parameter that can be set is the site density.
void SurfPhase::
setParameters(int n, doublereal* c) {
m_n0 = c[0];
@ -153,6 +155,7 @@ namespace Cantera {
// _updateThermo(true);
//}
/**
* Set the coverage fractions to a specified
* state. This routine converts to concentrations
@ -236,10 +239,46 @@ namespace Cantera {
}
}
void SurfPhase::
setParametersFromXML(const XML_Node& eosdata) {
eosdata.require("model","Surface");
doublereal n = getFloat(eosdata, "site_density", "-");
if (n <= 0.0)
throw CanteraError("SurfPhase::setParametersFromXML",
"missing or negative site density");
m_n0 = n;
m_logn0 = log(m_n0);
}
void SurfPhase::setStateFromXML(const XML_Node& state) {
if (state.hasChild("temperature")) {
double t = getFloat(state, "temperature", "temperature");
setTemperature(t);
}
if (state.hasChild("coverages")) {
string comp = getString(state,"coverages");
setCoveragesByName(comp);
}
}
EdgePhase::EdgePhase(doublereal n0) : SurfPhase(n0) {
setNDim(1);
}
void EdgePhase::
setParametersFromXML(const XML_Node& eosdata) {
eosdata.require("model","Edge");
doublereal n = getFloat(eosdata, "site_density", "-");
if (n <= 0.0)
throw CanteraError("EdgePhase::setParametersFromXML",
"missing or negative site density");
m_n0 = n;
m_logn0 = log(m_n0);
}
}

View file

@ -19,6 +19,7 @@
#include "mix_defs.h"
#include "ThermoPhase.h"
namespace Cantera {
@ -45,7 +46,9 @@ namespace Cantera {
virtual doublereal standardConcentration(int k = 0) const;
virtual doublereal logStandardConc(int k=0) const;
virtual void setParameters(int n, doublereal* c);
virtual void setParametersFromXML(const XML_Node& eosdata);
virtual void initThermo();
virtual void setStateFromXML(const XML_Node& state);
doublereal siteDensity(){ return m_n0; }
void setPotentialEnergy(int k, doublereal pe);
doublereal potentialEnergy(int k) {return m_pe[k];}

View file

@ -89,4 +89,77 @@ namespace Cantera {
}
return th;
}
// void setEOSParameters(const XML_Node& xmlphase, ThermoPhase* th) {
// // if no thermo model is specified for the phase, simply
// // return
// if (!phase.hasChild("thermo")) return;
// const XML_Node& eos = phase.child("thermo");
// // set the parameters for the particular equation of state type,
// // and
// if (eos["model"] == "Incompressible") {
// if (th->eosType() == cIncompressible) {
// doublereal rho = getFloat(eos, "density", "-");
// th->setParameters(1, &rho);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "StoichSubstance") {
// if (th->eosType() == cStoichSubstance) {
// doublereal rho = getFloat(eos, "density", "-");
// th->setDensity(rho);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "Surface") {
// if (th->eosType() == cSurf) {
// doublereal n = getFloat(eos, "site_density", "-");
// if (n <= 0.0)
// throw CanteraError("importCTML",
// "missing or negative site density");
// th->setParameters(1, &n);
// }
// else {
// eoserror = true;
// }
// }
// else if (eos["model"] == "Edge") {
// if (th->eosType() == cEdge) {
// doublereal n = getFloat(eos, "site_density", "-");
// if (n <= 0.0)
// throw CanteraError("importCTML",
// "missing or negative site density");
// th->setParameters(1, &n);
// }
// else {
// eoserror = true;
// }
// }
// #ifdef INCL_PURE_FLUIDS
// else if (eos["model"] == "PureFluid") {
// if (th->eosType() == cPureFluid) {
// subflag = atoi(eos["fluid_type"].c_str());
// if (subflag < 0)
// throw CanteraError("importCTML",
// "missing fluid type flag");
// }
// else {
// eoserror = true;
// }
// }
// #endif
// if (eoserror) {
// string msg = "Wrong equation of state type for phase "+phase["id"]+"\n";
// msg += eos["model"]+" is not consistent with eos type "+int2str(th->eosType());
// throw CanteraError("importCTML",msg);
// }
}

View file

@ -197,6 +197,35 @@ namespace Cantera {
}
}
/**
* Set the thermodynamic state.
*/
void ThermoPhase::setStateFromXML(const XML_Node& state) {
string comp = getString(state,"moleFractions");
if (comp != "")
setMoleFractionsByName(comp);
else {
comp = getString(state,"massFractions");
if (comp != "")
setMassFractionsByName(comp);
}
if (state.hasChild("temperature")) {
double t = getFloat(state, "temperature", "temperature");
setTemperature(t);
}
if (state.hasChild("pressure")) {
double p = getFloat(state, "pressure", "pressure");
setPressure(p);
}
if (state.hasChild("density")) {
double rho = getFloat(state, "density", "density");
setDensity(rho);
}
}
}

View file

@ -31,15 +31,15 @@ namespace Cantera {
*/
/**
* A phase with thermodynamic properties.
* Extends class Phase by adding methods that compute
* thermodynamic properties.
* A phase with thermodynamic properties. Extends class Phase by
* adding methods that compute thermodynamic properties that
* require knowledge of the equation of state.
*
* Class ThermoPhase is the base class for the family of classes
* that represent phases of matter with particular equations of
* state. Instances of subclasses of ThermoPhase should be created
* using the factory class ThermoFactory, not by calling the
* constructor directly.
* constructor directly.
*
* To implement a new equation of state, derive a class from
* ThermoPhase and overload the virtual methods in
@ -69,60 +69,6 @@ namespace Cantera {
* @{
*/
/**
* @internal
* Index number. This method can be used to identify the
* location of a phase object in a list, and is used by the
* interface library (clib) routines for this purpose.
*/
int index() { return m_index; }
/**
* @internal Set the index number. The Cantera interface
* library uses this method to set the index number to the
* location of the pointer to this object in the pointer array
* it maintains. Using this method for any other purpose will
* lead to unpredictable results if used in conjunction with
* the interface library.
*/
void setIndex(int m) { m_index = m; }
/// used to access data needed to construct transport manager
/// later.
void saveSpeciesData(const XML_Node* data) {
m_speciesData = data;
}
const XML_Node* speciesData() {
if (m_speciesData)
return m_speciesData;
else {
throw CanteraError("ThermoPhase::speciesData",
"m_speciesData is NULL");
return 0;
}
}
/**
* @internal Initialize. This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called just prior to returning
* from function importPhase.
*
* @see importCTML.cpp
*/
virtual void initThermo() {}
/**
* Equation of state type flag. The base class returns
* zero. Subclasses should define this to return a unique
@ -132,57 +78,43 @@ namespace Cantera {
virtual int eosType() const { return 0; }
/**
* @}
* @name Molar Thermodynamic Properties
* @{
*/
/**
* Molar enthalpy. Units: J/kmol.
*/
/// Molar enthalpy. Units: J/kmol.
virtual doublereal enthalpy_mole() const {
return err("enthalpy_mole");
}
/**
* Molar internal energy. Units: J/kmol.
*/
/// Molar internal energy. Units: J/kmol.
virtual doublereal intEnergy_mole() const {
return err("intEnergy_mole");
}
/**
* Molar entropy. Units: J/kmol/K.
*/
/// Molar entropy. Units: J/kmol/K.
virtual doublereal entropy_mole() const {
return err("entropy_mole");
}
/**
* Molar Gibbs function. Units: J/kmol.
*/
/// Molar Gibbs function. Units: J/kmol.
virtual doublereal gibbs_mole() const {
return err("gibbs_mole");
}
/**
* Molar heat capacity at constant pressure. Units: J/kmol/K.
*/
/// Molar heat capacity at constant pressure. Units: J/kmol/K.
virtual doublereal cp_mole() const {
return err("cp_mole");
}
/**
* Molar heat capacity at constant volume. Units: J/kmol/K.
*/
/// Molar heat capacity at constant volume. Units: J/kmol/K.
virtual doublereal cv_mole() const {
return err("cv_mole");
}
@ -246,11 +178,18 @@ namespace Cantera {
return err("potentialEnergy");
}
/**
* Set the electric potential of this phase (V).
* This is used by classes InterfaceKinetics and EdgeKinetics to
* compute the rates of charge-transfer reactions, and in computing
* the electrochemical potentials of the species.
*/
void setElectricPotential(doublereal v) {
m_phi = v;
}
doublereal electricPotential() { return m_phi; }
/// The electric potential of this phase (V).
doublereal electricPotential() const { return m_phi; }
/**
@ -271,8 +210,8 @@ namespace Cantera {
* C^0_k, \f$ where \f$ C^0_k \f$ is a standard concentration
* defined below. These generalized concentrations are used
* by kinetics manager classes to compute the forward and
* reverse rates of elementary reactions.
*
* reverse rates of elementary reactions.
*
* @param c Array of generalized concentrations. The
* units depend upon the implementation of the
* reaction rate expressions within the phase.
@ -298,7 +237,6 @@ namespace Cantera {
}
/**
*
* Returns the natural logarithm of the standard
* concentration of the kth species
*/
@ -315,10 +253,10 @@ namespace Cantera {
}
/**
* Returns the units of the standard and general concentrations
* Note they have the same units, as their divisor is
* defined to be equal to the activity of the kth species
* in the solution, which is unitless.
* Returns the units of the standard and generalized
* concentrations Note they have the same units, as their
* ratio is defined to be equal to the activity of the kth
* species in the solution, which is unitless.
*
* This routine is used in print out applications where the
* units are needed. Usually, MKS units are assumed throughout
@ -350,6 +288,19 @@ namespace Cantera {
err("getChemPotentials_RT");
}
/**
* Get the species electrochemical potentials. Units: J/kmol.
* This method adds a term \f$ Fz_k \phi_k$ to the
* to each chemical potential.
*/
void getElectrochemPotentials(doublereal* mu) const {
getChemPotentials(mu);
double ve = Faraday * electricPotential();
for (int k = 0; k < m_kk; k++) {
mu[k] += ve*charge(k);
}
}
//@}
/// @name Partial Molar Properties
//@{
@ -568,7 +519,9 @@ namespace Cantera {
* @param c array of \i n coefficients
*/
virtual void setParameters(int n, doublereal* c) {}
virtual void setParametersFromXML(const XML_Node& eosdata) {}
virtual void setStateFromXML(const XML_Node& state);
virtual doublereal isothermalCompressibility() {
err("isothermalCompressibility"); return -1.0;
}
@ -579,6 +532,7 @@ namespace Cantera {
//---------------------------------------------------------
/// @name Critical state properties.
/// These methods are only implemented by some subclasses.
//@{
@ -599,6 +553,10 @@ namespace Cantera {
//@}
/// @name Saturation properties.
/// These methods are only implemented by subclasses that
/// implement full liquid-vapor equations of state.
///
virtual doublereal satTemperature(doublereal p) const {
err("satTemperature"); return -1.0;
}
@ -619,6 +577,49 @@ namespace Cantera {
err("setState_sat");
}
//@}
/**
* Returns the reference pressure in Pa. This function is a wrapper
* that calls the species thermo refPressure function.
*/
doublereal refPressure() const {
return m_spthermo->refPressure();
}
doublereal minTemp(int k = -1) {
return m_spthermo->minTemp(k);
}
doublereal maxTemp(int k = -1) {
return m_spthermo->maxTemp(k);
}
/// 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 files importCTML.cpp and
/// ThermoFactory.cpp.
/// used to access data needed to construct transport manager
/// later.
void saveSpeciesData(const XML_Node* data) {
m_speciesData = data;
}
const XML_Node* speciesData() {
if (m_speciesData)
return m_speciesData;
else {
throw CanteraError("ThermoPhase::speciesData",
"m_speciesData is NULL");
return 0;
}
}
/**
* @internal Install a species thermodynamic property
@ -638,22 +639,48 @@ namespace Cantera {
*/
SpeciesThermo& speciesThermo() { return *m_spthermo; }
/**
* Returns the reference pressure in Pa. This function is a wrapper
* that calls the species thermo refPressure function.
*/
doublereal refPressure() const {
return m_spthermo->refPressure();
}
doublereal minTemp(int k = -1) {
return m_spthermo->minTemp(k);
}
/**
* @internal Initialize. This method is provided to allow
* subclasses to perform any initialization required after all
* species have been added. For example, it might be used to
* resize internal work arrays that must have an entry for
* each species. The base class implementation does nothing,
* and subclasses that do not require initialization do not
* need to overload this method. When importing a CTML phase
* description, this method is called just prior to returning
* from function importPhase.
*
* @see importCTML.cpp
*/
virtual void initThermo() {}
// The following methods are used by the clib interface
// library, and should not be used by application programs.
/**
* @internal
* Index number. This method can be used to identify the
* location of a phase object in a list, and is used by the
* interface library (clib) routines for this purpose.
*/
int index() { return m_index; }
/**
* @internal Set the index number. The Cantera interface
* library uses this method to set the index number to the
* location of the pointer to this object in the pointer array
* it maintains. Using this method for any other purpose will
* lead to unpredictable results if used in conjunction with
* the interface library.
*/
void setIndex(int m) { m_index = m; }
doublereal maxTemp(int k = -1) {
return m_spthermo->maxTemp(k);
}
protected:

View file

@ -42,8 +42,6 @@
using namespace ctml;
//#include <stdio.h>
// these are all used to check for duplicate reactions
vector< map<int, doublereal> > _reactiondata;
@ -55,7 +53,7 @@ vector<bool> _rev;
namespace Cantera {
/*
* First we define a coule of typedef's which will
* First we define a couple of typedefs that will
* be used throught this file
*/
typedef const vector<XML_Node*> nodeset_t;
@ -64,6 +62,8 @@ namespace Cantera {
const doublereal DefaultPref = 1.01325e5; // one atm
/// split a string at a '#' sign. Used to separate a file name
/// from an id string.
static void split(const string& src, string& file, string& id) {
string::size_type ipound = src.find('#');
if (ipound != string::npos) {
@ -76,6 +76,7 @@ namespace Cantera {
}
}
/**
* This routine will locate an XML node in either the input
* XML tree or in another input file specified by the file
@ -100,13 +101,16 @@ namespace Cantera {
XML_Node *db, *doc;
split(file_ID, fname, idstr);
if (fname == "") {
if (!root) throw CanteraError("get_XML_Node","no file name given. file_ID = "+file_ID);
if (!root) throw CanteraError("get_XML_Node",
"no file name given. file_ID = "+file_ID);
db = root->findID(idstr, 3);
} else {
doc = get_XML_File(fname);
if (!doc) throw CanteraError("get_XML_Node", "get_XML_File failed trying to open "+fname);
if (!doc) throw CanteraError("get_XML_Node",
"get_XML_File failed trying to open "+fname);
db = doc->findID(idstr, 3);
if (!db) throw CanteraError("get_XML_Node", "id tag "+idstr+" not found.");
if (!db) throw CanteraError("get_XML_Node",
"id tag "+idstr+" not found.");
}
return db;
}
@ -152,161 +156,6 @@ namespace Cantera {
return db;
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k.
*/
static void installNasaThermo(SpeciesThermo& sp, int k, const XML_Node* f0ptr,
const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else
c1.resize(7,0.0);
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(k, NASA, c.begin(), tmin, tmax, p0);
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k.
*/
static void installShomateThermo(SpeciesThermo& sp, int k, const XML_Node* f0ptr,
const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else
c1.resize(7,0.0);
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installShomateThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
copy(c0.begin(), c0.begin()+7, c.begin() + 1);
copy(c1.begin(), c1.begin()+7, c.begin() + 8);
sp.install(k, SHOMATE, c.begin(), tmin, tmax, p0);
}
// /**
// * Install a Shomate polynomial thermodynamic property
// * parameterization for species k.
// */
// static void installShomateThermo(SpeciesThermo& sp, int k, const XML_Node& f) {
// doublereal tmin, tmid, tmax;
// tmin = fpValue(f["Tmin"]);
// tmid = fpValue(f["Tmid"]);
// tmax = fpValue(f["Tmax"]);
// vector<XML_Node*> fa;
// f.getChildren("floatArray",fa);
// vector_fp c0, c1;
// getFloatArray(*fa[0], c0, false);
// getFloatArray(*fa[1], c1, false);
// array_fp c(15);
// c[0] = tmid;
// doublereal p0 = OneAtm;
// if ((*fa[0])["title"] == "low") {
// copy(c0.begin(), c0.end(), c.begin() + 1);
// copy(c1.begin(), c1.end(), c.begin() + 8);
// }
// else {
// copy(c1.begin(), c1.end(), c.begin() + 1);
// copy(c0.begin(), c0.end(), c.begin() + 8);
// }
// sp.install(k, SHOMATE, c.begin(), tmin, tmax, p0);
// }
/**
* Install a constant-cp thermodynamic property
* parameterization for species k.
*/
static void installSimpleThermo(SpeciesThermo& sp, int k, const XML_Node& f) {
doublereal tmin, tmax;
tmin = fpValue(f["Tmin"]);
tmax = fpValue(f["Tmax"]);
if (tmax == 0.0) tmax = 1.0e30;
vector_fp c(4);
c[0] = getFloat(f, "t0", "-");
c[1] = getFloat(f, "h0", "-");
c[2] = getFloat(f, "s0", "-");
c[3] = getFloat(f, "cp0", "-");
doublereal p0 = OneAtm;
sp.install(k, SIMPLE, c.begin(), tmin, tmax, p0);
}
/**
* Install a species into a ThermoPhase object, which defines
@ -329,7 +178,7 @@ namespace Cantera {
* an "UnknownSpeciesThermoModel" exception being thrown.
*/
bool installSpecies(int k, const XML_Node& s, thermo_t& p,
SpeciesThermo& spthermo, int rule) {
SpeciesThermo& spthermo, int rule, SpeciesThermoFactory* factory) {
// get the composition of the species
const XML_Node& a = s.child("atomArray");
@ -342,77 +191,46 @@ namespace Cantera {
// otherwise, throw an exception
map<string,string>::const_iterator _b = comp.begin();
for (; _b != comp.end(); ++_b) {
if (p.elementIndex(_b->first) < 0) {
if (rule == 0) {
throw CanteraError("installSpecies",
"Species " + s["name"] +
" contains undeclared element " + _b->first);
}
else
return false;
}
if (p.elementIndex(_b->first) < 0) {
if (rule == 0) {
throw CanteraError("installSpecies",
"Species " + s["name"] +
" contains undeclared element " + _b->first);
}
else
return false;
}
}
// construct a vector of atom numbers for each
// element in phase p. Elements not declared in the
// species (i.e., not in map comp) will have zero
// entries in the vector.
int m, nel = p.nElements();
vector_fp ecomp(nel, 0.0);
for (m = 0; m < nel; m++) {
ecomp[m] = atoi(comp[p.elementName(m)].c_str());
ecomp[m] = atoi(comp[p.elementName(m)].c_str());
}
/*
* Define a map and get all of the floats in the
* current XML species block
*/
// get the species charge, if any. Note that the charge need
// not be explicitly specified if special element 'E'
// (electron) is one of the elements.
doublereal chrg = 0.0;
if (s.hasChild("charge")) chrg = getFloat(s, "charge");
// get the species size, if any. (This is used by surface
// phases to represent how many sites a species occupies.)
doublereal sz = 1.0;
if (s.hasChild("size")) sz = getFloat(s, "size");
// add the species to phase p.
p.addUniqueSpecies(s["name"], ecomp.begin(), chrg, sz);
// get thermo. We currently only support single-range Shomate
// and const_cp, and dual-range NASA
if (!s.hasChild("thermo")) {
throw
UnknownSpeciesThermoModel("installSpecies", s["name"], "missing");
}
const XML_Node& thermo = s.child("thermo");
const vector<XML_Node*>& tp = thermo.children();
int nc = tp.size();
if (nc == 1) {
const XML_Node* f = tp[0];
if (f->name() == "Shomate") {
installShomateThermo(spthermo, k, f, 0);
}
else if (f->name() == "const_cp") {
installSimpleThermo(spthermo, k, *f);
}
else if (f->name() == "NASA") {
installNasaThermo(spthermo, k, f, 0);
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"], f->name());
}
}
else if (nc == 2) {
const XML_Node* f0 = tp[0];
const XML_Node* f1 = tp[1];
if (f0->name() == "NASA" && f1->name() == "NASA") {
installNasaThermo(spthermo, k, f0, f1);
}
else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
installShomateThermo(spthermo, k, f0, f1);
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"],
f0->name() + " and " + f1->name());
}
}
else {
UnknownSpeciesThermoModel("installSpecies", s["name"],
"multiple");
}
// install the thermo parameterization for this species into
// the species thermo manager for phase p.
factory->installThermoForSpecies(k, s, spthermo);
return true;
}
@ -815,15 +633,15 @@ namespace Cantera {
/**
* Create a new ThermoPhase object and initializes it according
* to the XML tree database.
* This routine first looks up the identity of the model for the
* solution thermodynamics in the model attribute of the thermo
* child of the xml phase node. Then, it does a string lookup on
* the model to figure out what ThermoPhase derived class is
* assigned. It mallocs a new instance of that class, and then
* calls importPhase() to populate that class with the correct
* parameters from the XML tree.
* Create a new ThermoPhase object and initializes it according to
* the XML tree database. This routine first looks up the
* identity of the model for the solution thermodynamics in the
* model attribute of the thermo child of the xml phase
* node. Then, it does a string lookup on the model to figure out
* what ThermoPhase derived class is assigned. It creates a new
* instance of that class, and then calls importPhase() to
* populate that class with the correct parameters from the XML
* tree.
*/
ThermoPhase* newPhase(XML_Node& xmlphase) {
const XML_Node& th = xmlphase.child("thermo");
@ -843,44 +661,44 @@ namespace Cantera {
return 0;
}
/**
* Set the thermodynamic state.
*/
static void setState(const XML_Node& phase, ThermoPhase* th) {
if (!phase.hasChild("state")) return;
const XML_Node state = phase.child("state");
doublereal t, p, rho;
string comp = getString(state,"moleFractions");
if (comp != "")
th->setMoleFractionsByName(comp);
else {
comp = getString(state,"massFractions");
if (comp != "")
th->setMassFractionsByName(comp);
}
if (state.hasChild("temperature")) {
t = getFloat(state, "temperature", "temperature");
th->setTemperature(t);
}
if (state.hasChild("pressure")) {
p = getFloat(state, "pressure", "pressure");
th->setPressure(p);
}
if (state.hasChild("density")) {
rho = getFloat(state, "density", "density");
th->setDensity(rho);
}
if (th->eosType() == cSurf && state.hasChild("coverages")) {
comp = getString(state,"coverages");
SurfPhase* s = (SurfPhase*)th;
s->setCoveragesByName(comp);
}
if (th->eosType() == cEdge && state.hasChild("coverages")) {
comp = getString(state,"coverages");
EdgePhase* s = (EdgePhase*)th;
s->setCoveragesByName(comp);
}
}
// /**
// * Set the thermodynamic state.
// */
// static void setState(const XML_Node& phase, ThermoPhase* th) {
// if (!phase.hasChild("state")) return;
// const XML_Node state = phase.child("state");
// doublereal t, p, rho;
// string comp = getString(state,"moleFractions");
// if (comp != "")
// th->setMoleFractionsByName(comp);
// else {
// comp = getString(state,"massFractions");
// if (comp != "")
// th->setMassFractionsByName(comp);
// }
// if (state.hasChild("temperature")) {
// t = getFloat(state, "temperature", "temperature");
// th->setTemperature(t);
// }
// if (state.hasChild("pressure")) {
// p = getFloat(state, "pressure", "pressure");
// th->setPressure(p);
// }
// if (state.hasChild("density")) {
// rho = getFloat(state, "density", "density");
// th->setDensity(rho);
// }
// if (th->eosType() == cSurf && state.hasChild("coverages")) {
// comp = getString(state,"coverages");
// SurfPhase* s = (SurfPhase*)th;
// s->setCoveragesByName(comp);
// }
// if (th->eosType() == cEdge && state.hasChild("coverages")) {
// comp = getString(state,"coverages");
// EdgePhase* s = (EdgePhase*)th;
// s->setCoveragesByName(comp);
// }
// }
/**
* Import a phase specification.
@ -907,15 +725,23 @@ namespace Cantera {
* here, especially for those objects which are
* part of the Cantera Kernel.
*/
bool importPhase(XML_Node& phase, ThermoPhase* th) {
int subflag = -1;
bool importPhase(XML_Node& phase, ThermoPhase* th,
SpeciesThermoFactory* spfactory) {
// Check the the supplied XML node in fact represents a
// phase.
if (phase.name() != "phase")
throw CanteraError("importPhase",
"Current const XML_Node is not a phase element.");
th->setID(phase.id()); // set the phase id
// if no species thermo factory was supplied,
// use the default one.
if (!spfactory)
spfactory = SpeciesThermoFactory::factory();
// set the id attribute of the phase to the 'id' attribute
// in the XML tree.
th->setID(phase.id());
// Number of spatial dimensions. Defaults to 3 (bulk phase)
if (phase.hasAttrib("dim")) {
@ -928,116 +754,30 @@ namespace Cantera {
else
th->setNDim(3); // default
/**
* Equation of State: We initialize the ThermoPhase objects that
* we know about here, with additional parameters obtained from
* the xml tree. EOS's that we don't know about don't create an
* error condition.
*/
bool eoserror = false;
// set equation of state parameters. The parameters are
// specific to each subclass of ThermoPhase, so this is done
// by method setParametersFromXML in each subclass.
if (phase.hasChild("thermo")) {
const XML_Node& eos = phase.child("thermo");
if (eos["model"] == "Incompressible") {
if (th->eosType() == cIncompressible) {
doublereal rho = getFloat(eos, "density", "-");
//doublereal rho = d["density"];
th->setParameters(1, &rho);
}
else {
eoserror = true;
}
}
else if (eos["model"] == "StoichSubstance") {
if (th->eosType() == cStoichSubstance) {
doublereal rho = getFloat(eos, "density", "-");
th->setDensity(rho);
}
else {
eoserror = true;
}
}
else if (eos["model"] == "Surface") {
if (th->eosType() == cSurf) {
doublereal n = getFloat(eos, "site_density", "-");
if (n <= 0.0)
throw CanteraError("importCTML",
"missing or negative site density");
th->setParameters(1, &n);
}
else {
eoserror = true;
}
}
else if (eos["model"] == "Edge") {
if (th->eosType() == cEdge) {
doublereal n = getFloat(eos, "site_density", "-");
if (n <= 0.0)
throw CanteraError("importCTML",
"missing or negative site density");
th->setParameters(1, &n);
}
else {
eoserror = true;
}
}
#ifdef INCL_PURE_FLUIDS
else if (eos["model"] == "PureFluid") {
if (th->eosType() == cPureFluid) {
subflag = atoi(eos["fluid_type"].c_str());
if (subflag < 0)
throw CanteraError("importCTML",
"missing fluid type flag");
}
else {
eoserror = true;
}
}
#endif
if (eoserror) {
string msg = "Wrong equation of state type for phase "+phase["id"]+"\n";
msg += eos["model"]+" is not consistent with eos type "+int2str(th->eosType());
throw CanteraError("importCTML",msg);
}
}
/*************************************************
* Add elements.
************************************************/
// get the declared element names
XML_Node& elements = phase.child("elementArray");
vector<string> enames;
getStringArray(elements, enames);
// // element database defaults to elements.xml
string element_database = "elements.xml";
if (elements.hasAttrib("datasrc"))
element_database = elements["datasrc"];
XML_Node* doc = get_XML_File(element_database);
XML_Node* dbe = &doc->child("ctml/elementData");
int nel = enames.size();
int i;
string enm;
for (i = 0; i < nel; i++) {
XML_Node* e = dbe->findByAttr("name",enames[i]);
if (e) {
th->addUniqueElement(*e);
}
else {
throw CanteraError("importPhase","no data for element "
+enames[i]);
}
th->setParametersFromXML(eos);
}
/***************************************************************
* Add the species. First get the speciesArray element, then
* the species database.
* Add the elements.
***************************************************************/
th->addElementsFromXML(phase);
/***************************************************************
* Add the species.
*
* Species definitions may be imported from multiple
* sources. For each one, a speciesArray element must be
* present.
***************************************************************/
XML_Node* db = 0;
vector<XML_Node*> sparrays;
phase.getChildren("speciesArray", sparrays);
@ -1045,10 +785,16 @@ namespace Cantera {
vector<XML_Node*> dbases;
vector_int sprule(nspa,0);
// loop over the speciesArray elements
for (jsp = 0; jsp < nspa; jsp++) {
const XML_Node& species = *sparrays[jsp];
// If the speciesArray element has a child element
// <skip element="undeclared">
// then set sprule[jsp] to 1, so
// that any species with an undeclared element will be
// quietly skipped when importing species.
if (species.hasChild("skip")) {
const XML_Node& sk = species.child("skip");
string eskip = sk["element"];
@ -1056,42 +802,54 @@ namespace Cantera {
sprule[jsp] = 1;
}
}
string fname, idstr;
// get a pointer to the node containing the species
// definitions for the species declared in this
// speciesArray element. This may be in the local file
// containing the phase element, or may be in another
// file.
db = get_XML_Node(species["datasrc"], &phase.root());
//db = find_XML(species["datasrc"], &phase.root(), species["idRef"],
// "","speciesData");
// add this node to the list of species database nodes.
dbases.push_back(db);
}
/*******************************************************
* Set the species thermo manager.
* Function 'newSpeciesThermoMgr' looks at the species
* in the database to see what thermodynamic property
* parameterizations are used, and selects a class
* that can handle the parameterizations found.
******************************************************/
// if the phase has a species thermo manager already installed,
// delete it since we are adding new species.
delete &th->speciesThermo();
// create a new species thermo manager. Function
// 'newSpeciesThermoMgr' looks at the species in the database
// to see what thermodynamic property parameterizations are
// used, and selects a class that can handle the
// parameterizations found.
SpeciesThermo* spth = newSpeciesThermoMgr(dbases);
// install it in the phase object
th->setSpeciesThermo(spth);
SpeciesThermo& spthermo = th->speciesThermo();
// used to check that each species is declared only once
map<string,bool> declared;
int k = 0;
int i, k = 0;
// loop over the species arrays
for (jsp = 0; jsp < nspa; jsp++) {
const XML_Node& species = *sparrays[jsp];
db = dbases[jsp];
/*
* Get the array of species name strings.
*/
// Get the array of species name strings.
vector<string> spnames;
getStringArray(species, spnames);
int nsp = spnames.size();
// if 'all' is specified, then add all species
// defined in this database to the phase
if (nsp == 1 && spnames[0] == "all") {
vector<XML_Node*> allsp;
db->getChildren("species",allsp);
@ -1113,12 +871,11 @@ namespace Cantera {
}
declared[name] = true;
/*
* Find the species in the database by name.
*/
// Find the species in the database by name.
XML_Node* s = db->findByAttr("name",spnames[i]);
if (s) {
if (installSpecies(k, *s, *th, spthermo, sprule[jsp]))
if (installSpecies(k, *s, *th, spthermo, sprule[jsp],
spfactory))
++k;
}
else {
@ -1127,20 +884,26 @@ namespace Cantera {
}
}
}
// done adding species.
th->freezeSpecies();
// perform any required subclass-specific initialization.
th->initThermo();
th->saveSpeciesData(db);
if (th->eosType() == cPureFluid) {
doublereal dsub = doublereal(subflag);
th->setParameters(1, &dsub);
// set the state of the phase from the XML specification
if (phase.hasChild("state")) {
XML_Node& state = phase.child("state");
th->setStateFromXML(state);
}
setState(phase, th);
return true;
}
/**
* This function returns true if two reactions are duplicates of
* one another, and false otherwise. The input arguments are two

View file

@ -22,6 +22,7 @@ using namespace std;
namespace Cantera {
class Kinetics;
class SpeciesThermoFactory;
//class ThermoPhase;
class XML_Node;
@ -72,10 +73,11 @@ namespace Cantera {
XML_Node* get_XML_NameID(const string& nameTarget,
const string& file_ID, XML_Node* root);
bool installSpecies(int k, const XML_Node& s, thermo_t& p,
SpeciesThermo& spthermo, int rule);
//bool installSpecies(int k, const XML_Node& s, thermo_t& p,
// SpeciesThermo& spthermo, int rule);
bool importPhase(XML_Node& phase, ThermoPhase* th);
bool importPhase(XML_Node& phase, ThermoPhase* th,
SpeciesThermoFactory* spfactory = 0);
/**
* This function returns true if two reactions are duplicates of

View file

@ -696,82 +696,87 @@ namespace Cantera {
}
}
//const XML_Node* XML_Node::getRef() const {
// if (!hasAttrib("idRef")) return this;
// XML_Node& node = *this;
// return find_XML(node["src"], &root(), node["idRef"]);
//}
#ifdef FIND_XML
/*
* Find a particular XML element by a fairly complicated hierarchal
* search objective.
*
* HKM -Note: Right now this routine contains a memory leak.
* A "new" operation is conditionally carried out and
* the pointer may or may not be returned to the calling
* program. Therefore, it can't be deleted in the
* calling program. This
* eventually needs to be fixed by extracting the xml
* malloc and build operation from the search operation.
*/
XML_Node* find_XML(string src, XML_Node* root, string id, string loc,
string name) {
string file, id2;
split(src, file, id2);
src = file;
if (id2 != "") id = id2;
XML_Node *doc = 0, *r = 0;
if (src != "") {
doc = new XML_Node("doc");
string spath = findInputFile(src);
ifstream fin(spath.c_str());
if (!fin)
throw CanteraError("find_XML","could not open file "+src+
" for input.");
doc->build(fin);
root = 0;
}
else if (root) {
doc = root;
}
else {
throw CanteraError("find_XML",
"either root or src must be specified.");
}
try {
if (id != "")
r = doc->findID(id);
else if (loc != "")
r = &doc->child(loc);
else if (name != "")
r = doc->findByName(name);
if (!r) {
string opt = " src="+src+", loc="+loc+", id="
+id+", name="+name;
throw CanteraError("find_XML", "XML element with "+opt+
" not found.");
}
return r;
}
catch (CanteraError) {
// root was used, but element was not found. Try src.
if (root && src != "") {
return find_XML(src, 0, id, loc, name);
}
else {
string opt = " src="+src+", loc="+loc+", id="
+id+", name="+name;
throw CanteraError("find_XML", "XML element with "+opt+
" not found.");
return 0;
}
void XML_Node::require(string a, string v) const {
if (hasAttrib(a)) {
if (attrib(a) == v) return;
}
string msg="XML_Node "+name()+" is required to have the value "
"\""+v+"\", but instead is \""+attrib(a);
throw CanteraError("XML_Node::require",msg);
}
#endif
// #ifdef FIND_XML
// /*
// * Find a particular XML element by a fairly complicated hierarchal
// * search objective.
// *
// * HKM -Note: Right now this routine contains a memory leak.
// * A "new" operation is conditionally carried out and
// * the pointer may or may not be returned to the calling
// * program. Therefore, it can't be deleted in the
// * calling program. This
// * eventually needs to be fixed by extracting the xml
// * malloc and build operation from the search operation.
// */
// XML_Node* find_XML(string src, XML_Node* root, string id, string loc,
// string name) {
// string file, id2;
// split(src, file, id2);
// src = file;
// if (id2 != "") id = id2;
// XML_Node *doc = 0, *r = 0;
// if (src != "") {
// doc = new XML_Node("doc");
// string spath = findInputFile(src);
// ifstream fin(spath.c_str());
// if (!fin)
// throw CanteraError("find_XML","could not open file "+src+
// " for input.");
// doc->build(fin);
// root = 0;
// }
// else if (root) {
// doc = root;
// }
// else {
// throw CanteraError("find_XML",
// "either root or src must be specified.");
// }
// try {
// if (id != "")
// r = doc->findID(id);
// else if (loc != "")
// r = &doc->child(loc);
// else if (name != "")
// r = doc->findByName(name);
// if (!r) {
// string opt = " src="+src+", loc="+loc+", id="
// +id+", name="+name;
// throw CanteraError("find_XML", "XML element with "+opt+
// " not found.");
// }
// return r;
// }
// catch (CanteraError) {
// // root was used, but element was not found. Try src.
// if (root && src != "") {
// return find_XML(src, 0, id, loc, name);
// }
// else {
// string opt = " src="+src+", loc="+loc+", id="
// +id+", name="+name;
// throw CanteraError("find_XML", "XML element with "+opt+
// " not found.");
// return 0;
// }
// }
// }
// #endif
XML_Node * findXMLPhase(XML_Node *root,

View file

@ -129,7 +129,7 @@ namespace Cantera {
int nChildren() const { return m_nchildren; }
void build(istream& f);
void require(string a, string v) const;
/**
* This routine carries out a search for an XML node based
* on both the xml element name and the attribute ID.

View file

@ -1,12 +1,15 @@
/**
* @file FlowDevice.h
*
* $Author$
* @file Wall.h
* Header file for class Wall.
*/
/* $Author$
* $Date$
* $Revision$
*/
// Copyright 2001 California Institute of Technology
// Copyright 2001-2004 California Institute of Technology
#ifndef CT_WALL_H
#define CT_WALL_H
@ -17,17 +20,21 @@
#endif
#include "../ct_defs.h"
#include "../ctexceptions.h"
#include "../Func1.h"
namespace Cantera {
class ReactorBase; // forward reference
// forward references
class ReactorBase;
class Kinetics;
class Func1;
class SurfPhase;
const int Rigid_Type = 1;
const int Flexible_Type = 2;
// const int Rigid_Type = 1;
// const int Flexible_Type = 2;
class Wall {
@ -36,14 +43,17 @@ namespace Cantera {
/// Constructor
Wall();
/// Destructor
/// Destructor. Since Wall instances do not allocate memory,
/// the destructor does nothing.
virtual ~Wall() {}
/**
* Rate of volume change (kg/s). Positive value increases
* volume of reactor on left, and decreases volume on right.
*/
/// Rate of volume change (kg/s). Positive value increases
/// volume of reactor on left, and decreases volume on right.
virtual doublereal vdot(doublereal t);
/// Heat flow rate through the wall (W). Positive values
/// denote a flux from left to right.
virtual doublereal Q(doublereal t);
/// Area in m^2.
@ -51,16 +61,18 @@ namespace Cantera {
/// Set the area [m^2].
void setArea(doublereal a) { m_area = a; }
void setThermalResistance(doublereal Rth) { m_rrth = 1.0/Rth; }
/// Set the overall heat transfer coefficient [W/m^2/K].
void setHeatTransferCoeff(doublereal U) { m_rrth = U; }
void setEmissivity(doublereal epsilon) { m_emiss = epsilon; }
// /** Set the rate of volume change to a specified function.*/
// void setExpansionRate(Func1* f=0) {if (f) m_vf = f;}
/// Set the emissivity.
void setEmissivity(doublereal epsilon) {
if (epsilon > 1.0 || epsilon < 0.0)
throw CanteraError("Wall::setEmissivity",
"emissivity must be between 0.0 and 1.0");
m_emiss = epsilon; }
/** Set the piston velocity to a specified function. */
void setVelocity(Func1* f=0) {if (f) m_vf = f;}
@ -70,31 +82,39 @@ namespace Cantera {
*/
void setExpansionRateCoeff(doublereal k) {m_k = k;}
/**
* Specify the heat flux q(t).
*/
/// Specify the heat flux function \f$ q_0(t) \f$.
void setHeatFlux(Func1* q) { m_qf = q;}
bool install(ReactorBase& in, ReactorBase& out);
/// Install the wall between two reactors or reservoirs
bool install(ReactorBase& leftReactor, ReactorBase& rightReactor);
/// True if the wall is correctly configured and ready to use.
virtual bool ready() { return (m_left != 0 && m_right != 0); }
int type() { return 0; }
// int type() { return 0; }
/// Return a reference to the left reactor.
/// Return a reference to the reactor or reservoir to the left
/// of the wall.
ReactorBase& left() const { return *m_left; }
/// Return a reference to the right-hand reactor.
/// Return a reference to the reactor or reservoir to the
/// right of the wall.
const ReactorBase& right() { return *m_right; }
/// set parameters
virtual void setParameters(int n, doublereal* coeffs) {
m_coeffs.resize(n);
copy(coeffs, coeffs + n, m_coeffs.begin());
}
// /// Set wall parameters.
//virtual void setParameters(int n, doublereal* coeffs) {
// m_coeffs.resize(n);
// copy(coeffs, coeffs + n, m_coeffs.begin());
//}
void setKinetics(Kinetics* left = 0,
Kinetics* right = 0);
// Specify the heterogeneous reaction mechanisms for each side
// of the wall.
void setKinetics(Kinetics* leftMechanism, Kinetics* rightMechanism);
/// Return a pointer to the surface phase object for the left
/// or right wall surface.
SurfPhase* surface(int leftright) {
return m_surf[leftright];
}
@ -103,16 +123,22 @@ namespace Cantera {
return m_chem[leftright];
}
/// Set the surface coverages on the left or right surface to
/// the values in array 'cov'.
void setCoverages(int leftright, const doublereal* cov);
/// Write the coverages of the left or right surface into
/// array cov.
void getCoverages(int leftright, doublereal* cov);
/// Set the coverages in the surface phase object to the
/// values for this wall surface.
void syncCoverages(int leftright);
protected:
vector_fp m_coeffs;
//vector_fp m_coeffs;
ReactorBase* m_left;
ReactorBase* m_right;
@ -128,53 +154,6 @@ namespace Cantera {
private:
};
// class Piston : public Wall {
// public:
// Piston()
// : m_omega(2.0*3.1415926*freq), Wall() {
// //m_vdisp = stroke * Pi * bore * bore / 4.0;
// //m_vclear = tdc * bore;
// //m_ra = 1.0/crankradius;
// }
// ~Piston() {}
// virtual doublereal vdot(double t) {
// doublereal theta = m_omega * t;
// doublereal sinth = sin(theta);
// return 0.0;
// //return m_vclear + 0.5*m_vdist*(1.0 + m_ra - m_omega*sin(theta)
// // - sqrt(m_ra * m_ra - sinth*sinth));
// }
// protected:
// doublereal m_tdc, m_bdc, m_stroke, m_bore, m_rodlen,
// m_radius, m_omega;
// };
class Piston : public Wall {
public:
Piston(doublereal freq,
doublereal tdc, doublereal bdc,
doublereal stroke, doublereal bore,
doublereal rodlen, doublereal crankradius)
: Wall(), m_omega(2.0*3.1415926*freq) {
//m_vdisp = stroke * Pi * bore * bore / 4.0;
//m_vclear = tdc * bore;
//m_ra = 1.0/crankradius;
}
virtual ~Piston() {}
virtual doublereal vdot(double t) {
// doublereal theta = m_omega * t;
//doublereal sinth = sin(theta);
return 0.0;
//return m_vclear + 0.5*m_vdist*(1.0 + m_ra - m_omega*sin(theta)
// - sqrt(m_ra * m_ra - sinth*sinth));
}
protected:
doublereal m_tdc, m_bdc, m_stroke, m_bore, m_rodlen,
m_radius, m_omega;
};
}