Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 8a69c0a

Browse files
authored
Merge pull request #4 from ikorotkin/issue-3-time-stepping
Closed issue #3 - time stepping
2 parents 1eda476 + 920c672 commit 8a69c0a

File tree

5 files changed

+127
-23
lines changed

5 files changed

+127
-23
lines changed

examples/diffusion_2d/diffusion_2d.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ int solution_check(dae::state_type &x, MKL_INT N, double t, double D)
212212
<< "% deviation from the analytical value)\n";
213213
std::cout << "Maximum relative error: " << err_max << "%\n";
214214

215-
if(err_max < 1.0 && err_conc < 1.0e-6)
215+
if(err_max < 2.0 && err_conc < 1.0e-6)
216216
return 0;
217217
else
218218
return 1;

examples/perovskite/perovskite.cpp

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,13 +99,10 @@ int main()
9999
// parameters defined in solver_options.h
100100
dae::SolverOptions opt;
101101

102-
#ifdef DAE_SINGLE
103-
opt.atol = 1.0e-3; // Absolute tolerance for single precision
104-
#else
105-
opt.atol = 1.0e-6; // Absolute tolerance for double precision
106-
#endif
107-
opt.fact_every_iter = false; // Gain some speed. The matrices will be
108-
// factorized only once each time step.
102+
opt.dt_increase_factor = 1.4; // Reduce time step increase factor to get
103+
// better accuracy (default value is 2.0)
104+
opt.fact_every_iter = false; // Gain some speed. The matrices will be
105+
// factorized only once each time step.
109106

110107
// Create an instance of the solver with particular RHS, Mass matrix,
111108
// Jacobian and solver options

src/solver.cpp

Lines changed: 87 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ void Solver::operator()(state_type &x)
3131
else if(m_opt.dt_init > m_t1)
3232
{
3333
double new_dt = m_t1 / 10.0;
34-
std::cout << "WARNING: Initial time step is bigger than the integration time t1: "
34+
std::cout << "WARNING: Initial time step is bigger than the "
35+
"integration time t1: "
3536
<< m_opt.dt_init
3637
<< "\n The solver will use dt = t1/10 = " << new_dt
3738
<< std::endl;
@@ -130,6 +131,7 @@ void Solver::operator()(state_type &x)
130131

131132
// TODO: Start timer here
132133

134+
// Memory control variables
133135
int peak_mem1 = 0, peak_mem2 = 0, peak_mem3 = 0;
134136

135137
bool final_time_step = false;
@@ -254,6 +256,7 @@ void Solver::operator()(state_type &x)
254256
{
255257
break;
256258
}
259+
257260
} // for iter
258261

259262
// Newton iterator failed to converge within max_Newton_iter iterations
@@ -268,27 +271,102 @@ void Solver::operator()(state_type &x)
268271
step_counter--;
269272
final_time_step = false;
270273
dt /= m_opt.dt_decrease_factor;
274+
current_scheme = 1;
275+
if(dt < m_opt.dt_min)
276+
{
277+
// This actually means solution error
278+
// TODO: stop the solver
279+
std::cout << "\nERROR: The time step was reduced to " << dt
280+
<< " but the Newton method failed to converge\n";
281+
exit(4);
282+
}
271283
x = x_prev[0];
272284
continue;
273285
}
274286

287+
// The solver reached the target time t1
275288
if(final_time_step)
276289
{
277290
break;
278291
}
279292

280293
// Simple yet efficient adaptive time stepping
281-
if(iter < m_opt.dt_increase_threshold)
294+
if(m_opt.time_stepping == 1) // S-SATS
282295
{
283-
dt *= m_opt.dt_increase_factor;
284-
if(m_opt.verbosity > 0)
285-
std::cout << '>';
296+
if(iter < m_opt.dt_increase_threshold)
297+
{
298+
dt *= m_opt.dt_increase_factor;
299+
if(m_opt.dt_increase_factor != 1.0)
300+
current_scheme = 1;
301+
if(dt > m_opt.dt_max)
302+
dt = m_opt.dt_max;
303+
if(m_opt.verbosity > 0)
304+
std::cout << '>';
305+
}
306+
else if(iter >= m_opt.dt_decrease_threshold - 1)
307+
{
308+
dt /= m_opt.dt_decrease_factor;
309+
if(m_opt.dt_decrease_factor != 1.0)
310+
current_scheme = 1;
311+
if(dt < m_opt.dt_min)
312+
dt = m_opt.dt_min;
313+
if(m_opt.verbosity > 0)
314+
std::cout << '<';
315+
}
286316
}
287-
else if(iter >= m_opt.dt_decrease_threshold - 1)
317+
else if(m_opt.time_stepping == 2) // A-SATS
288318
{
289-
dt /= m_opt.dt_decrease_factor;
290-
if(m_opt.verbosity > 0)
291-
std::cout << '<';
319+
double norm1 = 0.0;
320+
double norm2 = 0.0;
321+
322+
// Estimate NORM(C(n+1) - C(n)) and NORM(C(n))
323+
for(MKL_INT i = 0; i < size; i++)
324+
{
325+
norm1 += (x[i] - x_prev[0][i]) * (x[i] - x_prev[0][i]);
326+
norm2 += x_prev[0][i] * x_prev[0][i];
327+
}
328+
norm1 = sqrt(norm1);
329+
norm2 = sqrt(norm2);
330+
331+
// Monitor function
332+
double eta = norm1 / (norm2 + m_opt.dt_eps_m);
333+
334+
// The time step can be increased
335+
if(eta < m_opt.dt_eta_min)
336+
{
337+
dt *= m_opt.dt_increase_factor;
338+
if(m_opt.dt_increase_factor != 1.0)
339+
current_scheme = 1;
340+
if(dt > m_opt.dt_max)
341+
dt = m_opt.dt_max;
342+
if(m_opt.verbosity > 0)
343+
std::cout << '>';
344+
}
345+
346+
// The time step should be reduced, scrape the current time
347+
// iteration
348+
if(eta > m_opt.dt_eta_max)
349+
{
350+
if(m_opt.verbosity > 0)
351+
std::cout << " <- redo: eta = " << eta;
352+
353+
t -= dt;
354+
step_counter--;
355+
final_time_step = false;
356+
dt /= m_opt.dt_decrease_factor;
357+
current_scheme = 1;
358+
if(dt < m_opt.dt_min)
359+
{
360+
// This actually means solution error
361+
// TODO: stop the solver
362+
std::cout << "\nERROR: The time step was reduced to " << dt
363+
<< " but the relative error is still above the "
364+
"threshold\n";
365+
exit(5);
366+
}
367+
x = x_prev[0];
368+
continue;
369+
}
292370
}
293371

294372
if(t + dt > m_t1)

src/solver_options.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,13 @@ void SolverOptions::check_options()
9595
bdf_order = 1;
9696
}
9797

98+
if(time_stepping < 1 || time_stepping > 2)
99+
{
100+
// TODO: print warning
101+
// fall back to S-SATS
102+
time_stepping = 1;
103+
}
104+
98105
// TODO: add more checks
99106
}
100107

src/solver_options.h

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,30 +32,52 @@ class SolverOptions
3232
// 1 - first order BDF, 2 - BDF-2, ..., 6 - BDF-6
3333
int bdf_order = 6;
3434

35+
// Time stepping algorithm:
36+
// 1 - Stability-based Simple Adaptive Time Stepping (S-SATS),
37+
// 2 - Accuracy-based Simple Adaptive Time Stepping (A-SATS) from
38+
// https://www.sciencedirect.com/science/article/pii/S0377042705005534
39+
int time_stepping = 1;
40+
3541
// Maximum number of Newton iterations. If the Newton method fails to
3642
// converge after max_Newton_iter iterations, the solver reduces time step
3743
// and tries to make the current step again.
3844
int max_Newton_iter = 15;
3945

40-
// Absolute tolerance
46+
// Absolute tolerance for the Newton algorithm
4147
#ifdef DAE_SINGLE
4248
double atol = 1.0e-3; // Absolute tolerance for single precision
4349
#else
4450
double atol = 1.0e-6; // Absolute tolerance for double precision
4551
#endif
4652

53+
#ifdef DAE_SINGLE
54+
double dt_eps_m =
55+
1.0e-5; // The order of the rounding unit for single precision
56+
#else
57+
double dt_eps_m =
58+
1.0e-10; // The order of the rounding unit for double precision
59+
#endif
60+
4761
// Initial time step
4862
double dt_init = 0.1;
4963

64+
// Minimum and maximum time steps
65+
double dt_min = dt_eps_m;
66+
double dt_max = 100.0;
67+
5068
// Verbosity level of the solver:
5169
// 0 - be silent, 1 - prints some basic information, 2 - chatterbox
5270
int verbosity = 1;
5371

54-
// Adaptive time stepping options
55-
int dt_increase_threshold = 3;
56-
int dt_decrease_threshold = 7;
57-
double dt_increase_factor = 1.4;
58-
double dt_decrease_factor = 1.4;
72+
// Simple Adaptive Time Stepping options
73+
int dt_increase_threshold = 3; // Time step amplification threshold
74+
// (S-SATS only)
75+
int dt_decrease_threshold = 7; // Time stepreduction threshold
76+
// (S-SATS only)
77+
double dt_increase_factor = 2.0; // Time step amplification factor
78+
double dt_decrease_factor = 2.0; // Time step reduction factor
79+
double dt_eta_min = 0.05; // Monitor function lower threshold (A-SATS only)
80+
double dt_eta_max = 0.5; // Monitor function higher threshold (A-SATS only)
5981

6082
// Intel MKL PARDISO parameters (iparam). More about iparam:
6183
// https://software.intel.com/en-us/mkl-developer-reference-c-pardiso-iparm-parameter

0 commit comments

Comments
 (0)