Cantera  2.5.1
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 https://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, int loglevel = 0);
107 
108  /*!
109  * Compute the equilibrium composition for two specified properties and the
110  * specified element moles.
111  *
112  * The two specified properties are obtained by querying the ThermoPhase
113  * object. The properties must be already contained within the current
114  * thermodynamic state of the system.
115  *
116  * @param s phase object to be equilibrated
117  * @param XY property pair to hold constant
118  * @param elMoles specified vector of element abundances.
119  * @param loglevel Specify amount of debug logging (0 to disable)
120  * @return Successful returns are indicated by a return value of 0.
121  * Unsuccessful returns are indicated by a return value of -1 for lack
122  * of convergence or -3 for a singular Jacobian.
123  */
124  int equilibrate(thermo_t& s, const char* XY, vector_fp& elMoles,
125  int loglevel = 0);
126 
127  /**
128  * Options controlling how the calculation is carried out.
129  * @see EquilOptions
130  */
132 
133 protected:
134  //! Pointer to the ThermoPhase object used to initialize this object.
135  /*!
136  * This ThermoPhase object must be compatible with the ThermoPhase objects
137  * input from the equilibrate function. Currently, this means that the 2
138  * ThermoPhases have to have consist of the same species and elements.
139  */
141 
142  //! number of atoms of element m in species k.
143  doublereal nAtoms(size_t k, size_t m) const {
144  return m_comp[k*m_mm + m];
145  }
146 
147  /*!
148  * Prepare for equilibrium calculations.
149  * @param s object representing the solution phase.
150  */
151  void initialize(thermo_t& s);
152 
153  /*!
154  * Set mixture to an equilibrium state consistent with specified element
155  * potentials and temperature.
156  *
157  * @param s mixture to be updated
158  * @param x vector of non-dimensional element potentials
159  * \f[ \lambda_m/RT \f].
160  * @param t temperature in K.
161  */
162  void setToEquilState(thermo_t& s,
163  const vector_fp& x, doublereal t);
164 
165  //! Estimate the initial mole numbers. This version borrows from the
166  //! MultiPhaseEquil solver.
167  int setInitialMoles(thermo_t& s, vector_fp& elMoleGoal, int loglevel = 0);
168 
169  //! Generate a starting estimate for the element potentials.
171  vector_fp& elMolesGoal, int loglevel = 0);
172 
173  /*!
174  * Do a calculation of the element potentials using the Brinkley method,
175  * p. 129 Smith and Missen.
176  *
177  * We have found that the previous estimate may not be good enough to
178  * avoid drastic numerical issues associated with the use of a numerically
179  * generated Jacobian used in the main algorithm.
180  *
181  * The Brinkley algorithm, here, assumes a constant T, P system and uses a
182  * linearized analytical Jacobian that turns out to be very stable even
183  * given bad initial guesses.
184  *
185  * The pressure and temperature to be used are in the ThermoPhase object
186  * input into the routine.
187  *
188  * The initial guess for the element potentials used by this routine is
189  * taken from the input vector, x.
190  *
191  * elMoles is the input element abundance vector to be matched.
192  *
193  * Nonideal phases are handled in principle. This is done by calculating
194  * the activity coefficients and adding them into the formula in the
195  * correct position. However, these are treated as a RHS contribution
196  * only. Therefore, convergence might be a problem. This has not been
197  * tested. Also molality based unit systems aren't handled.
198  *
199  * On return, int return value contains the success code:
200  * - 0 - successful
201  * - 1 - unsuccessful, max num iterations exceeded
202  * - -3 - unsuccessful, singular Jacobian
203  *
204  * NOTE: update for activity coefficients.
205  */
206  int estimateEP_Brinkley(thermo_t& s, vector_fp& lambda, vector_fp& elMoles);
207 
208  //! Find an acceptable step size and take it.
209  /*!
210  * The original implementation employed a line search technique that
211  * enforced a reduction in the norm of the residual at every successful
212  * step. Unfortunately, this method created false convergence errors near
213  * the end of a significant number of steps, usually special conditions
214  * where there were stoichiometric constraints.
215  *
216  * This new method just does a delta damping approach, based on limiting
217  * the jump in the dimensionless element potentials. Mole fractions are
218  * limited to a factor of 2 jump in the values from this method. Near
219  * convergence, the delta damping gets out of the way.
220  */
221  int dampStep(thermo_t& s, vector_fp& oldx,
222  double oldf, vector_fp& grad, vector_fp& step, vector_fp& x,
223  double& f, vector_fp& elmols, double xval, double yval);
224 
225  /**
226  * Evaluates the residual vector F, of length #m_mm
227  */
228  void equilResidual(thermo_t& s, const vector_fp& x,
229  const vector_fp& elmtotal, vector_fp& resid,
230  double xval, double yval, int loglevel = 0);
231 
232  void equilJacobian(thermo_t& s, vector_fp& x,
233  const vector_fp& elmols, DenseMatrix& jac,
234  double xval, double yval, int loglevel = 0);
235 
236  void adjustEloc(thermo_t& s, vector_fp& elMolesGoal);
237 
238  //! Update internally stored state information.
239  void update(const thermo_t& s);
240 
241  /**
242  * Given a vector of dimensionless element abundances, this routine
243  * calculates the moles of the elements and the moles of the species.
244  *
245  * @param[in] x = current dimensionless element potentials..
246  */
247  double calcEmoles(thermo_t& s, vector_fp& x,
248  const double& n_t, const vector_fp& Xmol_i_calc,
249  vector_fp& eMolesCalc, vector_fp& n_i_calc,
250  double pressureConst);
251 
252  size_t m_mm; //!< number of elements in the phase
253  size_t m_kk; //!< number of species in the phase
254  size_t m_skip;
255 
256  //! This is equal to the rank of the stoichiometric coefficient matrix when
257  //! it is computed. It's initialized to #m_mm.
259 
260  std::function<double(ThermoPhase&)> m_p1, m_p2;
261 
262  //! Current value of the mole fractions in the single phase. length = #m_kk.
264 
265  //! Current value of the sum of the element abundances given the current
266  //! element potentials.
267  doublereal m_elementTotalSum;
268 
269  //! Current value of the element mole fractions. Note these aren't the goal
270  //! element mole fractions.
272  vector_fp m_reswork;
273  vector_fp m_jwork1;
274  vector_fp m_jwork2;
275 
276  //! Storage of the element compositions. natom(k,m) = m_comp[k*m_mm+ m];
278  doublereal m_temp, m_dens;
279  doublereal m_p0;
280 
281  //! Index of the element id corresponding to the electric charge of each
282  //! species. Equal to -1 if there is no such element id.
283  size_t m_eloc;
284 
285  vector_fp m_startSoln;
286 
287  vector_fp m_grt;
288  vector_fp m_mu_RT;
289 
290  //! Dimensionless values of the Gibbs free energy for the standard state of
291  //! each species, at the temperature and pressure of the solution (the star
292  //! standard state).
294  std::vector<size_t> m_component;
295 
296  //! element fractional cutoff, below which the element will be zeroed.
298  bool m_doResPerturb;
299 
300  std::vector<size_t> m_orderVectorElements;
301  std::vector<size_t> m_orderVectorSpecies;
302 
303  //! Verbosity of printed output. No messages when m_loglevel == 0. More
304  //! output as level increases.
306 };
307 
308 }
309 
310 #endif
Cantera::ChemEquil::m_kk
size_t m_kk
number of species in the phase
Definition: ChemEquil.h:253
Cantera::EquilOpt::relTolerance
doublereal relTolerance
Relative tolerance.
Definition: ChemEquil.h:34
ct_defs.h
Cantera::ChemEquil::m_nComponents
size_t m_nComponents
This is equal to the rank of the stoichiometric coefficient matrix when it is computed.
Definition: ChemEquil.h:258
Cantera::ChemEquil::m_molefractions
vector_fp m_molefractions
Current value of the mole fractions in the single phase. length = m_kk.
Definition: ChemEquil.h:263
Cantera::EquilOpt::propertyPair
int propertyPair
Property pair flag.
Definition: ChemEquil.h:49
Cantera::ChemEquil::m_elementmolefracs
vector_fp m_elementmolefracs
Current value of the element mole fractions.
Definition: ChemEquil.h:271
Cantera::ChemEquil::options
EquilOpt options
Options controlling how the calculation is carried out.
Definition: ChemEquil.h:131
Cantera::EquilOpt::iterations
int iterations
Iteration counter.
Definition: ChemEquil.h:37
Cantera::ChemEquil::setToEquilState
void setToEquilState(thermo_t &s, const vector_fp &x, doublereal t)
Definition: ChemEquil.cpp:132
Cantera::ChemEquil::estimateElementPotentials
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:218
Cantera::EquilOpt::maxStepSize
doublereal maxStepSize
Maximum step size.
Definition: ChemEquil.h:43
Cantera::vector_fp
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:180
Cantera::ChemEquil
Class ChemEquil implements a chemical equilibrium solver for single-phase solutions.
Definition: ChemEquil.h:82
Cantera::ChemEquil::m_mm
size_t m_mm
number of elements in the phase
Definition: ChemEquil.h:252
Cantera::ChemEquil::m_elementTotalSum
doublereal m_elementTotalSum
Current value of the sum of the element abundances given the current element potentials.
Definition: ChemEquil.h:267
Cantera::ChemEquil::nAtoms
doublereal nAtoms(size_t k, size_t m) const
number of atoms of element m in species k.
Definition: ChemEquil.h:143
Cantera::EquilOpt::absElemTol
doublereal absElemTol
Abs Tol in element number.
Definition: ChemEquil.h:35
Cantera::ChemEquil::initialize
void initialize(thermo_t &s)
Definition: ChemEquil.cpp:64
Cantera::ChemEquil::update
void update(const thermo_t &s)
Update internally stored state information.
Definition: ChemEquil.cpp:153
Cantera::ChemEquil::m_elemFracCutoff
double m_elemFracCutoff
element fractional cutoff, below which the element will be zeroed.
Definition: ChemEquil.h:297
Cantera::ChemEquil::m_phase
thermo_t * m_phase
Pointer to the ThermoPhase object used to initialize this object.
Definition: ChemEquil.h:140
Cantera::ChemEquil::estimateEP_Brinkley
int estimateEP_Brinkley(thermo_t &s, vector_fp &lambda, vector_fp &elMoles)
Definition: ChemEquil.cpp:843
Cantera::ThermoPhase
Base class for a phase with thermodynamic properties.
Definition: ThermoPhase.h:101
Cantera::ChemEquil::dampStep
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:689
Cantera::EquilOpt::contin
bool contin
Continuation flag.
Definition: ChemEquil.h:56
Cantera::ChemEquil::calcEmoles
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:807
Cantera::ChemEquil::equilibrate
int equilibrate(thermo_t &s, const char *XY, int loglevel=0)
Definition: ChemEquil.cpp:308
Cantera::ChemEquil::m_eloc
size_t m_eloc
Index of the element id corresponding to the electric charge of each species.
Definition: ChemEquil.h:283
Cantera::ChemEquil::m_muSS_RT
vector_fp m_muSS_RT
Dimensionless values of the Gibbs free energy for the standard state of each species,...
Definition: ChemEquil.h:293
Cantera::ChemEquil::m_loglevel
int m_loglevel
Verbosity of printed output.
Definition: ChemEquil.h:305
Cantera::DenseMatrix
A class for full (non-sparse) matrices with Fortran-compatible data storage, which adds matrix operat...
Definition: DenseMatrix.h:50
Cantera::_equilflag
int _equilflag(const char *xy)
map property strings to integers
Definition: ChemEquil.cpp:21
Cantera::ChemEquil::setInitialMoles
int setInitialMoles(thermo_t &s, vector_fp &elMoleGoal, int loglevel=0)
Estimate the initial mole numbers.
Definition: ChemEquil.cpp:182
Cantera::ChemEquil::equilResidual
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:728
Cantera::EquilOpt::maxIterations
int maxIterations
Maximum number of iterations.
Definition: ChemEquil.h:36
ctexceptions.h
Cantera
Namespace for the Cantera kernel.
Definition: AnyMap.cpp:263
ThermoPhase.h
Cantera::EquilOpt
Chemical equilibrium options.
Definition: ChemEquil.h:27
Cantera::ChemEquil::m_comp
vector_fp m_comp
Storage of the element compositions. natom(k,m) = m_comp[k*m_mm+ m];.
Definition: ChemEquil.h:277