ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_MRI.H
Go to the documentation of this file.
1 #ifndef ERF_MRI_H
2 #define ERF_MRI_H
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_Vector.H>
6 #include <AMReX_ParmParse.H>
7 #include <AMReX_IntegratorBase.H>
8 
9 #include <ERF_TI_slow_headers.H>
10 #include <ERF_TI_fast_headers.H>
11 
12 #include <functional>
13 
14 template<class T>
16 {
17 private:
18  /**
19  * \brief rhs is the right-hand-side function the integrator will use.
20  */
21  std::function<void(T&, const T&, const amrex::Real, const amrex::Real )> rhs;
22  std::function<void(T&, T&, T&, const amrex::Real, const amrex::Real, const amrex::Real, const int)> slow_rhs_pre;
23  std::function<void(T&, T&, T&, T&, const amrex::Real, const amrex::Real, const amrex::Real, const int )> slow_rhs_post;
24  std::function<void(int, int, int, T&, const T&, T&, T&, const amrex::Real, const amrex::Real,
25  const amrex::Real, const amrex::Real,
27 
28  /**
29  * \brief Integrator timestep size (Real)
30  */
32 
33  /**
34  * \brief The ratio of slow timestep size / fast timestep size (int)
35  */
37 
38  /**
39  * \brief Should we not do acoustic substepping
40  */
42 
43  /**
44  * \brief Should we use the anelastic integrator
45  */
46  int anelastic;
47 
48  /**
49  * \brief How many components in the cell-centered MultiFab
50  */
52 
53  /**
54  * \brief Do we follow the recommendation to only perform a single substep in the first RK stage
55  */
57 
58  /**
59  * \brief The no_substep function is called when we have no acoustic substepping
60  */
61  std::function<void (T&, T&, T&, amrex::Real, amrex::Real, int)> no_substep;
62 
63 
64  amrex::Vector<std::unique_ptr<T> > T_store;
65  T* S_sum;
67 
68  void initialize_data (const T& S_data)
69  {
70  // TODO: We can optimize memory by making the cell-centered part of S_sum
71  // have only 2 components, not ncomp_cons components
72  const bool include_ghost = true;
73  amrex::IntegratorOps<T>::CreateLike(T_store, S_data, include_ghost);
74  S_sum = T_store[0].get();
75  amrex::IntegratorOps<T>::CreateLike(T_store, S_data, include_ghost);
76  F_slow = T_store[1].get();
77  // initializing to zero
78  for (long idx = 0; idx < S_sum->size(); idx++) { (*S_sum)[idx].setVal(0.0); }
79  for (long idx = 0; idx < F_slow->size(); idx++) { (*F_slow)[idx].setVal(0.0); }
80  }
81 
82 public:
83  MRISplitIntegrator () = default;
84 
85  MRISplitIntegrator (const T& S_data)
86  {
87  initialize_data(S_data);
88  }
89 
90  void initialize (const T& S_data)
91  {
92  initialize_data(S_data);
93  }
94 
95  ~MRISplitIntegrator () = default;
96 
97  // Declare a default move constructor so we ensure the destructor is
98  // not called when we return an object of this class by value
99  MRISplitIntegrator(MRISplitIntegrator&&) noexcept = default;
100 
101  // Declare a default move assignment operator
102  MRISplitIntegrator& operator=(MRISplitIntegrator&& other) noexcept = default;
103 
104  // Delete the copy constructor and copy assignment operators because
105  // the integrator allocates internal memory that is best initialized
106  // from scratch when needed instead of making a copy.
107 
108  // Delete the copy constructor
109  MRISplitIntegrator(const MRISplitIntegrator& other) = delete;
110  //
111  // Delete the copy assignment operator
112  MRISplitIntegrator& operator=(const MRISplitIntegrator& other) = delete;
113 
114  void setNcompCons(int _ncomp_cons)
115  {
116  ncomp_cons = _ncomp_cons;
117  }
118 
119  void setAnelastic(int _anelastic)
120  {
121  anelastic = _anelastic;
122  }
123 
124  void setNoSubstepping(int _no_substepping)
125  {
126  no_substepping = _no_substepping;
127  }
128 
129  void setForceFirstStageSingleSubstep(int _force_stage1_single_substep)
130  {
131  force_stage1_single_substep = _force_stage1_single_substep;
132  }
133 
134  void set_slow_rhs_pre (std::function<void(T&, T&, T&, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
135  {
136  slow_rhs_pre = F;
137  }
138  void set_slow_rhs_post (std::function<void(T&, T&, T&, T&, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
139  {
140  slow_rhs_post = F;
141  }
142 
143  void set_acoustic_substepping (std::function<void(int, int, int, T&, const T&, T&, T&,
144  const amrex::Real, const amrex::Real,
145  const amrex::Real, const amrex::Real,
146  const amrex::Real)> F)
147  {
149  }
150 
151  void set_slow_fast_timestep_ratio (const int timestep_ratio = 1)
152  {
153  slow_fast_timestep_ratio = timestep_ratio;
154  }
155 
157  {
159  }
160 
161  void set_no_substep (std::function<void (T&, T&, T&, amrex::Real, amrex::Real, int)> F)
162  {
163  no_substep = F;
164  }
165 
166  std::function<void(T&, const T&, const amrex::Real, int)> get_rhs ()
167  {
168  return rhs;
169  }
170 
171  amrex::Real advance (T& S_old, T& S_new, amrex::Real time, const amrex::Real time_step)
172  {
173  BL_PROFILE_REGION("MRI_advance");
174  using namespace amrex;
175 
176  // *******************************************************************************
177  // !no_substepping: we only update the fast variables every fast timestep, then update
178  // the slow variables after the acoustic sub-stepping. This has
179  // two calls to slow_rhs so that we can update the slow variables
180  // with the velocity field after the acoustic substepping using
181  // the time-averaged velocity from the substepping
182  // no_substepping: we don't do any acoustic subcyling so we only make one call per RK
183  // stage to slow_rhs
184  // *******************************************************************************
185  timestep = time_step;
186 
187  const int substep_ratio = get_slow_fast_timestep_ratio();
188 
189  if (!no_substepping) {
190  AMREX_ALWAYS_ASSERT(substep_ratio > 1 && substep_ratio % 2 == 0);
191  }
192 
193  // Assume before advance() that S_old is valid data at the current time ("time" argument)
194  // And that if data is a MultiFab, both S_old and S_new contain ghost cells for evaluating a stencil based RHS
195  // We need this from S_old. This is convenient for S_new to have so we can use it
196  // as scratch space for stage values without creating a new scratch MultiFab with ghost cells.
197 
198  // NOTE: In the following, we use S_new to hold S*, S**, and finally, S^(n+1) at the new time
199  // DEFINITIONS:
200  // S_old = S^n
201  // S_sum = S(t)
202  // F_slow = F(S_stage)
203 
204  int n_data = IntVars::NumTypes;
205 
206  /**********************************************/
207  /* RK3 Integration with Acoustic Sub-stepping */
208  /**********************************************/
209  Vector<int> num_vars = {ncomp_cons, 1, 1, 1};
210  for (int i(0); i<n_data; ++i)
211  {
212  // Copy old -> new
213  MultiFab::Copy(S_new[i],S_old[i],0,0,num_vars[i],S_old[i].nGrowVect());
214  }
215 
216  // Timestep taken by the fast integrator
217  amrex::Real dtau;
218 
219  // How many timesteps taken by the fast integrator
220  int nsubsteps;
221 
222  // This is the final time of the full timestep (also the 3rd RK stage)
223  // Real new_time = time + timestep;
224 
225  amrex::Real time_stage = time;
226  amrex::Real old_time_stage;
227 
228  const amrex::Real sub_timestep = timestep / substep_ratio;
229 
230  if (!anelastic) {
231  // RK3 for compressible integrator
232  for (int nrk = 0; nrk < 3; nrk++)
233  {
234  // Capture the time we got to in the previous RK step
235  old_time_stage = time_stage;
236 
237  if (nrk == 0) {
239  nsubsteps = 1; dtau = timestep / 3.0;
240  } else {
241  nsubsteps = substep_ratio/3; dtau = sub_timestep ;
242  }
243  time_stage = time + timestep / 3.0;
244  }
245  if (nrk == 1) {
246  if (no_substepping) {
247  nsubsteps = 1; dtau = 0.5 * timestep;
248  } else {
249  nsubsteps = substep_ratio/2; dtau = sub_timestep;
250  }
251  time_stage = time + timestep / 2.0;
252  }
253  if (nrk == 2) {
254  if (no_substepping) {
255  nsubsteps = 1; dtau = timestep;
256  } else {
257  nsubsteps = substep_ratio; dtau = sub_timestep;
258 
259  // STRT HACK -- this hack can be used to approximate the no-substepping algorithm
260  // nsubsteps = 1; dtau = timestep;
261  // END HACK
262  }
263  time_stage = time + timestep;
264  }
265 
266  // step 1 starts with S_stage = S^n and we always start substepping at the old time
267  // step 2 starts with S_stage = S^* and we always start substepping at the old time
268  // step 3 starts with S_stage = S^** and we always start substepping at the old time
269 
270  slow_rhs_pre(*F_slow, S_old, S_new, time, old_time_stage, time_stage, nrk);
271 
272  amrex::Real inv_fac = 1.0 / static_cast<amrex::Real>(nsubsteps);
273 
274  // ****************************************************
275  // Acoustic substepping
276  // ****************************************************
277  if (!no_substepping)
278  {
279  // *******************************************************************************
280  // Update the fast variables
281  // *******************************************************************************
282  for (int ks = 0; ks < nsubsteps; ++ks)
283  {
284  acoustic_substepping(ks, nsubsteps, nrk, *F_slow, S_old, S_new, *S_sum, dtau, timestep, inv_fac,
285  time + ks*dtau, time + (ks+1) * dtau);
286 
287  } // ks
288 
289  } else {
290  no_substep(*S_sum, S_old, *F_slow, time + nsubsteps*dtau, nsubsteps*dtau, nrk);
291  }
292 
293  // ****************************************************
294  // Evaluate F_slow(S_stage) only for the slow variables
295  // Note that we are using the current stage versions (in S_new) of the slow variables
296  // (because we didn't update the slow variables in the substepping)
297  // but we are using the "new" versions (in S_sum) of the velocities
298  // (because we did update the fast variables in the substepping)
299  // ****************************************************
300  slow_rhs_post(*F_slow, S_old, S_new, *S_sum, time, old_time_stage, time_stage, nrk);
301  } // nrk
302 
303  } else {
304  // RK2 for anelastic integrator
305  for (int nrk = 0; nrk < 2; nrk++)
306  {
307  // Capture the time we got to in the previous RK step
308  old_time_stage = time_stage;
309 
310  if (nrk == 0) { nsubsteps = 1; dtau = timestep; time_stage = time + timestep; }
311  if (nrk == 1) { nsubsteps = 1; dtau = timestep; time_stage = time + timestep; }
312 
313  slow_rhs_pre(*F_slow, S_old, S_new, time, old_time_stage, time_stage, nrk);
314 
315  no_substep(*S_sum, S_old, *F_slow, time + nsubsteps*dtau, nsubsteps*dtau, nrk);
316 
317  // ****************************************************
318  // Evaluate F_slow(S_stage) only for the slow variables
319  // Note that we are using the current stage versions (in S_new) of the slow variables
320  // (because we didn't update the slow variables in the substepping)
321  // but we are using the "new" versions (in S_sum) of the velocities
322  // (because we did update the fast variables in the substepping)
323  // ****************************************************
324  slow_rhs_post(*F_slow, S_old, S_new, *S_sum, time, old_time_stage, time_stage, nrk);
325  } // nrk
326  }
327 
328  // Return timestep
329  return timestep;
330  }
331 
332  void map_data (std::function<void(T&)> Map)
333  {
334  for (auto& F : T_store) {
335  Map(*F);
336  }
337  }
338 };
339 
340 #endif
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_MRI.H:16
T * F_slow
Definition: ERF_MRI.H:66
void set_acoustic_substepping(std::function< void(int, int, int, T &, const T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real)> F)
Definition: ERF_MRI.H:143
std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> slow_rhs_post
Definition: ERF_MRI.H:23
amrex::Vector< std::unique_ptr< T > > T_store
Definition: ERF_MRI.H:64
void map_data(std::function< void(T &)> Map)
Definition: ERF_MRI.H:332
void set_no_substep(std::function< void(T &, T &, T &, amrex::Real, amrex::Real, int)> F)
Definition: ERF_MRI.H:161
int anelastic
Should we use the anelastic integrator.
Definition: ERF_MRI.H:46
void setNcompCons(int _ncomp_cons)
Definition: ERF_MRI.H:114
std::function< void(T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> slow_rhs_pre
Definition: ERF_MRI.H:22
amrex::Real timestep
Integrator timestep size (Real)
Definition: ERF_MRI.H:31
MRISplitIntegrator()=default
void setForceFirstStageSingleSubstep(int _force_stage1_single_substep)
Definition: ERF_MRI.H:129
int force_stage1_single_substep
Do we follow the recommendation to only perform a single substep in the first RK stage.
Definition: ERF_MRI.H:56
int ncomp_cons
How many components in the cell-centered MultiFab.
Definition: ERF_MRI.H:51
void setNoSubstepping(int _no_substepping)
Definition: ERF_MRI.H:124
std::function< void(int, int, int, T &, const T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real)> acoustic_substepping
Definition: ERF_MRI.H:26
void initialize(const T &S_data)
Definition: ERF_MRI.H:90
MRISplitIntegrator(MRISplitIntegrator &&) noexcept=default
void initialize_data(const T &S_data)
Definition: ERF_MRI.H:68
MRISplitIntegrator(const T &S_data)
Definition: ERF_MRI.H:85
std::function< void(T &, const T &, const amrex::Real, int)> get_rhs()
Definition: ERF_MRI.H:166
std::function< void(T &, const T &, const amrex::Real, const amrex::Real)> rhs
rhs is the right-hand-side function the integrator will use.
Definition: ERF_MRI.H:21
void setAnelastic(int _anelastic)
Definition: ERF_MRI.H:119
int get_slow_fast_timestep_ratio()
Definition: ERF_MRI.H:156
std::function< void(T &, T &, T &, amrex::Real, amrex::Real, int)> no_substep
The no_substep function is called when we have no acoustic substepping.
Definition: ERF_MRI.H:61
void set_slow_rhs_post(std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:138
int slow_fast_timestep_ratio
The ratio of slow timestep size / fast timestep size (int)
Definition: ERF_MRI.H:36
void set_slow_rhs_pre(std::function< void(T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:134
~MRISplitIntegrator()=default
void set_slow_fast_timestep_ratio(const int timestep_ratio=1)
Definition: ERF_MRI.H:151
T * S_sum
Definition: ERF_MRI.H:65
amrex::Real advance(T &S_old, T &S_new, amrex::Real time, const amrex::Real time_step)
Definition: ERF_MRI.H:171
int no_substepping
Should we not do acoustic substepping.
Definition: ERF_MRI.H:41
@ NumTypes
Definition: ERF_IndexDefines.H:162
@ T
Definition: ERF_IndexDefines.H:110
Definition: ERF_ConsoleIO.cpp:12