!# This source file is part of code Pégase.3.0.1 (2019-02-21).
!# Copyright: Michel Fioc (Michel.Fioc@iap.fr), Sorbonne université, 
!# Institut d'astrophysique de Paris/CNRS, France.
!# 
!# Pégase.3.0.1 is governed by the CeCILL license under French law and abides 
!# by the rules of distribution of free software. You can use, modify and/or 
!# redistribute this software under the terms of the CeCILL license as circulated 
!# by CEA, CNRS and INRIA at "http://www.cecill.info". The text of this license
!# is also available in French and in English in directory "doc_dir/" of this
!# code.
!# 
!# As a counterpart to the access to the source code and to the rights to copy,
!# modify and redistribute it granted by the license, users are provided only
!# with a limited warranty, and the software's author, the holder of the
!# economic rights, and the successive licensors have only limited
!# liability. 
!# 
!# The fact that you are presently reading this means that you have had
!# knowledge of the CeCILL license and that you accept its terms.
!#====================================================================== 

module mod_read_SF_param

  use mod_types
  use mod_analyze_statement, only : get_val, file_name, line_number, &
       error_message, warning_message
  use mod_convert_type, only : to_string
  use mod_spectra_constants, only : max_dim_SF_epis

  implicit none
  public
  real(CDR), dimension(max_dim_SF_epis), save :: SF_begin_time, SF_end_time
  character(len=std_string), dimension(max_dim_SF_epis), save :: SF_type
  real(CDR), dimension(max_dim_SF_epis), save :: SF_inst_mass, &
       SF_const_mass, &
       SF_expo_timescale, SF_expo_mass, &
       SF_peaked_timescale, SF_peaked_mass, &
       SF_ISM_timescale, SF_ISM_power, SF_ISM_threshold, &
       SF_infall_factor
  character(len=std_string), dimension(max_dim_SF_epis), save :: SF_file
  integer, dimension(max_dim_SF_epis), save :: SF_file_dim_time
  type(irreg_array_CDR), dimension(max_dim_SF_epis), save :: SF_file_time, &
       SF_file_rate

  logical, dimension(max_dim_SF_epis), save :: SF_stochastic
  real(CDR), dimension(max_dim_SF_epis), save :: SF_stoch_sigma, & !# Used in \
!# subroutine `evolution`, but not an input parameter: derived from \
!# `SF_stoch_fluc`.
       SF_stoch_fluc, & !# Output by subroutine `write_scenario_param`.
       SF_stoch_timescale
  character(len=std_string), dimension(max_dim_SF_epis), save :: SF_Z_type
  real(CDR), dimension(max_dim_SF_epis), save :: SF_Z_const_val
  character(len=std_string), dimension(max_dim_SF_epis), save :: SF_Z_file
  integer, dimension(max_dim_SF_epis), save :: SF_Z_file_dim_time
  type(irreg_array_CDR), dimension(max_dim_SF_epis), save :: SF_Z_file_time, &
       SF_Z_file_Z
  real(CDR), dimension(max_dim_SF_epis), save :: SF_inert_frac

!# Variables for which no default value exists.

  logical, dimension(max_dim_SF_epis), private :: SF_file_set, &
       SF_expo_timescale_set, &
       SF_peaked_timescale_set, &
       SF_ISM_timescale_set, &
       SF_stoch_fluc_set, SF_stoch_timescale_set, &
       SF_Z_const_val_set, &
       SF_Z_file_set

contains

!#======================================================================
  
  subroutine reset_SF

    use mod_spectra_def_param
    implicit none
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    SF_begin_time(:) = SF_begin_time_def
    SF_end_time(:) = SF_end_time_def

    SF_type(:) = SF_type_def

    SF_inst_mass(:) = SF_inst_mass_def

    SF_const_mass(:) = SF_const_mass_def

    SF_expo_timescale_set(:) = .false.
    SF_expo_mass(:) = SF_expo_mass_def

    SF_peaked_timescale_set(:) = .false.
    SF_peaked_mass(:) = SF_peaked_mass_def

    SF_ISM_timescale_set(:) = .false.
    SF_ISM_power(:) = SF_ISM_power_def
    SF_ISM_threshold(:) = SF_ISM_threshold_def

    SF_infall_factor(:) = SF_infall_factor_def

    SF_file_set(:)  = .false.

    SF_stochastic(:) = SF_stochastic_def
    SF_stoch_fluc_set(:) = .false.
    where (SF_stoch_fluc_set(:)) SF_stoch_sigma(:) = &
         sqrt(log(1+SF_stoch_fluc(:)**2))
    SF_stoch_timescale_set(:) = .false.

    SF_Z_type(:) = SF_Z_type_def
    SF_Z_const_val_set(:) = .false.
    SF_Z_file_set(:) = .false.

    SF_inert_frac(:) = SF_inert_frac_def

  end subroutine reset_SF

!#======================================================================

  subroutine SF_check

    implicit none
!#......................................................................
    integer :: i_epis
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    do i_epis = 1, max_dim_SF_epis
       if (SF_type(i_epis) == "none") cycle

       if (SF_type(i_epis) == "exponential") then
          if (.not. SF_expo_timescale_set(i_epis)) then
             call error_message("Value of `SF_expo_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (SF_type(i_epis) == "peaked") then
          if (.not. SF_peaked_timescale_set(i_epis)) then
             call error_message("Value of `SF_peaked_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (SF_type(i_epis) == "ISM_mass") then
          if (.not. SF_ISM_timescale_set(i_epis)) then
             call error_message("Value of `SF_ISM_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif
 
       if (SF_type(i_epis) == "file") then
          if (.not. SF_file_set(i_epis)) then
             call error_message("Value of `SF_file(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (SF_stochastic(i_epis)) then
          if (.not. SF_stoch_fluc_set(i_epis)) then
             call error_message("Value of `SF_stoch_fluc(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
          if (.not. SF_stoch_timescale_set(i_epis)) then
             call error_message("Value of `SF_stoch_timescale(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (SF_Z_type(i_epis) == "file") then
          if (.not. SF_Z_file_set(i_epis)) then
             call error_message("Value of `SF_Z_file(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       else if (SF_Z_type(i_epis) == "constant") then
          if (.not. SF_Z_const_val_set(i_epis)) then
             call error_message("Value of `SF_Z_const_val(" // &
                  to_string(i_epis) // ")` is unknown.")
          endif
       endif

       if (SF_end_time(i_epis) <= SF_begin_time(i_epis)) then
          call warning_message("Warning: `SF_end_time(" // &
               to_string(i_epis) // ")` = " // &
               to_string(SF_end_time(i_epis), "(f6.0)") // &
               " <= `SF_begin_time(" // to_string(i_epis) // ")` = " // &
               to_string(SF_begin_time(i_epis), "(f6.0)") // ".")
       endif
    enddo

  end subroutine SF_check

!#======================================================================

  subroutine read_SF_begin_time(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_begin_time, rhs, indices_string, index_present)
    where (SF_begin_time(:) > 0)
!# To make sure that the interval is closed on the left.
       SF_begin_time(:) = nearest(SF_begin_time(:), -1.) 
    end where

  end subroutine read_SF_begin_time

!#======================================================================

  subroutine read_SF_end_time(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_end_time, rhs, indices_string, index_present)
    where (SF_end_time(:) > 0)
!# To make sure that the interval is open on the right.
       SF_end_time(:) = nearest(SF_end_time(:), -1.)
    end where

  end subroutine read_SF_end_time

!#======================================================================

  subroutine read_SF_type(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
    integer :: i_epis
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_type, rhs, indices_string, index_present)
    do i_epis = 1, max_dim_SF_epis
       if (index_present(i_epis)) then
          if (all(SF_type(i_epis) /= (/ &
               "none         ", &
               "instantaneous", &
               "constant     ", &
               "exponential  ", &
               "peaked       ", &
               "ISM_mass     ", &
               "infall       ", &
               "file         "/))) &
               call error_message("The value of `SF_type(" // &
               to_string(i_epis) // ")` should be ""none"", &
               &""instantaneous"", ""constant"", ""exponential"", &
               &""peaked"", ""ISM_mass"", ""infall"" or ""file"".")
       endif
    enddo

  end subroutine read_SF_type

!#======================================================================

  subroutine read_SF_inst_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_inst_mass, rhs, indices_string, index_present)
    call set_SF_type(index_present, "instantaneous")

  end subroutine read_SF_inst_mass

!#======================================================================

  subroutine read_SF_const_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_const_mass, rhs, indices_string, index_present)
    call set_SF_type(index_present, "constant")

  end subroutine read_SF_const_mass

!#======================================================================

  subroutine read_SF_expo_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_expo_timescale, rhs, indices_string, index_present)
    where (index_present(:)) SF_expo_timescale_set(:) = .true.
    call set_SF_type(index_present, "exponential")

  end subroutine read_SF_expo_timescale

!#======================================================================

  subroutine read_SF_expo_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_expo_mass, rhs, indices_string, index_present)
    call set_SF_type(index_present, "exponential")

  end subroutine read_SF_expo_mass

!#======================================================================
  
!# Parametrization of Sandage-like (1986; A&A 161, 89) star formation 
!# histories.

  subroutine read_SF_peaked_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_peaked_timescale, rhs, indices_string, index_present)
    where (index_present(:)) SF_peaked_timescale_set(:) = .true.
    call set_SF_type(index_present, "peaked")

  end subroutine read_SF_peaked_timescale

!#======================================================================

  subroutine read_SF_peaked_mass(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_peaked_mass, rhs, indices_string, index_present)
    call set_SF_type(index_present, "peaked")

  end subroutine read_SF_peaked_mass

!#======================================================================

  subroutine read_SF_ISM_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_ISM_timescale, rhs, indices_string, index_present)
    where (index_present(:)) SF_ISM_timescale_set(:) = .true.
    call set_SF_type(index_present, "ISM_mass")

  end subroutine read_SF_ISM_timescale

!#======================================================================

  subroutine read_SF_ISM_power(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_ISM_power, rhs, indices_string, index_present)
    call set_SF_type(index_present, "ISM_mass")

  end subroutine read_SF_ISM_power

!#======================================================================

  subroutine read_SF_ISM_threshold(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_ISM_threshold, rhs, indices_string, index_present)
    call set_SF_type(index_present, "ISM_mass")

  end subroutine read_SF_ISM_threshold

!#======================================================================

  subroutine read_SF_infall_factor(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_infall_factor, rhs, indices_string, index_present)
    call set_SF_type(index_present, "infall")

  end subroutine read_SF_infall_factor

!#======================================================================

  subroutine read_SF_file(rhs, indices_string)

    use mod_strings, only : same_case_equal
    use mod_directories, only : scenarios_dir
    use mod_read_columns
    use mod_file_access, only : path_file

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    integer :: i_epis
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_file, rhs, indices_string, index_present)

    do i_epis = 1, max_dim_SF_epis
       if (index_present(i_epis)) then
          call read_columns(path_file(scenarios_dir, adjustl(SF_file(i_epis))), &
               SF_file_dim_time(i_epis), SF_file_time(i_epis) % val, &
               SF_file_rate(i_epis) % val)
       endif
    enddo

    where (index_present(:)) SF_file_set(:) = .true.
    call set_SF_type(index_present, "file")

  end subroutine read_SF_file

!#======================================================================

  subroutine read_SF_stochastic(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_stochastic, rhs, indices_string, index_present)

  end subroutine read_SF_stochastic

!#======================================================================

  subroutine read_SF_stoch_fluc(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_stoch_fluc, rhs, indices_string, index_present)
    where (index_present(:))
       SF_stoch_fluc_set(:) = .true.
       SF_stoch_sigma(:) = sqrt(log(1+SF_stoch_fluc(:)**2))
    end where
    call set_SF_stochastic(index_present)

  end subroutine read_SF_stoch_fluc

!#======================================================================

  subroutine read_SF_stoch_timescale(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_stoch_timescale, rhs, indices_string, index_present)
    where (index_present(:)) SF_stoch_timescale_set(:) = .true.
    call set_SF_stochastic(index_present)

  end subroutine read_SF_stoch_timescale

!#======================================================================

  subroutine read_SF_Z_type(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
    integer :: i_epis
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_Z_type, rhs, indices_string, index_present)
    do i_epis = 1, max_dim_SF_epis
       if (index_present(i_epis)) then
          if (all(SF_Z_type(i_epis) /= (/ &
               "consistent", &
               "constant  ", &
               "file      "/))) &
               call error_message("The value of `SF_Z_type(" // &
               to_string(i_epis) // ")` should be ""consistent"", &
               &""constant"" or ""file"".")
       endif
    enddo

  end subroutine read_SF_Z_type

!#======================================================================

  subroutine read_SF_Z_const_val(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_Z_const_val, rhs, indices_string, index_present)
    where (index_present(:)) SF_Z_const_val_set(:) = .true.
    call set_SF_Z_type(index_present, "constant")

  end subroutine read_SF_Z_const_val

!#======================================================================

  subroutine read_SF_Z_file(rhs, indices_string)

    use mod_strings, only : same_case_equal
    use mod_directories, only : scenarios_dir
    use mod_read_columns
    use mod_file_access, only : path_file
    
    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    integer :: i_epis
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_Z_file, rhs, indices_string, index_present)

    do i_epis = 1, max_dim_SF_epis
       if (index_present(i_epis)) then
          call read_columns(path_file(scenarios_dir, adjustl(SF_Z_file(i_epis))), &
               SF_Z_file_dim_time(i_epis), SF_Z_file_time(i_epis) % val, &
               SF_Z_file_Z(i_epis) % val)
       endif
    enddo

    where (index_present(:)) SF_Z_file_set(:) = .true.
    call set_SF_Z_type(index_present, "file")

  end subroutine read_SF_Z_file

!#======================================================================

  subroutine read_SF_inert_frac(rhs, indices_string)

    implicit none
    character(len=*), intent(in) :: rhs
    character(len=*), intent(inout) :: indices_string
!#......................................................................
    logical, dimension(max_dim_SF_epis) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    call get_val(SF_inert_frac, rhs, indices_string, index_present)

  end subroutine read_SF_inert_frac

!#======================================================================

  subroutine set_SF_type(index_present, string)

    implicit none
    logical, dimension(:), intent(in) :: index_present
    character(len=*), intent(in) :: string
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    where (index_present(:)) SF_type(:) = string

  end subroutine set_SF_type

!#======================================================================

  subroutine set_SF_stochastic(index_present)

    implicit none
    logical, dimension(:), intent(in) :: index_present
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    where (index_present(:)) SF_stochastic(:) = .true.

  end subroutine set_SF_stochastic

!#======================================================================

  subroutine set_SF_Z_type(index_present, string)

    implicit none
    logical, dimension(:), intent(in) :: index_present
    character(len=*), intent(in) :: string
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
    where (index_present(:)) SF_Z_type(:) = string

  end subroutine set_SF_Z_type

end module mod_read_SF_param
