@@ -108,6 +108,46 @@ void SteadyStateSystem::solve(int loglevel)
108108 }
109109}
110110
111+ double SteadyStateSystem::timeStepIncreaseFactor (double * x_before, double * x_after)
112+ {
113+ int heuristic = 2 ; // Can be 1-4
114+ m_work1.resize (m_size);
115+ const double grow_factor = 1.25 ;
116+
117+ if (heuristic == 1 ) {
118+ // Steady-state residual gate. If the steady-state residual decreased, allow
119+ // increase in timestep.
120+ double ss_before = ssnorm (x_before, m_work1.data ());
121+ double ss_after = ssnorm (x_after, m_work1.data ());
122+ return (ss_after < ss_before) ? grow_factor : 1.0 ;
123+ } else if (heuristic == 2 ) {
124+ // Transient residual gate. If the transient residual decreased, allow
125+ // increase in timestep.
126+ double ts_before = tsnorm (x_before, m_work1.data ());
127+ double ts_after = tsnorm (x_after, m_work1.data ());
128+ return (ts_after < ts_before) ? grow_factor : 1.0 ;
129+ } else if (heuristic == 3 ) {
130+ // Residual-ratio scaling gate (transient residual). If the transient residual
131+ // decreased significantly, allow larger increase in timestep.
132+ double ts_before = tsnorm (x_before, m_work1.data ());
133+ double ts_after = tsnorm (x_after, m_work1.data ());
134+ if (!(ts_after > 0.0 ) || !(ts_before > ts_after)) {
135+ return 1.0 ;
136+ }
137+ const double max_growth = 1.5 ;
138+ const double exponent = 0.2 ;
139+ double ratio = ts_before / ts_after;
140+ double factor = std::pow (ratio, exponent);
141+ return std::min (max_growth, std::max (1.0 , factor));
142+ } else if (heuristic == 4 ) {
143+ // Newton-iteration gate. If the last Newton solve required only a few
144+ // iterations, allow increase in timestep.
145+ const int max_iters_for_growth = 3 ;
146+ return (newton ().lastIterations () <= max_iters_for_growth) ? grow_factor : 1.0 ;
147+ }
148+ return 1.0 ;
149+ }
150+
111151double SteadyStateSystem::timeStep (int nsteps, double dt, double * x, double * r, int loglevel)
112152{
113153 // set the Jacobian age parameter to the transient value
@@ -123,12 +163,14 @@ double SteadyStateSystem::timeStep(int nsteps, double dt, double* x, double* r,
123163 writelog (" ============================" );
124164 }
125165 while (n < nsteps) {
126- if (loglevel == 1 ) { // At level 1, output concise information
127- double ss = ssnorm (x, r);
128- writelog (" \n {:<5d} {:<6.4e} {:>7.4f}" , n, dt, log10 (ss));
129- } else if (loglevel > 1 ) {
130- double ss = ssnorm (x, r);
131- writelog (" \n Timestep ({}) dt= {:<11.4e} log(ss)= {:<7.4f}" , n, dt, log10 (ss));
166+ if (loglevel >= 1 ) {
167+ double ss_before = ssnorm (x, r);
168+ if (loglevel == 1 ) { // At level 1, output concise information
169+ writelog (" \n {:<5d} {:<6.4e} {:>7.4f}" , n, dt, log10 (ss_before));
170+ } else {
171+ writelog (" \n Timestep ({}) dt= {:<11.4e} log(ss)= {:<7.4f}" , n, dt,
172+ log10 (ss_before));
173+ }
132174 }
133175
134176 // set up for time stepping with stepsize dt
@@ -148,17 +190,18 @@ double SteadyStateSystem::timeStep(int nsteps, double dt, double* x, double* r,
148190 successiveFailures = 0 ;
149191 m_nsteps++;
150192 n += 1 ;
151- copy (r, r + m_size, x);
152- // No Jacobian evaluations were performed, so a larger timestep can be used
193+ double grow_factor = 1.0 ;
153194 if (m_jac->nEvals () == j0) {
154- dt *= 1.5 ;
195+ grow_factor = timeStepIncreaseFactor (x, r) ;
155196 }
197+ copy (r, r + m_size, x);
198+ dt *= grow_factor;
156199 if (m_time_step_callback) {
157200 m_time_step_callback->eval (dt);
158201 }
159202 dt = std::min (dt, m_tmax);
160203 if (m_nsteps >= m_nsteps_max) {
161- throw CanteraError (" OneDim ::timeStep" ,
204+ throw CanteraError (" SteadyStateSystem ::timeStep" ,
162205 " Took maximum number of timesteps allowed ({}) without "
163206 " reaching steady-state solution." , m_nsteps_max);
164207 }
@@ -181,7 +224,7 @@ double SteadyStateSystem::timeStep(int nsteps, double dt, double* x, double* r,
181224 if (dt < m_tmin) {
182225 string err_msg = fmt::format (
183226 " Time integration failed. Minimum timestep ({}) reached." , m_tmin);
184- throw CanteraError (" OneDim ::timeStep" , err_msg);
227+ throw CanteraError (" SteadyStateSystem ::timeStep" , err_msg);
185228 }
186229 }
187230 }
@@ -212,6 +255,16 @@ double SteadyStateSystem::ssnorm(double* x, double* r)
212255 return ss;
213256}
214257
258+ double SteadyStateSystem::tsnorm (double * x, double * r)
259+ {
260+ eval (x, r, m_rdt, 0 );
261+ double ts = 0.0 ;
262+ for (size_t i = 0 ; i < m_size; i++) {
263+ ts = std::max (fabs (r[i]), ts);
264+ }
265+ return ts;
266+ }
267+
215268void SteadyStateSystem::setTimeStep (double stepsize, size_t n, const int * tsteps)
216269{
217270 m_tstep = stepsize;
@@ -261,7 +314,7 @@ void SteadyStateSystem::initTimeInteg(double dt, double* x)
261314 m_rdt = 1.0 /dt;
262315
263316 // if the stepsize has changed, then update the transient part of the Jacobian
264- if (fabs (rdt_old - m_rdt) > Tiny) {
317+ if (fabs (rdt_old - m_rdt) > Tiny && m_jac_ok ) {
265318 m_jac->updateTransient (m_rdt, m_mask.data ());
266319 }
267320}
@@ -273,7 +326,9 @@ void SteadyStateSystem::setSteadyMode()
273326 }
274327
275328 m_rdt = 0.0 ;
276- m_jac->updateTransient (m_rdt, m_mask.data ());
329+ if (m_jac_ok) {
330+ m_jac->updateTransient (m_rdt, m_mask.data ());
331+ }
277332}
278333
279334void SteadyStateSystem::setJacAge (int ss_age, int ts_age)
0 commit comments