Example #1
0
  /*
   * Add a phase to the kinetics manager object. This must
   * be done before the function init() is called or 
   * before any reactions are input.
   * The following fields are updated:
   *  m_start -> vector of integers, containing the
   *             starting position of the species for
   *             each phase in the kinetics mechanism.
   *  m_surfphase -> index of the surface phase.
   *  m_thermo -> vector of pointers to ThermoPhase phases
   *              that participate in the kinetics 
   *              mechanism.
   *  m_phaseindex -> map containing the string id of each
   *              ThermoPhase phase as a key and the
   *              index of the phase within the kinetics
   *              manager object as the value.
   */
  void Kinetics::addPhase(thermo_t& thermo) {

    // if not the first thermo object, set the start position
    // to that of the last object added + the number of its species 
    if (m_thermo.size() > 0) {
      m_start.push_back(m_start.back() 
			+ m_thermo.back()->nSpecies());
    }
    // otherwise start at 0
    else {
      m_start.push_back(0);
    }

    // the phase with lowest dimensionality is assumed to be the
    // phase/interface at which reactions take place
    if (thermo.nDim() <= m_mindim) {
      m_mindim = thermo.nDim();
      m_rxnphase = nPhases();
    }

    // there should only be one surface phase
    int ptype = -100;
    if (type() == cEdgeKinetics) ptype = cEdge;
    else if (type() == cInterfaceKinetics) ptype = cSurf;
    if (thermo.eosType() == ptype) {
      //   if (m_surfphase >= 0) {
      //    throw CanteraError("Kinetics::addPhase",
      //        "cannot add more than one surface phase");
      // }
      m_surfphase = nPhases();
      m_rxnphase = nPhases();
    }
    m_thermo.push_back(&thermo);
    m_phaseindex[m_thermo.back()->id()] = nPhases();
  }
Example #2
0
    /**
     * Get the equilibrium constants of all reactions, whether
     * reversible or not.
     */
    void InterfaceKinetics::getEquilibriumConstants(doublereal* kc) {
        int i;

        int n, nsp, k, ik=0;
        doublereal rt = GasConstant*thermo(0).temperature();
        doublereal rrt = 1.0/rt;
        int np = nPhases();
        for (n = 0; n < np; n++) {
            thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]);
            nsp = thermo(n).nSpecies();
            for (k = 0; k < nsp; k++) {
                m_mu0[ik] -= rt*thermo(n).logStandardConc(k);
                m_mu0[ik] += Faraday * m_phi[n] * thermo(n).charge(k);
                ik++;
            }
        }

        fill(kc, kc + m_ii, 0.0);

        m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_mu0), kc);

        for (i = 0; i < m_ii; i++) {
            kc[i] = exp(-kc[i]*rrt);
        }
    }
Example #3
0
  void InterfaceKinetics::getExchangeCurrentQuantities() {
    /*
     * Combine vectors of the standard Gibbs free energies of the
     * species and the standard concentrations to get change in 
     * standard chemical potential for reaction.
     * Outputs:
     *   - m_deltaG0  -- stores standard state chemical potentials
     *   - m_ProdStanConcReac -- stores products of standard concentrations
     */
    int ik = 0;  
    int np = nPhases();

    for (int n = 0; n < np; n++) {
      thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]);
      int nsp = thermo(n).nSpecies();
      for (int k = 0; k < nsp; k++) {
        m_StandardConc[ik] = thermo(n).standardConcentration(k);
        ik++;
      }
    }
    // m_deltaG0 will be used to pass electrochemical potentials
    m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_mu0), DATA_PTR(m_deltaG0));

    
    for (int i = 0; i < m_ii; i++) {
       m_ProdStanConcReac[i] = 1.0;
    }

    m_rxnstoich.multiplyReactants(DATA_PTR(m_StandardConc), DATA_PTR(m_ProdStanConcReac));

  }
Example #4
0
void Kinetics::finalize()
{
    m_kk = 0;
    for (size_t n = 0; n < nPhases(); n++) {
        size_t nsp = m_thermo[n]->nSpecies();
        m_kk += nsp;
    }
}
Example #5
0
 void Kinetics::finalize() {
   m_nTotalSpecies = 0;
   int np = nPhases();
   for (int n = 0; n < np; n++) {
     int nsp = m_thermo[n]->nSpecies();
     m_nTotalSpecies += nsp;
   }
 }
Example #6
0
  //====================================================================================================================
  void InterfaceKinetics::_update_rates_phi() {
    int np = nPhases();
    for (int n = 0; n < np; n++) {
      if (thermo(n).electricPotential() != m_phi[n]) {
	m_phi[n] = thermo(n).electricPotential();
	m_redo_rates = true;
      }
    }
  }
Example #7
0
void Kinetics::resizeSpecies()
{
    m_kk = 0;
    m_start.resize(nPhases());

    for (size_t i = 0; i < m_thermo.size(); i++) {
        m_start[i] = m_kk; // global index of first species of phase i
        m_kk += m_thermo[i]->nSpecies();
    }
    invalidateCache();
}
Example #8
0
  /**
   * For reactions that transfer charge across a potential difference,
   * the activation energies are modified by the potential difference.
   * (see, for example, ...). This method applies this correction.
   */
  void InterfaceKinetics::applyButlerVolmerCorrection(doublereal* kf) {
    int i;

    int n, nsp, k, ik=0;
    doublereal rt = GasConstant*thermo(0).temperature();
    doublereal rrt = 1.0/rt;
    int np = nPhases();

    // compute the electrical potential energy of each species
    for (n = 0; n < np; n++) {
      nsp = thermo(n).nSpecies();
      for (k = 0; k < nsp; k++) {
	m_pot[ik] = Faraday*thermo(n).charge(k)*m_phi[n];
	ik++;
      }
    }

    // Compute the change in electrical potential energy for each
    // reaction. This will only be non-zero if a potential
    // difference is present.
    m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_pot), 
				 DATA_PTR(m_rwork));

    // Modify the reaction rates. Only modify those with a
    // non-zero activation energy, and do not decrease the
    // activation energy below zero.
    doublereal eamod;
#ifdef DEBUG_MODE
    double ea;
#endif
    int nct = m_beta.size();
    int irxn;
    for (i = 0; i < nct; i++) {
      irxn = m_ctrxn[i];
      eamod = m_beta[i]*m_rwork[irxn];
      if (eamod != 0.0 && m_E[irxn] != 0.0) {
#ifdef DEBUG_MODE
	ea = GasConstant * m_E[irxn];
	if (eamod + ea < 0.0) {
	  writelog("Warning: act energy mod too large!\n");
	  writelog("  Delta phi = "+fp2str(m_rwork[irxn]/Faraday)+"\n");
	  writelog("  Delta Ea = "+fp2str(eamod)+"\n");
	  writelog("  Ea = "+fp2str(ea)+"\n");
	  for (n = 0; n < np; n++) {
	    writelog("Phase "+int2str(n)+": phi = "
		     +fp2str(m_phi[n])+"\n");
	  }
	}
#endif
	kf[irxn] *= exp(-eamod*rrt);
      }
    }
  }
Example #9
0
  /**
   * Add a single reaction to the mechanism. This routine
   * must be called after init() and before finalize().
   * This function branches on the types of reactions allowed
   * by the interfaceKinetics manager in order to install
   * the reaction correctly in the manager.
   * The manager allows the following reaction types
   *  Elementary
   *  Surface
   *  Global  
   * There is no difference between elementary and surface 
   * reactions.
   */
  void InterfaceKinetics::addReaction(const ReactionData& r) {

    /*
     * Install the rate coefficient for the current reaction
     * in the appropriate data structure.
     */
    addElementaryReaction(r);
    /*
     * Add the reactants and products for  m_ropnet;the current reaction
     * to the various stoichiometric coefficient arrays.
     */
    installReagents(r);
    /* 
     * Save the reaction and product groups, which are
     * part of the ReactionData class, in this class.
     * They aren't used for anything but reaction path
     * analysis.
     */
    //installGroups(reactionNumber(), r.rgroups, r.pgroups);
    /*
     * Increase the internal number of reactions, m_ii, by one.
     * increase the size of m_perturb by one as well.
     */
    incrementRxnCount();
    m_rxneqn.push_back(r.equation);

    m_rxnPhaseIsReactant.resize(m_ii, 0);
    m_rxnPhaseIsProduct.resize(m_ii, 0);
 
    int np = nPhases(); 
    int i = m_ii -1;
    m_rxnPhaseIsReactant[i] = new bool[np];
    m_rxnPhaseIsProduct[i] = new bool[np];

    for (int p = 0; p < np; p++) {
      m_rxnPhaseIsReactant[i][p] = false;
      m_rxnPhaseIsProduct[i][p] = false;
    }

    const vector_int& vr = reactants(i);
    for (int ik = 0; ik < (int) vr.size(); ik++) {
      int k = vr[ik];
      int p = speciesPhaseIndex(k);
      m_rxnPhaseIsReactant[i][p] = true;
    }
    const vector_int& vp = products(i);
    for (int ik = 0; ik < (int) vp.size(); ik++) {
      int k = vp[ik];
      int p = speciesPhaseIndex(k);
      m_rxnPhaseIsProduct[i][p] = true;
    }
 }
Example #10
0
  /**
   * Takes as input an array of properties for all species in the
   * mechanism and copies those values beloning to a particular
   * phase to the output array.
   * @param data Input data array.
   * @param phase Pointer to one of the phase objects participating
   * in this reaction mechanism
   * @param phase_data Output array where the values for the the
   * specified phase are to be written. 
   */
  void Kinetics::selectPhase(const doublereal* data, const thermo_t* phase,
			     doublereal* phase_data) {
    int n, nsp, np = nPhases();
    for (n = 0; n < np; n++) {
      if (phase == m_thermo[n]) {
	nsp = phase->nSpecies();
	copy(data + m_start[n], 
	     data + m_start[n] + nsp, phase_data);
	return;
      }
    }
    throw CanteraError("Kinetics::selectPhase", "Phase not found.");
  }
Example #11
0
 /**
  * Prepare the class for the addition of reactions. This function
  * must be called after instantiation of the class, but before
  * any reactions are actually added to the mechanism.
  * This function calculates m_kk the number of species in all
  * phases participating in the reaction mechanism. We don't know
  * m_kk previously, before all phases have been added. 
  */
 void InterfaceKinetics::init() {
     int n;
     m_kk = 0;
     int np = nPhases();
     for (n = 0; n < np; n++) {
         m_kk += thermo(n).nSpecies();
     }
     m_rrxn.resize(m_kk);
     m_prxn.resize(m_kk);
     m_conc.resize(m_kk);
     m_mu0.resize(m_kk);
     m_grt.resize(m_kk);
     m_pot.resize(m_kk, 0.0);
     m_phi.resize(np, 0.0);
 }
Example #12
0
void Kinetics::addPhase(thermo_t& thermo)
{
    // the phase with lowest dimensionality is assumed to be the
    // phase/interface at which reactions take place
    if (thermo.nDim() <= m_mindim) {
        m_mindim = thermo.nDim();
        m_rxnphase = nPhases();
    }

    // there should only be one surface phase
    int ptype = -100;
    if (type() == cEdgeKinetics) {
        ptype = cEdge;
    } else if (type() == cInterfaceKinetics) {
        ptype = cSurf;
    }
    if (thermo.eosType() == ptype) {
        m_surfphase = nPhases();
        m_rxnphase = nPhases();
    }
    m_thermo.push_back(&thermo);
    m_phaseindex[m_thermo.back()->id()] = nPhases();
    resizeSpecies();
}
Example #13
0
 /*
  * These values depend upon the concentration
  * of the solution.
  *
  *  units = J kmol-1 Kelvin-1
  *
  * @param deltaS vector of Enthalpy changes 
  *        Length = m_ii, number of reactions
  *         
  */
 void InterfaceKinetics::getDeltaEntropy(doublereal* deltaS) {
   /*
    * Get the partial molar entropy of all species in all of
    * the phases
    */
   int np = nPhases();
   int n;
   for (n = 0; n < np; n++) {
     thermo(n).getPartialMolarEntropies(DATA_PTR(m_grt) + m_start[n]);
   }
   /*
    * Use the stoichiometric manager to find deltaS for each
    * reaction.
    */
   m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaS);
 }
Example #14
0
 /*
  * These values depend upon the concentration of the solution and
  * the voltage of the phases
  *
  *  units = J kmol-1
  *
  * @param deltaM  Output vector of  deltaM's for reactions
  *                Length: m_ii.
  */
 void InterfaceKinetics::getDeltaElectrochemPotentials(doublereal* deltaM) {
   /*
    * Get the chemical potentials of the species in the 
    * ideal gas solution.
    */
   int np = nPhases();
   int n;
   for (n = 0; n < np; n++) {
     thermo(n).getElectrochemPotentials(DATA_PTR(m_grt) + m_start[n]);
   }
   /*
    * Use the stoichiometric manager to find deltaG for each
    * reaction.
    */
   m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaM);
 }
Example #15
0
  /**
   * Update properties that depend on concentrations. This method
   * fills out the array of generalized concentrations by calling
   * method getActivityConcentrations for each phase, which classes
   * representing phases should overload to return the appropriate
   * quantities.
   */ 
  void InterfaceKinetics::_update_rates_C() {
    int n;

    int np = nPhases();
    for (n = 0; n < np; n++) {
      /*
       * We call the getActivityConcentrations function of each
       * ThermoPhase class that makes up this kinetics object to 
       * obtain the generalized concentrations for species within that 
       * class. This is collected in the vector m_conc. m_start[]
       * are integer indecises for that vector denoting the start of the
       * species for each phase.
       */
      thermo(n).getActivityConcentrations(DATA_PTR(m_conc) + m_start[n]);
    }
    m_kdata->m_ROP_ok = false;
  }
Example #16
0
    /**
     *
     * getDeltaSSGibbs():
     *
     * Return the vector of values for the reaction 
     * standard state gibbs free energy change.
     * These values don't depend upon the concentration
     * of the solution.
     *
     *  units = J kmol-1
     */
    void InterfaceKinetics::getDeltaSSGibbs(doublereal* deltaG) {
	/*
	 *  Get the standard state chemical potentials of the species.
         *  This is the array of chemical potentials at unit activity 
	 *  We define these here as the chemical potentials of the pure
	 *  species at the temperature and pressure of the solution.
	 */
        int np = nPhases();
        int n;
        for (n = 0; n < np; n++) {
            thermo(n).getStandardChemPotentials(DATA_PTR(m_grt) + m_start[n]);
        }
	/*
	 * Use the stoichiometric manager to find deltaG for each
	 * reaction.
	 */
	m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaG);
    }
Example #17
0
  /**
   * Update the equilibrium constants in molar units for all
   * reversible reactions. Irreversible reactions have their 
   * equilibrium constant set to zero.
   * For reactions involving charged species the equilibrium 
   * constant is adjusted according to the electrostatis potential.
   */
  void InterfaceKinetics::updateKc() {
    int i, irxn;

    vector_fp& m_rkc = m_kdata->m_rkcn;
    fill(m_rkc.begin(), m_rkc.end(), 0.0);

    //static vector_fp mu(nTotalSpecies());
    if (m_nrev > 0) {

      /*
       * Get the vector of electrochemical potentials and store it in m_mu0
       */
      int n, nsp, k, ik = 0;
      doublereal rt = GasConstant*thermo(0).temperature();
      doublereal rrt = 1.0 / rt;
      int np = nPhases();
      for (n = 0; n < np; n++) {
	thermo(n).getStandardChemPotentials(DATA_PTR(m_mu0) + m_start[n]);
	nsp = thermo(n).nSpecies();
	for (k = 0; k < nsp; k++) {
	  m_mu0[ik] -= rt * thermo(n).logStandardConc(k);
	  m_mu0[ik] += Faraday * m_phi[n] * thermo(n).charge(k);
	  ik++;
	}
      }

      // compute Delta mu^0 for all reversible reactions
      m_rxnstoich.getRevReactionDelta(m_ii, DATA_PTR(m_mu0), 
				      DATA_PTR(m_rkc));

      for (i = 0; i < m_nrev; i++) {
	irxn = m_revindex[i];
	if (irxn < 0 || irxn >= nReactions()) {
	  throw CanteraError("InterfaceKinetics",
			     "illegal value: irxn = "+int2str(irxn));
	}
	m_rkc[irxn] = exp(m_rkc[irxn]*rrt);
      }
      for (i = 0; i != m_nirrev; ++i) {
	m_rkc[ m_irrev[i] ] = 0.0;
      }
    }
  }
Example #18
0
    /**
     *
     * getDeltaGibbs():
     *
     * Return the vector of values for the reaction gibbs free energy
     * change
     * These values depend upon the concentration
     * of the ideal gas.
     *
     *  units = J kmol-1
     */
    void InterfaceKinetics::getDeltaGibbs(doublereal* deltaG) {
	/*
	 * Get the chemical potentials of the species in the 
	 * ideal gas solution.
	 */
        int np = nPhases();
        int n;
        for (n = 0; n < np; n++) {
            thermo(n).getChemPotentials(DATA_PTR(m_grt) + m_start[n]);
        }
        //for (n = 0; n < m_grt.size(); n++) {
        //    cout << n << "G_RT = " << m_grt[n] << endl;
        //}

	/*
	 * Use the stoichiometric manager to find deltaG for each
	 * reaction.
	 */
	m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaG);
    }
Example #19
0
    void InterfaceKinetics::checkPartialEquil() {
        int i, irxn;
        vector_fp dmu(nTotalSpecies(), 0.0);
        vector_fp rmu(nReactions(), 0.0);
        vector_fp frop(nReactions(), 0.0);
        vector_fp rrop(nReactions(), 0.0);
        vector_fp netrop(nReactions(), 0.0);
        if (m_nrev > 0) {
            doublereal rt = GasConstant*thermo(0).temperature();
            cout << "T = " << thermo(0).temperature() << " " << rt << endl;
            int n, nsp, k, ik=0;
            //doublereal rt = GasConstant*thermo(0).temperature();
            //            doublereal rrt = 1.0/rt;
            int np = nPhases();
            doublereal delta;
            for (n = 0; n < np; n++) {
                thermo(n).getChemPotentials(DATA_PTR(dmu) + m_start[n]);
                nsp = thermo(n).nSpecies();
                for (k = 0; k < nsp; k++) {
                    delta = Faraday * m_phi[n] * thermo(n).charge(k);
                    //cout << thermo(n).speciesName(k) << "   " << (delta+dmu[ik])/rt << " " << dmu[ik]/rt << endl;
                    dmu[ik] += delta;
                    ik++;
                }
            }

            // compute Delta mu^ for all reversible reactions
            m_rxnstoich.getRevReactionDelta(m_ii, DATA_PTR(dmu), DATA_PTR(rmu));
            getFwdRatesOfProgress(DATA_PTR(frop));
            getRevRatesOfProgress(DATA_PTR(rrop));
            getNetRatesOfProgress(DATA_PTR(netrop));
            for (i = 0; i < m_nrev; i++) {
                irxn = m_revindex[i];
                cout << "Reaction " << reactionString(irxn) 
                     << "  " << rmu[irxn]/rt << endl;
                printf("%12.6e  %12.6e  %12.6e  %12.6e \n", 
                    frop[irxn], rrop[irxn], netrop[irxn], 
                    netrop[irxn]/(frop[irxn] + rrop[irxn]));
            }
        }
    }
Example #20
0
    /*********************************************************************
     *
     * getDeltaSSEntropy():
     *
     * Return the vector of values for the change in the
     * standard state entropies for each reaction.
     * These values don't depend upon the concentration
     * of the solution.
     *
     *  units = J kmol-1 Kelvin-1
     */
    void InterfaceKinetics::getDeltaSSEntropy(doublereal* deltaS) {
	/*
	 *  Get the standard state entropy of the species.
	 *  We define these here as the entropies of the pure
	 *  species at the temperature and pressure of the solution.
	 */
        int np = nPhases();
        int n;
        for (n = 0; n < np; n++) {
            thermo(n).getEntropy_R(DATA_PTR(m_grt) + m_start[n]);
        }
	doublereal R = GasConstant;
	for (int k = 0; k < m_kk; k++) {
	  m_grt[k] *= R;
	}
	/*
	 * Use the stoichiometric manager to find deltaS for each
	 * reaction.
	 */
	m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaS);
    }
Example #21
0
    /**
     *
     * getDeltaSSEnthalpy():
     *
     * Return the vector of values for the change in the
     * standard state enthalpies of reaction.
     * These values don't depend upon the concentration
     * of the solution.
     *
     *  units = J kmol-1
     */
    void InterfaceKinetics::getDeltaSSEnthalpy(doublereal* deltaH) {
	/*
	 *  Get the standard state enthalpies of the species.
         *  This is the array of chemical potentials at unit activity 
	 *  We define these here as the enthalpies of the pure
	 *  species at the temperature and pressure of the solution.
	 */
        int np = nPhases();
        int n;
        for (n = 0; n < np; n++) {
            thermo(n).getEnthalpy_RT(DATA_PTR(m_grt) + m_start[n]);
        }
	doublereal RT = thermo().temperature() * GasConstant;
	for (int k = 0; k < m_kk; k++) {
	  m_grt[k] *= RT;
	}
	/*
	 * Use the stoichiometric manager to find deltaG for each
	 * reaction.
	 */
	m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_grt), deltaH);
    }
Example #22
0
  /*
   *  This is NOT a virtual function.
   *
   * @param right    Reference to %Kinetics object to be copied into the
   *                 current one.
   */
  InterfaceKinetics& InterfaceKinetics::
  operator=(const InterfaceKinetics &right) {
    int i;
    /*
     * Check for self assignment.
     */
    if (this == &right) return *this;

    for (i = 0; i < m_ii; i++) {
      delete [] m_rxnPhaseIsReactant[i];
      delete [] m_rxnPhaseIsProduct[i];
    }

    Kinetics::operator=(right);

    m_grt                  = right.m_grt;
    m_kk                   = right.m_kk;
    m_revindex             = right.m_revindex;
    m_rates                = right.m_rates;
    m_redo_rates           = right.m_redo_rates;
    m_index                = right.m_index;
    m_irrev                = right.m_irrev; 
    m_rxnstoich            = right.m_rxnstoich;
    m_nirrev               = right.m_nirrev;
    m_nrev                 = right.m_nrev;
    m_rrxn                 = right.m_rrxn;
    m_prxn                 = right.m_prxn;
    m_rxneqn               = right.m_rxneqn;
    *m_kdata               = *right.m_kdata; 
    m_conc                 = right.m_conc;
    m_mu0                  = right.m_mu0;
    m_phi                  = right.m_phi;
    m_pot                  = right.m_pot;
    m_rwork                = right.m_rwork;
    m_E                    = right.m_E;
    m_surf                 = right.m_surf;  //DANGER - shallow copy
    m_integrator           = right.m_integrator;  //DANGER - shallow copy
    m_beta                 = right.m_beta;
    m_ctrxn                = right.m_ctrxn;
    m_ctrxn_ecdf           = right.m_ctrxn_ecdf;
    m_StandardConc         = right.m_StandardConc;
    m_deltaG0              = right.m_deltaG0;
    m_ProdStanConcReac     = right.m_ProdStanConcReac;
    m_finalized            = right.m_finalized;
    m_has_coverage_dependence = right.m_has_coverage_dependence;
    m_has_electrochem_rxns = right.m_has_electrochem_rxns;
    m_has_exchange_current_density_formulation = right.m_has_exchange_current_density_formulation;
    m_phaseExistsCheck     = right.m_phaseExistsCheck;
    m_phaseExists          = right.m_phaseExists;
    m_phaseIsStable        = right.m_phaseIsStable;

    m_rxnPhaseIsReactant.resize(m_ii, 0);
    m_rxnPhaseIsProduct.resize(m_ii, 0);
    int np = nPhases();
    for (i = 0; i < m_ii; i++) {
      m_rxnPhaseIsReactant[i] = new bool[np];
      m_rxnPhaseIsProduct[i] = new bool[np];
      for (int p = 0; p < np; p++) {
	m_rxnPhaseIsReactant[i][p] = right.m_rxnPhaseIsReactant[i][p];
	m_rxnPhaseIsProduct[i][p] = right.m_rxnPhaseIsProduct[i][p];  
      }
    }

    m_ioFlag               = right.m_ioFlag;

    return *this;
  }
Example #23
0
  /*
   * For reactions that transfer charge across a potential difference,
   * the activation energies are modified by the potential difference.
   * (see, for example, ...). This method applies this correction.
   *
   * @param kf  Vector of forward reaction rate constants on which to have
   *            the correction applied
   */
  void InterfaceKinetics::applyButlerVolmerCorrection(doublereal* const kf) {
    int i;

    int n, nsp, k, ik=0;
    doublereal rt = GasConstant*thermo(0).temperature();
    doublereal rrt = 1.0/rt;
    int np = nPhases();

    // compute the electrical potential energy of each species
    for (n = 0; n < np; n++) {
      nsp = thermo(n).nSpecies();
      for (k = 0; k < nsp; k++) {
	m_pot[ik] = Faraday*thermo(n).charge(k)*m_phi[n];
	ik++;
      }
    }

    // Compute the change in electrical potential energy for each
    // reaction. This will only be non-zero if a potential
    // difference is present.
    m_rxnstoich.getReactionDelta(m_ii, DATA_PTR(m_pot), DATA_PTR(m_rwork));

    // Modify the reaction rates. Only modify those with a
    // non-zero activation energy. Below we decrease the
    // activation energy below zero but in some debug modes
    // we print out a warning message about this. 
    /*
     *   NOTE, there is some discussion about this point.
     *   Should we decrease the activiation energy below zero?
     *   I don't think this has been decided in any definative way.
     *   The treatment below is numerically more stable, however.
     */
    doublereal eamod;
    doublereal ecoeff;
#ifdef DEBUG_KIN_MODE
    doublereal ea;
#endif
    int nct = m_beta.size();
    int irxn;
    for (i = 0; i < nct; i++) {
      irxn = m_ctrxn[i];
      eamod = m_beta[i]*m_rwork[irxn];
      //  if (eamod != 0.0 && m_E[irxn] != 0.0) {
      if (eamod != 0.0) {
#ifdef DEBUG_KIN_MODE
	ea = GasConstant * m_E[irxn];
	if (eamod + ea < 0.0) {
	  writelog("Warning: act energy mod too large!\n");
	  writelog("  Delta phi = "+fp2str(m_rwork[irxn]/Faraday)+"\n");
	  writelog("  Delta Ea = "+fp2str(eamod)+"\n");
	  writelog("  Ea = "+fp2str(ea)+"\n");
	  for (n = 0; n < np; n++) {
	    writelog("Phase "+int2str(n)+": phi = "
		     +fp2str(m_phi[n])+"\n");
	  }
	}
#endif
        /*
         *  Commonly, during electrochemistry problems the voltage may get out of sorts.
         *  Here, we seek to avoid producing inf results within Cantera by tempering the
         *  resulting rates of progress to ~10^150 or so. The ln calculation produces a
         *  small gradient pointing in the correct direction.
         *      (this would be a good place to pop a warning flag)
         */
        ecoeff = -eamod*rrt;
        if (ecoeff > 345.) {
          ecoeff = 339.1565 + log(ecoeff);
        } else if (ecoeff < -345.) {
          ecoeff = -339.1565 - log(-ecoeff);
        }
	kf[irxn] *= exp(ecoeff);
      }
    }
  }
Example #24
0
  /**
   * Update the rates of progress of the reactions in the reaction
   * mechanism. This routine operates on internal data.
   */
  void InterfaceKinetics::updateROP() {

    _update_rates_T();
    _update_rates_C();

    if (m_kdata->m_ROP_ok) return;

    const vector_fp& rf = m_kdata->m_rfn;
    const vector_fp& m_rkc = m_kdata->m_rkcn;
    array_fp& ropf = m_kdata->m_ropf;
    array_fp& ropr = m_kdata->m_ropr;
    array_fp& ropnet = m_kdata->m_ropnet;

    // copy rate coefficients into ropf
    copy(rf.begin(), rf.end(), ropf.begin());

    // multiply by perturbation factor
    multiply_each(ropf.begin(), ropf.end(), m_perturb.begin());
           
    // copy the forward rates to the reverse rates                
    copy(ropf.begin(), ropf.end(), ropr.begin());
        
    // for reverse rates computed from thermochemistry, multiply
    // the forward rates copied into m_ropr by the reciprocals of
    // the equilibrium constants
    multiply_each(ropr.begin(), ropr.end(), m_rkc.begin());

    // multiply ropf by concentration products
    m_rxnstoich.multiplyReactants(DATA_PTR(m_conc), DATA_PTR(ropf)); 
    //m_reactantStoich.multiply(m_conc.begin(), ropf.begin()); 

    // for reversible reactions, multiply ropr by concentration
    // products
    m_rxnstoich.multiplyRevProducts(DATA_PTR(m_conc), 
				    DATA_PTR(ropr)); 
    //m_revProductStoich.multiply(m_conc.begin(), ropr.begin());

    // do global reactions
    //m_globalReactantStoich.power(m_conc.begin(), ropf.begin());

    for (int j = 0; j != m_ii; ++j) {
      ropnet[j] = ropf[j] - ropr[j];
    }  


    /*
     *  For reactions involving multiple phases, we must check that the phase
     *  being consumed actually exists. This is particularly important for 
     *  phases that are stoichiometric phases containing one species with a unity activity
     */
    if (m_phaseExistsCheck) {
      for (int j = 0; j != m_ii; ++j) {
	if ((ropr[j] >  ropf[j]) && (ropr[j] > 0.0)) {
	  for (int p = 0; p < nPhases(); p++) {
	    if (m_rxnPhaseIsProduct[j][p]) {
	      if (! m_phaseExists[p]) {
		ropnet[j] = 0.0;
		ropr[j] = ropf[j];
		if (ropf[j] > 0.0) {
		  for (int rp = 0; rp < nPhases(); rp++) {
		    if (m_rxnPhaseIsReactant[j][rp]) {
		      if (! m_phaseExists[rp]) {
			ropnet[j] = 0.0;
			ropr[j] = ropf[j] = 0.0;;
		      }
		    }
		  }
		}
	      }
	    }
	    if (m_rxnPhaseIsReactant[j][p]) {
	      if (! m_phaseIsStable[p]) {
		ropnet[j] = 0.0;
		ropr[j] = ropf[j];
	      }
	    }
	  }
	} else if ((ropf[j] > ropr[j]) && (ropf[j] > 0.0)) {
	  for (int p = 0; p < nPhases(); p++) {
	    if (m_rxnPhaseIsReactant[j][p]) {
	      if (! m_phaseExists[p]) {
		ropnet[j] = 0.0;
		ropf[j] = ropr[j];     
		if (ropf[j] > 0.0) {
		  for (int rp = 0; rp < nPhases(); rp++) {
		    if (m_rxnPhaseIsProduct[j][rp]) {
		      if (! m_phaseExists[rp]) {
			ropnet[j] = 0.0;
			ropf[j] = ropr[j] = 0.0;
		      }
		    }
		  }
		}
	      }
	    }
	    if (m_rxnPhaseIsProduct[j][p]) {
	      if (! m_phaseIsStable[p]) {
		ropnet[j] = 0.0;
		ropf[j] = ropr[j];
	      }
	    }
	  }
	}
      }
    }

    m_kdata->m_ROP_ok = true;
  }
Example #25
0
void Kinetics::checkPhaseIndex(size_t m) const
{
    if (m >= nPhases()) {
        throw IndexError("checkPhaseIndex", "phase", m, nPhases()-1);
    }
}
Example #26
0
void Kinetics::checkPhaseArraySize(size_t mm) const
{
    if (nPhases() > mm) {
        throw ArraySizeError("checkPhaseArraySize", mm, nPhases());
    }
}