15 #include "cantera/thermo/mix_defs.h"
43 ReactionRules::ReactionRules() :
44 skipUndeclaredSpecies(false),
45 skipUndeclaredThirdBodies(false),
55 std::vector< std::map<int, doublereal> >
m_rdata;
85 const ReactionData& rdata, doublereal errorTolerance)
89 map<string, double> bal, balr, balp;
94 size_t np = rdata.products.size();
97 for (
size_t index = 0; index < np; index++) {
98 size_t kp = rdata.products[index];
101 kstoich = rdata.pstoich[index];
103 for (
size_t m = 0; m < ph.
nElements(); m++) {
110 for (
size_t index = 0; index < rdata.reactants.size(); index++) {
111 size_t kr = rdata.reactants[index];
115 kstoich = rdata.rstoich[index];
117 for (
size_t m = 0; m < ph.
nElements(); m++) {
125 map<string, double>::iterator b = bal.begin();
126 string msg =
"\n\tElement Reactants Products";
128 doublereal err, elemsum;
129 for (; b != bal.end(); ++b) {
130 elemsum = fabs(balr[b->first]) + fabs(balp[b->first]);
132 err = fabs(b->second/elemsum);
133 if (err > errorTolerance) {
135 msg +=
"\n\t"+b->first+
" "+
fp2str(balr[b->first])
136 +
" "+
fp2str(balp[b->first]);
141 msg =
"The following reaction is unbalanced:\n\t"
142 + rdata.equation +
"\n" + msg +
"\n";
178 std::string default_phase, std::vector<size_t>& spnum,
192 rptype =
"reactants";
203 vector<string> key, val;
209 doublereal ord, stch;
211 map<string, size_t> speciesMap;
212 for (
size_t n = 0; n < key.size(); n++) {
222 if (rules.skipUndeclaredSpecies) {
226 "Undeclared reactant or product species "+sp);
238 spnum.push_back(isp);
239 stch = atof(val[n].c_str());
240 stoich.push_back(stch);
241 ord = doublereal(stch);
242 order.push_back(ord);
248 speciesMap[sp] = order.size();
254 if (rp == 1 && rxn.
hasChild(
"order")) {
255 vector<XML_Node*> ord;
258 for (
size_t nn = 0; nn < ord.size(); nn++) {
260 string sp = oo[
"species"];
261 size_t loc = speciesMap[sp];
264 "reaction order specified for non-reactant: "
269 "reaction order must be non-negative");
274 order[loc-1] = forder;
287 doublereal& A, doublereal& b, doublereal& E)
290 if (node[
"name"] ==
"k0") {
300 E =
getFloat(node,
"E",
"actEnergy");
322 ReactionData& r, doublereal& A, doublereal& b, doublereal& E)
324 size_t nr = r.reactants.size();
325 size_t k, klocal, not_surf = 0;
336 string spname = node[
"species"];
346 for (
size_t n = 0; n < nr; n++) {
371 if (ispPhaseIndex == np) {
385 "reaction probabilities can only be used in "
386 "reactions with exactly 1 gas/liquid species.");
390 A = 0.25 *
getFloat(node,
"A",
"toSI") * cbar * f;
392 E =
getFloat(node,
"E",
"actEnergy");
396 static void getCoverageDependence(
const XML_Node& node,
397 thermo_t& surfphase, ReactionData& rdata)
399 vector<XML_Node*> cov;
400 node.getChildren(
"coverage", cov);
401 size_t k, nc = cov.size();
405 for (
size_t n = 0; n < nc; n++) {
406 const XML_Node& cnode = *cov[n];
407 spname = cnode[
"species"];
408 k = surfphase.speciesIndex(spname);
409 rdata.cov.push_back(doublereal(k));
410 rdata.cov.push_back(
getFloat(cnode,
"a"));
411 rdata.cov.push_back(
getFloat(cnode,
"m"));
412 e =
getFloat(cnode,
"e",
"actEnergy");
431 string type = f[
"type"];
435 int np =
static_cast<int>(p.size());
436 for (
int n = 0; n < np; n++) {
439 if (type ==
"Troe") {
441 rdata.falloffType = TROE4_FALLOFF;
442 }
else if (np == 3) {
443 rdata.falloffType = TROE3_FALLOFF;
445 throw CanteraError(
"getFalloff()",
"Troe parameterization is specified by number of pararameters, "
446 +
int2str(np) +
", is not equal to 3 or 4");
448 }
else if (type ==
"SRI") {
450 rdata.falloffType = SRI5_FALLOFF;
452 throw CanteraError(
"getFalloff()",
"SRI5 m_c parameter is less than zero: " +
fp2str(c[2]));
455 throw CanteraError(
"getFalloff()",
"SRI5 m_d parameter is less than zero: " +
fp2str(c[3]));
457 }
else if (np == 3) {
458 rdata.falloffType = SRI3_FALLOFF;
460 throw CanteraError(
"getFalloff()",
"SRI3 m_c parameter is less than zero: " +
fp2str(c[2]));
463 throw CanteraError(
"getFalloff()",
"SRI parameterization is specified by number of pararameters, "
464 +
int2str(np) +
", is not equal to 3 or 5");
467 rdata.falloffParameters = c;
479 rdata.default_3b_eff =
fpValue(eff[
"default"]);
481 vector<string> key, val;
485 for (
size_t n = 0; n < key.size(); n++) {
489 rdata.thirdBodyEfficiencies[k] =
fpValue(val[n]);
490 }
else if (!rules.skipUndeclaredThirdBodies) {
491 throw CanteraError(
"getEfficiencies",
"Encountered third-body "
492 "efficiency for undefined species \"" + nm +
"\"\n"
493 "while adding reaction " +
int2str(rdata.number+1) +
".");
509 if (rdata.reactionType ==
PLOG_RXN) {
510 rdata.rateCoeffType = PLOG_REACTION_RATECOEFF_TYPE;
511 for (
size_t m = 0; m < kf.
nChildren(); m++) {
513 double p =
getFloat(node,
"P",
"toSI");
514 vector_fp& rate = rdata.plogParameters.insert(
517 rate[0] =
getFloat(node,
"A",
"toSI");
523 rdata.rateCoeffType = CHEBYSHEV_REACTION_RATECOEFF_TYPE;
524 rdata.chebTmin =
getFloat(kf,
"Tmin",
"toSI");
525 rdata.chebTmax =
getFloat(kf,
"Tmax",
"toSI");
526 rdata.chebPmin =
getFloat(kf,
"Pmin",
"toSI");
527 rdata.chebPmax =
getFloat(kf,
"Pmax",
"toSI");
529 rdata.chebDegreeP = atoi(coeffs[
"degreeP"].c_str());
530 rdata.chebDegreeT = atoi(coeffs[
"degreeT"].c_str());
535 string type = kf.
attrib(
"type");
538 rdata.rateCoeffType = ARRHENIUS_REACTION_RATECOEFF_TYPE;
540 if (type ==
"ExchangeCurrentDensity") {
541 rdata.rateCoeffType = EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE;
542 }
else if (type ==
"Arrhenius") {
545 throw CanteraError(
"getRateCoefficient",
"Unknown type: " + type);
549 for (
size_t m = 0; m < kf.
nChildren(); m++) {
551 string nm = c.
name();
554 if (nm ==
"Arrhenius") {
556 if (c[
"type"] ==
"stick") {
557 getStick(c, kin, rdata, coeff[0], coeff[1], coeff[2]);
569 getCoverageDependence(c,
573 if (coeff[0] <= 0.0 && !rules.allowNegativeA) {
575 "negative or zero A coefficient for reaction "+
int2str(rdata.number));
577 }
else if (nm ==
"Arrhenius_ExchangeCurrentDensity") {
581 rdata.rateCoeffType = EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE;
582 }
else if (nm ==
"falloff") {
584 }
else if (nm ==
"efficiencies") {
586 }
else if (nm ==
"electrochem") {
587 rdata.beta =
fpValue(c[
"beta"]);
595 rdata.rateCoeffParameters = clow;
597 rdata.rateCoeffParameters = chigh;
601 rdata.auxRateCoeffParameters = clow;
603 rdata.auxRateCoeffParameters = chigh;
617 std::map<int, doublereal>& r2)
620 map<int, doublereal>::const_iterator b = r1.begin(), e = r1.end();
622 doublereal ratio = 0.0;
623 if (r1[k1] == 0.0 || r2[k1] == 0.0) {
626 ratio = r2[k1]/r1[k1];
628 for (; b != e; ++b) {
630 if (r1[k1] == 0.0 || r2[k1] == 0.0) {
633 if (fabs(r2[k1]/r1[k1] - ratio) > 1.e-8) {
642 if (r1[k1] == 0.0 || r2[-k1] == 0.0) {
645 ratio = r2[-k1]/r1[k1];
647 for (; b != e; ++b) {
649 if (r1[k1] == 0.0 || r2[-k1] == 0.0) {
652 if (fabs(r2[-k1]/r1[k1] - ratio) > 1.e-8) {
683 if (r.
name() !=
"reaction") {
685 " expected xml node reaction, got " + r.
name());
692 rdata.validate = validate_rxn;
697 int dup = (r.
hasAttrib(
"duplicate")) ? 1 : 0;
701 rules.allowNegativeA = (r.
hasAttrib(
"negative_A")) ? 1 : 0;
708 string eqn = (r.
hasChild(
"equation")) ? r(
"equation") :
"<no equation>";
709 for (
size_t nn = 0; nn < eqn.size(); nn++) {
710 if (eqn[nn] ==
'[') {
712 }
else if (eqn[nn] ==
']') {
719 rdata.rstoich, rdata.rorder, rules);
723 rdata.pstoich, rdata.porder, rules);
733 string isrev = r[
"reversible"];
734 rdata.reversible = (isrev ==
"yes" || isrev ==
"true");
743 if (rdata.reversible ==
true)
745 "reaction orders may only be given for "
746 "irreversible reactions");
756 if (rdata.reversible ==
true) {
757 for (
size_t i = 0; i < rdata.products.size(); i++) {
758 doublereal po = rdata.porder[i];
760 doublereal chk = po - 1.0 * int(po);
762 size_t k = rdata.products[i];
765 rdata.porder[i] = 0.0;
768 rdata.isReversibleWithFrac =
true;
771 for (
size_t i = 0; i < rdata.reactants.size(); i++) {
772 doublereal ro = rdata.rorder[i];
774 doublereal chk = ro - 1.0 * int(ro);
776 size_t k = rdata.reactants[i];
779 rdata.rorder[i] = 0.0;
781 rdata.isReversibleWithFrac =
true;
792 string typ = r[
"type"];
793 if (typ ==
"falloff") {
795 rdata.falloffType = SIMPLE_FALLOFF;
796 }
else if (typ ==
"chemAct") {
798 rdata.falloffType = SIMPLE_FALLOFF;
799 }
else if (typ ==
"threeBody") {
801 }
else if (typ ==
"plog") {
803 }
else if (typ ==
"chebyshev") {
805 }
else if (typ ==
"surface") {
807 }
else if (typ ==
"edge") {
809 }
else if (typ !=
"") {
810 throw CanteraError(
"installReaction",
"Unknown reaction type: " + typ);
815 map<int, doublereal> rxnstoich;
817 for (
size_t nn = 0; nn < rdata.reactants.size(); nn++) {
818 rxnstoich[-1 - int(rdata.reactants[nn])] -= rdata.rstoich[nn];
819 participants[rdata.reactants[nn]] += 1;
821 for (
size_t nn = 0; nn < rdata.products.size(); nn++) {
822 rxnstoich[int(rdata.products[nn])+1] += rdata.pstoich[nn];
823 participants[rdata.products[nn]] += 2;
827 for (
size_t mm = 0; mm < related.size(); mm++) {
828 size_t nn = related[mm];
829 if ((rdata.reactants.size() ==
m_nr[nn])
830 && (rdata.reactionType ==
m_typ[nn])) {
833 || (c < 0.0 && rdata.reversible)
834 || (c < 0.0 &&
m_rev[nn])) {
835 if ((!dup || !
m_dup[nn])) {
836 string msg = string(
"Undeclared duplicate reactions detected: \n")
838 +
"\nReaction "+
int2str(iRxn+1)+
": "+eqn+
"\n";
844 m_dup.push_back(dup);
845 m_rev.push_back(rdata.reversible);
846 m_eqn.push_back(eqn);
847 m_nr.push_back(rdata.reactants.size());
848 m_typ.push_back(rdata.reactionType);
853 rdata.equation = eqn;
855 rdata.rxn_number = iRxn;
888 std::string default_phase,
bool check_for_duplicates)
890 const std::auto_ptr<rxninfo> _rxns(
new rxninfo);
892 vector<XML_Node*> rarrays;
903 int na =
static_cast<int>(rarrays.size());
908 for (
int n = 0; n < na; n++) {
938 string sskip = sk[
"species"];
939 if (sskip ==
"undeclared") {
940 rxnrule.skipUndeclaredSpecies =
true;
942 if (sk[
"third_bodies"] ==
"undeclared") {
943 rxnrule.skipUndeclaredThirdBodies =
true;
952 vector<XML_Node*> incl;
954 int ninc =
static_cast<int>(incl.size());
956 vector<XML_Node*> allrxns;
958 nrxns =
static_cast<int>(allrxns.size());
961 for (i = 0; i < nrxns; i++) {
964 if (_rxns->installReaction(itot, *r, kin,
965 default_phase, rxnrule, check_for_duplicates)) {
971 for (
int nii = 0; nii < ninc; nii++) {
973 string imin = ii[
"min"];
974 string imax = ii[
"max"];
978 iwild = imin.find(
"*");
980 imin = imin.substr(0,iwild);
985 for (i = 0; i < nrxns; i++) {
991 rxid = rxid.substr(0,iwild);
998 if ((rxid >= imin) && (rxid <= imax)) {
999 if (_rxns->installReaction(itot, *r, kin,
1000 default_phase, rxnrule, check_for_duplicates)) {
1059 string owning_phase = phase[
"id"];
1061 bool check_for_duplicates =
false;
1064 if (d[
"reactions"] ==
"yes") {
1065 check_for_duplicates =
true;
1074 vector<string> phase_ids;
1075 if (phase.
hasChild(
"phaseArray")) {
1079 phase_ids.push_back(owning_phase);
1081 int np =
static_cast<int>(phase_ids.size());
1082 int nt =
static_cast<int>(th.size());
1090 for (
int n = 0; n < np; n++) {
1091 phase_id = phase_ids[n];
1096 for (
int m = 0; m < nt; m++) {
1097 if (th[m]->
id() == phase_id) {
1106 msg +=
" "+th[m]->id();
1110 "phase "+phase_id+
" not found. Supplied phases are:"+msg);
1146 vector<ThermoPhase*> phases(1);