14 Reaction::Reaction(
int type)
18 , allow_nonreactant_orders(false)
19 , allow_negative_orders(false)
23 Reaction::Reaction(
int type,
const Composition& reactants_,
26 , reactants(reactants_)
30 , allow_nonreactant_orders(false)
31 , allow_negative_orders(false)
35 void Reaction::validate()
37 if (!allow_nonreactant_orders) {
38 for (Composition::iterator iter = orders.begin();
41 if (reactants.find(iter->first) == reactants.end()) {
42 throw CanteraError(
"Reaction::validate",
"Reaction order "
43 "specified for non-reactant species '" + iter->first +
"'");
48 if (!allow_negative_orders) {
49 for (Composition::iterator iter = orders.begin();
52 if (iter->second < 0.0) {
53 throw CanteraError(
"Reaction::validate",
"Negative reaction "
54 "order specified for species '" + iter->first +
"'");
60 std::string Reaction::reactantString()
const
62 std::ostringstream result;
63 for (Composition::const_iterator iter = reactants.begin();
64 iter != reactants.end();
66 if (iter != reactants.begin()) {
69 if (iter->second != 1.0) {
70 result << iter->second <<
" ";
72 result << iter->first;
77 std::string Reaction::productString()
const
79 std::ostringstream result;
80 for (Composition::const_iterator iter = products.begin();
81 iter != products.end();
83 if (iter != products.begin()) {
86 if (iter->second != 1.0) {
87 result << iter->second <<
" ";
89 result << iter->first;
94 std::string Reaction::equation()
const
97 return reactantString() +
" <=> " + productString();
99 return reactantString() +
" => " + productString();
103 ElementaryReaction::ElementaryReaction(
const Composition& reactants_,
108 , allow_negative_pre_exponential_factor(false)
112 ElementaryReaction::ElementaryReaction()
114 , allow_negative_pre_exponential_factor(false)
121 if (!allow_negative_pre_exponential_factor &&
124 "Undeclared negative pre-exponential factor found in reaction '"
129 ThirdBody::ThirdBody(
double default_eff)
130 : default_efficiency(default_eff)
134 ThreeBodyReaction::ThreeBodyReaction()
139 ThreeBodyReaction::ThreeBodyReaction(
const Composition& reactants_,
141 const Arrhenius& rate_,
142 const ThirdBody& tbody)
143 : ElementaryReaction(reactants_, products_, rate_)
157 FalloffReaction::FalloffReaction()
162 FalloffReaction::FalloffReaction(
164 const Arrhenius& low_rate_,
const Arrhenius& high_rate_,
165 const ThirdBody& tbody)
167 , low_rate(low_rate_)
168 , high_rate(high_rate_)
197 throw CanteraError(
"FalloffReaction::validate",
"Negative "
198 "pre-exponential factor found for reaction '" +
equation() +
"'");
202 ChemicallyActivatedReaction::ChemicallyActivatedReaction()
207 ChemicallyActivatedReaction::ChemicallyActivatedReaction(
209 const Arrhenius& low_rate_,
const Arrhenius& high_rate_,
210 const ThirdBody& tbody)
211 : FalloffReaction(reactants_, products_, low_rate, high_rate, tbody)
216 PlogReaction::PlogReaction()
221 PlogReaction::PlogReaction(
const Composition& reactants_,
223 : Reaction(
PLOG_RXN, reactants_, products_)
228 ChebyshevReaction::ChebyshevReaction()
233 ChebyshevReaction::ChebyshevReaction(
const Composition& reactants_,
235 const ChebyshevRate& rate_)
241 InterfaceReaction::InterfaceReaction()
242 : is_sticking_coefficient(false)
247 InterfaceReaction::InterfaceReaction(
const Composition& reactants_,
249 const Arrhenius& rate_,
251 : ElementaryReaction(reactants_, products_, rate_)
252 , is_sticking_coefficient(isStick)
257 ElectrochemicalReaction::ElectrochemicalReaction()
258 : film_resistivity(0.0)
260 , exchange_current_density_formulation(false)
264 ElectrochemicalReaction::ElectrochemicalReaction(
const Composition& reactants_,
266 const Arrhenius& rate_)
267 : InterfaceReaction(reactants_, products_, rate_)
268 , film_resistivity(0.0)
270 , exchange_current_density_formulation(false)
275 Arrhenius readArrhenius(
const XML_Node& arrhenius_node)
277 return Arrhenius(
getFloat(arrhenius_node,
"A",
"toSI"),
291 std::vector<std::string> p;
294 size_t np = p.size();
295 for (
size_t n = 0; n < np; n++) {
299 int falloff_type = 0;
300 if (
lowercase(falloff[
"type"]) ==
"lindemann") {
301 falloff_type = SIMPLE_FALLOFF;
303 throw CanteraError(
"readFalloff",
"Lindemann parameterization "
304 "takes no parameters, but " +
int2str(np) +
"were given");
306 }
else if (
lowercase(falloff[
"type"]) ==
"troe") {
307 falloff_type = TROE_FALLOFF;
308 if (np != 3 && np != 4) {
309 throw CanteraError(
"readFalloff",
"Troe parameterization takes "
310 "3 or 4 parameters, but " +
int2str(np) +
"were given");
312 }
else if (
lowercase(falloff[
"type"]) ==
"sri") {
313 falloff_type = SRI_FALLOFF;
314 if (np != 3 && np != 5) {
315 throw CanteraError(
"readFalloff",
"SRI parameterization takes "
316 "3 or 5 parameters, but " +
int2str(np) +
"were given");
319 throw CanteraError(
"readFalloff",
"Unrecognized falloff type: '" +
320 falloff[
"type"] +
"'");
325 void readEfficiencies(ThirdBody& tbody,
const XML_Node& rc_node)
327 if (!rc_node.hasChild(
"efficiencies")) {
328 tbody.default_efficiency = 1.0;
331 const XML_Node& eff_node = rc_node.child(
"efficiencies");
332 tbody.default_efficiency =
fpValue(eff_node[
"default"]);
336 void setupReaction(Reaction& R,
const XML_Node& rxn_node)
343 std::vector<XML_Node*> orders = rxn_node.getChildren(
"order");
344 for (
size_t i = 0; i < orders.size(); i++) {
345 R.orders[orders[i]->attrib(
"species")] = orders[i]->fp_value();
349 R.id = rxn_node.attrib(
"id");
350 R.duplicate = rxn_node.hasAttrib(
"duplicate");
351 const std::string& rev = rxn_node[
"reversible"];
352 R.reversible = (rev ==
"true" || rev ==
"yes");
355 void setupElementaryReaction(ElementaryReaction& R,
const XML_Node& rxn_node)
357 const XML_Node& rc_node = rxn_node.child(
"rateCoeff");
358 if (rc_node.hasChild(
"Arrhenius")) {
359 R.rate = readArrhenius(rc_node.child(
"Arrhenius"));
360 }
else if (rc_node.hasChild(
"Arrhenius_ExchangeCurrentDensity")) {
361 R.rate = readArrhenius(rc_node.child(
"Arrhenius_ExchangeCurrentDensity"));
363 throw CanteraError(
"setupElementaryReaction",
"Couldn't find Arrhenius node");
365 if (rxn_node[
"negative_A"] ==
"yes") {
366 R.allow_negative_pre_exponential_factor =
true;
368 if (rxn_node[
"negative_orders"] ==
"yes") {
369 R.allow_negative_orders =
true;
371 setupReaction(R, rxn_node);
374 void setupThreeBodyReaction(ThreeBodyReaction& R,
const XML_Node& rxn_node)
376 readEfficiencies(R.third_body, rxn_node.child(
"rateCoeff"));
377 setupElementaryReaction(R, rxn_node);
380 void setupFalloffReaction(FalloffReaction& R,
const XML_Node& rxn_node)
382 XML_Node& rc_node = rxn_node.child(
"rateCoeff");
383 std::vector<XML_Node*> rates = rc_node.getChildren(
"Arrhenius");
386 for (
size_t i = 0; i < rates.size(); i++) {
387 XML_Node& node = *rates[i];
388 if (node[
"name"] ==
"") {
389 R.high_rate = readArrhenius(node);
391 }
else if (node[
"name"] ==
"k0") {
392 R.low_rate = readArrhenius(node);
395 throw CanteraError(
"setupFalloffReaction",
"Found an Arrhenius XML "
396 "node with an unexpected type '" + node[
"name"] +
"'");
399 if (nLow != 1 || nHigh != 1) {
400 throw CanteraError(
"setupFalloffReaction",
"Did not find the correct "
401 "number of Arrhenius rate expressions");
404 readEfficiencies(R.third_body, rc_node);
405 setupReaction(R, rxn_node);
408 void setupChemicallyActivatedReaction(ChemicallyActivatedReaction& R,
409 const XML_Node& rxn_node)
411 XML_Node& rc_node = rxn_node.child(
"rateCoeff");
412 std::vector<XML_Node*> rates = rc_node.getChildren(
"Arrhenius");
415 for (
size_t i = 0; i < rates.size(); i++) {
416 XML_Node& node = *rates[i];
417 if (node[
"name"] ==
"kHigh") {
418 R.high_rate = readArrhenius(node);
420 }
else if (node[
"name"] ==
"") {
421 R.low_rate = readArrhenius(node);
424 throw CanteraError(
"setupChemicallyActivatedReaction",
"Found an "
425 "Arrhenius XML node with an unexpected type '" + node[
"name"] +
"'");
428 if (nLow != 1 || nHigh != 1) {
429 throw CanteraError(
"setupChemicallyActivatedReaction",
"Did not find "
430 "the correct number of Arrhenius rate expressions");
433 readEfficiencies(R.third_body, rc_node);
434 setupReaction(R, rxn_node);
437 void setupPlogReaction(PlogReaction& R,
const XML_Node& rxn_node)
439 XML_Node& rc = rxn_node.child(
"rateCoeff");
440 std::multimap<double, Arrhenius> rates;
441 for (
size_t m = 0; m < rc.nChildren(); m++) {
442 const XML_Node& node = rc.child(m);
443 rates.insert(std::make_pair(
getFloat(node,
"P",
"toSI"),
444 readArrhenius(node)));
446 R.rate = Plog(rates);
447 setupReaction(R, rxn_node);
460 size_t nP = atoi(coeff_node[
"degreeP"].c_str());
461 size_t nT = atoi(coeff_node[
"degreeT"].c_str());
466 for (
size_t t = 0; t < nT; t++) {
467 for (
size_t p = 0; p < nP; p++) {
468 coeffs(t,p) = coeffs_flat[nP*t + p];
471 R.rate = ChebyshevRate(
getFloat(rc,
"Tmin",
"toSI"),
476 setupReaction(R, rxn_node);
479 void setupInterfaceReaction(InterfaceReaction& R,
const XML_Node& rxn_node)
481 if (
lowercase(rxn_node[
"type"]) ==
"global") {
484 XML_Node& arr = rxn_node.child(
"rateCoeff").child(
"Arrhenius");
486 R.is_sticking_coefficient =
true;
487 R.sticking_species = arr[
"species"];
489 std::vector<XML_Node*> cov = arr.getChildren(
"coverage");
490 for (std::vector<XML_Node*>::iterator iter = cov.begin();
494 CoverageDependency& cdep = R.coverage_deps[(*iter)->attrib(
"species")];
495 cdep.a =
getFloat(**iter,
"a",
"toSI");
499 setupElementaryReaction(R, rxn_node);
502 void setupElectrochemicalReaction(ElectrochemicalReaction& R,
503 const XML_Node& rxn_node)
506 std::string type =
lowercase(rxn_node[
"type"]);
507 if (type ==
"butlervolmer") {
509 }
else if (type ==
"butlervolmer_noactivitycoeffs") {
511 }
else if (type ==
"surfaceaffinity") {
513 }
else if (type ==
"global") {
517 XML_Node& rc = rxn_node.
child(
"rateCoeff");
518 std::string rc_type =
lowercase(rc[
"type"]);
519 if (rc_type ==
"exchangecurrentdensity") {
520 R.exchange_current_density_formulation =
true;
521 }
else if (rc_type !=
"" && rc_type !=
"arrhenius") {
522 throw CanteraError(
"setupElectrochemicalReaction",
523 "Unknown rate coefficient type: '" + rc_type +
"'");
525 if (rc.hasChild(
"Arrhenius_ExchangeCurrentDensity")) {
526 R.exchange_current_density_formulation =
true;
529 if (rc.hasChild(
"electrochem") && rc.child(
"electrochem").hasAttrib(
"beta")) {
535 setupInterfaceReaction(R, rxn_node);
541 throw CanteraError(
"setupElectrochemicalReaction",
542 "A Butler-Volmer reaction must be reversible");
547 R.allow_nonreactant_orders =
true;
548 for (Composition::const_iterator iter = R.reactants.begin();
549 iter != R.reactants.end();
551 R.orders[iter->first] += iter->second * (1.0 - R.beta);
553 for (Composition::const_iterator iter = R.products.begin();
554 iter != R.products.end();
556 R.orders[iter->first] += iter->second * R.beta;
561 if (rxn_node.hasChild(
"reactionOrderFormulation")) {
564 R.allow_nonreactant_orders =
true;
565 const XML_Node& rof_node = rxn_node.child(
"reactionOrderFormulation");
566 if (
lowercase(rof_node[
"model"]) ==
"reactantorders") {
567 R.orders = initial_orders;
568 }
else if (
lowercase(rof_node[
"model"]) ==
"zeroorders") {
569 for (Composition::const_iterator iter = R.reactants.begin();
570 iter != R.reactants.end();
572 R.orders[iter->first] = 0.0;
574 }
else if (
lowercase(rof_node[
"model"]) ==
"butlervolmerorders") {
576 for (Composition::const_iterator iter = R.reactants.begin();
577 iter != R.reactants.end();
579 double c =
getValue(initial_orders, iter->first, iter->second);
580 R.orders[iter->first] += c * (1.0 - R.beta);
582 for (Composition::const_iterator iter = R.products.begin();
583 iter != R.products.end();
585 double c =
getValue(initial_orders, iter->first, iter->second);
586 R.orders[iter->first] += c * R.beta;
590 throw CanteraError(
"setupElectrochemicalReaction",
"unknown model "
591 "for reactionOrderFormulation XML_Node: '" +
592 rof_node[
"model"] +
"'");
597 if (rxn_node.hasChild(
"orders")) {
599 for (Composition::iterator iter = orders.begin();
600 iter != orders.end();
602 R.orders[iter->first] = iter->second;
609 std::string type =
lowercase(rxn_node[
"type"]);
613 if (rxn_node.
child(
"rateCoeff").
hasChild(
"electrochem") && type ==
"edge") {
614 type =
"electrochemical";
618 if (type ==
"elementary" || type ==
"arrhenius" || type ==
"") {
620 setupElementaryReaction(*R, rxn_node);
623 }
else if (type ==
"threebody" || type ==
"three_body") {
625 setupThreeBodyReaction(*R, rxn_node);
628 }
else if (type ==
"falloff") {
630 setupFalloffReaction(*R, rxn_node);
633 }
else if (type ==
"chemact" || type ==
"chemically_activated") {
635 setupChemicallyActivatedReaction(*R, rxn_node);
638 }
else if (type ==
"plog" || type ==
"pdep_arrhenius") {
640 setupPlogReaction(*R, rxn_node);
643 }
else if (type ==
"chebyshev") {
645 setupChebyshevReaction(*R, rxn_node);
648 }
else if (type ==
"interface" || type ==
"surface" || type ==
"edge" ||
651 setupInterfaceReaction(*R, rxn_node);
654 }
else if (type ==
"electrochemical" ||
655 type ==
"butlervolmer_noactivitycoeffs" ||
656 type ==
"butlervolmer" ||
657 type ==
"surfaceaffinity") {
659 setupElectrochemicalReaction(*R, rxn_node);
664 "Unknown reaction type '" + rxn_node[
"type"] +
"'");
670 std::vector<shared_ptr<Reaction> > all_reactions;
671 std::vector<XML_Node*> reaction_nodes =
674 for (std::vector<XML_Node*>::iterator iter = reaction_nodes.begin();
675 iter != reaction_nodes.end();
680 return all_reactions;
doublereal fpValue(const std::string &val)
Translate a string into one doublereal value.
const int PLOG_RXN
A pressure-dependent rate expression consisting of several Arrhenius rate expressions evaluated at di...
virtual std::string reactantString() const
The reactant side of the chemical equation for this reaction.
void readFalloff(FalloffReaction &R, const XML_Node &rc_node)
Parse falloff parameters, given a rateCoeff node.
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
virtual std::string reactantString() const
The reactant side of the chemical equation for this reaction.
int reaction_type
Type of the reaction.
CTML ("Cantera Markup Language") is the variant of XML that Cantera uses to store data...
A reaction which follows mass-action kinetics with a modified Arrhenius reaction rate.
const int INTERFACE_RXN
A reaction occurring on an interface, e.g a surface or edge.
A pressure-dependent reaction parameterized by a bi-variate Chebyshev polynomial in temperature and p...
shared_ptr< Falloff > newFalloff(int type, const vector_fp &c)
Return a pointer to a new falloff function calculator.
virtual void validate()
Ensure that the rate constant and other parameters for this reaction are valid.
virtual void validate()
Ensure that the rate constant and other parameters for this reaction are valid.
const int CHEBYSHEV_RXN
A general gas-phase pressure-dependent reaction where k(T,P) is defined in terms of a bivariate Cheby...
const int SURFACEAFFINITY_RXN
This is a surface reaction that is formulated using the affinity representation, common in the geoche...
virtual std::string productString() const
The product side of the chemical equation for this reaction.
virtual std::string productString() const
The product side of the chemical equation for this reaction.
Class XML_Node is a tree-based representation of the contents of an XML file.
virtual std::string reactantString() const
The reactant side of the chemical equation for this reaction.
Parameterizations for reaction falloff functions.
std::string lowercase(const std::string &s)
Cast a copy of a string to lower case.
A pressure-dependent reaction parameterized by logarithmically interpolating between Arrhenius rate e...
const int CHEMACT_RXN
A chemical activation reaction.
XML_Node & child(const size_t n) const
Return a changeable reference to the n'th child of the current node.
A class for 2D arrays stored in column-major (Fortran-compatible) form.
Header file for class Cantera::Array2D.
const int FALLOFF_RXN
The general form for a gas-phase association or dissociation reaction, with a pressure-dependent rate...
virtual void validate()
Ensure that the rate constant and other parameters for this reaction are valid.
shared_ptr< Falloff > falloff
Falloff function which determines how low_rate and high_rate are combined to determine the rate const...
std::map< std::string, doublereal > Composition
Map from string names to doubles.
A reaction occurring on an interface (i.e. a SurfPhase or an EdgePhase)
A reaction that is first-order in [M] at low pressure, like a third-body reaction, but zeroth-order in [M] as pressure increases.
Base class for exceptions thrown by Cantera classes.
shared_ptr< Reaction > newReaction(const XML_Node &rxn_node)
Create a new Reaction object for the reaction defined in rxn_node
void validate(const std::string &equation)
Check to make sure that the rate expression is finite over a range of temperatures at each interpolat...
Intermediate class which stores data about a reaction and its rate parameterization so that it can be...
const U & getValue(const std::map< T, U > &m, const T &key)
Const accessor for a value in a std::map.
bool hasChild(const std::string &ch) const
Tests whether the current node has a child node with a particular name.
double preExponentialFactor() const
Return the pre-exponential factor A (in m, kmol, s to powers depending on the reaction order) ...
const int THREE_BODY_RXN
A gas-phase reaction that requires a third-body collision partner.
Arrhenius reaction rate type depends only on temperature.
virtual std::string productString() const
The product side of the chemical equation for this reaction.
const int GLOBAL_RXN
A global reaction.
compositionMap parseCompString(const std::string &ss, const std::vector< std::string > &names)
Parse a composition string into a map consisting of individual key:composition pairs.
std::string equation() const
The chemical equation for this reaction.
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Composition efficiencies
Map of species to third body efficiency.
virtual void validate()
Ensure that the rate constant and other parameters for this reaction are valid.
void getStringArray(const XML_Node &node, std::vector< std::string > &v)
This function interprets the value portion of an XML element as a string.
size_t getFloatArray(const XML_Node &node, std::vector< doublereal > &v, const bool convert, const std::string &unitsString, const std::string &nodeName)
This function reads the current node or a child node of the current node with the default name...
A reaction with a non-reacting third body "M" that acts to add or remove energy from the reacting spe...
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
const int ELEMENTARY_RXN
A reaction with a rate coefficient that depends only on temperature and voltage that also obeys mass-...
doublereal getFloat(const XML_Node &parent, const std::string &name, const std::string &type)
Get a floating-point value from a child element.
Arrhenius high_rate
The rate constant in the high-pressure limit.
Arrhenius low_rate
The rate constant in the low-pressure limit.
const int BUTLERVOLMER_NOACTIVITYCOEFFS_RXN
This is a surface reaction that is formulated using the Butler-Volmer formulation and using concentra...
const int BUTLERVOLMER_RXN
This is a surface reaction that is formulated using the Butler-Volmer formulation.
std::vector< shared_ptr< Reaction > > getReactions(const XML_Node &node)
Create Reaction objects for all <reaction> nodes in an XML document.
doublereal fpValueCheck(const std::string &val)
Translate a string into one doublereal value, with error checking.
double default_efficiency
The default third body efficiency for species not listed in efficiencies.
An interface reaction which involves charged species.
ThirdBody third_body
Relative efficiencies of third-body species in enhancing the reaction rate.
void getChildren(const std::string &name, std::vector< XML_Node * > &children) const
Get a vector of pointers to XML_Node containing all of the children of the current node which matches...
A reaction where the rate decreases as pressure increases due to collisional stabilization of a react...
bool getOptionalFloat(const XML_Node &parent, const std::string &name, doublereal &fltRtn, const std::string &type)
Get an optional floating-point value from a child element.