/* * Add a phase to the kinetics manager object. This must * be done before the function init() is called or * before any reactions are input. * The following fields are updated: * m_start -> vector of integers, containing the * starting position of the species for * each phase in the kinetics mechanism. * m_surfphase -> index of the surface phase. * m_thermo -> vector of pointers to ThermoPhase phases * that participate in the kinetics * mechanism. * m_phaseindex -> map containing the string id of each * ThermoPhase phase as a key and the * index of the phase within the kinetics * manager object as the value. */ void Kinetics::addPhase(thermo_t& thermo) { // if not the first thermo object, set the start position // to that of the last object added + the number of its species if (m_thermo.size() > 0) { m_start.push_back(m_start.back() + m_thermo.back()->nSpecies()); } // otherwise start at 0 else { m_start.push_back(0); } // the phase with lowest dimensionality is assumed to be the // phase/interface at which reactions take place if (thermo.nDim() <= m_mindim) { m_mindim = thermo.nDim(); m_rxnphase = nPhases(); } // there should only be one surface phase int ptype = -100; if (type() == cEdgeKinetics) ptype = cEdge; else if (type() == cInterfaceKinetics) ptype = cSurf; if (thermo.eosType() == ptype) { // if (m_surfphase >= 0) { // throw CanteraError("Kinetics::addPhase", // "cannot add more than one surface phase"); // } m_surfphase = nPhases(); m_rxnphase = nPhases(); } m_thermo.push_back(&thermo); m_phaseindex[m_thermo.back()->id()] = nPhases(); }
/** * Get the equilibrium constants of all reactions, whether * reversible or not. */ void InterfaceKinetics::getEquilibriumConstants(doublereal* kc) { int i; int n, nsp, k, ik=0; doublereal rt = GasConstant*thermo(0).temperature(); doublereal rrt = 1.0/rt; int np = nPhases(); for (n = 0; n < np; n++) { thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]); nsp = thermo(n).nSpecies(); for (k = 0; k < nsp; k++) { m_mu0[ik] -= rt*thermo(n).logStandardConc(k); m_mu0[ik] += Faraday * m_phi[n] * thermo(n).charge(k); ik++; } } fill(kc, kc + m_ii, 0.0); m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_mu0), kc); for (i = 0; i < m_ii; i++) { kc[i] = exp(-kc[i]*rrt); } }
void InterfaceKinetics::getExchangeCurrentQuantities() { /* * Combine vectors of the standard Gibbs free energies of the * species and the standard concentrations to get change in * standard chemical potential for reaction. * Outputs: * - m_deltaG0 -- stores standard state chemical potentials * - m_ProdStanConcReac -- stores products of standard concentrations */ int ik = 0; int np = nPhases(); for (int n = 0; n < np; n++) { thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]); int nsp = thermo(n).nSpecies(); for (int k = 0; k < nsp; k++) { m_StandardConc[ik] = thermo(n).standardConcentration(k); ik++; } } // m_deltaG0 will be used to pass electrochemical potentials m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_mu0), DATA_PTR(m_deltaG0)); for (int i = 0; i < m_ii; i++) { m_ProdStanConcReac[i] = 1.0; } m_rxnstoich.multiplyReactants(DATA_PTR(m_StandardConc), DATA_PTR(m_ProdStanConcReac)); }
void Kinetics::finalize() { m_kk = 0; for (size_t n = 0; n < nPhases(); n++) { size_t nsp = m_thermo[n]->nSpecies(); m_kk += nsp; } }
void Kinetics::finalize() { m_nTotalSpecies = 0; int np = nPhases(); for (int n = 0; n < np; n++) { int nsp = m_thermo[n]->nSpecies(); m_nTotalSpecies += nsp; } }
//==================================================================================================================== void InterfaceKinetics::_update_rates_phi() { int np = nPhases(); for (int n = 0; n < np; n++) { if (thermo(n).electricPotential() != m_phi[n]) { m_phi[n] = thermo(n).electricPotential(); m_redo_rates = true; } } }
void Kinetics::resizeSpecies() { m_kk = 0; m_start.resize(nPhases()); for (size_t i = 0; i < m_thermo.size(); i++) { m_start[i] = m_kk; // global index of first species of phase i m_kk += m_thermo[i]->nSpecies(); } invalidateCache(); }
/** * For reactions that transfer charge across a potential difference, * the activation energies are modified by the potential difference. * (see, for example, ...). This method applies this correction. */ void InterfaceKinetics::applyButlerVolmerCorrection(doublereal* kf) { int i; int n, nsp, k, ik=0; doublereal rt = GasConstant*thermo(0).temperature(); doublereal rrt = 1.0/rt; int np = nPhases(); // compute the electrical potential energy of each species for (n = 0; n < np; n++) { nsp = thermo(n).nSpecies(); for (k = 0; k < nsp; k++) { m_pot[ik] = Faraday*thermo(n).charge(k)*m_phi[n]; ik++; } } // Compute the change in electrical potential energy for each // reaction. This will only be non-zero if a potential // difference is present. m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_pot), DATA_PTR(m_rwork)); // Modify the reaction rates. Only modify those with a // non-zero activation energy, and do not decrease the // activation energy below zero. doublereal eamod; #ifdef DEBUG_MODE double ea; #endif int nct = m_beta.size(); int irxn; for (i = 0; i < nct; i++) { irxn = m_ctrxn[i]; eamod = m_beta[i]*m_rwork[irxn]; if (eamod != 0.0 && m_E[irxn] != 0.0) { #ifdef DEBUG_MODE ea = GasConstant * m_E[irxn]; if (eamod + ea < 0.0) { writelog("Warning: act energy mod too large!\n"); writelog(" Delta phi = "+fp2str(m_rwork[irxn]/Faraday)+"\n"); writelog(" Delta Ea = "+fp2str(eamod)+"\n"); writelog(" Ea = "+fp2str(ea)+"\n"); for (n = 0; n < np; n++) { writelog("Phase "+int2str(n)+": phi = " +fp2str(m_phi[n])+"\n"); } } #endif kf[irxn] *= exp(-eamod*rrt); } } }
/** * Add a single reaction to the mechanism. This routine * must be called after init() and before finalize(). * This function branches on the types of reactions allowed * by the interfaceKinetics manager in order to install * the reaction correctly in the manager. * The manager allows the following reaction types * Elementary * Surface * Global * There is no difference between elementary and surface * reactions. */ void InterfaceKinetics::addReaction(const ReactionData& r) { /* * Install the rate coefficient for the current reaction * in the appropriate data structure. */ addElementaryReaction(r); /* * Add the reactants and products for m_ropnet;the current reaction * to the various stoichiometric coefficient arrays. */ installReagents(r); /* * Save the reaction and product groups, which are * part of the ReactionData class, in this class. * They aren't used for anything but reaction path * analysis. */ //installGroups(reactionNumber(), r.rgroups, r.pgroups); /* * Increase the internal number of reactions, m_ii, by one. * increase the size of m_perturb by one as well. */ incrementRxnCount(); m_rxneqn.push_back(r.equation); m_rxnPhaseIsReactant.resize(m_ii, 0); m_rxnPhaseIsProduct.resize(m_ii, 0); int np = nPhases(); int i = m_ii -1; m_rxnPhaseIsReactant[i] = new bool[np]; m_rxnPhaseIsProduct[i] = new bool[np]; for (int p = 0; p < np; p++) { m_rxnPhaseIsReactant[i][p] = false; m_rxnPhaseIsProduct[i][p] = false; } const vector_int& vr = reactants(i); for (int ik = 0; ik < (int) vr.size(); ik++) { int k = vr[ik]; int p = speciesPhaseIndex(k); m_rxnPhaseIsReactant[i][p] = true; } const vector_int& vp = products(i); for (int ik = 0; ik < (int) vp.size(); ik++) { int k = vp[ik]; int p = speciesPhaseIndex(k); m_rxnPhaseIsProduct[i][p] = true; } }
/** * Takes as input an array of properties for all species in the * mechanism and copies those values beloning to a particular * phase to the output array. * @param data Input data array. * @param phase Pointer to one of the phase objects participating * in this reaction mechanism * @param phase_data Output array where the values for the the * specified phase are to be written. */ void Kinetics::selectPhase(const doublereal* data, const thermo_t* phase, doublereal* phase_data) { int n, nsp, np = nPhases(); for (n = 0; n < np; n++) { if (phase == m_thermo[n]) { nsp = phase->nSpecies(); copy(data + m_start[n], data + m_start[n] + nsp, phase_data); return; } } throw CanteraError("Kinetics::selectPhase", "Phase not found."); }
/** * Prepare the class for the addition of reactions. This function * must be called after instantiation of the class, but before * any reactions are actually added to the mechanism. * This function calculates m_kk the number of species in all * phases participating in the reaction mechanism. We don't know * m_kk previously, before all phases have been added. */ void InterfaceKinetics::init() { int n; m_kk = 0; int np = nPhases(); for (n = 0; n < np; n++) { m_kk += thermo(n).nSpecies(); } m_rrxn.resize(m_kk); m_prxn.resize(m_kk); m_conc.resize(m_kk); m_mu0.resize(m_kk); m_grt.resize(m_kk); m_pot.resize(m_kk, 0.0); m_phi.resize(np, 0.0); }
void Kinetics::addPhase(thermo_t& thermo) { // the phase with lowest dimensionality is assumed to be the // phase/interface at which reactions take place if (thermo.nDim() <= m_mindim) { m_mindim = thermo.nDim(); m_rxnphase = nPhases(); } // there should only be one surface phase int ptype = -100; if (type() == cEdgeKinetics) { ptype = cEdge; } else if (type() == cInterfaceKinetics) { ptype = cSurf; } if (thermo.eosType() == ptype) { m_surfphase = nPhases(); m_rxnphase = nPhases(); } m_thermo.push_back(&thermo); m_phaseindex[m_thermo.back()->id()] = nPhases(); resizeSpecies(); }
/* * These values depend upon the concentration * of the solution. * * units = J kmol-1 Kelvin-1 * * @param deltaS vector of Enthalpy changes * Length = m_ii, number of reactions * */ void InterfaceKinetics::getDeltaEntropy(doublereal* deltaS) { /* * Get the partial molar entropy of all species in all of * the phases */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getPartialMolarEntropies(DATA_PTR(m_grt) + m_start[n]); } /* * Use the stoichiometric manager to find deltaS for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaS); }
/* * These values depend upon the concentration of the solution and * the voltage of the phases * * units = J kmol-1 * * @param deltaM Output vector of deltaM's for reactions * Length: m_ii. */ void InterfaceKinetics::getDeltaElectrochemPotentials(doublereal* deltaM) { /* * Get the chemical potentials of the species in the * ideal gas solution. */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getElectrochemPotentials(DATA_PTR(m_grt) + m_start[n]); } /* * Use the stoichiometric manager to find deltaG for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaM); }
/** * Update properties that depend on concentrations. This method * fills out the array of generalized concentrations by calling * method getActivityConcentrations for each phase, which classes * representing phases should overload to return the appropriate * quantities. */ void InterfaceKinetics::_update_rates_C() { int n; int np = nPhases(); for (n = 0; n < np; n++) { /* * We call the getActivityConcentrations function of each * ThermoPhase class that makes up this kinetics object to * obtain the generalized concentrations for species within that * class. This is collected in the vector m_conc. m_start[] * are integer indecises for that vector denoting the start of the * species for each phase. */ thermo(n).getActivityConcentrations(DATA_PTR(m_conc) + m_start[n]); } m_kdata->m_ROP_ok = false; }
/** * * getDeltaSSGibbs(): * * Return the vector of values for the reaction * standard state gibbs free energy change. * These values don't depend upon the concentration * of the solution. * * units = J kmol-1 */ void InterfaceKinetics::getDeltaSSGibbs(doublereal* deltaG) { /* * Get the standard state chemical potentials of the species. * This is the array of chemical potentials at unit activity * We define these here as the chemical potentials of the pure * species at the temperature and pressure of the solution. */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getStandardChemPotentials(DATA_PTR(m_grt) + m_start[n]); } /* * Use the stoichiometric manager to find deltaG for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaG); }
/** * Update the equilibrium constants in molar units for all * reversible reactions. Irreversible reactions have their * equilibrium constant set to zero. * For reactions involving charged species the equilibrium * constant is adjusted according to the electrostatis potential. */ void InterfaceKinetics::updateKc() { int i, irxn; vector_fp& m_rkc = m_kdata->m_rkcn; fill(m_rkc.begin(), m_rkc.end(), 0.0); //static vector_fp mu(nTotalSpecies()); if (m_nrev > 0) { /* * Get the vector of electrochemical potentials and store it in m_mu0 */ int n, nsp, k, ik = 0; doublereal rt = GasConstant*thermo(0).temperature(); doublereal rrt = 1.0 / rt; int np = nPhases(); for (n = 0; n < np; n++) { thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]); nsp = thermo(n).nSpecies(); for (k = 0; k < nsp; k++) { m_mu0[ik] -= rt * thermo(n).logStandardConc(k); m_mu0[ik] += Faraday * m_phi[n] * thermo(n).charge(k); ik++; } } // compute Delta mu^0 for all reversible reactions m_rxnstoich.getRevReactionDelta(m_ii, DATA_PTR(m_mu0), DATA_PTR(m_rkc)); for (i = 0; i < m_nrev; i++) { irxn = m_revindex[i]; if (irxn < 0 || irxn >= nReactions()) { throw CanteraError("InterfaceKinetics", "illegal value: irxn = "+int2str(irxn)); } m_rkc[irxn] = exp(m_rkc[irxn]*rrt); } for (i = 0; i != m_nirrev; ++i) { m_rkc[ m_irrev[i] ] = 0.0; } } }
/** * * getDeltaGibbs(): * * Return the vector of values for the reaction gibbs free energy * change * These values depend upon the concentration * of the ideal gas. * * units = J kmol-1 */ void InterfaceKinetics::getDeltaGibbs(doublereal* deltaG) { /* * Get the chemical potentials of the species in the * ideal gas solution. */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getChemPotentials(DATA_PTR(m_grt) + m_start[n]); } //for (n = 0; n < m_grt.size(); n++) { // cout << n << "G_RT = " << m_grt[n] << endl; //} /* * Use the stoichiometric manager to find deltaG for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaG); }
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])); } } }
/********************************************************************* * * getDeltaSSEntropy(): * * Return the vector of values for the change in the * standard state entropies for each reaction. * These values don't depend upon the concentration * of the solution. * * units = J kmol-1 Kelvin-1 */ void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS) { /* * Get the standard state entropy of the species. * We define these here as the entropies of the pure * species at the temperature and pressure of the solution. */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getEntropy_R(DATA_PTR(m_grt) + m_start[n]); } doublereal R = GasConstant; for (int k = 0; k < m_kk; k++) { m_grt[k] *= R; } /* * Use the stoichiometric manager to find deltaS for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaS); }
/** * * getDeltaSSEnthalpy(): * * Return the vector of values for the change in the * standard state enthalpies of reaction. * These values don't depend upon the concentration * of the solution. * * units = J kmol-1 */ void InterfaceKinetics::getDeltaSSEnthalpy(doublereal* deltaH) { /* * Get the standard state enthalpies of the species. * This is the array of chemical potentials at unit activity * We define these here as the enthalpies of the pure * species at the temperature and pressure of the solution. */ int np = nPhases(); int n; for (n = 0; n < np; n++) { thermo(n).getEnthalpy_RT(DATA_PTR(m_grt) + m_start[n]); } doublereal RT = thermo().temperature() * GasConstant; for (int k = 0; k < m_kk; k++) { m_grt[k] *= RT; } /* * Use the stoichiometric manager to find deltaG for each * reaction. */ m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaH); }
/* * This is NOT a virtual function. * * @param right Reference to %Kinetics object to be copied into the * current one. */ InterfaceKinetics& InterfaceKinetics:: operator=(const InterfaceKinetics &right) { int i; /* * Check for self assignment. */ if (this == &right) return *this; for (i = 0; i < m_ii; i++) { delete [] m_rxnPhaseIsReactant[i]; delete [] m_rxnPhaseIsProduct[i]; } Kinetics::operator=(right); m_grt = right.m_grt; m_kk = right.m_kk; m_revindex = right.m_revindex; m_rates = right.m_rates; m_redo_rates = right.m_redo_rates; m_index = right.m_index; m_irrev = right.m_irrev; m_rxnstoich = right.m_rxnstoich; m_nirrev = right.m_nirrev; m_nrev = right.m_nrev; m_rrxn = right.m_rrxn; m_prxn = right.m_prxn; m_rxneqn = right.m_rxneqn; *m_kdata = *right.m_kdata; m_conc = right.m_conc; m_mu0 = right.m_mu0; m_phi = right.m_phi; m_pot = right.m_pot; m_rwork = right.m_rwork; m_E = right.m_E; m_surf = right.m_surf; //DANGER - shallow copy m_integrator = right.m_integrator; //DANGER - shallow copy m_beta = right.m_beta; m_ctrxn = right.m_ctrxn; m_ctrxn_ecdf = right.m_ctrxn_ecdf; m_StandardConc = right.m_StandardConc; m_deltaG0 = right.m_deltaG0; m_ProdStanConcReac = right.m_ProdStanConcReac; m_finalized = right.m_finalized; m_has_coverage_dependence = right.m_has_coverage_dependence; m_has_electrochem_rxns = right.m_has_electrochem_rxns; m_has_exchange_current_density_formulation = right.m_has_exchange_current_density_formulation; m_phaseExistsCheck = right.m_phaseExistsCheck; m_phaseExists = right.m_phaseExists; m_phaseIsStable = right.m_phaseIsStable; m_rxnPhaseIsReactant.resize(m_ii, 0); m_rxnPhaseIsProduct.resize(m_ii, 0); int np = nPhases(); for (i = 0; i < m_ii; i++) { m_rxnPhaseIsReactant[i] = new bool[np]; m_rxnPhaseIsProduct[i] = new bool[np]; for (int p = 0; p < np; p++) { m_rxnPhaseIsReactant[i][p] = right.m_rxnPhaseIsReactant[i][p]; m_rxnPhaseIsProduct[i][p] = right.m_rxnPhaseIsProduct[i][p]; } } m_ioFlag = right.m_ioFlag; return *this; }
/* * For reactions that transfer charge across a potential difference, * the activation energies are modified by the potential difference. * (see, for example, ...). This method applies this correction. * * @param kf Vector of forward reaction rate constants on which to have * the correction applied */ void InterfaceKinetics::applyButlerVolmerCorrection(doublereal* const kf) { int i; int n, nsp, k, ik=0; doublereal rt = GasConstant*thermo(0).temperature(); doublereal rrt = 1.0/rt; int np = nPhases(); // compute the electrical potential energy of each species for (n = 0; n < np; n++) { nsp = thermo(n).nSpecies(); for (k = 0; k < nsp; k++) { m_pot[ik] = Faraday*thermo(n).charge(k)*m_phi[n]; ik++; } } // Compute the change in electrical potential energy for each // reaction. This will only be non-zero if a potential // difference is present. m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_pot), DATA_PTR(m_rwork)); // Modify the reaction rates. Only modify those with a // non-zero activation energy. Below we decrease the // activation energy below zero but in some debug modes // we print out a warning message about this. /* * NOTE, there is some discussion about this point. * Should we decrease the activiation energy below zero? * I don't think this has been decided in any definative way. * The treatment below is numerically more stable, however. */ doublereal eamod; doublereal ecoeff; #ifdef DEBUG_KIN_MODE doublereal ea; #endif int nct = m_beta.size(); int irxn; for (i = 0; i < nct; i++) { irxn = m_ctrxn[i]; eamod = m_beta[i]*m_rwork[irxn]; // if (eamod != 0.0 && m_E[irxn] != 0.0) { if (eamod != 0.0) { #ifdef DEBUG_KIN_MODE ea = GasConstant * m_E[irxn]; if (eamod + ea < 0.0) { writelog("Warning: act energy mod too large!\n"); writelog(" Delta phi = "+fp2str(m_rwork[irxn]/Faraday)+"\n"); writelog(" Delta Ea = "+fp2str(eamod)+"\n"); writelog(" Ea = "+fp2str(ea)+"\n"); for (n = 0; n < np; n++) { writelog("Phase "+int2str(n)+": phi = " +fp2str(m_phi[n])+"\n"); } } #endif /* * Commonly, during electrochemistry problems the voltage may get out of sorts. * Here, we seek to avoid producing inf results within Cantera by tempering the * resulting rates of progress to ~10^150 or so. The ln calculation produces a * small gradient pointing in the correct direction. * (this would be a good place to pop a warning flag) */ ecoeff = -eamod*rrt; if (ecoeff > 345.) { ecoeff = 339.1565 + log(ecoeff); } else if (ecoeff < -345.) { ecoeff = -339.1565 - log(-ecoeff); } kf[irxn] *= exp(ecoeff); } } }
/** * Update the rates of progress of the reactions in the reaction * mechanism. This routine operates on internal data. */ void InterfaceKinetics::updateROP() { _update_rates_T(); _update_rates_C(); if (m_kdata->m_ROP_ok) return; const vector_fp& rf = m_kdata->m_rfn; const vector_fp& m_rkc = m_kdata->m_rkcn; array_fp& ropf = m_kdata->m_ropf; array_fp& ropr = m_kdata->m_ropr; array_fp& ropnet = m_kdata->m_ropnet; // copy rate coefficients into ropf copy(rf.begin(), rf.end(), ropf.begin()); // multiply by perturbation factor multiply_each(ropf.begin(), ropf.end(), m_perturb.begin()); // copy the forward rates to the reverse rates copy(ropf.begin(), ropf.end(), ropr.begin()); // for reverse rates computed from thermochemistry, multiply // the forward rates copied into m_ropr by the reciprocals of // the equilibrium constants multiply_each(ropr.begin(), ropr.end(), m_rkc.begin()); // multiply ropf by concentration products m_rxnstoich.multiplyReactants(DATA_PTR(m_conc), DATA_PTR(ropf)); //m_reactantStoich.multiply(m_conc.begin(), ropf.begin()); // for reversible reactions, multiply ropr by concentration // products m_rxnstoich.multiplyRevProducts(DATA_PTR(m_conc), DATA_PTR(ropr)); //m_revProductStoich.multiply(m_conc.begin(), ropr.begin()); // do global reactions //m_globalReactantStoich.power(m_conc.begin(), ropf.begin()); for (int j = 0; j != m_ii; ++j) { ropnet[j] = ropf[j] - ropr[j]; } /* * For reactions involving multiple phases, we must check that the phase * being consumed actually exists. This is particularly important for * phases that are stoichiometric phases containing one species with a unity activity */ if (m_phaseExistsCheck) { for (int j = 0; j != m_ii; ++j) { if ((ropr[j] > ropf[j]) && (ropr[j] > 0.0)) { for (int p = 0; p < nPhases(); p++) { if (m_rxnPhaseIsProduct[j][p]) { if (! m_phaseExists[p]) { ropnet[j] = 0.0; ropr[j] = ropf[j]; if (ropf[j] > 0.0) { for (int rp = 0; rp < nPhases(); rp++) { if (m_rxnPhaseIsReactant[j][rp]) { if (! m_phaseExists[rp]) { ropnet[j] = 0.0; ropr[j] = ropf[j] = 0.0;; } } } } } } if (m_rxnPhaseIsReactant[j][p]) { if (! m_phaseIsStable[p]) { ropnet[j] = 0.0; ropr[j] = ropf[j]; } } } } else if ((ropf[j] > ropr[j]) && (ropf[j] > 0.0)) { for (int p = 0; p < nPhases(); p++) { if (m_rxnPhaseIsReactant[j][p]) { if (! m_phaseExists[p]) { ropnet[j] = 0.0; ropf[j] = ropr[j]; if (ropf[j] > 0.0) { for (int rp = 0; rp < nPhases(); rp++) { if (m_rxnPhaseIsProduct[j][rp]) { if (! m_phaseExists[rp]) { ropnet[j] = 0.0; ropf[j] = ropr[j] = 0.0; } } } } } } if (m_rxnPhaseIsProduct[j][p]) { if (! m_phaseIsStable[p]) { ropnet[j] = 0.0; ropf[j] = ropr[j]; } } } } } } m_kdata->m_ROP_ok = true; }
void Kinetics::checkPhaseIndex(size_t m) const { if (m >= nPhases()) { throw IndexError("checkPhaseIndex", "phase", m, nPhases()-1); } }
void Kinetics::checkPhaseArraySize(size_t mm) const { if (nPhases() > mm) { throw ArraySizeError("checkPhaseArraySize", mm, nPhases()); } }