! See copyright notice in the COPYRIGHT file.
! ****************************************************************************** !
!> This module provides the definition and methods for
!! boundarys.
module mus_param_module

  ! include musubi modules
  use mus_physics_module,     only: mus_physics_type

  ! include treelm modules
  use env_module,             only: labelLen, rk
  use tem_logging_module,     only: logUnit
  use tem_general_module,     only: tem_general_type
  use tem_tools_module,       only: tem_horizontalSpacer

  ! include aotus modules
  use aotus_module,   only: flu_state, aot_get_val
  use aot_out_module, only: aot_out_type, aot_out_val

  implicit none

  private

  public :: mus_param_type
  public :: mus_load_param
  public :: mus_param_out

  integer, parameter :: block_size = 576

  !> Global parameter type definition, filled with
  type mus_param_type

    !> Treelm param parameter type
    type( tem_general_type ) :: general

    !> contains basic SI units to convert from lattice to physical and
    !! vice versa
    type(mus_physics_type) :: physics

    !> type of the control routine
    character(len=labelLen) :: controlRoutine
    !> initialize all elements with valid entries?
    !! This should only be activated for debugging, 
    !! as it needs to be ensured that all helper elements
    !! are filled by communication and interpolation instead
    !! of filling initial values (consider restart!)
    logical :: init_allElems = .false.
    !> type of the scaling:
    !! * acoustic
    !! * diffusive
    character(len=labelLen) :: scaling
    !> Temporal scaling factor for the scaling. Acoustic = 2, Diffusive = 4
    integer :: scaleFactor
    !> Nesting: 2: acoustic, 4: diffusive
    !! To calculate turbulent viscosity, velocity on buffer ghost elements 
    !! should be valid to nesting is set to same as scaling Factor 
    integer :: nNesting = 2
    !> Required interval, in which the update MUST occur.
    !! This is required for the musubi multilevel, where the time step should
    !! only be determined active, when the end of the largest cycle is reached.
    integer :: reqInterval
    logical :: comm_reduced = .true. !< Communicate all links?
    !> need to set solver version in  general%solver%version
    character(len=labelLen) :: version = 'v1.1'
    !> active when restart is triggered by restart timeControl
    !! dump restart when simulation reached end only when
    !! restart is not triggered by its timeControl before
    logical :: restart_triggered = .false.

    !> remove solid from BC list
    logical :: remove_solid = .true.

    !> Block size for compute kernel
    integer :: block = block_size

    !> Initial balance
    logical :: initial_balance = .false.

    !> scratch file unit contains solver specific info in dump in restart header
    !! This file should contain the information in form of a Lua script.
    !! KM: Not required anymore. Load config file name from restart header
    !! integer :: solSpec_unit = -1

    !> Dump level timing
    logical :: dump_level_timing = .false.

    !> Dump linear partition
    logical :: dump_linear_partition = .false.

    !> Dump computation and bc timing information for all ranks
    logical :: dump_bc_timing = .false.

  end type mus_param_type

contains

! ****************************************************************************** !
  !> load global parameter from conf
  subroutine mus_load_param( params, conf )
    ! ---------------------------------------------------------------------------
    !> global parameter info
    type(mus_param_type), intent(inout)  :: params
    !> lua state
    type(flu_state) :: conf
    ! ---------------------------------------------------------------------------
    integer :: iError
    ! ---------------------------------------------------------------------------
    write(logUnit(1),*) 'Loading general solver params: '
    ! Load the control routine
    call aot_get_val( L       = conf,                                          &
      &               key     = 'control_routine',                             &
      &               val     = params%controlRoutine,                         &
      &               ErrCode = iError,                                        &
      &               default = 'standard' )
    write(logUnit(1),*)'Choosing Control Routine: ', trim(params%controlRoutine)

    ! load scaling type
    ! KM: @todo move scaling inside physics table because for lbm
    ! default scaling is acoustic and for multi-species default is diffusive
    call aot_get_val( L       = conf,                                          &
      &               key     = 'scaling',                                     &
      &               val     = params%scaling,                                &
      &               ErrCode = iError,                                        &
      &               default = 'acoustic')
    write(logUnit(1),*) 'Setting SCALING to:',trim( params%scaling )

    ! Set acoustic or diffusive scaling parameters
    !! KM: To calculate turbulent viscosity, velocity on buffer ghost elements 
    !! should be valid to nesting is set to same as scaling Factor 
    select case( trim( params%scaling ))
    case('acoustic')
      params%nNesting = 2
      params%scaleFactor = 2
    case('diffusive')
      params%nNesting = 4
      params%scaleFactor = 4
    end select

    ! Communicate reduced set of links only? 
    call aot_get_val( L       = conf,                                          &
      &               key     = 'comm_reduced',                                &
      &               val     = params%comm_reduced,                           &
      &               ErrCode = iError,                                        &
      &               default = .true.)

    ! initialize all elements? this includes not only fluid but also ghost and
    ! halo
    call aot_get_val( L       = conf,                                          &
      &               key     = 'init_allElems',                               &
      &               val     = params%init_allElems,                          &
      &               ErrCode = iError,                                        &
      &               default = .false.)
    if( params%init_allElems ) then
      write(logUnit(1),*) 'WARNING: Initializing all (including helper '//     &
        &                           'elements) with valid data'
    end if

    call aot_get_val( L       = conf,                                          &
      &               key     = 'remove_solid',                                &
      &               val     = params%remove_solid,                           &
      &               ErrCode = iError,                                        &
      &               default = .true.)
    if( params%remove_solid ) then
      write(logUnit(1),"(A)") 'Solid elements will be removed from BC list'
    end if

    call aot_get_val( L       = conf,                     &
      &               key     = 'initial_balance',        &
      &               val     = params%initial_balance,   &
      &               ErrCode = iError,                   &
      &               default = .false.)

    call aot_get_val( L       = conf,                     &
      &               key     = 'dump_level_timing',      &
      &               val     = params%dump_level_timing, &
      &               ErrCode = iError,                   &
      &               default = .false.                   )

    call aot_get_val( L       = conf,                  &
      &               key     = 'dump_bc_timing',      &
      &               val     = params%dump_bc_timing, &
      &               ErrCode = iError,                &
      &               default = .false.                )

    call aot_get_val( L       = conf,                     &
      &               key     = 'dump_linear_partition',      &
      &               val     = params%dump_linear_partition, &
      &               ErrCode = iError,                   &
      &               default = .false.                   )

    call aot_get_val( L       = conf,         &
      &               key     = 'block',      &
      &               val     = params%block, &
      &               ErrCode = iError,       &
      &               default = block_size    )
    write(logUnit(1),"(A,I0)") 'Block size (elements): ', params%block

    call tem_horizontalSpacer(fUnit = logUnit(1))

  end subroutine mus_load_param
! ****************************************************************************** !


! ****************************************************************************** !
  !> This routine writes global parameter into solver specific string in lua
  !! format
  subroutine mus_param_out( me, conf )
    ! ---------------------------------------------------------------------------
    type( mus_param_type ), intent(in) :: me !< params
    type( aot_out_type ) :: conf
    ! ---------------------------------------------------------------------------
    call aot_out_val( put_conf = conf, vname = 'scaling', &
      &               val = trim(me%scaling) )

  end subroutine mus_param_out
! ****************************************************************************** !

end module mus_param_module
! ****************************************************************************** !

