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