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