atl_rk4_module.f90 Source File


This file depends on

sourcefile~~atl_rk4_module.f90~~EfferentGraph sourcefile~atl_rk4_module.f90 atl_rk4_module.f90 sourcefile~atl_scheme_module.f90 atl_scheme_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_scheme_module.f90 sourcefile~atl_kerneldata_module.f90 atl_kerneldata_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_kerneldata_module.f90 sourcefile~atl_elemental_time_integration_module.f90 atl_elemental_time_integration_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_elemental_time_integration_module.f90 sourcefile~atl_penalization_module.f90 atl_penalization_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_penalization_module.f90 sourcefile~atl_cube_container_module.f90 atl_cube_container_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_cube_container_module.f90 sourcefile~atl_cube_elem_module.f90 atl_cube_elem_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_cube_elem_module.f90 sourcefile~atl_bc_header_module.f90 atl_bc_header_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_bc_header_module.f90 sourcefile~atl_boundary_module.f90 atl_boundary_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_boundary_module.f90 sourcefile~atl_materialprp_module.f90 atl_materialPrp_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_materialprp_module.f90 sourcefile~atl_time_integration_module.f90 atl_time_integration_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_time_integration_module.f90 sourcefile~ply_poly_project_module.f90 ply_poly_project_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~ply_poly_project_module.f90 sourcefile~atl_stabilize_module.f90 atl_stabilize_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_stabilize_module.f90 sourcefile~atl_facedata_module.f90 atl_facedata_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_facedata_module.f90 sourcefile~atl_writeprecice_module.f90 atl_writePrecice_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_writeprecice_module.f90 sourcefile~atl_equation_module.f90 atl_equation_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_equation_module.f90 sourcefile~atl_source_types_module.f90 atl_source_types_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_source_types_module.f90 sourcefile~atl_compute_module.f90 atl_compute_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_compute_module.f90

Files dependent on this one

sourcefile~~atl_rk4_module.f90~~AfferentGraph sourcefile~atl_rk4_module.f90 atl_rk4_module.f90 sourcefile~atl_global_time_integration_module.f90 atl_global_time_integration_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_rk4_module.f90 sourcefile~atl_program_module.f90 atl_program_module.f90 sourcefile~atl_program_module.f90->sourcefile~atl_global_time_integration_module.f90 sourcefile~atl_container_module.f90 atl_container_module.f90 sourcefile~atl_program_module.f90->sourcefile~atl_container_module.f90 sourcefile~atl_initialize_module.f90 atl_initialize_module.f90 sourcefile~atl_program_module.f90->sourcefile~atl_initialize_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_global_time_integration_module.f90 sourcefile~atl_initialize_module.f90->sourcefile~atl_container_module.f90 sourcefile~atl_harvesting.f90 atl_harvesting.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_program_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_container_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_initialize_module.f90 sourcefile~ateles.f90 ateles.f90 sourcefile~ateles.f90->sourcefile~atl_program_module.f90 sourcefile~ateles.f90->sourcefile~atl_container_module.f90

Contents

Source Code


Source Code

! Copyright (c) 2012-2014 Jens Zudrop <j.zudrop@grs-sim.de>
! Copyright (c) 2012-2014, 2016, 2018 Harald Klimach <harald.klimach@uni-siegen.de>
! Copyright (c) 2013 Melven Zoellner <yameta@freenet.de>
! Copyright (c) 2013-2016 Verena Krupp <verena.krupp@uni-siegen.de>
! Copyright (c) 2013-2019 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2014-2015 Nikhil Anand <nikhil.anand@uni-siegen.de>
! Copyright (c) 2016 Parid Ndreka
! Copyright (c) 2016 Kannan Masilamani <kannan.masilamani@uni-siegen.de>
! Copyright (c) 2016 Tobias Girresser <tobias.girresser@student.uni-siegen.de>
! Copyright (c) 2016-2017 Jiaxing Qi <jiaxing.qi@uni-siegen.de>
! Copyright (c) 2017 Daniel PetrĂ³ <daniel.petro@student.uni-siegen.de>
! Copyright (c) 2018 Neda Ebrahimi Pour <neda.epour@uni-siegen.de>
!
! Permission to use, copy, modify, and distribute this software for any
! purpose with or without fee is hereby granted, provided that the above
! copyright notice and this permission notice appear in all copies.
!
! THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
! WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
! ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! **************************************************************************** !

!> author: Jens Zudrop
!! Routines,functions, datatypes related to Runge Kutta 4 (i.e. classical Runge
!! Kutta) timestepping method.
module atl_rk4_module
  use env_module,                            only: rk
  use tem_aux_module,                        only: tem_abort
  use tem_element_module,                    only: eT_fluid
  use tem_general_module,                    only: tem_general_type
  use tem_logging_module,                    only: logUnit
  use treelmesh_module,                      only: treelmesh_type
  use tem_precice_module,                    only: precice_available

  use atl_elemental_time_integration_module, only: atl_timestep_type
  use atl_cube_elem_module,                  only: atl_cube_elem_type
  use atl_kerneldata_module,                 only: atl_kerneldata_type, &
    &                                              atl_statedata_type
  use atl_scheme_module,                     only: atl_scheme_type,         &
    &                                              atl_local_timestep_type
  use atl_source_types_module,               only: atl_source_type
  use atl_compute_module,                    only: atl_compute_rhs,    &
    &                                              atl_preprocess_rhs, &
    &                                              atl_postprocess_rhs
  use atl_boundary_module,                   only: atl_level_boundary_type
  use atl_facedata_module,                   only: atl_facedata_type
  use atl_time_integration_module,           only: atl_global_timestep_type
  use atl_equation_module,                   only: atl_equations_type
  use atl_bc_header_module,                  only: atl_boundary_type
  use atl_stabilize_module,                  only: atl_stabilize
  use ply_poly_project_module,               only: ply_poly_project_type, &
    &                                              assignment(=)
  use atl_materialPrp_module,                only: atl_material_type
  use atl_writePrecice_module,               only: atl_write_precice
  use atl_cube_container_module,             only: atl_cube_container_type
  use atl_penalization_module,               only: atl_penalizationData_type
!!VK  use atl_timer_module,                      only: atl_timerHandles

  implicit none
  private

  public :: atl_init_explicitRungeKutta

contains

  !> Routine to initialize explicit runge kutta scheme for timestepping.
  subroutine atl_init_explicitRungeKutta( me, minLevel, maxLevel, steps, &
    &                                     statedata_list                 )
    ! --------------------------------------------------------------------------
    !> The datatype to initialize.
    type(atl_global_timestep_type), intent(inout) :: me

    !> The minimum of level of the mesh.
    integer, intent(in) :: minLevel

    !> The maximum of level of the mesh.
    integer, intent(in) :: maxLevel

    !> The number of steps in the runge kutta procedure
    integer, intent(in) :: steps

    !> The state list used in your solver, for each level one entry.
    type(atl_statedata_type), intent(in) :: statedata_list(minLevel:maxLevel)
    ! --------------------------------------------------------------------------
    integer :: iLevel, iStep
    ! --------------------------------------------------------------------------
    ! point to euler step function, we dont have to allocate any of the
    ! additional arrays for coefficients or buffering.
    allocate( me%elementSteps(minLevel:maxLevel) )
    select case(steps)
    case(4) ! we have runge kutta with 4 steps, and fourth order
      do iLevel = minLevel, maxLevel
        if(allocated(statedata_list(iLevel)%state)) then
          ! We store one integer, indicating the elemental operation in which
          ! step we are.
          allocate(me%elementSteps(iLevel)%timestepInfoInteger(1))
          ! In a 4 step runge kutta method we have to store 4 intermediate
          ! results.
          allocate(me%elementSteps(iLevel)%timestepData(4))
          do iStep = 1, 4
            allocate(me%elementSteps(iLevel)                          &
              &        %timestepData(iStep)                           &
              &         %state(size(statedata_list(iLevel)%state, 1), &
              &                size(statedata_list(iLevel)%state, 2), &
              &                size(statedata_list(iLevel)%state, 3)) )
          end do
          me%elementSteps(iLevel)%elemStep     => elemental_timestep_rk4
          me%elementSteps(iLevel)%elemStep_vec => elemental_timestep_vec_rk4
          me%elementSteps(iLevel)%updateStep   => update_timestep_rk4
        end if
      end do
      me%meshStep => mesh_timestep_rk4

    case default
      write(logUnit(1),*) 'init runge kutta method for this number of steps' &
        & //' not implemented, stopping...'
      call tem_abort()
    end select
  end subroutine atl_init_explicitRungeKutta



  !> Levelwise updating of runge kutta of order 4
  subroutine update_timestep_rk4( me, timestepInfo )
    ! --------------------------------------------------------------------------
    !> The type of your timestepping.
    class(atl_timestep_type), intent(inout) :: me

    !> Local timestepping information for that part of the mesh
    type(atl_local_timestep_type), intent(in) :: timestepInfo
    ! --------------------------------------------------------------------------
    ! nothing to be done here.
  end subroutine update_timestep_rk4



  !> Elemental operation for timestepping of order 4.
  subroutine elemental_timestep_rk4( me, state, cell, dof, sideFlux)
    ! --------------------------------------------------------------------------
    !> Description of the timestep integration method.
    class(atl_timestep_type), intent(inout) :: me

    !> The state of all cells on this level. This field will be updated
    !! ad the cell position. See kerneldata type for more explanations.
    real(kind=rk), intent(inout) :: state(:,:,:)

    !> Position of the cell to update in the state vector.
    integer,intent(in) :: cell

    !> The degree of freedom to update
    integer, intent(in) :: dof

    !> The flux for one of the sides of this cell. The length of this array
    !! is the number of conservative variables of your equation.
    real(kind=rk), intent(in) :: sideFlux(:)
    ! --------------------------------------------------------------------------
    me%timestepData(me%timestepInfoInteger(1))%state(cell,dof,:)       &
      & = me%timestepData(me%timestepInfoInteger(1))%state(cell,dof,:) &
      &   + sideFlux(:)
  end subroutine elemental_timestep_rk4


  !> Elemental operation for timestepping of order 4.
  subroutine elemental_timestep_vec_rk4( me, state, kerneldata )
    ! --------------------------------------------------------------------------
    !> Description of the timestep integration method.
    class(atl_timestep_type), intent(inout) :: me

    !> The state of all cells on this level. This field will be updated
    !! ad the cell position. See kerneldata type for more explanations.
    real(kind=rk), intent(inout) :: state(:,:,:)

    !> Complete kerneldata to get the flux from with additional information.
    type(atl_kerneldata_type), intent(in) :: kerneldata
    ! --------------------------------------------------------------------------

    call compute(kerneldata%nTotal,                                &
      &          kerneldata%nDofs,                                 &
      &          kerneldata%nVars,                                 &
      &          me%timestepData(me%timestepInfoInteger(1))%state, &
      &          kerneldata%state_der                              )

  contains

    ! put it in an own subroutine to allow vectorization with gcc
    subroutine compute( nTotal, nDofs, nScalars, state, state_der )
      ! ------------------------------------------------------------------------
      integer, intent(in) :: nTotal, nDofs, nScalars
      real(kind=rk), intent(inout) :: state(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state_der(:,:,:)
      ! ------------------------------------------------------------------------

      state(:nTotal,:,:) = state(:nTotal,:,:) + state_der(:nTotal,:nDofs,:)

    end subroutine compute

  end subroutine elemental_timestep_vec_rk4


  !> Subroutine for timestepping with explicit runge kutta of order 4.
  !! It contains four Euler forwarding substeps:
  !! 0.1   temp = u0
  !! 1.1   u1   = rk4_substep(temp) = rhs(temp)
  !! 1.2   temp = u0 + dt/2 * u1
  !! 2.1   u2   = rk4_substep(temp) = rhs(temp)
  !! 2.2   temp = u0 + dt/2 * u2
  !! 3.1   u3   = rk4_substep(temp) = rhs(temp)
  !! 3.2   temp = u0 + dt   * u3
  !! 4.1   u4   = rk4_substep(temp) = rhs(temp)
  !! 4.2   u0   = u0 + dt/6 * ( u1 + 2*(u2+u3) + u4 )
  !! After each substep, the results are stabilized
  subroutine mesh_timestep_rk4( minLevel, maxLevel, currentLevel, cubes, tree, &
    &                           timestep_list, nSteps, equation, general,      &
    &                           commStateTimer, poly_proj_list                 )
    ! --------------------------------------------------------------------------
    !> The minimum refinement level of the mesh.
    integer, intent(in) :: minLevel

    !> The maximum refinement level of the mesh.
    integer, intent(in) :: maxLevel

    !> The level the timestep has to be performed for.
    integer, intent(in) :: currentLevel

    !> Container for the cubical elements.
    type(atl_cube_container_type), intent(inout) :: cubes

    !> treelm mesh
    type(treelmesh_type), intent(in) :: tree

    !> List of levelwise timestepping algorihtms
    type(atl_timestep_type), intent(inout) :: timestep_list(minLevel:)

    !> The number of steps of the time stepping scheme (assumed to be 4)
    integer, intent(in) :: nSteps

    !> The equation you are operating with.
    type(atl_equations_type),intent(inout) :: equation

    !> General treelm settings
    type(tem_general_type), intent(inout) :: general

    !> Timer for measuring the communication time inside this routine.
    integer,intent(inout) :: commStateTimer

    !> unique list for projection methods
    type(ply_poly_project_type), intent(inout) :: poly_proj_list(:)
    ! --------------------------------------------------------------------------
    integer :: iLevel, iStep
    type(atl_statedata_type) :: statedata_list_temp(minLevel:maxLevel)
    ! --------------------------------------------------------------------------

    ! Init the arrays with the intermediate results
    do iLevel = minLevel, maxLevel
      ! four arrays which store results of rk4_substep, i.e. u1,u2,u3,u4
      do iStep = 1, 4
        timestep_list(iLevel)%timestepData(iStep)%state(:,:,:) = 0.0_rk
      end do
      ! temp array which stores results of temporal forward steps
      allocate(statedata_list_temp(iLevel)%                               &
        & state(cubes%mesh_list(iLevel)%descriptor%elem%nElems(eT_Fluid), &
        & cubes%scheme_list(iLevel)%nDofs,                                &
        & equation%varSys%nScalars)                                       )
      statedata_list_temp(iLevel)%state = &
        & cubes%statedata_list(iLevel)%state
    end do

    ! Loop 4 RK substeps
    ! Each substep first calculates RHS, then Euler forward, finally stabilize
    do iStep = 1, 4
      call substep( iStep, currentLevel, minLevel, maxLevel, cubes, tree, &
        &           statedata_list_temp, poly_proj_list, timestep_list,   &
        &           equation, general, commStateTimer                     )
    end do

    ! copy temp data back to state
    do iLevel = minLevel, maxLevel
      cubes%statedata_list(iLevel)%state = statedata_list_temp(iLevel)%state
    end do

    ! After the runge kutta FULL step, write the results to precice
    !!VK      call tem_startTimer( timerHandle = atl_timerHandles%preciceWrite )
    if (precice_available) then
      call atl_write_precice( stFunList = equation%stFunList,     &
        &                     varSys    = equation%varSys,        &
        &                     time      = general%simControl%now, &
        &                     tree      = tree                    )
    end if
    !!VK      call tem_stopTimer( timerHandle = atl_timerHandles%preciceWrite )

  contains

    ! This subtouine performs the substep of RK4
    ! It first compute RHS, then compute temporal forward step, finally
    ! stabalize
    subroutine substep( iSubstep, currentLevel, minLevel, maxLevel, cubes, &
      &                 tree, statedata_list_temp, poly_proj_list,         &
      &                 timestep_list, equation, general, commStateTimer   )
      ! ------------------------------------------------------------------------
      !> the substep within the RK4
      integer, intent(in) :: iSubstep

      !> The minimum refinement level of the mesh.
      integer, intent(in) :: minLevel

      !> The maximum refinement level of the mesh.
      integer, intent(in) :: maxLevel

      !> The level the timestep has to be performed for.
      integer, intent(in) :: currentLevel

      !> Container for the cubical elements.
      type(atl_cube_container_type), intent(inout) :: cubes

      !> treelm mesh
      type(treelmesh_type), intent(in) :: tree

      !> Temporary state data
      type(atl_statedata_type), intent(inout) &
        & :: statedata_list_temp(minLevel:maxLevel)

      !> List of levelwise timestepping algorihtms
      type(atl_timestep_type), intent(inout) :: timestep_list(minLevel:)

      !> The equation you are operating with.
      type(atl_equations_type),intent(inout) :: equation

      !> General treelm settings
      type(tem_general_type), intent(inout) :: general

      !> Timer for measuring the communication time inside this routine.
      integer, intent(inout) :: commStateTimer

      !> unique list for projection methods
      type(ply_poly_project_type), intent(inout) :: poly_proj_list(:)

      ! ------------------------------------------------------------------------
      integer :: iLevel
      !> dt factor used in RK4 algorithm
      real(kind=rk) :: rk4_dt(4) = [ 0.5_rk, 0.5_rk, 1.0_rk, 1.0_rk ]
      !> dt factor used to forward local time
      real(kind=rk) :: local_dt(4) = [0.0_rk, 0.5_rk, 0.0_rk, 0.5_rk ]
      ! ------------------------------------------------------------------------

      do iLevel = minLevel, maxLevel
        cubes%statedata_list(iLevel)%local_time%sim                   &
          & = cubes%statedata_list(iLevel)%local_time%sim             &
          &   + local_dt(iSubstep) * cubes%scheme_list(iLevel)%time%dt
        ! update the intermediate time for next rk4 substep, this necessary to
        ! calculate source terms and time-dependent boundary values correctly.
        statedata_list_temp(iLevel)%local_time%sim &
          & = cubes%statedata_list(iLevel)%local_time%sim

        ! Store, in which step of the RK method we are
        timestep_list(iLevel)%timestepInfoInteger(1) = iSubstep
      end do

      !  Compute RHS
      !  timestep_list(iLevel)%timestepData(iSubstep)%state
      !   = rhs( statedata_list_temp )
      call rk4_substep( minLevel              = minLevel,                    &
        &               maxLevel              = maxLevel,                    &
        &               currentLevel          = currentLevel,                &
        &               mesh_list             = cubes%mesh_list,             &
        &               tree                  = tree,                        &
        &               levelPointer          = cubes%levelPointer,          &
        &               kerneldata_list       = cubes%kerneldata_list,       &
        &               statedata_list        = statedata_list_temp,         &
        &               facedata_list         = cubes%facedata_list,         &
        &               source                = cubes%source,                &
        &               penalizationdata_list = cubes%penalizationdata_list, &
        &               boundary_list         = cubes%boundary_list,         &
        &               bc                    = cubes%bc,                    &
        &               scheme_list           = cubes%scheme_list,           &
        &               poly_proj_pos         = cubes%poly_proj_pos,         &
        &               poly_proj_list        = poly_proj_list,              &
        &               timestep_list         = timestep_list,               &
        &               equation              = equation,                    &
        &               material_list         = cubes%material_list,         &
        &               general               = general,                     &
        &               commStateTimer        = commStateTimer               )

      ! Now, build the intermediate values for the RK4 method. Since the substep
      ! was carried out for all the levels in the previous step, we can continue
      ! in a simple loop over the levels.
      if ( iSubstep == 4 ) then
        do iLevel = minLevel, maxLevel
          ! state = state + (dt/6) * ( state1 + 2*(state2+state3) + state4 )
          call compute_final(                                         &
            & nTotal   = size(cubes%statedata_list(iLevel)%state, 1), &
            & nDofs    = cubes%scheme_list(iLevel)%nDofs,             &
            & nScalars = equation%varSys%nScalars,                    &
            & state    = statedata_list_temp(iLevel)%state,           &
            & state0   = cubes%statedata_list(iLevel)%state,          &
            & state1   = timestep_list(iLevel)%timestepData(1)%state, &
            & state2   = timestep_list(iLevel)%timestepData(2)%state, &
            & state3   = timestep_list(iLevel)%timestepData(3)%state, &
            & state4   = timestep_list(iLevel)%timestepData(4)%state, &
            & dt       = cubes%scheme_list(iLevel)%time%dt            )
        end do
      else ! iSubstep = 1 or 2 or 3
        do iLevel = minLevel, maxLevel
          ! statedata_list_temp = cubes%statedata_list(iLevel)%state
          !   + factor * dt * timestep_list(iLevel)%timestepData(iSubstep)%state
          ! For 1st and 2nd substep, rk4_dt = 0.5
          ! For 3rd         substep, rk4_dt = 1.0
          call compute_intermediate(                                      &
            &    nTotal    = cubes%mesh_list(iLevel)                      &
            &                     %descriptor                             &
            &                     %elem                                   &
            &                     %nElems(eT_fluid),                      &
            &    nDofs     = cubes%scheme_list(iLevel)                    &
            &                     %nDofs,                                 &
            &    nScalars  = equation%varSys                              &
            &                        %nScalars,                           &
            &    state_tmp = statedata_list_temp(iLevel)                  &
            &                  %state,                                    &
            &    state1    = cubes%statedata_list(iLevel)                 &
            &                     %state,                                 &
            &    state2    = timestep_list(iLevel)%timestepData(iSubstep) &
            &                                     %state,                 &
            &    factor    = rk4_dt(iSubstep)                             &
            &                  * cubes%scheme_list(iLevel)                &
            &                         %time                               &
            &                         %dt                                 )
        end do
      end if ! iSubstep == 4

      ! Stabilize the intermediate result of this stage of the RK4 scheme
      call atl_stabilize( minlevel            = minlevel,                  &
        &                 maxlevel            = maxlevel,                  &
        &                 statedata_list      = statedata_list_temp,       &
        &                 statedata_stab_list = cubes%statedata_stab_list, &
        &                 mesh_list           = cubes%mesh_list,           &
        &                 scheme_list         = cubes%scheme_list,         &
        &                 equation            = equation,                  &
        &                 tree                = tree,                      &
        &                 poly_proj_pos       = cubes%poly_proj_pos,       &
        &                 poly_proj_list      = poly_proj_list,            &
        &                 bc                  = cubes%bc,                  &
        &                 boundary            = cubes%boundary_stab_list,  &
        &                 general             = general,                   &
        &                 material_list       = cubes%material_list,       &
        &                 commStateTimer      = commStateTimer             )

    end subroutine substep

    ! own subroutine to allow vectorization with gcc
    subroutine compute_intermediate( nTotal, nDofs, nScalars, state_tmp, &
      &                              state1, state2, factor              )
      ! ------------------------------------------------------------------------
      integer, intent(in) :: nTotal, nDofs, nScalars
      real(kind=rk), intent(out) :: state_tmp(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state1(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state2(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: factor
      ! ------------------------------------------------------------------------

      state_tmp = state1 + factor*state2

    end subroutine compute_intermediate

    ! own subroutine to allow vectorization with gcc
    subroutine compute_final( nTotal, nDofs, nScalars, state, state0, state1, &
      &                       state2, state3, state4, dt                      )
      ! ------------------------------------------------------------------------
      integer, intent(in) :: nTotal, nDofs, nScalars
      real(kind=rk), intent(out) :: state(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state0(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state1(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state2(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state3(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: state4(nTotal, nDofs, nScalars)
      real(kind=rk), intent(in) :: dt
      ! ------------------------------------------------------------------------

      state = state0 + (dt/6.0_rk) &
        & * ( state1 + 2.0_rk * (state2+state3) + state4 )

    end subroutine compute_final

  end subroutine mesh_timestep_rk4


  !> Subroutine calculates a substep of the Runge-Kutta timestepping scheme.
  !! Calls itself recursively for the finer levels until the finest level is
  !! reached.
  recursive subroutine rk4_substep( minLevel, maxLevel, currentLevel,       &
    & mesh_list, tree, levelPointer, kerneldata_list, statedata_list,       &
    & facedata_list, source, penalizationdata_list, boundary_list, bc,      &
    & scheme_list, poly_proj_pos, poly_proj_list, timestep_list, equation,  &
    & material_list, general, commStateTimer                                )
    ! --------------------------------------------------------------------------
    !> The minimum refinement level of the mesh.
    integer, intent(in) :: minLevel
    !> The maximum refinement level of the mesh.
    integer, intent(in) :: maxLevel
    !> The level the timestep has to be performed for.
    integer, intent(in) :: currentLevel
    !> List of mesh parts. For each level we have one.
    type(atl_cube_elem_type), intent(inout) :: mesh_list(minLevel:maxLevel)
    !> treelm mesh
    type(treelmesh_type), intent(in) :: tree
    !> Pointer for elements from global treeID list index to index in
    !! levelwise fluid lists
    integer, intent(in)  :: levelPointer(:)
    !> List of kerneldatas. For each level we have one
    type(atl_kerneldata_type), intent(inout) :: &
      & kerneldata_list(minLevel:maxLevel)
    !> List of states you want to calc the rhs for. For each level we have one.
    type(atl_statedata_type), intent(inout) :: statedata_list(minLevel:maxLevel)
    !> List of faces states you want to calc the rhs for. For each level we have
    !! one.
    type(atl_facedata_type), intent(inout) :: facedata_list(minLevel:maxLevel)
    !> List of sources, for each level
    type(atl_source_type), intent(inout) :: source
    !> List of penalization data, for each level.
    type(atl_penalizationData_type), intent(inout) :: &
      & penalizationdata_list(minLevel:maxLevel)
    !> List of boundaries, for each level.
    type(atl_level_boundary_type), intent(inout) :: &
      & boundary_list(minLevel:maxLevel)
    !> Global description of the boundaries
    type(atl_boundary_type), intent(in) :: bc(:)
    !> List of schemes, for each level.
    type(atl_scheme_type), intent(inout) :: scheme_list(minLevel:maxLevel)
    !> List of position of projection method in unique projection list, for each
    !! level
    integer, intent(in) :: poly_proj_pos(minLevel:maxLevel)
    !> unique list for projection methods
    type(ply_poly_project_type), intent(inout) :: poly_proj_list(:)
    !> List of levelwise timestepping algorihtms
    type(atl_timestep_type), intent(inout) :: timestep_list(minLevel:maxLevel)
    !> The equation you are operating with.
    type(atl_equations_type),intent(inout) :: equation
    !> Material parameter description.
    type(atl_material_type), intent(inout) :: material_list(minlevel:maxlevel)
    !> General treelm settings
    type(tem_general_type), intent(inout) :: general
    !> Timer for measuring the communication time inside this routine.
    integer,intent(inout) :: commStateTimer
    ! --------------------------------------------------------------------------
    ! --------------------------------------------------------------------------

    ! Before going to the next finer level, we do the following:
    !(0. Create modal representation of source terms)
    ! 1. Project modal representation to the faces.
    ! 2. Communicate the face representations (only the current level).
    ! 3. Interpolate face representations from the current level to
    !    the next finer level.
    ! All these steps are done in the preprocess step of the compute module.
    call atl_preprocess_rhs( minLevel        = minLevel,        &
      &                      maxLevel        = maxLevel,        &
      &                      currentLevel    = currentLevel,    &
      &                      mesh_list       = mesh_list,       &
      &                      tree            = tree,            &
      &                      statedata_list  = statedata_list,  &
      &                      facedata_list   = facedata_list,   &
      &                      boundary_list   = boundary_list,   &
      &                      bc              = bc,              &
      &                      scheme_list     = scheme_list,     &
      &                      poly_proj_list  = poly_proj_list,  &
      &                      equation        = equation,        &
      &                      material_list   = material_list,   &
      &                      general         = general          )


    ! Now, we call the timestep for the next level. I.e. the timestepping
    ! for the finer levels is called recursively unitl we reached the
    ! finest level (i.e. maxLevel) of the mesh.
    if(currentLevel .lt. maxLevel) then
      call rk4_substep( minLevel              = minLevel,              &
        &               maxLevel              = maxLevel,              &
        &               currentLevel          = currentLevel + 1,      &
        &               mesh_list             = mesh_list,             &
        &               tree                  = tree,                  &
        &               levelPointer          = levelPointer,          &
        &               kerneldata_list       = kerneldata_list,       &
        &               statedata_list        = statedata_list,        &
        &               facedata_list         = facedata_list,         &
        &               source                = source,                &
        &               penalizationdata_list = penalizationdata_list, &
        &               boundary_list         = boundary_list,         &
        &               bc                    = bc,                    &
        &               scheme_list           = scheme_list,           &
        &               poly_proj_pos         = poly_proj_pos,         &
        &               poly_proj_list        = poly_proj_list,        &
        &               timestep_list         = timestep_list,         &
        &               equation              = equation,              &
        &               material_list         = material_list,         &
        &               general               = general,               &
        &               commStateTimer        = commStateTimer         )
    end if

    ! After making the timestep on the finer level, we do the following:
    ! 1. Interpolate flux from finer level to the current level.
    ! 2. Calculate the fluxes for the current level.
    ! 3. Communicate the fluxes (only the current level).
    ! 4. Calculate the physical fluxes.
    ! 5. Project physical flux + numerical fluxes to test functions.
    ! 6. Multiply with inverse of (cell local) mass matrix.
    ! ... this call includes steps 1 to 5.
    call atl_compute_rhs( minLevel, maxLevel, currentLevel, mesh_list, tree, &
      &                   kerneldata_list, statedata_list, facedata_list,    &
      &                   source, penalizationdata_list, scheme_list,        &
      &                   poly_proj_pos, poly_proj_list, equation,           &
      &                   material_list, general                             )
    ! ... this call applies the inverse of the mass matrix.
    call atl_postprocess_rhs( mesh       = mesh_list(currentLevel),       &
      &                       kerneldata = kerneldata_list(currentLevel), &
      &                       statedata  = statedata_list(currentLevel),  &
      &                       scheme     = scheme_list(currentLevel),     &
      &                       timestep   = timestep_list(currentLevel),   &
      &                       equation   = equation                       )

  end subroutine rk4_substep

end module atl_rk4_module