Cantera  2.2.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ChemEquil.h
Go to the documentation of this file.
1 /**
2  * @file ChemEquil.h Chemical equilibrium.
3  */
4 /*
5  * Copyright 2001 California Institute of Technology
6  */
7 
8 #ifndef CT_CHEM_EQUIL_H
9 #define CT_CHEM_EQUIL_H
10 
11 // Cantera includes
12 #include "cantera/base/ct_defs.h"
15 
16 #include <memory>
17 
18 namespace Cantera
19 {
20 
21 class DenseMatrix;
22 /// map property strings to integers
23 int _equilflag(const char* xy);
24 
25 /**
26  * Chemical equilibrium options. Used internally by class ChemEquil.
27  */
28 class EquilOpt
29 {
30 public:
31  EquilOpt() : relTolerance(1.e-8), absElemTol(1.0E-70),maxIterations(1000),
32  iterations(0),
33  maxStepSize(10.0), propertyPair(TP), contin(false) {}
34 
35  doublereal relTolerance; ///< Relative tolerance
36  doublereal absElemTol; ///< Abs Tol in element number
37  int maxIterations; ///< Maximum number of iterations
38  int iterations; ///< Iteration counter
39 
40  /**
41  * Maximum step size. Largest change in any element potential or
42  * in log(T) allowed in one Newton step. Default: 10.0
43  */
44  doublereal maxStepSize;
45 
46  /**
47  * Property pair flag. Determines which two thermodynamic properties
48  * are fixed.
49  */
51 
52  /**
53  * Continuation flag. Set true if the calculation should be
54  * initialized from the last calculation. Otherwise, the
55  * calculation will be started from scratch and the initial
56  * composition and element potentials estimated.
57  */
58  bool contin;
59 };
60 
61 template<class M>
62 class PropertyCalculator;
63 
64 /**
65  * @defgroup equil Chemical Equilibrium
66  *
67  */
68 
69 /**
70  * Class ChemEquil implements a chemical equilibrium solver for
71  * single-phase solutions. It is a "non-stoichiometric" solver in
72  * the terminology of Smith and Missen, meaning that every
73  * intermediate state is a valid chemical equilibrium state, but
74  * does not necessarily satisfy the element constraints. In
75  * contrast, the solver implemented in class MultiPhaseEquil uses
76  * a "stoichiometric" algorithm, in which each intermediate state
77  * satisfies the element constraints but is not a state of
78  * chemical equilibrium. Non-stoichiometric methods are faster
79  * when they converge, but stoichiometric ones tend to be more
80  * robust and can be used also for problems with multiple
81  * condensed phases. As expected, the ChemEquil solver is faster
82  * than MultiPhaseEquil for many single-phase equilibrium
83  * problems (particularly if there are only a few elements but
84  * very many species), but can be less stable. Problem
85  * situations include low temperatures where only a few species
86  * have non-zero mole fractions, precisely stoichiometric
87  * compositions (e.g. 2 H2 + O2). In general, if speed is
88  * important, this solver should be tried first, and if it fails
89  * then use MultiPhaseEquil.
90  * @ingroup equil
91  */
92 class ChemEquil
93 {
94 public:
95  ChemEquil();
96 
97  //! Constructor combined with the initialization function
98  /*!
99  * This constructor initializes the ChemEquil object with everything it
100  * needs to start solving equilibrium problems.
101  * @param s ThermoPhase object that will be used in the equilibrium calls.
102  */
103  ChemEquil(thermo_t& s);
104 
105  virtual ~ChemEquil();
106 
107  /*!
108  * Equilibrate a phase, holding the elemental composition fixed
109  * at the initial value found within the ThermoPhase object *s*.
110  *
111  * The value of 2 specified properties are obtained by querying the
112  * ThermoPhase object. The properties must be already contained
113  * within the current thermodynamic state of the system.
114  */
115  int equilibrate(thermo_t& s, const char* XY,
116  bool useThermoPhaseElementPotentials = false, int loglevel = 0);
117 
118  /*!
119  * Compute the equilibrium composition for 2 specified
120  * properties and the specified element moles.
121  *
122  * The 2 specified properties are obtained by querying the
123  * ThermoPhase object. The properties must be already contained
124  * within the current thermodynamic state of the system.
125  *
126  * @param s phase object to be equilibrated
127  * @param XY property pair to hold constant
128  * @param elMoles specified vector of element abundances.
129  * @param useThermoPhaseElementPotentials get the initial estimate for the
130  * chemical potentials from the ThermoPhase object (true) or create
131  * our own estimate (false)
132  * @param loglevel Specify amount of debug logging (0 to disable)
133  * @return Successful returns are indicated by a return value of 0.
134  * Unsuccessful returns are indicated by a return value of -1 for lack
135  * of convergence or -3 for a singular Jacobian.
136  */
137  int equilibrate(thermo_t& s, const char* XY, vector_fp& elMoles,
138  bool useThermoPhaseElementPotentials = false, int loglevel = 0);
139  const vector_fp& elementPotentials() const {
140  return m_lambda;
141  }
142 
143  /**
144  * Options controlling how the calculation is carried out.
145  * @see EquilOptions
146  */
148 
149 
150 protected:
151 
152  //! Pointer to the ThermoPhase object used to initialize this object.
153  /*!
154  * This ThermoPhase object must be compatible with the ThermoPhase
155  * objects input from the equilibrate function. Currently, this
156  * means that the 2 ThermoPhases have to have consist of the same
157  * species and elements.
158  */
160 
161  //! number of atoms of element m in species k.
162  doublereal nAtoms(size_t k, size_t m) const {
163  return m_comp[k*m_mm + m];
164  }
165 
166  /*!
167  * Prepare for equilibrium calculations.
168  * @param s object representing the solution phase.
169  */
170  void initialize(thermo_t& s);
171 
172  /*!
173  * Set mixture to an equilibrium state consistent with specified
174  * element potentials and temperature.
175  *
176  * @param s mixture to be updated
177  * @param x vector of non-dimensional element potentials
178  * \f[ \lambda_m/RT \f].
179  * @param t temperature in K.
180  */
181  void setToEquilState(thermo_t& s,
182  const vector_fp& x, doublereal t);
183 
184  //! Estimate the initial mole numbers. This version borrows from the
185  //! MultiPhaseEquil solver.
186  int setInitialMoles(thermo_t& s, vector_fp& elMoleGoal, int loglevel = 0);
187 
188  //! Generate a starting estimate for the element potentials.
190  vector_fp& elMolesGoal, int loglevel = 0);
191 
192  /*!
193  * Do a calculation of the element potentials using the Brinkley method,
194  * p. 129 Smith and Missen.
195  *
196  * We have found that the previous estimate may not be good enough to
197  * avoid drastic numerical issues associated with the use of a numerically
198  * generated Jacobian used in the main algorithm.
199  *
200  * The Brinkley algorithm, here, assumes a constant T, P system and uses a
201  * linearized analytical Jacobian that turns out to be very stable even
202  * given bad initial guesses.
203  *
204  * The pressure and temperature to be used are in the ThermoPhase object
205  * input into the routine.
206  *
207  * The initial guess for the element potentials used by this routine is
208  * taken from the input vector, x.
209  *
210  * elMoles is the input element abundance vector to be matched.
211  *
212  * Nonideal phases are handled in principle. This is done by calculating
213  * the activity coefficients and adding them into the formula in the
214  * correct position. However, these are treated as a RHS contribution
215  * only. Therefore, convergence might be a problem. This has not been
216  * tested. Also molality based unit systems aren't handled.
217  *
218  * On return, int return value contains the success code:
219  * - 0 - successful
220  * - 1 - unsuccessful, max num iterations exceeded
221  * - -3 - unsuccessful, singular Jacobian
222  *
223  * NOTE: update for activity coefficients.
224  */
225  int estimateEP_Brinkley(thermo_t& s, vector_fp& lambda, vector_fp& elMoles);
226 
227  //! Find an acceptable step size and take it.
228  /*!
229  * The original implementation employed a line search technique that
230  * enforced a reduction in the norm of the residual at every successful
231  * step. Unfortunately, this method created false convergence errors near
232  * the end of a significant number of steps, usually special conditions
233  * where there were stoichiometric constraints.
234  *
235  * This new method just does a delta damping approach, based on limiting
236  * the jump in the dimensionless element potentials. Mole fractions are
237  * limited to a factor of 2 jump in the values from this method. Near
238  * convergence, the delta damping gets out of the way.
239  */
240  int dampStep(thermo_t& s, vector_fp& oldx,
241  double oldf, vector_fp& grad, vector_fp& step, vector_fp& x,
242  double& f, vector_fp& elmols, double xval, double yval);
243 
244  /**
245  * Evaluates the residual vector F, of length #m_mm
246  */
247  void equilResidual(thermo_t& s, const vector_fp& x,
248  const vector_fp& elmtotal, vector_fp& resid,
249  double xval, double yval, int loglevel = 0);
250 
251  void equilJacobian(thermo_t& s, vector_fp& x,
252  const vector_fp& elmols, DenseMatrix& jac,
253  double xval, double yval, int loglevel = 0);
254 
255  void adjustEloc(thermo_t& s, vector_fp& elMolesGoal);
256 
257  //! Update internally stored state information.
258  void update(const thermo_t& s);
259 
260  /**
261  * Given a vector of dimensionless element abundances, this routine
262  * calculates the moles of the elements and the moles of the species.
263  *
264  * @param[in] x = current dimensionless element potentials..
265  */
266  double calcEmoles(thermo_t& s, vector_fp& x,
267  const double& n_t, const vector_fp& Xmol_i_calc,
268  vector_fp& eMolesCalc, vector_fp& n_i_calc,
269  double pressureConst);
270 
271  size_t m_mm; //!< number of elements in the phase
272  size_t m_kk; //!< number of species in the phase
273  size_t m_skip;
274 
275  /**
276  * This is equal to the rank of the stoichiometric coefficient
277  * matrix when it is computed. It's initialized to #m_mm.
278  */
280 
281  std::auto_ptr<PropertyCalculator<thermo_t> > m_p1, m_p2;
282 
283  /**
284  * Current value of the mole fractions in the single phase.
285  * -> length = #m_kk.
286  */
288  /**
289  * Current value of the dimensional element potentials
290  * -> length = #m_mm
291  */
293 
294  /*
295  * Current value of the sum of the element abundances given the
296  * current element potentials.
297  */
298  doublereal m_elementTotalSum;
299  /*
300  * Current value of the element mole fractions. Note these aren't
301  * the goal element mole fractions.
302  */
303  vector_fp m_elementmolefracs;
304  vector_fp m_reswork;
305  vector_fp m_jwork1;
306  vector_fp m_jwork2;
307 
308  /*
309  * Storage of the element compositions
310  * natom(k,m) = m_comp[k*m_mm+ m];
311  */
312  vector_fp m_comp;
313  doublereal m_temp, m_dens;
314  doublereal m_p0;
315 
316  /**
317  * Index of the element id corresponding to the electric charge of each
318  * species. Equal to -1 if there is no such element id.
319  */
320  size_t m_eloc;
321 
322  vector_fp m_startSoln;
323 
324  vector_fp m_grt;
325  vector_fp m_mu_RT;
326 
327  /**
328  * Dimensionless values of the Gibbs free energy for the
329  * standard state of each species, at the temperature and
330  * pressure of the solution (the star standard state).
331  */
333  std::vector<size_t> m_component;
334 
335  //! element fractional cutoff, below which the element will be zeroed.
337  bool m_doResPerturb;
338 
339  std::vector<size_t> m_orderVectorElements;
340  std::vector<size_t> m_orderVectorSpecies;
341 };
342 
343 extern int ChemEquil_print_lvl;
344 
345 }
346 
347 #endif
Class ChemEquil implements a chemical equilibrium solver for single-phase solutions.
Definition: ChemEquil.h:92
EquilOpt options
Options controlling how the calculation is carried out.
Definition: ChemEquil.h:147
vector_fp m_muSS_RT
Dimensionless values of the Gibbs free energy for the standard state of each species, at the temperature and pressure of the solution (the star standard state).
Definition: ChemEquil.h:332
thermo_t * m_phase
Pointer to the ThermoPhase object used to initialize this object.
Definition: ChemEquil.h:159
doublereal relTolerance
Relative tolerance.
Definition: ChemEquil.h:35
int setInitialMoles(thermo_t &s, vector_fp &elMoleGoal, int loglevel=0)
Estimate the initial mole numbers.
Definition: ChemEquil.cpp:192
size_t m_kk
number of species in the phase
Definition: ChemEquil.h:272
Classes used by ChemEquil.
doublereal maxStepSize
Maximum step size.
Definition: ChemEquil.h:44
int equilibrate(thermo_t &s, const char *XY, bool useThermoPhaseElementPotentials=false, int loglevel=0)
Definition: ChemEquil.cpp:336
This file contains definitions of terms that are used in internal routines and are unlikely to need m...
int propertyPair
Property pair flag.
Definition: ChemEquil.h:50
void initialize(thermo_t &s)
Definition: ChemEquil.cpp:67
size_t m_nComponents
This is equal to the rank of the stoichiometric coefficient matrix when it is computed.
Definition: ChemEquil.h:279
void equilResidual(thermo_t &s, const vector_fp &x, const vector_fp &elmtotal, vector_fp &resid, double xval, double yval, int loglevel=0)
Evaluates the residual vector F, of length m_mm.
Definition: ChemEquil.cpp:846
void update(const thermo_t &s)
Update internally stored state information.
Definition: ChemEquil.cpp:162
int iterations
Iteration counter.
Definition: ChemEquil.h:38
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:97
void setToEquilState(thermo_t &s, const vector_fp &x, doublereal t)
Definition: ChemEquil.cpp:142
Chemical equilibrium options.
Definition: ChemEquil.h:28
size_t m_eloc
Index of the element id corresponding to the electric charge of each species.
Definition: ChemEquil.h:320
doublereal absElemTol
Abs Tol in element number.
Definition: ChemEquil.h:36
double m_elemFracCutoff
element fractional cutoff, below which the element will be zeroed.
Definition: ChemEquil.h:336
int estimateEP_Brinkley(thermo_t &s, vector_fp &lambda, vector_fp &elMoles)
Definition: ChemEquil.cpp:972
bool contin
Continuation flag.
Definition: ChemEquil.h:58
int estimateElementPotentials(thermo_t &s, vector_fp &lambda, vector_fp &elMolesGoal, int loglevel=0)
Generate a starting estimate for the element potentials.
Definition: ChemEquil.cpp:240
size_t m_mm
number of elements in the phase
Definition: ChemEquil.h:271
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
vector_fp m_lambda
Current value of the dimensional element potentials -> length = m_mm.
Definition: ChemEquil.h:292
doublereal nAtoms(size_t k, size_t m) const
number of atoms of element m in species k.
Definition: ChemEquil.h:162
vector_fp m_molefractions
Current value of the mole fractions in the single phase.
Definition: ChemEquil.h:287
double calcEmoles(thermo_t &s, vector_fp &x, const double &n_t, const vector_fp &Xmol_i_calc, vector_fp &eMolesCalc, vector_fp &n_i_calc, double pressureConst)
Given a vector of dimensionless element abundances, this routine calculates the moles of the elements...
Definition: ChemEquil.cpp:934
int maxIterations
Maximum number of iterations.
Definition: ChemEquil.h:37
int _equilflag(const char *xy)
map property strings to integers
Definition: ChemEquil.cpp:24
Header file for class ThermoPhase, the base class for phases with thermodynamic properties, and the text for the Module thermoprops (see Thermodynamic Properties and class ThermoPhase).
Definitions for the classes that are thrown when Cantera experiences an error condition (also contain...
A class for full (non-sparse) matrices with Fortran-compatible data storage, which adds matrix operat...
Definition: DenseMatrix.h:71
int dampStep(thermo_t &s, vector_fp &oldx, double oldf, vector_fp &grad, vector_fp &step, vector_fp &x, double &f, vector_fp &elmols, double xval, double yval)
Find an acceptable step size and take it.
Definition: ChemEquil.cpp:802