391 lines
11 KiB
C++
Executable file
391 lines
11 KiB
C++
Executable file
/**
|
|
* @file SurfKinetics.cpp
|
|
*
|
|
*/
|
|
|
|
// Copyright 2002 California Institute of Technology
|
|
|
|
|
|
// turn off warnings under Windows
|
|
#ifdef WIN32
|
|
#pragma warning(disable:4786)
|
|
#pragma warning(disable:4503)
|
|
#endif
|
|
|
|
|
|
#include "surfKinetics.h"
|
|
#include "ReactionData.h"
|
|
#include "RateCoeffMgr.h"
|
|
#include "ImplicitSurfChem.h"
|
|
#include <iostream>
|
|
using namespace std;
|
|
|
|
#include "ctml.h"
|
|
using namespace ctml;
|
|
|
|
#include <time.h>
|
|
|
|
namespace Cantera {
|
|
|
|
void importInterfaceData(SurfacePhase* ph, SurfKinetics* kin, string fname, string id);
|
|
|
|
/**
|
|
* Construct an empty surface reaction mechanism.
|
|
*/
|
|
SurfKinetics::
|
|
SurfKinetics(SurfacePhase* surfphase,
|
|
thermo_t* th1,
|
|
thermo_t* th2, string fname, string id) :
|
|
Kinetics(),
|
|
m_surfphase(surfphase),
|
|
m_kk(0),
|
|
m_kk1(0),
|
|
m_kk2(0),
|
|
m_ktot(0),
|
|
m_nirrev(0),
|
|
m_integrator(0),
|
|
m_finalized(false),
|
|
m_twobulk(false),
|
|
m_xml(new XML_Node("interface_reactions"))
|
|
{
|
|
|
|
// add the two bulk phases
|
|
addPhase(*th1);
|
|
if (th2) {
|
|
m_twobulk = true;
|
|
addPhase(*th2);
|
|
}
|
|
|
|
m_kk1 = phase(0).nSpecies();
|
|
|
|
if (th2) {
|
|
m_kk2 = phase(1).nSpecies();
|
|
}
|
|
m_kk = m_surfphase->nSpecies();
|
|
m_kdata = new SurfKineticsData;
|
|
m_kdata->m_temp = 0.0;
|
|
|
|
if (fname != "") importInterfaceData(surfphase, this, fname, id);
|
|
}
|
|
|
|
void SurfKinetics::
|
|
_update_rates_T() {
|
|
doublereal T = m_surfphase->temperature();
|
|
if (T != m_kdata->m_temp) {
|
|
doublereal logT = log(T);
|
|
m_rates.update(T, logT, m_kdata->m_rfn.begin());
|
|
m_kdata->m_temp = T;
|
|
m_kdata->m_ROP_ok = false;
|
|
}
|
|
};
|
|
|
|
void SurfKinetics::
|
|
_update_rates_C() {
|
|
phase(0).getConcentrations(m_conc.begin());
|
|
if (m_twobulk) {
|
|
phase(1).getConcentrations(m_conc.begin() + m_kk1);
|
|
}
|
|
m_surfphase->getConcentrations(m_conc.begin() + m_kk1 + m_kk2);
|
|
m_rates.update_C(m_conc.begin());
|
|
m_kdata->m_ROP_ok = false;
|
|
}
|
|
|
|
void SurfKinetics::updateROP() {
|
|
|
|
_update_rates_C();
|
|
_update_rates_T();
|
|
|
|
if (m_kdata->m_ROP_ok) return;
|
|
|
|
const vector_fp& rf = m_kdata->m_rfn;
|
|
vector_fp& ropf = m_kdata->m_ropf;
|
|
|
|
// 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());
|
|
|
|
// multiply ropf by concentration products
|
|
int i, j, k, o;
|
|
for (i = 0; i < m_ii; i++) {
|
|
for (j = 0; j < m_nr[i]; j++) {
|
|
k = m_reactants[i][j];
|
|
o = m_order[i][j];
|
|
ropf[i] *= pow(m_conc[k],m_order[i][j]);
|
|
}
|
|
}
|
|
m_kdata->m_ROP_ok = true;
|
|
}
|
|
|
|
|
|
void SurfKinetics::
|
|
getNetProductionRates(doublereal* net) {
|
|
updateROP();
|
|
int i, n, k;
|
|
doublereal q;
|
|
for (k = 0; k < m_ktot; k++) net[k] = 0.0;
|
|
|
|
for (i = 0; i < m_ii; i++) {
|
|
q = m_kdata->m_ropf[i];
|
|
for (n = 0; n < m_nr[i]; n++) {
|
|
k = m_reactants[i][n];
|
|
net[k] -= q*m_rst[i][n];
|
|
}
|
|
for (n = 0; n < m_np[i]; n++) {
|
|
k = m_products[i][n];
|
|
net[k] += q*m_pst[i][n];
|
|
}
|
|
}
|
|
}
|
|
|
|
void SurfKinetics::
|
|
getCreationRates(doublereal* cdot) {
|
|
updateROP();
|
|
int i, n, k;
|
|
doublereal q;
|
|
fill(cdot, cdot + m_ktot, 0.0);
|
|
for (i = 0; i < m_ii; i++) {
|
|
q = m_kdata->m_ropf[i];
|
|
for (n = 0; n < m_np[i]; n++) {
|
|
k = m_products[i][n];
|
|
cdot[k] += q*m_pst[i][n];
|
|
}
|
|
}
|
|
}
|
|
|
|
void SurfKinetics::
|
|
getDestructionRates(doublereal* ddot) {
|
|
updateROP();
|
|
int i, n, k;
|
|
doublereal q;
|
|
fill(ddot, ddot + m_ktot, 0.0);
|
|
for (i = 0; i < m_ii; i++) {
|
|
q = m_kdata->m_ropf[i];
|
|
for (n = 0; n < m_nr[i]; n++) {
|
|
k = m_reactants[i][n];
|
|
ddot[k] += q*m_rst[i][n];
|
|
}
|
|
}
|
|
}
|
|
|
|
void SurfKinetics::
|
|
getChemRates(doublereal* rtau) {
|
|
updateROP();
|
|
int i, n, k;
|
|
doublereal q;
|
|
fill(rtau, rtau + m_ktot, 0.0);
|
|
for (i = 0; i < m_ii; i++) {
|
|
q = m_kdata->m_ropf[i];
|
|
for (n = 0; n < m_nr[i]; n++) {
|
|
k = m_reactants[i][n];
|
|
rtau[k] += q*m_rst[i][n];
|
|
}
|
|
}
|
|
for (k = 0;k < m_ktot; k++) {
|
|
if (m_conc[k] != 0.0)
|
|
rtau[k] = fabs(rtau[k]/m_conc[k]);
|
|
else
|
|
rtau[k] = 0.0;
|
|
}
|
|
}
|
|
|
|
void SurfKinetics::
|
|
saveReactionData(
|
|
const vector_int& r,
|
|
const vector_int& rstoich,
|
|
const vector_int& order,
|
|
const vector_int& p,
|
|
const vector_int& pstoich,
|
|
const vector_fp& rateParams) {
|
|
|
|
if (nReactions() == 0)
|
|
m_xml->addChild("ReactionArray");
|
|
|
|
XML_Node& rxndata = *new XML_Node("reaction");
|
|
int n, k;
|
|
string nm, ph, ustr, comment;
|
|
for (n = 0; n < r.size(); n++) {
|
|
XML_Node& reac = rxndata.addChild("reactant");
|
|
if (r[n] < m_kk1) {
|
|
k = r[n];
|
|
nm = phase(0).speciesName(k);
|
|
ph = phase(0).id();
|
|
ustr = "kmol/m^3";
|
|
m_bsp1[nm] = 1;
|
|
}
|
|
else if (r[n] < m_kk1 + m_kk2) {
|
|
k = r[n] - m_kk1;
|
|
nm = phase(1).speciesName(k);
|
|
ph = phase(1).id();
|
|
ustr = "kmol/m^3";
|
|
m_bsp2[nm] = 1;
|
|
}
|
|
else {
|
|
k = r[n] - m_kk1 - m_kk2; nm = m_surfphase->speciesName(k);
|
|
ph = ""; // m_surfphase->id();
|
|
ustr = "kmol/m^2";
|
|
}
|
|
if (ph != "") reac.addAttribute("phase",ph);
|
|
reac.addAttribute("name",nm);
|
|
reac.addAttribute("stoich",rstoich[n]);
|
|
reac.addAttribute("order",order[n]);
|
|
// reac.addAttribute("units",ustr);
|
|
comment += nm+" + ";
|
|
}
|
|
comment = comment.substr(0, comment.size() - 2) + " => ";
|
|
|
|
for (n = 0; n < p.size(); n++) {
|
|
XML_Node& prod = rxndata.addChild("product");
|
|
if (p[n] < m_kk1) {
|
|
k = p[n]; nm = phase(0).speciesName(k);
|
|
ph = phase(0).id();
|
|
ustr = "kmol/m^3";
|
|
}
|
|
else if (p[n] < m_kk1 + m_kk2) {
|
|
k = p[n] - m_kk1;
|
|
nm = phase(1).speciesName(k);
|
|
ph = phase(1).id();
|
|
ustr = "kmol/m^3";
|
|
}
|
|
else {
|
|
k = p[n] - m_kk1 - m_kk2;
|
|
nm = m_surfphase->speciesName(k);
|
|
ph = "";
|
|
ustr = "kmol/m^2";
|
|
}
|
|
if (ph != "") prod.addAttribute("phase",ph);
|
|
prod.addAttribute("name",nm);
|
|
prod.addAttribute("stoich",pstoich[n]);
|
|
comment += nm+" + ";
|
|
}
|
|
comment = " "+comment.substr(0, comment.size() - 2)+" ";
|
|
|
|
XML_Node& rate = rxndata.addChild("rate");
|
|
rate.addAttribute("type","Arrhenius");
|
|
rate.addAttribute("units","kmol/m^2/s");
|
|
addFloat(rate, "A", rateParams[0]);
|
|
addFloat(rate, "n", rateParams[1]);
|
|
addFloat(rate, "E", rateParams[2], "K");
|
|
|
|
XML_Node& rxns = m_xml->child("ReactionArray");
|
|
rxns.addComment(comment);
|
|
rxns.addChild(rxndata);
|
|
};
|
|
|
|
|
|
void SurfKinetics::
|
|
addReaction(const vector_int& r,
|
|
const vector_int& rstoich,
|
|
const vector_int& order,
|
|
const vector_int& p,
|
|
const vector_int& pstoich,
|
|
const vector_fp& rateParams) {
|
|
|
|
// record reaction parameters
|
|
saveReactionData(r, rstoich, order, p, pstoich, rateParams);
|
|
|
|
// prohibit adding more species
|
|
if (!m_surfphase->speciesFrozen())
|
|
m_surfphase->freezeSpecies();
|
|
|
|
// if init() hasn't been called yet, call it
|
|
if (m_kk == 0) init();
|
|
|
|
int iloc;
|
|
// install rate coeff calculator
|
|
iloc = m_rates.install( m_ii,
|
|
ARRHENIUS, rateParams.size(), rateParams.begin());
|
|
|
|
// add constant term to rate coeff value vector
|
|
m_kdata->m_rfn.push_back(rateParams[0]);
|
|
|
|
// forward rxn order
|
|
m_order.push_back(order);
|
|
|
|
m_kdata->m_ropf.push_back(0.0); // extend by one for new rxn
|
|
|
|
m_reactants.push_back(r);
|
|
m_rst.push_back(rstoich);
|
|
m_products.push_back(p);
|
|
m_pst.push_back(pstoich);
|
|
|
|
m_nr.push_back(r.size());
|
|
m_np.push_back(p.size());
|
|
|
|
incrementRxnCount();
|
|
}
|
|
|
|
|
|
void SurfKinetics::init() {
|
|
m_kk = m_surfphase->nSpecies();
|
|
m_ktot = m_kk + m_kk1 + m_kk2;
|
|
m_conc.resize(m_ktot);
|
|
Kinetics::init();
|
|
}
|
|
|
|
void SurfKinetics::save(string fname, string idtag, string comment) {
|
|
struct tm *newtime;
|
|
time_t aclock;
|
|
::time( &aclock ); /* Get time in seconds */
|
|
newtime = localtime( &aclock ); /* Convert time to struct tm form */
|
|
|
|
ofstream fout(fname.c_str());
|
|
XML_Node root("doc");
|
|
XML_Node& ct = root.addChild("ctml");
|
|
ct.addComment(comment);
|
|
|
|
XML_Node& iface = ct.addChild("interface");
|
|
addString(iface,"timestamp",asctime(newtime));
|
|
iface.addAttribute("id",idtag);
|
|
addFloat(iface, "site_density", m_surfphase->siteDensity());
|
|
XML_Node& bp1 = iface.addChild("phase");
|
|
bp1.addAttribute("id",phase(0).id());
|
|
map<string,int>::const_iterator b = m_bsp1.begin(), e = m_bsp1.end();
|
|
for (; b != e; ++b) {
|
|
bp1.addChild("species").addAttribute("name",b->first);
|
|
}
|
|
bp1.addChild(thermo(0).xml());
|
|
if (m_twobulk) {
|
|
XML_Node& bp2 = iface.addChild("phase");
|
|
bp2.addAttribute("id",phase(1).id());
|
|
map<string,int>::const_iterator b = m_bsp2.begin(), e = m_bsp2.end();
|
|
for (; b != e; ++b) {
|
|
bp2.addChild("species").addAttribute("name",b->first);
|
|
}
|
|
bp2.addChild(thermo(1).xml());
|
|
}
|
|
iface.addChild(m_surfphase->xml().child("SpeciesArray"));
|
|
iface.addChild(m_xml->child("ReactionArray"));
|
|
ct.writeHeader(fout);
|
|
ct.write(fout);
|
|
fout.close();
|
|
}
|
|
|
|
void SurfKinetics::finalize() {
|
|
if (!m_finalized) {
|
|
m_finalized = true;
|
|
}
|
|
}
|
|
|
|
bool SurfKinetics::ready() const {
|
|
return (m_finalized);
|
|
}
|
|
|
|
void SurfKinetics::integrate(doublereal dt) {
|
|
finalize();
|
|
if (m_integrator == 0) {
|
|
m_integrator = new ImplicitSurfChem(*this);
|
|
m_integrator->initialize(0.0);
|
|
}
|
|
m_integrator->integrate(0.0, dt);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|