atl_modg_1d_kernel_module.f90 Source File


This file depends on

sourcefile~~atl_modg_1d_kernel_module.f90~~EfferentGraph sourcefile~atl_modg_1d_kernel_module.f90 atl_modg_1d_kernel_module.f90 sourcefile~atl_modg_1d_scheme_module.f90 atl_modg_1d_scheme_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_modg_1d_scheme_module.f90 sourcefile~atl_scheme_module.f90 atl_scheme_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_scheme_module.f90 sourcefile~atl_kerneldata_module.f90 atl_kerneldata_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_kerneldata_module.f90 sourcefile~ply_modg_basis_module.f90 ply_modg_basis_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~ply_modg_basis_module.f90 sourcefile~atl_elemental_time_integration_module.f90 atl_elemental_time_integration_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_elemental_time_integration_module.f90 sourcefile~atl_penalization_module.f90 atl_penalization_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_penalization_module.f90 sourcefile~atl_parallel_module.f90 atl_parallel_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_parallel_module.f90 sourcefile~atl_cube_elem_module.f90 atl_cube_elem_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_cube_elem_module.f90 sourcefile~atl_boundary_module.f90 atl_boundary_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_boundary_module.f90 sourcefile~atl_materialprp_module.f90 atl_materialPrp_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_materialprp_module.f90 sourcefile~ply_dof_module.f90 ply_dof_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~ply_dof_module.f90 sourcefile~ply_poly_project_module.f90 ply_poly_project_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~ply_poly_project_module.f90 sourcefile~atl_equation_module.f90 atl_equation_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_equation_module.f90 sourcefile~atl_materialini_module.f90 atl_materialIni_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_materialini_module.f90 sourcefile~atl_facedata_module.f90 atl_facedata_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_facedata_module.f90 sourcefile~ply_leg_diff_module.f90 ply_leg_diff_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~ply_leg_diff_module.f90 sourcefile~atl_source_types_module.f90 atl_source_types_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_source_types_module.f90

Files dependent on this one

sourcefile~~atl_modg_1d_kernel_module.f90~~AfferentGraph sourcefile~atl_modg_1d_kernel_module.f90 atl_modg_1d_kernel_module.f90 sourcefile~atl_container_module.f90 atl_container_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_modg_1d_kernel_module.f90 sourcefile~atl_global_time_integration_module.f90 atl_global_time_integration_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_global_time_integration_module.f90 sourcefile~atl_compute_module.f90 atl_compute_module.f90 sourcefile~atl_compute_module.f90->sourcefile~atl_modg_1d_kernel_module.f90 sourcefile~atl_program_module.f90 atl_program_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_program_module.f90->sourcefile~atl_global_time_integration_module.f90 sourcefile~atl_imexrk_module.f90 atl_imexrk_module.f90 sourcefile~atl_imexrk_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_ssprk2_module.f90 atl_ssprk2_module.f90 sourcefile~atl_ssprk2_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_harvesting.f90 atl_harvesting.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_container_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_program_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_initialize_module.f90 sourcefile~atl_fwdeuler_module.f90 atl_fwdEuler_module.f90 sourcefile~atl_fwdeuler_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_initialize_module.f90->sourcefile~atl_container_module.f90 sourcefile~ateles.f90 ateles.f90 sourcefile~ateles.f90->sourcefile~atl_container_module.f90 sourcefile~ateles.f90->sourcefile~atl_program_module.f90 sourcefile~atl_predcor_cerk4_module.f90 atl_predcor_cerk4_module.f90 sourcefile~atl_predcor_cerk4_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_rk4_module.f90 atl_rk4_module.f90 sourcefile~atl_rk4_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_rktaylor_module.f90 atl_rktaylor_module.f90 sourcefile~atl_rktaylor_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_imexrk_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_ssprk2_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_fwdeuler_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_predcor_cerk4_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_rk4_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_rktaylor_module.f90

Contents


Source Code

! Copyright (c) 2013-2014 Jens Zudrop <j.zudrop@grs-sim.de>
! Copyright (c) 2013-2019 Harald Klimach <harald.klimach@uni-siegen.de>
! Copyright (c) 2013-2015 Verena Krupp <verena.krupp@uni-siegen.de>
! Copyright (c) 2013-2018, 2020 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2014-2016 Nikhil Anand <nikhil.anand@uni-siegen.de>
! Copyright (c) 2016 Tobias Girresser <tobias.girresser@student.uni-siegen.de>
! Copyright (c) 2016 Kannan Masilamani <kannan.masilamani@uni-siegen.de>
! Copyright (c) 2017 Daniel PetrĂ³ <daniel.petro@student.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.
! **************************************************************************** !

! Copyright (c) 2014,2016-2017 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2014 Harald Klimach <harald.klimach@uni-siegen.de>
!
! Parts of this file were written by Peter Vitt and Harald Klimach for
! University of Siegen.
!
! 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.
! **************************************************************************** !
!
! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * Ansatzfunction index in z direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for Q-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * Ansatzfunction index in z direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * Ansatzfunction index in y direction. Index starts with 1.
! * The maximal polynomial degree per spatial direction.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the position of a given ansatz function combination in the
! linearized list of modal coefficients for P-Tensor product polynomials.
! You must provide
! * Ansatzfunction index in x direction. Index starts with 1.
! * The variable to store the position of the modal coefficient in the list of
!   modal coefficients in.


! Return the number of degrees of freedom for Q polynomial space
! Your must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! Your must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * The variable to store the number of degrees of freedom for a P tensor
!   product polynomial


! Return the number of degrees of freedom for Q polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * A variable to store the number of degrees of freedom for a P tensor product
!   polynomial


! Return the number of degrees of freedom for Q polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction
! * The variable to store the number of degrees of freedom for a Q tensor
!   product polynomial


! Return the number of degrees of freedom for broken polynomial space
! You must provide:
! * The maximal polynomial degree per spatial direction (for P Tensor product
!   polynomials this assumed to be the same for each spatial direction).
! * The variable to store the number of degrees of freedom for a P tensor
!   product polynomial

! The x, y and z ansatz degrees are turned into the degrees of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Ansatz function index in z direction. First ansatz function has index 1.

! The x and y ansatz degrees are turned into the degrees of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.

! The x ansatz degree is turned into the degree of the next
! ansatz function in the layered P list
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.

! The x, y and z ansatz degrees are turned into the degrees of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Ansatz function index in z direction. First ansatz function has index 1.
! * Maximal polynomial degree

! The x and y ansatz degrees are turned into the degrees of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
! * Ansatz function index in y direction. First ansatz function has index 1.
! * Maximal polynomial degree

! The x ansatz degree is turned into the degree of the next
! ansatz function in the linearized Q tensor
! You must provide:
! * Ansatz function index in x direction. First ansatz function has index 1.
!> author: Jens Zudrop
!! Module for routines and datatypes of MOdal Discontinuous Galerkin (MODG)
!! scheme. This scheme is a spectral scheme for linear, purley hyperbolic
!! partial differential equation systems.
!!
!!@todo HK: Split this module into three: a common one, a Q part and a P part.
module atl_modg_1d_kernel_module
  use env_module,               only: rk, long_k

  use tem_aux_module,           only: tem_abort
  use treelmesh_module,         only: treelmesh_type
  use tem_element_module,       only: eT_fluid
  use tem_param_module,         only: q__E, q__W, qAxis
  use tem_time_module,          only: tem_time_type
  use tem_element_module,       only: eT_fluid
  use tem_faceData_module,      only: tem_dirToFace_map, tem_left, tem_right
  use tem_logging_module,       only: logUnit
  use tem_comm_module,          only: tem_commPattern_type
  use tem_comm_env_module,      only: tem_comm_env_type

  use ply_modg_basis_module,    only: ply_faceValLeftBndAns,       &
    &                                 ply_faceValLeftBndTest,      &
    &                                 ply_faceValRightBndTest,     &
    &                                 ply_faceValLeftBndgradTest,  &
    &                                 ply_faceValRightBndgradTest, &
    &                                 ply_scalProdDualLeg,         &
    &                                 ply_scalProdDualLegDiff
  use ply_dof_module,           only: Q_space
  use ply_poly_project_module,  only: ply_poly_project_type, assignment(=)
  use ply_leg_diff_module,      only: ply_calcDiff_leg_1d
  use atl_modg_1d_scheme_module,only: atl_modg_1d_scheme_type
  use atl_equation_module,      only: atl_equations_type
  use atl_kerneldata_module,    only: atl_kerneldata_type, &
    &                                 atl_init_kerneldata, &
    &                                 atl_init_statedata,  &
    &                                 atl_statedata_type
  use atl_cube_elem_module,     only: atl_cube_elem_type
  use atl_parallel_module,      only: atl_init_parallel_module
  use atl_scheme_module,        only: atl_scheme_type
  use atl_elemental_time_integration_module,                      &
    &                           only: atl_elemental_timestep_vec, &
    &                                 atl_timestep_type
  use atl_source_types_module,  only: atl_source_type
  use atl_facedata_module,      only: atl_facedata_type, &
    &                                 atl_facerep_type,  &
    &                                 atl_elemfaceToNormal_prp
  use atl_boundary_module,      only: atl_level_boundary_type, &
    &                                 atl_get_numBndElems
  use atl_penalization_module,  only: atl_penalizationData_type
  use atl_materialPrp_module,   only: atl_material_type
  use atl_materialIni_module,   only: atl_update_materialParams

  implicit none

  private

  public :: atl_init_modg_1d_kernel,        &
    & atl_preprocess_modg_1d_kernel,        &
    & atl_modg_1d_ensure_pos_face,          &
    & atl_modg_1d_invMassMatrix,            &
    & atl_modg_1d_modalVolToModalFace,      &
    & atl_modg_1d_project_testFunc,         &
    & atl_modg_1d_project_PhysFlux_testFunc

contains

  subroutine atl_preprocess_modg_1d_kernel(                                &
    &          currentlevel, minLevel, maxLevel,                           &
    &          equation, statedata, mesh_list, boundary_list, scheme_list, &
    &          poly_proj_material, material_list, commPattern, proc        )
    ! --------------------------------------------------------------------------
    integer, intent(in) :: currentLevel
    integer, intent(in) :: minLevel
    integer, intent(in) :: maxLevel
    type(atl_equations_type), intent(inout) :: equation
    type(atl_statedata_type), intent(inout) :: statedata
    type(atl_level_boundary_type), intent(in) :: &
      & boundary_list(minlevel:maxLevel)
    type(atl_cube_elem_type), intent(inout) :: mesh_list(minlevel:maxlevel)
    type(atl_scheme_type), intent(inout) :: scheme_list(minlevel:maxlevel)
    type(atl_material_type), intent(inout) :: material_list(minlevel:maxlevel)
    type(ply_poly_project_type), intent(inout) :: poly_proj_material
    !> mpi communication environment with mpi communicator
    type(tem_comm_env_type), intent(inout) :: proc
    !> mpi communication pattern type
    type(tem_commPattern_type), intent(inout) :: commPattern
    ! --------------------------------------------------------------------------

    call atl_update_materialParams( equation    = equation,                    &
      &                             mesh        = mesh_list(currentLevel),     &
      &                             scheme      = scheme_list(currentlevel),   &
      &                             boundary    = boundary_list(currentlevel), &
      &                             material    = material_list(currentlevel), &
      &                             time        = statedata%local_time,        &
      &                             poly_proj   = poly_proj_material,          &
      &                             proc        = proc,                        &
      &                             commPattern = commPattern                  )


  end subroutine atl_preprocess_modg_1d_kernel


  !> Initiate the MODG kernel for cubic elements on all levels.
  subroutine atl_init_modg_1d_kernel(                                     &
    &          kerneldata_list, statedata_list, statedata_stab_list,      &
    &          mesh_list, scheme_list, boundary_list, boundary_stab_list, &
    &          equation, tree, time, commPattern,                         &
    &          need_deviation                                             )
    ! --------------------------------------------------------------------------
    !> Array of kerneldata_types, one for each level. They will be initialized.
    type(atl_kerneldata_type), allocatable :: kerneldata_list(:)
    !> Array of statedata_types, one for each level.
    type(atl_statedata_type), allocatable :: statedata_list(:)
    type(atl_statedata_type), allocatable :: statedata_stab_list(:,:)
    !> List of cubic meshes. One entry per level.
    type(atl_cube_elem_type), allocatable :: mesh_list(:)
    !> List of schemes on the levels.
    type(atl_scheme_type), allocatable :: scheme_list(:)
    !> The boundary description for the faces on the current level.
    type(atl_level_boundary_type), allocatable :: boundary_list(:)
    !> The boundary description for the faces on the current level.
    type(atl_level_boundary_type), allocatable :: boundary_stab_list(:)
    !> The equation type.
    type(atl_equations_type) :: equation
    !> The tree of the simulation domain
    type(treelmesh_type), intent(in) :: tree
    !> current time
    type(tem_time_type), intent(in) :: time
    !> mpi communication pattern type
    type(tem_commPattern_type), intent(in) :: commPattern
    !> Flag to indicate whether maximal polynomial deviations should be
    !! computed for the state.
    logical, intent(in) :: need_deviation
    ! --------------------------------------------------------------------------
    integer :: iList, iStab, nTotal
    integer :: nScalars, nDer, nDof, nScalarsState_Comm, nScalarsFlux_Comm
    logical :: stab_reqNeigh
    integer :: nBndStabElems(tree%global%minLevel:tree%global%maxLevel,1:3)
    ! --------------------------------------------------------------------------

    ! the number of scalar variables of our equation system
    nScalars = equation%varSys%nScalars

    ! If the stabilization requires further neighbor information,
    ! we init the buffer for it
    stab_reqNeigh = .false.
    do iStab = 1, size(scheme_list(tree%global%minLevel)%stabilization)
      if( scheme_list(tree%global%minLevel)%stabilization(iStab)%reqNeigh ) then
        stab_reqNeigh = .true.
      end if
    end do

    ! init the kerneldata on each level.
    do iList = tree%global%minLevel, tree%global%maxLevel
      ! The number of derived quantities is the number of polynomial degrees of
      ! freedoms per scalar variable.

      select case(scheme_list(iList)%modg_1d%basisType)
      case(Q_space)
        nDer = (scheme_list(iList)%modg_1d%maxPolyDegree+1)**1
        nDof = nDer
      end select

      call atl_init_kerneldata(                                             &
        &    kerneldata     = kerneldata_list(iList),                       &
        &    statedata      = statedata_list(iList),                        &
        &    nTotal         = mesh_list(iList)%descriptor%elem              &
        &                                                %nElems(eT_fluid), &
        &    nVars          = nScalars,                                     &
        &    nDofs          = nDof,                                         &
        &    nDervQuant     = nDer,                                         &
        &    time           = time,                                         &
        &    maxPolyDegree  = scheme_list(iList)%modg_1d%maxPolyDegree,     &
        &    nDims          = 1,                                            &
        &    poly_space     = scheme_list(iList)%modg_1d%basisType,         &
        &    need_deviation = need_deviation,                               &
        &    need_maxgrad   = equation%requires_gradmax                     )

      if(stab_reqNeigh) then
        nBndStabElems = atl_get_numBndElems(      &
          & minLevel      = tree%global%minLevel, &
          & maxLevel      = tree%global%maxLevel, &
          & boundary_list = boundary_stab_list    )
        nTotal = mesh_list(iList)%faces%dimByDimDesc(1)%nElems &
          &      + nBndStabElems(iList,1)
        call atl_init_statedata(                              &
          &    statedata      = statedata_stab_list(iList,1), &
          &    nTotal         = nTotal,                       &
          &    nVars          = nScalars,                     &
          &    nDofs          = nDof,                         &
          &    time           = time                          )
      end if
    end do

    ! Init the parallel module here, as well. DG requires only face values, so
    ! we init only the face buffers and do not init the cell buffers.
    ! ... for the state, we need the state and all its derivatives
    !     (in all directions)
    nScalarsState_Comm = nScalars*(1+equation%nDerivatives*1)
    ! ... for the flux, we need the numerical flux and the stabilization flux
    nScalarsFlux_Comm = nScalars*(1+equation%nDerivatives)
    call atl_init_parallel_module(                   &
      & commPattern          = commPattern,          &
      & scheme               = scheme_list,          &
      & nValsElem            = nScalars,             &
      & nValsStateFace       = nScalarsState_Comm,   &
      & nValsFluxFace        = nScalarsFlux_Comm,    &
      & cube                 = mesh_list,            &
      & boundary             = boundary_list,        &
      & createCellBuffer     = .false.,              &
      & createFaceBuffer     = .true.,               &
      & createStabFaceBuffer = .false.,              &
      & createStabElemBuffer = stab_reqNeigh,        &
      & nBndStabElems        = nBndStabElems,        &
      & minLevel             = tree%global%minLevel, &
      & maxLevel             = tree%global%maxLevel  )

  end subroutine atl_init_modg_1d_kernel



  !> Subroutine to project modal representations of physical flux, numerical
  !! flux and source terms onto test functions.
  subroutine atl_modg_1d_project_testFunc( mesh, equation, kerneldata,        &
    &                                      facedata, sourcedata,              &
    &                                      penalizationdata, usePenalization, &
    &                                      level, scheme                      )
    ! --------------------------------------------------------------------------
    !> Descritption of the cubical elements in the mesh
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The equation description.
    type(atl_equations_type), intent(in) :: equation
    !> The data of the kernel. Holds the physical fluxes.
    type(atl_kerneldata_type), intent(inout) :: kerneldata
    !> The representation on the face + representation of the flux.
    type(atl_facedata_type), intent(inout) :: facedata
    !> Volumetric data for the penalization
    type(atl_penalizationData_type), intent(in) :: penalizationdata
    !> Flag to indicate whether the penalization data has to be considered, or
    !! if it is taken care of somewhere else (imex)
    logical, intent(in) :: usePenalization
    !> Modal representation of the sources.
    type(atl_source_type), intent(inout) :: sourcedata
    !> The level you compute for
    integer, intent(in) :: level
    !> The parameters of the MODG scheme
    type(atl_modg_1d_scheme_type), intent(in) :: scheme
    ! --------------------------------------------------------------------------

    select case(scheme%basisType)
    case(Q_space)
      call modg_1d_project_testFunc_Q( mesh             = mesh,              &
        &                              equation          = equation,         &
        &                              kerneldata        = kerneldata,       &
        &                              facedata          = facedata,         &
        &                              penalizationdata  = penalizationdata, &
        &                              usePenalization   = usePenalization,  &
        &                              sourcedata        = sourcedata,       &
        &                              Currentlevel      = level,            &
        &                              scheme            = scheme            )
    end select

  end subroutine atl_modg_1d_project_testFunc

  !> Subroutine to project modal representations of physical flux, numerical flux
  !! and source terms onto test functions.
  subroutine atl_modg_1d_project_PhysFlux_testFunc( equation, kerneldata, &
    &                                               scheme, iElem, nDofs, &
    &                                               state_data            )
    ! --------------------------------------------------------------------------
    !> The equation description.
    type(atl_equations_type), intent(in) :: equation
    !> The data of the kernel. Holds the physical fluxes.
    type(atl_kerneldata_type), intent(inout) :: kerneldata
    !> The parameters of the MODG scheme
    type(atl_modg_1d_scheme_type), intent(in) :: scheme
    !> The total degrees of freedom
    integer, intent(in) :: nDofs
    !> The element index
    integer, intent(in) :: iElem
    !> The physical fluxes that needs to be projected
    real(kind=rk), intent(in)  :: state_data(nDofs,equation%varSys%nScalars)
    ! --------------------------------------------------------------------------

    select case(scheme%basisType)
    case(Q_space)
      ! Projection of the physical flux
      ! ... x direction
      call modg_1d_project_physFluxX_Q(             &
        & nScalars      = equation%varSys%nScalars, &
        & maxPolyDegree = scheme%maxPolyDegree,     &
        & iElem         = iElem,                    &
        & state_der     = state_data,               &
        & state         = kerneldata%state_der      )
    end select

  end subroutine atl_modg_1d_project_PhysFlux_testFunc


  !> Subroutine to project modal representations of physical flux, numerical flux
  !! and source terms onto test functions.
  subroutine modg_1d_project_testFunc_Q( mesh, equation, kerneldata, facedata, &
                            & penalizationdata, usePenalization, sourcedata,   &
                            & Currentlevel, scheme                             )
    ! --------------------------------------------------------------------------
    !> Descritption of the cubical elements in the mesh
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The equation description.
    type(atl_equations_type), intent(in) :: equation
    !> The data of the kernel. Holds the physical fluxes.
    type(atl_kerneldata_type), intent(inout) :: kerneldata
    !> The representation on the face + representation of the flux.
    type(atl_facedata_type), intent(inout) :: facedata
    !> Volumetric data for the penalization
    type(atl_penalizationData_type), intent(in) :: penalizationdata
    !> Flag to indicate whether the penalization data has to be considered, or
    !! if it is taken care of somewhere else (imex)
    logical, intent(in) :: usePenalization
    !> Modal representation of the sources.
    type(atl_source_type), intent(inout) :: sourcedata
    !> The level you compute for
    integer, intent(in) :: Currentlevel
    !> The parameters of the MODG scheme
    type(atl_modg_1d_scheme_type), intent(in) :: scheme
    ! --------------------------------------------------------------------------

    ! Iterate over all the elements and do the following:
    ! 1. Project physical fluxes (3 directions) to test functions (stiffness terms).
    !    Attention: physical x flux: state_der(:,:,2,:)
    ! 2. Project numerical fluxes (4 faces) to test functions.
    ! 3. Project source terms to test functions.
    ! Attention: write the projections to state_der(:,:,1,:) because inverse
    ! of mass matrix will be applied to these entries.

    ! Before, we start the projections, we initialize the entries (where we sum up) with
    ! zeros.


    ! Projection of the numerical flux
    ! ... x faces
    call modg_1d_project_numFluxX_Q(                              &
      & numFluxLeftFace  = facedata%faceFlux(1)%dat,              &
      & numFluxRightFace = facedata%faceFlux(1)%dat,              &
      & nScalars         = equation%varSys%nScalars,              &
      & maxPolyDegree    = scheme%maxPolyDegree,                  &
      & nElems_fluid     = mesh%descriptor%elem%nElems(eT_fluid), &
      & projection       = kerneldata%state_der                   )

    select case(equation%eq_kind)
      case('heat_1d')
        ! Projection of the appropriate  numerical flux onto the derivative of
        ! the test functions
        ! ... x faces
        call modg_1d_project_numFlux_diffTestX_Q(                     &
          & numFluxLeftFace  = facedata%faceFlux(1)%dat,              &
          & numFluxRightFace = facedata%faceFlux(1)%dat,              &
          & nScalars         = equation%varSys%nScalars,              &
          & maxPolyDegree    = scheme%maxPolyDegree,                  &
          & nElems_fluid     = mesh%descriptor%elem%nElems(eT_fluid), &
          & projection       = kerneldata%state_der                   )

    end select

    ! Projection of the source terms onto the test functions.
    call modg_1d_project_source_Q( sourcedata = sourcedata,            &
      &                         nScalars = equation%varSys%nScalars,   &
      &                         mesh = mesh,                           &
      &                         maxPolyDegree = scheme%maxPolyDegree,  &
      &                         kerneldata = kerneldata,               &
      &                         currentLevel = currentLevel            )

    ! Project the penalization term to test function
    ! Projection of the penalization term if is not computed somewhere else
    if (penalizationdata%isActive .and. usePenalization) then
      call modg_1d_project_penalization(                               &
        &                 nScalars         = equation%varSys%nScalars, &
        &                 mesh             = mesh,                     &
        &                 maxPolyDegree    = scheme%maxPolyDegree,     &
        &                 penalizationdata = penalizationdata,         &
        &                 kerneldata       = kerneldata                )
    end if


  end subroutine modg_1d_project_testFunc_Q


  !> Projection of the source terms (in modal representation) to the test functions.
  subroutine modg_1d_project_source_Q( sourcedata, nScalars, mesh, &
    &                                  maxPolyDegree, kerneldata,  &
    &                                  currentLevel )
    ! ---------------------------------------------------------------------------
    !> The number scalar variables in the equation system.
    integer, intent(in) :: nScalars
    !> The modal representation of the source
    type(atl_source_type), intent(in) :: sourcedata
    !> The maximal polynomial degree of the modg scheme
    integer, intent(in) :: maxPolyDegree
    !> The cubical elements.
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The data of the kernel. This one is updated by the projection.
    type(atl_kerneldata_type), intent(inout) :: kerneldata
    !> The current level
    integer, intent(in) :: currentLevel
    ! ---------------------------------------------------------------------------
    integer(kind=long_k) :: elemPos
    integer :: iElem, xTestFunc, testPos, xAnsFuncMin, xAnsFunc, &
      &        ansPos, varPos, iSource, nSourceElems
    real(kind=rk) :: jacobiDet, xScalProd
    ! ---------------------------------------------------------------------------

    jacobiDet = (0.5_rk*mesh%length)**1

    do iSource = 1, size(sourcedata%method)

      nSourceElems = sourcedata%method(iSource)%elems(currentLevel)%nElems

      do varPos = 1, nScalars
        do iElem = 1, nSourceElems

          ! Position of the current element
          if (sourcedata%method(iSource)%isPermanent) then
            elempos = iElem
          else
            elempos = sourcedata%method(iSource)%elems(currentLevel) &
                                %posInTotal%val(iElem)
          end if

          ! Now, we loop over all the test functions for this element and calculate
          ! the projection of the source terms onto this test functions.
          do xTestFunc = 1, maxPolyDegree+1

            ! Get the position of the test functions in the serialized list
            ! of dofs
  testpos = xtestfunc                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

            ! Loop over relevant ans functions
            xAnsFuncMin = xTestFunc-2
            if( xAnsFuncMin < 1 ) then
              xAnsFuncMin = xTestFunc
            end if
            do xAnsFunc = xAnsFuncMin,xTestFunc,2

              ! get position of ansatz functions in the serialized list
              ! of dofs.
  anspos = xansfunc                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

              ! project the current ansatz function onto the test function
              xScalProd = ply_scalProdDualLeg(xAnsFunc, xTestFunc)
              kernelData%state_der(elemPos, testPos,  varPos) &
                  & = kernelData%state_der(elemPos, testPos,  varPos) &
                  & + xScalProd &
                  & * jacobiDet &
                  & * sourcedata%method(iSource)%val(iElem, ansPos, varPos)
            end do ! x ansatz functions

          end do ! x test functions

        end do ! elem loop
      end do ! variable loop
    end do ! source loop


  end subroutine modg_1d_project_source_Q


  !> Projection of the penalization terms (in modal representation) to the test functions.
  subroutine modg_1d_project_penalization( nScalars, mesh, maxPolyDegree, &
                                           & kerneldata, penalizationdata )
    ! ---------------------------------------------------------------------------
    !> The number scalar variables in the equation system.
    integer, intent(in) :: nScalars
    !> The maximal polynomial degree of the modg scheme
    integer, intent(in) :: maxPolyDegree
    !> The cubical elements.
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The data of the kernel. This one is updated by the projection.
    type(atl_kerneldata_type), intent(inout) :: kerneldata
    !> Volumetric data for the penalization
    type(atl_penalizationData_type), intent(in) :: penalizationdata
    ! ---------------------------------------------------------------------------
    integer :: iElem, xTestFunc, testPos, &
             & xAnsFuncMin, xAnsFunc,     &
             & ansPos
    real(kind=rk) :: jacobiDet, xScalProd
    ! ---------------------------------------------------------------------------

    jacobiDet = (0.5_rk*mesh%length)

    do iElem = 1, mesh%descriptor%elem%nElems(eT_fluid)

      ! Now, we loop over all the test functions for this element and calculate
      ! the projection of the term onto this test functions.
      do testpos=1, maxPolyDegree+1

        ! Get the position of the test functions in the serialized list
        ! of dofs and store it in xTestFunc
  xtestfunc = testpos                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
        ! Loop over relevant ans functions
        xAnsFuncMin = xTestFunc-2
        if( xAnsFuncMin < 1 ) then
          xAnsFuncMin = xTestFunc
        end if
        do xAnsFunc = xAnsFuncMin,xTestFunc,2

            ! get position of ansatz functions in the serialized list
            ! of dofs.
  anspos = xansfunc                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

            ! project the current ansatz function onto the test function
            xScalProd = ply_scalProdDualLeg(xAnsFunc, xTestFunc)
            kernelData%state_der(iElem, testPos,  1:nScalars) &
                         & = kernelData%state_der(iElem, testPos, 1:nScalars) &
                         & + xScalProd &
                         & * jacobiDet &
                         & * penalizationdata%penalization_data(iElem, ansPos,1:nScalars)
        end do ! x ansatz functions

      end do ! test functions

    end do ! elem loop

  end subroutine modg_1d_project_penalization

  !> Projection of the numerical flux in x direction onto the testfunctions.
  subroutine modg_1d_project_numFluxX_Q( numFluxLeftFace, numFluxRightFace, &
    &                                    nScalars, maxPolyDegree,           &
    &                                    nElems_fluid,  projection          )
    ! --------------------------------------------------------------------------
    !> The numerical flux on the left face in modal representations.
    !! Dimension is (maxPolyDegree+1)^2 , nScalars
    real(kind=rk), intent(inout) :: numFluxLeftFace(:,:,:,:)
    !> The numerical flux on the right face in modal representations.
    !! Dimension is (maxPolyDegree+1)^2 , nScalars
    real(kind=rk), intent(inout) :: numFluxRightFace(:,:,:,:)
    !> The number of scalar variables in your equation system.
    integer, intent(in) :: nScalars
    !> The maximal polynomial degree in each spatial direction.
    integer, intent(in) :: maxPolyDegree
    !> The element index
    integer, intent(in) :: nElems_fluid
    !> The numerical flux projected onto the test functions.
    real(kind=rk), intent(inout) :: projection(:,:,:)
    ! --------------------------------------------------------------------------
    integer :: xTestFunc
    integer :: testPos, ansPos
    real(kind=rk) :: outerNormalLeft, outerNormalRight
    real(kind=rk) :: faceValLeft, faceValRight
    integer :: iElem, iVar
    ! --------------------------------------------------------------------------


    ! Jacobi determinant for the projections of the numerical fluxes onto the test functions
    outerNormalLeft = atl_elemfaceToNormal_prp(tem_left)
    outerNormalRight = atl_elemfaceToNormal_prp(tem_right)

    ! Loop over all the test functions and project the numerical flux to them.
    do xTestFunc = 1,min(maxPolyDegree+1,2)

      faceValLeft = ply_faceValLeftBndTest(xTestFunc) * outerNormalLeft
      faceValRight = ply_faceValRightBndTest(xTestFunc) * outerNormalRight
      ! position of the test functions in the kerneldata
  testpos = xtestfunc                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

      ! the position of the modal coefficeint of this ansatz functions
  anspos = 1                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)


      ! buffer the result in kernel data and take care of the outer surface unit normal
      ! ... for the left face
      elementLoop: do iElem = 1,nElems_fluid
        do iVar = 1,nScalars
          projection(iElem,testPos,iVar) = projection(iElem,testPos,iVar) &
                          & - faceValLeft &
                          & * numFluxLeftFace(iElem,ansPos,iVar,1)
          ! ... for the right face
          projection(iElem,testPos,iVar) = projection(iElem,testPos,iVar) &
                          & - faceValRight &
                          & * numFluxRightFace(iElem,ansPos,iVar,2)

        end do

      end do elementLoop
    end do

  end subroutine modg_1d_project_numFluxX_Q


  !> Projection of the numerical flux in x direction onto the differentiated
  !  testfunctions.
  subroutine modg_1d_project_numFlux_diffTestX_Q( &
    &          numFluxLeftFace, numFluxRightFace, nScalars, maxPolyDegree, &
    &          nElems_fluid,  projection )
    ! --------------------------------------------------------------------------
    !> The numerical flux on the left face in modal representations.
    !! Dimension is (maxPolyDegree+1)^2 , nScalars
    real(kind=rk), intent(inout) :: numFluxLeftFace(:,:,:,:)
    !> The numerical flux on the right face in modal representations.
    !! Dimension is (maxPolyDegree+1)^2 , nScalars
    real(kind=rk), intent(inout) :: numFluxRightFace(:,:,:,:)
    !> The number of scalar variables in your equation system.
    integer, intent(in) :: nScalars
    !> The maximal polynomial degree in each spatial direction.
    integer, intent(in) :: maxPolyDegree
    !> The element index
    integer, intent(in) :: nElems_fluid
    !> The numerical flux projected onto the test functions.
    real(kind=rk), intent(inout) :: projection(:,:,:)
    ! --------------------------------------------------------------------------
    integer :: xTestFunc
    integer :: testPos, ansPos
    real(kind=rk) :: faceValLeft, faceValRight
    integer :: iElem, iVar
    ! --------------------------------------------------------------------------


    ! Jacobi determinant for the projections of the numerical fluxes
    ! onto the test functions

    ! Loop over all the test functions and project the numerical flux to them.
    do xTestFunc = 1,maxPolyDegree+1

      faceValLeft = ply_faceValLeftBndgradTest(xTestFunc)
      faceValRight = ply_faceValRightBndgradTest(xTestFunc)

      ! position of the test functions in the kerneldata
  testpos = xtestfunc                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

      ! the position of the modal coefficeint of this ansatz functions
  anspos = 1                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)


      ! buffer the result in kernel data and take care of the outer surface unit normal
      ! ... for the left face
      elementLoop: do iElem = 1,nElems_fluid
        do iVar = 1,nScalars
          projection(iElem,testPos,iVar) = projection(iElem,testPos,iVar) &
                          & - faceValLeft &
                          & * numFluxLeftFace(iElem,ansPos,nScalars+iVar,1)
          ! ... for the right face
          projection(iElem,testPos,iVar) = projection(iElem,testPos,iVar) &
                          & - faceValRight &
                          & * numFluxRightFace(iElem,ansPos,nscalars+iVar,2)
        end do
      end do elementLoop

    end do
  end subroutine modg_1d_project_numFlux_diffTestX_Q


  !> Projection of the physical flux in x direction onto the testfunctions.
  subroutine modg_1d_project_physFluxX_Q( nScalars, maxPolyDegree, state, &
    &                                     iElem, state_der )
    ! --------------------------------------------------------------------------
    !> The number of scalar variables in your equation system.
    integer, intent(in) :: nScalars
    !> The maximal polynomial degree in each spatial direction.
    integer, intent(in) :: maxPolyDegree
    !> The state to alter.
    real(kind=rk), intent(inout) :: state(:,:,:)
    !> The element index
    integer, intent(in) :: iElem
    !> The state data for the element
    real(kind=rk), intent(in)  :: state_der((maxPolyDegree+1),nScalars)
    ! --------------------------------------------------------------------------
    real(kind=rk) :: scalProdX(maxPolyDegree)
    integer :: ansPos(4), testPos
    integer :: iAnsX
    integer :: iVar
    integer :: var_lb, var_ub
    real(kind=rk) :: scalProd(4)
    ! --------------------------------------------------------------------------

    ! Jacobi determinant for pojections of the physical fluxes onto the test
    ! functions.
    ! This is the stiffness term!

    var_lb = lbound(state,3)
    var_ub = ubound(state,3)

    ! for x direction (x test function differentiated)
    ! get the relevant indices for the ansatz function
    do iAnsX=1,maxPolyDegree
      scalProdX(iAnsX) = ply_scalProdDualLegDiff(iAnsX, iAnsX+1)
    end do

    ! now, project onto all test functions
  testpos = 1                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
    do iVar=var_lb,var_ub
      state(iElem,testPos,iVar) = 0.0_rk
    end do

    ! Need to add one term
    do iAnsX = 1, maxPolyDegree
      ! the position of the current test functions
  testpos = iansx+1                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
      scalProd(1) = scalProdX(iAnsX)
  anspos(1) = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)

      do iVar=var_lb,var_ub
        state(iElem,testPos,iVar) &
          &  = state_der(ansPos(1),iVar) * scalProd(1)
      end do

    end do

  end subroutine modg_1d_project_physFluxX_Q



  !> Lift the value on the face to a positive value if necessary.
  !!
  !! In some equations, some variables may not be allowed to be negative,
  !! for example the density and energy in flow simulations.
  !! With this routine we enforce this limitation for the projected mean
  !! state on the element surfaces.
  subroutine atl_modg_1d_ensure_pos_face(                                   &
    &          nelems_fluid, volState, faceRep, nScalars, ensure_positivity )
    ! -------------------------------------------------------------------- !
    !> Number of fluid elements
    integer, intent(in) :: nElems_fluid

    !> Volumetric modal states for each element
    real(kind=rk), intent(in) :: volState(:,:,:)

    !> Modal representation on the face that might need limiting.
    !!
    !! All means below 0 of variables where positivity is to be ensured will
    !! be increased to a small value above 0.
    type(atl_faceRep_type), intent(inout) :: faceRep(:)

    !> Number of variables
    integer, intent(in) :: nScalars

    !> Indication for each variable, whether positivity is to be ensured
    !! or not.
    !!
    !! Only variables where this is set to .true. will be modified by this
    !! routine.
    logical, intent(in) :: ensure_positivity(:)
    ! --------------------------------------------------------------------------
    integer :: iVar
    real(kind=rk) :: epsfact
    ! --------------------------------------------------------------------------

    epsfact = epsilon(volState(1,1,1))

    do iVar=1,nScalars
      if (ensure_positivity(iVar)) then

        ! We assume the integral mean of the element is positive for all
        ! elements. The integral mean on the surface will now be lifted to
        ! a small fraction of that element mean if it is below that threshold.
        facerep(1)%dat(1:nElems_fluid,1,iVar,1)             &
          & = max( facerep(1)%dat(1:nElems_fluid,1,iVar,1), &
          &        epsfact * volState(1:nElems_fluid,1,iVar)   )
        facerep(1)%dat(1:nElems_fluid,1,iVar,2)             &
          & = max( facerep(1)%dat(1:nElems_fluid,1,iVar,2), &
          &        epsfact * volState(1:nElems_fluid,1,iVar)   )

      end if
    end do

  end subroutine atl_modg_1d_ensure_pos_face


  !> Projects modal representation of each cell to its faces, i.e.
  !! this subroutine creates a modal representation on the faces.
  subroutine atl_modg_1d_modalVolToModalFace( mesh , statedata, facedata, &
    &                                         nScalars, modg_1d, equation )
    ! --------------------------------------------------------------------------
    !> The elements we apply the projection for.
    type(atl_cube_elem_type),  intent(in) :: mesh
    !> Volumetric, modal states for each element.
    type(atl_statedata_type), intent(in) :: statedata
    !> Modal representation on the face (will be updated by this routine for all
    !! fluid elements in mesh).
    type(atl_facedata_type), intent(inout) :: facedata
    !> The number of scalars varaibales in your equation system.
    integer, intent(in) :: nScalars
    !> The parameters of your modg scheme.
    type(atl_modg_1d_scheme_type), intent(in) :: modg_1d
    !> The equation you solve.
    type(atl_equations_type) :: equation
    ! --------------------------------------------------------------------------
    integer :: spaceDir, iDir
    ! --------------------------------------------------------------------------

    ! Iterate over all the fluid elements and project its modal representations
    ! to the faces of the element.

    select case(modg_1d%basisType)
      case(Q_space) ! Q tensor product ansatz functions

        do iDir = 1, size(facedata%faceRep)
          facedata%faceRep(iDir)                              &
            &     %dat(1:mesh%descriptor                      &
            &                %elem                            &
            &                %nElems(eT_fluid),:,:,:) = 0.0_rk
        end do


        ! Now, iterate over all the faces and project to this face.
        ! ... x faces
        ! Project to the face in the current direction.
        spaceDir = qAxis(1)
        call modg_1d_volToFace_Q(                                  &
          & volState      = statedata%state,                       &
          & maxPolyDegree = modg_1d%maxPolyDegree,                 &
          & faceDir       = 1,                                     &
          & nScalars      = nScalars,                              &
          & nElems        = mesh%descriptor%elem%nElems(eT_fluid), &
          & faceState     = facedata%faceRep(spaceDir)%dat         )
        ! ... x
        ! Project to the face in the current direction.
        spaceDir = qAxis(4)
        call modg_1d_volToFace_Q(                                  &
          & volState      = statedata%state,                       &
          & maxPolyDegree = modg_1d%maxPolyDegree,                 &
          & faceDir       = 4,                                     &
          & nScalars      = nScalars,                              &
          & nElems        = mesh%descriptor%elem%nElems(eT_fluid), &
          & faceState     = facedata%faceRep(spaceDir)%dat         )


        ! Now, iterate over all the faces and project the gradients to this face.
        if(equation%nDerivatives == 1 ) then
          spaceDir = qAxis(1)

          call modg_1d_VolToFace_grad_Q(                             &
            & volState      = statedata%state,                       &
            & maxPolyDegree = modg_1d%maxPolyDegree,                 &
            & faceDir       = 1,                                     &
            & nScalars      = nScalars,                              &
            & nElems        = mesh%descriptor%elem%nElems(eT_fluid), &
            & elemLength    = mesh%length,                           &
            & faceState     = facedata%faceRep(spaceDir)%dat         )

          spaceDir = qAxis(4)

          call modg_1d_VolToFace_grad_Q(                             &
            & volState      = statedata%state,                       &
            & maxPolyDegree = modg_1d%maxPolyDegree,                 &
            & faceDir       = 4,                                     &
            & nScalars      = nScalars,                              &
            & nElems        = mesh%descriptor%elem%nElems(eT_fluid), &
            & elemLength    = mesh%length,                           &
            & faceState     = facedata%faceRep(spaceDir)%dat         )
          end if
      case default
        call tem_abort( 'ERROR in atl_modg_1d_modalVolToModalFace:' &
          & // ' Unknown tensor product'                            )
    end select
  end subroutine atl_modg_1d_modalVolToModalFace

  subroutine modg_1d_VolToFace_grad_Q( volstate, maxPolyDegree, faceDir,       &
    &                         nScalars, nElems,elemLength, faceState           )
    ! --------------------------------------------------------------------------
    !> The modal representation in the volume. First dimension is the number of
    !! voluemtrix numbers of degrees of freedom and second dimension is the number
    !! of scalar variables in the equation system.
    real(kind=rk), intent(in) :: volState(:,:,:)
    !> The maximal polynomial degree per spatial direction.
    integer, intent(in) :: maxPolyDegree
    !> The face to project the modal representation to.
    !! Use one of the first six directions of \link tem_param_module \endlink, e.g.
    !! \link tem_param_module::q__e \endlink
    integer, intent(in) :: faceDir
    !> The number of scalar variables in your equation system.
    integer, intent(in) :: nScalars
    !> The number of elements
    integer, intent(in) :: nElems
    !> Length of elements
    real(kind=rk), intent(in) :: elemLength
    !> The modal representation on the face
    real(kind=rk), intent(inout) :: faceState(:,:,:,:)
    ! --------------------------------------------------------------------------
    integer :: iElem, lb, ub
    integer :: pos, iAnsX,leftOrRight
    real(kind=rk) :: faceVal
    real(kind=rk), allocatable :: modalCoeffs(:,:)
    real(kind=rk), allocatable :: state_gradient(:,:)
    ! --------------------------------------------------------------------------

    ! Allocate memory for the gradient buffer
    allocate( state_gradient(maxPolyDegree+1,nScalars) )
    allocate( modalCoeffs(maxPolyDegree+1,nScalars) )

    lb = nScalars + 1
    ub = lb + nScalars -1

    leftOrRight = tem_dirToFace_map(faceDir)

    do iElem = 1, nElems

      modalCoeffs(:,:) = volState(iElem,:,:)

      ! Now we calculate the gradient of the modal representation required
      call ply_calcDiff_leg_1d( legCoeffs     = modalCoeffs,    &
        &                       legcoeffsDiff = state_gradient, &
        &                       maxPolyDegree = maxPolyDegree,  &
        &                       elemLength    = elemLength      )

        ! now, project to a certain face.
      if( faceDir.eq.q__E ) then
        do iAnsX = 1, maxPolyDegree+1
          ! get position of the current ansatz function
  pos = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
          faceState(iElem,1,lb:ub,leftOrRight) &
            &  = faceState(iElem,1,lb:ub,leftOrRight) &
            &  + state_gradient(pos,1:nScalars)
        end do
      elseif(faceDir.eq.q__W) then
        do iAnsX = 1, maxPolyDegree+1
          ! get position of the current ansatz function
  pos = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
          ! get the face value of the ansatz function with fixed coordinate
          faceVal = ply_faceValLeftBndAns(iAnsX)
          faceState(iElem,1,lb:ub,leftOrRight) &
            &  = faceState(iElem,1,lb:ub,leftOrRight) &
            &  + faceVal*state_gradient(pos,1:nScalars)
        end do
      else
        write(logUnit(1),*) 'ERROR in modg_1d_volToFace: unsupported       &
          &                                 face direction, stopping...'
        call tem_abort()
      end if

    end do  ! elems loop

  end subroutine modg_1d_VolToFace_grad_Q

  !> Projects derivative of modal representation of each cell to its faces, i.e.
  !! this subroutine creates a modal representation on the faces.
!NA!  subroutine modg_1d_modalVolToModalFace_der( mesh , statedata, facedata,      &
!NA!    &                                          nScalars, modg_1d, poly_proj    )
!NA!    ! --------------------------------------------------------------------------
!NA!    !> The elements we apply the projection for.
!NA!    type(atl_cube_elem_type),  intent(in) :: mesh
!NA!    !> Volumetric, modal states for each element.
!NA!    type(atl_statedata_type), intent(in) :: statedata
!NA!    !> Modal representation on the face (will be updated by this routine for all
!NA!    !! fluid elements in mesh).
!NA!    type(atl_facedata_type), intent(inout) :: facedata
!NA!    !> The number of scalars varaibales in your equation system.
!NA!    integer, intent(in) :: nScalars
!NA!    !> The parameters of your modg scheme.
!NA!    type(atl_modg_1d_scheme_type), intent(in) :: modg_1d
!NA!    !> Parameters for projection
!NA!    type(ply_poly_project_type), intent(inout) :: poly_proj
!NA!    ! --------------------------------------------------------------------------
!NA!    integer :: spaceDir, leftOrRightFace, iDir
!NA!    integer :: dofs , nquadpointsPerDir, iDegX, iElem, iDof
!NA!    real(kind=rk), allocatable :: modalCoeffs(:,:)
!NA!    real(kind=rk), allocatable :: modalCoeffsDiff(:,:)
!NA!    real(kind=rk), allocatable :: state_der(:,:,:)
!NA!    ! --------------------------------------------------------------------------
!NA!
!NA!    dofs = poly_proj%body_1d%ndofs
!NA!    nquadpointsPerDir = poly_proj%nquadpointsPerDir
!NA!
!NA!    allocate( modalCoeffs(dofs,1) )
!NA!    allocate( modalCoeffsDiff(dofs,1) )
!NA!    allocate( state_der(mesh%descriptor%nElems_fluid,dofs,1) )
!NA!
!NA!    elemLoop: do iElem = 1, mesh%descriptor%nElems_fluid
!NA!
!NA!      ! get the modal coefficients of the current cell (for all variables)
!NA!      ! -->modal space
!NA!      modalCoeffs(:,:) = 0.0_rk
!NA!      do iDegX = 1, dofs
!NA!        idof = 1 + (iDegX-1)
!NA!        modalCoeffs(idof,:) = statedata%state(iElem,idof,:)
!NA!      end do
!NA!
!NA!      ! Now we calculate the gradient of the modal representation required
!NA!      call ply_calcDiff_leg_1d( legCoeffs     = modalCoeffs,             &
!NA!        &                       legcoeffsDiff = modalCoeffsDiff,         &
!NA!        &                       maxPolyDegree = poly_proj%maxPolyDegree, &
!NA!        &                       nVars         = 1                        )
!NA!
!NA!        state_der(iElem,:,1) = modalCoeffsDiff(:,1)
!NA!    end do elemLoop
!NA!
!NA!    ! Iterate over all the fluid elements and project its modal representations
!NA!    ! of the state derivatives to the faces of the element.
!NA!    select case(modg_1d%basisType)
!NA!      case(Q_space) ! Q tensor product ansatz functions
!NA!
!NA!! @todo commented out!
!NA!write(*,*) 'Commented out der_dat in 1D modg kernel, ... STOPPING'
!NA!stop
!NA!!JZ:        do iDir = 1, size(facedata%faceRep)
!NA!!JZ:          facedata%faceRep(iDir)%der_dat(1:mesh%descriptor%nElems_fluid,:,:,:,1) &
!NA!!JZ:            &                                                    = 0.0_rk
!NA!!JZ:        end do
!NA!
!NA!
!NA!        ! Now, iterate over all the faces and project to this face.
!NA!        ! ... x faces
!NA!        ! Project to the face in the current direction.
!NA!        spaceDir = qAxis(1)
!NA!! @todo commented out!
!NA!write(*,*) 'Commented out der_dat in 1D modg kernel, ... STOPPING'
!NA!stop
!NA!!JZ:        call modg_1d_volToFace_Q( volState = state_der,                       &
!NA!!JZ:              & maxPolyDegree = modg_1d%maxPolyDegree,         &
!NA!!JZ:              & faceDir = 1,                                   &
!NA!!JZ:              & nScalars = nScalars,                           &
!NA!!JZ:              & nElems = mesh%descriptor%nElems_fluid,         &
!NA!!JZ:              & faceState = facedata%faceRep(spaceDir)%der_dat(:,:,:,:,1) )
!NA!        ! ... x faces
!NA!        ! Project to the face in the current direction.
!NA!        spaceDir = qAxis(4)
!NA!! @todo commented out!
!NA!write(*,*) 'Commented out der_dat in 1D modg kernel, ... STOPPING'
!NA!stop
!NA!!JZ:        call modg_1d_volToFace_Q( volState = state_der,                       &
!NA!!JZ:              & maxPolyDegree = modg_1d%maxPolyDegree,         &
!NA!!JZ:              & faceDir = 4,                                   &
!NA!!JZ:              & nScalars = nScalars,                           &
!NA!!JZ:              & nElems = mesh%descriptor%nElems_fluid,         &
!NA!!JZ:              & faceState = facedata%faceRep(spaceDir)%der_dat(:,:,:,:,1) )
!NA!
!NA!
!NA!      case default
!NA!        write(logUnit(1),*) 'ERROR in modg_1d_modalVolToModalFace_der:         &
!NA!          &                      Unknown tensor product, stopping ...'
!NA!        call tem_abort()
!NA!    end select
!NA!
!NA!  end subroutine modg_1d_modalVolToModalFace_der
!NA!


  !> Project modal representation of an element to one of its faces for Q space.
  !!
  !! Project modal representation of an element onto one of its faces. Therefore,
  !! this function returns the modal representation of the solution on the face. This
  !! function can project onto an arbitrary face direction.
  subroutine modg_1d_volToFace_Q( volState, maxPolyDegree, faceDir, nScalars, nELems, faceState )
    ! --------------------------------------------------------------------------
    !> The modal representation in the volume. First dimension is the number of
    !! voluemtrix numbers of degrees of freedom and second dimension is the number
    !! of scalar variables in the equation system.
    real(kind=rk), intent(in) :: volState(:,:,:)
    !> The maximal polynomial degree per spatial direction.
    integer, intent(in) :: maxPolyDegree
    !> The face to project the modal representation to.
    !! Use one of the first six directions of \link tem_param_module \endlink, e.g.
    !! \link tem_param_module::q__e \endlink
    integer, intent(in) :: faceDir
    !> The number of scalar variables in your equation system.
    integer, intent(in) :: nScalars
    !> The number of elements
    integer, intent(in) :: nElems
    !> The modal representation on the face
    real(kind=rk), intent(inout) :: faceState(:,:,:,:)
    ! --------------------------------------------------------------------------
    integer :: iElem, iVar
    integer :: pos, iAnsX,leftOrRight
    real(kind=rk) :: faceVal
    ! --------------------------------------------------------------------------

    leftOrRight = tem_dirToFace_map(faceDir)

    ! now, project to a certain face.
    if( faceDir.eq.q__E ) then
      do iAnsX = 1, maxPolyDegree+1
        ! get position of the current ansatz function
  pos = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
        do iElem=1,nElems
          do iVar = 1, nScalars
            faceState(iElem,1,iVar,leftOrRight) &
              &  = faceState(iElem,1,iVar,leftOrRight) &
              &  + volState(iElem,pos,iVar)
          end do
        end do
      end do
    elseif(faceDir.eq.q__W) then
      do iAnsX = 1, maxPolyDegree+1
        ! get position of the current ansatz function
  pos = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(maxpolydegree+1))*(maxpolydegree+1)
        ! get the face value of the ansatz function with fixed coordinate
        faceVal = ply_faceValLeftBndAns(iAnsX)
        do iElem=1,nElems
          do iVar = 1, nScalars
            faceState(iElem,1,iVar,leftOrRight) &
              &  = faceState(iElem,1,iVar,leftOrRight) &
              &  + faceVal*volState(iElem,pos,iVar)
          end do
        end do
      end do
    else
      write(logUnit(1),*) 'ERROR in modg_1d_volToFace: unsupported face direction, stopping...'
      call tem_abort()
    end if

  end subroutine modg_1d_volToFace_Q


  !> Applies the inverse of the mass matrix for a 3D scheme.
  subroutine atl_modg_1d_invMassMatrix( mesh, kerneldata, statedata,        &
    &                                   elementalTimestep, timestep, scheme )
    ! --------------------------------------------------------------------------
    !> The mesh you are working with.
    type(atl_cube_elem_type) :: mesh
    !> The data of the kernel.
    type(atl_kerneldata_type) :: kerneldata
    !> THe state if the equation
    type(atl_statedata_type) :: statedata
    !> The elemental timestepping routine, because of performance, this
    !! is constant.
    procedure(atl_elemental_timestep_vec), pointer, intent(in) &
      & :: elementalTimestep
    !> The timestepping data.
    type(atl_timestep_type) :: timestep
    !> Parameters of the modal dg scheme
    type(atl_modg_1d_scheme_type), intent(in) :: scheme
    ! -------------------------------------------------------------------------!
    integer :: nElems

    nElems = mesh%descriptor%elem%nElems(eT_fluid)

    select case(scheme%basisType)
      case(Q_space)
        call modg_1d_invMassMatrix_Q( mesh, kerneldata, scheme, nElems )
    end select

    ! Since this is the last part of the MOdal Discontinuous Galerkin (MODG)
    ! algorithm we can make the final timestep, now.
    call elementalTimestep( timestep, statedata%state, kerneldata)

  end subroutine atl_modg_1d_invMassMatrix

  !> Applies the inverse of the mass matrix for a 3D scheme.
  subroutine modg_1d_invMassMatrix_Q( mesh, kerneldata, scheme, nElems )
    ! --------------------------------------------------------------------------
    !> The mesh you are working with.
    type(atl_cube_elem_type) :: mesh
    !> The data of the kernel.
    type(atl_kerneldata_type) :: kerneldata
    !> Parameters of the modal dg scheme
    type(atl_modg_1d_scheme_type), intent(in) :: scheme
    integer, intent(in) :: nElems
    ! -------------------------------------------------------------------------!
    ! Loop indices for ansatz functions
    integer :: iAnsX
    ! Positions for the given ansatz functions
    integer :: ansLow, ansPrevLow
    ! Inverse of the determintant of the jacobian of the mapping from reference
    ! to physical element.
    real(kind=rk) :: inv_jacobiDet
    ! -------------------------------------------------------------------------!

    inv_jacobiDet = (2.0_rk/mesh%length)

    ! apply the 1D inverse of the mass matrix
    do iAnsX = 3, scheme%maxPolyDegree+1
  anslow = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(scheme%maxpolydegree+1))*(scheme%maxpolydegree+1)
  ansprevlow = iansx-2                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(scheme%maxpolydegree+1))*(scheme%maxpolydegree+1)
      kerneldata%state_der(:nElems, ansLow,  :) &
        &        = kerneldata%state_der(:nElems, ansLow,  :) &
        &        + kerneldata%state_der(:nElems, ansPrevLow,  :)
    end do


    do iAnsX = 1, scheme%maxPolyDegree+1
  anslow = iansx                                      &
    &      + ( ( 1-1)                             &
    &      + (1-1)*(scheme%maxpolydegree+1))*(scheme%maxpolydegree+1)
      kerneldata%state_der(:nElems, ansLow,  :) &
        &    = kerneldata%state_der(:nElems, ansLow,  :) &
        &      * 0.5_rk*(2*iAnsX-1)*inv_jacobiDet
    end do

  end subroutine modg_1d_invMassMatrix_Q


end module atl_modg_1d_kernel_module