cantera/Cantera/src/SpeciesThermoFactory.cpp

443 lines
14 KiB
C++
Executable file

/**
* @file SpeciesThermoFactory.cpp
*/
// Copyright 2001 California Institute of Technology
#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "SpeciesThermoFactory.h"
#include "SpeciesThermo.h"
#include "NasaThermo.h"
#include "ShomateThermo.h"
//#include "PolyThermoMgr.h"
#include "SimpleThermo.h"
#include "GeneralSpeciesThermo.h"
#include "Mu0Poly.h"
#include "SpeciesThermoMgr.h"
#include "speciesThermoTypes.h"
#include "xml.h"
#include "ctml.h"
using namespace ctml;
namespace Cantera {
SpeciesThermoFactory* SpeciesThermoFactory::s_factory = 0;
static void getSpeciesThermoTypes(XML_Node* node,
int& has_nasa, int& has_shomate, int& has_simple,
int &has_other) {
const XML_Node& sparray = *node;
vector<XML_Node*> sp;
sparray.getChildren("species",sp);
int ns = static_cast<int>(sp.size());
for (int n = 0; n < ns; n++) {
XML_Node* spNode = sp[n];
if (spNode->hasChild("thermo")) {
const XML_Node& th = sp[n]->child("thermo");
if (th.hasChild("NASA")) has_nasa = 1;
if (th.hasChild("Shomate")) has_shomate = 1;
if (th.hasChild("const_cp")) has_simple = 1;
if (th.hasChild("poly")) {
if (th.child("poly")["order"] == "1") has_simple = 1;
else throw CanteraError("newSpeciesThermo",
"poly with order > 1 not yet supported");
}
if (th.hasChild("Mu0")) has_other = 1;
} else {
throw UnknownSpeciesThermoModel("getSpeciesThermoTypes:",
spNode->attrib("name"), "missing");
}
}
}
/**
* Return a species thermo manager to handle the parameterizations
* specified in a CTML phase specification.
*/
SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(XML_Node* node) {
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
try {
getSpeciesThermoTypes(node, inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
}
if (iother) {
writelog("returning new GeneralSpeciesThermo");
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
SpeciesThermo* SpeciesThermoFactory::
newSpeciesThermo(vector<XML_Node*> nodes) {
int n = static_cast<int>(nodes.size());
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
for (int j = 0; j < n; j++) {
try {
getSpeciesThermoTypes(nodes[j], inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
}
}
if (iother) {
writelog("returning new GeneralSpeciesThermo");
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
SpeciesThermo* SpeciesThermoFactory::
newSpeciesThermoOpt(vector<XML_Node*> nodes) {
int n = static_cast<int>(nodes.size());
int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
for (int j = 0; j < n; j++) {
try {
getSpeciesThermoTypes(nodes[j], inasa, ishomate, isimple, iother);
} catch (UnknownSpeciesThermoModel) {
iother = 1;
popError();
}
}
if (iother) {
writelog("returning new GeneralSpeciesThermo");
return new GeneralSpeciesThermo();
}
return newSpeciesThermo(NASA*inasa
+ SHOMATE*ishomate + SIMPLE*isimple);
}
SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(int type) {
switch (type) {
case NASA:
return new NasaThermo;
case SHOMATE:
return new ShomateThermo;
case SIMPLE:
return new SimpleThermo;
case NASA + SHOMATE:
return new SpeciesThermoDuo<NasaThermo, ShomateThermo>;
case NASA + SIMPLE:
return new SpeciesThermoDuo<NasaThermo, SimpleThermo>;
case SHOMATE + SIMPLE:
return new SpeciesThermoDuo<ShomateThermo, SimpleThermo>;
default:
throw UnknownSpeciesThermo(
"SpeciesThermoFactory::newSpeciesThermo",type);
return 0;
}
}
/// Check the continuity of properties at the midpoint
/// temperature.
void NasaThermo::checkContinuity(string name, double tmid, const doublereal* clow,
doublereal* chigh) {
// heat capacity
doublereal cplow = poly4(tmid, clow+2);
doublereal cphigh = poly4(tmid, chigh+2);
doublereal delta = cplow - cphigh;
if (fabs(delta/cplow) > 0.001) {
writelog("\n**** WARNING ****\nFor species "+name+
", discontinuity in cp/R detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "+fp2str(cplow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "+fp2str(cphigh)+".\n");
}
// enthalpy
doublereal hrtlow = enthalpy_RT(tmid, clow);
doublereal hrthigh = enthalpy_RT(tmid, chigh);
delta = hrtlow - hrthigh;
if (fabs(delta/hrtlow) > 0.001) {
writelog("\n**** WARNING ****\nFor species "+name+", discontinuity in h/RT detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "+fp2str(hrtlow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "+fp2str(hrthigh)+".\n");
}
// entropy
doublereal srlow = entropy_R(tmid, clow);
doublereal srhigh = entropy_R(tmid, chigh);
delta = srlow - srhigh;
if (fabs(delta/srlow) > 0.001) {
writelog("\n**** WARNING ****\nFor species "+name+", discontinuity in s/R detected at Tmid = "
+fp2str(tmid)+"\n");
writelog("\tValue computed using low-temperature polynomial: "+fp2str(srlow)+".\n");
writelog("\tValue computed using high-temperature polynomial: "+fp2str(srhigh)+".\n");
}
}
/**
* Install a NASA polynomial thermodynamic property
* parameterization for species k into a SpeciesThermo instance.
*/
static void installNasaThermoFromXML(string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
c1.resize(7,0.0);
copy(c0.begin(), c0.end(), c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(speciesName, k, NASA, c.begin(), tmin, tmax, p0);
}
#ifdef INCL_NASA96
/**
* Install a NASA96 polynomial thermodynamic property
* parameterization for species k into a SpeciesThermo instance.
*/
static void installNasa96ThermoFromXML(string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
c1.resize(7,0.0);
copy(c0.begin(), c0.end(), c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installNasaThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
c[1] = c0[5];
c[2] = c0[6];
copy(c0.begin(), c0.begin()+5, c.begin() + 3);
c[8] = c1[5];
c[9] = c1[6];
copy(c1.begin(), c1.begin()+5, c.begin() + 10);
sp.install(speciesName, k, NASA, c.begin(), tmin, tmax, p0);
}
#endif
/**
* Install a Shomate polynomial thermodynamic property
* parameterization for species k.
*/
static void installShomateThermoFromXML(string speciesName,
SpeciesThermo& sp, int k,
const XML_Node* f0ptr, const XML_Node* f1ptr) {
doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
const XML_Node& f0 = *f0ptr;
bool dualRange = false;
if (f1ptr) {dualRange = true;}
tmin0 = fpValue(f0["Tmin"]);
tmax0 = fpValue(f0["Tmax"]);
tmin1 = tmax0;
tmax1 = tmin1 + 0.0001;
if (dualRange) {
tmin1 = fpValue((*f1ptr)["Tmin"]);
tmax1 = fpValue((*f1ptr)["Tmax"]);
}
vector_fp c0, c1;
if (fabs(tmax0 - tmin1) < 0.01) {
tmin = tmin0;
tmid = tmax0;
tmax = tmax1;
getFloatArray(f0.child("floatArray"), c0, false);
if (dualRange)
getFloatArray(f1ptr->child("floatArray"), c1, false);
else {
c1.resize(7,0.0);
copy(c0.begin(), c0.begin()+7, c1.begin());
}
}
else if (fabs(tmax1 - tmin0) < 0.01) {
tmin = tmin1;
tmid = tmax1;
tmax = tmax0;
getFloatArray(f1ptr->child("floatArray"), c0, false);
getFloatArray(f0.child("floatArray"), c1, false);
}
else {
throw CanteraError("installShomateThermo",
"non-continuous temperature ranges.");
}
array_fp c(15);
c[0] = tmid;
doublereal p0 = OneAtm;
copy(c0.begin(), c0.begin()+7, c.begin() + 1);
copy(c1.begin(), c1.begin()+7, c.begin() + 8);
sp.install(speciesName, k, SHOMATE, c.begin(), tmin, tmax, p0);
}
/**
* Install a constant-cp thermodynamic property
* parameterization for species k.
*/
static void installSimpleThermoFromXML(string speciesName,
SpeciesThermo& sp, int k,
const XML_Node& f) {
doublereal tmin, tmax;
tmin = fpValue(f["Tmin"]);
tmax = fpValue(f["Tmax"]);
if (tmax == 0.0) tmax = 1.0e30;
vector_fp c(4);
c[0] = getFloat(f, "t0", "-");
c[1] = getFloat(f, "h0", "-");
c[2] = getFloat(f, "s0", "-");
c[3] = getFloat(f, "cp0", "-");
doublereal p0 = OneAtm;
sp.install(speciesName, k, SIMPLE, c.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) {
/*
* Check to see that the species block has a thermo block
* before processing. Throw an error if not there.
*/
if (!(s.hasChild("thermo"))) {
throw UnknownSpeciesThermoModel("installSpecies",
s["name"], "<nonexistent>");
}
const XML_Node& thermo = s.child("thermo");
const vector<XML_Node*>& tp = thermo.children();
int nc = static_cast<int>(tp.size());
if (nc == 1) {
const XML_Node* f = tp[0];
if (f->name() == "Shomate") {
installShomateThermoFromXML(s["name"], spthermo, k, f, 0);
}
else if (f->name() == "const_cp") {
installSimpleThermoFromXML(s["name"], spthermo, k, *f);
}
else if (f->name() == "NASA") {
installNasaThermoFromXML(s["name"], spthermo, k, f, 0);
}
else if (f->name() == "Mu0") {
installMu0ThermoFromXML(s["name"], spthermo, k, f);
}
else {
throw UnknownSpeciesThermoModel("installSpecies",
s["name"], f->name());
}
}
else if (nc == 2) {
const XML_Node* f0 = tp[0];
const XML_Node* f1 = tp[1];
if (f0->name() == "NASA" && f1->name() == "NASA") {
installNasaThermoFromXML(s["name"], spthermo, k, f0, f1);
}
else if (f0->name() == "Shomate" && f1->name() == "Shomate") {
installShomateThermoFromXML(s["name"], spthermo, k, f0, f1);
}
else {
throw UnknownSpeciesThermoModel("installSpecies", s["name"],
f0->name() + " and "
+ f1->name());
}
}
else {
throw UnknownSpeciesThermoModel("installSpecies", s["name"],
"multiple");
}
}
}