Cantera  2.0
ImplicitSurfChem.cpp
Go to the documentation of this file.
1 /**
2  * @file ImplicitSurfChem.cpp
3  * Definitions for the implicit integration of surface site density equations
4  * (see \ref kineticsmgr and class
5  * \link Cantera::ImplicitSurfChem ImplicitSurfChem\endlink).
6  */
7 // Copyright 2001 California Institute of Technology
8 
9 #include "ImplicitSurfChem.h"
11 #include "solveSP.h"
12 
13 using namespace std;
14 
15 namespace Cantera
16 {
17 
18 // Constructor
19 ImplicitSurfChem::ImplicitSurfChem(vector<InterfaceKinetics*> k) :
20  FuncEval(),
21  m_nsurf(0),
22  m_nv(0),
23  m_numBulkPhases(0),
24  m_numTotalBulkSpecies(0),
25  m_numTotalSpecies(0),
26  m_integ(0),
27  m_atol(1.e-14),
28  m_rtol(1.e-7),
29  m_maxstep(0.0),
30  m_mediumSpeciesStart(-1),
31  m_bulkSpeciesStart(-1),
32  m_surfSpeciesStart(-1),
33  m_surfSolver(0),
34  m_commonTempPressForPhases(true),
35  m_ioFlag(0)
36 {
37  m_nsurf = k.size();
38  size_t ns, nsp;
39  size_t nt, ntmax = 0;
40  size_t kinSpIndex = 0;
41  // Loop over the number of surface kinetics objects
42  for (size_t n = 0; n < m_nsurf; n++) {
43  InterfaceKinetics* kinPtr = k[n];
44  m_vecKinPtrs.push_back(kinPtr);
45  ns = k[n]->surfacePhaseIndex();
46  if (ns == npos)
47  throw CanteraError("ImplicitSurfChem",
48  "kinetics manager contains no surface phase");
49  m_surfindex.push_back(ns);
50  m_surf.push_back((SurfPhase*)&k[n]->thermo(ns));
51  nsp = m_surf.back()->nSpecies();
52  m_nsp.push_back(nsp);
53  m_nv += m_nsp.back();
54  nt = k[n]->nTotalSpecies();
55  if (nt > ntmax) {
56  ntmax = nt;
57  }
58  m_specStartIndex.push_back(kinSpIndex);
59  kinSpIndex += nsp;
60 
61  size_t nPhases = kinPtr->nPhases();
62  vector_int pLocTmp(nPhases);
63  size_t imatch = npos;
64  for (size_t ip = 0; ip < nPhases; ip++) {
65  if (ip != ns) {
66  ThermoPhase* thPtr = & kinPtr->thermo(ip);
67  if ((imatch = checkMatch(m_bulkPhases, thPtr)) == npos) {
68  m_bulkPhases.push_back(thPtr);
69  m_numBulkPhases++;
70  nsp = thPtr->nSpecies();
71  m_nspBulkPhases.push_back(nsp);
72  m_numTotalBulkSpecies += nsp;
73  imatch = m_bulkPhases.size() - 1;
74  }
75  pLocTmp[ip] = int(imatch);
76  } else {
77  pLocTmp[ip] = -int(n);
78  }
79  }
80  pLocVec.push_back(pLocTmp);
81 
82  }
83  m_numTotalSpecies = m_nv + m_numTotalBulkSpecies;
84  m_concSpecies.resize(m_numTotalSpecies, 0.0);
85  m_concSpeciesSave.resize(m_numTotalSpecies, 0.0);
86 
87  m_integ = newIntegrator("CVODE");
88 
89 
90 
91  // use backward differencing, with a full Jacobian computed
92  // numerically, and use a Newton linear iterator
93 
95  m_integ->setProblemType(DENSE + NOJAC);
97  m_work.resize(ntmax);
98 }
99 
100 int ImplicitSurfChem::checkMatch(std::vector<ThermoPhase*> m_vec, ThermoPhase* thPtr)
101 {
102  int retn = -1;
103  for (int i = 0; i < (int) m_vec.size(); i++) {
104  ThermoPhase* th = m_vec[i];
105  if (th == thPtr) {
106  return i;
107  }
108  }
109  return retn;
110 }
111 
112 /*
113  * Destructor. Deletes the integrator.
114  */
116 {
117  if (m_integ) {
118  delete m_integ;
119  }
120  if (m_surfSolver) {
121  delete m_surfSolver;
122  }
123 }
124 
125 // overloaded method of FuncEval. Called by the integrator to
126 // get the initial conditions.
127 void ImplicitSurfChem::getInitialConditions(doublereal t0, size_t lenc,
128  doublereal* c)
129 {
130  size_t loc = 0;
131  for (size_t n = 0; n < m_nsurf; n++) {
132  m_surf[n]->getCoverages(c + loc);
133  loc += m_nsp[n];
134  }
135 }
136 
137 
138 /*
139  * Must be called before calling method 'advance'
140  */
141 void ImplicitSurfChem::initialize(doublereal t0)
142 {
143  m_integ->setTolerances(m_rtol, m_atol);
144  m_integ->initialize(t0, *this);
145 }
146 
147 // Integrate from t0 to t1. The integrator is reinitialized first.
148 /*
149  * This routine does a time accurate solve from t = t0 to t = t1.
150  * of the surface problem.
151  *
152  * @param t0 Initial Time -> this is an input
153  * @param t1 Final Time -> This is an input
154  */
155 void ImplicitSurfChem::integrate(doublereal t0, doublereal t1)
156 {
157  m_integ->initialize(t0, *this);
158  m_integ->setMaxStepSize(t1 - t0);
159  m_integ->integrate(t1);
161 }
162 
163 // Integrate from t0 to t1 without reinitializing the integrator.
164 /*
165  * Use when the coverages have not changed from
166  * their values on return from the last call to integrate or
167  * integrate0.
168  *
169  * @param t0 Initial Time -> this is an input
170  * @param t1 Final Time -> This is an input
171  */
172 void ImplicitSurfChem::integrate0(doublereal t0, doublereal t1)
173 {
174  m_integ->integrate(t1);
176 }
177 
178 void ImplicitSurfChem::updateState(doublereal* c)
179 {
180  size_t loc = 0;
181  for (size_t n = 0; n < m_nsurf; n++) {
182  m_surf[n]->setCoverages(c + loc);
183  loc += m_nsp[n];
184  }
185 }
186 
187 /*
188  * Called by the integrator to evaluate ydot given y at time 'time'.
189  */
190 void ImplicitSurfChem::eval(doublereal time, doublereal* y,
191  doublereal* ydot, doublereal* p)
192 {
193  updateState(y); // synchronize the surface state(s) with y
194  doublereal rs0, sum;
195  size_t loc, kstart;
196  for (size_t n = 0; n < m_nsurf; n++) {
197  rs0 = 1.0/m_surf[n]->siteDensity();
198  m_vecKinPtrs[n]->getNetProductionRates(DATA_PTR(m_work));
199  kstart = m_vecKinPtrs[n]->kineticsSpeciesIndex(0,m_surfindex[n]);
200  sum = 0.0;
201  loc = 0;
202  for (size_t k = 1; k < m_nsp[n]; k++) {
203  ydot[k + loc] = m_work[kstart + k] * rs0 * m_surf[n]->size(k);
204  sum -= ydot[k];
205  }
206  ydot[loc] = sum;
207  loc += m_nsp[n];
208  }
209 }
210 
211 // Solve for the pseudo steady-state of the surface problem
212 /*
213  * Solve for the steady state of the surface problem.
214  * This is the same thing as the advanceCoverages() function,
215  * but at infinite times.
216  *
217  * Note, a direct solve is carried out under the hood here,
218  * to reduce the computational time.
219  */
221  doublereal timeScaleOverride)
222 {
223 
224  int ifunc;
225  /*
226  * set bulkFunc
227  * -> We assume that the bulk concentrations are constant.
228  */
229  int bulkFunc = BULK_ETCH;
230  /*
231  * time scale - time over which to integrate equations
232  */
233  doublereal time_scale = timeScaleOverride;
234  if (!m_surfSolver) {
235  m_surfSolver = new solveSP(this, bulkFunc);
236  /*
237  * set ifunc, which sets the algorithm.
238  */
239  ifunc = SFLUX_INITIALIZE;
240  } else {
241  ifunc = SFLUX_RESIDUAL;
242  }
243 
244  // Possibly override the ifunc value
245  if (ifuncOverride >= 0) {
246  ifunc = ifuncOverride;
247  }
248 
249  /*
250  * Get the specifications for the problem from the values
251  * in the ThermoPhase objects for all phases.
252  *
253  * 1) concentrations of all species in all phases, m_concSpecies[]
254  * 2) Temperature and pressure
255  */
256  getConcSpecies(DATA_PTR(m_concSpecies));
258  ThermoPhase& tp = ik->thermo(0);
259  doublereal TKelvin = tp.temperature();
260  doublereal PGas = tp.pressure();
261  /*
262  * Make sure that there is a common temperature and
263  * pressure for all ThermoPhase objects belonging to the
264  * interfacial kinetics object, if it is required by
265  * the problem statement.
266  */
268  setCommonState_TP(TKelvin, PGas);
269  }
270 
271  doublereal reltol = 1.0E-6;
272  doublereal atol = 1.0E-20;
273 
274  /*
275  * Install a filter for negative concentrations. One of the
276  * few ways solveSS can fail is if concentrations on input
277  * are below zero.
278  */
279  bool rset = false;
280  for (size_t k = 0; k < m_nv; k++) {
281  if (m_concSpecies[k] < 0.0) {
282  rset = true;
283  m_concSpecies[k] = 0.0;
284  }
285  }
286  if (rset) {
288  }
289 
290  m_surfSolver->m_ioflag = m_ioFlag;
291 
292  // Save the current solution
293  copy(m_concSpecies.begin(), m_concSpecies.end(), m_concSpeciesSave.begin());
294 
295 
296  int retn = m_surfSolver->solveSurfProb(ifunc, time_scale, TKelvin, PGas,
297  reltol, atol);
298  if (retn != 1) {
299  // reset the concentrations
300  copy(m_concSpeciesSave.begin(), m_concSpeciesSave.end(), m_concSpecies.begin());
301  setConcSpecies(DATA_PTR(m_concSpeciesSave));
302  ifunc = SFLUX_INITIALIZE;
303  retn = m_surfSolver->solveSurfProb(ifunc, time_scale, TKelvin, PGas,
304  reltol, atol);
305 
306  if (retn != 1) {
307  throw CanteraError("ImplicitSurfChem::solvePseudoSteadyStateProblem",
308  "solveSP return an error condition!");
309  }
310  }
311 }
312 
313 
314 
315 /*
316  * getConcSpecies():
317  *
318  * Fills the local concentration vector, m_concSpecies for all of the
319  * species in all of the phases that are unknowns in the surface
320  * problem.
321  *
322  * m_concSpecies[]
323  */
324 void ImplicitSurfChem::getConcSpecies(doublereal* const vecConcSpecies) const
325 {
326  size_t kstart;
327  for (size_t ip = 0; ip < m_nsurf; ip++) {
328  ThermoPhase* TP_ptr = m_surf[ip];
329  kstart = m_specStartIndex[ip];
330  TP_ptr->getConcentrations(vecConcSpecies + kstart);
331  }
332  kstart = m_nv;
333  for (size_t ip = 0; ip < m_numBulkPhases; ip++) {
334  ThermoPhase* TP_ptr = m_bulkPhases[ip];
335  TP_ptr->getConcentrations(vecConcSpecies + kstart);
336  kstart += TP_ptr->nSpecies();
337  }
338 }
339 
340 /*
341  * setConcSpecies():
342  *
343  * Fills the local concentration vector, m_concSpecies for all of the
344  * species in all of the phases that are unknowns in the surface
345  * problem.
346  *
347  * m_concSpecies[]
348  */
349 void ImplicitSurfChem::setConcSpecies(const doublereal* const vecConcSpecies)
350 {
351  size_t kstart;
352  for (size_t ip = 0; ip < m_nsurf; ip++) {
353  ThermoPhase* TP_ptr = m_surf[ip];
354  kstart = m_specStartIndex[ip];
355  TP_ptr->setConcentrations(vecConcSpecies + kstart);
356  }
357  kstart = m_nv;
358  for (size_t ip = 0; ip < m_numBulkPhases; ip++) {
359  ThermoPhase* TP_ptr = m_bulkPhases[ip];
360  TP_ptr->setConcentrations(vecConcSpecies + kstart);
361  kstart += TP_ptr->nSpecies();
362  }
363 }
364 
365 /*
366  * setCommonState_TP():
367  *
368  * Sets a common temperature and pressure amongst the
369  * thermodynamic objects in the interfacial kinetics object.
370  *
371  * Units Temperature = Kelvin
372  * Pressure = Pascal
373  */
375 setCommonState_TP(doublereal TKelvin, doublereal PresPa)
376 {
377  for (size_t ip = 0; ip < m_nsurf; ip++) {
378  ThermoPhase* TP_ptr = m_surf[ip];
379  TP_ptr->setState_TP(TKelvin, PresPa);
380  }
381  for (size_t ip = 0; ip < m_numBulkPhases; ip++) {
382  ThermoPhase* TP_ptr = m_bulkPhases[ip];
383  TP_ptr->setState_TP(TKelvin, PresPa);
384  }
385 }
386 
387 }