37 SpeciesThermoFactory* SpeciesThermoFactory::s_factory = 0;
38 mutex_t SpeciesThermoFactory::species_thermo_mutex;
55 int& has_nasa,
int& has_shomate,
int& has_simple,
58 size_t ns = spDataNodeList.size();
59 for (
size_t n = 0; n < ns; n++) {
60 XML_Node* spNode = spDataNodeList[n];
61 if (spNode->
hasChild(
"standardState")) {
63 string mname = ss[
"model"];
64 if (mname ==
"water" || mname ==
"waterIAPWS") {
77 }
else if (th.
hasChild(
"const_cp")) {
80 if (th.
child(
"poly")[
"order"] ==
"1") {
83 "poly with order > 1 not yet supported");
88 }
else if (th.
hasChild(
"NASA9MULTITEMP")) {
90 }
else if (th.
hasChild(
"adsorbate")) {
99 spNode->
attrib(
"name") +
" is missing the thermo XML node");
115 ScopedLock lock(species_thermo_mutex);
128 void SpeciesThermoFactory::deleteFactory()
130 ScopedLock lock(species_thermo_mutex);
144 SpeciesThermoFactory::~SpeciesThermoFactory()
152 SpeciesThermo* SpeciesThermoFactory::newSpeciesThermo(std::vector<XML_Node*> & spDataNodeList)
const
154 int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
165 return newSpeciesThermo(
NASA*inasa
174 newSpeciesThermoOpt(std::vector<XML_Node*> & spDataNodeList)
const
176 int inasa = 0, ishomate = 0, isimple = 0, iother = 0;
187 return newSpeciesThermo(
NASA*inasa
213 SpeciesThermo* SpeciesThermoFactory::newSpeciesThermoManager(std::string& stype)
const
216 if (ltype ==
"nasa") {
218 }
else if (ltype ==
"shomate") {
220 }
else if (ltype ==
"simple" || ltype ==
"constant_cp") {
222 }
else if (ltype ==
"nasa_shomate_duo") {
224 }
else if (ltype ==
"nasa_simple_duo") {
226 }
else if (ltype ==
"shomate_simple_duo") {
228 }
else if (ltype ==
"general") {
230 }
else if (ltype ==
"") {
243 void NasaThermo::checkContinuity(std::string name,
double tmid,
const doublereal* clow,
247 doublereal cplow =
poly4(tmid, clow);
248 doublereal cphigh =
poly4(tmid, chigh);
249 doublereal delta = cplow - cphigh;
250 if (fabs(delta/(fabs(cplow)+1.0E-4)) > 0.001) {
251 writelog(
"\n\n**** WARNING ****\nFor species "+name+
252 ", discontinuity in cp/R detected at Tmid = "
254 writelog(
"\tValue computed using low-temperature polynomial: "
256 writelog(
"\tValue computed using high-temperature polynomial: "
261 doublereal hrtlow = enthalpy_RT(tmid, clow);
262 doublereal hrthigh = enthalpy_RT(tmid, chigh);
263 delta = hrtlow - hrthigh;
264 if (fabs(delta/(fabs(hrtlow)+cplow*tmid)) > 0.001) {
265 writelog(
"\n\n**** WARNING ****\nFor species "+name+
266 ", discontinuity in h/RT detected at Tmid = "
268 writelog(
"\tValue computed using low-temperature polynomial: "
270 writelog(
"\tValue computed using high-temperature polynomial: "
275 doublereal srlow = entropy_R(tmid, clow);
276 doublereal srhigh = entropy_R(tmid, chigh);
277 delta = srlow - srhigh;
278 if (fabs(delta/(fabs(srlow)+cplow)) > 0.001) {
279 writelog(
"\n\n**** WARNING ****\nFor species "+name+
280 ", discontinuity in s/R detected at Tmid = "
282 writelog(
"\tValue computed using low-temperature polynomial: "
284 writelog(
"\tValue computed using high-temperature polynomial: "
304 doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
309 bool dualRange =
false;
330 tmax1 = tmin1 + 0.0001;
332 tmin1 =
fpValue((*f1ptr)[
"Tmin"]);
333 tmax1 =
fpValue((*f1ptr)[
"Tmax"]);
337 if (fabs(tmax0 - tmin1) < 0.01) {
348 copy(c0.begin(), c0.end(), c1.begin());
350 }
else if (fabs(tmax1 - tmin0) < 0.01) {
359 "non-continuous temperature ranges.");
369 copy(c0.begin(), c0.begin()+5, c.begin() + 3);
372 copy(c1.begin(), c1.begin()+5, c.begin() + 10);
373 sp.
install(speciesName, k,
NASA, &c[0], tmin, tmax, p0);
385 throw CanteraError(
"PDSS_HKFT::LookupGe",
"element " + elemName +
" not found");
390 "element " + elemName +
" doesn not have a supplied entropy298");
392 geValue *= (-298.15);
413 doublereal totalSum = 0.0;
414 for (
size_t m = 0; m < ne; m++) {
415 na = th_ptr->
nAtoms(k, m);
443 std::string astring = (*MinEQ3node)[
"Tmin"];
445 astring = (*MinEQ3node)[
"Tmax"];
447 astring = (*MinEQ3node)[
"Pref"];
450 doublereal deltaG_formation_pr_tr =
452 doublereal deltaH_formation_pr_tr =
458 doublereal dg = deltaG_formation_pr_tr * 4.184 * 1.0E3;
460 doublereal Mu0_tr_pr = fac + dg;
461 doublereal e = Entrop_pr_tr * 1.0E3 * 4.184;
462 doublereal Hcalc = Mu0_tr_pr + 298.15 * e;
463 doublereal DHjmol = deltaH_formation_pr_tr * 1.0E3 * 4.184;
467 if (fabs(Hcalc -DHjmol) > 10.* 1.0E6 * 4.184) {
468 throw CanteraError(
"installMinEQ3asShomateThermoFromXML()",
469 "DHjmol is not consistent with G and S" +
483 double As = a * 4.184;
484 double Bs = b * 4.184 * 1000.;
487 double Es = c * 4.184 / (1.0E6);
489 double t = 298.15 / 1000.;
490 double H298smFs = As * t + Bs * t * t / 2.0 - Es / t;
492 double HcalcS = Hcalc / 1.0E6;
493 double Fs = HcalcS - H298smFs;
495 double S298smGs = As * log(t) + Bs * t - Es/(2.0*t*t);
496 double ScalcS = e / 1.0E3;
497 double Gs = ScalcS - S298smGs;
507 coef[0] = tmax0 - 0.001;
508 copy(c0.begin(), c0.begin()+7, coef.begin() + 1);
509 copy(c0.begin(), c0.begin()+7, coef.begin() + 8);
526 doublereal tmin0, tmax0, tmin1, tmax1, tmin, tmid, tmax;
528 bool dualRange =
false;
545 tmax1 = tmin1 + 0.0001;
547 tmin1 =
fpValue((*f1ptr)[
"Tmin"]);
548 tmax1 =
fpValue((*f1ptr)[
"Tmax"]);
552 if (fabs(tmax0 - tmin1) < 0.01) {
561 copy(c0.begin(), c0.begin()+7, c1.begin());
563 }
else if (fabs(tmax1 - tmin0) < 0.01) {
571 "non-continuous temperature ranges.");
575 copy(c0.begin(), c0.begin()+7, c.begin() + 1);
576 copy(c1.begin(), c1.begin()+7, c.begin() + 8);
593 doublereal tmin, tmax;
621 const std::vector<XML_Node*>& tp)
627 std::vector<Nasa9Poly1*> regionPtrs;
628 doublereal tmin, tmax, pref =
OneAtm;
630 for (
size_t i = 0; i < tp.size(); i++) {
633 if (fptr->
name() ==
"NASA9") {
636 tmin =
fpValue((*fptr)[
"Tmin"]);
637 tmax =
fpValue((*fptr)[
"Tmax"]);
638 if ((*fptr).hasAttrib(
"P0")) {
641 if ((*fptr).hasAttrib(
"Pref")) {
642 pref =
fpValue((*fptr)[
"Pref"]);
646 if (cPoly.size() != 9) {
648 "Expected 9 coeff polynomial");
652 regionPtrs.push_back(np_ptr);
661 }
else if (nRegions == 1) {
684 doublereal tmin, tmax, pref =
OneAtm;
700 nfreq = freqs.size();
702 for (
size_t n = 0; n < nfreq; n++) {
706 coeffs[0] =
static_cast<double>(nfreq);
707 coeffs[1] =
getFloat(f,
"binding_energy",
"toSI");
708 copy(freqs.begin(), freqs.end(), coeffs.begin() + 2);
709 (&sp)->install(speciesName, k,
ADSORBATE, &coeffs[0], tmin, tmax, pref);
725 void SpeciesThermoFactory::installThermoForSpecies
733 if (!(speciesNode.
hasChild(
"thermo"))) {
735 speciesNode[
"name"],
"<nonexistent>");
742 const std::vector<XML_Node*>& tpWC = thermo.
children();
743 std::vector<XML_Node*> tp;
744 for (
int i = 0; i < static_cast<int>(tpWC.size()); i++) {
745 if (!(tpWC[i])->isComment()) {
746 tp.push_back(tpWC[i]);
749 int nc =
static_cast<int>(tp.size());
750 string mname = thermo[
"model"];
752 if (mname ==
"MineralEQ3") {
754 if (f->
name() !=
"MinEQ3") {
755 throw CanteraError(
"SpeciesThermoFactory::installThermoForSpecies",
756 "confused: expedted MinEQ3");
762 if (f->
name() ==
"Shomate") {
764 }
else if (f->
name() ==
"const_cp") {
766 }
else if (f->
name() ==
"NASA") {
768 }
else if (f->
name() ==
"Mu0") {
770 }
else if (f->
name() ==
"NASA9") {
773 else if (f->
name() ==
"adsorbate") {
778 speciesNode[
"name"], f->
name());
780 }
else if (nc == 2) {
783 if (f0->
name() ==
"NASA" && f1->
name() ==
"NASA") {
785 }
else if (f0->
name() ==
"Shomate" && f1->
name() ==
"Shomate") {
787 }
else if (f0->
name() ==
"NASA9" && f1->
name() ==
"NASA9") {
795 if (f0->
name() ==
"NASA9") {
828 void SpeciesThermoFactory::
829 installVPThermoForSpecies(
size_t k,
const XML_Node& speciesNode,
833 const XML_Node* phaseNode_ptr)
const
844 vp_ptr->createInstallPDSS(k, speciesNode, phaseNode_ptr);
864 f = SpeciesThermoFactory::factory();
888 f = SpeciesThermoFactory::factory();
914 f = SpeciesThermoFactory::factory();