Cantera  2.5.1
InterfaceKinetics.cpp
Go to the documentation of this file.
1 /**
2  * @file InterfaceKinetics.cpp
3  */
4 
5 // This file is part of Cantera. See License.txt in the top-level directory or
6 // at https://cantera.org/license.txt for license and copyright information.
7 
12 
13 #include <cstdio>
14 
15 using namespace std;
16 
17 namespace Cantera
18 {
19 
20 InterfaceKinetics::InterfaceKinetics(thermo_t* thermo) :
21  m_redo_rates(false),
22  m_surf(0),
23  m_integrator(0),
24  m_ROP_ok(false),
25  m_temp(0.0),
26  m_logtemp(0.0),
27  m_has_coverage_dependence(false),
28  m_has_electrochem_rxns(false),
29  m_has_exchange_current_density_formulation(false),
30  m_phaseExistsCheck(false),
31  m_ioFlag(0),
32  m_nDim(2)
33 {
34  if (thermo != 0) {
35  addPhase(*thermo);
36  }
37 }
38 
39 InterfaceKinetics::~InterfaceKinetics()
40 {
41  delete m_integrator;
42 }
43 
44 void InterfaceKinetics::setElectricPotential(int n, doublereal V)
45 {
47  m_redo_rates = true;
48 }
49 
51 {
52  // First task is update the electrical potentials from the Phases
55  m_surf->getCoverages(m_actConc.data());
56  m_rates.update_C(m_actConc.data());
57  m_redo_rates = true;
58  }
59 
60  // Go find the temperature from the surface
61  doublereal T = thermo(surfacePhaseIndex()).temperature();
62  m_redo_rates = true;
63  if (T != m_temp || m_redo_rates) {
64  m_logtemp = log(T);
65 
66  // Calculate the forward rate constant by calling m_rates and store it in m_rfn[]
67  m_rates.update(T, m_logtemp, m_rfn.data());
68  applyStickingCorrection(T, m_rfn.data());
69 
70  // If we need to do conversions between exchange current density
71  // formulation and regular formulation (either way) do it here.
74  }
77  }
78  m_temp = T;
79  updateKc();
80  m_ROP_ok = false;
81  m_redo_rates = false;
82  }
83 }
84 
86 {
87  // Store electric potentials for each phase in the array m_phi[].
88  for (size_t n = 0; n < nPhases(); n++) {
89  if (thermo(n).electricPotential() != m_phi[n]) {
90  m_phi[n] = thermo(n).electricPotential();
91  m_redo_rates = true;
92  }
93  }
94 }
95 
97 {
98  for (size_t n = 0; n < nPhases(); n++) {
99  const ThermoPhase* tp = m_thermo[n];
100  /*
101  * We call the getActivityConcentrations function of each ThermoPhase
102  * class that makes up this kinetics object to obtain the generalized
103  * concentrations for species within that class. This is collected in
104  * the vector m_conc. m_start[] are integer indices for that vector
105  * denoting the start of the species for each phase.
106  */
108 
109  // Get regular concentrations too
110  tp->getConcentrations(m_conc.data() + m_start[n]);
111  }
112  m_ROP_ok = false;
113 }
114 
116 {
117  _update_rates_C();
118  copy(m_actConc.begin(), m_actConc.end(), conc);
119 }
120 
122 {
123  fill(m_rkcn.begin(), m_rkcn.end(), 0.0);
124 
125  if (m_revindex.size() > 0) {
126  /*
127  * Get the vector of standard state electrochemical potentials for
128  * species in the Interfacial kinetics object and store it in m_mu0[]
129  * and m_mu0_Kc[]
130  */
131  updateMu0();
132  doublereal rrt = 1.0 / thermo(reactionPhaseIndex()).RT();
133 
134  // compute Delta mu^0 for all reversible reactions
135  getRevReactionDelta(m_mu0_Kc.data(), m_rkcn.data());
136 
137  for (size_t i = 0; i < m_revindex.size(); i++) {
138  size_t irxn = m_revindex[i];
139  if (irxn == npos || irxn >= nReactions()) {
140  throw CanteraError("InterfaceKinetics::updateKc",
141  "illegal value: irxn = {}", irxn);
142  }
143  // WARNING this may overflow HKM
144  m_rkcn[irxn] = exp(m_rkcn[irxn]*rrt);
145  }
146  for (size_t i = 0; i != m_irrev.size(); ++i) {
147  m_rkcn[ m_irrev[i] ] = 0.0;
148  }
149  }
150 }
151 
153 {
154  // First task is update the electrical potentials from the Phases
156 
158  size_t ik = 0;
159  for (size_t n = 0; n < nPhases(); n++) {
161  for (size_t k = 0; k < thermo(n).nSpecies(); k++) {
162  m_mu0_Kc[ik] = m_mu0[ik] + Faraday * m_phi[n] * thermo(n).charge(k);
164  * thermo(n).logStandardConc(k);
165  ik++;
166  }
167  }
168 }
169 
171 {
172  updateMu0();
173  doublereal rrt = 1.0 / thermo(reactionPhaseIndex()).RT();
174  std::fill(kc, kc + nReactions(), 0.0);
175  getReactionDelta(m_mu0_Kc.data(), kc);
176  for (size_t i = 0; i < nReactions(); i++) {
177  kc[i] = exp(-kc[i]*rrt);
178  }
179 }
180 
182 {
183  // Calculate:
184  // - m_StandardConc[]
185  // - m_ProdStanConcReac[]
186  // - m_deltaG0[]
187  // - m_mu0[]
188 
189  // First collect vectors of the standard Gibbs free energies of the
190  // species and the standard concentrations
191  // - m_mu0
192  // - m_StandardConc
193  size_t ik = 0;
194 
195  for (size_t n = 0; n < nPhases(); n++) {
197  size_t nsp = thermo(n).nSpecies();
198  for (size_t k = 0; k < nsp; k++) {
200  ik++;
201  }
202  }
203 
204  getReactionDelta(m_mu0.data(), m_deltaG0.data());
205 
206  // Calculate the product of the standard concentrations of the reactants
207  for (size_t i = 0; i < nReactions(); i++) {
208  m_ProdStanConcReac[i] = 1.0;
209  }
210  m_reactantStoich.multiply(m_StandardConc.data(), m_ProdStanConcReac.data());
211 }
212 
214 {
215  // Compute the electrical potential energy of each species
216  size_t ik = 0;
217  for (size_t n = 0; n < nPhases(); n++) {
218  size_t nsp = thermo(n).nSpecies();
219  for (size_t k = 0; k < nsp; k++) {
220  m_pot[ik] = Faraday * thermo(n).charge(k) * m_phi[n];
221  ik++;
222  }
223  }
224 
225  // Compute the change in electrical potential energy for each reaction. This
226  // will only be non-zero if a potential difference is present.
228 
229  // Modify the reaction rates. Only modify those with a non-zero activation
230  // energy. Below we decrease the activation energy below zero but in some
231  // debug modes we print out a warning message about this.
232 
233  // NOTE, there is some discussion about this point. Should we decrease the
234  // activation energy below zero? I don't think this has been decided in any
235  // definitive way. The treatment below is numerically more stable, however.
236  for (size_t i = 0; i < m_beta.size(); i++) {
237  size_t irxn = m_ctrxn[i];
238 
239  // If we calculate the BV form directly, we don't add the voltage
240  // correction to the forward reaction rate constants.
241  if (m_ctrxn_BVform[i] == 0) {
242  double eamod = m_beta[i] * deltaElectricEnergy_[irxn];
243  if (eamod != 0.0) {
244  kf[irxn] *= exp(-eamod/thermo(reactionPhaseIndex()).RT());
245  }
246  }
247  }
248 }
249 
251 {
253  // Loop over all reactions which are defined to have a voltage transfer
254  // coefficient that affects the activity energy for the reaction
255  for (size_t i = 0; i < m_ctrxn.size(); i++) {
256  size_t irxn = m_ctrxn[i];
257 
258  // Determine whether the reaction rate constant is in an exchange
259  // current density formulation format.
260  int iECDFormulation = m_ctrxn_ecdf[i];
261  if (iECDFormulation) {
262  // If the BV form is to be converted into the normal form then we go
263  // through this process. If it isn't to be converted, then we don't
264  // go through this process.
265  //
266  // We need to have the straight chemical reaction rate constant to
267  // come out of this calculation.
268  if (m_ctrxn_BVform[i] == 0) {
269  // Calculate the term and modify the forward reaction
270  double tmp = exp(- m_beta[i] * m_deltaG0[irxn]
271  / thermo(reactionPhaseIndex()).RT());
272  tmp *= 1.0 / m_ProdStanConcReac[irxn] / Faraday;
273  kfwd[irxn] *= tmp;
274  }
275  // If BVform is nonzero we don't need to do anything.
276  } else {
277  // kfwd[] is the chemical reaction rate constant
278  //
279  // If we are to calculate the BV form directly, then we will do the
280  // reverse. We will calculate the exchange current density
281  // formulation here and substitute it.
282  if (m_ctrxn_BVform[i] != 0) {
283  // Calculate the term and modify the forward reaction rate
284  // constant so that it's in the exchange current density
285  // formulation format
286  double tmp = exp(m_beta[i] * m_deltaG0[irxn]
287  * thermo(reactionPhaseIndex()).RT());
288  tmp *= Faraday * m_ProdStanConcReac[irxn];
289  kfwd[irxn] *= tmp;
290  }
291  }
292  }
293 }
294 
296 {
297  updateROP();
298  for (size_t i = 0; i < nReactions(); i++) {
299  // base rate coefficient multiplied by perturbation factor
300  kfwd[i] = m_rfn[i] * m_perturb[i];
301  }
302 }
303 
304 void InterfaceKinetics::getRevRateConstants(doublereal* krev, bool doIrreversible)
305 {
306  getFwdRateConstants(krev);
307  if (doIrreversible) {
309  for (size_t i = 0; i < nReactions(); i++) {
310  krev[i] /= m_ropnet[i];
311  }
312  } else {
313  for (size_t i = 0; i < nReactions(); i++) {
314  krev[i] *= m_rkcn[i];
315  }
316  }
317 }
318 
320 {
321  // evaluate rate constants and equilibrium constants at temperature and phi
322  // (electric potential)
323  _update_rates_T();
324  // get updated activities (rates updated below)
325  _update_rates_C();
326 
327  if (m_ROP_ok) {
328  return;
329  }
330 
331  for (size_t i = 0; i < nReactions(); i++) {
332  // Scale the base forward rate coefficient by the perturbation factor
333  m_ropf[i] = m_rfn[i] * m_perturb[i];
334  // Multiply the scaled forward rate coefficient by the reciprocal of the
335  // equilibrium constant
336  m_ropr[i] = m_ropf[i] * m_rkcn[i];
337  }
338 
339  // multiply ropf by the activity concentration reaction orders to obtain
340  // the forward rates of progress.
341  m_reactantStoich.multiply(m_actConc.data(), m_ropf.data());
342 
343  // For reversible reactions, multiply ropr by the activity concentration
344  // products
345  m_revProductStoich.multiply(m_actConc.data(), m_ropr.data());
346 
347  for (size_t j = 0; j != nReactions(); ++j) {
348  m_ropnet[j] = m_ropf[j] - m_ropr[j];
349  }
350 
351  // For reactions involving multiple phases, we must check that the phase
352  // being consumed actually exists. This is particularly important for phases
353  // that are stoichiometric phases containing one species with a unity
354  // activity
355  if (m_phaseExistsCheck) {
356  for (size_t j = 0; j != nReactions(); ++j) {
357  if ((m_ropr[j] > m_ropf[j]) && (m_ropr[j] > 0.0)) {
358  for (size_t p = 0; p < nPhases(); p++) {
359  if (m_rxnPhaseIsProduct[j][p] && !m_phaseExists[p]) {
360  m_ropnet[j] = 0.0;
361  m_ropr[j] = m_ropf[j];
362  if (m_ropf[j] > 0.0) {
363  for (size_t rp = 0; rp < nPhases(); rp++) {
364  if (m_rxnPhaseIsReactant[j][rp] && !m_phaseExists[rp]) {
365  m_ropnet[j] = 0.0;
366  m_ropr[j] = m_ropf[j] = 0.0;
367  }
368  }
369  }
370  }
371  if (m_rxnPhaseIsReactant[j][p] && !m_phaseIsStable[p]) {
372  m_ropnet[j] = 0.0;
373  m_ropr[j] = m_ropf[j];
374  }
375  }
376  } else if ((m_ropf[j] > m_ropr[j]) && (m_ropf[j] > 0.0)) {
377  for (size_t p = 0; p < nPhases(); p++) {
378  if (m_rxnPhaseIsReactant[j][p] && !m_phaseExists[p]) {
379  m_ropnet[j] = 0.0;
380  m_ropf[j] = m_ropr[j];
381  if (m_ropf[j] > 0.0) {
382  for (size_t rp = 0; rp < nPhases(); rp++) {
383  if (m_rxnPhaseIsProduct[j][rp] && !m_phaseExists[rp]) {
384  m_ropnet[j] = 0.0;
385  m_ropf[j] = m_ropr[j] = 0.0;
386  }
387  }
388  }
389  }
390  if (m_rxnPhaseIsProduct[j][p] && !m_phaseIsStable[p]) {
391  m_ropnet[j] = 0.0;
392  m_ropf[j] = m_ropr[j];
393  }
394  }
395  }
396  }
397  }
398  m_ROP_ok = true;
399 }
400 
401 void InterfaceKinetics::getDeltaGibbs(doublereal* deltaG)
402 {
403  // Get the chemical potentials of the species in the all of the phases used
404  // in the kinetics mechanism
405  for (size_t n = 0; n < nPhases(); n++) {
406  m_thermo[n]->getChemPotentials(m_mu.data() + m_start[n]);
407  }
408 
409  // Use the stoichiometric manager to find deltaG for each reaction.
410  getReactionDelta(m_mu.data(), m_deltaG.data());
411  if (deltaG != 0 && (m_deltaG.data() != deltaG)) {
412  for (size_t j = 0; j < nReactions(); ++j) {
413  deltaG[j] = m_deltaG[j];
414  }
415  }
416 }
417 
419 {
420  // Get the chemical potentials of the species
421  for (size_t n = 0; n < nPhases(); n++) {
423  }
424 
425  // Use the stoichiometric manager to find deltaG for each reaction.
426  getReactionDelta(m_grt.data(), deltaM);
427 }
428 
429 void InterfaceKinetics::getDeltaEnthalpy(doublereal* deltaH)
430 {
431  // Get the partial molar enthalpy of all species
432  for (size_t n = 0; n < nPhases(); n++) {
434  }
435 
436  // Use the stoichiometric manager to find deltaH for each reaction.
437  getReactionDelta(m_grt.data(), deltaH);
438 }
439 
440 void InterfaceKinetics::getDeltaEntropy(doublereal* deltaS)
441 {
442  // Get the partial molar entropy of all species in all of the phases
443  for (size_t n = 0; n < nPhases(); n++) {
445  }
446 
447  // Use the stoichiometric manager to find deltaS for each reaction.
448  getReactionDelta(m_grt.data(), deltaS);
449 }
450 
451 void InterfaceKinetics::getDeltaSSGibbs(doublereal* deltaGSS)
452 {
453  // Get the standard state chemical potentials of the species. This is the
454  // array of chemical potentials at unit activity We define these here as the
455  // chemical potentials of the pure species at the temperature and pressure
456  // of the solution.
457  for (size_t n = 0; n < nPhases(); n++) {
459  }
460 
461  // Use the stoichiometric manager to find deltaG for each reaction.
462  getReactionDelta(m_mu0.data(), deltaGSS);
463 }
464 
466 {
467  // Get the standard state enthalpies of the species. This is the array of
468  // chemical potentials at unit activity We define these here as the
469  // enthalpies of the pure species at the temperature and pressure of the
470  // solution.
471  for (size_t n = 0; n < nPhases(); n++) {
472  thermo(n).getEnthalpy_RT(m_grt.data() + m_start[n]);
473  }
474  for (size_t k = 0; k < m_kk; k++) {
475  m_grt[k] *= thermo(reactionPhaseIndex()).RT();
476  }
477 
478  // Use the stoichiometric manager to find deltaH for each reaction.
479  getReactionDelta(m_grt.data(), deltaH);
480 }
481 
482 void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS)
483 {
484  // Get the standard state entropy of the species. We define these here as
485  // the entropies of the pure species at the temperature and pressure of the
486  // solution.
487  for (size_t n = 0; n < nPhases(); n++) {
488  thermo(n).getEntropy_R(m_grt.data() + m_start[n]);
489  }
490  for (size_t k = 0; k < m_kk; k++) {
491  m_grt[k] *= GasConstant;
492  }
493 
494  // Use the stoichiometric manager to find deltaS for each reaction.
495  getReactionDelta(m_grt.data(), deltaS);
496 }
497 
498 bool InterfaceKinetics::addReaction(shared_ptr<Reaction> r_base)
499 {
500  if (!m_surf) {
501  init();
502  }
503 
504  // Check that the number of surface sites is balanced
505  double reac_sites = 0.0;
506  double prod_sites = 0.0;
507  for (const auto& reactant : r_base->reactants) {
508  size_t k = m_surf->speciesIndex(reactant.first);
509  if (k != npos) {
510  reac_sites += reactant.second * m_surf->size(k);
511  }
512  }
513  for (const auto& product : r_base->products) {
514  size_t k = m_surf->speciesIndex(product.first);
515  if (k != npos) {
516  prod_sites += product.second * m_surf->size(k);
517  }
518  }
519  if (fabs(reac_sites - prod_sites) > 1e-5 * (reac_sites + prod_sites)) {
520  throw CanteraError("InterfaceKinetics::addReaction", "Number of surface"
521  " sites not balanced in reaction {}.\nReactant sites: {}\n"
522  "Product sites: {}", r_base->equation(), reac_sites, prod_sites);
523  }
524 
525  size_t i = nReactions();
526  bool added = Kinetics::addReaction(r_base);
527  if (!added) {
528  return false;
529  }
530 
531  InterfaceReaction& r = dynamic_cast<InterfaceReaction&>(*r_base);
532  SurfaceArrhenius rate = buildSurfaceArrhenius(i, r, false);
533  m_rates.install(i, rate);
534 
535  // Turn on the global flag indicating surface coverage dependence
536  if (!r.coverage_deps.empty()) {
538  }
539 
540  ElectrochemicalReaction* re = dynamic_cast<ElectrochemicalReaction*>(&r);
541  if (re) {
542  m_has_electrochem_rxns = true;
543  m_beta.push_back(re->beta);
544  m_ctrxn.push_back(i);
545  if (re->exchange_current_density_formulation) {
547  m_ctrxn_ecdf.push_back(1);
548  } else {
549  m_ctrxn_ecdf.push_back(0);
550  }
551 
555  r.reaction_type == GLOBAL_RXN) {
556  // Specify alternative forms of the electrochemical reaction
557  if (r.reaction_type == BUTLERVOLMER_RXN) {
558  m_ctrxn_BVform.push_back(1);
560  m_ctrxn_BVform.push_back(2);
561  } else {
562  // set the default to be the normal forward / reverse calculation method
563  m_ctrxn_BVform.push_back(0);
564  }
565  if (!r.orders.empty()) {
566  vector_fp orders(nTotalSpecies(), 0.0);
567  for (const auto& order : r.orders) {
568  orders[kineticsSpeciesIndex(order.first)] = order.second;
569  }
570  }
571  } else {
572  m_ctrxn_BVform.push_back(0);
573  if (re->film_resistivity > 0.0) {
574  throw CanteraError("InterfaceKinetics::addReaction",
575  "film resistivity set for elementary reaction");
576  }
577  }
578  }
579 
580  if (r.reversible) {
581  m_revindex.push_back(i);
582  } else {
583  m_irrev.push_back(i);
584  }
585 
586  m_rxnPhaseIsReactant.emplace_back(nPhases(), false);
587  m_rxnPhaseIsProduct.emplace_back(nPhases(), false);
588 
589  for (const auto& sp : r.reactants) {
590  size_t k = kineticsSpeciesIndex(sp.first);
591  size_t p = speciesPhaseIndex(k);
592  m_rxnPhaseIsReactant[i][p] = true;
593  }
594  for (const auto& sp : r.products) {
595  size_t k = kineticsSpeciesIndex(sp.first);
596  size_t p = speciesPhaseIndex(k);
597  m_rxnPhaseIsProduct[i][p] = true;
598  }
599 
600  deltaElectricEnergy_.push_back(0.0);
601  m_deltaG0.push_back(0.0);
602  m_deltaG.push_back(0.0);
603  m_ProdStanConcReac.push_back(0.0);
604 
605  return true;
606 }
607 
608 void InterfaceKinetics::modifyReaction(size_t i, shared_ptr<Reaction> r_base)
609 {
610  Kinetics::modifyReaction(i, r_base);
611  InterfaceReaction& r = dynamic_cast<InterfaceReaction&>(*r_base);
612  SurfaceArrhenius rate = buildSurfaceArrhenius(i, r, true);
613  m_rates.replace(i, rate);
614 
615  // Invalidate cached data
616  m_redo_rates = true;
617  m_temp += 0.1;
618 }
619 
621  size_t i, InterfaceReaction& r, bool replace)
622 {
623  if (r.is_sticking_coefficient) {
624  // Identify the interface phase
625  size_t iInterface = npos;
626  size_t min_dim = 4;
627  for (size_t n = 0; n < nPhases(); n++) {
628  if (thermo(n).nDim() < min_dim) {
629  iInterface = n;
630  min_dim = thermo(n).nDim();
631  }
632  }
633 
634  std::string sticking_species = r.sticking_species;
635  if (sticking_species == "") {
636  // Identify the sticking species if not explicitly given
637  bool foundStick = false;
638  for (const auto& sp : r.reactants) {
639  size_t iPhase = speciesPhaseIndex(kineticsSpeciesIndex(sp.first));
640  if (iPhase != iInterface) {
641  // Non-interface species. There should be exactly one of these
642  if (foundStick) {
643  throw CanteraError("InterfaceKinetics::buildSurfaceArrhenius",
644  "Multiple non-interface species found"
645  "in sticking reaction: '" + r.equation() + "'");
646  }
647  foundStick = true;
648  sticking_species = sp.first;
649  }
650  }
651  if (!foundStick) {
652  throw CanteraError("InterfaceKinetics::buildSurfaceArrhenius",
653  "No non-interface species found"
654  "in sticking reaction: '" + r.equation() + "'");
655  }
656  }
657 
658  double surface_order = 0.0;
659  double multiplier = 1.0;
660  // Adjust the A-factor
661  for (const auto& sp : r.reactants) {
662  size_t iPhase = speciesPhaseIndex(kineticsSpeciesIndex(sp.first));
663  const ThermoPhase& p = thermo(iPhase);
664  size_t k = p.speciesIndex(sp.first);
665  if (sp.first == sticking_species) {
666  multiplier *= sqrt(GasConstant/(2*Pi*p.molecularWeight(k)));
667  } else {
668  // Non-sticking species. Convert from coverages used in the
669  // sticking probability expression to the concentration units
670  // used in the mass action rate expression. For surface phases,
671  // the dependence on the site density is incorporated when the
672  // rate constant is evaluated, since we don't assume that the
673  // site density is known at this time.
674  double order = getValue(r.orders, sp.first, sp.second);
675  if (&p == m_surf) {
676  multiplier *= pow(m_surf->size(k), order);
677  surface_order += order;
678  } else {
679  multiplier *= pow(p.standardConcentration(k), -order);
680  }
681  }
682  }
683 
684  if (!replace) {
685  m_stickingData.emplace_back(StickData{i, surface_order, multiplier,
687  } else {
688  // Modifying an existing sticking reaction.
689  for (auto& item : m_stickingData) {
690  if (item.index == i) {
691  item.order = surface_order;
692  item.multiplier = multiplier;
693  item.use_motz_wise = r.use_motz_wise_correction;
694  break;
695  }
696  }
697  }
698  }
699 
701  r.rate.temperatureExponent(),
702  r.rate.activationEnergy_R());
703 
704  // Set up coverage dependencies
705  for (const auto& sp : r.coverage_deps) {
706  size_t k = thermo(reactionPhaseIndex()).speciesIndex(sp.first);
707  rate.addCoverageDependence(k, sp.second.a, sp.second.m, sp.second.E);
708  }
709  return rate;
710 }
711 
712 void InterfaceKinetics::setIOFlag(int ioFlag)
713 {
714  m_ioFlag = ioFlag;
715  if (m_integrator) {
716  m_integrator->setIOFlag(ioFlag);
717  }
718 }
719 
721 {
723  m_phaseExists.push_back(true);
724  m_phaseIsStable.push_back(true);
725 }
726 
728 {
729  size_t ks = reactionPhaseIndex();
730  if (ks == npos) {
731  throw CanteraError("InterfaceKinetics::init",
732  "no surface phase is present.");
733  }
734 
735  // Check to see that the interface routine has a dimension of 2
736  m_surf = (SurfPhase*)&thermo(ks);
737  if (m_surf->nDim() != m_nDim) {
738  throw CanteraError("InterfaceKinetics::init",
739  "expected interface dimension = 2, but got dimension = {}",
740  m_surf->nDim());
741  }
742 }
743 
745 {
746  size_t kOld = m_kk;
748  if (m_kk != kOld && nReactions()) {
749  throw CanteraError("InterfaceKinetics::resizeSpecies", "Cannot add"
750  " species to InterfaceKinetics after reactions have been added.");
751  }
752  m_actConc.resize(m_kk);
753  m_conc.resize(m_kk);
754  m_StandardConc.resize(m_kk, 0.0);
755  m_mu0.resize(m_kk);
756  m_mu.resize(m_kk);
757  m_mu0_Kc.resize(m_kk);
758  m_grt.resize(m_kk);
759  m_pot.resize(m_kk, 0.0);
760  m_phi.resize(nPhases(), 0.0);
761 }
762 
763 doublereal InterfaceKinetics::electrochem_beta(size_t irxn) const
764 {
765  for (size_t i = 0; i < m_ctrxn.size(); i++) {
766  if (m_ctrxn[i] == irxn) {
767  return m_beta[i];
768  }
769  }
770  return 0.0;
771 }
772 
773 void InterfaceKinetics::advanceCoverages(doublereal tstep, doublereal rtol,
774  doublereal atol, doublereal maxStepSize,
775  size_t maxSteps, size_t maxErrTestFails)
776 {
777  if (m_integrator == 0) {
778  vector<InterfaceKinetics*> k{this};
780  }
781  m_integrator->setTolerances(rtol, atol);
782  m_integrator->setMaxStepSize(maxStepSize);
783  m_integrator->setMaxSteps(maxSteps);
784  m_integrator->setMaxErrTestFails(maxErrTestFails);
785  m_integrator->integrate(0.0, tstep);
786  delete m_integrator;
787  m_integrator = 0;
788 }
789 
791  int ifuncOverride, doublereal timeScaleOverride)
792 {
793  // create our own solver object
794  if (m_integrator == 0) {
795  vector<InterfaceKinetics*> k{this};
798  }
799  m_integrator->setIOFlag(m_ioFlag);
800  // New direct method to go here
801  m_integrator->solvePseudoSteadyStateProblem(ifuncOverride, timeScaleOverride);
802 }
803 
804 void InterfaceKinetics::setPhaseExistence(const size_t iphase, const int exists)
805 {
806  checkPhaseIndex(iphase);
807  if (exists) {
808  if (!m_phaseExists[iphase]) {
810  m_phaseExistsCheck = std::max(m_phaseExistsCheck, 0);
811  m_phaseExists[iphase] = true;
812  }
813  m_phaseIsStable[iphase] = true;
814  } else {
815  if (m_phaseExists[iphase]) {
817  m_phaseExists[iphase] = false;
818  }
819  m_phaseIsStable[iphase] = false;
820  }
821 }
822 
823 int InterfaceKinetics::phaseExistence(const size_t iphase) const
824 {
825  checkPhaseIndex(iphase);
826  return m_phaseExists[iphase];
827 }
828 
829 int InterfaceKinetics::phaseStability(const size_t iphase) const
830 {
831  checkPhaseIndex(iphase);
832  return m_phaseIsStable[iphase];
833 }
834 
835 void InterfaceKinetics::setPhaseStability(const size_t iphase, const int isStable)
836 {
837  checkPhaseIndex(iphase);
838  if (isStable) {
839  m_phaseIsStable[iphase] = true;
840  } else {
841  m_phaseIsStable[iphase] = false;
842  }
843 }
844 
846 {
847  // Start out with the full ROP orders vector.
848  // This vector will have the BV exchange current density orders in it.
849  fwdFullOrders.assign(nTotalSpecies(), 0.0);
850  for (const auto& order : r.orders) {
851  fwdFullOrders[kineticsSpeciesIndex(order.first)] = order.second;
852  }
853 
854  // forward and reverse beta values
855  double betaf = r.beta;
856 
857  // Loop over the reactants doing away with the BV terms.
858  // This should leave the reactant terms only, even if they are non-mass action.
859  for (const auto& sp : r.reactants) {
860  size_t k = kineticsSpeciesIndex(sp.first);
861  fwdFullOrders[k] += betaf * sp.second;
862  // just to make sure roundoff doesn't leave a term that should be zero (haven't checked this out yet)
863  if (abs(fwdFullOrders[k]) < 0.00001) {
864  fwdFullOrders[k] = 0.0;
865  }
866  }
867 
868  // Loop over the products doing away with the BV terms.
869  // This should leave the reactant terms only, even if they are non-mass action.
870  for (const auto& sp : r.products) {
871  size_t k = kineticsSpeciesIndex(sp.first);
872  fwdFullOrders[k] -= betaf * sp.second;
873  // just to make sure roundoff doesn't leave a term that should be zero (haven't checked this out yet)
874  if (abs(fwdFullOrders[k]) < 0.00001) {
875  fwdFullOrders[k] = 0.0;
876  }
877  }
878 }
879 
880 void InterfaceKinetics::applyStickingCorrection(double T, double* kf)
881 {
882  if (m_stickingData.empty()) {
883  return;
884  }
885 
886  static const int cacheId = m_cache.getId();
887  CachedArray cached = m_cache.getArray(cacheId);
888  vector_fp& factors = cached.value;
889 
890  double n0 = m_surf->siteDensity();
891  if (!cached.validate(n0)) {
892  factors.resize(m_stickingData.size());
893  for (size_t n = 0; n < m_stickingData.size(); n++) {
894  factors[n] = pow(n0, -m_stickingData[n].order);
895  }
896  }
897 
898  for (size_t n = 0; n < m_stickingData.size(); n++) {
899  const StickData& item = m_stickingData[n];
900  if (item.use_motz_wise) {
901  kf[item.index] /= 1 - 0.5 * kf[item.index];
902  }
903  kf[item.index] *= factors[n] * sqrt(T) * item.multiplier;
904  }
905 }
906 
907 }
Declarations for the implicit integration of surface site density equations (see Kinetics Managers an...
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase,...
double temperatureExponent() const
Return the temperature exponent b
Definition: RxnRates.h:87
doublereal activationEnergy_R() const
Return the activation energy divided by the gas constant (i.e.
Definition: RxnRates.h:93
double preExponentialFactor() const
Return the pre-exponential factor A (in m, kmol, s to powers depending on the reaction order)
Definition: RxnRates.h:82
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:61
An interface reaction which involves charged species.
Definition: Reaction.h:242
doublereal beta
Forward value of the apparent Electrochemical transfer coefficient.
Definition: Reaction.h:259
doublereal film_resistivity
Film Resistivity value.
Definition: Reaction.h:256
Advances the surface coverages of the associated set of SurfacePhase objects in time.
void integrate(doublereal t0, doublereal t1)
Integrate from t0 to t1. The integrator is reinitialized first.
virtual void setTolerances(double rtol=1.e-7, double atol=1.e-14)
virtual void setMaxStepSize(double maxstep=0.0)
virtual void setMaxSteps(size_t maxsteps=20000)
virtual void initialize(doublereal t0=0.0)
void solvePseudoSteadyStateProblem(int ifuncOverride=-1, doublereal timeScaleOverride=1.0)
Solve for the pseudo steady-state of the surface problem.
virtual void setMaxErrTestFails(size_t maxErrTestFails=7)
virtual void init()
Prepare the class for the addition of reactions, after all phases have been added.
virtual void getDeltaSSGibbs(doublereal *deltaG)
Return the vector of values for the reaction standard state Gibbs free energy change.
std::vector< size_t > m_revindex
List of reactions numbers which are reversible reactions.
int phaseExistence(const size_t iphase) const
Gets the phase existence int for the ith phase.
SurfPhase * m_surf
Pointer to the single surface phase.
vector_fp m_beta
Electrochemical transfer coefficient for the forward direction.
virtual void getRevRateConstants(doublereal *krev, bool doIrreversible=false)
Return the reverse rate constants.
void applyVoltageKfwdCorrection(doublereal *const kfwd)
Apply modifications for the forward reaction rate for interfacial charge transfer reactions.
size_t m_nDim
Number of dimensions of reacting phase (2 for InterfaceKinetics, 1 for EdgeKinetics)
vector_fp m_deltaG0
Vector of delta G^0, the standard state Gibbs free energies for each reaction.
void setPhaseStability(const size_t iphase, const int isStable)
Set the stability of a phase in the reaction object.
vector_fp m_StandardConc
Vector of standard concentrations.
vector_fp m_deltaG
Vector of deltaG[] of reaction, the delta Gibbs free energies for each reaction.
vector_fp m_phi
Vector of phase electric potentials.
virtual void getDeltaElectrochemPotentials(doublereal *deltaM)
Return the vector of values for the reaction electrochemical free energy change.
void convertExchangeCurrentDensityFormulation(doublereal *const kfwd)
When an electrode reaction rate is optionally specified in terms of its exchange current density,...
void _update_rates_phi()
Update properties that depend on the electric potential.
doublereal m_temp
Current temperature of the data.
std::vector< std::vector< bool > > m_rxnPhaseIsReactant
Vector of vector of booleans indicating whether a phase participates in a reaction as a reactant.
virtual void getDeltaEnthalpy(doublereal *deltaH)
Return the vector of values for the reactions change in enthalpy.
bool m_has_electrochem_rxns
Boolean flag indicating whether any reaction in the mechanism has a beta electrochemical parameter.
virtual void getFwdRateConstants(doublereal *kfwd)
Return the forward rate constants.
std::vector< size_t > m_ctrxn
Vector of reaction indexes specifying the id of the charge transfer reactions in the mechanism.
std::vector< StickData > m_stickingData
Data for sticking reactions.
vector_fp m_actConc
Array of activity concentrations for each species in the kinetics object.
void setElectricPotential(int n, doublereal V)
Set the electric potential in the nth phase.
virtual bool addReaction(shared_ptr< Reaction > r)
Add a single reaction to the mechanism.
vector_int m_ctrxn_ecdf
Vector of booleans indicating whether the charge transfer reaction rate constant is described by an e...
vector_fp m_conc
Array of concentrations for each species in the kinetics mechanism.
void updateKc()
Update the equilibrium constants and stored electrochemical potentials in molar units for all reversi...
void setPhaseExistence(const size_t iphase, const int exists)
Set the existence of a phase in the reaction object.
std::vector< size_t > m_irrev
Vector of irreversible reaction numbers.
vector_fp m_mu0
Vector of standard state chemical potentials for all species.
SurfaceArrhenius buildSurfaceArrhenius(size_t i, InterfaceReaction &r, bool replace)
Build a SurfaceArrhenius object from a Reaction, taking into account the possible sticking coefficien...
virtual void getActivityConcentrations(doublereal *const conc)
Get the vector of activity concentrations used in the kinetics object.
vector_fp m_pot
Vector of potential energies due to Voltages.
void _update_rates_C()
Update properties that depend on the species mole fractions and/or concentration,.
virtual void modifyReaction(size_t i, shared_ptr< Reaction > rNew)
Modify the rate expression associated with a reaction.
std::vector< size_t > m_ctrxn_BVform
Vector of Reactions which follow the Butler-Volmer methodology for specifying the exchange current de...
vector_fp m_mu
Vector of chemical potentials for all species.
vector_fp m_grt
Temporary work vector of length m_kk.
vector_fp deltaElectricEnergy_
Storage for the net electric energy change due to reaction.
doublereal m_logtemp
Current log of the temperature.
int phaseStability(const size_t iphase) const
Gets the phase stability int for the ith phase.
ImplicitSurfChem * m_integrator
Pointer to the Implicit surface chemistry object.
virtual void getEquilibriumConstants(doublereal *kc)
Equilibrium constant for all reactions including the voltage term.
virtual void getDeltaSSEntropy(doublereal *deltaS)
Return the vector of values for the change in the standard state entropies for each reaction.
virtual void getDeltaEntropy(doublereal *deltaS)
Return the vector of values for the reactions change in entropy.
void solvePseudoSteadyStateProblem(int ifuncOverride=-1, doublereal timeScaleOverride=1.0)
Solve for the pseudo steady-state of the surface problem.
void _update_rates_T()
Update properties that depend on temperature.
virtual void updateROP()
Internal routine that updates the Rates of Progress of the reactions.
virtual void getDeltaSSEnthalpy(doublereal *deltaH)
Return the vector of values for the change in the standard state enthalpies of reaction.
virtual void determineFwdOrdersBV(ElectrochemicalReaction &r, vector_fp &fwdFullorders)
bool m_has_coverage_dependence
Boolean flag indicating whether any reaction in the mechanism has a coverage dependent forward reacti...
virtual void updateMu0()
Update the standard state chemical potentials and species equilibrium constant entries.
std::vector< std::vector< bool > > m_rxnPhaseIsProduct
Vector of vector of booleans indicating whether a phase participates in a reaction as a product.
vector_fp m_mu0_Kc
Vector of standard state electrochemical potentials modified by a standard concentration term.
vector_int m_phaseIsStable
Vector of int indicating whether phases are stable or not.
void updateExchangeCurrentQuantities()
values needed to convert from exchange current density to surface reaction rate.
std::vector< bool > m_phaseExists
Vector of booleans indicating whether phases exist or not.
virtual void getDeltaGibbs(doublereal *deltaG)
Return the vector of values for the reaction Gibbs free energy change.
int m_phaseExistsCheck
Int flag to indicate that some phases in the kinetics mechanism are non-existent.
vector_fp m_ProdStanConcReac
Vector of the products of the standard concentrations of the reactants.
void advanceCoverages(doublereal tstep, double rtol=1.e-7, double atol=1.e-14, double maxStepSize=0, size_t maxSteps=20000, size_t maxErrTestFails=7)
Advance the surface coverages in time.
doublereal electrochem_beta(size_t irxn) const
Return the charge transfer rxn Beta parameter for the ith reaction.
bool m_has_exchange_current_density_formulation
Boolean flag indicating whether any reaction in the mechanism is described by an exchange current den...
virtual void resizeSpecies()
Resize arrays with sizes that depend on the total number of species.
Rate1< SurfaceArrhenius > m_rates
Templated class containing the vector of reactions for this interface.
virtual void addPhase(thermo_t &thermo)
Add a phase to the kinetics manager object.
A reaction occurring on an interface (i.e. a SurfPhase or an EdgePhase)
Definition: Reaction.h:213
bool is_sticking_coefficient
Set to true if rate is a parameterization of the sticking coefficient rather than the forward rate co...
Definition: Reaction.h:227
std::map< std::string, CoverageDependency > coverage_deps
Adjustments to the Arrhenius rate expression dependent on surface species coverages.
Definition: Reaction.h:223
std::string sticking_species
For reactions with multiple non-surface species, the sticking species needs to be explicitly identifi...
Definition: Reaction.h:237
bool use_motz_wise_correction
Set to true if rate is a sticking coefficient which should be translated into a rate coefficient usin...
Definition: Reaction.h:233
size_t reactionPhaseIndex() const
Phase where the reactions occur.
Definition: Kinetics.h:214
void checkPhaseIndex(size_t m) const
Check that the specified phase index is in range Throws an exception if m is greater than nPhases()
Definition: Kinetics.cpp:50
std::vector< size_t > m_start
m_start is a vector of integers specifying the beginning position for the species vector for the n'th...
Definition: Kinetics.h:900
ValueCache m_cache
Cache for saved calculations within each Kinetics object.
Definition: Kinetics.h:824
vector_fp m_ropnet
Net rate-of-progress for each reaction.
Definition: Kinetics.h:936
thermo_t & thermo(size_t n=0)
This method returns a reference to the nth ThermoPhase object defined in this kinetics mechanism.
Definition: Kinetics.h:227
size_t m_kk
The number of species in all of the phases that participate in this kinetics mechanism.
Definition: Kinetics.h:872
doublereal multiplier(size_t i) const
The current value of the multiplier for reaction i.
Definition: Kinetics.h:775
vector_fp m_perturb
Vector of perturbation factors for each reaction's rate of progress vector.
Definition: Kinetics.h:876
virtual void getReactionDelta(const doublereal *property, doublereal *deltaProperty)
Change in species properties.
Definition: Kinetics.cpp:388
size_t nPhases() const
The number of phases participating in the reaction mechanism.
Definition: Kinetics.h:167
vector_fp m_rkcn
Reciprocal of the equilibrium constant in concentration units.
Definition: Kinetics.h:927
vector_fp m_ropf
Forward rate-of-progress for each reaction.
Definition: Kinetics.h:930
virtual void getRevReactionDelta(const doublereal *g, doublereal *dg)
Given an array of species properties 'g', return in array 'dg' the change in this quantity in the rev...
Definition: Kinetics.cpp:398
vector_fp m_ropr
Reverse rate-of-progress for each reaction.
Definition: Kinetics.h:933
virtual bool addReaction(shared_ptr< Reaction > r)
Add a single reaction to the mechanism.
Definition: Kinetics.cpp:476
std::vector< thermo_t * > m_thermo
m_thermo is a vector of pointers to ThermoPhase objects that are involved with this kinetics operator
Definition: Kinetics.h:894
virtual void modifyReaction(size_t i, shared_ptr< Reaction > rNew)
Modify the rate expression associated with a reaction.
Definition: Kinetics.cpp:588
StoichManagerN m_revProductStoich
Stoichiometry manager for the products of reversible reactions.
Definition: Kinetics.h:864
size_t nReactions() const
Number of reactions in the reaction mechanism.
Definition: Kinetics.h:135
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition: Kinetics.h:261
vector_fp m_rfn
Forward rate constant for each reaction.
Definition: Kinetics.h:924
StoichManagerN m_reactantStoich
Stoichiometry manager for the reactants for each reaction.
Definition: Kinetics.h:861
size_t surfacePhaseIndex() const
This returns the integer index of the phase which has ThermoPhase type cSurf.
Definition: Kinetics.h:202
virtual void resizeSpecies()
Resize arrays with sizes that depend on the total number of species.
Definition: Kinetics.cpp:464
size_t nTotalSpecies() const
The total number of species in all phases participating in the kinetics mechanism.
Definition: Kinetics.h:239
virtual void addPhase(thermo_t &thermo)
Add a phase to the kinetics manager object.
Definition: Kinetics.cpp:445
size_t speciesPhaseIndex(size_t k) const
This function takes as an argument the kineticsSpecies index (i.e., the list index in the list of spe...
Definition: Kinetics.cpp:347
void getConcentrations(double *const c) const
Get the species concentrations (kmol/m^3).
Definition: Phase.cpp:625
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:285
doublereal charge(size_t k) const
Dimensionless electrical charge of a single molecule of species k The charge is normalized by the the...
Definition: Phase.h:643
size_t nDim() const
Returns the number of spatial dimensions (1, 2, or 3)
Definition: Phase.h:651
doublereal molecularWeight(size_t k) const
Molecular weight of species k.
Definition: Phase.cpp:521
doublereal temperature() const
Temperature (K).
Definition: Phase.h:667
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition: Phase.cpp:201
Composition orders
Forward reaction order with respect to specific species.
Definition: Reaction.h:57
bool reversible
True if the current reaction is reversible. False otherwise.
Definition: Reaction.h:64
Composition products
Product species and stoichiometric coefficients.
Definition: Reaction.h:52
Composition reactants
Reactant species and stoichiometric coefficients.
Definition: Reaction.h:49
int reaction_type
Type of the reaction.
Definition: Reaction.h:46
std::string equation() const
The chemical equation for this reaction.
Definition: Reaction.cpp:96
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
Definition: SurfPhase.h:143
void getCoverages(doublereal *theta) const
Return a vector of surface coverages.
Definition: SurfPhase.cpp:261
virtual double size(size_t k) const
Returns the number of sites occupied by one molecule of species k.
Definition: SurfPhase.h:327
doublereal siteDensity()
Returns the site density.
Definition: SurfPhase.h:322
An Arrhenius rate with coverage-dependent terms.
Definition: RxnRates.h:125
void addCoverageDependence(size_t k, doublereal a, doublereal m, doublereal e)
Add a coverage dependency for species k, with exponential dependence a, power-law exponent m,...
Definition: RxnRates.cpp:51
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:102
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: ThermoPhase.h:525
void setElectricPotential(doublereal v)
Set the electric potential of this phase (V).
Definition: ThermoPhase.h:312
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: ThermoPhase.h:515
doublereal RT() const
Return the Gas Constant multiplied by the current temperature.
Definition: ThermoPhase.h:776
virtual void getEnthalpy_RT(doublereal *hrt) const
Get the nondimensional Enthalpy functions for the species at their standard states at the current T a...
Definition: ThermoPhase.h:584
virtual doublereal logStandardConc(size_t k=0) const
Natural logarithm of the standard concentration of the kth species.
Definition: ThermoPhase.cpp:70
virtual void getEntropy_R(doublereal *sr) const
Get the array of nondimensional Entropy functions for the standard state species at the current T and...
Definition: ThermoPhase.h:594
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: ThermoPhase.h:398
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: ThermoPhase.h:419
void getElectrochemPotentials(doublereal *mu) const
Get the species electrochemical potentials.
Definition: ThermoPhase.cpp:91
virtual void getStandardChemPotentials(doublereal *mu) const
Get the array of chemical potentials at unit activity for the species at their standard states at the...
Definition: ThermoPhase.h:574
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:320
CachedArray getArray(int id)
Get a reference to a CachedValue object representing an array (vector_fp) with the given id.
Definition: ValueCache.h:171
int getId()
Get a unique id for a cached value.
Definition: ValueCache.cpp:21
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:188
const double Faraday
Faraday constant [C/kmol].
Definition: ct_defs.h:123
std::vector< double > vector_fp
Turn on the use of stl vectors for the basic array type within cantera Vector of doubles.
Definition: ct_defs.h:180
const double GasConstant
Universal Gas Constant [J/kmol/K].
Definition: ct_defs.h:109
const double Pi
Pi.
Definition: ct_defs.h:53
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:264
const U & getValue(const std::map< T, U > &m, const T &key, const U &default_val)
Const accessor for a value in a std::map.
Definition: utilities.h:528
const int BUTLERVOLMER_NOACTIVITYCOEFFS_RXN
This is a surface reaction that is formulated using the Butler-Volmer formulation and using concentra...
Definition: reaction_defs.h:83
const int BUTLERVOLMER_RXN
This is a surface reaction that is formulated using the Butler-Volmer formulation.
Definition: reaction_defs.h:90
const int GLOBAL_RXN
A global reaction.
const int SURFACEAFFINITY_RXN
This is a surface reaction that is formulated using the affinity representation, common in the geoche...
Definition: reaction_defs.h:97
Values used for converting sticking coefficients into rate constants.