/** * This routine will look up a species number based on the input * std::string nm. The lookup of species will occur in the specified * phase of the object, or all phases if ph is "<any>". * * return * - If a match is found, the position in the species list is returned. * - If no match is found, the value npos (-1) is returned. * * @param nm Input string name of the species * @param ph Input string name of the phase. */ size_t Kinetics::kineticsSpeciesIndex(const std::string& nm, const std::string& ph) const { if (ph == "<any>") { return kineticsSpeciesIndex(nm); } for (size_t n = 0; n < m_thermo.size(); n++) { string id = thermo(n).id(); if (ph == id) { size_t k = thermo(n).speciesIndex(nm); if (k == npos) { return npos; } return k + m_start[n]; } } return npos; }
void GasKinetics::addThreeBodyReaction(ThreeBodyReaction& r) { m_rates.install(nReactions()-1, r.rate); map<size_t, double> efficiencies; for (Composition::const_iterator iter = r.third_body.efficiencies.begin(); iter != r.third_body.efficiencies.end(); ++iter) { size_t k = kineticsSpeciesIndex(iter->first); if (k != npos) { efficiencies[k] = iter->second; } else if (!m_skipUndeclaredThirdBodies) { throw CanteraError("GasKinetics::addThreeBodyReaction", "Found " "third-body efficiency for undefined species '" + iter->first + "' while adding reaction '" + r.equation() + "'"); } } m_3b_concm.install(nReactions()-1, efficiencies, r.third_body.default_efficiency); }
void GasKinetics::addFalloffReaction(FalloffReaction& r) { // install high and low rate coeff calculators // and extend the high and low rate coeff value vectors m_falloff_high_rates.install(m_nfall, r.high_rate); m_rfn_high.push_back(0.0); m_falloff_low_rates.install(m_nfall, r.low_rate); m_rfn_low.push_back(0.0); // add this reaction number to the list of falloff reactions m_fallindx.push_back(nReactions()-1); m_rfallindx[nReactions()-1] = m_nfall; // install the enhanced third-body concentration calculator map<size_t, double> efficiencies; for (Composition::const_iterator iter = r.third_body.efficiencies.begin(); iter != r.third_body.efficiencies.end(); ++iter) { size_t k = kineticsSpeciesIndex(iter->first); if (k != npos) { efficiencies[k] = iter->second; } else if (!m_skipUndeclaredThirdBodies) { throw CanteraError("GasKinetics::addTFalloffReaction", "Found " "third-body efficiency for undefined species '" + iter->first + "' while adding reaction '" + r.equation() + "'"); } } m_falloff_concm.install(m_nfall, efficiencies, r.third_body.default_efficiency); // install the falloff function calculator for this reaction m_falloffn.install(m_nfall, r.reaction_type, r.falloff); // increment the falloff reaction counter ++m_nfall; }
bool Kinetics::addReaction(shared_ptr<Reaction> r) { r->validate(); if (m_kk == 0) { init(); } resizeSpecies(); // If reaction orders are specified, then this reaction does not follow // mass-action kinetics, and is not an elementary reaction. So check that it // is not reversible, since computing the reverse rate from thermochemistry // only works for elementary reactions. if (r->reversible && !r->orders.empty()) { throw CanteraError("Kinetics::addReaction", "Reaction orders may only " "be given for irreversible reactions"); } // Check for undeclared species for (const auto& sp : r->reactants) { if (kineticsSpeciesIndex(sp.first) == npos) { if (m_skipUndeclaredSpecies) { return false; } else { throw CanteraError("Kinetics::addReaction", "Reaction '" + r->equation() + "' contains the undeclared species '" + sp.first + "'"); } } } for (const auto& sp : r->products) { if (kineticsSpeciesIndex(sp.first) == npos) { if (m_skipUndeclaredSpecies) { return false; } else { throw CanteraError("Kinetics::addReaction", "Reaction '" + r->equation() + "' contains the undeclared species '" + sp.first + "'"); } } } checkReactionBalance(*r); size_t irxn = nReactions(); // index of the new reaction // indices of reactant and product species within this Kinetics object std::vector<size_t> rk, pk; // Reactant and product stoichiometric coefficients, such that rstoich[i] is // the coefficient for species rk[i] vector_fp rstoich, pstoich; for (const auto& sp : r->reactants) { size_t k = kineticsSpeciesIndex(sp.first); rk.push_back(k); rstoich.push_back(sp.second); } for (const auto& sp : r->products) { size_t k = kineticsSpeciesIndex(sp.first); pk.push_back(k); pstoich.push_back(sp.second); } // The default order for each reactant is its stoichiometric coefficient, // which can be overridden by entries in the Reaction.orders map. rorder[i] // is the order for species rk[i]. vector_fp rorder = rstoich; for (const auto& sp : r->orders) { size_t k = kineticsSpeciesIndex(sp.first); // Find the index of species k within rk auto rloc = std::find(rk.begin(), rk.end(), k); if (rloc != rk.end()) { rorder[rloc - rk.begin()] = sp.second; } else { // If the reaction order involves a non-reactant species, add an // extra term to the reactants with zero stoichiometry so that the // stoichiometry manager can be used to compute the global forward // reaction rate. rk.push_back(k); rstoich.push_back(0.0); rorder.push_back(sp.second); } } m_reactantStoich.add(irxn, rk, rorder, rstoich); // product orders = product stoichiometric coefficients if (r->reversible) { m_revProductStoich.add(irxn, pk, pstoich, pstoich); } else { m_irrevProductStoich.add(irxn, pk, pstoich, pstoich); } m_reactions.push_back(r); m_rfn.push_back(0.0); m_rkcn.push_back(0.0); m_ropf.push_back(0.0); m_ropr.push_back(0.0); m_ropnet.push_back(0.0); m_perturb.push_back(1.0); return true; }
std::pair<size_t, size_t> Kinetics::checkDuplicates(bool throw_err) const { //! Map of (key indicating participating species) to reaction numbers std::map<size_t, std::vector<size_t> > participants; std::vector<std::map<int, double> > net_stoich; for (size_t i = 0; i < m_reactions.size(); i++) { // Get data about this reaction unsigned long int key = 0; Reaction& R = *m_reactions[i]; net_stoich.emplace_back(); std::map<int, double>& net = net_stoich.back(); for (const auto& sp : R.reactants) { int k = static_cast<int>(kineticsSpeciesIndex(sp.first)); key += k*(k+1); net[-1 -k] -= sp.second; } for (const auto& sp : R.products) { int k = static_cast<int>(kineticsSpeciesIndex(sp.first)); key += k*(k+1); net[1+k] += sp.second; } // Compare this reaction to others with similar participants vector<size_t>& related = participants[key]; for (size_t m = 0; m < related.size(); m++) { Reaction& other = *m_reactions[related[m]]; if (R.reaction_type != other.reaction_type) { continue; // different reaction types } else if (R.duplicate && other.duplicate) { continue; // marked duplicates } doublereal c = checkDuplicateStoich(net_stoich[i], net_stoich[m]); if (c == 0) { continue; // stoichiometries differ (not by a multiple) } else if (c < 0.0 && !R.reversible && !other.reversible) { continue; // irreversible reactions in opposite directions } else if (R.reaction_type == FALLOFF_RXN || R.reaction_type == CHEMACT_RXN) { ThirdBody& tb1 = dynamic_cast<FalloffReaction&>(R).third_body; ThirdBody& tb2 = dynamic_cast<FalloffReaction&>(other).third_body; bool thirdBodyOk = true; for (size_t k = 0; k < nTotalSpecies(); k++) { string s = kineticsSpeciesName(k); if (tb1.efficiency(s) * tb2.efficiency(s) != 0.0) { // non-zero third body efficiencies for species `s` in // both reactions thirdBodyOk = false; break; } } if (thirdBodyOk) { continue; // No overlap in third body efficiencies } } else if (R.reaction_type == THREE_BODY_RXN) { ThirdBody& tb1 = dynamic_cast<ThreeBodyReaction&>(R).third_body; ThirdBody& tb2 = dynamic_cast<ThreeBodyReaction&>(other).third_body; bool thirdBodyOk = true; for (size_t k = 0; k < nTotalSpecies(); k++) { string s = kineticsSpeciesName(k); if (tb1.efficiency(s) * tb2.efficiency(s) != 0.0) { // non-zero third body efficiencies for species `s` in // both reactions thirdBodyOk = false; break; } } if (thirdBodyOk) { continue; // No overlap in third body efficiencies } } if (throw_err) { throw CanteraError("installReaction", "Undeclared duplicate reactions detected:\n" "Reaction {}: {}\nReaction {}: {}\n", i+1, other.equation(), m+1, R.equation()); } else { return {i,m}; } } participants[key].push_back(i); } return {npos, npos}; }