void InterfaceKinetics::checkPartialEquil() { int i, irxn; vector_fp dmu(nTotalSpecies(), 0.0); vector_fp rmu(nReactions(), 0.0); vector_fp frop(nReactions(), 0.0); vector_fp rrop(nReactions(), 0.0); vector_fp netrop(nReactions(), 0.0); if (m_nrev > 0) { doublereal rt = GasConstant*thermo(0).temperature(); cout << "T = " << thermo(0).temperature() << " " << rt << endl; int n, nsp, k, ik=0; //doublereal rt = GasConstant*thermo(0).temperature(); // doublereal rrt = 1.0/rt; int np = nPhases(); doublereal delta; for (n = 0; n < np; n++) { thermo(n).getChemPotentials(DATA_PTR(dmu) + m_start[n]); nsp = thermo(n).nSpecies(); for (k = 0; k < nsp; k++) { delta = Faraday * m_phi[n] * thermo(n).charge(k); //cout << thermo(n).speciesName(k) << " " << (delta+dmu[ik])/rt << " " << dmu[ik]/rt << endl; dmu[ik] += delta; ik++; } } // compute Delta mu^ for all reversible reactions m_rxnstoich.getRevReactionDelta(m_ii, DATA_PTR(dmu), DATA_PTR(rmu)); getFwdRatesOfProgress(DATA_PTR(frop)); getRevRatesOfProgress(DATA_PTR(rrop)); getNetRatesOfProgress(DATA_PTR(netrop)); for (i = 0; i < m_nrev; i++) { irxn = m_revindex[i]; cout << "Reaction " << reactionString(irxn) << " " << rmu[irxn]/rt << endl; printf("%12.6e %12.6e %12.6e %12.6e \n", frop[irxn], rrop[irxn], netrop[irxn], netrop[irxn]/(frop[irxn] + rrop[irxn])); } } }
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}; }