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