module_time_integration.f90 Source File


Contents


Source Code

module time_integrator
  use field, only: field_type
  implicit none

  type, abstract :: time_integrator_type
     real :: starttime, endtime, dt
   contains
     procedure(integrate_proc), public, &
          & deferred :: integrate
  end type time_integrator_type

  type, extends(time_integrator_type) :: euler_integrator_type
     real :: alpha = 1.
   contains
     procedure :: integrate => integrate_euler
  end type euler_integrator_type

  type, extends(time_integrator_type) :: AB2_integrator_type
   contains
     procedure :: integrate => integrate_AB2
  end type AB2_integrator_type

  type, extends(time_integrator_type) :: RK3_integrator_type
   contains
     procedure :: integrate => integrate_RK3
  end type RK3_integrator_type

  abstract interface
     subroutine integrate_proc(self, afield)
       import time_integrator_type, field_type
       class(time_integrator_type), intent(in) :: self
       class(field_type), allocatable, intent(inout) :: afield
     end subroutine integrate_proc
  end interface

contains

  subroutine integrate_euler(self, afield)
    class(euler_integrator_type), intent(in) :: self
    class(field_type), allocatable, intent(inout) :: afield
    integer :: nt
    integer :: i

    nt = floor((self%endtime - self%starttime) / self%dt)
    do i = 1, nt
       afield = euler_timestep(afield, self%dt)
    end do
  end subroutine integrate_euler

  subroutine integrate_AB2(self, afield)
    class(AB2_integrator_type), intent(in) :: self
    class(field_type), allocatable, intent(inout) :: afield
    class(field_type), allocatable :: f1, f2
    integer :: nt
    integer :: i

    nt = floor((self%endtime - self%starttime) / self%dt)
    f1 = afield
    f2 = euler_timestep(afield, self%dt)
    do i = 2, nt
       call AB2_timestep(f1, f2, self%dt)
    end do
    afield = f2
  end subroutine integrate_AB2

  subroutine integrate_RK3(self, afield)
    class(RK3_integrator_type), intent(in) :: self
    class(field_type), allocatable, intent(inout) :: afield
    class(field_type), allocatable :: afield2
    integer :: nt, i

    nt = floor((self%endtime - self%starttime) / self%dt)
    do i = 1, nt
       ! First fractional step is Euler like
       afield2 = afield + afield%rhs() * (8. / 15.) * self%dt
       ! Second and third steps are AB2 like
       afield = afield2 + afield2%rhs() * (5. / 12.) * self%dt &
            & + afield%rhs() * (- 17. / 60.) * self%dt
       afield = afield + afield%rhs() * (3. / 4.) * self%dt &
            & + afield2%rhs() * (- 5. / 12.) * self%dt
    end do
  end subroutine integrate_RK3

  pure function euler_timestep(afield, dt) result(res)
    class(field_type), intent(in) :: afield
    real, intent(in) :: dt
    class(field_type), allocatable :: res
      res = afield + afield%rhs() *  dt
  end function euler_timestep

  subroutine AB2_timestep(f1, f2, dt)
    class(field_type), allocatable, intent(inout) :: f1, f2
    real, intent(in) :: dt

    f2 = f2 + f2%rhs() * 1.5 * dt + (-1. * f1%rhs() * 0.5 * dt)
    f1 = f2
  end subroutine AB2_timestep

end module time_integrator