Cantera  2.0
solveSP.h
Go to the documentation of this file.
1 /**
2  * @file solveSP.h
3  * Header file for implicit surface problem solver
4  * (see \ref chemkinetics and class \link Cantera::solveSP solveSP\endlink).
5  */
6 /*
7  * Copyright 2004 Sandia Corporation. Under the terms of Contract
8  * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
9  * retains certain rights in this software.
10  * See file License.txt for licensing information.
11  */
12 
13 #ifndef SOLVESP_H
14 #define SOLVESP_H
15 
16 #include "ImplicitSurfChem.h"
18 
19 #include <vector>
20 #include "cantera/base/Array.h"
21 
22 //! Solution Methods
23 /*!
24  * Flag to specify the solution method
25  *
26  * 1: SFLUX_INITIALIZE = This assumes that the initial guess supplied to the
27  * routine is far from the correct one. Substantial
28  * work plus transient time-stepping is to be expected
29  * to find a solution.
30  * 2: SFLUX_RESIDUAL = Need to solve the surface problem in order to
31  * calculate the surface fluxes of gas-phase species.
32  * (Can expect a moderate change in the solution
33  * vector -> try to solve the system by direct
34  * methods
35  * with no damping first -> then, try time-stepping
36  * if the first method fails)
37  * A "time_scale" supplied here is used in the
38  * algorithm to determine when to shut off
39  * time-stepping.
40  * 3: SFLUX_JACOBIAN = Calculation of the surface problem is due to the
41  * need for a numerical jacobian for the gas-problem.
42  * The solution is expected to be very close to the
43  * initial guess, and accuracy is needed.
44  * 4: SFLUX_TRANSIENT = The transient calculation is performed here for an
45  * amount of time specified by "time_scale". It is
46  * not guaranteed to be time-accurate - just stable
47  * and fairly fast. The solution after del_t time is
48  * returned, whether it's converged to a steady
49  * state or not.
50  */
51 const int SFLUX_INITIALIZE = 1;
52 const int SFLUX_RESIDUAL = 2;
53 const int SFLUX_JACOBIAN = 3;
54 const int SFLUX_TRANSIENT = 4;
55 
56 
57 /*
58  * bulkFunc: Functionality expected from the bulk phase. This changes the
59  * equations that will be used to solve for the bulk mole
60  * fractions.
61  * 1: BULK_DEPOSITION = deposition of a bulk phase is to be expected.
62  * Bulk mole fractions are determined from ratios of
63  * growth rates of bulk species.
64  * 2: BULK_ETCH = Etching of a bulk phase is to be expected.
65  * Bulk mole fractions are assumed constant, and given
66  * by the initial conditions. This is also used
67  whenever the condensed phase is part of the larger
68  solution.
69 */
70 const int BULK_DEPOSITION = 1;
71 const int BULK_ETCH = 2;
72 
73 namespace Cantera
74 {
75 
76 class InterfaceKinetics;
77 
78 //! Method to solve a pseudo steady state surface problem
79 /*!
80  * The following class handles solving the surface problem.
81  * The calculation uses Newton's method to
82  * obtain the surface fractions of the surface and bulk species by
83  * requiring that the
84  * surface species production rate = 0 and that the either the
85  * bulk fractions are proportional to their production rates
86  * or they are constants.
87  *
88  * Currently, the bulk mole fractions are treated as constants.
89  * Implementation of their being added to the unknown solution
90  * vector is delayed.
91  *
92  * Lets introduce the unknown vector for the "surface
93  * problem". The surface problem is defined as the evaluation of the surface
94  * site fractions for multiple surface phases.
95  * The unknown vector will consist of the vector of surface concentrations for each
96  * species in each surface vector. Species are grouped first by their surface phases
97  *
98  * C_i_j = Concentration of the ith species in the jth surface phase
99  * Nj = number of surface species in the jth surface phase
100  *
101  * The unknown solution vector is defined as follows:
102  *
103  * kindexSP
104  * ----------------------------
105  * C_0_0 0
106  * C_1_0 1
107  * C_2_0 2
108  * . . . ...
109  * C_N0-1_0 N0-1
110  * C_0_1 N0
111  * C_1_1 N0+1
112  * C_2_1 N0+2
113  * . . . ...
114  * C_N1-1_1 NO+N1-1
115  *
116  *
117  * Note there are a couple of different types of species indices
118  * floating around in the formulation of this object.
119  *
120  * kindexSP This is the species index in the contiguous vector of unknowns
121  * for the surface problem.
122  *
123  * Note, in the future, BULK_DEPOSITION systems will be added, and the solveSP unknown
124  * vector will get more complicated. It will include the mole fraction and growth rates
125  * of specified bulk phases
126  *
127  * Indices which relate to individual kinetics objects use the suffix KSI (kinetics
128  * species index).
129  *
130  *
131  * Solution Method
132  *
133  * This routine is typically used within a residual calculation in a large code.
134  * It's typically invoked millions of times for large calculations, and it must
135  * work every time. Therefore, requirements demand that it be robust but also
136  * efficient.
137  *
138  * The solution methodology is largely determined by the <TT>ifunc<\TT> parameter,
139  * that is input to the solution object. This parameter may have the following
140  * 4 values:
141  *
142  *
143  * 1: SFLUX_INITIALIZE = This assumes that the initial guess supplied to the
144  * routine is far from the correct one. Substantial
145  * work plus transient time-stepping is to be expected
146  * to find a solution.
147  *
148  * 2: SFLUX_RESIDUAL = Need to solve the surface problem in order to
149  * calculate the surface fluxes of gas-phase species.
150  * (Can expect a moderate change in the solution
151  * vector -> try to solve the system by direct methods
152  * with no damping first -> then, try time-stepping
153  * if the first method fails)
154  * A "time_scale" supplied here is used in the
155  * algorithm to determine when to shut off
156  * time-stepping.
157  *
158  * 3: SFLUX_JACOBIAN = Calculation of the surface problem is due to the
159  * need for a numerical jacobian for the gas-problem.
160  * The solution is expected to be very close to the
161  * initial guess, and extra accuracy is needed because
162  * solution variables have been delta'd from
163  * nominal values to create jacobian entries.
164  *
165  * 4: SFLUX_TRANSIENT = The transient calculation is performed here for an
166  * amount of time specified by "time_scale". It is
167  * not guaranteed to be time-accurate - just stable
168  * and fairly fast. The solution after del_t time is
169  * returned, whether it's converged to a steady
170  * state or not. This is a poor man's time stepping
171  * algorithm.
172  *
173  * Pseudo time stepping algorithm:
174  * The time step is determined from sdot[], so so that the time step
175  * doesn't ever change the value of a variable by more than 100%.
176  *
177  * This algorithm does use a damped Newton's method to relax the equations.
178  * Damping is based on a "delta damping" technique. The solution unknowns
179  * are not allowed to vary too much between iterations.
180  *
181  *
182  * EXTRA_ACCURACY:A constant that is the ratio of the required update norm in
183  * this Newton iteration compared to that in the nonlinear solver.
184  * A value of 0.1 is used so surface species are safely overconverged.
185  *
186  * Functions called:
187  *----------------------------------------------------------------------------
188  *
189  * ct_dgetrf -- First half of LAPACK direct solve of a full Matrix
190  *
191  * ct_dgetrs -- Second half of LAPACK direct solve of a full matrix. Returns
192  * solution vector in the right-hand-side vector, resid.
193  *
194  *----------------------------------------------------------------------------
195  *
196  */
197 class solveSP
198 {
199 
200 public:
201 
202  //! Constructor for the object
203  /*!
204  * @param surfChemPtr Pointer to the ImplicitSurfChem object that
205  * defines the surface problem to be solved.
206  *
207  * @param bulkFunc Integer representing how the bulk phases
208  * should be handled. Currently, only the
209  * default value of BULK_ETCH is supported.
210  */
211  solveSP(ImplicitSurfChem* surfChemPtr, int bulkFunc = BULK_ETCH);
212 
213  //! Destructor. Deletes the integrator.
214  ~solveSP();
215 
216 private:
217 
218  //! Unimplemented private copy constructor
219  solveSP(const solveSP& right);
220 
221  //! Unimplemented private assignment operator
222  solveSP& operator=(const solveSP& right);
223 
224 public:
225 
226  //! Main routine that actually calculates the pseudo steady state
227  //! of the surface problem
228  /*!
229  * The actual converged solution is returned as part of the
230  * internal state of the InterfaceKinetics objects.
231  *
232  * @param ifunc Determines the type of solution algorithm to be
233  * used. Possible values are SFLUX_INITIALIZE ,
234  * SFLUX_RESIDUAL SFLUX_JACOBIAN SFLUX_TRANSIENT .
235  *
236  * @param time_scale Time over which to integrate the surface equations,
237  * where applicable
238  *
239  * @param TKelvin Temperature (kelvin)
240  *
241  * @param PGas Pressure (pascals)
242  *
243  * @param reltol Relative tolerance to use
244  * @param abstol absolute tolerance.
245  *
246  * @return Returns 1 if the surface problem is successfully solved.
247  * Returns -1 if the surface problem wasn't solved successfully.
248  * Note the actual converged solution is returned as part of the
249  * internal state of the InterfaceKinetics objects.
250  */
251  int solveSurfProb(int ifunc, doublereal time_scale, doublereal TKelvin,
252  doublereal PGas, doublereal reltol, doublereal abstol);
253 
254 private:
255 
256  //! Printing routine that gets called at the start of every
257  //! invocation
258  void print_header(int ioflag, int ifunc, doublereal time_scale,
259  int damping, doublereal reltol, doublereal abstol,
260  doublereal TKelvin, doublereal PGas, doublereal netProdRate[],
261  doublereal XMolKinSpecies[]);
262 
263  //! Printing routine that gets called after every iteration
264  void printIteration(int ioflag, doublereal damp, int label_d, int label_t,
265  doublereal inv_t, doublereal t_real, size_t iter,
266  doublereal update_norm, doublereal resid_norm,
267  doublereal netProdRate[], doublereal CSolnSP[],
268  doublereal resid[], doublereal XMolSolnSP[],
269  doublereal wtSpecies[], size_t dim, bool do_time);
270 
271 
272  //! Print a summary of the solution
273  /*!
274  *
275  */
276  void printFinal(int ioflag, doublereal damp, int label_d, int label_t,
277  doublereal inv_t, doublereal t_real, size_t iter,
278  doublereal update_norm, doublereal resid_norm,
279  doublereal netProdRateKinSpecies[], const doublereal CSolnSP[],
280  const doublereal resid[], doublereal XMolSolnSP[],
281  const doublereal wtSpecies[], const doublereal wtRes[],
282  size_t dim, bool do_time,
283  doublereal TKelvin, doublereal PGas);
284 
285  //! Calculate a conservative delta T to use in a pseudo-steady state
286  //! algorithm
287  /*!
288  * This routine calculates a pretty conservative 1/del_t based
289  * on MAX_i(sdot_i/(X_i*SDen0)). This probably guarantees
290  * diagonal dominance.
291  *
292  * Small surface fractions are allowed to intervene in the del_t
293  * determination, no matter how small. This may be changed.
294  * Now minimum changed to 1.0e-12,
295  *
296  * Maximum time step set to time_scale.
297  *
298  * @param netProdRateSolnSP Output variable. Net production rate
299  * of all of the species in the solution vector.
300  * @param XMolSolnSP output variable.
301  * Mole fraction of all of the species in the solution vector
302  * @param label Output variable. Pointer to the value of the
303  * species index (kindexSP) that is controlling
304  * the time step
305  * @param label_old Output variable. Pointer to the value of the
306  * species index (kindexSP) that controlled
307  * the time step at the previous iteration
308  * @param label_factor Output variable. Pointer to the current
309  * factor that is used to indicate the same species
310  * is controlling the time step.
311  *
312  * @param ioflag Level of the output requested.
313  *
314  * @return Returns the 1. / delta T to be used on the next step
315  */
316  doublereal calc_t(doublereal netProdRateSolnSP[], doublereal XMolSolnSP[],
317  int* label, int* label_old,
318  doublereal* label_factor, int ioflag);
319 
320  //! Calculate the solution and residual weights
321  /*!
322  * @param wtSpecies Weights to use for the soln unknowns. These
323  * are in concentration units
324  * @param wtResid Weights to sue for the residual unknowns.
325  *
326  * @param Jac Jacobian. Row sum scaling is used for the Jacobian
327  * @param CSolnSP Solution vector for the surface problem
328  * @param abstol Absolute error tolerance
329  * @param reltol Relative error tolerance
330  */
331  void calcWeights(doublereal wtSpecies[], doublereal wtResid[],
332  const Array2D& Jac, const doublereal CSolnSP[],
333  const doublereal abstol, const doublereal reltol);
334 
335  /**
336  * Update the surface states of the surface phases.
337  */
338  void updateState(const doublereal* cSurfSpec);
339 
340  //! Update mole fraction vector consisting of unknowns in surface problem
341  /*!
342  * @param XMolSolnSP Vector of mole fractions for the unknowns in the
343  * surface problem.
344  */
345  void updateMFSolnSP(doublereal* XMolSolnSP);
346 
347  //! Update the mole fraction vector for a specific kinetic species vector
348  //! corresponding to one InterfaceKinetics object
349  /*!
350  * @param XMolKinSp Mole fraction vector corresponding to a particular
351  * kinetic species for a single InterfaceKinetics Object
352  * This is a vector over all the species in all of the
353  * phases in the InterfaceKinetics object
354  * @param isp ID of the InterfaceKinetics Object.
355  */
356  void updateMFKinSpecies(doublereal* XMolKinSp, int isp);
357 
358 
359  //! Update the vector that keeps track of the largest species in each
360  //! surface phase.
361  /*!
362  * @param CsolnSP Vector of the current values of the surface concentrations
363  * in all of the surface species.
364  */
365  void evalSurfLarge(const doublereal* CSolnSP);
366 
367  //! Main Function evaluation
368  /*!
369  *
370  * @param resid output Vector of residuals, length = m_neq
371  * @param CSolnSP Vector of species concentrations, unknowns in the
372  * problem, length = m_neq
373  * @param CSolnSPOld Old Vector of species concentrations, unknowns in the
374  * problem, length = m_neq
375  * @param do_time Calculate a time dependent residual
376  * @param deltaT Delta time for time dependent problem.
377  */
378  void fun_eval(doublereal* resid, const doublereal* CSolnSP,
379  const doublereal* CSolnOldSP, const bool do_time, const doublereal deltaT);
380 
381  //! Main routine that calculates the current residual and Jacobian
382  /*!
383  * @param JacCol Vector of pointers to the tops of columns of the
384  * Jacobian to be evaluated.
385  * @param resid output Vector of residuals, length = m_neq
386  * @param CSolnSP Vector of species concentrations, unknowns in the
387  * problem, length = m_neq. These are tweaked in order
388  * to derive the columns of the jacobian.
389  * @param CSolnSPOld Old Vector of species concentrations, unknowns in the
390  * problem, length = m_neq
391  * @param do_time Calculate a time dependent residual
392  * @param deltaT Delta time for time dependent problem.
393  */
394  void resjac_eval(std::vector<doublereal*>& JacCol, doublereal* resid,
395  doublereal* CSolnSP,
396  const doublereal* CSolnSPOld, const bool do_time,
397  const doublereal deltaT);
398 
399  //! Pointer to the manager of the implicit surface chemistry
400  //! problem
401  /*!
402  * This object actually calls the current object. Thus, we are
403  * providing a loop-back functionality here.
404  */
406 
407  //! Vector of interface kinetics objects
408  /*!
409  * Each of these is associated with one and only one surface phase.
410  */
411  std::vector<InterfaceKinetics*> &m_objects;
412 
413  //! Total number of equations to solve in the implicit problem.
414  /*!
415  * Note, this can be zero, and frequently is
416  */
417  size_t m_neq;
418 
419  //! This variable determines how the bulk phases are to be handled
420  /*!
421  * = BULK_ETCH (default) The concentrations of the bulk phases are
422  * considered constant, just as the gas phase is.
423  * They are not part of the solution vector.
424  * = BULK_DEPOSITION =
425  * We solve here for the composition of the bulk
426  * phases by calculating a growth rate. The equations
427  * for the species in the bulk phases are
428  * unknowns in this calculation.
429  */
431 
432  //! Number of surface phases in the surface problem
433  /*!
434  * This number is equal to the number of InterfaceKinetics objects
435  * in the problem. (until further noted)
436  */
438 
439  //! Total number of surface species in all surface phases.
440  /*!
441  * This is also the number of equations to solve for m_mode=0 system
442  * It's equal to the sum of the number of species in each of the
443  * m_numSurfPhases.
444  */
446 
447  //! Mapping between the surface phases and the InterfaceKinetics objects
448  /*!
449  * Currently this is defined to be a 1-1 mapping (and probably assumed
450  * in some places)
451  * m_surfKinObjID[i] = i
452  */
453  std::vector<size_t> m_indexKinObjSurfPhase;
454 
455  //! Vector of length number of surface phases containing
456  //! the number of surface species in each phase
457  /*!
458  * Length is equal to the number of surface phases, m_numSurfPhases
459  */
460  std::vector<size_t> m_nSpeciesSurfPhase;
461 
462  //! Vector of surface phase pointers
463  /*!
464  * This is created during the constructor
465  * Length is equal to the number of surface phases, m_numSurfPhases
466  */
467  std::vector<SurfPhase*> m_ptrsSurfPhase;
468 
469  //! Index of the start of the unknowns for each solution phase
470  /*!
471  * i_eqn = m_eqnIndexStartPhase[isp]
472  *
473  * isp is the phase id in the list of phases solved by the
474  * surface problem.
475  *
476  * i_eqn is the equation number of the first unknown in the
477  * solution vector corresponding to isp'th phase.
478  */
479  std::vector<size_t> m_eqnIndexStartSolnPhase;
480 
481  //! Phase ID in the InterfaceKinetics object of the surface phase
482  /*!
483  * For each surface phase, this lists the PhaseId of the
484  * surface phase in the corresponding InterfaceKinetics object
485  *
486  * Length is equal to m_numSurfPhases
487  */
488  std::vector<size_t> m_kinObjPhaseIDSurfPhase;
489 
490  //! Total number of volumetric condensed phases included in the steady state
491  //! problem handled by this routine.
492  /*!
493  * This is equal to or less
494  * than the total number of volumetric phases in all of the InterfaceKinetics
495  * objects. We usually do not include bulk phases. Bulk phases
496  * are only included in the calculation when their domain isn't included
497  * in the underlying continuum model conservation equation system.
498  *
499  * This is equal to 0, for the time being
500  */
502 
503  //! Vector of number of species in the m_numBulkPhases phases.
504  /*!
505  * Length is number of bulk phases
506  */
507  std::vector<size_t> m_numBulkSpecies;
508 
509  //std::vector<int> m_bulkKinObjID;
510  //std::vector<int> m_bulkKinObjPhaseID;
511 
512 
513  //! Total number of species in all bulk phases.
514  /*!
515  * This is also the number of bulk equations to solve when bulk
516  * equation solving is turned on.
517  */
519 
520  //! Vector of bulk phase pointers, length is equal to m_numBulkPhases.
521  /*!
522  *
523  */
524  std::vector<ThermoPhase*> m_bulkPhasePtrs;
525 
526  //! Index between the equation index and the position in the
527  //! kinetic species array for the appropriate kinetics
528  //! operator
529  /*!
530  * Length = m_neq.
531  *
532  * ksp = m_kinSpecIndex[ieq]
533  * ksp is the kinetic species index for the ieq'th equation.
534  */
535  std::vector<size_t> m_kinSpecIndex;
536 
537  //! Index between the equation index and the index of the
538  //! InterfaceKinetics object
539  /*!
540  * Length m_neq
541  */
542  std::vector<size_t> m_kinObjIndex;
543 
544  //! Vector containing the indices of the largest species
545  //! in each surface phase
546  /*!
547  * k = m_spSurfLarge[i]
548  * where
549  * k is the local species index, i.e.,
550  * it varies from 0 num species in phase-1
551  * i is the surface phase index in the problem
552  *
553  * length is equal to m_numSurfPhases
554  */
555  std::vector<size_t> m_spSurfLarge;
556 
557  //! m_atol is the absolute tolerance in real units.
558  /*!
559  * units are (kmol/m2)
560  */
561  doublereal m_atol;
562 
563  //! m_rtol is the relative error tolerance.
564  doublereal m_rtol;
565 
566  //! maximum value of the time step
567  /*!
568  * units = seconds
569  */
570  doublereal m_maxstep;
571 
572  //! Maximum number of species in any single kinetics operator
573  //! -> also maxed wrt the total # of solution species
575 
576  //! Temporary vector with length equal to max m_maxTotSpecies
578 
579  //! Temporary vector with length equal to max m_maxTotSpecies
581 
582  //! Temporary vector with length equal to max m_maxTotSpecies
584 
585  //! Temporary vector with length equal to max m_maxTotSpecies
587 
588  //! Solution vector
589  /*!
590  * length MAX(1, m_neq)
591  */
593 
594  //! Saved initial solution vector
595  /*!
596  * length MAX(1, m_neq)
597  */
599 
600  //! Saved solution vector at the old time step
601  /*!
602  * length MAX(1, m_neq)
603  */
605 
606  //! Weights for the residual norm calculation
607  /*!
608  * length MAX(1, m_neq)
609  */
611 
612  //! Weights for the species concentrations norm calculation
613  /*!
614  * length MAX(1, m_neq)
615  */
617 
618  //! Residual for the surface problem
619  /*!
620  * The residual vector of length "dim" that, that has the value
621  * of "sdot" for surface species. The residuals for the bulk
622  * species are a function of the sdots for all species in the bulk
623  * phase. The last residual of each phase enforces {Sum(fractions)
624  * = 1}. After linear solve (dgetrf_ & dgetrs_), resid holds the
625  * update vector.
626  *
627  * length MAX(1, m_neq)
628  */
630 
631  //! Vector of mole fractions
632  /*!
633  *length m_maxTotSpecies
634  */
636 
637  //! pivots
638  /*!
639  * length MAX(1, m_neq)
640  */
642 
643  //! Vector of pointers to the top of the columns of the
644  //! jacobians
645  /*!
646  * The "dim" by "dim" computed Jacobian matrix for the
647  * local Newton's method.
648  */
649  std::vector<doublereal*> m_JacCol;
650 
651  //! Jacobian
652  /*!
653  * m_neq by m_neq computed Jacobian matrix for the
654  * local Newton's method.
655  */
657 
658 
659 public:
660  int m_ioflag;
661 };
662 }
663 #endif