Afivo  0.3
m_af_advance.f90
1 #include "cpp_macros.h"
2 
4  use m_af_types
5 
6  implicit none
7  private
8 
9  integer, parameter, public :: af_num_integrators = 8
11  integer, parameter, public :: af_forward_euler = 1
14  integer, parameter, public :: af_heuns_method = 2
16  integer, parameter, public :: af_midpoint_method = 3
19  integer, parameter, public :: af_ssprk33_method = 4
22  integer, parameter, public :: af_ssprk43_method = 5
24  integer, parameter, public :: af_imex_euler = 6
26  integer, parameter, public :: af_imex_trapezoidal = 7
29  integer, parameter, public :: af_rk4_method = 8
30 
31  character(len=af_nlen), public :: af_integrator_names(af_num_integrators) = &
32  [character(len=af_nlen) :: "forward_euler", "heuns_method", &
33  "midpoint_method", "ssprk33", "ssprk43", "imex_euler", &
34  "imex_trapezoidal", "rk4"]
35 
37  integer, parameter, public :: &
38  af_advance_num_steps(af_num_integrators) = [1, 2, 2, 3, 4, 1, 2, 4]
39 
41  integer, parameter :: req_copies(af_num_integrators) = af_advance_num_steps
42 
44  logical, parameter :: req_implicit(af_num_integrators) = &
45  [.false., .false., .false., .false., .false., .true., .true., .false.]
46 
47  interface
48 
70  subroutine subr_feuler(tree, dt, dt_stiff, dt_lim, time, s_deriv, n_prev, &
71  s_prev, w_prev, s_out, i_step, n_steps)
72  import
73  type(af_t), intent(inout) :: tree
74  real(dp), intent(in) :: dt
75  real(dp), intent(in) :: dt_stiff
76  real(dp), intent(inout) :: dt_lim
77  real(dp), intent(in) :: time
78  integer, intent(in) :: s_deriv
79  integer, intent(in) :: n_prev
80  integer, intent(in) :: s_prev(n_prev)
81  real(dp), intent(in) :: w_prev(n_prev)
82  integer, intent(in) :: s_out
83  integer, intent(in) :: i_step
84  integer, intent(in) :: n_steps
85  end subroutine subr_feuler
86 
94  subroutine subr_implicit(tree, dt_stiff, time, n_prev, s_prev, w_prev, s_out)
95  import
96  type(af_t), intent(inout) :: tree
97  real(dp), intent(in) :: dt_stiff
98  real(dp), intent(in) :: time
99  integer, intent(in) :: n_prev
100  integer, intent(in) :: s_prev(n_prev)
101  real(dp), intent(in) :: w_prev(n_prev)
102  integer, intent(in) :: s_out
103  end subroutine subr_implicit
104  end interface
105 
106  public :: af_advance
107 
108 contains
109 
118  subroutine af_advance(tree, dt, dt_lim, time, i_cc, time_integrator, &
119  forward_euler, implicit_solver)
120  type(af_t), intent(inout) :: tree
121  real(dp), intent(in) :: dt
122  real(dp), intent(out) :: dt_lim
123  real(dp), intent(inout) :: time
124  integer, intent(in) :: i_cc(:)
126  integer, intent(in) :: time_integrator
128  procedure(subr_feuler) :: forward_euler
130  procedure(subr_implicit), optional :: implicit_solver
131  integer :: n_steps
132 
133  real(dp), parameter :: third = 1/3.0_dp
134  real(dp), parameter :: sixth = 1/6.0_dp
135 
136  if (time_integrator < 1 .or. time_integrator > af_num_integrators) &
137  error stop "Invalid time integrator"
138 
139  if (any(tree%cc_num_copies(i_cc) < req_copies(time_integrator))) &
140  error stop "Not enough copies available"
141 
142  if (req_implicit(time_integrator) .and. .not. present(implicit_solver)) &
143  error stop "implicit_solver required"
144 
145  n_steps = af_advance_num_steps(time_integrator)
146  dt_lim = 1e100_dp
147 
148  select case (time_integrator)
149  case (af_forward_euler)
150  call forward_euler(tree, dt, dt, dt_lim, time, 0, &
151  1, [0], [1.0_dp], 0, 1, n_steps)
152  case (af_midpoint_method)
153  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time, 0, &
154  1, [0], [1.0_dp], 1, 1, n_steps)
155  call forward_euler(tree, dt, dt, dt_lim, time+0.5_dp*dt, 1, &
156  1, [0], [1.0_dp], 0, 2, n_steps)
157  case (af_heuns_method)
158  call forward_euler(tree, dt, dt, dt_lim, time, 0, &
159  1, [0], [1.0_dp], 1, 1, n_steps)
160  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time+dt, 1, &
161  2, [0, 1], [0.5_dp, 0.5_dp], 0, 2, n_steps)
162  case (af_ssprk33_method)
163  call forward_euler(tree, dt, dt, dt_lim, time, 0, &
164  1, [0], [1.0_dp], 1, 1, n_steps)
165  call forward_euler(tree, 0.25_dp*dt, 0.25_dp*dt, dt_lim, time+dt, 1, &
166  2, [0, 1], [0.75_dp, 0.25_dp], 2, 2, n_steps)
167  call forward_euler(tree, 2*third*dt, 2*third*dt, dt_lim, time+0.5_dp*dt, 2, &
168  2, [0, 2], [third, 2*third], 0, 3, n_steps)
169  case (af_ssprk43_method)
170  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time, 0, &
171  1, [0], [1.0_dp], 1, 1, n_steps)
172  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time+0.5_dp*dt, 1, &
173  1, [1], [1.0_dp], 2, 2, n_steps)
174  call forward_euler(tree, sixth*dt, sixth*dt, dt_lim, time+dt, 2, &
175  2, [0, 2], [2*third, third], 3, 3, n_steps)
176  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time+0.5_dp*dt, 3, &
177  1, [3], [1.0_dp], 0, 4, n_steps)
178  case (af_imex_euler)
179  call forward_euler(tree, dt, 0*dt, dt_lim, time, 0, &
180  1, [0], [1.0_dp], 0, 1, n_steps)
181  call implicit_solver(tree, dt, time, 1, [0], [1.0_dp], 0)
182  case (af_imex_trapezoidal)
183  ! Compute y* = y_n + dt*F0(y_n) + 0.5*dt * (F1(y_n) + F1(y*))
184  call forward_euler(tree, dt, 0.5_dp*dt, dt_lim, time, 0, &
185  1, [0], [1.0_dp], 1, 1, n_steps)
186  call implicit_solver(tree, 0.5_dp*dt, time, 1, [1], [1.0_dp], 1)
187 
188  ! Compute y_n+1 = y_n + 0.5*dt * (F(y_n) + F(y*))
189  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time, 0, &
190  1, [0], [1.0_dp], 0, 1, n_steps)
191  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time, 1, &
192  1, [0], [1.0_dp], 0, 2, n_steps)
193  case (af_rk4_method)
194  ! This looks different than the standard formulation in most textbooks.
195  ! The idea is to construct the states needed for the derivatives, and
196  ! then take a linear combination. Note the negative coefficient used in
197  ! the last step.
198  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time, 0, &
199  1, [0], [1.0_dp], 1, 1, n_steps)
200  call forward_euler(tree, 0.5_dp*dt, 0.5_dp*dt, dt_lim, time+0.5_dp*dt, 1, &
201  1, [0], [1.0_dp], 2, 2, n_steps)
202  call forward_euler(tree, dt, dt, dt_lim, time+0.5_dp*dt, 2, &
203  1, [0], [1.0_dp], 3, 3, n_steps)
204  call forward_euler(tree, sixth*dt, sixth*dt, dt_lim, time+dt, 3, &
205  4, [0, 1, 2, 3], [-third, third, 2*third, third], 0, 4, n_steps)
206  case default
207  error stop "Unknown time integrator"
208  end select
209 
210  time = time + dt
211  end subroutine af_advance
212 
213 end module m_af_advance
Interface for a generic forward Euler scheme for time integration.
Interface for a implicit solver for integrating stiff terms over time.
Module with methods to perform time integration.
Definition: m_af_advance.f90:3
This module contains the basic types and constants that are used in the NDIM-dimensional version of A...
Definition: m_af_types.f90:4
Type which stores all the boxes and levels, as well as some information about the number of boxes,...
Definition: m_af_types.f90:326