atl_materialIni_module.f90 Source File


This file depends on

sourcefile~~atl_materialini_module.f90~~EfferentGraph sourcefile~atl_materialini_module.f90 atl_materialIni_module.f90 sourcefile~atl_boundary_module.f90 atl_boundary_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_boundary_module.f90 sourcefile~atl_cube_elem_module.f90 atl_cube_elem_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_cube_elem_module.f90 sourcefile~atl_eqn_maxwell_var_module.f90 atl_eqn_maxwell_var_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_eqn_maxwell_var_module.f90 sourcefile~atl_eqn_maxwelldivcorr_var_module.f90 atl_eqn_maxwelldivcorr_var_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_eqn_maxwelldivcorr_var_module.f90 sourcefile~atl_equation_module.f90 atl_equation_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_equation_module.f90 sourcefile~atl_materialfun_module.f90 atl_materialFun_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_materialfun_module.f90 sourcefile~atl_materialprp_module.f90 atl_materialPrp_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_materialprp_module.f90 sourcefile~atl_parallel_module.f90 atl_parallel_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_parallel_module.f90 sourcefile~atl_reference_element_module.f90 atl_reference_element_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_reference_element_module.f90 sourcefile~atl_scheme_module.f90 atl_scheme_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_scheme_module.f90 sourcefile~atl_timer_module.f90 atl_timer_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_timer_module.f90 sourcefile~atl_varsys_module.f90 atl_varSys_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~atl_varsys_module.f90 sourcefile~ply_poly_project_module.f90 ply_poly_project_module.f90 sourcefile~atl_materialini_module.f90->sourcefile~ply_poly_project_module.f90

Files dependent on this one

sourcefile~~atl_materialini_module.f90~~AfferentGraph sourcefile~atl_materialini_module.f90 atl_materialIni_module.f90 sourcefile~atl_initialize_module.f90 atl_initialize_module.f90 sourcefile~atl_initialize_module.f90->sourcefile~atl_materialini_module.f90 sourcefile~atl_container_module.f90 atl_container_module.f90 sourcefile~atl_initialize_module.f90->sourcefile~atl_container_module.f90 sourcefile~atl_modg_1d_kernel_module.f90 atl_modg_1d_kernel_module.f90 sourcefile~atl_modg_1d_kernel_module.f90->sourcefile~atl_materialini_module.f90 sourcefile~atl_modg_2d_kernel_module.f90 atl_modg_2d_kernel_module.f90 sourcefile~atl_modg_2d_kernel_module.f90->sourcefile~atl_materialini_module.f90 sourcefile~atl_modg_kernel_module.f90 atl_modg_kernel_module.f90 sourcefile~atl_modg_kernel_module.f90->sourcefile~atl_materialini_module.f90 sourcefile~atl_compute_local_module.f90 atl_compute_local_module.f90 sourcefile~atl_compute_local_module.f90->sourcefile~atl_modg_kernel_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_compute_module.f90->sourcefile~atl_modg_2d_kernel_module.f90 sourcefile~atl_compute_module.f90->sourcefile~atl_modg_kernel_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_modg_1d_kernel_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_modg_2d_kernel_module.f90 sourcefile~atl_container_module.f90->sourcefile~atl_modg_kernel_module.f90 sourcefile~atl_harvesting.f90 atl_harvesting.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_initialize_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_container_module.f90 sourcefile~atl_program_module.f90 atl_program_module.f90 sourcefile~atl_harvesting.f90->sourcefile~atl_program_module.f90 sourcefile~atl_program_module.f90->sourcefile~atl_initialize_module.f90 sourcefile~atl_program_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_fwdeuler_module.f90 atl_fwdEuler_module.f90 sourcefile~atl_fwdeuler_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_imexrk_module.f90 atl_imexrk_module.f90 sourcefile~atl_imexrk_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_predcor_cerk4_module.f90 atl_predcor_cerk4_module.f90 sourcefile~atl_predcor_cerk4_module.f90->sourcefile~atl_compute_local_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_ssprk2_module.f90 atl_ssprk2_module.f90 sourcefile~atl_ssprk2_module.f90->sourcefile~atl_compute_module.f90 sourcefile~atl_global_time_integration_module.f90 atl_global_time_integration_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_fwdeuler_module.f90 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_imexrk_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 sourcefile~atl_global_time_integration_module.f90->sourcefile~atl_ssprk2_module.f90

Source Code

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

! Copyright (c) 2013 Harald Klimach <harald.klimach@uni-siegen.de>
! Copyright (c) 2013-2014 Nikhil Anand <nikhil.anand@uni-siegen.de>
! Copyright (c) 2014, 2016 Kannan Masilamani <kannan.masilamani@uni-siegen.de>
! Copyright (c) 2015, 2018, 2020 Peter Vitt <peter.vitt2@uni-siegen.de>
! Copyright (c) 2016 Verena Krupp <verena.krupp@uni-siegen.de>
! Copyright (c) 2016 Tobias Schneider <tobias1.schneider@student.uni-siegen.de>
!
! Redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions are met:
!
! 1. Redistributions of source code must retain the above copyright notice, this
! list of conditions and the following disclaimer.
!
! 2. Redistributions in binary form must reproduce the above copyright notice,
! this list of conditions and the following disclaimer in the documentation
! and/or other materials provided with the distribution.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
!--------------------------------------------
!    A O S - Array of structures layout new
!-------------------------------------------
! Access to get_point value output
! Access to get_element value output
! Copyright (c) 2013 Harald Klimach <harald.klimach@uni-siegen.de>
! Copyright (c) 2016 Tobias Schneider <tobias1.schneider@student.uni-siegen.de>
!
! Redistribution and use in source and binary forms, with or without
! modification, are permitted provided that the following conditions are met:
!
! 1. Redistributions of source code must retain the above copyright notice, this
! list of conditions and the following disclaimer.
!
! 2. Redistributions in binary form must reproduce the above copyright notice,
! this list of conditions and the following disclaimer in the documentation
! and/or other materials provided with the distribution.
!
! THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
! AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
! DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
! FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
! SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
! CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
! OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! Make sure loglvl is defined to an integer value.
! Usually this should be defined on the command line with -Dloglvl=
! to some value.

module atl_materialIni_module
  use, intrinsic :: iso_c_binding,    only: c_f_pointer
  ! Treelm modules
  use env_module,                     only: rk, labelLen
  use tem_tools_module,               only: tem_horizontalSpacer
  use tem_aux_module,                 only: tem_abort
  use treelmesh_module,               only: treelmesh_type
  use tem_element_module,             only: eT_fluid
  use tem_time_module,                only: tem_time_type
  use tem_spacetime_fun_module,       only: tem_spacetime_for,       &
    &                                       tem_st_fun_listElem_type
  use tem_topology_module,            only: tem_levelOf
  use tem_faceData_module,            only: tem_invFace_map, &
    &                                       tem_left,        &
    &                                       tem_right
  use tem_grow_array_module,          only: grw_intArray_type, &
    &                                       init,              &
    &                                       append,            &
    &                                       destroy
  use tem_dyn_array_module,           only: dyn_intArray_type, &
    &                                       init,              &
    &                                       append,            &
    &                                       destroy,           &
    &                                       PositionOfVal
  use tem_logging_module,             only: logUnit,   &
    &                                       llerror,   &
    &                                       llwarning, &
    &                                       llinfo,    &
    &                                       lldebug
  use tem_comm_module,                only: tem_commPattern_type
  use tem_comm_env_module,            only: tem_comm_env_type
  use tem_varSys_module,              only: tem_varSys_type,              &
    &                                       tem_varSys_op_type,           &
    &                                       tem_varSys_append_derVar,     &
    &                                       tem_varSys_proc_point,        &
    &                                       tem_varSys_proc_element,      &
    &                                       tem_varSys_proc_setParams,    &
    &                                       tem_varSys_proc_getParams,    &
    &                                       tem_varSys_proc_setupIndices, &
    &                                       tem_varSys_proc_getValOfIndex
  use tem_varMap_module,              only: tem_variable_loadMapping,           &
    &                                       tem_possible_variable_type
  use tem_stringKeyValuePair_module,  only: grw_stringKeyValuePairArray_type, &
    &                                       init
  use tem_timer_module,               only: tem_startTimer, &
    &                                       tem_stopTimer

  ! Aotus modules
  use aotus_module,                   only: flu_State, &
    &                                       aot_get_val
  use aot_table_module,               only: aot_table_open, &
    &                                       aot_table_close

  ! Ateles modules
  use atl_timer_module,               only: atl_timerHandles, atl_elemTimers
  use atl_equation_module,            only: atl_equations_type
  use atl_eqn_maxwelldivcorr_var_module, &
    &                                 only: atl_getMaxPropSpeedDivCor
  use atl_eqn_maxwell_var_module,     only: atl_getMaxPropSpeed
  use atl_boundary_module,            only: atl_level_boundary_type
  use atl_parallel_module,            only: atl_init_faceStateBuffer
  use atl_scheme_module,              only: atl_modg_scheme_prp,    &
    &                                       atl_modg_2d_scheme_prp, &
    &                                       atl_modg_1d_scheme_prp
  use atl_reference_element_module,   only: atl_refToPhysCoord
  use atl_cube_elem_module,           only: atl_cube_elem_type
  use atl_scheme_module,              only: atl_scheme_type
  use atl_varSys_module,              only: atl_varSys_solverData_type,  &
    &                                       atl_get_new_varSys_data_ptr
  use atl_materialPrp_module,         only: atl_mixedMat_prp,               &
    &                                       atl_pureConstMat_prp,           &
    &                                       atl_material_type,              &
    &                                       atl_spacetime_fun_pointer_type, &
    &                                       atl_ConstMatIdx,                &
    &                                       atl_VarMatIdx,                  &
    &                                       atl_init_material_type
  use atl_materialFun_module,         only: atl_materialFun_type, &
    &                                       atl_mode_reduction_type

  ! Polynomials modules
  use ply_poly_project_module,        only: ply_get_quadpoints_faces,    &
    &                                       ply_get_quadpoints_faces_2d, &
    &                                       ply_get_quadpoints_faces_1d, &
    &                                       ply_poly_project_type

  implicit none

  private

  public :: atl_init_materialParams
  public :: atl_update_materialParams
  ! Made public solely for unit test access.
  public ::                        &
    & atl_create_materialElemList, &
    & atl_append_newMaterialVars

contains

  ! ****************************************************************************
  !> This routine implements the getElement interface for material variables.
  !!
  !! Material variables basically refer to spacetime functions which are
  !! already present in the varSys. This spacetime function variable is the
  !! only input variable for the material variable. Thus the solely purpose of
  !! this routine is to forward any getElement request to the material variable
  !! to the correspondig spacetime function variable.
  subroutine atl_getMaterialForElement( fun, varsys, elempos, time, tree, &
    &                                   nElems, nDofs, res                )
    ! --------------------------------------------------------------------------

    !> Description of the method to obtain the variables, here some preset
    !! values might be stored, like the spacetime function to use or the
    !! required variables.
    class(tem_varSys_op_type), intent(in) :: fun

    !> The variable system to obtain the variable from.
    type(tem_varSys_type), intent(in)     :: varSys

    !> Position of the TreeID of the element to get the variable for in the
    !! global treeID list.
    integer, intent(in)                   :: elempos(:)

    !> Point in time at which to evaluate the variable.
    type(tem_time_type), intent(in)       :: time

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

    !> Number of values to obtain for this variable (vectorized access).
    integer, intent(in)                   :: nElems

    !> Number of degrees of freedom within an element.
    integer, intent(in)                   :: nDofs

    !> Resulting values for the requested variable.
    !!
    !! Linearized array dimension:
    !! (n requested entries) x (nComponents of this variable)
    !! x (nDegrees of freedom)
    !! Access: (iElem-1)*fun%nComponents*nDofs +
    !!         (iDof-1)*fun%nComponents + iComp
    real(kind=rk), intent(out)            :: res(:)
    ! --------------------------------------------------------------------------

    call varSys%method%val(fun%input_varPos(1))%get_element( &
      & varSys  = varSys,                                    &
      & elempos = elempos,                                   &
      & time    = time,                                      &
      & tree    = tree,                                      &
      & nElems  = nElems,                                    &
      & nDofs   = nDofs,                                     &
      & res     = res                                        )

  end subroutine atl_getMaterialForElement
  ! ****************************************************************************


  ! ****************************************************************************
  !> This routine implements the getPoint interface for material variables.
  !!
  !! Material variables basically refer to spacetime functions which are
  !! already present in the varSys. This spacetime function variable is the
  !! only input variable for the material variable. Thus the solely purpose of
  !! this routine is to forward any getPoint request to the material variable
  !! to the correspondig spacetime function variable.
  subroutine atl_getMaterialForPoint(fun, varsys, point, time, tree, nPnts, res)
    ! --------------------------------------------------------------------------
    !> Description of the method to obtain the variables, here some preset
    !! values might be stored, like the spacetime function to use or the
    !! required variables.
    class(tem_varSys_op_type), intent(in) :: fun

    !> The variable system to obtain the variable from.
    type(tem_varSys_type), intent(in) :: varSys

    !> Three-dimensional coordinates at which the variable should be
    !! evaluated. Only useful for variables provided as space-time functions.
    real(kind=rk), intent(in) :: point(:,:)

    !> Point in time at which to evaluate the variable.
    type(tem_time_type), intent(in)  :: time

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

    !> Number of values to obtain for this variable (vectorized access).
    integer, intent(in) :: nPnts

    !> Resulting values for the requested variable.
    !!
    !! Dimension: n requested entries x nComponents of this variable
    !! Access: (iElem-1)*fun%nComponents + iComp
    real(kind=rk), intent(out) :: res(:)
    ! --------------------------------------------------------------------------

    call varSys%method%val(fun%input_varPos(1))%get_point( varSys = varSys, &
      &                                                    point  = point,  &
      &                                                    time   = time,   &
      &                                                    tree   = tree,   &
      &                                                    nPnts  = nPnts,  &
      &                                                    res    = res     )

  end subroutine atl_getMaterialForPoint
  ! ****************************************************************************


  ! ****************************************************************************
  !> Adds the configured material variables to the variable system.
  !!
  !! All variables in \ref variables are added to the varSys. Their getPoint
  !! and getElement routines are confgured to retrieve their data from the
  !! corresponding spacetime function that was already added to the varSys.
  subroutine atl_append_newMaterialVars( varSys, varSys_data, poss_matVars,    &
    &                                    materialFun, variables                )
    ! --------------------------------------------------------------------------
    !> The variable system to which the souce variables have to be added
    type(tem_varSys_type), intent(inout) :: varSys
    !> Data of the variable System
    type(atl_varSys_solverData_type), intent(inout), target :: varSys_data
    !! index of the eval-source_routine in eval_source.
    type(tem_possible_variable_type) :: poss_matVars
    type(atl_materialFun_type), intent(inout) :: materialFun
    type(grw_stringKeyValuePairArray_type), intent(inout) :: variables
    ! --------------------------------------------------------------------------
    integer :: addedAtPos, iMat, iVar, nComponents, varPos
    integer :: iStFun
    integer :: inputVarPos
    character(labellen) :: varname, inputVarName
    logical :: wasAdded
    type(tem_st_fun_listElem_type), pointer :: stFunList
    procedure(tem_varSys_proc_point), pointer :: get_point
    procedure(tem_varSys_proc_element), pointer :: get_element
    procedure(tem_varSys_proc_setParams), pointer :: set_params
    procedure(tem_varSys_proc_getParams), pointer :: get_params
    procedure(tem_varSys_proc_setupIndices), pointer ::setup_indices
    procedure(tem_varSys_proc_getValOfIndex), pointer :: get_ValOfIndex
    ! --------------------------------------------------------------------------

    get_point => atl_getMaterialForPoint
    get_element => atl_getMaterialForElement
    set_params => null()
    get_params => null()
    setup_indices => null()
    get_ValOfIndex => NULL()

    materialFun%nMat = 0
    allocate( materialFun%nScalars( poss_matVars%varname%nVals ) )
    allocate( materialFun%matvar_pos( poss_matVars%varname%nVals ) )
    allocate( materialFun%matParNames( poss_matVars%varname%nVals ) )

    materialFun%is_transient = .false.

    ! loop over all present material variables
    do iVar = 1, poss_matVars%varname%nVals
      varname = ''
      do iMat = 1, variables%nVals

        if ( trim(variables%val(iMat)%key) &
          &  == trim(poss_matVars%varname%val(iVar)) ) then


          ! Here we add the source variable specific spacetime function as the
          ! last input variable. The state variables in the first slots stay
          ! unchanged.
          inputVarName = variables%val(iMat)%value

          varPos = PositionOfVal( me  = varSys%varName,    &
            &                     val = trim(inputVarName) )

          nComponents = poss_matVars%nComponents%val(iVar)

          ! Check whether the input variable is able to provide as much
          ! components as the material expects
          if (nComponents /= varSys%method%val(varPos)%nComponents) then
            call tem_abort( "Source variable for material "          &
              & // trim(variables%val(iMat)%key)                     &
              & // " doesn't have the correct number of components." )
          endif

          ! get the name of the current variable and prefix it with mat_ as it
          ! is a material parameter. Without prefixing, it wouldn't be possible
          ! to define a user defined variable in the variable table that has the
          ! name of the material parameter. This handling of the variable names
          ! is equal to the name handling for source variables.
          varname = 'mat_' // trim(variables%val(iMat)%key)

          EXIT
        end if
      end do

      if (varname /= '') then
        call tem_varSys_append_derVar(                                 &
          & me             = varSys,                                   &
          & varName        = varname,                                  &
          & operType       = 'material',                               &
          & nComponents    = nComponents,                              &
          & input_varname  = (/ inputVarName /),                       &
          & method_data    = atl_get_new_varSys_data_ptr(varSys_data), &
          & get_point      = get_point,                                &
          & get_element    = get_element,                              &
          & set_params     = set_params,                               &
          & get_params     = get_params,                               &
          & setup_indices  = setup_indices,                            &
          & get_valOfIndex = get_valOfIndex,                           &
          & pos            = addedAtPos,                               &
          & wasAdded       = wasAdded                                  )

        if (wasAdded) then
          materialFun%nMat = materialFun%nMat + 1
          materialFun%nScalars( materialFun%nMat ) = nComponents
          materialFun%matvar_pos( materialFun%nMat ) = addedAtPos
          materialFun%matParNames( materialFun%nMat ) = varName
          ! We expect only one input variable, which is the variable containing
          ! the spacetime functions. Thus we hard-code index 1 here.
          inputVarPos = varSys%method%val(addedAtPos)%input_varPos(1)
          ! Now that we have the position of the lua variable, we can cast the
          ! list of spacetime functions for this variable, which is pointed to
          ! by the method data, back into a Fortran type to iterate over it.
          call c_f_pointer(varSys%method%val(inputVarPos)%method_data, &
            &              stFunList)
          do iStFun = 1, stFunList%nVals
            select case(trim(stFunList%val(iStFun)%fun_kind))
            case ('const')
              ! Nothing to do, keep the assumption, that the material is not
              ! transient.
            case ('combined')
              if (trim(stFunList%val(iStFun)%temporal%kind) /= 'const') then
                materialFun%is_transient = .true.
              end if
            case default
              materialFun%is_transient = .true.
            end select
          end do
        else

          write(logUnit(llerror),*) 'Error: variable ' // trim(varname) &
            & // ' was not added to the variable system.'

        end if

      else ! if (varname /= '')

        ! No definition for one of the materials found.
        ! FAIL now.
        !> @todo We might use default settings here instead, if applicable, as
        !!       for example for the conductivity in maxwell equations.
        !!       However, the behavior should be configured by the equation
        !!       system. Maybe this could also be handled when loading the
        !!       materials instead.
        write(logunit(llerror),*) 'FAILED to find a definition for ' &
          & // trim(poss_matVars%varname%val(iVar))
        write(logunit(llerror),*) 'You need to define a variable for this in' &
          & // ' the material table!'
        call tem_abort( 'Not knowing what to do, ABORTING...' )

      end if

    end do

  end subroutine atl_append_newMaterialVars
  ! ****************************************************************************


  ! ****************************************************************************
  !> Reassigns the spacetime function pointers based on the material variable
  !! position and the spacetime function position.
  subroutine atl_reassignStFunPtr( varSys, tree, material_list, iLevel, iDir, &
    &                              iMat                                       )
    ! --------------------------------------------------------------------------
    !> global variable system to which luaVar to be appended
    type(tem_varSys_type), intent(in) :: varSys
    !> Mesh data in treelmesh format.
    type(treelmesh_type), intent(in) :: tree
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: &
      & material_list(tree%global%minLevel:tree%global%maxLevel)
    integer, intent(in) :: iLevel
    integer, intent(in) :: iDir
    integer, intent(in) :: iMat
    ! --------------------------------------------------------------------------
    integer :: iFace, iLR, matVarPos, stFunPos, nFaces
    type(tem_st_fun_listElem_type), pointer :: stFunList
    ! --------------------------------------------------------------------------

    nFaces = size( material_list(iLevel)%material_desc       &
          &                             %material_face(iDir) &
          &                             %mat,                &
          &         1                                        )
    do iFace=1,nFaces
      do iLR=1,2
        matVarPos = material_list(iLevel)%material_desc          &
          &                              %material_face(iDir)    &
          &                              %mat(iFace, iLR, iMat)  &
          &                              %matVarPos
        ! There are situations where not all faces have material assigned. This
        ! is due to the fact that the array is oversized to also contain
        ! boundary faces, which are not necessarily initialized yet. Thus we
        ! have to check for valid matVarPos. We assume that stFunPos is set to a
        ! meaningful value when matVarPos is within the valid range.
        if ( (matVarPos > 0) .and. (matVarPos <= varSys%method%nVals) ) then
          stFunPos = material_list(iLevel)%material_desc         &
            &                             %material_face(iDir)   &
            &                             %mat(iFace, iLR, iMat) &
            &                             %stFunPos
          call c_f_pointer( cptr = varSys%method%val(matVarPos)%method_data, &
            &               fptr = stFunList                                 )
          material_list(iLevel)%material_desc         &
            &                  %material_face(iDir)   &
            &                  %mat(iFace, iLR, iMat) &
            &                  %stFunPtr              &
            & => stFunList%val(stFunPos)
        end if
      end do
    end do

  end subroutine atl_reassignStFunPtr
  ! ****************************************************************************

  ! ****************************************************************************
  !> Read the configuration for the material paramters for Maxwell equations
  !! from configuration files and init the material parameter datatype.
  subroutine atl_init_materialParams( equation, tree, varSys_data,           &
    &                                 material_list, mesh_list, scheme_list, &
    &                                 boundary_list, time, conf, proc,       &
    &                                 commPattern, poly_proj_list,           &
    &                                 levelpointer, initMaterial             )
    ! --------------------------------------------------------------------------
    !> Description on the equation system to solve.
    type(atl_Equations_type), intent(inout) :: equation
    !> Mesh data in treelmesh format.
    type(treelmesh_type), intent(in) :: tree
    !> Data in variable system
    type(atl_varSys_solverData_type), intent(inout) :: varSys_data
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: &
      & material_list(tree%global%minLevel:tree%global%maxLevel)
    !> Description of the mesh
    type(atl_cube_elem_type), intent(inout) :: &
      & mesh_list(tree%global%minLevel:tree%global%maxLevel)
    !> Information about the scheme
    type(atl_scheme_type), intent(in) :: &
      & scheme_list(tree%global%minLevel:tree%global%maxLevel)
    !> Global description of the boundary conditions.
    type(atl_level_boundary_type), intent(in) :: &
      & boundary_list(tree%global%minLevel:tree%global%maxLevel)
    !> The current simulation time
    type(tem_time_type), intent(in) :: time
    !> Flu binding to configuration file.
    type(flu_State), intent(inout) :: conf
    !> 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
    !> unique list for projection methods
    type(ply_poly_project_type), intent(inout)  :: poly_proj_list(:)
    !> Pointer from treeIDlist entry to level-wise fluid part of total list.
    !! The length of this vector is the total number of cubic elements.
    integer, intent(in) :: levelPointer(:)
    !> Information about expected material parameters and the user defined
    !! variables to the expected material parameters.
    type(atl_init_material_type) :: initMaterial
    ! --------------------------------------------------------------------------
    integer :: iMat, iLevel, iDir, iLR, iError, iProc
    integer :: nFaces, nElemsCons, nElemsVar, nquadpoints, nScalars, nBcs
    integer :: nConstFace, nVarFace
    integer :: tblHandle, matTblHandle
    integer :: projectionPos
    character(len=labelLen), allocatable :: materials(:)
    ! --------------------------------------------------------------------------

    ! initialize just to silence a compiler warning, will be overwritten later
    ! on
    nquadpoints = 0

    call tem_horizontalSpacer(fUnit=logUnit(llerror))
    call aot_table_open( L       = conf,      &
      &                  thandle = tblHandle, &
      &                  key     = "equation" )
    if( tblHandle > 0 ) then
      ! Initilized keyValuePair dict for material
      call init( me = initMaterial%materialDict )

      ! Read the enabled state for mode reduction from the equation.material
      ! table.
      call aot_table_open( L       = conf,         &
        &                  parent  = tblHandle,    &
        &                  thandle = matTblHandle, &
        &                  key     = 'material'    )
      call aot_get_val( L       = conf,                                     &
        &               thandle = matTblHandle,                             &
        &               key     = 'mode_reduction',                         &
        &               val     = equation%material%mode_reduction%enabled, &
        &               default = .false.,                                  &
        &               ErrCode = iError                                    )
      call aot_get_val( L       = conf,                                       &
        &               thandle = matTblHandle,                               &
        &               key     = 'reduction_threshold',                      &
        &               val     = equation%material%mode_reduction%threshold, &
        &               default = 1.0_rk,                                     &
        &               ErrCode = iError                                      )
      call aot_table_close( conf, matTblHandle )
      write(logUnit(1),'(A,L5)') 'Mode reduction for flux computation: ', &
        & equation%material%mode_reduction%enabled
      write(logUnit(1),'(A,F8.2)') 'Mode reduction threshold: ', &
        & equation%material%mode_reduction%threshold

      ! Read the material mapping from the equation table. A mapping is a
      ! reference from an (anonymous) variable to a material parameter.
      call tem_variable_loadMapping(                               &
        &    possVars            = initMaterial%poss_materialVars, &
        &    conf                = conf,                           &
        &    parent              = tblHandle,                      &
        &    key                 = "material",                     &
        &    varSys              = equation%varSys,                &
        &    varDict             = initMaterial%materialDict       )

      call aot_table_close( conf, tblHandle )

    end if
    call atl_append_newMaterialVars(                   &
      & varSys       = equation%varSys,                &
      & varSys_data  = varSys_data,                    &
      & poss_matVars = initMaterial%poss_materialVars, &
      & materialFun  = equation%material,              &
      & variables    = initMaterial%materialDict       )

    ! Material to use for decision whether to reduce order if constant.
    ! Default is to not use mode reduction, for this we set matpos to
    ! a negative value, so it will not match any material.
    equation%material%mode_reduction%matPos = -1
    if (equation%material%mode_reduction%enabled) then
      select case(equation%eq_kind)
      case('euler', 'navier_stokes','euler_2d', 'navier_stokes_2d', &
        &     'filtered_navier_stokes', 'euler_1d', 'filtered_navier_stokes_2d')
        ! Base decision for reduced order on Chi (masking), which will be found
        ! as first material in the flow equations.
        equation%material%mode_reduction%matPos = 1
      end select
    end if

    ! Store the positions of variables acting as data providers for materials
    ! in a sepparate list.
    allocate(materials(equation%material%nMat))
    do iMat=1, equation%material%nMat
      materials(iMat) = equation%varSys                                  &
        &                       %varname                                 &
        &                       %val( equation%material%matvar_pos(iMat) )
    end do

    ! Assing the material variables to the elements
    call atl_assign_elem_varProp(          &
      & tree           = tree,             &
      & mesh_list      = mesh_list,        &
      & affection_list = material_list,    &
      & levelPointer   = levelPointer,     &
      & varSys         = equation%varSys,  &
      & materialFun    = equation%material )

    ! create the element index list differentiating elements with
    ! constant and non-constant material parameters.
    call atl_create_materialElemList(      &
      & tree          = tree,              &
      & levelPointer  = levelPointer,      &
      & material_list = material_list,     &
      & materialFun   = equation%material, &
      & varSys        = equation%varSys,   &
      & materials     = materials          )

    nScalars = sum(equation%material%nScalars)

    do iLevel = tree%global%minlevel, tree%global%maxlevel
      do iProc = 1, mesh_list(iLevel)%descriptor%recvbuffer%nProcs
        call commPattern%initBuf_int(       &
          &    me    = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %recvBuffer        &
          &              %buf_int(iProc),   &
          &    pos   = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %recvBuffer        &
          &              %elemPos(iProc)    &
          &              %val,              &
          &    nVals = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %recvBuffer        &
          &              %nElemsProc(iProc) )
      end do
      do iProc = 1, mesh_list(iLevel)%descriptor%sendbuffer%nProcs
        call commPattern%initBuf_int(       &
          &    me    = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %sendBuffer        &
          &              %buf_int(iProc),   &
          &    pos   = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %sendBuffer        &
          &              %elemPos(iProc)    &
          &              %val,              &
          &    nVals = mesh_list(iLevel)    &
          &              %descriptor        &
          &              %sendBuffer        &
          &              %nElemsProc(iProc) )
      end do

      ProjectionPos = material_list(iLevel)%poly_proj_pos
      nElemsCons = material_list(iLevel)%material_desc                 &
        &                               %computeElems(atl_ConstMatIdx) &
        &                               %nElems
      nElemsVar = material_list(iLevel)%material_desc               &
        &                              %computeElems(atl_VarMatIdx) &
        &                              %nElems
      material_list(iLevel)%material_dat                      &
        &                  %elemMaterialData(atl_ConstMatIdx) &
        &                  %nPointsPerDir &
        & = 1
      material_list(iLevel)%material_dat                  &
        &                  %elemMaterialData(2)           &
        &                  %nPointsPerDir                 &
        & = poly_proj_list(ProjectionPos)%nquadpointsperDir

      select case(scheme_list(iLevel)%scheme)
      case(atl_modg_scheme_prp)
        ! get correct amount of  number of points on the face
        nquadpoints = poly_proj_list(ProjectionPos)%body_3D%nquadpoints
      case(atl_modg_2d_scheme_prp)
        ! get correct amount of  number of points on the face
        nquadpoints = poly_proj_list(ProjectionPos)%body_2D%nquadpoints
      case(atl_modg_1d_scheme_prp)
        ! get correct amount of  number of points on the face
        nquadpoints = poly_proj_list(ProjectionPos)%body_1D%nquadpoints
      case default
        call tem_abort( 'ERROR in atl_init_materialParams: scheme not known' )
      end select

      allocate( material_list(iLevel)%material_dat                           &
        &                            %elemMaterialData(atl_ConstMatIdx)      &
        &                            %materialDat( nElemsCons, 1, nScalars ) )
      allocate( material_list(iLevel)%material_dat                    &
        &                            %elemMaterialData(atl_varMatIdx) &
        &                            %materialDat( nElemsVar,         &
        &                                          nquadpoints,       &
        &                                          nScalars )         )
      allocate( material_list(iLevel)%material_dat%mode_reducable( &
        &         mesh_list(iLevel)%descriptor%nElems)             )
      material_list(iLevel)%material_dat%mode_reducable = .false.

      ! Evaluate all material properties for the fluid elements (i.e. the
      ! element that are added to the computeElems variable of material_desc
      ! on each level)
      projectionPos = material_list(iLevel)%poly_proj_pos
      call atl_evalElemMaterial(                             &
        & mesh           = mesh_list(iLevel),                &
        & scheme         = scheme_list(iLevel),              &
        & material       = material_list(iLevel),            &
        & materialFun    = equation%material,                &
        & time           = time,                             &
        & mode_reduction = equation%material%mode_reduction, &
        & poly_proj      = poly_proj_list(projectionPos),    &
        & proc           = proc,                             &
        & commPattern    = commPattern                       )

      do iDir = 1, equation%nDimensions

        nFaces = mesh_list(iLevel)%faces%faces(iDir)%faceList%faceId%nVals

        ! Allocate space for the face material information for all faces, i.e.
        ! fluid, ghost, halos, etc. in advance
        ! The allocation has to be done before calling atl_assign_face_matPrp
        ! as this call is done levelwise, but currentLevel+1 is being accessed
        ! inside the routine. So we need to allocate the complete array
        ! beforehand.
        allocate( material_list(iLevel)%material_desc                 &
          &                            %material_face( iDir )         &
          &                            %mat( nFaces,                  &
          &                                  2,                       &
          &                                  equation%material%nMat ) )
        material_list(iLevel)%material_desc &
          &                  %material_face( iDir ) &
          &                  %mat &
          &                  %matVarPos = 0
        material_list(iLevel)%material_desc &
          &                  %material_face( iDir ) &
          &                  %mat &
          &                  %stFunPos = 0
      end do
    end do

    ! Now material lists for all levels have been created and we can
    ! inherit information from one to the next as needed.
    do iLevel = tree%global%minlevel, tree%global%maxlevel
      ! Assign the material properties to all faces in a recursive way with
      ! inheritance to cover local refinement)
      ! Note that this includes modifications of the next finer level.
      call atl_assign_face_matPrp(              &
        & mesh_list     = mesh_list,            &
        & material_list = material_list,        &
        & materialFun   = equation%material,    &
        & spatial_dim   = equation%nDimensions, &
        & currentLevel  = iLevel,               &
        & maxLevel      = tree%global%maxlevel, &
        & minLevel      = tree%global%minlevel  )

      ! Init the integer buffers to communicate the material
      ! information.
      call atl_init_faceStateBuffer( nFaceDofs   = 1,                       &
        &                            faces       = mesh_list(iLevel)%faces, &
        &                            nValsState  = 1,                       &
        &                            nValsFlux   = 1,                       &
        &                            boundary    = boundary_list(iLevel),   &
        &                            initRealBuf = .false.,                 &
        &                            commPattern = commPattern              )

      ! Communicate the material properties for the faces
      do iMat = 1, equation%material%nMat
        do iDir = 1, equation%nDimensions
          do iLR = tem_left, tem_right
            call commPattern%exchange_int(                                &
              & send         = mesh_list(iLevel)%faces                    &
              &                                 %faces(iDir)              &
              &                                 %sendBuffer_state(iLR),   &
              & recv         = mesh_list(iLevel)%faces                    &
              &                                 %faces(iDir)              &
              &                                 %recvBuffer_state(iLR),   &
              & state        = material_list(iLevel)%material_desc        &
              &                                     %material_face(iDir)  &
              &                                     %mat(:,:,iMat)        &
              &                                     %stFunPos,            &
              & message_flag = iLevel,                                    &
              & comm         = proc%comm                                  )
            call commPattern%exchange_int(                                &
              & send         = mesh_list(iLevel)%faces                    &
              &                                 %faces(iDir)              &
              &                                 %sendBuffer_state(iLR),   &
              & recv         = mesh_list(iLevel)%faces                    &
              &                                 %faces(iDir)              &
              &                                 %recvBuffer_state(iLR),   &
              & state        = material_list(iLevel)%material_desc        &
              &                                     %material_face(iDir)  &
              &                                     %mat(:,:,iMat)        &
              &                                     %matVarPos,           &
              & message_flag = iLevel,                                    &
              & comm         = proc%comm                                  )
          end do

          ! There are pointers included in the data exchange above. But the data
          ! exchange can be across ranks, so we have to redo the pointers to
          ! make sure that we have the correct adresses for the current rank.
          call atl_reassignStFunPtr( varSys        = equation%varSys, &
            &                        tree          = tree,            &
            &                        material_list = material_list,   &
            &                        iLevel        = iLevel,          &
            &                        iDir          = iDir,            &
            &                        iMat          = iMat             )

        end do
      end do

      ! Create new compute lists, depending on the combinations
      ! of material properties.
      call atl_create_materialComputeList(     &
        & mesh        = mesh_list(iLevel),     &
        & spatial_dim = equation%nDimensions,  &
        & material    = material_list(iLevel), &
        & materialFun = equation%material      )

      ! Evaluate all material properties for the compute faces (left + right
      ! element). Allocate face data in materialDat in advance
      ProjectionPos = material_list(iLevel)%poly_proj_pos
      do iDir = 1, equation%nDimensions
        select case(scheme_list(iLevel)%scheme)
        case(atl_modg_scheme_prp)
          ! detect the correct number of points on the face due to projection
          ! it is assumed that on left and right face thre is the same amount
          ! of points further is the number of points in a spatial direction
          ! for all dimension equal
          nquadpoints = poly_proj_list(ProjectionPos)%body_3D       &
            &                                        %faces(idir,2) &
            &                                        %nquadpoints
        case(atl_modg_2d_scheme_prp)
          nquadpoints = poly_proj_list(ProjectionPos)%body_2D       &
            &                                        %faces(idir,2) &
            &                                        %nquadpoints
        case(atl_modg_1d_scheme_prp)
          nquadpoints = poly_proj_list(ProjectionPos)%body_1D       &
            &                                        %faces(idir,2) &
            &                                        %nquadpoints
        case default
          call tem_abort( 'ERROR in atl_initMaterialParams: not able to ' &
            & // 'get nquadpoints for evaluate material parameters for '  &
            & // 'this scheme, stopping ...'                              )
        end select

        nConstFace = size(                                                &
          & material_list(iLevel)%material_desc                           &
          &                      %computeFace(iDir, atl_pureConstMat_prp) &
          &                      %facePos                                 )
        nVarFace = size(                                             &
          & material_list(iLevel)%material_desc                      &
          &                      %computeFace(iDir,atl_mixedMat_prp) &
          &                      %facePos                            )

        allocate(material_list(iLevel)%material_dat                          &
          &                           %faceMaterialData(iDir, atl_varMatIdx) &
          &                           %leftElemMaterialDat( nVarFace,        &
          &                                                 nquadpoints,     &
          &                                                 nScalars)        )
        allocate(material_list(iLevel)%material_dat                          &
          &                           %faceMaterialData(iDir, atl_varMatIdx) &
          &                           %rightElemMaterialDat( nVarFace,       &
          &                                                  nquadpoints,    &
          &                                                  nScalars)       )
        allocate( &
          & material_list(iLevel)%material_dat                            &
          &                      %faceMaterialData(iDir, atl_constMatIdx) &
          &                      %leftElemMaterialDat( nConstFace,        &
          &                                            1,                 &
          &                                            nScalars)          )
        allocate( &
          & material_list(iLevel)%material_dat                            &
          &                      %faceMaterialData(iDir, atl_constMatIdx) &
          &                      %rightElemMaterialDat( nConstFace,       &
          &                                             1,                &
          &                                             nScalars)         )
      end do

      call atl_evalFaceMaterial(                             &
        & mesh           = mesh_list(iLevel),                &
        & scheme         = scheme_list(iLevel),              &
        & material       = material_list(iLevel),            &
        & materialFun    = equation%material,                &
        & time           = time,                             &
        & spatial_dim    = equation%nDimensions,             &
        & poly_proj      = poly_proj_list(ProjectionPos)     )

      ! Create list of boundary faces, depending on the combinations
      ! of material properties.
      nBCs = boundary_list(iLevel)%nBcs
      allocate( material_list(iLevel)%material_desc              &
        &                            %bnd_faces(atl_constMatIdx) &
        &                            %boundary                   &
        &                            %bnd( nBCs )                )
      allocate( material_list(iLevel)%material_desc            &
        &                            %bnd_faces(atl_varMatIdx) &
        &                            %boundary                 &
        &                            %bnd( nBCs )              )
      call atl_create_materialBoundaryList(    &
        & material    = material_list(iLevel), &
        & materialFun = equation%material,     &
        & mesh        = mesh_list(iLevel),     &
        & boundary    = boundary_list(iLevel)  )
    end do

    ! Check for Maxwell equations
    select case(equation%eq_kind)
    case('maxwell','maxwell_2d')
      ! Get the maximum information propagation speed in the domain, e.g. the
      ! speed of light which soleny depends on the material parameters.
      call atl_getMaxPropSpeed( tree          = tree,              &
        &                       materialFun   = equation%material, &
        &                       material_list = material_list      )

    case('maxwelldivcorrection')
      ! Get the maximum information propagation speed in the domain, e.g. the
      ! speed of light which soleny depends on the material parameters.
      call atl_getMaxPropSpeedDivCor( tree          = tree,              &
        &                             materialFun   = equation%material, &
        &                             material_list = material_list      )

    end select

    deallocate(materials)

    call tem_horizontalSpacer(fUnit = logUnit(1))

  end subroutine atl_init_materialParams
  ! ****************************************************************************


  ! ****************************************************************************
  !> Assign reference to spacetime functions to the affected elements. This
  !! means: The position of the variable in the variable system, which reflects
  !! the spacetime function is determined and assigned to the element_list.
  !!
  !! This assignment is done as follows:
  !! 1. Set each fluid element's spacetime function pointer to null
  !! 2. Iterate over all material variables
  !! 2.1 Iterate over the first input variable's spacetime function list
  !! 2.1.a If it is a global shape spacetime function, have all element's
  !!       material stfun pointer set to this spacetime function.
  !! 2.1.b Take the spacetime function subtree and assign this spacetime
  !!       function to all element's material stfun pointer in this subtree.
  !! 2.2 Iterate over all elements and check whether their stfun pointer is
  !!     associated, which means, that the material is defined for the element.
  !!
  !! If there is one or more elements that are not covered by all materials, the
  !! solver will abort.
  subroutine atl_assign_elem_varProp( tree, mesh_list, affection_list,  &
    &                                 levelPointer, varSys, materialFun )
    ! ---------------------------------------------------------------------------
    !> The global description of the tree.
    type(treelmesh_type), intent(in) :: tree
    !> List of  mesh for different kernels
    type(atl_cube_elem_type), intent(in)  :: mesh_list( &
             &  tree%global%minlevel:tree%global%maxlevel)
    !> The description of the material properties on the element basis.
    type(atl_material_type), intent(inout) :: &
             & affection_list(tree%global%minlevel:tree%global%maxlevel)
    integer, intent(in)  :: levelPointer(:)
    !> global variable system to which luaVar to be appended
    type(tem_varSys_type), intent(in) :: varSys
    !> The list of material variable indizes.
    type(atl_materialFun_type), intent(in) :: materialFun
    ! ---------------------------------------------------------------------------
    integer :: nfluids, elemPos, levelElemPos
    integer :: iLevel, iMat, iElem, iStFun, varPos, inputVarPos
    type(tem_st_fun_listElem_type), pointer :: stFunList
    logical :: allElemsDefined
    ! ---------------------------------------------------------------------------

    do iLevel = tree%global%minlevel,tree%global%maxlevel
      ! Create array for all fluid properties
      nfluids = mesh_list(ilevel)%descriptor%elem%nElems(eT_fluid)
      allocate( affection_list(iLevel)%material_desc%material_elems( &
        & nfluids, size(materialFun%matvar_pos) ) )
      ! We don't have a global material anymore, thus we assign null here. Later
      ! on we check for elements with null, which indicates holes in the user
      ! defined shapes. If we find those holes, we report them as error.
      do iElem = 1, nFluids
        do iMat = 1, size( materialFun%matvar_pos )
          affection_list(iLevel)%material_desc               &
            &                   %material_elems(iElem, iMat) &
            &                   %stFunPtr                    &
            & => null()

        end do
      end do
    end do

    ! Iterate over all the materials and overwrite the material properties
    ! that have been defined before hand.
    do iMat = 1, size(materialFun%matvar_pos)
      ! get the position of the spacetime function in the varSys for the
      ! current material
      varPos = materialFun%matvar_pos(iMat)

      write(logUnit(lldebug),*) "Material at index ", iMat,    &
        & " refers to variable at index ", varPos, " called ", &
        & trim(varSys%varName%val(varPos)), " with ",          &
        & varSys%method%val(varPos)%nComponents, " components"

      ! We expect only one input variable, which is the variable containing the
      ! spacetime functions. Thus we hard-code index 1 here.
      inputVarPos = varSys%method%val(varPos)%input_varPos(1)

      write(logUnit(lldebug),*) "This variable uses the variable at index ", &
        & inputVarPos, " called ", trim(varSys%varName%val(inputVarPos)),    &
        & " as input."

      ! Now that we have the position of the lua variable, we can cast the
      ! list of spacetime functions for this variable, which is pointer to
      ! by the method data, back into a Fortran type to iterate over it.
      call c_f_pointer(varSys%method%val(inputVarPos)%method_data, stFunList)

      do iStFun = 1, stFunList%nVals
        if (stFunList%val(iStFun)%subTree%useGlobalMesh) then
          do iElem = 1, tree%nElems
            ! Make use of the levelpointer to read out level and position in the
            ! levewise list of elements.
            iLevel = tem_levelOf( tree%treeid(iElem) )
            levelElemPos = levelPointer(iElem)
            call assignStFunPointer( affection_list = affection_list, &
              &                      stFunList      = stFunList,      &
              &                      iLevel         = iLevel,         &
              &                      iMat           = iMat,           &
              &                      iStFun         = iStFun,         &
              &                      levelElemPos   = levelElemPos,   &
              &                      inputVarPos    = inputVarPos     )
          end do
        else
          do iElem = 1, stFunList%val(iStFun)%subTree%nElems
            ! We read out the position in current partition of the original
            ! tree.
            elemPos = stFunList%val(iStFun)%subTree%map2global(iElem)
            ! Make use of the levelpointer to read out level and position in the
            ! levewise list of elements.
            iLevel = tem_levelOf( tree%treeid(elemPos) )
            levelElemPos = levelPointer(elemPos)
            call assignStFunPointer( affection_list = affection_list, &
              &                      stFunList      = stFunList,      &
              &                      iLevel         = iLevel,          &
              &                      iMat           = iMat,           &
              &                      iStFun         = iStFun,         &
              &                      levelElemPos   = levelElemPos,   &
              &                      inputVarPos    = inputVarPos     )
          end do
        end if
      end do
      allElemsDefined = .true.
      do iElem = 1, tree%nElems
        ! Make use of the levelpointer to read out level and position in the
        ! levewise list of elements.
        iLevel = tem_levelOf( tree%treeid(iElem) )
        levelElemPos = levelPointer(iElem)
        allElemsDefined = allElemsDefined                                &
          &                 .and. associated(                            &
          &                         affection_list(ilevel)               &
          &                           %material_desc                     &
          &                           %material_elems(levelElemPos,iMat) &
          &                           %stFunPtr                          )

      end do
      if (.not. allElemsDefined) then
        write(logUnit(1),*) 'ERROR: Material ',                    &
              &                 trim(varSys%varName%val(varPos)),  &
              &                 ' is not defined for all elements'
        write(logUnit(1),*) 'Maybe you forgot to define a global const' &
          &                 // ' in your space-time function!'

        call tem_abort()
      end if

  end do

    contains

      ! *************************************************************************
      subroutine assignStFunPointer( affection_list, stFunList, iLevel, iMat, &
        &                            iStFun, levelElemPos, inputVarPos        )
        ! -----------------------------------------------------------------------
        type(atl_material_type), intent(inout) :: &
                 & affection_list(tree%global%minlevel:tree%global%maxlevel)
        type(tem_st_fun_listElem_type), pointer :: stFunList
        integer :: iLevel
        integer :: iMat
        integer :: iStFun
        integer :: levelElemPos
        integer :: inputVarPos
        ! -----------------------------------------------------------------------
        affection_list(iLevel)%material_desc                      &
          &                   %material_elems(levelElemPos, iMat) &
          &                   %stFunPtr                           &
          & => stFunList%val(iStFun)
        ! The following information is used for communication. We can't send
        ! the stFunPtr to another rank, thus we need some other way to
        ! address the spacetime functions. Therefore we also store the
        ! index of the variable as well as the index of the particular
        ! spacetime function within the variable's spacetime function
        ! list.
        affection_list(iLevel)%material_desc                      &
          &                   %material_elems(levelElemPos, iMat) &
          &                   %stFunPos                           &
          & = iStFun
        affection_list(iLevel)%material_desc                      &
          &                   %material_elems(levelElemPos, iMat) &
          &                   %matVarPos                          &
          & = inputVarPos
      end subroutine
      ! *************************************************************************

  end subroutine atl_assign_elem_varProp
  ! ****************************************************************************


  ! ****************************************************************************
  !> Read the configuration for the material paramters for Maxwell equations
  !! from configuration files and init the material parameter datatype.
  subroutine atl_update_materialParams( equation, mesh, scheme, boundary, &
    &                                   material, time, poly_proj, proc,  &
    &                                   commPattern                       )
    ! --------------------------------------------------------------------------
    !> Description on the equation system to solve.
    type(atl_Equations_type), intent(inout) :: equation
    !> Description of the mesh
    type(atl_cube_elem_type), intent(inout) :: mesh
    !> Information about the scheme
    type(atl_scheme_type), intent(in) :: scheme
    !> Global description of the boundary conditions.
    type(atl_level_boundary_type), intent(in)  :: boundary
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: material
    !> The current simulation time
    type(tem_time_type), intent(in) :: time
    !> unique list for projection methods
    type(ply_poly_project_type), intent(inout) :: poly_proj
    !> 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
    ! --------------------------------------------------------------------------

    if (equation%material%is_transient) then
      ! Evaluate all material properties for the fluid elements (i.e. the
      ! element that are added to the computeElems variable of material_desc
      ! on each level)
      call atl_evalElemMaterial(                             &
        & mesh           = mesh,                             &
        & scheme         = scheme,                           &
        & material       = material,                         &
        & materialFun    = equation%material,                &
        & time           = time,                             &
        & mode_reduction = equation%material%mode_reduction, &
        & poly_proj      = poly_proj,                        &
        & time_weights   = .true.,                           &
        & proc           = proc,                             &
        & commPattern    = commPattern                       )

      ! Evaluate all material properties for the compute faces (left + right
      ! element)
      call atl_evalFaceMaterial(                             &
        & mesh           = mesh,          &
        & scheme         = scheme,        &
        & material       = material,      &
        & materialFun    = equation%material,                &
        & time           = time,                             &
        & spatial_dim    = equation%nDimensions,             &
        & poly_proj      = poly_proj,                        &
        & time_weights   = .true.                            )

      ! Create list of boundary faces, depending on the combinations
      ! of material properties.
      call atl_create_materialBoundaryList( &
        & material     = material,           &
        & mesh         = mesh,               &
        & materialFun  = equation%material,  &
        & boundary     = boundary,           &
        & time_weights = .true.              )
    end if

  end subroutine atl_update_materialParams
  ! ****************************************************************************


  ! ****************************************************************************
  !> Subroutine to evaluate the material properties on the nodes
  !! of the compute faces (left and right element's trace).
  subroutine atl_evalFaceMaterial( mesh, scheme, material, materialFun, time, &
    &                              spatial_dim, poly_proj, time_weights       )
    ! ---
    !> Description of the mesh
    type(atl_cube_elem_type), intent(in) :: mesh
    !> Information about the scheme
    type(atl_scheme_type), intent(in) :: scheme
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: material
    !! The indizes of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(in) :: materialFun
    !> The current simulation time
    type(tem_time_type), intent(in) :: time
    !> The spatial dimension
    integer, intent(in) :: spatial_dim
    !> Projection method for current level
    type(ply_poly_project_type), intent(inout) :: poly_proj
    logical, optional, intent(in) :: time_weights
    ! --------------------------------------------------------------------------
    integer :: iDir, iFace, iMat, iAlign
    integer :: faceIndex, leftIndex, rightIndex, res_lb, res_ub
    integer :: nMaxComps, compOffset
    type(atl_spacetime_fun_pointer_type) :: rightElemMat, leftElemMat
    real(kind=rk) :: bndBaryCoord(1,3)
    real(kind=rk), allocatable :: bary_matParLeft(:), bary_matParRight(:)
    integer :: nConstFace, nVarFace
    integer :: nquadpoints, elempos
    real(kind=rk), allocatable :: facePoints(:,:), facePhysCoord(:,:)
    logical :: use_timer
    ! --------------------------------------------------------------------------

    use_timer = .false.
    if (present(time_weights)) then
      use_timer = time_weights
    end if

    ! Store the max number of components a single material parameter has. This
    ! number is used to allocate buffers, as every material parameter fits
    ! into these buffers. We could allocate these buffers for every material
    ! parameter explicitly to not waste some memory in some cases, but
    ! allocating and deallocating the buffers is a costly operation. So for
    ! the sake of performance I decided to go for a slightly higher memory
    ! usage.
    nMaxComps = maxval(materialFun%nScalars)

    ! Use this to allocate a temporary array to avoid doing this for each
    ! materia parameter individually.
    allocate( bary_matParLeft( nMaxComps ), bary_matParRight( nMaxComps ) )

    matLoop: do iMat = 1, materialFun%nMat
      dirLoop: do iDir = 1, spatial_dim

        ! Calculate the component offsets for the current material iMat.These
        ! offsets are used for the assembled material array where all material
        ! parameters for one elemen reside next to each other.
        ! This calculation could have been done in the matLoop, but later on in
        ! the dirLoop res_lb and res_ub are potentially overwritten. Thus we
        ! have to renew it's value here.
        res_lb = sum(materialFun%nScalars(1:iMat-1))+1
        res_ub = sum(materialFun%nScalars(1:iMat))

        ! allocate space for the constant material parameters
        nConstFace = size(                                   &
          & material%material_desc                           &
          &         %computeFace(iDir, atl_pureConstMat_prp) &
          &         %facePos                                 )

        ! Iterate over all the compute faces with purely constant material
        ! parameters
        constFaceLoop: do iFace = 1, nConstFace


          ! Get the indices in the original compute face list
          faceIndex = material%material_desc                           &
            &                 %computeFace(iDir, atl_pureConstMat_prp) &
            &                 %facePos(iFace)
          leftIndex = material%material_desc                           &
            &                 %computeFace(iDir, atl_pureConstMat_prp) &
            &                 %leftPos(iFace)
          rightIndex = material%material_desc                           &
            &                  %computeFace(iDir, atl_pureConstMat_prp) &
            &                  %rightPos(iFace)

          ! Get the barycentric coordinate on the face (we use the barycentric
          ! coordinate of the left element for that). We check if one if the
          ! elements is a boundary. We use the one that is not a boundary
          ! element to calculate the barycentric coordinate.
          if ( leftIndex > mesh%descriptor%elem%nElems(eT_fluid)) then
            bndBaryCoord(1,1:3) = mesh%bary_coord(rightIndex,1:3)
            bndBaryCoord(1,iDir) = bndBaryCoord(1,iDir) - 0.5_rk*mesh%length
            elempos = mesh%descriptor%pntTID(rightIndex)
          else
            bndBaryCoord(1,1:3) = mesh%bary_coord(leftIndex,1:3)
            bndBaryCoord(1,iDir) = bndBaryCoord(1,iDir) + 0.5_rk*mesh%length
            elempos = mesh%descriptor%pntTID(leftIndex)
          end if
          if (use_timer) then
            call tem_startTimer( me          = atl_elemTimers, &
              &                  timerHandle = elemPos         )
          end if

          ! Read out the material positions for both elements (the left element
          ! property is stored
          ! as the right property and vice versa)
          leftElemMat = material%material_desc                  &
            &                   %material_face(iDir)            &
            &                   %mat( faceIndex, tem_left, iMat )
          rightElemMat = material%material_desc                   &
            &                    %material_face(iDir)             &
            &                    %mat( faceIndex, tem_right, iMat )

          ! Evaluate the constant at the barycentric face value (left and right
          ! limit)
          material%material_dat                                 &
            &     %faceMaterialData(iDir, atl_constMatIdx)      &
            &     %leftElemMaterialDat(iFace,1:1,res_lb:res_ub) &
            & = tem_spacetime_for(                              &
            &     me    = leftElemMat%stFunPtr,                 &
            &     coord = bndBaryCoord,                         &
            &     time  = time,                                 &
            &     n     = 1,                                    &
            &     nComp = materialFun%nScalars(iMat)            )
          material%material_dat                                  &
            &     %faceMaterialData(iDir, atl_constMatIdx)       &
            &     %rightElemMaterialDat(iFace,1:1,res_lb:res_ub) &
            & = tem_spacetime_for(                               &
            &     me    = rightElemMat%stFunPtr,                 &
            &     coord = bndBaryCoord,                          &
            &     time  = time,                                  &
            &     n     = 1,                                     &
            &     nComp = materialFun%nScalars(iMat)             )

          if (use_timer) then
            call tem_stopTimer( me          = atl_elemTimers, &
              &                 timerHandle = elemPos         )
          end if

        end do constFaceLoop

        ! Detect the correct number of points on the face due to projection;
        ! It is assumed that on left and right face there is the same amount of
        ! points. Further is the number of points in a spatial direction for all
        ! dimension equal
        select case(scheme%scheme)
        case(atl_modg_scheme_prp)
          nquadpoints = poly_proj%body_3D%faces(idir,2)%nquadpoints
        case(atl_modg_2d_scheme_prp)
          nquadpoints = poly_proj%body_2D%faces(idir,2)%nquadpoints
        case(atl_modg_1d_scheme_prp)
          nquadpoints = poly_proj%body_1D%faces(idir,2)%nquadpoints
        case default
          call tem_abort( 'ERROR in atl_evalFaceMaterial: not able to '      &
            & // 'evaluate face nodal material parameters for this scheme, ' &
            & // 'stopping ...'                                              )
        end select


        ! allocate space for the constant material parameters
        nVarFace = size( material%material_desc                       &
          &                      %computeFace(iDir, atl_mixedMat_prp) &
          &                      %facePos                             )
        allocate( facePhysCoord(nquadpoints,3) )


        ! Iterate over all the non-constant faces
        varFaceLoop: do iFace = 1, nVarFace

          ! Get the indices in the original compute face list
          faceIndex = material%material_desc                       &
            &                 %computeFace(iDir, atl_mixedMat_prp) &
            &                 %facePos(iFace)
          leftIndex = material%material_desc                       &
            &                 %computeFace(iDir, atl_mixedMat_prp) &
            &                 %leftPos(iFace)
          rightIndex = material%material_desc                       &
            &                  %computeFace(iDir, atl_mixedMat_prp) &
            &                  %rightPos(iFace)

          ! At least one of them has to be a fluid element, so we check which
          ! one and use the fluid element to shift the reference Chebyshev face
          ! nodes to the physical element
          if( leftIndex.le.mesh%descriptor%elem%nElems(eT_fluid) ) then
            ! Get the barycentric coordinate of the left element
            bndBaryCoord(1,1:3) = mesh%bary_coord(leftIndex,1:3)
            iAlign = 2
            elempos = mesh%descriptor%pntTID(leftIndex)
          else if(rightIndex.le.mesh%descriptor%elem%nElems(eT_fluid)) then
            ! Get the barycentric coordinate of the right element
            bndBaryCoord(1,1:3) = mesh%bary_coord(rightIndex,1:3)
            iAlign = 1
            elempos = mesh%descriptor%pntTID(rightIndex)
          else
            call tem_abort( 'ERROR in atl_evalFaceMaterial: compute '  &
              & // 'face without adjacent fluid element, stopping ...' )
          end if

          if (use_timer) then
            call tem_startTimer( me          = atl_elemTimers, &
              &                  timerHandle = elemPos         )
          end if

          ! get the quadrature points on the boundary faces
          select case(scheme%scheme)
          case(atl_modg_scheme_prp)
            call ply_get_quadpoints_faces( poly_proj = poly_proj, &
              &                            iDir      = iDir,      &
              &                            iAlign    = iAlign,    &
              &                            points    = facePoints )
          case(atl_modg_2d_scheme_prp)
            call ply_get_quadpoints_faces_2d( poly_proj = poly_proj, &
              &                               iDir      = iDir,      &
              &                               iAlign    = iAlign,    &
              &                               points    = facePoints )
          case(atl_modg_1d_scheme_prp)
            call ply_get_quadpoints_faces_1d( poly_proj = poly_proj, &
              &                               iDir      = iDir,      &
              &                               iAlign    = iAlign,    &
              &                               points    = facePoints )
          case default
            call tem_abort( errorMsg = 'ERROR in atl_evalFaceMaterial: not ' &
              & // 'able to get facial quadpoints to evaluate material '     &
              & // 'parameters for this scheme, stopping ...'                )
          end select

          ! Shift the face reference nodes to the physical face. For the left
          ! element, we have to use the reference face points on its right
          ! face (and vice versa).
          call atl_refToPhysCoord( refpoints  = facePoints,   &
            &                      nPoints    = nquadpoints,  &
            &                      baryCoord  = bndBaryCoord, &
            &                      elemLength = mesh%length,  &
            &                      physPoints = facePhysCoord )

          deallocate( facePoints )

          ! Read out the material positions for both elements (the left element
          ! property is stored as the right property and vice versa)
          leftElemMat = material%material_desc                  &
            &                   %material_face(iDir)            &
            &                   %mat( faceIndex, tem_left, iMat )
          rightElemMat = material%material_desc                   &
            &                    %material_face(iDir)             &
            &                    %mat( faceIndex, tem_right, iMat )

          compOffset = sum(materialFun%nScalars(1:iMat-1))
          res_lb = compOffset + 1
          res_ub = sum(materialFun%nScalars(1:iMat))

          ! Evaluate the material parameters at the physical nodes (left and
          ! right limit)
          if ( materialFun%nScalars(iMat) > 1 ) then
            ! Only call the vectorial routine when actually expecting a vector
            material%material_dat                                 &
              &     %faceMaterialData(iDir, atl_varMatIdx)        &
              &     %leftElemMaterialDat(iFace, :, res_lb:res_ub) &
              & = tem_spacetime_for(                              &
              &     me    = leftElemMat%stFunPtr,                 &
              &     coord = facePhysCoord,                        &
              &     time  = time,                                 &
              &     n     = nQuadPoints,                          &
              &     nComp = materialFun%nScalars(iMat)            )
            material%material_dat                                  &
              &     %faceMaterialData(iDir, atl_varMatIdx)         &
              &     %rightElemMaterialDat(iFace, :, res_lb:res_ub) &
              & = tem_spacetime_for(                               &
              &     me    = rightElemMat%stFunPtr,                 &
              &     coord = facePhysCoord,                         &
              &     time  = time,                                  &
              &     n     = nQuadPoints,                           &
              &     nComp = materialFun%nScalars(iMat)             )
          else
            ! Call the scalar routine when expecting only one value
            material%material_dat                          &
              &     %faceMaterialData(iDir, atl_varMatIdx) &
              &     %leftElemMaterialDat(iFace, :, res_lb) &
              & = tem_spacetime_for(                       &
              &     me    = leftElemMat%stFunPtr,          &
              &     coord = facePhysCoord,                 &
              &     time  = time,                          &
              &     n     = nQuadPoints                    )
            material%material_dat                           &
              &     %faceMaterialData(iDir, atl_varMatIdx)  &
              &     %rightElemMaterialDat(iFace, :, res_lb) &
              & = tem_spacetime_for(                        &
              &     me    = rightElemMat%stFunPtr,          &
              &     coord = facePhysCoord,                  &
              &     time  = time,                           &
              &     n     = nQuadPoints                     )
          end if

          if (use_timer) then
            call tem_stopTimer( me          = atl_elemTimers, &
              &                 timerHandle = elemPos         )
          end if

        end do varFaceLoop

        ! Free the temporary memory
        deallocate( facePhysCoord )

      end do dirLoop
    end do matLoop

    deallocate( bary_matParLeft, bary_matParRight )

  end subroutine atl_evalFaceMaterial
  ! ****************************************************************************


  ! ****************************************************************************
  !> Evaluates the material properties for all elements contained
  !! in the computeElems variable of the material_desc datatype.
  subroutine atl_evalElemMaterial( mesh, scheme, material, materialFun, time, &
    &                              poly_proj, mode_reduction, time_weights,   &
    &                              proc, commPattern                          )
    ! --------------------------------------------------------------------------
    !> Description of the mesh
    type(atl_cube_elem_type), intent(inout) :: mesh
    !> Information about the scheme
    type(atl_scheme_type), intent(in) :: scheme
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: material
    !! The indizes of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(in) :: materialFun
    !> The current simulation time
    type(tem_time_type), intent(in) :: time
    !> Projection method for current level
    type(ply_poly_project_type), intent(inout) :: poly_proj
    !> Settings for mode reduction. Used to determine which element can be
    !! calculated with reduced computational effort due to mode reduction.
    type(atl_mode_reduction_type), intent(in) :: mode_reduction
    logical, optional, intent(in) :: time_weights
    !> Communication environment
    type(tem_comm_env_type), intent(inout) :: proc
    !> mpi communication pattern type
    type(tem_commPattern_type), intent(inout) :: commPattern
    ! --------------------------------------------------------------------------
    real(kind=rk) :: bary_coord(1,3)
    real(kind=rk), allocatable :: volumePhysCoord(:,:), volumePoints (:,:)
    integer, allocatable :: commreduce(:)
    integer :: nElemsCons, nElemsVar, compOffset
    integer :: levelIndex, res_lb, res_ub
    integer :: iElem, iMat
    integer :: iFluid
    integer :: elemPos
    integer :: nquadpoints
    real(kind=rk) :: mode_reduction_val, min_mode_reduction_val
    logical :: use_timer
    integer :: nNeighbors
    integer :: iNeighbor
    integer :: neighbor
    logical :: fluidisreducable
    ! --------------------------------------------------------------------------

    use_timer = .false.
    if (present(time_weights)) then
      use_timer = time_weights
    end if

    !> @todo PV 20151027 Write unit tests for this routine as I'm not sure
    !!                   whether the index calculations around nScalars and iMat
    !!                   do what they are supposed to do.

    ! First we handle the constant material parameters
    nElemsCons = material%material_desc%computeElems(atl_constMatIdx)%nElems

    if( nElemsCons > 0 ) then
      constElemLoop: do iElem = 1, nElemsCons
        ! Get the element index in the total list and read out the
        ! position of the material property.
        levelIndex = material%material_desc                 &
          &                  %computeElems(atl_constMatIdx) &
          &                  %totElemIndices(iElem)

        !timer for LB of the global elements
        elempos = mesh%descriptor%pntTID(levelIndex)
        if (use_timer) then
          call tem_startTimer( me          = atl_elemTimers, &
            &                  timerHandle = elemPos         )
        end if

        ! Read out the barycenter of the element
        bary_coord(1,1:3) = mesh%bary_coord(levelIndex,1:3)

        ! We need to loop over the individual material parameters, because
        ! fortran is not capable of accepting an array of pointers as an
        ! argument. Thus we have to call tem_spacetime_for for each stFunPtr
        ! separately. The result of these calls is an array. The problem is to
        ! store the result at the correct indizes. Therefore we have to
        ! calculate the positions based on the number of components each
        ! material parameter has.
        do iMat = 1, materialFun%nMat
          res_lb = sum(materialFun%nScalars(1:iMat-1))+1
          res_ub = sum(materialFun%nScalars(1:iMat))
          !!if (.not. associated (material%material_desc%material_elems(levelindex, iMat) &
          !!        & %stFunPtr )) then
          !!    write(*,*) '++++++++POINTER is not set!!++++++++++'
          !!end if
          material%material_dat                                     &
            &     %elemMaterialData(atl_constMatIdx)                &
            &     %materialDat(iElem,1:1,res_lb:res_ub)             &
            & =  tem_spacetime_for(                                 &
            &      me    = material%material_desc                   &
            &                      %material_elems(levelIndex,iMat) &
            &                      %stFunPtr,                       &
            &      coord = bary_coord,                              &
            &      time  = time,                                    &
            &      n     = 1,                                       &
            &      nComp = materialFun%nScalars(iMat)               )
          if ( iMat == mode_reduction%matPos ) then
            mode_reduction_val = material%material_dat                      &
              &                          %elemMaterialData(atl_constMatIdx) &
              &                          %materialDat( iElem, 1, res_lb )
            material%material_dat%mode_reducable(levelIndex) = &
              & mode_reduction_val >= mode_reduction%threshold
          end if
        end do
        if (use_timer) then
          call tem_stopTimer( me          = atl_elemTimers,  &
            &                 timerHandle = elemPos          )
        end if
      end do constElemLoop

    end if

    ! Second, we handle the non-constant material parameters. This depends on
    ! the scheme we use, so we check for them and call separate routines for
    ! them.
    select case(scheme%scheme)
    case(atl_modg_scheme_prp)
      ! get correct amount of  number of points on the face
      nquadpoints = poly_proj%body_3D%nquadpoints
      allocate(volumePoints(nquadpoints,3))
      volumePoints = poly_proj%body_3d%nodes

    case(atl_modg_2d_scheme_prp)
      ! get correct amount of  number of points on the face
      nquadpoints = poly_proj%body_2D%nquadpoints
      allocate(volumePoints(nquadpoints,3))
      volumePoints = poly_proj%body_2d%nodes

    case(atl_modg_1d_scheme_prp)
      ! get correct amount of  number of points on the face
      nquadpoints = poly_proj%body_1D%nquadpoints
      allocate(volumePoints(nquadpoints,3))
      volumePoints = poly_proj%body_1d%nodes

    case default
      call tem_abort( 'ERROR in atl_evalElemMaterial: not able to evaluate '   &
        & // 'element nodal material parameters for this scheme, stopping ...' )
    end select

    ! For the variable material parameters we use the quadrature points
    ! provided by the FPT
    nElemsVar = material%material_desc%computeElems(atl_varMatIdx)%nElems

    if( nElemsVar > 0 ) then
      ! Allocate some temporary memory for the qudrature nodes on the physical
      ! element and the nodal material parameters at these points.
      allocate( volumePhysCoord(nquadpoints,1:3) )

      ! Now, we iterate over all the elements with variable coefficients and
      ! evaluate the material parameter for them.
      varElemLoop: do iElem = 1, nElemsVar

        ! Get the element position in the total list and recover the material
        ! position.
        levelIndex = material%material_desc               &
          &                  %computeElems(atl_varMatIdx) &
          &                  %totElemIndices(iElem)

        elempos = mesh%descriptor%pntTID(levelIndex)
        if (use_timer) then
          call tem_startTimer( me          = atl_elemTimers, &
            &                  timerHandle = elemPos         )
        end if
        !PV! Alter Code
        !PV!matPos = material%material_desc%material_elems(levelIndex)

        ! shift Chebyshev nodes to physical element coord
        call atl_refToPhysCoord( refPoints  = volumePoints,                   &
          &                      nPoints    = nquadpoints,                    &
          &                      baryCoord  = mesh%bary_coord(levelIndex, :), &
          &                      elemLength = mesh%length,                    &
          &                      physPoints = volumePhysCoord                 )

        do iMat = 1, materialFun%nMat
          compOffset = sum(materialFun%nScalars(1:iMat-1))
          res_lb = compOffset + 1
          res_ub = sum(materialFun%nScalars(1:iMat))

          if( materialFun%nScalars(iMat) > 1 ) then
            ! Only call the vectorial routine when actually expecting a vector
            material%material_dat                                    &
              &     %elemMaterialData(atl_varmatIdx)                 &
              &     %materialDat( iElem, :, res_lb:res_ub )          &
              & = tem_spacetime_for(                                 &
              &     me    = material%material_desc                   &
              &                     %material_elems(levelIndex,iMat) &
              &                     %stFunPtr,                       &
              &     coord = volumePhysCoord,                         &
              &     time  = time,                                    &
              &     n     = nQuadPoints,                             &
              &     nComp = materialFun%nScalars(iMat)               )
          else
            ! Call the scalar routine when only expecting one value
            material%material_dat                                    &
              &     %elemMaterialData(atl_varmatIdx)                 &
              &     %materialDat( iElem, :, res_lb )                 &
              & = tem_spacetime_for(                                 &
              &     me    = material%material_desc                   &
              &                     %material_elems(levelIndex,iMat) &
              &                     %stFunPtr,                       &
              &     coord = volumePhysCoord,                         &
              &     time  = time,                                    &
              &     n     = nQuadPoints                              )
          end if
          if ( iMat == mode_reduction%matPos ) then
            min_mode_reduction_val =                            &
              & minval(material%material_dat                    &
              &                %elemMaterialData(atl_varmatIdx) &
              &                %materialDat( iElem, :, res_lb ))
            material%material_dat%mode_reducable(levelIndex) = &
              & min_mode_reduction_val >= mode_reduction%threshold
          end if

        end do

        if (use_timer) then
          call tem_stopTimer( me          = atl_elemTimers,  &
            &                 timerHandle = elemPos          )
        end if

      end do varElemLoop

      deallocate(volumePhysCoord)
    end if

    ! Communicate the material%material_dat%mode_reducable info
    ! between processes.
    ! Use an integer to reuse existing communication buffer.
    allocate( commreduce(size(material%material_dat%mode_reducable)) )
    commreduce = 0
    where(material%material_dat%mode_reducable) commreduce = 1

    ! Information about neighbors provided by mesh%descriptor
    ! Communicate reducable flag across processes into halo elements.
    call commPattern%exchange_int(         &
      &    send         = mesh%descriptor  &
      &                       %sendBuffer, &
      &    recv         = mesh%descriptor  &
      &                       %recvBuffer, &
      &    state        = commreduce,      &
      &    message_flag = 123,             &
      &    comm         = proc%comm        )

    ! Run over all *fluid* elements, check reducable flag of all neighbors
    ! in the commreduce array and update mode_reducable accordingly.
    nNeighbors = size(mesh%descriptor%neigh(1)%nghElems, 1)
    do iFluid=1,mesh%descriptor%elem%nElems(eT_fluid)

      fluidisreducable = (commreduce(iFluid) == 1)
      do iNeighbor=1,nNeighbors
        neighbor = mesh%descriptor%neigh(1)%nghElems(iNeighbor,iFluid)

        if (neighbor > 0) then
          fluidisreducable = fluidisreducable &
            &                .and. (commreduce(neighbor) == 1)
        end if
      end do
      material%material_dat%mode_reducable(iFluid) = fluidisreducable

    end do

    ! Clean up the temporary memory for the next iteration
    deallocate(commreduce)
    deallocate(volumePoints)

  end subroutine atl_evalElemMaterial
  ! ****************************************************************************


  ! ****************************************************************************
  !> Subroutine to create element index list for constant and non-constant
  !! material parameters.
  !!
  !! To create the two lists, one list with elements with constant material
  !! parameters and one list with elements with variable material parameters,
  !! we have to follow several steps split into separate phases:
  !! Phase 1: Determine variable and constant elements
  !! 1. Loop over all materials
  !! 1.1. Loop over all spacetime functions
  !! 1.1.1 Determine whether the element is variable or not and add it to the
  !!       according list.
  !! Phase 2: Determine the levelwise element lists
  !! 2. Loop over all elements.
  !! 2.1. Determine the element's level.
  !! 2.2. Add them to intermediate lists.
  !! Phase 3: Create the result
  !! 3. Copy intermediate lists into result type.
  subroutine atl_create_materialElemList( tree, levelPointer, material_list, &
    &                                     varSys, materials, materialFun     )
    ! --------------------------------------------------------------------------
    !> Mesh data in treelmesh format.
    type(treelmesh_type), intent(in) :: tree
    !> The levelPointer contains the indizes on the levelwise fluid list for all
    !! treeID entries.
    integer, intent(in) :: levelPointer(:)
    !> The description of the material properties. This routine fills the
    !! compute lists in the material description.
    type(atl_material_type), intent(inout) &
      & :: material_list(tree%global%minLevel:tree%global%maxLevel)
    !> global variable system to which lua variables are to be appended
    type(tem_varSys_type), intent(in) :: varSys
    !> The list of the variables that should be used as materials.
    character(len=labelLen), intent(in) :: materials(:)
    !! The indizes of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(inout) :: materialFun
    ! --------------------------------------------------------------------------
    integer :: iLevel, iElem, iStFun, iMat, iIndex, level
    integer :: nElemsConst, nElemsVar
    integer :: matPos, inVarPos
    logical :: allElemsAffected
    !> The position of an element according to the sorted array.
    integer :: sortedIndex
    !> Indicates that an element has variable material.
    logical :: elemHasVarMat
    type(dyn_intArray_type) :: variableElements
    type(dyn_intArray_type) ::                                                &
      & variableElementsPerLevel( tree%global%minLevel : tree%global%maxLevel )
    type(dyn_intArray_type) ::                                                &
      & constantElementsPerLevel( tree%global%minLevel : tree%global%maxLevel )
    type(tem_st_fun_listElem_type), pointer :: stFunList
    ! --------------------------------------------------------------------------

    !! Phase 1: Determine variable and constant elements

    !! this variable should be false if no material is there
    allElemsAffected = .false.
    do iMat = 1, materialFun%nMat
      ! get the position of the spacetime function in the varSys for the
      ! current material
      matPos = positionOfVal( me  = varSys%varName, &
        &                     val = materials(iMat) )
      ! The material variable just points to the variable contaning the
      ! spacetime functions. So we have to get this variable's index, which is
      ! the only input variable, so we will always find this variable at index 1
      inVarPos = varSys%method%val(matPos)%input_varPos(1)

      ! With the position of the lua variable, we can cast the list of
      ! spacetime functions for this variable, which is pointed to by
      ! method_data, back into a Fortran type to iterate over it.
      call c_f_pointer(varSys%method%val(inVarPos)%method_data, stFunList)

      ! Loop over all spacetime functions
      do iStFun = 1, stFunList%nVals
        write(logUnit(lldebug),'(A)') 'Kind of space-time function: ' &
          & // trim(stFunList%val(iStFun)%fun_kind)
        ! If the spacetime function is not constant, we need to add it's
        ! elements to the list of variable elements.
        if( stFunList%val(iStFun)%fun_kind /= 'const' ) then

          ! Check whether this material affects the whole mesh. If so, there
          ! is no need to examine further spacetime functions, because all
          ! elements have at least this material as variable material and thus
          ! all elements belong to the variable elements.
          allElemsAffected = stFunList%val(iStFun)%subTree%useGlobalMesh
          if( allElemsAffected ) exit

          do iElem = 1, stFunList%val(iStFun)%subTree%nElems
            call append(                                              &
              & me  = variableElements,                               &
              & val = stFunList%val(iStFun)%subTree%map2global(iElem) )
          end do

        end if

        if( allElemsAffected ) exit

      end do

    end do

    !! Phase 2: Determine the levelwise element lists
    iIndex = 1
    do iElem = 1, tree%nElems
      level = tem_levelOf(tree%treeID(iElem))

      if( allElemsAffected ) then
        elemHasVarMat = .true.
      else
        elemHasVarMat = .false.
        ! Check whether the index of the current element is in variableElements,
        ! which contains the indizes of variable Elements.
        if ( variableElements%nVals >= iIndex ) then
          sortedIndex = variableElements%sorted(iIndex)
          if( sortedIndex /= 0 ) then
            elemHasVarMat = variableElements%val(sortedIndex) == iElem
          end if
        end if
      end if
      if( elemHasVarMat ) then
        ! The element at index iElem is also part of the variableElements list
        ! and thus belongs to the variable elements
        call append( me  = variableElementsPerLevel(level), &
          &          val = levelPointer(iElem)              )
        ! As the current element is part of variableElements, we have to
        ! increase the pointer to the next possible element
        iIndex = iIndex + 1
      else
        ! The element at index iElem is not part of the variableElements list
        ! and thus belongs to the constant elements
        call append( me  = constantElementsPerLevel(level), &
          &          val = levelPointer(iElem)              )
      end if

    end do

    !! Phase 3: Create the result
    do iLevel = tree%global%minLevel, tree%global%maxLevel

      nElemsVar = variableElementsPerLevel(iLevel)%nVals
      nElemsConst = constantElementsPerLevel(iLevel)%nVals

      material_list(iLevel)%material_desc                 &
        &                  %computeElems(atl_ConstMatIdx) &
        &                  %nElems                        &
        & = nElemsConst
      allocate( material_list(iLevel)%material_desc                 &
        &                            %computeElems(atl_ConstMatIdx) &
        &                            %totElemIndices(nElemsConst)   )
      if( nElemsConst > 0 ) then
        material_list(iLevel)%material_desc                 &
          &                  %computeElems(atl_ConstMatIdx) &
          &                  %totElemIndices                &
          & = constantElementsPerLevel(iLevel)%val(:nElemsConst)
      end if

      material_list(iLevel)%material_desc               &
        &                  %computeElems(atl_VarMatIdx) &
        &                  %nElems                      &
        & = nElemsVar
      allocate(                                             &
        & material_list(iLevel)%material_desc               &
        &                      %computeElems(atl_VarMatIdx) &
        &                      %totElemIndices(nElemsVar)   )
      if( nElemsVar > 0 ) then
        material_list(iLevel)%material_desc                  &
          &                  %computeElems(atl_VarMatIdx)    &
          &                  %totElemIndices                 &
          & = variableElementsPerLevel(iLevel)%val(:nElemsVar)
      end if

    end do

    do iLevel = tree%global%minLevel, tree%global%maxLevel
      call destroy( variableElementsPerLevel( iLevel ) )
      call destroy( constantElementsPerLevel( iLevel ) )
    end do

  end subroutine atl_create_materialElemList
  ! ****************************************************************************


  ! ****************************************************************************
  !> Create separate compute list for constant-constant, constant-variable (or
  !! vice versa) and variable-variable material parameter compute faces on this
  !! rank.
  subroutine atl_create_materialBoundaryList( material, materialFun, boundary, &
    &                                         mesh, time_weights )
    ! --------------------------------------------------------------------------
    !> Description of the mesh
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: material
    !! The indizes of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(in) :: materialFun
    !> Boundary description for the all the levels.
    type(atl_level_boundary_type), intent(in) :: boundary
    logical, optional, intent(in) :: time_weights
    ! --------------------------------------------------------------------------
    integer :: iBc, iDir, iAlign, iFace, nBCs, iMat
    integer :: facePos, neighPos
    type(atl_spacetime_fun_pointer_type) :: neighMat(materialFun%nMat)
    integer :: matType, elempos
    logical :: constMat(materialFun%nMat)
    logical :: use_timer
    ! --------------------------------------------------------------------------

    use_timer = .false.
    if (present(time_weights)) then
      use_timer = time_weights
    end if

    nBCs = boundary%nBcs
    material%material_desc%bnd_faces(:)%boundary%nBCs = nBCs
    bcLoop: do iBc = 1, nBcs
      dirLoop: do iDir = 1,3
        alignLoop: do iAlign = 1, 2

          ! Init the new datatype which holds the boundary material
          ! information.
          call init( me     = material%material_desc              &
            &                         %bnd_faces(atl_constMatIdx) &
            &                         %boundary                   &
            &                         %bnd(iBc)                   &
            &                         %faces(iDir,iAlign)         &
            &                         %facePos,                   &
            &        length = 16                                  )
          call init( me     = material%material_desc            &
            &                         %bnd_faces(atl_varMatIdx) &
            &                         %boundary                 &
            &                         %bnd(iBc)                 &
            &                         %faces(iDir,iAlign)       &
            &                         %facePos,                 &
            &        length = 16                                )
          call init( me     = material%material_desc              &
            &                         %bnd_faces(atl_constMatIdx) &
            &                         %boundary                   &
            &                         %bnd(iBc)                   &
            &                         %faces(iDir,iAlign)         &
            &                         %neighPos,                  &
            &        length = 16                                  )
          call init( me     = material%material_desc            &
            &                         %bnd_faces(atl_varMatIdx) &
            &                         %boundary                 &
            &                         %bnd(iBc)                 &
            &                         %faces(iDir,iAlign)       &
            &                         %neighPos,                &
            &        length = 16                                )

          faceLoop: do iFace = 1, boundary%bnd(iBc)           &
            &                             %faces(iDir,iAlign) &
            &                             %facePos            &
            &                             %nVals

            ! Get the position of the boundary face and neighboring fluid
            ! element's face
            facePos = boundary%bnd(iBc)%faces(iDir,iAlign)%facePos  &
              &                                           %val(iFace)
            neighPos = boundary%bnd(iBc)%faces(iDir,iAlign)%neighPos &
              &                                            %val(iFace)
            elempos = mesh%descriptor%pntTID(neighPos)
            if (use_timer) then
              call tem_startTimer( me          = atl_elemTimers, &
                &                  timerHandle = elemPos         )
            end if
            ! Now, we get the material property assigned for this face from
            ! its fluid neighbor element.
            neighMat = material%material_desc%material_elems(neighPos, :)

            matLoop: do iMat = 1, materialFun%nMat
              ! Check if this boundary face has the same material function from
              ! both sides
              if( .not. associated( neighMat(iMat)%stFunPtr ) ) then
                call tem_abort( 'ERROR in atl_create_materialBoundaryList: ' &
                  & // 'no material at boundary face, stopping ...'   )
              end if
              constMat(iMat) = neighMat(iMat)%stFunPtr%fun_kind == 'const'
            end do matLoop

            ! Locate the position of the face materials
            if ( all(constMat) ) then
              matType = atl_pureConstMat_prp
            else
              matType = atl_mixedMat_prp
            end if

            ! Store the gathered information.
            call append( me  = material%material_desc      &
              &                        %bnd_faces(matType) &
              &                        %boundary           &
              &                        %bnd(iBc)           &
              &                        %faces(iDir,iAlign) &
              &                        %facePos,           &
              &          val = facePos                     )
            call append( me  = material%material_desc      &
              &                        %bnd_faces(matType) &
              &                        %boundary           &
              &                        %bnd(iBc)           &
              &                        %faces(iDir,iAlign) &
              &                        %neighPos,          &
              &          val = neighPos                    )

            if (use_timer) then
              call tem_stopTimer( me          = atl_elemTimers, &
                &                 timerHandle = elemPos         )
            end if
          end do faceLoop
        end do alignLoop
      end do dirLoop
    end do bcLoop

  end subroutine atl_create_materialBoundaryList
  ! ****************************************************************************


  ! ****************************************************************************
  !> Create separate compute list for constant-constant, constant-variable (or
  !! vice versa) and variable-variable material parameter compute faces on this
  !! rank.
  subroutine atl_create_materialComputeList( mesh, spatial_dim, material, &
    &                                        materialFun )
    ! --------------------------------------------------------------------------
    !> Description of the mesh
    type(atl_cube_elem_type), intent(in) :: mesh
    !> The spatial dimension
    integer, intent(in) :: spatial_dim
    !> The description of the material properties. The compute lists in the
    !! material description is filled up by calling this subroutine.
    type(atl_material_type), intent(inout) :: material
    !! The indizes of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(in) :: materialFun
    ! --------------------------------------------------------------------------
    type(grw_intArray_type) :: faceLists(2)
    integer :: iDir, iFace, iList, iMat
    integer :: facePos
    logical :: left_isConst, right_isConst
    integer :: compute_type
    integer :: computeIndex, nFaces
    ! --------------------------------------------------------------------------

    ! Iterate over all the levels and the spatial directions and prepare the
    ! separate compute lists
    do iDir = 1,spatial_dim

      ! Init the temporary index lists
      call init( me = faceLists(1), length = 16 )
      call init( me = faceLists(2), length = 16 )

        ! We iterate over all the compute faces and check left and right
      ! material position. Then we check the combination of the adjacent
      ! materials and decide what we do with this face.
      faceLoop: do iFace = 1, size( mesh%faces%faces(iDir)%computeFace &
        &                                                 %facePos     )

        facePos = mesh%faces%faces(iDir)%computeFace%FacePos(iFace)

        ! Check if the left and right material property are constants
        left_isConst = .true.
        right_isConst = .true.
        do iMat = 1, materialFun%nMat
          if (associated(material%material_desc               &
              &                          %material_face(iDir) &
              &                          %mat( FacePos,       &
              &                                tem_left,      &
              &                                iMat )         &
              &                          %stFunPtr)           ) then
            left_isConst = left_isConst                          &
              & .and. 'const' == material%material_desc          &
              &                          %material_face(iDir)    &
              &                          %mat( FacePos,          &
              &                                tem_left,         &
              &                                iMat )            &
              &                          %stFunPtr               &
              &                          %fun_kind
          end if
          if (associated(material%material_desc               &
              &                          %material_face(iDir) &
              &                          %mat( FacePos,       &
              &                                tem_right,     &
              &                                iMat )         &
              &                          %stFunPtr)           ) then
            right_isConst = right_isConst                       &
              & .and. 'const' == material%material_desc         &
              &                          %material_face(iDir)   &
              &                          %mat( FacePos,         &
              &                                tem_right,       &
              &                                iMat )           &
              &                          %stFunPtr              &
              &                          %fun_kind
          end if
        end do !iMat

        ! Check if both are constants or at least one of them has a variable
        ! coefficient.
        if (left_isConst.and.right_isConst) then
          compute_type = atl_pureConstMat_prp
        else
          compute_type = atl_mixedMat_prp
        end if

        ! add this face index to the corresponding list
        call append( me = faceLists(compute_type), val = iFace )

      end do faceLoop

      ! Build up the final compute lists from the temporary arrays.
      ! We build one for the atl_pureConstMat_prp -> iList=1
      ! and another one for atl_mixedMat_prp -> iList=2 .
      do iList = 1, 2
        nFaces = faceLists(iList)%nVals

        if ( .not. allocated( material%material_desc           &
          &                           %computeFace(iDir,iList) &
          &                           %facePos) ) then
          allocate(                            &
            & material%material_desc           &
            &         %computeFace(iDir,iList) &
            &         %facePos(nFaces),        &
            & material%material_desc           &
            &         %computeFace(iDir,iList) &
            &         %leftPos(nFaces),        &
            & material%material_desc           &
            &         %computeFace(iDir,iList) &
            &         %rightPos(nFaces)        )
        end if

        do iFace = 1, nFaces
          ! Get the index in the original compute face list
          computeIndex = faceLists(iList)%val(iFace)
          ! Get the face position from the original face description
          material%material_desc           &
            &     %computeFace(iDir,iList) &
            &     %facePos(iFace)          &
            & = mesh%faces                 &
            &       %faces(iDir)           &
            &       %computeFace           &
            &       %facePos(computeIndex)
          ! Get the left element's position from the original face description
          material%material_desc           &
            &     %computeFace(iDir,iList) &
            &     %leftPos(iFace)          &
            & = mesh%faces                 &
            &       %faces(iDir)           &
            &       %computeFace           &
            &       %leftPos(computeIndex)
          ! Get the right element's position from the original face
          ! description
          material%material_desc           &
            &     %computeFace(iDir,iList) &
            &     %rightPos(iFace)         &
            & = mesh%faces                 &
            &       %faces(iDir)           &
            &       %computeFace           &
            &       %rightPos(computeIndex)
            end do !iFace
      end do !iList

      ! Clean up the temporary arrays on this level
      call destroy( me = faceLists(1) )
      call destroy( me = faceLists(2) )

    end do !iDir

  end subroutine atl_create_materialComputeList
  ! ****************************************************************************


  ! ****************************************************************************
  !> Define material properties for the faces of all fluid elements and inherit
  !! the face material property to all ghost elements on the finer level.
  subroutine atl_assign_face_matPrp( minLevel, maxLevel, mesh_list,            &
    &                                currentLevel, spatial_dim, material_list, &
    &                                materialFun                               )
    ! --------------------------------------------------------------------------
    integer,intent(in) :: minLevel, maxLevel
    !> List of  mesh for different kernels
    type(atl_cube_elem_type), intent(in) :: mesh_list(minlevel:maxlevel)
    !> currentLevel
    integer, intent(in) :: currentLevel
    !> The spatial dimension
    integer, intent(in) :: spatial_dim
    !> The description of the material properties on the element basis.
    type(atl_material_type), intent(inout) :: material_list(minlevel:maxlevel)
    !! The indices of variables in the global varSys that are used as
    !! material's, penalization's or whatever's data sources.
    !!
    !! This data is needed to calculate the number of total material components.
    type(atl_materialFun_type), intent(in) :: materialFun
    ! --------------------------------------------------------------------------
    integer :: nFluids
    integer :: facepos
    integer :: iDir, iFace, iAlign, invAlign, iMat
    integer :: elemPos, childPos(4), lrElemPos(2)
    integer :: nChilds
    integer :: matvarpos
    logical :: failed
    ! --------------------------------------------------------------------------


    failed = .false.
    nfluids = mesh_list(currentlevel)%descriptor%elem%nElems(eT_fluid)

    ! Assign the material properties to all faces
    dirloop: do iDir = 1, spatial_dim

      ! Total number of faces on this level for this direction,
      ! including ghosts.
      ! (Virtual) boundary elements will have indices greater than
      ! this, and we need to set the material of the inner adjacent
      ! element for these.

      faceloop: do iFace = 1, size( mesh_list(currentLevel)%faces       &
        &                                                  %faces(iDir) &
        &                                                  %computeFace &
        &                                                  %facePos )

        ! The position of this face in the complete list of faces on the
        ! level.
        facepos = mesh_list(currentLevel)%faces       &
          &                              %faces(iDir) &
          &                              %computeFace &
          &                              %facePos(iFace)

        ! Get the left and right element positions
        lrElemPos(1) = mesh_list(currentLevel)%faces         &
          &                                   %faces(iDir)   &
          &                                   %computeFace   &
          &                                   %leftPos(iFace)
        lrElemPos(2) = mesh_list(currentLevel)%faces          &
          &                                   %faces(iDir)    &
          &                                   %computeFace    &
          &                                   %rightPos(iFace)

        ! Look up left(1) and right(2) elements for all faces.
        do iAlign=1,2
          invAlign = tem_invFace_map(iAlign)
          if (lrElemPos(iAlign) <= nFluids) then
            elempos = lrelempos(iAlign)
          else if (lrElemPos(invAlign) <= nFluids) then
            ! There is no fluid neighbor on this side.
            ! We try to use the material from of the element
            ! on the other side of the face instead.
            elempos = lrElemPos(invAlign)
          else
            elempos = nFluids+1
            failed = .true.
          end if

          if (elempos <= nFluids) then
            ! Adjacent element is a fluid element, use its material for
            ! this side of the face.
            do iMat=1,materialFun%nMat
              matvarpos = material_list(currentLevel)%material_desc &
                &           %material_face(iDir)                    &
                &           %mat( facepos, iAlign, iMat )           &
                &           %matvarpos
              if (matvarpos == 0) then
                ! Only set the material, if it was not set already.
                ! If there is a refinement, the material might already be
                ! set by the coarser level.
                material_list(currentLevel)%material_desc                  &
                  &                        %material_face(iDir)            &
                  &                        %mat( facepos,                  &
                  &                              iAlign,                   &
                  &                              iMat )                    &
                  & = material_list(currentLevel)%material_desc            &
                  &                              %material_elems( ElemPos, &
                  &                                               iMat     )
              end if
            end do

          end if

        end do

      end do faceloop

      if (failed) then
        write(logunit(1),*) 'Ran into a computed face without fluid neighbor!'
        call tem_abort()
      end if


      ! Inherit the material position for the faces which have children
      ! on the next level (i.e. for all from finer faces).
      !
      ! Fluxes are computed on the finest level, so we only need to set the side
      ! towards the coarser elements to ensure that we have material information
      ! on the finest level for the fine ghost faces.
      if (currentLevel < maxLevel) then
        nChilds = size(mesh_list(currentlevel)%faces%faces(iDir) &
          &                                         %faceDep &
          &                                         %childFacePos, 1)
        do iAlign = 1, 2
          do iFace = 1, size( mesh_list(currentLevel)%faces                 &
            &                                        %faces(iDir)           &
            &                                        %fromFinerFace(iAlign) &
            &                                        %facePos               )

            ! Position of this from finer face in the face list.
            facepos = mesh_list(currentLevel)%faces                 &
              &                              %faces(iDir)           &
              &                              %fromFinerFace(iAlign) &
              &                              %facePos(iFace)

            ! The children's face positions
            childPos(:nChilds) = mesh_list(currentLevel) &
              &                    %faces%faces(iDir)    &
              &                    %facedep%childfacepos(:,facepos)

            ! The parent's neighboring coarse element (on the opposite side of
            ! this from finer face side).
            elemPos = mesh_list(currentLevel)%faces                 &
              &                              %faces(iDir)           &
              &                              %fromFinerFace(iAlign) &
              &                              %elemPosOp(iFace)

            do iMat = 1,  materialFun%nMat
              ! Set the material of the child faces according to
              ! their parents element material.
              material_list(currentLevel+1)                   &
                & %material_desc                              &
                & %material_face(iDir)                        &
                & %mat(childPos(:nChilds), iAlign, iMat)      &
                & = material_list(currentLevel)%material_desc &
                &                              %material_elems(elemPos, iMat)
            end do
          end do
        end do
      end if
    end do dirloop

  end subroutine atl_assign_face_matPrp
  ! ****************************************************************************


end module atl_materialIni_module