status_t DLL_EXPORT kin_getdestructionrates_(const integer* n, doublereal* ddot) { try { Kinetics* k = _fkin(n); k->getDestructionRates(ddot); return 0; } catch (CanteraError) {handleError(); return -1;} }
status_t DLL_EXPORT kin_getfwdratesofprogress_(const integer* n, doublereal* fwdROP) { Kinetics* k = _fkin(n); try { k->getFwdRatesOfProgress(fwdROP); return 0; } catch (CanteraError) {handleError(); return -1;} }
status_t DLL_EXPORT kin_getnetratesofprogress_(const integer* n, doublereal* netROP) { try { Kinetics* k = _fkin(n); k->getNetRatesOfProgress(netROP); return 0; } catch (CanteraError) {handleError(); return -1;} }
status_t kin_getnetratesofprogress_(const integer* n, doublereal* netROP) { try { Kinetics* k = _fkin(n); k->getNetRatesOfProgress(netROP); } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t kin_getdestructionrates_(const integer* n, doublereal* ddot) { try { Kinetics* k = _fkin(n); k->getDestructionRates(ddot); } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t kin_getnetproductionrates_(const integer* n, doublereal* wdot) { try { Kinetics* k = _fkin(n); k->getNetProductionRates(wdot); } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t kin_getequilibriumconstants_(const integer* n, doublereal* kc) { try { Kinetics* k = _fkin(n); k->getEquilibriumConstants(kc); } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t DLL_EXPORT kin_getreactionstring_(const integer* n, integer* i, char* buf, ftnlen lenbuf) { try { Kinetics* k = _fkin(n); std::string r = k->reactionString(*i-1); int lout = min(lenbuf,r.size()); std::copy(r.c_str(), r.c_str() + lout, buf); for (int nn = lout; nn < lenbuf; nn++) buf[nn] = ' '; return 0; } catch (CanteraError) {handleError(); return -1;} }
status_t DLL_EXPORT kin_advancecoverages_(const integer* n, doublereal* tstep) { try { Kinetics* k = _fkin(n); if (k->type() == cInterfaceKinetics) { ((InterfaceKinetics*)k)->advanceCoverages(*tstep); } else { throw CanteraError("kin_advanceCoverages", "wrong kinetics manager type"); } return 0; } catch (CanteraError) {handleError(); return -1;} }
status_t kin_advancecoverages_(const integer* n, doublereal* tstep) { try { Kinetics* k = _fkin(n); if (k->type() == cInterfaceKinetics) { ((InterfaceKinetics*)k)->advanceCoverages(*tstep); } else { throw CanteraError("kin_advanceCoverages", "wrong kinetics manager type"); } } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t kin_getreactionstring_(const integer* n, integer* i, char* buf, ftnlen lenbuf) { try { Kinetics* k = _fkin(n); std::string r = k->reactionString(*i-1); int lout = std::min(lenbuf, (int) r.size()); std::copy(r.c_str(), r.c_str() + lout, buf); for (int nn = lout; nn < lenbuf; nn++) { buf[nn] = ' '; } } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
status_t ctbuildsolutionfromxml(char* src, integer* ixml, char* id, integer* ith, integer* ikin, ftnlen lensrc, ftnlen lenid) { try { XML_Node* root = 0; if (*ixml > 0) { root = _xml(ixml); } thermo_t* t = _fth(ith); Kinetics* k = _fkin(ikin); XML_Node* x, *r=0; if (root) { r = &root->root(); } std::string srcS = f2string(src, lensrc); std::string idS = f2string(id, lenid); if (srcS != "") { x = get_XML_Node(srcS, r); } else { x = get_XML_Node(idS, r); } if (!x) { return 0; } importPhase(*x, t); k->addPhase(*t); k->init(); installReactionArrays(*x, *k, x->id()); t->setState_TP(300.0, OneAtm); if (r) { if (&x->root() != &r->root()) { delete &x->root(); } } else { delete &x->root(); } } catch (...) { return handleAllExceptions(-1, ERR); } return 0; }
double Reactor::evalSurfaces(double t, double* ydot) { const vector_fp& mw = m_thermo->molecularWeights(); fill(m_sdot.begin(), m_sdot.end(), 0.0); size_t loc = 0; // offset into ydot double mdot_surf = 0.0; // net mass flux from surface for (size_t i = 0; i < m_wall.size(); i++) { Kinetics* kin = m_wall[i]->kinetics(m_lr[i]); SurfPhase* surf = m_wall[i]->surface(m_lr[i]); if (surf && kin) { double rs0 = 1.0/surf->siteDensity(); size_t nk = surf->nSpecies(); double sum = 0.0; surf->setTemperature(m_state[0]); m_wall[i]->syncCoverages(m_lr[i]); kin->getNetProductionRates(&m_work[0]); size_t ns = kin->surfacePhaseIndex(); size_t surfloc = kin->kineticsSpeciesIndex(0,ns); for (size_t k = 1; k < nk; k++) { ydot[loc + k] = m_work[surfloc+k]*rs0*surf->size(k); sum -= ydot[loc + k]; } ydot[loc] = sum; loc += nk; double wallarea = m_wall[i]->area(); for (size_t k = 0; k < m_nsp; k++) { m_sdot[k] += m_work[k]*wallarea; mdot_surf += m_sdot[k] * mw[k]; } } } return mdot_surf; }
bool checkElectrochemReaction(const XML_Node& p, Kinetics& kin, const XML_Node& r) { // If other phases are involved in the reaction mechanism, they must be // listed in a 'phaseArray' child element. Homogeneous mechanisms do not // need to include a phaseArray element. vector<string> phase_ids; if (p.hasChild("phaseArray")) { const XML_Node& pa = p.child("phaseArray"); getStringArray(pa, phase_ids); } phase_ids.push_back(p["id"]); // Get reaction product and reactant information Composition reactants = parseCompString(r.child("reactants").value()); Composition products = parseCompString(r.child("products").value()); // If the reaction has undeclared species don't perform electrochemical check for (const auto& sp : reactants) { if (kin.kineticsSpeciesIndex(sp.first) == npos) { return true; } } for (const auto& sp : products) { if (kin.kineticsSpeciesIndex(sp.first) == npos) { return true; } } // Initialize the electron counter for each phase std::vector<double> e_counter(phase_ids.size(), 0.0); // Find the amount of electrons in the products for each phase for (const auto& sp : products) { const ThermoPhase& ph = kin.speciesPhase(sp.first); size_t k = ph.speciesIndex(sp.first); double stoich = sp.second; for (size_t m = 0; m < phase_ids.size(); m++) { if (phase_ids[m] == ph.id()) { e_counter[m] += stoich * ph.charge(k); break; } } } // Subtract the amount of electrons in the reactants for each phase for (const auto& sp : reactants) { const ThermoPhase& ph = kin.speciesPhase(sp.first); size_t k = ph.speciesIndex(sp.first); double stoich = sp.second; for (size_t m = 0; m < phase_ids.size(); m++) { if (phase_ids[m] == ph.id()) { e_counter[m] -= stoich * ph.charge(k); break; } } } // If the electrons change phases then the reaction is electrochemical bool echemical = false; for(size_t m = 0; m < phase_ids.size(); m++) { if (fabs(e_counter[m]) > 1e-4) { echemical = true; break; } } // If the reaction is electrochemical, ensure the reaction is identified as // electrochemical. If not already specified beta is assumed to be 0.5 std::string type = ba::to_lower_copy(r["type"]); if (!r.child("rateCoeff").hasChild("electrochem")) { if ((type != "butlervolmer_noactivitycoeffs" && type != "butlervolmer" && type != "surfaceaffinity") && echemical) { XML_Node& f = r.child("rateCoeff").addChild("electrochem",""); f.addAttribute("beta",0.5); } } return true; }
void IdealGasConstPressureReactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { size_t nk; m_thermo->restoreState(m_state); Kinetics* kin; size_t npar, ploc; double mult; // process sensitivity parameters if (params) { npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult*params[n]); } ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->setSensitivityParameters(m_lr[m], params + ploc); ploc += m_nsens_wall[m]; } } } m_Q = 0.0; // compute wall terms doublereal rs0, sum, wallarea; double mcpdTdt = 0.0; // m * c_p * dT/dt double dmdt = 0.0; // dm/dt (gas phase) double* dYdt = ydot + 2; m_thermo->getPartialMolarEnthalpies(&m_hk[0]); SurfPhase* surf; size_t lr, ns, loc = m_nsp+2, surfloc; fill(m_sdot.begin(), m_sdot.end(), 0.0); for (size_t i = 0; i < m_nwalls; i++) { lr = 1 - 2*m_lr[i]; m_Q += lr*m_wall[i]->Q(time); kin = m_wall[i]->kinetics(m_lr[i]); surf = m_wall[i]->surface(m_lr[i]); if (surf && kin) { rs0 = 1.0/surf->siteDensity(); nk = surf->nSpecies(); sum = 0.0; surf->setTemperature(m_state[0]); m_wall[i]->syncCoverages(m_lr[i]); kin->getNetProductionRates(DATA_PTR(m_work)); ns = kin->surfacePhaseIndex(); surfloc = kin->kineticsSpeciesIndex(0,ns); for (size_t k = 1; k < nk; k++) { ydot[loc + k] = m_work[surfloc+k]*rs0*surf->size(k); sum -= ydot[loc + k]; } ydot[loc] = sum; loc += nk; wallarea = m_wall[i]->area(); for (size_t k = 0; k < m_nsp; k++) { m_sdot[k] += m_work[k]*wallarea; } } } const vector_fp& mw = m_thermo->molecularWeights(); const doublereal* Y = m_thermo->massFractions(); if (m_chem) { m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot" } double mdot_surf = 0.0; // net mass flux from surface for (size_t k = 0; k < m_nsp; k++) { // production in gas phase and from surfaces dYdt[k] = (m_wdot[k] * m_vol + m_sdot[k]) * mw[k] / m_mass; mdot_surf += m_sdot[k] * mw[k]; } dmdt += mdot_surf; // external heat transfer mcpdTdt -= m_Q; for (size_t n = 0; n < m_nsp; n++) { // heat release from gas phase and surface reations mcpdTdt -= m_wdot[n] * m_hk[n] * m_vol; mcpdTdt -= m_sdot[n] * m_hk[n]; // dilution by net surface mass flux dYdt[n] -= Y[n] * mdot_surf / m_mass; } // add terms for open system if (m_open) { // outlets for (size_t i = 0; i < m_nOutlets; i++) { dmdt -= m_outlet[i]->massFlowRate(time); // mass flow out of system } // inlets for (size_t i = 0; i < m_nInlets; i++) { double mdot_in = m_inlet[i]->massFlowRate(time); dmdt += mdot_in; // mass flow into system mcpdTdt += m_inlet[i]->enthalpy_mass() * mdot_in; for (size_t n = 0; n < m_nsp; n++) { double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n); // flow of species into system and dilution by other species dYdt[n] += (mdot_spec - mdot_in * Y[n]) / m_mass; mcpdTdt -= m_hk[n] / mw[n] * mdot_spec; } } } ydot[0] = dmdt; if (m_energy) { ydot[1] = mcpdTdt / (m_mass * m_thermo->cp_mass()); } else { ydot[1] = 0.0; } // reset sensitivity parameters if (params) { npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult/params[n]); } ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->resetSensitivityParameters(m_lr[m]); ploc += m_nsens_wall[m]; } } } }
void IdealGasReactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { m_thermo->restoreState(m_state); // process sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult*params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->setSensitivityParameters(m_lr[m], params + ploc); ploc += m_nsens_wall[m]; } } } m_vdot = 0.0; m_Q = 0.0; double mcvdTdt = 0.0; // m * c_v * dT/dt double dmdt = 0.0; // dm/dt (gas phase) double* dYdt = ydot + 3; m_thermo->getPartialMolarIntEnergies(&m_uk[0]); // compute wall terms size_t loc = m_nsp+3; fill(m_sdot.begin(), m_sdot.end(), 0.0); for (size_t i = 0; i < m_nwalls; i++) { int lr = 1 - 2*m_lr[i]; double vdot = lr*m_wall[i]->vdot(time); m_vdot += vdot; m_Q += lr*m_wall[i]->Q(time); Kinetics* kin = m_wall[i]->kinetics(m_lr[i]); SurfPhase* surf = m_wall[i]->surface(m_lr[i]); if (surf && kin) { double rs0 = 1.0/surf->siteDensity(); size_t nk = surf->nSpecies(); double sum = 0.0; surf->setTemperature(m_state[0]); m_wall[i]->syncCoverages(m_lr[i]); kin->getNetProductionRates(DATA_PTR(m_work)); size_t ns = kin->surfacePhaseIndex(); size_t surfloc = kin->kineticsSpeciesIndex(0,ns); for (size_t k = 1; k < nk; k++) { ydot[loc + k] = m_work[surfloc+k]*rs0*surf->size(k); sum -= ydot[loc + k]; } ydot[loc] = sum; loc += nk; double wallarea = m_wall[i]->area(); for (size_t k = 0; k < m_nsp; k++) { m_sdot[k] += m_work[k]*wallarea; } } } const vector_fp& mw = m_thermo->molecularWeights(); const doublereal* Y = m_thermo->massFractions(); if (m_chem) { m_kin->getNetProductionRates(&m_wdot[0]); // "omega dot" } double mdot_surf = 0.0; // net mass flux from surfaces for (size_t k = 0; k < m_nsp; k++) { // production in gas phase and from surfaces dYdt[k] = (m_wdot[k] * m_vol + m_sdot[k]) * mw[k] / m_mass; mdot_surf += m_sdot[k] * mw[k]; } dmdt += mdot_surf; // compression work and external heat transfer mcvdTdt += - m_pressure * m_vdot - m_Q; for (size_t n = 0; n < m_nsp; n++) { // heat release from gas phase and surface reations mcvdTdt -= m_wdot[n] * m_uk[n] * m_vol; mcvdTdt -= m_sdot[n] * m_uk[n]; // dilution by net surface mass flux dYdt[n] -= Y[n] * mdot_surf / m_mass; } // add terms for open system if (m_open) { // outlets for (size_t i = 0; i < m_nOutlets; i++) { double mdot_out = m_outlet[i]->massFlowRate(time); dmdt -= mdot_out; // mass flow out of system mcvdTdt -= mdot_out * m_pressure * m_vol / m_mass; // flow work } // inlets for (size_t i = 0; i < m_nInlets; i++) { double mdot_in = m_inlet[i]->massFlowRate(time); dmdt += mdot_in; // mass flow into system mcvdTdt += m_inlet[i]->enthalpy_mass() * mdot_in; for (size_t n = 0; n < m_nsp; n++) { double mdot_spec = m_inlet[i]->outletSpeciesMassFlowRate(n); // flow of species into system and dilution by other species dYdt[n] += (mdot_spec - mdot_in * Y[n]) / m_mass; // In combintion with h_in*mdot_in, flow work plus thermal // energy carried with the species mcvdTdt -= m_uk[n] / mw[n] * mdot_spec; } } } ydot[0] = dmdt; ydot[1] = m_vdot; if (m_energy) { ydot[2] = mcvdTdt / (m_mass * m_thermo->cv_mass()); } else { ydot[2] = 0; } for (size_t i = 0; i < m_nv; i++) { AssertFinite(ydot[i], "IdealGasReactor::evalEqs", "ydot[" + int2str(i) + "] is not finite"); } // reset sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult/params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->resetSensitivityParameters(m_lr[m]); ploc += m_nsens_wall[m]; } } } }
/* * This virtual routine can be used to duplicate %Kinetics objects * inherited from %Kinetics even if the application only has * a pointer to %Kinetics to work with. * * These routines are basically wrappers around the derived copy * constructor. */ Kinetics *Kinetics::duplMyselfAsKinetics(const std::vector<thermo_t*> & tpVector) const { Kinetics* ko = new Kinetics(*this); ko->assignShallowPointers(tpVector); return ko; }
/* * Called by the integrator to evaluate ydot given y at time 'time'. */ void Reactor::evalEqs(doublereal time, doublereal* y, doublereal* ydot, doublereal* params) { m_time = time; m_thermo->restoreState(m_state); // process sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult*params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->setSensitivityParameters(m_lr[m], params + ploc); ploc += m_nsens_wall[m]; } } } m_vdot = 0.0; m_Q = 0.0; // compute wall terms size_t loc = m_nsp+2; fill(m_sdot.begin(), m_sdot.end(), 0.0); for (size_t i = 0; i < m_nwalls; i++) { int lr = 1 - 2*m_lr[i]; double vdot = lr*m_wall[i]->vdot(time); m_vdot += vdot; m_Q += lr*m_wall[i]->Q(time); Kinetics* kin = m_wall[i]->kinetics(m_lr[i]); SurfPhase* surf = m_wall[i]->surface(m_lr[i]); if (surf && kin) { double rs0 = 1.0/surf->siteDensity(); size_t nk = surf->nSpecies(); double sum = 0.0; surf->setTemperature(m_state[0]); m_wall[i]->syncCoverages(m_lr[i]); kin->getNetProductionRates(DATA_PTR(m_work)); size_t ns = kin->surfacePhaseIndex(); size_t surfloc = kin->kineticsSpeciesIndex(0,ns); for (size_t k = 1; k < nk; k++) { ydot[loc + k] = m_work[surfloc+k]*rs0*surf->size(k); sum -= ydot[loc + k]; } ydot[loc] = sum; loc += nk; double wallarea = m_wall[i]->area(); for (size_t k = 0; k < m_nsp; k++) { m_sdot[k] += m_work[k]*wallarea; } } } // volume equation ydot[1] = m_vdot; /* species equations * Equation is: * \dot M_k = \hat W_k \dot\omega_k + \dot m_{in} Y_{k,in} * - \dot m_{out} Y_{k} + A \dot s_k. */ const vector_fp& mw = m_thermo->molecularWeights(); if (m_chem) { m_kin->getNetProductionRates(ydot+2); // "omega dot" } else { fill(ydot + 2, ydot + 2 + m_nsp, 0.0); } for (size_t n = 0; n < m_nsp; n++) { ydot[n+2] *= m_vol; // moles/s/m^3 -> moles/s ydot[n+2] += m_sdot[n]; ydot[n+2] *= mw[n]; } /* * Energy equation. * \f[ * \dot U = -P\dot V + A \dot q + \dot m_{in} h_{in} * - \dot m_{out} h. * \f] */ if (m_energy) { ydot[0] = - m_thermo->pressure() * m_vdot - m_Q; } else { ydot[0] = 0.0; } // add terms for open system if (m_open) { const doublereal* mf = m_thermo->massFractions(); doublereal enthalpy = m_thermo->enthalpy_mass(); // outlets for (size_t i = 0; i < m_nOutlets; i++) { double mdot_out = m_outlet[i]->massFlowRate(time); for (size_t n = 0; n < m_nsp; n++) { ydot[2+n] -= mdot_out * mf[n]; } if (m_energy) { ydot[0] -= mdot_out * enthalpy; } } // inlets for (size_t i = 0; i < m_nInlets; i++) { double mdot_in = m_inlet[i]->massFlowRate(time); for (size_t n = 0; n < m_nsp; n++) { ydot[2+n] += m_inlet[i]->outletSpeciesMassFlowRate(n); } if (m_energy) { ydot[0] += mdot_in * m_inlet[i]->enthalpy_mass(); } } } // reset sensitivity parameters if (params) { size_t npar = m_pnum.size(); for (size_t n = 0; n < npar; n++) { double mult = m_kin->multiplier(m_pnum[n]); m_kin->setMultiplier(m_pnum[n], mult/params[n]); } size_t ploc = npar; for (size_t m = 0; m < m_nwalls; m++) { if (m_nsens_wall[m] > 0) { m_wall[m]->resetSensitivityParameters(m_lr[m]); ploc += m_nsens_wall[m]; } } } }
bool installReactionArrays(const XML_Node& p, Kinetics& kin, std::string default_phase, bool check_for_duplicates) { int itot = 0; // Search the children of the phase element for the XML element named // reactionArray. If we can't find it, then return signaling having not // found any reactions. Apparently, we allow multiple reactionArray elements // here Each one will be processed sequentially, with the end result being // purely additive. vector<XML_Node*> rarrays = p.getChildren("reactionArray"); if (rarrays.empty()) { return false; } for (size_t n = 0; n < rarrays.size(); n++) { // Go get a reference to the current XML element, reactionArray. We will // process this element now. const XML_Node& rxns = *rarrays[n]; // The reactionArray element has an attribute called, datasrc. The value // of the attribute is the XML element comprising the top of the tree of // reactions for the phase. Find this datasrc element starting with the // root of the current XML node. 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.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). if (rxns.hasChild("skip")) { const XML_Node& sk = rxns.child("skip"); if (sk["species"] == "undeclared") { kin.skipUndeclaredSpecies(true); } if (sk["third_bodies"] == "undeclared") { kin.skipUndeclaredThirdBodies(true); } } // Search for child elements called include. We only include a reaction // if it's tagged by one of the include fields. Or, we include all // reactions if there are no include fields. vector<XML_Node*> incl = rxns.getChildren("include"); vector<XML_Node*> allrxns = rdata->getChildren("reaction"); // if no 'include' directive, then include all reactions if (incl.empty()) { for (size_t i = 0; i < allrxns.size(); i++) { checkElectrochemReaction(p,kin,*allrxns[i]); kin.addReaction(newReaction(*allrxns[i])); ++itot; } } else { for (size_t nii = 0; nii < incl.size(); nii++) { const XML_Node& ii = *incl[nii]; string imin = ii["min"]; string imax = ii["max"]; string::size_type iwild = string::npos; if (imax == imin) { iwild = imin.find("*"); if (iwild != string::npos) { imin = imin.substr(0,iwild); imax = imin; } } for (size_t i = 0; i < allrxns.size(); i++) { const XML_Node* r = allrxns[i]; string rxid; if (r) { rxid = r->attrib("id"); if (iwild != string::npos) { rxid = rxid.substr(0,iwild); } // To decide whether the reaction is included or not we // do a lexical min max and operation. This sometimes // has surprising results. if ((rxid >= imin) && (rxid <= imax)) { checkElectrochemReaction(p,kin,*r); kin.addReaction(newReaction(*r)); ++itot; } } } } } } if (check_for_duplicates) { kin.checkDuplicates(); } return true; }