Skip to content

Commit 259db7c

Browse files
ajnonakagardner48
andauthored
Sundials Update (#3984)
## Summary Changes to the time integrator interface to now support explicit, implicit, and ImEx methods with fixed or adaptive time step size, as well as MRI approaches. ## Additional background Can be tested with amrex-tutorials PR AMReX-Codes/amrex-tutorials#123 --------- Co-authored-by: David J. Gardner <[email protected]>
1 parent adfc227 commit 259db7c

File tree

5 files changed

+837
-793
lines changed

5 files changed

+837
-793
lines changed

Src/Base/AMReX_FEIntegrator.H

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,92 @@ private:
1515

1616
amrex::Vector<std::unique_ptr<T> > F_nodes;
1717

18-
void initialize_stages (const T& S_data)
18+
// Current (internal) state and time
19+
amrex::Vector<std::unique_ptr<T> > S_current;
20+
amrex::Real time_current;
21+
22+
void initialize_stages (const T& S_data, const amrex::Real time)
1923
{
24+
// Create data for stage RHS
2025
IntegratorOps<T>::CreateLike(F_nodes, S_data);
26+
27+
// Create and initialize data for current state
28+
IntegratorOps<T>::CreateLike(S_current, S_data, true);
29+
IntegratorOps<T>::Copy(*S_current[0], S_data);
30+
31+
// Set the initial time
32+
time_current = time;
2133
}
2234

2335
public:
2436
FEIntegrator () {}
2537

26-
FEIntegrator (const T& S_data)
38+
FEIntegrator (const T& S_data, const amrex::Real time = 0.0)
2739
{
28-
initialize(S_data);
40+
initialize(S_data, time);
2941
}
3042

3143
virtual ~FEIntegrator () {}
3244

33-
void initialize (const T& S_data) override
45+
void initialize (const T& S_data, const amrex::Real time = 0.0)
3446
{
35-
initialize_stages(S_data);
47+
initialize_stages(S_data, time);
3648
}
3749

38-
amrex::Real advance (T& S_old, T& S_new, amrex::Real time, const amrex::Real time_step) override
50+
amrex::Real advance (T& S_old, T& S_new, amrex::Real time, const amrex::Real dt) override
3951
{
40-
BaseT::timestep = time_step;
41-
// Assume before advance() that S_old is valid data at the current time ("time" argument)
52+
// Assume before step() that S_old is valid data at the current time ("time" argument)
4253
// So we initialize S_new by copying the old state.
4354
IntegratorOps<T>::Copy(S_new, S_old);
4455

56+
// Call the pre RHS hook
57+
BaseT::pre_rhs_action(S_new, time);
58+
4559
// F = RHS(S, t)
4660
T& F = *F_nodes[0];
47-
BaseT::rhs(F, S_new, time);
61+
BaseT::Rhs(F, S_new, time);
4862

4963
// S_new += timestep * dS/dt
50-
IntegratorOps<T>::Saxpy(S_new, BaseT::timestep, F);
64+
IntegratorOps<T>::Saxpy(S_new, dt, F);
5165

52-
// Call the post-update hook for S_new
53-
BaseT::post_update(S_new, time + BaseT::timestep);
66+
// Call the post step hook
67+
BaseT::post_step_action(S_new, time + dt);
5468

5569
// Return timestep
56-
return BaseT::timestep;
70+
return dt;
71+
}
72+
73+
void evolve (T& S_out, const amrex::Real time_out) override
74+
{
75+
amrex::Real dt = BaseT::time_step;
76+
bool stop = false;
77+
78+
for (int step_number = 0; step_number < BaseT::max_steps && !stop; ++step_number)
79+
{
80+
// Adjust step size to reach output time
81+
if (time_out - time_current < dt) {
82+
dt = time_out - time_current;
83+
stop = true;
84+
}
85+
86+
// Call the time integrator step
87+
advance(*S_current[0], S_out, time_current, dt);
88+
89+
// Update current state S_current = S_out
90+
IntegratorOps<T>::Copy(*S_current[0], S_out);
91+
92+
// Update time
93+
time_current += dt;
94+
95+
if (step_number == BaseT::max_steps - 1) {
96+
Error("Did not reach output time in max steps.");
97+
}
98+
}
5799
}
58100

59101
virtual void time_interpolate (const T& /* S_new */, const T& /* S_old */, amrex::Real /* timestep_fraction */, T& /* data */) override
60102
{
61-
amrex::Error("Time interpolation not yet supported by forward euler integrator.");
103+
amrex::Error("Time interpolation not yet supported by the forward euler integrator.");
62104
}
63105

64106
virtual void map_data (std::function<void(T&)> Map) override

Src/Base/AMReX_IntegratorBase.H

Lines changed: 181 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -161,37 +161,120 @@ struct IntegratorOps<T, std::enable_if_t<std::is_same_v<amrex::MultiFab, T> > >
161161
template<class T>
162162
class IntegratorBase
163163
{
164-
private:
165-
/**
166-
* \brief Fun is the right-hand-side function the integrator will use.
167-
*/
168-
std::function<void(T&, const T&, const amrex::Real)> Fun;
169-
170-
/**
171-
* \brief FastFun is the fast timescale right-hand-side function for a multirate integration problem.
172-
*/
173-
std::function<void(T&, T&, const T&, const amrex::Real)> FastFun;
174-
175164
protected:
176-
/**
177-
* \brief Integrator timestep size (Real)
178-
*/
179-
amrex::Real timestep;
180-
181-
/**
182-
* \brief For multirate problems, the ratio of slow timestep size / fast timestep size (int)
183-
*/
184-
int slow_fast_timestep_ratio = 0;
185-
186-
/**
187-
* \brief For multirate problems, the fast timestep size (Real)
188-
*/
189-
Real fast_timestep = 0.0;
190-
191-
/**
192-
* \brief The post_update function is called by the integrator on state data before using it to evaluate a right-hand side.
193-
*/
194-
std::function<void (T&, amrex::Real)> post_update;
165+
/**
166+
* \brief Rhs is the right-hand-side function the integrator will use.
167+
*/
168+
std::function<void(T& rhs, const T& state, const amrex::Real time)> Rhs;
169+
170+
/**
171+
* \brief RhsIm is the implicit right-hand-side function an ImEx integrator
172+
* will use.
173+
*/
174+
std::function<void(T& rhs, const T& state, const amrex::Real time)> RhsIm;
175+
176+
/**
177+
* \brief RhsEx is the explicit right-hand-side function an ImEx integrator
178+
* will use.
179+
*/
180+
std::function<void(T& rhs, const T& state, const amrex::Real time)> RhsEx;
181+
182+
/**
183+
* \brief RhsFast is the fast timescale right-hand-side function a multirate
184+
* integrator will use.
185+
*/
186+
std::function<void(T& rhs, const T& state, const amrex::Real time)> RhsFast;
187+
188+
/**
189+
* \brief The pre_rhs_action function is called by the integrator on state
190+
* data before using it to evaluate a right-hand side.
191+
*/
192+
std::function<void (T&, amrex::Real)> pre_rhs_action;
193+
194+
/**
195+
* \brief The post_stage_action function is called by the integrator on
196+
* the computed stage just after it is computed
197+
*/
198+
std::function<void (T&, amrex::Real)> post_stage_action;
199+
200+
/**
201+
* \brief The post_step_action function is called by the integrator on
202+
* the computed state just after it is computed
203+
*/
204+
std::function<void (T&, amrex::Real)> post_step_action;
205+
206+
/**
207+
* \brief The post_stage_action function is called by the integrator on
208+
* the computed stage just after it is computed
209+
*/
210+
std::function<void (T&, amrex::Real)> post_fast_stage_action;
211+
212+
/**
213+
* \brief The post_step_action function is called by the integrator on
214+
* the computed state just after it is computed
215+
*/
216+
std::function<void (T&, amrex::Real)> post_fast_step_action;
217+
218+
/**
219+
* \brief Flag to enable/disable adaptive time stepping in single rate
220+
* methods or at the slow time scale in multirate methods (bool)
221+
*/
222+
bool use_adaptive_time_step = false;
223+
224+
/**
225+
* \brief Current integrator time step size (Real)
226+
*/
227+
amrex::Real time_step;
228+
229+
/**
230+
* \brief Step size of the last completed step (Real)
231+
*/
232+
amrex::Real previous_time_step;
233+
234+
/**
235+
* \brief Flag to enable/disable adaptive time stepping at the fast time
236+
* scale in multirate methods (bool)
237+
*/
238+
bool use_adaptive_fast_time_step = false;
239+
240+
/**
241+
* \brief Current integrator fast time scale time step size with multirate
242+
* methods (Real)
243+
*/
244+
amrex::Real fast_time_step;
245+
246+
/**
247+
* \brief Number of integrator time steps (Long)
248+
*/
249+
amrex::Long num_steps = 0;
250+
251+
/**
252+
* \brief Max number of internal steps before an error is returned (Long)
253+
*/
254+
int max_steps = 500;
255+
256+
/**
257+
* \brief Relative tolerance for adaptive time stepping (Real)
258+
*/
259+
amrex::Real rel_tol = 1.0e-4;
260+
261+
/**
262+
* \brief Absolute tolerance for adaptive time stepping (Real)
263+
*/
264+
amrex::Real abs_tol = 1.0e-9;
265+
266+
/**
267+
* \brief Relative tolerance for adaptive time stepping at the fast time
268+
* scale (Real)
269+
*/
270+
amrex::Real fast_rel_tol = 1.0e-4;
271+
272+
/**
273+
* \brief Absolute tolerance for adaptive time stepping at the fast time
274+
* scale (Real)
275+
*/
276+
amrex::Real fast_abs_tol = 1.0e-9;
277+
195278

196279
public:
197280
IntegratorBase () = default;
@@ -200,71 +283,112 @@ public:
200283

201284
virtual ~IntegratorBase () = default;
202285

203-
virtual void initialize (const T& S_data) = 0;
204-
205286
void set_rhs (std::function<void(T&, const T&, const amrex::Real)> F)
206287
{
207-
Fun = F;
288+
Rhs = F;
289+
}
290+
291+
void set_imex_rhs (std::function<void(T&, const T&, const amrex::Real)> Fi,
292+
std::function<void(T&, const T&, const amrex::Real)> Fe)
293+
{
294+
RhsIm = Fi;
295+
RhsEx = Fe;
296+
}
297+
298+
void set_fast_rhs (std::function<void(T&, const T&, const amrex::Real)> F)
299+
{
300+
RhsFast = F;
208301
}
209302

210-
void set_fast_rhs (std::function<void(T&, T&, const T&, const amrex::Real)> F)
303+
void set_pre_rhs_action (std::function<void (T&, amrex::Real)> A)
211304
{
212-
FastFun = F;
305+
pre_rhs_action = A;
213306
}
214307

215-
void set_slow_fast_timestep_ratio (const int timestep_ratio = 1)
308+
void set_post_stage_action (std::function<void (T&, amrex::Real)> A)
216309
{
217-
slow_fast_timestep_ratio = timestep_ratio;
310+
post_stage_action = A;
218311
}
219312

220-
void set_fast_timestep (const Real fast_dt = 1.0)
313+
void set_post_step_action (std::function<void (T&, amrex::Real)> A)
221314
{
222-
fast_timestep = fast_dt;
315+
post_step_action = A;
223316
}
224317

225-
void set_post_update (std::function<void (T&, amrex::Real)> F)
318+
void set_post_fast_stage_action (std::function<void (T&, amrex::Real)> A)
226319
{
227-
post_update = F;
320+
post_fast_stage_action = A;
228321
}
229322

230-
std::function<void (T&, amrex::Real)> get_post_update ()
323+
void set_post_fast_step_action (std::function<void (T&, amrex::Real)> A)
231324
{
232-
return post_update;
325+
post_fast_step_action = A;
233326
}
234327

235-
std::function<void(T&, const T&, const amrex::Real)> get_rhs ()
328+
void set_post_update (std::function<void (T&, amrex::Real)> A)
236329
{
237-
return Fun;
330+
set_post_stage_action(A);
331+
set_post_step_action(A);
238332
}
239333

240-
std::function<void(T&, T&, const T&, const amrex::Real)> get_fast_rhs ()
334+
amrex::Real get_time_step ()
241335
{
242-
return FastFun;
336+
return time_step;
243337
}
244338

245-
int get_slow_fast_timestep_ratio ()
339+
void set_time_step (amrex::Real dt)
246340
{
247-
return slow_fast_timestep_ratio;
341+
time_step = dt;
342+
use_adaptive_time_step = false;
248343
}
249344

250-
Real get_fast_timestep ()
345+
void set_adaptive_step ()
251346
{
252-
return fast_timestep;
347+
use_adaptive_time_step = true;
253348
}
254349

255-
void rhs (T& S_rhs, const T& S_data, const amrex::Real time)
350+
void set_fast_time_step (amrex::Real dt)
256351
{
257-
Fun(S_rhs, S_data, time);
352+
fast_time_step = dt;
353+
use_adaptive_fast_time_step = false;
258354
}
259355

260-
void fast_rhs (T& S_rhs, T& S_extra, const T& S_data, const amrex::Real time)
356+
void set_adaptive_fast_step ()
261357
{
262-
FastFun(S_rhs, S_extra, S_data, time);
358+
use_adaptive_fast_time_step = true;
263359
}
264360

265-
virtual amrex::Real advance (T& S_old, T& S_new, amrex::Real time, amrex::Real dt) = 0;
361+
void set_max_steps (int steps)
362+
{
363+
max_steps = steps;
364+
}
365+
366+
void set_tolerances (amrex::Real rtol, amrex::Real atol)
367+
{
368+
rel_tol = rtol;
369+
abs_tol = atol;
370+
}
371+
372+
void set_fast_tolerances (amrex::Real rtol, amrex::Real atol)
373+
{
374+
fast_rel_tol = rtol;
375+
fast_abs_tol = atol;
376+
}
377+
378+
/**
379+
* \brief Take a single time step from (time, S_old) to (time + dt, S_new)
380+
* with the given step size.
381+
*/
382+
virtual amrex::Real advance (T& S_old, T& S_new, amrex::Real time,
383+
amrex::Real dt) = 0;
384+
385+
/**
386+
* \brief Evolve the current (internal) integrator state to time_out
387+
*/
388+
virtual void evolve (T& S_out, const amrex::Real time_out) = 0;
266389

267-
virtual void time_interpolate (const T& S_new, const T& S_old, amrex::Real timestep_fraction, T& data) = 0;
390+
virtual void time_interpolate (const T& S_new, const T& S_old,
391+
amrex::Real timestep_fraction, T& data) = 0;
268392

269393
virtual void map_data (std::function<void(T&)> Map) = 0;
270394
};

0 commit comments

Comments
 (0)