Cantera  3.2.0a2
Loading...
Searching...
No Matches
SteadyStateSystem.cpp
Go to the documentation of this file.
1//! @file SteadyStateSystem.cpp
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
9
10using namespace std;
11
12namespace Cantera
13{
14
15SteadyStateSystem::SteadyStateSystem()
16{
17 m_state = make_shared<vector<double>>();
18 m_newt = make_unique<MultiNewton>(1);
19}
20
21SteadyStateSystem::~SteadyStateSystem()
22{
23}
24
26{
29 m_state->assign(x, x + size());
30}
31
32void SteadyStateSystem::getState(double* x) const
33{
34 copy(m_xnew.begin(), m_xnew.end(), x);
35}
36
37int SteadyStateSystem::solve(double* x, double* xnew, int loglevel)
38{
39 warn_deprecated("SteadyStateSystem::solve(double*, double*, int)",
40 "To be removed after Cantera 3.2. Use setInitialGuess, solve(int), and "
41 "getState instead.");
43 solve(loglevel);
44 getState(xnew);
45 return 1;
46}
47
48void SteadyStateSystem::solve(int loglevel)
49{
50 size_t istep = 0;
51 int nsteps = m_steps[istep];
52 m_nsteps = 0;
53 double dt = m_tstep;
54
55 while (true) {
56 // Keep the attempt_counter in the range of [1, max_history]
58
59 // Attempt to solve the steady problem
62 debuglog("\nAttempt Newton solution of steady-state problem.", loglevel);
63 if (!m_jac_ok) {
64 evalJacobian(m_state->data());
65 try {
66 m_jac->updateTransient(m_rdt, m_mask.data());
67 m_jac_ok = true;
68 } catch (CanteraError& err) {
69 // Allow solver to continue after failure to factorize the steady-state
70 // Jacobian by returning to time stepping mode
71 if (m_rdt == 0.0) {
72 if (loglevel > 1) {
73 writelog("\nSteady Jacobian factorization failed:"
74 "\n {}:\n {}",
75 err.getMethod(), err.getMessage());
76 }
77 } else {
78 throw;
79 }
80 }
81 }
82 int m = -1;
83 if (m_jac_ok) {
84 m = newton().solve(m_state->data(), m_xnew.data(), *this, loglevel);
85 }
86 if (m == 1) {
87 *m_state = m_xnew;
88 writeDebugInfo("NewtonSuccess", "After successful Newton solve",
89 loglevel, m_attempt_counter);
90
91 return;
92 } else {
93 debuglog("\nNewton steady-state solve failed.\n", loglevel);
94 writeDebugInfo("NewtonFail", "After unsuccessful Newton solve",
95 loglevel, m_attempt_counter);
96
97 if (loglevel > 0) {
98 writelog("\nAttempt {} timesteps.", nsteps);
99 }
100
101 dt = timeStep(nsteps, dt, m_state->data(), m_xnew.data(), loglevel-1);
103 writeDebugInfo("Timestepping", "After timestepping", loglevel,
105
106 // Repeat the last timestep's data for logging purposes
107 if (loglevel == 1) {
108 writelog("\nFinal timestep info: dt= {:<10.4g} log(ss)= {:<10.4g}\n", dt,
109 log10(ssnorm(m_state->data(), m_xnew.data())));
110 }
111 istep++;
112 if (istep >= m_steps.size()) {
113 nsteps = m_steps.back();
114 } else {
115 nsteps = m_steps[istep];
116 }
117 dt = std::min(dt, m_tmax);
118 }
119 }
120}
121
122double SteadyStateSystem::timeStep(int nsteps, double dt, double* x, double* r, int loglevel)
123{
124 // set the Jacobian age parameter to the transient value
126
127 int n = 0;
128 int successiveFailures = 0;
129
130 // Only output this if nothing else under this function call will be output
131 if (loglevel == 1) {
132 writelog("\n============================");
133 writelog("\n{:<5s} {:<11s} {:<7s}\n", "step", "dt (s)", "log(ss)");
134 writelog("============================");
135 }
136 while (n < nsteps) {
137 if (loglevel == 1) { // At level 1, output concise information
138 double ss = ssnorm(x, r);
139 writelog("\n{:<5d} {:<6.4e} {:>7.4f}", n, dt, log10(ss));
140 } else if (loglevel > 1) {
141 double ss = ssnorm(x, r);
142 writelog("\nTimestep ({}) dt= {:<11.4e} log(ss)= {:<7.4f}", n, dt, log10(ss));
143 }
144
145 // set up for time stepping with stepsize dt
146 initTimeInteg(dt,x);
147
148 int j0 = m_jac->nEvals(); // Store the current number of Jacobian evaluations
149
150 // solve the transient problem
151 int status = newton().solve(x, r, *this, loglevel);
152
153 // successful time step. Copy the new solution in r to
154 // the current solution in x.
155 if (status >= 0) {
156 if (loglevel > 1) {
157 writelog("\nTimestep ({}) succeeded", n);
158 }
159 successiveFailures = 0;
160 m_nsteps++;
161 n += 1;
162 copy(r, r + m_size, x);
163 // No Jacobian evaluations were performed, so a larger timestep can be used
164 if (m_jac->nEvals() == j0) {
165 dt *= 1.5;
166 }
169 }
170 dt = std::min(dt, m_tmax);
171 if (m_nsteps >= m_nsteps_max) {
172 throw CanteraError("OneDim::timeStep",
173 "Took maximum number of timesteps allowed ({}) without "
174 "reaching steady-state solution.", m_nsteps_max);
175 }
176 } else {
177 // No solution could be found with this time step.
178 // Decrease the stepsize and try again.
179 successiveFailures++;
180 if (loglevel == 1) {
181 writelog("\nTimestep failed");
182 } else if (loglevel > 1) {
183 writelog("\nTimestep ({}) failed", n);
184 }
185 if (successiveFailures > 2) {
186 debuglog("--> Resetting negative species concentrations", loglevel);
188 successiveFailures = 0;
189 } else {
190 debuglog("--> Reducing timestep", loglevel);
191 dt *= m_tfactor;
192 if (dt < m_tmin) {
193 string err_msg = fmt::format(
194 "Time integration failed. Minimum timestep ({}) reached.", m_tmin);
195 throw CanteraError("OneDim::timeStep", err_msg);
196 }
197 }
198 }
199 }
200
201 // Write the final step to the log
202 if (loglevel == 1) {
203 double ss = ssnorm(x, r);
204 writelog("\n{:<5d} {:<6.4e} {:>7.4f}", n, dt, log10(ss));
205 writelog("\n============================");
206 } else if (loglevel > 1) {
207 double ss = ssnorm(x, r);
208 writelog("\nTimestep ({}) dt= {:<11.4e} log10(ss)= {:<7.4f}\n", n, dt, log10(ss));
209 }
210
211 // return the value of the last stepsize, which may be smaller
212 // than the initial stepsize
213 return dt;
214}
215
216double SteadyStateSystem::ssnorm(double* x, double* r)
217{
218 eval(x, r, 0.0, 0);
219 double ss = 0.0;
220 for (size_t i = 0; i < m_size; i++) {
221 ss = std::max(fabs(r[i]),ss);
222 }
223 return ss;
224}
225
226void SteadyStateSystem::setTimeStep(double stepsize, size_t n, const int* tsteps)
227{
228 m_tstep = stepsize;
229 m_steps.resize(n);
230 for (size_t i = 0; i < n; i++) {
231 m_steps[i] = tsteps[i];
232 }
233}
234
236{
237 m_state->resize(size());
238 m_xnew.resize(size());
239 m_newt->resize(size());
240 m_mask.resize(size());
241 if (!m_jac) {
242 throw CanteraError("SteadyStateSystem::resize",
243 "Jacobian evaluator must be instantiated before calling resize()");
244 }
245 m_jac->initialize(size());
246 m_jac->setBandwidth(bandwidth());
247 m_jac->clearStats();
248 m_jac_ok = false;
249}
250
251void SteadyStateSystem::setLinearSolver(shared_ptr<SystemJacobian> solver)
252{
253 m_jac = solver;
254 m_jac->initialize(size());
255 m_jac->setBandwidth(bandwidth());
256 m_jac->clearStats();
257 m_jac_ok = false;
258}
259
260void SteadyStateSystem::evalSSJacobian(double* x, double* rsd)
261{
262 double rdt_save = m_rdt;
263 m_jac_ok = false;
265 evalJacobian(x);
266 m_rdt = rdt_save;
267}
268
269void SteadyStateSystem::initTimeInteg(double dt, double* x)
270{
271 double rdt_old = m_rdt;
272 m_rdt = 1.0/dt;
273
274 // if the stepsize has changed, then update the transient part of the Jacobian
275 if (fabs(rdt_old - m_rdt) > Tiny) {
276 m_jac->updateTransient(m_rdt, m_mask.data());
277 }
278}
279
281{
282 if (m_rdt == 0) {
283 return;
284 }
285
286 m_rdt = 0.0;
287 m_jac->updateTransient(m_rdt, m_mask.data());
288}
289
290void SteadyStateSystem::setJacAge(int ss_age, int ts_age)
291{
292 m_ss_jac_age = ss_age;
293 if (ts_age > 0) {
294 m_ts_jac_age = ts_age;
295 } else {
297 }
298}
299
301{
302 return *m_newt;
303}
304
305}
Base class for exceptions thrown by Cantera classes.
virtual string getMessage() const
Method overridden by derived classes to format the error message.
virtual string getMethod() const
Get the name of the method that threw the exception.
virtual double eval(double t) const
Evaluate the function.
Definition Func1.cpp:28
Newton iterator for multi-domain, one-dimensional problems.
Definition MultiNewton.h:25
int solve(double *x0, double *x1, SteadyStateSystem &r, int loglevel)
Find the solution to F(x) = 0 by damped Newton iteration.
void setOptions(int maxJacAge=5)
Set options.
int solve(double *x0, double *x1, int loglevel)
Solve , where is the residual function.
int m_nsteps
Number of time steps taken in the current call to solve()
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...
vector< double > m_xnew
Work array used to hold the residual or the new solution.
unique_ptr< MultiNewton > m_newt
Newton iterator.
virtual void resetBadValues(double *x)
Reset values such as negative species concentrations.
size_t size() const
Total solution vector length;.
double ssnorm(double *x, double *r)
Steady-state max norm (infinity norm) of the residual evaluated using solution x.
virtual void initTimeInteg(double dt, double *x)
Prepare for time stepping beginning with solution x and timestep dt.
size_t bandwidth() const
Jacobian bandwidth.
double m_rdt
Reciprocal of time step.
shared_ptr< SystemJacobian > m_jac
Jacobian evaluator.
shared_ptr< vector< double > > m_state
Solution vector.
vector< int > m_mask
Transient mask.
vector< int > m_steps
Array of number of steps to take after each unsuccessful steady-state solve before re-attempting the ...
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 m_ts_jac_age
Maximum age of the Jacobian in time-stepping mode.
virtual void eval(double *x, double *r, double rdt=-1.0, int count=1)=0
Evaluate the residual function.
double timeStep(int nsteps, double dt, double *x, double *r, int loglevel)
Take time steps using Backward Euler.
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...
void evalSSJacobian(double *x, double *rsd)
Evaluate the steady-state Jacobian, accessible via linearSolver()
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.
double m_tmax
Maximum timestep size.
int m_ss_jac_age
Maximum age of the Jacobian in steady-state mode.
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(...
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...
void setTimeStep(double stepsize, size_t n, const int *tsteps)
Set the number of time steps to try when the steady Newton solver is unsuccessful.
int m_max_history
Constant that determines the maximum number of states stored in the debug log file generated by write...
void setInitialGuess(const double *x)
Set the initial guess. Should be called before solve().
void getState(double *x) const
Get the converged steady-state solution after calling solve().
Func1 * m_time_step_callback
User-supplied function called after each successful timestep.
virtual void evalJacobian(double *x0)=0
Evaluates the Jacobian at x0 using finite differences.
vector< double > m_xlast_ts
State vector after the last successful set of time steps.
MultiNewton & newton()
Return a reference to the Newton iterator.
void debuglog(const string &msg, int loglevel)
Write a message to the log only if loglevel > 0.
Definition global.h:154
void writelog(const string &fmt, const Args &... args)
Write a formatted message to the screen.
Definition global.h:171
Namespace for the Cantera kernel.
Definition AnyMap.cpp:595
const double Tiny
Small number to compare differences of mole fractions against.
Definition ct_defs.h:173
void warn_deprecated(const string &source, const AnyBase &node, const string &message)
A deprecation warning for syntax in an input file.
Definition AnyMap.cpp:1997