From 754faa3b1342132c077883d0653459a3894e40a4 Mon Sep 17 00:00:00 2001 From: Ray Speth Date: Fri, 18 May 2012 22:41:58 +0000 Subject: [PATCH] Added option to ignore third-body efficiencies for undeclared species To enable this option, in the phase definition, add 'skip_undeclared_third_bodies' to the list passed as the 'options' argument. --- doc/sphinx/cti/phases.rst | 25 +++++---- include/cantera/kinetics/importKinetics.h | 24 +++++---- interfaces/python/ctml_writer.py | 6 +++ src/kinetics/importKinetics.cpp | 64 ++++++++++++++--------- 4 files changed, 75 insertions(+), 44 deletions(-) diff --git a/doc/sphinx/cti/phases.rst b/doc/sphinx/cti/phases.rst index 76dfd9a77..d831c7624 100644 --- a/doc/sphinx/cti/phases.rst +++ b/doc/sphinx/cti/phases.rst @@ -252,17 +252,20 @@ The options field is used to indicate how certain conditions should be handled when importing the phase definition. The options field may be assigned a string or a sequence of strings from the table below. -============================== ================ -Option String Meaning -============================== ================ -``'no_validation'`` Turn off all validation. Use when the definition - has been previously validated to speed up importing - the definition into an application. Use with caution! -``'skip_undeclared_elements'`` When importing species, skip any containing undeclared - elements, rather than flagging them as an error. -``'skip_undeclared_species'`` When importing reactions, skip any containing undeclared - species, rather than flagging them as an error. -============================== ================ +================================== ================ +Option String Meaning +================================== ================ +``'no_validation'`` Turn off all validation. Use when the definition + has been previously validated to speed up importing + the definition into an application. Use with caution! +``'skip_undeclared_elements'`` When importing species, skip any containing undeclared + elements, rather than flagging them as an error. +``'skip_undeclared_species'`` When importing reactions, skip any containing undeclared + species, rather than flagging them as an error. +``'skip_undeclared_third_bodies'`` When importing reactions with third body efficiencies, + ignore any efficiencies for undeclared species, rather + than flagging them as an error. +================================== ================ Using the ``options`` field, it is possible to extract a sub-mechanism from a large reaction mechanism, as follows:: diff --git a/include/cantera/kinetics/importKinetics.h b/include/cantera/kinetics/importKinetics.h index 740e15ba6..0a61f5651 100644 --- a/include/cantera/kinetics/importKinetics.h +++ b/include/cantera/kinetics/importKinetics.h @@ -27,6 +27,14 @@ class Kinetics; class SpeciesThermoFactory; class XML_Node; +//! Rules for parsing and installing reactions +struct ReactionRules +{ + ReactionRules(); + bool skipUndeclaredSpecies; + bool skipUndeclaredThirdBodies; + bool allowNegativeA; +}; //!This function returns a ratio if two reactions are duplicates of //!one another, and 0.0 otherwise. @@ -85,17 +93,15 @@ void checkRxnElementBalance(Kinetics& kin, * Length is number of reactants or products. * stoich = stoichiometric coefficient of the reactant or product * Length is number of reactants or products. - * order = Order of the reactant and product in the reaction - * rate expression - * @param rule If we fail to find a species, we will throw an error - * if rule != 1. If rule = 1, we simply return false, - * allowing the calling routine to skip this reaction - * and continue. + * order = Order of the reactant and product in the reaction rate expression + * @param rules If rules.skipUndeclaredSpecies is set and we fail to find a + * species we simply return false, allowing the calling routine to skip + * this reaction and continue. Otherwise, we will throw an error. */ bool getReagents(const XML_Node& rxn, Kinetics& kin, int rp, std::string default_phase, std::vector& spnum, vector_fp& stoich, - vector_fp& order, int rule); + vector_fp& order, const ReactionRules& rule); //! Read the rate coefficient data from the XML file. /*! @@ -113,8 +119,8 @@ bool getReagents(const XML_Node& rxn, Kinetics& kin, int rp, * * @ingroup kineticsmgr */ -void getRateCoefficient(const XML_Node& kf, Kinetics& kin, - ReactionData& rdata, int negA); +void getRateCoefficient(const XML_Node& kf, Kinetics& kin, ReactionData& rdata, + const ReactionRules& rules); //! Create a new ThermoPhase object and initializes it according to the XML tree database. diff --git a/interfaces/python/ctml_writer.py b/interfaces/python/ctml_writer.py index c18bda3d0..5e254a58b 100644 --- a/interfaces/python/ctml_writer.py +++ b/interfaces/python/ctml_writer.py @@ -1621,10 +1621,16 @@ class phase: datasrc = r[0] ra = p.addChild('reactionArray') ra['datasrc'] = datasrc+'#reaction_data' + rk = None if 'skip_undeclared_species' in self._options: rk = ra.addChild('skip') rk['species'] = 'undeclared' + if 'skip_undeclared_third_bodies' in self._options: + if not rk: + rk = ra.addChild('skip') + rk['third_bodies'] = 'undeclared' + rtoks = r[1].split() if rtoks[0] != 'all': i = ra.addChild('include') diff --git a/src/kinetics/importKinetics.cpp b/src/kinetics/importKinetics.cpp index 5d23eb8ce..a7f8662d2 100644 --- a/src/kinetics/importKinetics.cpp +++ b/src/kinetics/importKinetics.cpp @@ -40,6 +40,13 @@ using namespace std; namespace Cantera { +ReactionRules::ReactionRules() : + skipUndeclaredSpecies(false), + skipUndeclaredThirdBodies(false), + allowNegativeA(false) +{ +} + //! these are all used to check for duplicate reactions class rxninfo { @@ -67,7 +74,7 @@ public: std::map, std::vector > m_participants; bool installReaction(int i, const XML_Node& r, Kinetics& kin, - std::string default_phase, int rule, + std::string default_phase, ReactionRules& rule, bool validate_rxn) ; }; @@ -162,14 +169,15 @@ void checkRxnElementBalance(Kinetics& kin, * Length is number of reactants or products. * order = Order of the reactant and product in the reaction * rate expression - * rule = If we fail to find a species, we will throw an error + * rules = If we fail to find a species, we will throw an error * if rule != 1. If rule = 1, we simply return false, * allowing the calling routine to skip this reaction * and continue. */ bool getReagents(const XML_Node& rxn, Kinetics& kin, int rp, std::string default_phase, std::vector& spnum, - vector_fp& stoich, vector_fp& order, int rule) + vector_fp& stoich, vector_fp& order, + const ReactionRules& rules) { string rptype; @@ -211,7 +219,7 @@ bool getReagents(const XML_Node& rxn, Kinetics& kin, int rp, */ size_t isp = kin.kineticsSpeciesIndex(sp); if (isp == npos) { - if (rule == 1) { + if (rules.skipUndeclaredSpecies) { return false; } else { throw CanteraError("getReagents", @@ -464,7 +472,8 @@ static void getFalloff(const XML_Node& f, ReactionData& rdata) * reaction mechanism is homogeneous, so that all species belong * to phase(0) of 'kin'. */ -static void getEfficiencies(const XML_Node& eff, Kinetics& kin, ReactionData& rdata) +static void getEfficiencies(const XML_Node& eff, Kinetics& kin, + ReactionData& rdata, const ReactionRules& rules) { // set the default collision efficiency rdata.default_3b_eff = fpValue(eff["default"]); @@ -476,12 +485,13 @@ static void getEfficiencies(const XML_Node& eff, Kinetics& kin, ReactionData& rd for (size_t n = 0; n < key.size(); n++) { // ; bb != ee; ++bb) { nm = key[n];// bb->first; size_t k = kin.kineticsSpeciesIndex(nm, phse); - if (k == npos) { + if (k != npos) { + rdata.thirdBodyEfficiencies[k] = fpValue(val[n]); // bb->second; + } else if (!rules.skipUndeclaredThirdBodies) { throw CanteraError("getEfficiencies", "Encountered third-body " "efficiency for undefined species \"" + nm + "\"\n" "while adding reaction " + int2str(rdata.number+1) + "."); } - rdata.thirdBodyEfficiencies[k] = fpValue(val[n]); // bb->second; } } @@ -494,7 +504,7 @@ static void getEfficiencies(const XML_Node& eff, Kinetics& kin, ReactionData& rd * @param kf Reference to the XML Node named rateCoeff */ void getRateCoefficient(const XML_Node& kf, Kinetics& kin, - ReactionData& rdata, int negA) + ReactionData& rdata, const ReactionRules& rules) { if (rdata.reactionType == PLOG_RXN) { rdata.rateCoeffType = PLOG_REACTION_RATECOEFF_TYPE; @@ -560,7 +570,7 @@ void getRateCoefficient(const XML_Node& kf, Kinetics& kin, kin.thermo(kin.surfacePhaseIndex()), rdata); } - if (coeff[0] <= 0.0 && negA == 0) { + if (coeff[0] <= 0.0 && !rules.allowNegativeA) { throw CanteraError("getRateCoefficient", "negative or zero A coefficient for reaction "+int2str(rdata.number)); } @@ -572,7 +582,7 @@ void getRateCoefficient(const XML_Node& kf, Kinetics& kin, } else if (nm == "falloff") { getFalloff(c, rdata); } else if (nm == "efficiencies") { - getEfficiencies(c, kin, rdata); + getEfficiencies(c, kin, rdata, rules); } else if (nm == "electrochem") { rdata.beta = fpValue(c["beta"]); } @@ -666,7 +676,7 @@ next: * @ingroup kineticsmgr */ bool rxninfo::installReaction(int iRxn, const XML_Node& r, Kinetics& kin, - string default_phase, int rule, + string default_phase, ReactionRules& rules, bool validate_rxn) { // Check to see that we are in fact at a reaction node @@ -687,7 +697,7 @@ bool rxninfo::installReaction(int iRxn, const XML_Node& r, Kinetics& kin, // Check to see if the reaction rate constant can be negative. It's an // error if a negative rate constant is found and this is not set. - int negA = (r.hasAttrib("negative_A")) ? 1 : 0; + rules.allowNegativeA = (r.hasAttrib("negative_A")) ? 1 : 0; // Use the contents of the "equation" child element as the reaction's // string representation. Post-process to convert "[" and "]" characters @@ -705,11 +715,11 @@ bool rxninfo::installReaction(int iRxn, const XML_Node& r, Kinetics& kin, // get the reactants bool ok = getReagents(r, kin, 1, default_phase, rdata.reactants, - rdata.rstoich, rdata.rorder, rule); + rdata.rstoich, rdata.rorder, rules); // Get the products. We store the id of products in rdata.products ok = ok && getReagents(r, kin, -1, default_phase, rdata.products, - rdata.pstoich, rdata.porder, rule); + rdata.pstoich, rdata.porder, rules); // if there was a problem getting either the reactants or the products, // then abort. @@ -845,7 +855,7 @@ bool rxninfo::installReaction(int iRxn, const XML_Node& r, Kinetics& kin, // Read the rate coefficient data from the XML file. Trigger an // exception for negative A unless specifically authorized. - getRateCoefficient(r.child("rateCoeff"), kin, rdata, negA); + getRateCoefficient(r.child("rateCoeff"), kin, rdata, rules); // Check to see that the elements balance in the reaction. // Throw an error if they don't @@ -909,20 +919,26 @@ bool installReactionArrays(const XML_Node& p, Kinetics& kin, */ const XML_Node* rdata = get_XML_Node(rxns["datasrc"], &rxns.root()); /* - * If the reactionArray element has a child element named - * "skip", and if the attribute of skip called "species" has - * a value of "undeclared", we will set rxnrule = 1. - * rxnrule is passed to the routine that parses each individual - * reaction. I believe what this means is that the parser will - * skip all reactions containing an undefined species without - * throwing an error condition. + * If the reactionArray element has a child element named "skip", and + * if the attribute of skip called "species" has a value of "undeclared", + * we will set rxnrule.skipUndeclaredSpecies to 'true'. rxnrule is + * passed to the routine that parses each individual reaction so that + * the parser will skip all reactions containing an undefined species + * without throwing an error. + * + * Similarly, an attribute named "third_bodies" with the value of + * "undeclared" will skip undeclared third body efficiencies (while + * retaining the reaction and any other efficiencies). */ - int rxnrule = 0; + ReactionRules rxnrule; if (rxns.hasChild("skip")) { const XML_Node& sk = rxns.child("skip"); string sskip = sk["species"]; if (sskip == "undeclared") { - rxnrule = 1; + rxnrule.skipUndeclaredSpecies = true; + } + if (sk["third_bodies"] == "undeclared") { + rxnrule.skipUndeclaredThirdBodies = true; } } int i, nrxns = 0;