Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
InterfaceKinetics.cpp
Go to the documentation of this file.
1 /**
2  * @file InterfaceKinetics.cpp
3  */
4 
5 // Copyright 2002 California Institute of Technology
6 
13 
14 #include <cstdio>
15 
16 using namespace std;
17 
18 namespace Cantera
19 {
20 
21 InterfaceKinetics::InterfaceKinetics(thermo_t* thermo) :
22  m_redo_rates(false),
23  m_nirrev(0),
24  m_nrev(0),
25  m_surf(0),
26  m_integrator(0),
27  m_logp0(0.0),
28  m_logc0(0.0),
29  m_ROP_ok(false),
30  m_temp(0.0),
31  m_logtemp(0.0),
32  m_finalized(false),
33  m_has_coverage_dependence(false),
34  m_has_electrochem_rxns(false),
35  m_has_exchange_current_density_formulation(false),
36  m_phaseExistsCheck(false),
37  m_ioFlag(0)
38 {
39  if (thermo != 0) {
40  addPhase(*thermo);
41  }
42 }
43 
45 {
46  delete m_integrator;
47 
48  for (size_t i = 0; i < m_ctrxn_ROPOrdersList_.size(); i++) {
49  delete m_ctrxn_ROPOrdersList_[i];
50  }
51  for (size_t i = 0; i < m_ctrxn_FwdOrdersList_.size(); i++) {
52  delete m_ctrxn_FwdOrdersList_[i];
53  }
54 }
55 
57 {
58  /*
59  * Call the assignment operator
60  */
61  operator=(right);
62 }
63 
65 {
66  /*
67  * Check for self assignment.
68  */
69  if (this == &right) {
70  return *this;
71  }
72 
73  Kinetics::operator=(right);
74 
75  m_grt = right.m_grt;
76  m_revindex = right.m_revindex;
77  m_rates = right.m_rates;
78  m_redo_rates = right.m_redo_rates;
79  m_irrev = right.m_irrev;
80  m_nirrev = right.m_nirrev;
81  m_nrev = right.m_nrev;
82  m_conc = right.m_conc;
83  m_actConc = right.m_actConc;
84  m_mu0 = right.m_mu0;
85  m_mu = right.m_mu;
86  m_mu0_Kc = right.m_mu0_Kc;
87  m_phi = right.m_phi;
88  m_pot = right.m_pot;
90  m_E = right.m_E;
91  m_surf = right.m_surf; //DANGER - shallow copy
92  m_integrator = right.m_integrator; //DANGER - shallow copy
93  m_beta = right.m_beta;
94  m_ctrxn = right.m_ctrxn;
96  m_ctrxn_ecdf = right.m_ctrxn_ecdf;
98  m_deltaG0 = right.m_deltaG0;
99  m_deltaG = right.m_deltaG;
101  m_logp0 = right.m_logp0;
102  m_logc0 = right.m_logc0;
103  m_ROP_ok = right.m_ROP_ok;
104  m_temp = right.m_temp;
105  m_logtemp = right.m_logtemp;
106  m_finalized = right.m_finalized;
115  m_ioFlag = right.m_ioFlag;
116 
117  for (size_t i = 0; i < m_ctrxn_ROPOrdersList_.size(); i++) {
118  delete m_ctrxn_ROPOrdersList_[i];
119  }
121  for (size_t i = 0; i < m_ctrxn_ROPOrdersList_.size(); i++) {
122  RxnOrders* ro = right.m_ctrxn_ROPOrdersList_[i];
123  m_ctrxn_ROPOrdersList_[i] = new RxnOrders(*ro);
124  }
125 
126  for (size_t i = 0; i < m_ctrxn_FwdOrdersList_.size(); i++) {
127  delete m_ctrxn_FwdOrdersList_[i];
128  }
130  for (size_t i = 0; i < m_ctrxn_FwdOrdersList_.size(); i++) {
131  RxnOrders* ro = right.m_ctrxn_FwdOrdersList_[i];
132  m_ctrxn_FwdOrdersList_[i] = new RxnOrders(*ro);
133  }
134 
135  return *this;
136 }
137 
139 {
140  return cInterfaceKinetics;
141 }
142 
143 Kinetics* InterfaceKinetics::duplMyselfAsKinetics(const std::vector<thermo_t*> & tpVector) const
144 {
145  InterfaceKinetics* iK = new InterfaceKinetics(*this);
146  iK->assignShallowPointers(tpVector);
147  return iK;
148 }
149 
151 {
153  m_redo_rates = true;
154 }
155 
157 {
158  // First task is update the electrical potentials from the Phases
162  m_rates.update_C(DATA_PTR(m_actConc));
163  m_redo_rates = true;
164  }
165 
166  // Go find the temperature from the surface
167  doublereal T = thermo(surfacePhaseIndex()).temperature();
168  m_redo_rates = true;
169  if (T != m_temp || m_redo_rates) {
170  m_logtemp = log(T);
171 
172  // Calculate the forward rate constant by calling m_rates and store it in m_rfn[]
173  m_rates.update(T, m_logtemp, DATA_PTR(m_rfn));
174  applyStickingCorrection(&m_rfn[0]);
175 
176  // If we need to do conversions between exchange current density formulation and regular formulation
177  // (either way) do it here.
180  }
183  }
184  m_temp = T;
185  updateKc();
186  m_ROP_ok = false;
187  m_redo_rates = false;
188  }
189 }
190 
192 {
193  // Store electric potentials for each phase in the array m_phi[].
194  for (size_t n = 0; n < nPhases(); n++) {
195  if (thermo(n).electricPotential() != m_phi[n]) {
196  m_phi[n] = thermo(n).electricPotential();
197  m_redo_rates = true;
198  }
199  }
200 }
201 
202 // Updates the internal variables m_actConc and m_conc
204 {
205  for (size_t n = 0; n < nPhases(); n++) {
206  const ThermoPhase* tp = m_thermo[n];
207  /*
208  * We call the getActivityConcentrations function of each
209  * ThermoPhase class that makes up this kinetics object to
210  * obtain the generalized concentrations for species within that
211  * class. This is collected in the vector m_conc. m_start[]
212  * are integer indices for that vector denoting the start of the
213  * species for each phase.
214  */
216 
217  // Get regular concentrations too
219  }
220  m_ROP_ok = false;
221 }
222 
224 {
225  _update_rates_C();
226  copy(m_actConc.begin(), m_actConc.end(), conc);
227 }
228 
230 {
231  fill(m_rkcn.begin(), m_rkcn.end(), 0.0);
232 
233  if (m_nrev > 0) {
234  /*
235  * Get the vector of standard state electrochemical potentials for species in the Interfacial
236  * kinetics object and store it in m_mu0[] and m_mu0_Kc[]
237  */
238  updateMu0();
239  doublereal rrt = 1.0 / (GasConstant * thermo(0).temperature());
240 
241  // compute Delta mu^0 for all reversible reactions
243 
244  for (size_t i = 0; i < m_nrev; i++) {
245  size_t irxn = m_revindex[i];
246  if (irxn == npos || irxn >= nReactions()) {
247  throw CanteraError("InterfaceKinetics", "illegal value: irxn = "+int2str(irxn));
248  }
249  // WARNING this may overflow HKM
250  m_rkcn[irxn] = exp(m_rkcn[irxn]*rrt);
251  }
252  for (size_t i = 0; i != m_nirrev; ++i) {
253  m_rkcn[ m_irrev[i] ] = 0.0;
254  }
255  }
256 }
257 
259 {
260  // First task is update the electrical potentials from the Phases
262 
264  /*
265  * Get the vector of standard state electrochemical potentials for species in the Interfacial
266  * kinetics object and store it in m_mu0[] and in m_mu0_Kc[]
267  */
268  size_t nsp, ik = 0;
269  doublereal rt = GasConstant * thermo(0).temperature();
270  size_t np = nPhases();
271  for (size_t n = 0; n < np; n++) {
273  nsp = thermo(n).nSpecies();
274  for (size_t k = 0; k < nsp; k++) {
275  m_mu0_Kc[ik] = m_mu0[ik] + Faraday * m_phi[n] * thermo(n).charge(k);
276  m_mu0_Kc[ik] -= rt * thermo(n).logStandardConc(k);
277  ik++;
278  }
279  }
280 }
281 
282 void InterfaceKinetics::checkPartialEquil()
283 {
284  // First task is update the electrical potentials from the Phases
286 
287  vector_fp dmu(nTotalSpecies(), 0.0);
288  vector_fp rmu(std::max<size_t>(nReactions(), 1), 0.0);
289  if (m_nrev > 0) {
290  doublereal rt = GasConstant*thermo(0).temperature();
291  cout << "T = " << thermo(0).temperature() << " " << rt << endl;
292  size_t nsp, ik=0;
293  doublereal delta;
294  for (size_t n = 0; n < nPhases(); n++) {
296  nsp = thermo(n).nSpecies();
297  for (size_t k = 0; k < nsp; k++) {
298  delta = Faraday * m_phi[n] * thermo(n).charge(k);
299  dmu[ik] += delta;
300  ik++;
301  }
302  }
303 
304  // compute Delta mu^ for all reversible reactions
306  updateROP();
307  for (size_t i = 0; i < m_nrev; i++) {
308  size_t irxn = m_revindex[i];
309  cout << "Reaction " << reactionString(irxn)
310  << " " << rmu[irxn]/rt << endl;
311  printf("%12.6e %12.6e %12.6e %12.6e \n",
312  m_ropf[irxn], m_ropr[irxn], m_ropnet[irxn],
313  m_ropnet[irxn]/(m_ropf[irxn] + m_ropr[irxn]));
314  }
315  }
316 }
317 
319 {
320  updateMu0();
321  doublereal rrt = 1.0 / (GasConstant * thermo(0).temperature());
322 
323  std::fill(kc, kc + m_ii, 0.0);
324 
326 
327  for (size_t i = 0; i < m_ii; i++) {
328  kc[i] = exp(-kc[i]*rrt);
329  }
330 }
331 
333 {
334  /*
335  * Calculate:
336  * - m_StandardConc[]
337  * - m_ProdStandConcReac[]
338  * - m_deltaG0[]
339  * - m_mu0[]
340  */
341 
342  /*
343  * First collect vectors of the standard Gibbs free energies of the
344  * species and the standard concentrations
345  * - m_mu0
346  * - m_StandardConc
347  */
348  size_t ik = 0;
349 
350  for (size_t n = 0; n < nPhases(); n++) {
352  size_t nsp = thermo(n).nSpecies();
353  for (size_t k = 0; k < nsp; k++) {
355  ik++;
356  }
357  }
358 
360 
361  // Calculate the product of the standard concentrations of the reactants
362  for (size_t i = 0; i < m_ii; i++) {
363  m_ProdStanConcReac[i] = 1.0;
364  }
366 }
367 
369 {
370  // Compute the electrical potential energy of each species
371  size_t ik = 0;
372  for (size_t n = 0; n < nPhases(); n++) {
373  size_t nsp = thermo(n).nSpecies();
374  for (size_t k = 0; k < nsp; k++) {
375  m_pot[ik] = Faraday * thermo(n).charge(k) * m_phi[n];
376  ik++;
377  }
378  }
379 
380  // Compute the change in electrical potential energy for each
381  // reaction. This will only be non-zero if a potential
382  // difference is present.
384 
385  // Modify the reaction rates. Only modify those with a
386  // non-zero activation energy. Below we decrease the
387  // activation energy below zero but in some debug modes
388  // we print out a warning message about this.
389  /*
390  * NOTE, there is some discussion about this point.
391  * Should we decrease the activation energy below zero?
392  * I don't think this has been decided in any definitive way.
393  * The treatment below is numerically more stable, however.
394  */
395  doublereal eamod;
396 #ifdef DEBUG_KIN_MODE
397  doublereal ea;
398 #endif
399  for (size_t i = 0; i < m_beta.size(); i++) {
400  size_t irxn = m_ctrxn[i];
401 
402  // If we calculate the BV form directly, we don't add the voltage correction to the
403  // forward reaction rate constants.
404  if (m_ctrxn_BVform[i] == 0) {
405  eamod = m_beta[i] * deltaElectricEnergy_[irxn];
406  if (eamod != 0.0) {
407 #ifdef DEBUG_KIN_MODE
408  ea = GasConstant * m_E[irxn];
409  if (eamod + ea < 0.0) {
410  writelog("Warning: act energy mod too large!\n");
411  writelog(" Delta phi = "+fp2str(deltaElectricEnergy_[irxn]/Faraday)+"\n");
412  writelog(" Delta Ea = "+fp2str(eamod)+"\n");
413  writelog(" Ea = "+fp2str(ea)+"\n");
414  for (n = 0; n < np; n++) {
415  writelog("Phase "+int2str(n)+": phi = "
416  +fp2str(m_phi[n])+"\n");
417  }
418  }
419 #endif
420  doublereal rt = GasConstant*thermo(0).temperature();
421  doublereal rrt = 1.0/rt;
422  kf[irxn] *= exp(-eamod*rrt);
423  }
424  }
425  }
426 }
427 
429 {
431  doublereal rt = GasConstant * thermo(0).temperature();
432  doublereal rrt = 1.0/rt;
433 
434  // Loop over all reactions which are defined to have a voltage transfer coefficient that
435  // affects the activity energy for the reaction
436  for (size_t i = 0; i < m_ctrxn.size(); i++) {
437  size_t irxn = m_ctrxn[i];
438 
439  // Determine whether the reaction rate constant is in an exchange current density formulation format.
440  int iECDFormulation = m_ctrxn_ecdf[i];
441  if (iECDFormulation) {
442  // If the BV form is to be converted into the normal form then we go through this process.
443  // If it isn't to be converted, then we don't go through this process.
444  //
445  // We need to have the straight chemical reaction rate constant to come out of this calculation.
446  if (m_ctrxn_BVform[i] == 0) {
447  //
448  // Calculate the term and modify the forward reaction
449  //
450  double tmp = exp(- m_beta[i] * m_deltaG0[irxn] * rrt);
451  double tmp2 = m_ProdStanConcReac[irxn];
452  tmp *= 1.0 / tmp2 / Faraday;
453  kfwd[irxn] *= tmp;
454  }
455  // If BVform is nonzero we don't need to do anything.
456 
457  } else {
458  // kfwd[] is the chemical reaction rate constant
459  //
460  // If we are to calculate the BV form directly, then we will do the reverse.
461  // We will calculate the exchange current density formulation here and
462  // substitute it.
463  if (m_ctrxn_BVform[i] != 0) {
464 
465  // Calculate the term and modify the forward reaction rate constant so that
466  // it's in the exchange current density formulation format
467  double tmp = exp(m_beta[i] * m_deltaG0[irxn] * rrt);
468  double tmp2 = m_ProdStanConcReac[irxn];
469  tmp *= Faraday * tmp2;
470  kfwd[irxn] *= tmp;
471  }
472  }
473  }
474 }
475 
477 {
478  updateROP();
479 
480  // copy rate coefficients into kfwd
481  copy(m_rfn.begin(), m_rfn.end(), kfwd);
482 
483  // multiply by perturbation factor
484  multiply_each(kfwd, kfwd + nReactions(), m_perturb.begin());
485 }
486 
487 void InterfaceKinetics::getRevRateConstants(doublereal* krev, bool doIrreversible)
488 {
489  getFwdRateConstants(krev);
490  if (doIrreversible) {
492  for (size_t i = 0; i < m_ii; i++) {
493  krev[i] /= m_ropnet[i];
494  }
495  } else {
496  multiply_each(krev, krev + nReactions(), m_rkcn.begin());
497  }
498 }
499 
501 {
502  // evaluate rate constants and equilibrium constants at temperature and phi (electric potential)
503  _update_rates_T();
504  // get updated activities (rates updated below)
505  _update_rates_C();
506 
507  if (m_ROP_ok) {
508  return;
509  }
510 
511  // Copy the reaction rate coefficients, m_rfn, into m_ropf
512  copy(m_rfn.begin(), m_rfn.end(), m_ropf.begin());
513 
514  // Multiply by the perturbation factor
515  multiply_each(m_ropf.begin(), m_ropf.end(), m_perturb.begin());
516  //
517  // Copy the forward rate constants to the reverse rate constants
518  //
519  copy(m_ropf.begin(), m_ropf.end(), m_ropr.begin());
520 
521  // For reverse rates computed from thermochemistry, multiply
522  // the forward rates copied into m_ropr by the reciprocals of
523  // the equilibrium constants
524  multiply_each(m_ropr.begin(), m_ropr.end(), m_rkcn.begin());
525 
526  // multiply ropf by the activity concentration reaction orders to obtain
527  // the forward rates of progress.
529 
530  // For reversible reactions, multiply ropr by the activity concentration products
532 
533  // Fix up these calculations for cases where the above formalism doesn't hold
534  double OCV = 0.0;
535  for (size_t jrxn = 0; jrxn != m_ii; ++jrxn) {
536  int reactionType = m_rxntype[jrxn];
537  if (reactionType == BUTLERVOLMER_RXN) {
538  //
539  // OK, the reaction rate constant contains the current density rate constant calculation
540  // the rxnstoich calculation contained the dependence of the current density on the activity concentrations
541  // We finish up with the ROP calculation
542  //
543  // Calculate the overpotential of the reaction
544  //
545  // double nStoichElectrons = - rmc->m_phaseChargeChange[metalPhaseRS_];
546  double nStoichElectrons=1;
547  //*nStoich = nStoichElectrons;
548 
549 
550 
551  getDeltaGibbs(0);
552 
553  if (nStoichElectrons != 0.0) {
554  OCV = m_deltaG[jrxn]/Faraday/ nStoichElectrons;
555  }
556 
557  /*
558 
559  double exp1 = nu * nStoich * beta / rtdf
560  double exp2 = -nu * nStoich * Faraday * (1.0 - beta) / (GasConstant * temp);
561  double val = io * (exp(exp1) - exp(exp2));
562 
563  doublereal BVterm = exp(exp1 ) - exp(exp2);
564  m_ropnet[j] = m_ropf[j] * BVterm
565  m_ropf[j] =
566  //
567  m_ropr[j] = m_ropnet[j] - m_ropf[j];
568  */
569  }
570  }
571 
572  for (size_t j = 0; j != m_ii; ++j) {
573  m_ropnet[j] = m_ropf[j] - m_ropr[j];
574  }
575 
576  /*
577  * For reactions involving multiple phases, we must check that the phase
578  * being consumed actually exists. This is particularly important for
579  * phases that are stoichiometric phases containing one species with a unity activity
580  */
581  if (m_phaseExistsCheck) {
582  for (size_t j = 0; j != m_ii; ++j) {
583  if ((m_ropr[j] > m_ropf[j]) && (m_ropr[j] > 0.0)) {
584  for (size_t p = 0; p < nPhases(); p++) {
585  if (m_rxnPhaseIsProduct[j][p]) {
586  if (! m_phaseExists[p]) {
587  m_ropnet[j] = 0.0;
588  m_ropr[j] = m_ropf[j];
589  if (m_ropf[j] > 0.0) {
590  for (size_t rp = 0; rp < nPhases(); rp++) {
591  if (m_rxnPhaseIsReactant[j][rp]) {
592  if (! m_phaseExists[rp]) {
593  m_ropnet[j] = 0.0;
594  m_ropr[j] = m_ropf[j] = 0.0;
595  }
596  }
597  }
598  }
599  }
600  }
601  if (m_rxnPhaseIsReactant[j][p]) {
602  if (! m_phaseIsStable[p]) {
603  m_ropnet[j] = 0.0;
604  m_ropr[j] = m_ropf[j];
605  }
606  }
607  }
608  } else if ((m_ropf[j] > m_ropr[j]) && (m_ropf[j] > 0.0)) {
609  for (size_t p = 0; p < nPhases(); p++) {
610  if (m_rxnPhaseIsReactant[j][p]) {
611  if (! m_phaseExists[p]) {
612  m_ropnet[j] = 0.0;
613  m_ropf[j] = m_ropr[j];
614  if (m_ropf[j] > 0.0) {
615  for (size_t rp = 0; rp < nPhases(); rp++) {
616  if (m_rxnPhaseIsProduct[j][rp]) {
617  if (! m_phaseExists[rp]) {
618  m_ropnet[j] = 0.0;
619  m_ropf[j] = m_ropr[j] = 0.0;
620  }
621  }
622  }
623  }
624  }
625  }
626  if (m_rxnPhaseIsProduct[j][p]) {
627  if (! m_phaseIsStable[p]) {
628  m_ropnet[j] = 0.0;
629  m_ropf[j] = m_ropr[j];
630  }
631  }
632  }
633  }
634  }
635  }
636 
637  m_ROP_ok = true;
638 }
639 
640 void InterfaceKinetics::getDeltaGibbs(doublereal* deltaG)
641 {
642  /*
643  * Get the chemical potentials of the species in the all of the phases used in the
644  * kinetics mechanism
645  */
646  for (size_t n = 0; n < nPhases(); n++) {
647  m_thermo[n]->getChemPotentials(DATA_PTR(m_mu) + m_start[n]);
648  }
649 
650  // Use the stoichiometric manager to find deltaG for each reaction.
652  if (deltaG != 0 && (DATA_PTR(m_deltaG) != deltaG)) {
653  for (size_t j = 0; j < m_ii; ++j) {
654  deltaG[j] = m_deltaG[j];
655  }
656  }
657 }
658 
660 {
661  /*
662  * Get the chemical potentials of the species
663  */
664  size_t np = nPhases();
665  for (size_t n = 0; n < np; n++) {
667  }
668  /*
669  * Use the stoichiometric manager to find deltaG for each
670  * reaction.
671  */
672  getReactionDelta(DATA_PTR(m_grt), deltaM);
673 }
674 
675 void InterfaceKinetics::getDeltaEnthalpy(doublereal* deltaH)
676 {
677  /*
678  * Get the partial molar enthalpy of all species
679  */
680  for (size_t n = 0; n < nPhases(); n++) {
682  }
683  /*
684  * Use the stoichiometric manager to find deltaG for each
685  * reaction.
686  */
687  getReactionDelta(DATA_PTR(m_grt), deltaH);
688 }
689 
690 void InterfaceKinetics::getDeltaEntropy(doublereal* deltaS)
691 {
692  /*
693  * Get the partial molar entropy of all species in all of
694  * the phases
695  */
696  for (size_t n = 0; n < nPhases(); n++) {
698  }
699  /*
700  * Use the stoichiometric manager to find deltaS for each
701  * reaction.
702  */
703  getReactionDelta(DATA_PTR(m_grt), deltaS);
704 }
705 
706 void InterfaceKinetics::getDeltaSSGibbs(doublereal* deltaGSS)
707 {
708  /*
709  * Get the standard state chemical potentials of the species.
710  * This is the array of chemical potentials at unit activity
711  * We define these here as the chemical potentials of the pure
712  * species at the temperature and pressure of the solution.
713  */
714  for (size_t n = 0; n < nPhases(); n++) {
716  }
717  /*
718  * Use the stoichiometric manager to find deltaG for each
719  * reaction.
720  */
721  getReactionDelta(DATA_PTR(m_mu0), deltaGSS);
722 }
723 
725 {
726  /*
727  * Get the standard state enthalpies of the species.
728  * This is the array of chemical potentials at unit activity
729  * We define these here as the enthalpies of the pure
730  * species at the temperature and pressure of the solution.
731  */
732  for (size_t n = 0; n < nPhases(); n++) {
734  }
735  doublereal RT = thermo(0).temperature() * GasConstant;
736  for (size_t k = 0; k < m_kk; k++) {
737  m_grt[k] *= RT;
738  }
739  /*
740  * Use the stoichiometric manager to find deltaG for each
741  * reaction.
742  */
743  getReactionDelta(DATA_PTR(m_grt), deltaH);
744 }
745 
746 void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS)
747 {
748  /*
749  * Get the standard state entropy of the species.
750  * We define these here as the entropies of the pure
751  * species at the temperature and pressure of the solution.
752  */
753  for (size_t n = 0; n < nPhases(); n++) {
755  }
756  doublereal R = GasConstant;
757  for (size_t k = 0; k < m_kk; k++) {
758  m_grt[k] *= R;
759  }
760  /*
761  * Use the stoichiometric manager to find deltaS for each
762  * reaction.
763  */
764  getReactionDelta(DATA_PTR(m_grt), deltaS);
765 }
766 
768 {
769  int reactionType = r.reactionType;
770 
771  // Install rate coeff calculator
772  if (r.cov.size() > 3) {
774  }
775  for (size_t m = 0; m < r.cov.size(); m++) {
776  r.rateCoeffParameters.push_back(r.cov[m]);
777  }
778 
779  /*
780  * Temporarily change the reaction rate coefficient type to surface arrhenius.
781  * This is what is expected. We'll handle exchange current types below by hand.
782  */
783  int reactionRateCoeffType_orig = r.rateCoeffType;
784  if (r.rateCoeffType == EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE) {
785  r.rateCoeffType = SURF_ARRHENIUS_REACTION_RATECOEFF_TYPE;
786  }
787  if (r.rateCoeffType == ARRHENIUS_REACTION_RATECOEFF_TYPE) {
788  r.rateCoeffType = SURF_ARRHENIUS_REACTION_RATECOEFF_TYPE;
789  }
790  /*
791  * Install the reaction rate into the vector of reactions handled by this class
792  */
793  m_rates.install(m_ii, r);
794 
795  /*
796  * Change the reaction rate coefficient type back to its original value
797  */
798  r.rateCoeffType = reactionRateCoeffType_orig;
799 
800  // Store activation energy
801  m_E.push_back(r.rateCoeffParameters[2]);
802 
803  if (r.beta > 0.0) {
804  m_has_electrochem_rxns = true;
805  m_beta.push_back(r.beta);
806  m_ctrxn.push_back(m_ii);
807  if (r.rateCoeffType == EXCHANGE_CURRENT_REACTION_RATECOEFF_TYPE) {
809  m_ctrxn_ecdf.push_back(1);
810  } else {
811  m_ctrxn_ecdf.push_back(0);
812  }
813  m_ctrxn_resistivity_.push_back(r.filmResistivity);
814 
815  if (reactionType == BUTLERVOLMER_NOACTIVITYCOEFFS_RXN ||
816  reactionType == BUTLERVOLMER_RXN ||
817  reactionType == SURFACEAFFINITY_RXN ||
818  reactionType == GLOBAL_RXN) {
819  // Specify alternative forms of the electrochemical reaction
820  if (r.reactionType == BUTLERVOLMER_RXN) {
821  m_ctrxn_BVform.push_back(1);
823  m_ctrxn_BVform.push_back(2);
824  } else {
825  // set the default to be the normal forward / reverse calculation method
826  m_ctrxn_BVform.push_back(0);
827  }
828  if (r.forwardFullOrder_.size() > 0) {
829  RxnOrders* ro = new RxnOrders();
830  ro->fill(r.forwardFullOrder_);
831  m_ctrxn_ROPOrdersList_.push_back(ro);
832  m_ctrxn_FwdOrdersList_.push_back(0);
833 
834  // Fill in the Fwd Orders dependence here for B-V reactions
837  vector_fp fwdFullorders(m_kk, 0.0);
838  determineFwdOrdersBV(r, fwdFullorders);
839  RxnOrders* ro = new RxnOrders();
840  ro->fill(fwdFullorders);
842  }
843  } else {
844  m_ctrxn_ROPOrdersList_.push_back(0);
845  m_ctrxn_FwdOrdersList_.push_back(0);
846  }
847 
848  } else {
849  m_ctrxn_BVform.push_back(0);
850  m_ctrxn_ROPOrdersList_.push_back(0);
851  m_ctrxn_FwdOrdersList_.push_back(0);
852  if (r.filmResistivity > 0.0) {
853  throw CanteraError("InterfaceKinetics::addReaction()",
854  "film resistivity set for elementary reaction");
855  }
856  }
857  }
858 
859  if (r.reversible) {
860  m_revindex.push_back(nReactions());
861  m_nrev++;
862  } else {
863  m_irrev.push_back(nReactions());
864  m_nirrev++;
865  }
867 
868  m_rxnPhaseIsReactant.push_back(std::vector<bool>(nPhases(), false));
869  m_rxnPhaseIsProduct.push_back(std::vector<bool>(nPhases(), false));
870 
871  size_t i = m_ii - 1;
872  for (size_t ik = 0; ik < r.reactants.size(); ik++) {
873  size_t k = r.reactants[ik];
874  size_t p = speciesPhaseIndex(k);
875  m_rxnPhaseIsReactant[i][p] = true;
876  }
877  for (size_t ik = 0; ik < r.products.size(); ik++) {
878  size_t k = r.products[ik];
879  size_t p = speciesPhaseIndex(k);
880  m_rxnPhaseIsProduct[i][p] = true;
881  }
882 }
883 
884 bool InterfaceKinetics::addReaction(shared_ptr<Reaction> r_base)
885 {
886  size_t i = nReactions();
887  bool added = Kinetics::addReaction(r_base);
888  if (!added) {
889  return false;
890  }
891 
892  InterfaceReaction& r = dynamic_cast<InterfaceReaction&>(*r_base);
894  m_rates.install(i, rate);
895 
896  // Turn on the global flag indicating surface coverage dependence
897  if (!r.coverage_deps.empty()) {
899  }
900 
901  // Store activation energy
902  m_E.push_back(rate.activationEnergy_R());
903 
904  ElectrochemicalReaction* re = dynamic_cast<ElectrochemicalReaction*>(&r);
905  if (re) {
906  m_has_electrochem_rxns = true;
907  m_beta.push_back(re->beta);
908  m_ctrxn.push_back(i);
909  if (re->exchange_current_density_formulation) {
911  m_ctrxn_ecdf.push_back(1);
912  } else {
913  m_ctrxn_ecdf.push_back(0);
914  }
915  m_ctrxn_resistivity_.push_back(re->film_resistivity);
916 
920  r.reaction_type == GLOBAL_RXN) {
921  // Specify alternative forms of the electrochemical reaction
922  if (r.reaction_type == BUTLERVOLMER_RXN) {
923  m_ctrxn_BVform.push_back(1);
925  m_ctrxn_BVform.push_back(2);
926  } else {
927  // set the default to be the normal forward / reverse calculation method
928  m_ctrxn_BVform.push_back(0);
929  }
930  if (!r.orders.empty()) {
931  vector_fp orders(nTotalSpecies(), 0.0);
932  for (Composition::const_iterator iter = r.orders.begin();
933  iter != r.orders.end();
934  ++iter) {
935  orders[kineticsSpeciesIndex(iter->first)] = iter->second;
936  }
937  RxnOrders* ro = new RxnOrders();
938  ro->fill(orders);
939  m_ctrxn_ROPOrdersList_.push_back(ro);
940  m_ctrxn_FwdOrdersList_.push_back(0);
941 
942  // Fill in the Fwd Orders dependence here for B-V reactions
945  vector_fp fwdFullorders(m_kk, 0.0);
946  determineFwdOrdersBV(*re, fwdFullorders);
947  RxnOrders* ro = new RxnOrders();
948  ro->fill(fwdFullorders);
949  m_ctrxn_FwdOrdersList_[i] = ro;
950  }
951  } else {
952  m_ctrxn_ROPOrdersList_.push_back(0);
953  m_ctrxn_FwdOrdersList_.push_back(0);
954  }
955 
956  } else {
957  m_ctrxn_BVform.push_back(0);
958  m_ctrxn_ROPOrdersList_.push_back(0);
959  m_ctrxn_FwdOrdersList_.push_back(0);
960  if (re->film_resistivity > 0.0) {
961  throw CanteraError("InterfaceKinetics::addReaction()",
962  "film resistivity set for elementary reaction");
963  }
964  }
965  }
966 
967  if (r.reversible) {
968  m_revindex.push_back(i);
969  m_nrev++;
970  } else {
971  m_irrev.push_back(i);
972  m_nirrev++;
973  }
974 
975  m_rxnPhaseIsReactant.push_back(std::vector<bool>(nPhases(), false));
976  m_rxnPhaseIsProduct.push_back(std::vector<bool>(nPhases(), false));
977 
978  for (Composition::const_iterator iter = r.reactants.begin();
979  iter != r.reactants.end();
980  ++iter) {
981  size_t k = kineticsSpeciesIndex(iter->first);
982  size_t p = speciesPhaseIndex(k);
983  m_rxnPhaseIsReactant[i][p] = true;
984  }
985  for (Composition::const_iterator iter = r.products.begin();
986  iter != r.products.end();
987  ++iter) {
988  size_t k = kineticsSpeciesIndex(iter->first);
989  size_t p = speciesPhaseIndex(k);
990  m_rxnPhaseIsProduct[i][p] = true;
991  }
992  return true;
993 }
994 
995 void InterfaceKinetics::modifyReaction(size_t i, shared_ptr<Reaction> r_base)
996 {
997  Kinetics::modifyReaction(i, r_base);
998  InterfaceReaction& r = dynamic_cast<InterfaceReaction&>(*r_base);
1000  m_rates.replace(i, rate);
1001 
1002  // Invalidate cached data
1003  m_redo_rates = true;
1004  m_temp += 0.1;
1005 }
1006 
1008  size_t i, InterfaceReaction& r)
1009 {
1010  double A_rate = r.rate.preExponentialFactor();
1011  double b_rate = r.rate.temperatureExponent();
1012 
1013  if (r.is_sticking_coefficient) {
1014  // Identify the interface phase
1015  size_t iInterface = npos;
1016  size_t min_dim = 4;
1017  for (size_t n = 0; n < nPhases(); n++) {
1018  if (thermo(n).nDim() < min_dim) {
1019  iInterface = n;
1020  min_dim = thermo(n).nDim();
1021  }
1022  }
1023 
1024  b_rate += 0.5;
1025  std::string sticking_species = r.sticking_species;
1026  if (sticking_species == "") {
1027  // Identify the sticking species if not explicitly given
1028  bool foundStick = false;
1029  for (Composition::const_iterator iter = r.reactants.begin();
1030  iter != r.reactants.end();
1031  ++iter) {
1032  size_t iPhase = speciesPhaseIndex(kineticsSpeciesIndex(iter->first));
1033  if (iPhase != iInterface) {
1034  // Non-interface species. There should be exactly one of these
1035  if (foundStick) {
1036  throw CanteraError("InterfaceKinetics::addReaction",
1037  "Multiple non-interface species found"
1038  "in sticking reaction: '" + r.equation() + "'");
1039  }
1040  foundStick = true;
1041  sticking_species = iter->first;
1042  }
1043  }
1044  if (!foundStick) {
1045  throw CanteraError("InterfaceKinetics::addReaction",
1046  "No non-interface species found"
1047  "in sticking reaction: '" + r.equation() + "'");
1048  }
1049  }
1050 
1051  double surface_order = 0.0;
1052  // Adjust the A-factor
1053  for (Composition::const_iterator iter = r.reactants.begin();
1054  iter != r.reactants.end();
1055  ++iter) {
1056  size_t iPhase = speciesPhaseIndex(kineticsSpeciesIndex(iter->first));
1057  const ThermoPhase& p = thermo(iPhase);
1058  const ThermoPhase& surf = thermo(surfacePhaseIndex());
1059  size_t k = p.speciesIndex(iter->first);
1060  if (iter->first == sticking_species) {
1061  A_rate *= sqrt(GasConstant/(2*Pi*p.molecularWeight(k)));
1062  } else {
1063  // Non-sticking species. Convert from coverages used in the
1064  // sticking probability expression to the concentration units
1065  // used in the mass action rate expression. For surface phases,
1066  // the dependence on the site density is incorporated when the
1067  // rate constant is evaluated, since we don't assume that the
1068  // site density is known at this time.
1069  double order = getValue(r.orders, iter->first, iter->second);
1070  if (&p == &surf) {
1071  A_rate *= pow(p.size(k), order);
1072  surface_order += order;
1073  } else {
1074  A_rate *= pow(p.standardConcentration(k), -order);
1075  }
1076  }
1077  }
1078  if (i != npos) {
1079  m_sticking_orders.push_back(make_pair(i, surface_order));
1080  }
1081  }
1082 
1083  SurfaceArrhenius rate(A_rate, b_rate, r.rate.activationEnergy_R());
1084 
1085  // Set up coverage dependencies
1086  for (map<string, CoverageDependency>::const_iterator iter = r.coverage_deps.begin();
1087  iter != r.coverage_deps.end();
1088  ++iter) {
1089  size_t k = thermo(reactionPhaseIndex()).speciesIndex(iter->first);
1090  rate.addCoverageDependence(k, iter->second.a, iter->second.m, iter->second.E);
1091  }
1092 
1093  return rate;
1094 }
1095 
1096 void InterfaceKinetics::setIOFlag(int ioFlag)
1097 {
1098  m_ioFlag = ioFlag;
1099  if (m_integrator) {
1100  m_integrator->setIOFlag(ioFlag);
1101  }
1102 }
1103 
1105 {
1106  Kinetics::addPhase(thermo);
1107  m_phaseExists.push_back(true);
1108  m_phaseIsStable.push_back(true);
1109 }
1110 
1112 {
1113  m_kk = 0;
1114  for (size_t n = 0; n < nPhases(); n++) {
1115  m_kk += thermo(n).nSpecies();
1116  }
1117  m_rrxn.resize(m_kk);
1118  m_prxn.resize(m_kk);
1119  m_actConc.resize(m_kk);
1120  m_conc.resize(m_kk);
1121  m_mu0.resize(m_kk);
1122  m_mu.resize(m_kk);
1123  m_mu0_Kc.resize(m_kk);
1124  m_grt.resize(m_kk);
1125  m_pot.resize(m_kk, 0.0);
1126  m_phi.resize(nPhases(), 0.0);
1127 }
1128 
1130 {
1132  size_t safe_reaction_size = std::max<size_t>(m_ii, 1);
1133  deltaElectricEnergy_.resize(safe_reaction_size);
1134  size_t ks = reactionPhaseIndex();
1135  if (ks == npos) throw CanteraError("InterfaceKinetics::finalize",
1136  "no surface phase is present.");
1137 
1138  // Check to see that the interface routine has a dimension of 2
1139  m_surf = (SurfPhase*)&thermo(ks);
1140  if (m_surf->nDim() != 2) {
1141  throw CanteraError("InterfaceKinetics::finalize",
1142  "expected interface dimension = 2, but got dimension = "
1143  +int2str(m_surf->nDim()));
1144  }
1145  m_StandardConc.resize(m_kk, 0.0);
1146  m_deltaG0.resize(safe_reaction_size, 0.0);
1147  m_deltaG.resize(safe_reaction_size, 0.0);
1148 
1149  m_ProdStanConcReac.resize(safe_reaction_size, 0.0);
1150 
1151  if (m_thermo.size() != m_phaseExists.size()) {
1152  throw CanteraError("InterfaceKinetics::finalize", "internal error");
1153  }
1154 
1155  // Guarantee that these arrays can be converted to double* even in the
1156  // special case where there are no reactions defined.
1157  if (!m_ii) {
1158  m_perturb.resize(1, 1.0);
1159  m_ropf.resize(1, 0.0);
1160  m_ropr.resize(1, 0.0);
1161  m_ropnet.resize(1, 0.0);
1162  m_rkcn.resize(1, 0.0);
1163  }
1164 
1165  m_finalized = true;
1166 }
1167 
1168 doublereal InterfaceKinetics::electrochem_beta(size_t irxn) const
1169 {
1170  for (size_t i = 0; i < m_ctrxn.size(); i++) {
1171  if (m_ctrxn[i] == irxn) {
1172  return m_beta[i];
1173  }
1174  }
1175  return 0.0;
1176 }
1177 
1179 {
1180  return m_finalized;
1181 }
1182 
1184 {
1185  if (m_integrator == 0) {
1186  vector<InterfaceKinetics*> k;
1187  k.push_back(this);
1188  m_integrator = new ImplicitSurfChem(k);
1190  }
1191  m_integrator->integrate(0.0, tstep);
1192  delete m_integrator;
1193  m_integrator = 0;
1194 }
1195 
1197  int ifuncOverride, doublereal timeScaleOverride)
1198 {
1199  // create our own solver object
1200  if (m_integrator == 0) {
1201  vector<InterfaceKinetics*> k;
1202  k.push_back(this);
1203  m_integrator = new ImplicitSurfChem(k);
1205  }
1206  m_integrator->setIOFlag(m_ioFlag);
1207  /*
1208  * New direct method to go here
1209  */
1210  m_integrator->solvePseudoSteadyStateProblem(ifuncOverride, timeScaleOverride);
1211 }
1212 
1213 void InterfaceKinetics::setPhaseExistence(const size_t iphase, const int exists)
1214 {
1215  if (iphase >= m_thermo.size()) {
1216  throw CanteraError("InterfaceKinetics:setPhaseExistence", "out of bounds");
1217  }
1218  if (exists) {
1219  if (!m_phaseExists[iphase]) {
1221  m_phaseExistsCheck = std::max(m_phaseExistsCheck, 0);
1222  m_phaseExists[iphase] = true;
1223  }
1224  m_phaseIsStable[iphase] = true;
1225  } else {
1226  if (m_phaseExists[iphase]) {
1228  m_phaseExists[iphase] = false;
1229  }
1230  m_phaseIsStable[iphase] = false;
1231  }
1232 }
1233 
1234 int InterfaceKinetics::phaseExistence(const size_t iphase) const
1235 {
1236  if (iphase >= m_thermo.size()) {
1237  throw CanteraError("InterfaceKinetics:phaseExistence()", "out of bounds");
1238  }
1239  return m_phaseExists[iphase];
1240 }
1241 
1242 int InterfaceKinetics::phaseStability(const size_t iphase) const
1243 {
1244  if (iphase >= m_thermo.size()) {
1245  throw CanteraError("InterfaceKinetics:phaseStability()", "out of bounds");
1246  }
1247  return m_phaseIsStable[iphase];
1248 }
1249 
1250 void InterfaceKinetics::setPhaseStability(const size_t iphase, const int isStable)
1251 {
1252  if (iphase >= m_thermo.size()) {
1253  throw CanteraError("InterfaceKinetics:setPhaseStability", "out of bounds");
1254  }
1255  if (isStable) {
1256  m_phaseIsStable[iphase] = true;
1257  } else {
1258  m_phaseIsStable[iphase] = false;
1259  }
1260 }
1261 
1262 void InterfaceKinetics::determineFwdOrdersBV(ReactionData& rdata, std::vector<doublereal>& fwdFullorders)
1263 {
1264  // Start out with the full ROP orders vector.
1265  // This vector will have the BV exchange current density orders in it.
1266  fwdFullorders = rdata.forwardFullOrder_;
1267 
1268  // forward and reverse beta values
1269  double betaf = rdata.beta;
1270 
1271  // Loop over the reactants doing away with the BV terms.
1272  // This should leave the reactant terms only, even if they are non-mass action.
1273  for (size_t j = 0; j < rdata.reactants.size(); j++) {
1274  size_t kkin = rdata.reactants[j];
1275  double oo = rdata.rstoich[j];
1276  fwdFullorders[kkin] += betaf * oo;
1277  // just to make sure roundoff doesn't leave a term that should be zero (haven't checked this out yet)
1278  if (abs(fwdFullorders[kkin]) < 0.00001) {
1279  fwdFullorders[kkin] = 0.0;
1280  }
1281  }
1282 
1283  // Loop over the products doing away with the BV terms.
1284  // This should leave the reactant terms only, even if they are non-mass action.
1285  for (size_t j = 0; j < rdata.products.size(); j++) {
1286  size_t kkin = rdata.products[j];
1287  double oo = rdata.pstoich[j];
1288  fwdFullorders[kkin] -= betaf * oo;
1289  if (abs(fwdFullorders[kkin]) < 0.00001) {
1290  fwdFullorders[kkin] = 0.0;
1291  }
1292  }
1293 }
1294 
1295 void InterfaceKinetics::determineFwdOrdersBV(ElectrochemicalReaction& r, std::vector<doublereal>& fwdFullOrders)
1296 {
1297  // Start out with the full ROP orders vector.
1298  // This vector will have the BV exchange current density orders in it.
1299  fwdFullOrders.assign(nTotalSpecies(), 0.0);
1300  for (Composition::const_iterator iter = r.orders.begin();
1301  iter != r.orders.end();
1302  ++iter) {
1303  fwdFullOrders[kineticsSpeciesIndex(iter->first)] = iter->second;
1304  }
1305 
1306  // forward and reverse beta values
1307  double betaf = r.beta;
1308 
1309  // Loop over the reactants doing away with the BV terms.
1310  // This should leave the reactant terms only, even if they are non-mass action.
1311  for (Composition::const_iterator iter = r.reactants.begin();
1312  iter != r.reactants.end();
1313  ++iter) {
1314  size_t k = kineticsSpeciesIndex(iter->first);
1315  fwdFullOrders[k] += betaf * iter->second;
1316  // just to make sure roundoff doesn't leave a term that should be zero (haven't checked this out yet)
1317  if (abs(fwdFullOrders[k]) < 0.00001) {
1318  fwdFullOrders[k] = 0.0;
1319  }
1320  }
1321 
1322  // Loop over the products doing away with the BV terms.
1323  // This should leave the reactant terms only, even if they are non-mass action.
1324  for (Composition::const_iterator iter = r.products.begin();
1325  iter != r.products.end();
1326  ++iter) {
1327  size_t k = kineticsSpeciesIndex(iter->first);
1328  fwdFullOrders[k] -= betaf * iter->second;
1329  // just to make sure roundoff doesn't leave a term that should be zero (haven't checked this out yet)
1330  if (abs(fwdFullOrders[k]) < 0.00001) {
1331  fwdFullOrders[k] = 0.0;
1332  }
1333  }
1334 }
1335 
1336 void InterfaceKinetics::applyStickingCorrection(double* kf)
1337 {
1338  if (m_sticking_orders.empty()) {
1339  return;
1340  }
1341 
1342  static const int cacheId = m_cache.getId();
1343  CachedArray cached = m_cache.getArray(cacheId);
1344  vector_fp& factors = cached.value;
1345 
1346  SurfPhase& surf = dynamic_cast<SurfPhase&>(thermo(reactionPhaseIndex()));
1347  double n0 = surf.siteDensity();
1348  if (!cached.validate(n0)) {
1349  factors.resize(m_sticking_orders.size());
1350  for (size_t n = 0; n < m_sticking_orders.size(); n++) {
1351  factors[n] = pow(n0, -m_sticking_orders[n].second);
1352  }
1353  }
1354 
1355  for (size_t n = 0; n < m_sticking_orders.size(); n++) {
1356  kf[m_sticking_orders[n].first] *= factors[n];
1357  }
1358 }
1359 
1360 
1362 {
1363  // Note we can't call the Interface::finalize() routine because we need to check for a dimension of 1 below.
1364  // Therefore, we have to malloc room in arrays that would normally be
1365  // handled by the InterfaceKinetics::finalize() call.
1367 
1368  size_t safe_reaction_size = std::max<size_t>(m_ii, 1);
1369  deltaElectricEnergy_.resize(safe_reaction_size);
1370  size_t ks = reactionPhaseIndex();
1371  if (ks == npos) throw CanteraError("EdgeKinetics::finalize",
1372  "no surface phase is present.");
1373 
1374  // Check to see edge phase has a dimension of 1
1375  m_surf = (SurfPhase*)&thermo(ks);
1376  if (m_surf->nDim() != 1) {
1377  throw CanteraError("EdgeKinetics::finalize",
1378  "expected interface dimension = 1, but got dimension = "
1379  +int2str(m_surf->nDim()));
1380  }
1381  m_StandardConc.resize(m_kk, 0.0);
1382  m_deltaG0.resize(safe_reaction_size, 0.0);
1383  m_deltaG.resize(safe_reaction_size, 0.0);
1384 
1385  m_ProdStanConcReac.resize(safe_reaction_size, 0.0);
1386 
1387  if (m_thermo.size() != m_phaseExists.size()) {
1388  throw CanteraError("InterfaceKinetics::finalize", "internal error");
1389  }
1390 
1391  // Guarantee that these arrays can be converted to double* even in the
1392  // special case where there are no reactions defined.
1393  if (!m_ii) {
1394  m_perturb.resize(1, 1.0);
1395  m_ropf.resize(1, 0.0);
1396  m_ropr.resize(1, 0.0);
1397  m_ropnet.resize(1, 0.0);
1398  m_rkcn.resize(1, 0.0);
1399  }
1400 
1401  m_finalized = true;
1402 }
1403 
1404 RxnOrders::RxnOrders(const RxnOrders& right) :
1405  kinSpeciesIDs_(right.kinSpeciesIDs_),
1406  kinSpeciesOrders_(right.kinSpeciesOrders_)
1407 {
1408 }
1409 
1410 RxnOrders& RxnOrders::operator=(const RxnOrders& right)
1411 {
1412  if (this == &right) {
1413  return *this;
1414  }
1415  kinSpeciesIDs_ = right.kinSpeciesIDs_;
1416  kinSpeciesOrders_ = right.kinSpeciesOrders_;
1417  return *this;
1418 }
1419 
1420 int RxnOrders::fill(const std::vector<doublereal>& fullForwardOrders)
1421 {
1422  int nzeroes = 0;
1423  kinSpeciesIDs_.clear();
1424  kinSpeciesOrders_.clear();
1425  for (size_t k = 0; k < fullForwardOrders.size(); ++k) {
1426  if (fullForwardOrders[k] != 0.0) {
1427  kinSpeciesIDs_.push_back(k);
1428  kinSpeciesOrders_.push_back(fullForwardOrders[k]);
1429  ++nzeroes;
1430  }
1431  }
1432  return nzeroes;
1433 }
1434 
1435 }
virtual void modifyReaction(size_t i, shared_ptr< Reaction > rNew)
Modify the rate expression associated with a reaction.
Definition: Kinetics.cpp:773
const std::string & reactionString(size_t i) const
Return a string representing the reaction.
Definition: Kinetics.h:706
doublereal molecularWeight(size_t k) const
Molecular weight of species k.
Definition: Phase.cpp:494
std::string sticking_species
For reactions with multiple non-surface species, the sticking species needs to be explicitly identifi...
Definition: Reaction.h:223
void applyVoltageKfwdCorrection(doublereal *const kfwd)
Apply modifications for the forward reaction rate for interfacial charge transfer reactions...
StoichManagerN m_revProductStoich
Stoichiometry manager for the products of reversible reactions.
Definition: Kinetics.h:971
void setElectricPotential(int n, doublereal V)
Set the electric potential in the nth phase.
int phaseStability(const size_t iphase) const
Gets the phase stability int for the ith phase.
vector_fp m_deltaG0
Vector of delta G^0, the standard state Gibbs free energies for each reaction.
std::string int2str(const int n, const std::string &fmt)
Convert an int to a string using a format converter.
Definition: stringUtils.cpp:39
vector_fp m_ropr
Reverse rate-of-progress for each reaction.
Definition: Kinetics.h:1107
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:1056
doublereal electricPotential() const
Returns the electric potential of this phase (V).
Definition: ThermoPhase.h:352
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:219
int getId()
Get a unique id for a cached value.
Definition: ValueCache.cpp:18
int reaction_type
Type of the reaction.
Definition: Reaction.h:43
virtual bool ready() const
Returns true if the kinetics manager has been properly initialized and finalized. ...
Header for a simple thermodynamics model of a surface phase derived from ThermoPhase, assuming an ideal solution model (see Thermodynamic Properties and class SurfPhase).
doublereal m_logtemp
Current log of the temperature.
virtual void getDeltaEnthalpy(doublereal *deltaH)
Return the vector of values for the reactions change in enthalpy.
int reactionType
Type of the reaction.
Definition: ReactionData.h:58
virtual void assignShallowPointers(const std::vector< thermo_t * > &tpVector)
Reassign the pointers within the Kinetics object.
Definition: Kinetics.cpp:140
doublereal electrochem_beta(size_t irxn) const
Return the charge transfer rxn Beta parameter for the ith reaction.
SurfaceArrhenius buildSurfaceArrhenius(size_t i, InterfaceReaction &r)
Build a SurfaceArrhenius object from a Reaction, taking into account the possible sticking coefficien...
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:680
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:285
vector_fp forwardFullOrder_
Reaction order for the forward direction of the reaction.
Definition: ReactionData.h:87
void setElectricPotential(doublereal v)
Set the electric potential of this phase (V).
Definition: ThermoPhase.h:344
void solvePseudoSteadyStateProblem(int ifuncOverride=-1, doublereal timeScaleOverride=1.0)
Solve for the pseudo steady-state of the surface problem.
size_t m_kk
The number of species in all of the phases that participate in this kinetics mechanism.
Definition: Kinetics.h:982
SurfPhase * m_surf
Pointer to the single surface phase.
int phaseExistence(const size_t iphase) const
Gets the phase existence int for the ith phase.
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:1063
const size_t npos
index returned by functions to indicate "no position"
Definition: ct_defs.h:165
vector_fp m_phi
Vector of phase electric potentials.
void advanceCoverages(doublereal tstep)
Advance the surface coverages in time.
vector_fp cov
Adjustments to the Arrhenius rate expression dependent on surface species coverages.
Definition: ReactionData.h:186
doublereal beta
Forward value of the apparent Electrochemical transfer coefficient.
Definition: ReactionData.h:201
vector_fp pstoich
Product stoichiometric coefficients, in the order given by products.
Definition: ReactionData.h:101
vector_fp m_deltaG
Vector of deltaG[] of reaction, the delta Gibbs free energies for each 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:92
Composition orders
Forward reaction order with respect to specific species.
Definition: Reaction.h:54
virtual void getDeltaEntropy(doublereal *deltaS)
Return the vector of values for the reactions change in entropy.
virtual ~InterfaceKinetics()
Destructor.
vector_fp m_beta
Electrochemical transfer coefficient for the forward direction.
std::vector< size_t > kinSpeciesIDs_
ID's of the kinetic species.
virtual void updateMu0()
Update the standard state chemical potentials and species equilibrium constant entries.
doublereal size(size_t k) const
This routine returns the size of species k.
Definition: Phase.h:411
virtual void getDeltaSSEntropy(doublereal *deltaS)
Return the vector of values for the change in the standard state entropies for each reaction...
size_t nTotalSpecies() const
The total number of species in all phases participating in the kinetics mechanism.
Definition: Kinetics.h:297
virtual void getEquilibriumConstants(doublereal *kc)
Equilibrium constant for all reactions including the voltage term.
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_StandardConc
Vector of standard concentrations.
virtual void addPhase(thermo_t &thermo)
Add a phase to the kinetics manager object.
doublereal activationEnergy_R() const
Return the activation energy divided by the gas constant (i.e.
Definition: RxnRates.h:117
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:670
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:466
vector_fp m_ropnet
Net rate-of-progress for each reaction.
Definition: Kinetics.h:1110
const doublereal Pi
Pi.
Definition: ct_defs.h:51
virtual void addReaction(ReactionData &r)
Add a single reaction to the mechanism.
size_t reactionPhaseIndex()
Phase where the reactions occur.
Definition: Kinetics.h:272
forward orders
void convertExchangeCurrentDensityFormulation(doublereal *const kfwd)
When an electrode reaction rate is optionally specified in terms of its exchange current density...
size_t m_nrev
Number of reversible reactions in the mechanism.
void getConcentrations(doublereal *const c) const
Get the species concentrations (kmol/m^3).
Definition: Phase.cpp:609
bool m_has_electrochem_rxns
Boolean flag indicating whether any reaction in the mechanism has a beta electrochemical parameter...
void getCoverages(doublereal *theta) const
Return a vector of surface coverages.
Definition: SurfPhase.cpp:319
void multiply_each(OutputIter x_begin, OutputIter x_end, InputIter y_begin)
Multiply each entry in x by the corresponding entry in y.
Definition: utilities.h:234
int m_phaseExistsCheck
Int flag to indicate that some phases in the kinetics mechanism are non-existent. ...
virtual void finalize()
Finish adding reactions and prepare for use.
vector_fp rateCoeffParameters
Vector of rate coefficient parameters.
Definition: ReactionData.h:152
vector_fp m_mu0_Kc
Vector of standard state electrochemical potentials modified by a standard concentration term...
virtual doublereal standardConcentration(size_t k=0) const
Return the standard concentration for the kth species.
Definition: ThermoPhase.h:447
vector_fp deltaElectricEnergy_
Storage for the net electric energy change due to reaction.
vector_fp m_ropf
Forward rate-of-progress for each reaction.
Definition: Kinetics.h:1104
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:97
void updateKc()
Update the equilibrium constants and stored electrochemical potentials in molar units for all reversi...
std::vector< size_t > products
Indices of product species.
Definition: ReactionData.h:64
doublereal m_temp
Current temperature of the data.
std::map< std::string, CoverageDependency > coverage_deps
Adjustments to the Arrhenius rate expression dependent on surface species coverages.
Definition: Reaction.h:215
A simple thermodynamic model for a surface phase, assuming an ideal solution model.
Definition: SurfPhase.h:143
size_t speciesIndex(const std::string &name) const
Returns the index of a species named 'name' within the Phase object.
Definition: Phase.cpp:257
size_t surfacePhaseIndex()
This returns the integer index of the phase which has ThermoPhase type cSurf.
Definition: Kinetics.h:260
bool m_has_coverage_dependence
Boolean flag indicating whether any reaction in the mechanism has a coverage dependent forward reacti...
ValueCache m_cache
Cache for saved calculations within each Kinetics object.
Definition: Kinetics.h:931
vector_int m_ctrxn_ecdf
Vector of booleans indicating whether the charge transfer reaction rate constant is described by an e...
virtual void getDeltaGibbs(doublereal *deltaG)
Return the vector of values for the reaction Gibbs free energy change.
std::vector< RxnOrders * > m_ctrxn_ROPOrdersList_
Vector of booleans indicating whether the charge transfer reaction rate constant is described by an e...
bool reversible
True if the current reaction is reversible. False otherwise.
Definition: Reaction.h:61
std::vector< size_t > m_ctrxn_BVform
Vector of Reactions which follow the Butler-Volmer methodology for specifying the exchange current de...
virtual void getFwdRateConstants(doublereal *kfwd)
Return the forward rate constants.
vector_fp kinSpeciesOrders_
Orders of the kinetic species.
vector_fp m_E
Vector of raw activation energies for the reactions.
size_t nPhases() const
The number of phases participating in the reaction mechanism.
Definition: Kinetics.h:225
A kinetics manager for heterogeneous reaction mechanisms.
doublereal filmResistivity
Film Resistivity value.
Definition: ReactionData.h:120
vector_fp m_conc
Array of concentrations for each species in the kinetics mechanism.
void solvePseudoSteadyStateProblem(int ifuncOverride=-1, doublereal timeScaleOverride=1.0)
Solve for the pseudo steady-state of the surface problem.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
Definition: stringUtils.cpp:28
virtual int type() const
Identifies the kinetics manager type.
std::vector< bool > m_phaseExists
Vector of booleans indicating whether phases exist or not.
std::vector< std::map< size_t, doublereal > > m_prxn
m_prxn is a vector of maps, containing the reactant stoichiometric coefficient information ...
Definition: Kinetics.h:1037
vector_fp m_rfn
Forward rate constant for each reaction.
Definition: Kinetics.h:1098
virtual void getChemPotentials(doublereal *mu) const
Get the species chemical potentials. Units: J/kmol.
Definition: ThermoPhase.h:554
StoichManagerN m_reactantStoich
Stoichiometry manager for the reactants for each reaction.
Definition: Kinetics.h:968
std::vector< std::pair< size_t, double > > m_sticking_orders
Pairs of (reaction index, total order) for sticking reactions, which are needed to compute the depend...
void _update_rates_T()
Update properties that depend on temperature.
A reaction occurring on an interface (i.e. a SurfPhase or an EdgePhase)
Definition: Reaction.h:204
vector_fp m_actConc
Array of activity concentrations for each species in the kinetics object.
vector_fp m_perturb
Vector of perturbation factors for each reaction's rate of progress vector.
Definition: Kinetics.h:986
Public interface for kinetics managers.
Definition: Kinetics.h:128
virtual void getActivityConcentrations(doublereal *const conc)
Get the vector of activity concentrations used in the kinetics object.
void _update_rates_C()
Update properties that depend on the species mole fractions and/or concentration,.
vector_fp m_pot
Vector of potential energies due to Voltages.
Intermediate class which stores data about a reaction and its rate parameterization before adding the...
Definition: ReactionData.h:22
size_t m_nirrev
Number of irreversible reactions in the mechanism.
void setPhaseStability(const size_t iphase, const int isStable)
Set the stability of a phase in the reaction object.
virtual void getPartialMolarEntropies(doublereal *sbar) const
Returns an array of partial molar entropies of the species in the solution.
Definition: ThermoPhase.h:597
double temperatureExponent() const
Return the temperature exponent b
Definition: RxnRates.h:111
Base class for exceptions thrown by Cantera classes.
Definition: ctexceptions.h:99
Composition reactants
Reactant species and stoichiometric coefficients.
Definition: Reaction.h:46
bool m_has_exchange_current_density_formulation
Boolean flag indicating whether any reaction in the mechanism is described by an exchange current den...
const U & getValue(const std::map< T, U > &m, const T &key)
Const accessor for a value in a std::map.
Definition: utilities.h:714
double preExponentialFactor() const
Return the pre-exponential factor A (in m, kmol, s to powers depending on the reaction order) ...
Definition: RxnRates.h:106
std::vector< std::map< size_t, doublereal > > m_rrxn
m_rrxn is a vector of maps, containing the reactant stoichiometric coefficient information ...
Definition: Kinetics.h:1027
Declarations for the implicit integration of surface site density equations (see Kinetics Managers an...
std::vector< std::vector< bool > > m_rxnPhaseIsReactant
Vector of vector of booleans indicating whether a phase participates in a reaction as a reactant...
RxnOrders()
constructors
Kinetics & operator=(const Kinetics &right)
Assignment operator.
Definition: Kinetics.cpp:41
virtual void modifyReaction(size_t i, shared_ptr< Reaction > rNew)
Modify the rate expression associated with a reaction.
size_t kineticsSpeciesIndex(size_t k, size_t n) const
The location of species k of phase n in species arrays.
Definition: Kinetics.h:323
std::vector< size_t > m_revindex
List of reactions numbers which are reversible reactions.
vector_fp m_rkcn
Reciprocal of the equilibrium constant in concentration units.
Definition: Kinetics.h:1101
std::vector< size_t > reactants
Indices of reactant species.
Definition: ReactionData.h:63
vector_fp rstoich
Reactant stoichiometric coefficients, in the order given by reactants.
Definition: ReactionData.h:94
virtual void getRevRateConstants(doublereal *krev, bool doIrreversible=false)
Return the reverse rate constants.
size_t nSpecies() const
Returns the number of species in the phase.
Definition: Phase.h:265
const int GLOBAL_RXN
A global reaction.
bool reversible
True if the current reaction is reversible. False otherwise.
Definition: ReactionData.h:137
int rateCoeffType
Type of the rate coefficient for the forward rate constant.
Definition: ReactionData.h:147
void _update_rates_phi()
Update properties that depend on the electric potential.
doublereal film_resistivity
Film Resistivity value.
Definition: Reaction.h:241
virtual void init()
Prepare the class for the addition of reactions.
std::vector< size_t > m_irrev
Vector of irreversible reaction numbers.
Advances the surface coverages of the associated set of SurfacePhase objects in time.
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:690
doublereal temperature() const
Temperature (K).
Definition: Phase.h:602
size_t nDim() const
Returns the number of spatial dimensions (1, 2, or 3)
Definition: Phase.h:586
InterfaceKinetics(thermo_t *thermo=0)
Constructor.
virtual Kinetics * duplMyselfAsKinetics(const std::vector< thermo_t * > &tpVector) const
Duplication routine for objects which inherit from Kinetics.
virtual void getActivityConcentrations(doublereal *c) const
This method returns an array of generalized concentrations.
Definition: ThermoPhase.h:425
std::string equation() const
The chemical equation for this reaction.
Definition: Reaction.cpp:94
virtual void initialize(doublereal t0=0.0)
vector_fp m_mu
Vector of chemical potentials for all species.
void updateExchangeCurrentQuantities()
values needed to convert from exchange current density to surface reaction rate.
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:157
virtual void updateROP()
Internal routine that updates the Rates of Progress of the reactions.
size_t speciesPhaseIndex(size_t k)
This function takes as an argument the kineticsSpecies index (i.e., the list index in the list of spe...
Definition: Kinetics.cpp:417
doublereal beta
Forward value of the apparent Electrochemical transfer coefficient.
Definition: Reaction.h:244
std::vector< int > m_phaseIsStable
Vector of int indicating whether phases are stable or not.
Rate1< SurfaceArrhenius > m_rates
Templated class containing the vector of reactions for this interface.
const doublereal GasConstant
Universal Gas Constant. [J/kmol/K].
Definition: ct_defs.h:64
size_t m_ii
Number of reactions in the mechanism.
Definition: Kinetics.h:978
std::vector< size_t > m_ctrxn
Vector of reaction indexes specifying the id of the current transfer reactions in the mechanism...
size_t nReactions() const
Number of reactions in the reaction mechanism.
Definition: Kinetics.h:193
vector_fp m_ProdStanConcReac
Vector of the products of the standard concentrations of the reactants.
#define DATA_PTR(vec)
Creates a pointer to the start of the raw data for a vector.
Definition: ct_defs.h:36
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:80
void setPhaseExistence(const size_t iphase, const int exists)
Set the existence of a phase in the reaction object.
virtual void getPartialMolarEnthalpies(doublereal *hbar) const
Returns an array of partial molar enthalpies for the species in the mixture.
Definition: ThermoPhase.h:587
virtual doublereal logStandardConc(size_t k=0) const
Natural logarithm of the standard concentration of the kth species.
CachedArray getArray(int id)
Get a reference to a CachedValue object representing an array (vector_fp) with the given id...
Definition: ValueCache.h:168
const int BUTLERVOLMER_RXN
This is a surface reaction that is formulated using the Butler-Volmer formulation.
Definition: reaction_defs.h:86
void writelog(const std::string &msg)
Write a message to the screen.
Definition: global.cpp:33
Composition products
Product species and stoichiometric coefficients.
Definition: Reaction.h:49
virtual void getDeltaSSGibbs(doublereal *deltaG)
Return the vector of values for the reaction standard state Gibbs free energy change.
virtual void getDeltaElectrochemPotentials(doublereal *deltaM)
Return the vector of values for the reaction electrochemical free energy change.
virtual int reactionType(size_t i) const
Flag specifying the type of reaction.
Definition: Kinetics.h:686
virtual void finalize()
Finish adding reactions and prepare for use.
Definition: Kinetics.cpp:548
vector_fp m_mu0
Vector of standard state chemical potentials for all species.
vector_fp m_grt
Temporary work vector of length m_kk.
virtual void addPhase(thermo_t &thermo)
Add a phase to the kinetics manager object.
Definition: Kinetics.cpp:513
virtual void getDeltaSSEnthalpy(doublereal *deltaH)
Return the vector of values for the change in the standard state enthalpies of reaction.
void getElectrochemPotentials(doublereal *mu) const
Get the species electrochemical potentials.
Definition: ThermoPhase.h:573
ImplicitSurfChem * m_integrator
Pointer to the Implicit surface chemistry object.
An Arrhenius rate with coverage-dependent terms.
Definition: RxnRates.h:145
virtual void getReactionDelta(const doublereal *property, doublereal *deltaProperty)
Change in species properties.
Definition: Kinetics.cpp:456
An interface reaction which involves charged species.
Definition: Reaction.h:227
void integrate(doublereal t0, doublereal t1)
Integrate from t0 to t1. The integrator is reinitialized first.
InterfaceKinetics & operator=(const InterfaceKinetics &right)
Assignment operator.
virtual void addReaction(ReactionData &r)
Add a single reaction to the mechanism.
Definition: Kinetics.cpp:557
bool m_finalized
Boolean indicating whether mechanism has been finalized.
virtual void finalize()
Finish adding reactions and prepare for use.
int fill(const vector_fp &fullForwardOrders)
Fill in the structure with the array.
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:578
std::vector< RxnOrders * > m_ctrxn_FwdOrdersList_
Reaction Orders for the case where the forwards rate of progress is being calculated.