!= NAMELIST 繝輔ぃ繧､繝ｫ蜈･蜉帙↓髢｢縺吶ｋ繝ｦ繝ｼ繝�ぅ繝ｪ繝�ぅ
!
!= Utilities for NAMELIST file input
!
! Authors::   Yasuhiro Morikawa, Yoshiyuki O. Takahashi
! Version::   $Id: namelist_util.f90,v 1.4 2013/09/21 14:40:07 yot Exp $
! Tag Name::  $Name:  $
! Copyright:: Copyright (C) GFD Dennou Club, 2008. All rights reserved.
! License::   See COPYRIGHT[link:../../../COPYRIGHT]
!

module namelist_util
  !
  != NAMELIST 繝輔ぃ繧､繝ｫ蜈･蜉帙↓髢｢縺吶ｋ繝ｦ繝ｼ繝�ぅ繝ｪ繝�ぅ
  !
  != Utilities for NAMELIST file input
  !
  ! <b>Note that Japanese and English are described in parallel.</b>
  !
  !== Variables List
  !
  ! namelist_filename :: NAMELIST 繝輔ぃ繧､繝ｫ縺ｮ蜷咲ｧｰ.
  ! MaxNmlArySize     :: NAMELIST 縺九ｉ隱ｭ縺ｿ霎ｼ繧驟榊�縺ｮ譛螟ｧ繧ｵ繧､繧ｺ.
  ! ------------      :: ------------
  ! namelist_filename :: NAMELIST file name
  ! MaxNmlArySize     :: Maximum size of arrays loaded from NAMELIST
  !
  !== Procedures List
  !
  ! NmlutilInit      :: NAMELIST 繝輔ぃ繧､繝ｫ蜷阪�險ｭ螳�
  ! NmlutilMsg       :: NAMELIST 繝輔ぃ繧､繝ｫ蜈･蜉帙↓髢｢縺吶ｋ繝｡繝�そ繝ｼ繧ｸ陦ｨ遉ｺ
  ! NmlutilAryValid  :: NAMELIST 繝輔ぃ繧､繝ｫ縺九ｉ隱ｭ縺ｿ霎ｼ繧薙□驟榊�縺ｮ譛牙柑諤ｧ繧偵メ繧ｧ繝�け
  ! ------------  :: ------------
  ! NmlutilInit      :: Settings of NAMELIST file name
  ! NmlutilMsg       :: Print messages about NAMELIST file input
  ! NmlutilAryValid  :: Check validation of arrays loaded from NAMELIST file

  ! 繝｢繧ｸ繝･繝ｼ繝ｫ蠑慕畑 ; USE statements
  !

  ! 遞ｮ蛻･蝙九ヱ繝ｩ繝｡繧ｿ
  ! Kind type parameter
  !
  use dc_types, only: STRING  ! 譁�ｭ怜�. Strings.

  ! 繝｡繝�そ繝ｼ繧ｸ蜃ｺ蜉�
  ! Message output
  !
  use dc_message, only: MessageNotify

  ! 螳｣險譁� ; Declaration statements
  !
  implicit none
  private

  ! 蜈ｬ髢区焔邯壹″
  ! Public procedure
  !
  public:: NmlutilInit, NmlutilMsg, NmlutilAryValid

  ! 蜈ｬ髢句､画焚
  ! Public variables
  !
  logical, save, public:: namelist_util_inited = .false.
                              ! 蛻晄悄險ｭ螳壹ヵ繝ｩ繧ｰ.
                              ! Initialization flag
  character(STRING), save, public:: namelist_filename = ''
                              ! NAMELIST 繝輔ぃ繧､繝ｫ縺ｮ蜷咲ｧｰ.
                              ! NAMELIST file name

  integer, parameter, public:: MaxNmlArySize = 256
                              ! NAMELIST 縺九ｉ隱ｭ縺ｿ霎ｼ繧驟榊�縺ｮ譛螟ｧ繧ｵ繧､繧ｺ.
                              ! Maximum size of arrays loaded from NAMELIST

  ! 髱槫�髢句､画焚
  ! Private variables
  !

  !  NAMELIST 螟画焚鄒､
  !  NAMELIST group name
  !
!!$  namelist /namelist_util_nml/ MaxNmlArySize

  character(*), parameter:: module_name = 'namelist_util'
                              ! 繝｢繧ｸ繝･繝ｼ繝ｫ縺ｮ蜷咲ｧｰ.
                              ! Module name
  character(*), parameter:: version = &
    & '$Name:  $' // &
    & '$Id: namelist_util.f90,v 1.4 2013/09/21 14:40:07 yot Exp $'
                              ! 繝｢繧ｸ繝･繝ｼ繝ｫ縺ｮ繝舌�繧ｸ繝ｧ繝ｳ
                              ! Module version

contains

  subroutine NmlutilInit(  &
    & namelist_filename_in & ! (in)
    & )
    !
    ! namelist_util 繝｢繧ｸ繝･繝ｼ繝ｫ縺ｮ蛻晄悄險ｭ螳壹ｒ陦後＞縺ｾ縺�.
    !
    ! Initialize "namelist_util" module.
    !

    ! 繝｢繧ｸ繝･繝ｼ繝ｫ蠑慕畑 ; USE statements
    !

    ! 繝輔ぃ繧､繝ｫ蜈･蜃ｺ蜉幄｣懷勧
    ! File I/O support
    !
    use dc_iounit, only: FileOpen

    ! 螳｣險譁� ; Declaration statements
    !
    implicit none

    character(*), intent(in ) :: namelist_filename_in
                              ! NAMELIST 繝輔ぃ繧､繝ｫ縺ｮ蜷咲ｧｰ.
                              ! NAMELIST file name

!!$    integer:: unit_nml        ! NAMELIST 繝輔ぃ繧､繝ｫ繧ｪ繝ｼ繝励Φ逕ｨ陬�ｽｮ逡ｪ蜿ｷ.
!!$                              ! Unit number for NAMELIST file open
!!$    integer:: iostat_nml      ! NAMELIST 隱ｭ縺ｿ霎ｼ縺ｿ譎ゅ� IOSTAT.
!!$                              ! IOSTAT of NAMELIST read

    ! 螳溯｡梧枚 ; Executable statement
    !

    if ( namelist_util_inited ) return
    namelist_filename = namelist_filename_in

    ! NAMELIST 縺ｮ隱ｭ縺ｿ霎ｼ縺ｿ
    ! NAMELIST is input
    !
!!$    call FileOpen( unit_nml, &          ! (out)
!!$      & namelist_filename, mode = 'r' ) ! (in)
!!$
!!$    rewind( unit_nml )
!!$    read( unit_nml, &               ! (in)
!!$      & nml = namelist_util_nml, &  ! (out)
!!$      & iostat = iostat_nml )       ! (out)
!!$    close( unit_nml )
!!$
!!$    call NmlutilMsg( iostat_nml, module_name ) ! (in)

    ! 蜊ｰ蟄� ; Print
    !
    call MessageNotify( 'M', module_name, '----- Initialization Messages -----' )
    call MessageNotify( 'M', module_name, '  MaxNmlArySize = %d', i = (/ MaxNmlArySize /) )
    call MessageNotify( 'M', module_name, '-- version = %c', c1 = trim(version) )

    namelist_util_inited = .true.
  end subroutine NmlutilInit

  subroutine NmlutilMsg( iostat, name & ! (in)
    & )
    !
    ! NAMELIST 繝輔ぃ繧､繝ｫ蜈･蜉帙せ繝��繧ｿ繧ｹ縺九ｉ
    ! 驕ｩ蛻�↑繝｡繝�そ繝ｼ繧ｸ繧定｡ｨ遉ｺ縺励∪縺�.
    !
    ! Appropriate messages are output from
    ! status of NAMELIST file loading.
    !

    implicit none
    integer, intent(in):: iostat
                              ! NAMELIST 隱ｭ縺ｿ霎ｼ縺ｿ譎ゅ�繧ｹ繝��繧ｿ繧ｹ.
                              ! Status of NAMELIST loading
    character(*), intent(in):: name
                              ! 繝｢繧ｸ繝･繝ｼ繝ｫ縺ｮ蜷咲ｧｰ.
                              ! Module name

    ! 螳溯｡梧枚 ; Executable statement
    !

    if ( iostat == 0 ) then
      call MessageNotify( 'M', name, &
        & 'NAMELIST group "%c" is loaded from "%c".', &
        & c1 = trim(name) // '_nml', &
        & c2 = trim(namelist_filename) )
    else if ( iostat > 0 ) then
      call MessageNotify( 'E', name, &
        & 'NAMELIST group "%c" has something wrong in "%c" (iostat=%d).', &
        & c1 = trim(name) // '_nml', &
        & c2 = trim(namelist_filename), &
        & i = (/iostat/) )
    else
      call MessageNotify( 'W', name, &
        & 'NAMELIST group "%c" is not found in "%c" (iostat=%d).', &
        & c1 = trim(name) // '_nml', &
        & c2 = trim(namelist_filename), &
        & i = (/iostat/) )
    end if

  end subroutine NmlutilMsg

  subroutine NmlutilAryValid( name, &               ! (in)
    & array, array_name, need_num, need_num_name, & ! (in)
    & valid_limit &                                 ! (in) optional
    )
    !
    ! NAMELIST 縺九ｉ隱ｭ縺ｿ霎ｼ繧薙□驟榊�蝙九ョ繝ｼ繧ｿ縺ｮ螯･蠖捺ｧ繧�
    ! 繝√ぉ繝�け縺励∪縺�.
    !
    ! 繝�ヵ繧ｩ繝ｫ繝医〒縺ｯ, 豁｣縺ｮ蛟､繧呈怏蜉ｹ縺ｨ謇ｱ縺�∪縺�.
    ! 辟｡蜉ｹ縺ｧ縺ゅｋ縺ｨ讀懆ｨｼ縺輔ｌ縺溷�ｴ蜷医↓縺ｯ, 繧ｨ繝ｩ繝ｼ繧堤匱逕溘＆縺帙∪縺�.
    !
    ! Check validation of array data loaded from NAMELIST.
    !
    ! By defaut, positive values are treated as valid values.
    ! If invalidation is checked, an error is occurred.
    !

    ! 繝｢繧ｸ繝･繝ｼ繝ｫ蠑慕畑 ; USE statements
    !

    ! 遞ｮ蛻･蝙九ヱ繝ｩ繝｡繧ｿ
    ! Kind type parameter
    !
    use dc_types, only: DP      ! 蛟咲ｲｾ蠎ｦ螳滓焚蝙�. Double precision.

    ! 螳｣險譁� ; Declaration statements
    !
    implicit none
    character(*), intent(in):: name
                              ! 縺薙�繧ｵ繝悶Ν繝ｼ繝√Φ繧貞他縺ｳ蜃ｺ縺吶Δ繧ｸ繝･繝ｼ繝ｫ縺ｮ蜷咲ｧｰ.
                              ! Module name calling this subroutine
    real(DP), intent(in):: array(:)
                              ! 讀懆ｨｼ縺吶∋縺埼�蛻励ョ繝ｼ繧ｿ.
                              ! Checked array data
    character(*), intent(in):: array_name
                              ! 讀懆ｨｼ縺吶∋縺埼�蛻励ョ繝ｼ繧ｿ縺ｮ蜷榊燕.
                              ! Name of checked array data
    integer, intent(in):: need_num
                              ! 蠢�ｦ√↑繝��繧ｿ謨ｰ.
                              ! 0 譛ｪ貅縺ｮ謨ｰ繧剃ｸ弱∴繧九→繧ｨ繝ｩ繝ｼ繧堤函縺倥∪縺�.
                              !
                              ! Number of needed data.
                              ! If number less than 0, an error is occurred.
    character(*), intent(in):: need_num_name
                              ! 蠢�ｦ√↑繝��繧ｿ謨ｰ繧堤､ｺ縺吝､画焚縺ｮ蜷榊燕.
                              ! Name of a variable that indicates number of needed data
    real(DP), intent(in), optional:: valid_limit
                              ! 譛牙柑荳矩剞蛟､ (繝�ヵ繧ｩ繝ｫ繝医� 0.0).
                              ! Lower limit of validation (defalt is 0.0)

    ! 菴懈･ｭ螟画焚
    ! Work variables
    !
    real(DP):: valid_limit_work
                              ! 譛牙柑荳矩剞蛟､ (繝�ヵ繧ｩ繝ｫ繝医� 0.0).
                              ! Lower limit of validation (defalt is 0.0)
    integer:: valid_count     ! 驟榊�繝��繧ｿ縺ｮ譛牙柑蛟､縺ｮ謨ｰ.
                              ! Number of valid values in an array
    integer:: size_array      ! 驟榊�繝��繧ｿ縺ｮ繧ｵ繧､繧ｺ
                              ! Size of array data

    ! 螳溯｡梧枚 ; Executable statement
    !

    ! need_num 縺瑚ｲ�縺ｧ縺ｯ縺ｪ縺�％縺ｨ繧偵メ繧ｧ繝�け
    ! Check that "need_num" is not negative
    !
    if ( need_num < 0 ) then
      call MessageNotify( 'E', name, '%c=<%d> must not be negative.', &
        &                 c1 = trim(need_num_name), i = (/ need_num /) )
    end if

    ! array 縺ｮ繧ｵ繧､繧ｺ縺悟香蛻�〒縺ゅｋ縺薙→繧偵メ繧ｧ繝�け
    ! Check that size of "array" is enough
    !
    size_array = size(array)
    if ( need_num > size_array ) then
      call MessageNotify( 'E', name, &
        &  'Maximum size=<%d> of "%c" is too smaller than %c=<%d>. ' // &
        &  'Please search for a statement "MaxNmlArySize = %d" in ' // &
        &  '"namelist_util.f90", and change it into "MaxNmlArySize = %d".', &
!!$        &  'Please add a following phrase to NAMELIST file. ' // &
!!$        &  ' "&namelist_util_nml  MaxNmlArySize=%d /"', &
        &  i = (/ size_array, need_num, MaxNmlArySize, need_num /), &
        &  c1 = trim(array_name), c2 = trim(need_num_name) )
    end if

    ! array 繧偵メ繧ｧ繝�け
    ! Check "array"
    !
    if ( need_num > 0 ) then
      valid_limit_work = 0.0_DP
      if ( present( valid_limit ) ) valid_limit_work = valid_limit

      if ( any( array(1:need_num) < valid_limit_work ) ) then
        valid_count = count( .not. ( array(1:need_num) < valid_limit_work ) )
        if ( valid_count > 0 ) then
          call MessageNotify( 'E', name, &
            &   'Number of valid data of %c=<%*f> is %d. ' // &
            &   'Valid data is %c=<%d> necessary.', &
            &   c1 = trim( array_name ), c2 = trim( need_num_name ), &
            &   d = array(1:valid_count), n = (/ valid_count /), &
            &   i = (/ valid_count, need_num /) )
        else
          call MessageNotify( 'E', name, &
            &   'Valid data of %c is nothing. ' // &
            &   'Valid data is %c=<%d> necessary.', &
            &   c1 = trim( array_name ), c2 = trim( need_num_name ), &
            &   i = (/ need_num /) )
        end if
      end if
    end if

  end subroutine NmlutilAryValid

end module namelist_util