Cantera  4.0.0a2
Loading...
Searching...
No Matches
SteadyStateSystem.h
Go to the documentation of this file.
1//! @file SteadyStateSystem.h
2
3// This file is part of Cantera. See License.txt in the top-level directory or
4// at https://cantera.org/license.txt for license and copyright information.
5
6#ifndef CT_STEADYSTATESYSTEM_H
7#define CT_STEADYSTATESYSTEM_H
8
9#include <cmath>
10
12#include "SystemJacobian.h"
13
14namespace Cantera
15{
16
17class Func1;
18class MultiNewton;
19
20//! Error thrown when time stepping cannot proceed and the steady-state solver
21//! should be given a chance to recover by other means.
23{
24public:
25 template <typename... Args>
26 TimeStepError(const string& func, const string& msg, const Args&... args) :
27 CanteraError(func, msg, args...) {}
28
29 string getClass() const override {
30 return "TimeStepError";
31 }
32};
33
34//! Base class for representing a system of differential-algebraic equations and solving
35//! for its steady-state response.
36//!
37//! @since New in %Cantera 3.2.
38//! @ingroup numerics
40{
41public:
43 virtual ~SteadyStateSystem();
44 SteadyStateSystem(const SteadyStateSystem&) = delete;
45 SteadyStateSystem& operator=(const SteadyStateSystem&) = delete;
46
47 //! Evaluate the residual function
48 //!
49 //! @param[in] x State vector
50 //! @param[out] r On return, contains the residual vector
51 //! @param rdt Reciprocal of the time step. if omitted, then the internally stored
52 //! value (accessible using the rdt() method) is used.
53 //! @param count Set to zero to omit this call from the statistics
54 virtual void eval(span<const double> x, span<double> r,
55 double rdt=-1.0, int count=1) = 0;
56
57 //! Evaluates the Jacobian at x0 using finite differences.
58 //!
59 //! The Jacobian is computed by perturbing each component of `x0`, evaluating the
60 //! residual function, and then estimating the partial derivatives numerically using
61 //! finite differences to determine the corresponding column of the Jacobian.
62 //!
63 //! @param x0 State vector at which to evaluate the Jacobian
64 virtual void evalJacobian(span<const double> x0) = 0;
65
66 //! Compute the weighted norm of `step`.
67 //!
68 //! The purpose is to measure the "size" of the step vector @f$ \Delta x @f$ in a
69 //! way that takes into account the relative importance or scale of different
70 //! solution components. Each component of the step vector is normalized by a weight
71 //! that depends on both the current magnitude of the solution vector and specified
72 //! tolerances. This makes the norm dimensionless and scaled appropriately, avoiding
73 //! issues where some components dominate due to differences in their scales. See
74 //! OneDim::weightedNorm() for a representative implementation.
75 virtual double weightedNorm(span<const double> step) const = 0;
76
77 //! Set the initial guess. Should be called before solve().
78 void setInitialGuess(span<const double> x);
79
80 //! Solve the steady-state problem, taking internal timesteps as necessary until
81 //! the Newton solver can converge for the steady problem.
82 //! @param loglevel Controls amount of diagnostic output.
83 void solve(int loglevel=0);
84
85 //! Get the converged steady-state solution after calling solve().
86 void getState(span<double> x) const;
87
88 //! Steady-state max norm (infinity norm) of the residual evaluated using solution
89 //! x. On return, array r contains the steady-state residual values.
90 double ssnorm(span<const double> x, span<double> r);
91
92 //! Transient max norm (infinity norm) of the residual evaluated using solution
93 //! x and the current timestep (rdt). On return, array r contains the
94 //! transient residual values.
95 double tsnorm(span<const double> x, span<double> r);
96
97 //! Total solution vector length;
98 size_t size() const {
99 return m_size;
100 }
101
102 //! Call to set the size of internal data structures after first defining the system
103 //! or if the problem size changes, for example after grid refinement.
104 //!
105 //! The #m_size variable should be updated before calling this method
106 virtual void resize();
107
108 //! Jacobian bandwidth.
109 size_t bandwidth() const {
110 return m_bw;
111 }
112
113 //! Get the name of the i-th component of the state vector
114 virtual string componentName(size_t i) const { return fmt::format("{}", i); }
115
116 //! Get header lines describing the column names included in a component label.
117 //! Headings should be aligned with items formatted in the output of
118 //! componentTableLabel(). Two lines are allowed. If only one is needed, the first
119 //! line should be blank.
120 virtual pair<string, string> componentTableHeader() const {
121 return {"", "component name"};
122 }
123
124 //! Get elements of the component name, aligned with the column headings given
125 //! by componentTableHeader().
126 virtual string componentTableLabel(size_t i) const { return componentName(i); }
127
128 //! Get the upper bound for global component *i* in the state vector
129 virtual double upperBound(size_t i) const = 0;
130
131 //! Get the lower bound for global component *i* in the state vector
132 virtual double lowerBound(size_t i) const = 0;
133
134 //! Return a reference to the Newton iterator.
136
137 //! Set the linear solver used to hold the Jacobian matrix and solve linear systems
138 //! as part of each Newton iteration.
139 void setLinearSolver(shared_ptr<SystemJacobian> solver);
140
141 //! Get the the linear solver being used to hold the Jacobian matrix and solve
142 //! linear systems as part of each Newton iteration.
143 shared_ptr<SystemJacobian> linearSolver() const { return m_jac; }
144
145 //! Reciprocal of the time step.
146 double rdt() const {
147 return m_rdt;
148 }
149
150 //! True if transient mode.
151 bool transient() const {
152 return (m_rdt != 0.0);
153 }
154
155 //! True if steady mode.
156 bool steady() const {
157 return (m_rdt == 0.0);
158 }
159
160 //! Prepare for time stepping beginning with solution *x* and timestep *dt*.
161 virtual void initTimeInteg(double dt, span<const double> x);
162
163 //! Prepare to solve the steady-state problem. After invoking this method,
164 //! subsequent calls to solve() will solve the steady-state problem. Sets the
165 //! reciprocal of the time step to zero, and, if it was previously non-zero, signals
166 //! that a new Jacobian will be needed.
167 virtual void setSteadyMode();
168
169 //! Access the vector indicating which equations contain a transient term.
170 //! Elements are 1 for equations with a transient terms and 0 otherwise.
171 vector<int>& transientMask() {
172 return m_mask;
173 }
174
175 //! Take time steps using Backward Euler.
176 //!
177 //! @param nsteps number of steps
178 //! @param dt initial step size
179 //! @param x current solution vector
180 //! @param r solution vector after time stepping
181 //! @param loglevel controls amount of printed diagnostics
182 //! @returns size of last timestep taken
183 double timeStep(int nsteps, double dt, span<double> x, span<double> r,
184 int loglevel);
185
186 //! Reset values such as negative species concentrations
187 virtual void resetBadValues(span<double> x) {}
188
189 //! @name Options
190 //! @{
191
192 //! Set the number of time steps to try when the steady Newton solver is
193 //! unsuccessful.
194 //! @param stepsize Initial time step size [s]
195 //! @param tsteps A sequence of time step counts to take after subsequent failures
196 //! of the steady-state solver. The last value in `tsteps` will be used again
197 //! after further unsuccessful solution attempts.
198 void setTimeStep(double stepsize, span<const int> tsteps);
199
200 //! Set the minimum time step allowed during time stepping
201 void setMinTimeStep(double tmin) {
202 m_tmin = tmin;
203 }
204
205 //! Set the maximum time step allowed during time stepping
206 void setMaxTimeStep(double tmax) {
207 m_tmax = tmax;
208 }
209
210 //! Sets a factor by which the time step is reduced if the time stepping fails.
211 //! The default value is 0.5.
212 //!
213 //! @param tfactor factor time step is multiplied by if time stepping fails
214 void setTimeStepFactor(double tfactor) {
215 m_tfactor = tfactor;
216 }
217
218 //! Set the growth factor used after successful timesteps when the Jacobian is
219 //! re-used.
220 //!
221 //! This factor is used directly by the `fixed-growth` strategy, and as the
222 //! accepted growth factor or upper bound for the other named strategies.
223 //!
224 //! The default value is 1.5, matching historical behavior.
225 //! @param tfactor Finite growth factor applied to successful timesteps;
226 //! must be >= 1.0.
227 void setTimeStepGrowthFactor(double tfactor) {
228 if (!std::isfinite(tfactor) || tfactor < 1.0) {
229 throw CanteraError("SteadyStateSystem::setTimeStepGrowthFactor",
230 "Time step growth factor must be finite and >= 1.0. Got {}.",
231 tfactor);
232 }
233 m_tstep_growth = tfactor;
234 }
235
236 //! Get the successful-step time step growth factor.
237 double timeStepGrowthFactor() const {
238 return m_tstep_growth;
239 }
240
241 //! Set the strategy used to grow the timestep after a successful step that
242 //! reuses the current Jacobian.
243 //!
244 //! Available options are:
245 //! - `fixed-growth`: Always apply timeStepGrowthFactor().
246 //! - `steady-norm`: Apply timeStepGrowthFactor() only if the steady-state
247 //! residual norm decreases.
248 //! - `transient-residual`: Apply timeStepGrowthFactor() only if the transient
249 //! residual norm decreases.
250 //! - `residual-ratio`: Scale the growth factor based on transient residual
251 //! improvement, capped by timeStepGrowthFactor().
252 //! - `newton-iterations`: Apply timeStepGrowthFactor() only if the most recent
253 //! Newton solve used at most 3 iterations.
254 //!
255 //! The default strategy is `fixed-growth`, which matches historical behavior.
256 void setTimeStepGrowthStrategy(const string& strategy);
257
258 //! Get the configured timestep growth strategy.
259 string timeStepGrowthStrategy() const;
260
261 //! Set the maximum number of timeteps allowed before successful steady-state solve
262 void setMaxTimeStepCount(int nmax) {
263 m_nsteps_max = nmax;
264 }
265
266 //! Get the maximum number of timeteps allowed before successful steady-state solve
267 int maxTimeStepCount() const {
268 return m_nsteps_max;
269 }
270 //! @}
271
272 //! Set the maximum number of steps that can be taken using the same Jacobian
273 //! before it must be re-evaluated.
274 //! @param ss_age Age limit during steady-state mode
275 //! @param ts_age Age limit during time stepping mode. If not specified, the
276 //! steady-state age is also used during time stepping.
277 void setJacAge(int ss_age, int ts_age=-1);
278
279 //! Set a function that will be called every time #eval is called.
280 //! Can be used to provide keyboard interrupt support in the high-level
281 //! language interfaces.
282 void setInterrupt(Func1* interrupt) {
283 m_interrupt = interrupt;
284 }
285
286 //! Set a function that will be called after each successful timestep. The
287 //! function will be called with the size of the timestep as the argument.
288 //! Intended to be used for observing solver progress for debugging
289 //! purposes.
290 void setTimeStepCallback(Func1* callback) {
291 m_time_step_callback = callback;
292 }
293
294 //! Configure perturbations used to evaluate finite difference Jacobian
295 //! @param relative Relative perturbation (multiplied by the absolute value of
296 //! each component). Default `1.0e-5`.
297 //! @param absolute Absolute perturbation (independent of component value).
298 //! Default `1.0e-10`.
299 //! @param threshold Threshold below which to exclude elements from the Jacobian
300 //! Default `0.0`.
301 void setJacobianPerturbation(double relative, double absolute, double threshold) {
302 m_jacobianRelPerturb = relative;
303 m_jacobianAbsPerturb = absolute;
304 m_jacobianThreshold = threshold;
305 }
306
307 //! Write solver debugging based on the specified log level.
308 //!
309 //! @see Sim1D::writeDebugInfo for a specific implementation of this capability.
310 virtual void writeDebugInfo(const string& header_suffix, const string& message,
311 int loglevel, int attempt_counter) {}
312
313 //! Delete debug output file that may be created by writeDebugInfo() when solving
314 //! with high `loglevel`.
315 virtual void clearDebugFile() {}
316
317protected:
318 enum class TimeStepGrowthStrategy {
319 fixed,
320 steadyNorm,
321 transientResidual,
322 residualRatio,
323 newtonIterations
324 };
325
326 //! Evaluate the steady-state Jacobian, accessible via linearSolver()
327 //! @param[in] x Current state vector, length size()
328 void evalSSJacobian(span<const double> x);
329
330 static TimeStepGrowthStrategy parseTimeStepGrowthStrategy(const string& strategy);
331 static string timeStepGrowthStrategyName(TimeStepGrowthStrategy strategy);
332
333 //! Determine the timestep growth factor after a successful step.
334 //!
335 //! Called only when a successful step reuses the current Jacobian.
336 double calculateTimeStepGrowthFactor(span<const double> x_before,
337 span<const double> x_after);
338
339 //! Array of number of steps to take after each unsuccessful steady-state solve
340 //! before re-attempting the steady-state solution. For subsequent time stepping
341 //! calls, the final value is reused. See setTimeStep().
342 vector<int> m_steps = { 10 };
343
344 double m_tstep = 1.0e-5; //!< Initial timestep
345 double m_tmin = 1e-16; //!< Minimum timestep size
346 double m_tmax = 1e+08; //!< Maximum timestep size
347
348 //! Factor time step is multiplied by if time stepping fails ( < 1 )
349 double m_tfactor = 0.5;
350
351 //! Growth factor for successful steps that reuse the Jacobian.
352 //!
353 //! Used directly for `fixed-growth`, and as the base / cap value for the
354 //! other named growth strategies.
355 double m_tstep_growth = 1.5;
356
357 //! Selected strategy for successful-step growth.
358 TimeStepGrowthStrategy m_tstep_growth_strategy = TimeStepGrowthStrategy::fixed;
359
360 shared_ptr<vector<double>> m_state; //!< Solution vector
361
362 //! Work array used to hold the residual or the new solution
363 vector<double> m_xnew;
364
365 //! State vector after the last successful set of time steps
366 vector<double> m_xlast_ts;
367
368 unique_ptr<MultiNewton> m_newt; //!< Newton iterator
369 double m_rdt = 0.0; //!< Reciprocal of time step
370
371 shared_ptr<SystemJacobian> m_jac; //!< Jacobian evaluator
372 bool m_jac_ok = false; //!< If `true`, Jacobian is current
373
374 size_t m_bw = 0; //!< Jacobian bandwidth
375 size_t m_size = 0; //!< %Solution vector size
376
377 //! Work arrays used during Jacobian evaluation
378 vector<double> m_work1, m_work2;
379
380 vector<int> m_mask; //!< Transient mask. See transientMask()
381 int m_ss_jac_age = 20; //!< Maximum age of the Jacobian in steady-state mode.
382 int m_ts_jac_age = 20; //!< Maximum age of the Jacobian in time-stepping mode.
383
384 //! Counter used to manage the number of states stored in the debug log file
385 //! generated by writeDebugInfo()
387
388 //! Constant that determines the maximum number of states stored in the debug log
389 //! file generated by writeDebugInfo()
391
392 //! Function called at the start of every call to #eval.
393 Func1* m_interrupt = nullptr;
394
395 //! User-supplied function called after each successful timestep.
397
398 int m_nsteps = 0; //!< Number of time steps taken in the current call to solve()
399 int m_nsteps_max = 500; //!< Maximum number of timesteps allowed per call to solve()
400
401 //! Threshold for ignoring small elements in Jacobian
403 //! Relative perturbation of each component in finite difference Jacobian
404 double m_jacobianRelPerturb = 1e-5;
405 //! Absolute perturbation of each component in finite difference Jacobian
406 double m_jacobianAbsPerturb = 1e-10;
407
408};
409
410}
411
412#endif
Declarations for class SystemJacobian.
Base class for exceptions thrown by Cantera classes.
CanteraError()
Protected default constructor discourages throwing errors containing no information.
Base class for 'functor' classes that evaluate a function of one variable.
Definition Func1.h:75
Newton iterator for multi-domain, one-dimensional problems.
Definition MultiNewton.h:24
Base class for representing a system of differential-algebraic equations and solving for its steady-s...
int m_nsteps
Number of time steps taken in the current call to solve()
double calculateTimeStepGrowthFactor(span< const double > x_before, span< const double > x_after)
Determine the timestep growth factor after a successful step.
size_t m_size
Solution vector size
int m_nsteps_max
Maximum number of timesteps allowed per call to solve()
virtual void resize()
Call to set the size of internal data structures after first defining the system or if the problem si...
shared_ptr< SystemJacobian > linearSolver() const
Get the the linear solver being used to hold the Jacobian matrix and solve linear systems as part of ...
double timeStep(int nsteps, double dt, span< double > x, span< double > r, int loglevel)
Take time steps using Backward Euler.
virtual void resetBadValues(span< double > x)
Reset values such as negative species concentrations.
vector< double > m_xnew
Work array used to hold the residual or the new solution.
unique_ptr< MultiNewton > m_newt
Newton iterator.
void getState(span< double > x) const
Get the converged steady-state solution after calling solve().
double m_jacobianAbsPerturb
Absolute perturbation of each component in finite difference Jacobian.
size_t size() const
Total solution vector length;.
vector< int > & transientMask()
Access the vector indicating which equations contain a transient term.
virtual double upperBound(size_t i) const =0
Get the upper bound for global component i in the state vector.
double rdt() const
Reciprocal of the time step.
virtual string componentName(size_t i) const
Get the name of the i-th component of the state vector.
virtual string componentTableLabel(size_t i) const
Get elements of the component name, aligned with the column headings given by componentTableHeader().
virtual void initTimeInteg(double dt, span< const double > x)
Prepare for time stepping beginning with solution x and timestep dt.
double tsnorm(span< const double > x, span< double > r)
Transient max norm (infinity norm) of the residual evaluated using solution x and the current timeste...
void evalSSJacobian(span< const double > x)
Evaluate the steady-state Jacobian, accessible via linearSolver()
size_t bandwidth() const
Jacobian bandwidth.
virtual double weightedNorm(span< const double > step) const =0
Compute the weighted norm of step.
double m_rdt
Reciprocal of time step.
double m_jacobianThreshold
Threshold for ignoring small elements in Jacobian.
void setMaxTimeStep(double tmax)
Set the maximum time step allowed during time stepping.
shared_ptr< SystemJacobian > m_jac
Jacobian evaluator.
void setInitialGuess(span< const double > x)
Set the initial guess. Should be called before solve().
shared_ptr< vector< double > > m_state
Solution vector.
void setMinTimeStep(double tmin)
Set the minimum time step allowed during time stepping.
void setTimeStepGrowthStrategy(const string &strategy)
Set the strategy used to grow the timestep after a successful step that reuses the current Jacobian.
virtual void eval(span< const double > x, span< double > r, double rdt=-1.0, int count=1)=0
Evaluate the residual function.
vector< int > m_mask
Transient mask.
void setTimeStepCallback(Func1 *callback)
Set a function that will be called after each successful timestep.
Func1 * m_interrupt
Function called at the start of every call to eval.
virtual double lowerBound(size_t i) const =0
Get the lower bound for global component i in the state vector.
bool transient() const
True if transient mode.
void setMaxTimeStepCount(int nmax)
Set the maximum number of timeteps allowed before successful steady-state solve.
void solve(int loglevel=0)
Solve the steady-state problem, taking internal timesteps as necessary until the Newton solver can co...
double ssnorm(span< const double > x, span< double > r)
Steady-state max norm (infinity norm) of the residual evaluated using solution x.
void setTimeStepFactor(double tfactor)
Sets a factor by which the time step is reduced if the time stepping fails.
string timeStepGrowthStrategy() const
Get the configured timestep growth strategy.
void setTimeStep(double stepsize, span< const int > tsteps)
Set the number of time steps to try when the steady Newton solver is unsuccessful.
vector< int > m_steps
Array of number of steps to take after each unsuccessful steady-state solve before re-attempting the ...
TimeStepGrowthStrategy m_tstep_growth_strategy
Selected strategy for successful-step growth.
size_t m_bw
Jacobian bandwidth.
double m_tfactor
Factor time step is multiplied by if time stepping fails ( < 1 )
bool m_jac_ok
If true, Jacobian is current.
double m_tstep
Initial timestep.
int maxTimeStepCount() const
Get the maximum number of timeteps allowed before successful steady-state solve.
void setTimeStepGrowthFactor(double tfactor)
Set the growth factor used after successful timesteps when the Jacobian is re-used.
int m_ts_jac_age
Maximum age of the Jacobian in time-stepping mode.
void setJacAge(int ss_age, int ts_age=-1)
Set the maximum number of steps that can be taken using the same Jacobian before it must be re-evalua...
virtual void writeDebugInfo(const string &header_suffix, const string &message, int loglevel, int attempt_counter)
Write solver debugging based on the specified log level.
double m_tmin
Minimum timestep size.
void setJacobianPerturbation(double relative, double absolute, double threshold)
Configure perturbations used to evaluate finite difference Jacobian.
double m_tmax
Maximum timestep size.
int m_ss_jac_age
Maximum age of the Jacobian in steady-state mode.
virtual void evalJacobian(span< const double > x0)=0
Evaluates the Jacobian at x0 using finite differences.
virtual void setSteadyMode()
Prepare to solve the steady-state problem.
virtual void clearDebugFile()
Delete debug output file that may be created by writeDebugInfo() when solving with high loglevel.
int m_attempt_counter
Counter used to manage the number of states stored in the debug log file generated by writeDebugInfo(...
double timeStepGrowthFactor() const
Get the successful-step time step growth factor.
void setLinearSolver(shared_ptr< SystemJacobian > solver)
Set the linear solver used to hold the Jacobian matrix and solve linear systems as part of each Newto...
int m_max_history
Constant that determines the maximum number of states stored in the debug log file generated by write...
Func1 * m_time_step_callback
User-supplied function called after each successful timestep.
virtual pair< string, string > componentTableHeader() const
Get header lines describing the column names included in a component label.
double m_jacobianRelPerturb
Relative perturbation of each component in finite difference Jacobian.
vector< double > m_xlast_ts
State vector after the last successful set of time steps.
bool steady() const
True if steady mode.
vector< double > m_work1
Work arrays used during Jacobian evaluation.
MultiNewton & newton()
Return a reference to the Newton iterator.
double m_tstep_growth
Growth factor for successful steps that reuse the Jacobian.
void setInterrupt(Func1 *interrupt)
Set a function that will be called every time eval is called.
Error thrown when time stepping cannot proceed and the steady-state solver should be given a chance t...
string getClass() const override
Method overridden by derived classes to indicate their type.
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