!# 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_SSPs

  implicit none
  private
  public :: read_SSPs_set, read_SSP_Z

contains

!#======================================================================
  
  subroutine read_SSPs_set(SSPs_set, dim_SSP, SSP_file, used_SL_global, &
       stel_lib_set)

    use mod_types
    use mod_linked_list
    use mod_directories, only : SSPs_dir
    use mod_file_access, only : open_file, close_file, skip_comment_lines, &
         path_file

    implicit none
    character(len=*), intent(inout) :: SSPs_set
    character(len=*), intent(inout) :: stel_lib_set
    integer, intent(out) :: dim_SSP
    character(len=*), dimension(:), pointer :: SSP_file
    type(irreg_array_int), dimension(:), pointer :: used_SL_global
!#......................................................................
    integer :: i_SSP, unit_SSPs_set, error, unit_SSP, i_SL
    character(len=std_string) :: string
    type(lk_lst_std_string) :: head_node
    type(lk_lst_std_string), pointer :: current_node
    character(len=std_string) :: version_id, version_date
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

    call open_file(unit_SSPs_set, path_file(SSPs_dir, SSPs_set))
    read(unit_SSPs_set,*) version_id
    read(unit_SSPs_set,*) version_date 
    call skip_comment_lines(unit_SSPs_set)
    read(unit_SSPs_set, *, iostat = error) stel_lib_set
    call skip_comment_lines(unit_SSPs_set)

    dim_SSP = 0
    call lk_lst_initialize(head_node)
    do
       read(unit_SSPs_set, *, iostat = error) string
       if (error /= 0) exit
       dim_SSP = dim_SSP+1
       call lk_lst_new_node(head_node, current_node)
       current_node % val = string
    enddo
    call close_file(unit_SSPs_set)

    call lk_lst_to_array(head_node, SSP_file, dim_SSP)

!# Read the stellar libraries from the end of the file of SSPs.

    if (associated(used_SL_global)) deallocate(used_SL_global)
    allocate(used_SL_global(dim_SSP))
    do i_SSP = 1, dim_SSP
       call open_file(unit_SSP, path_file(SSPs_dir, SSP_file(i_SSP)), position="append")
       backspace(unit_SSP)
       read(unit_SSP, *) used_SL_global(i_SSP) % dim
       if (associated(used_SL_global(i_SSP) % val)) &
            deallocate(used_SL_global(i_SSP) % val)
       allocate(used_SL_global(i_SSP) % val(used_SL_global(i_SSP) % dim))

       backspace(unit_SSP)
       do i_SL = 1, used_SL_global(i_SSP) % dim
          backspace(unit_SSP)
       enddo
       do i_SL = 1, used_SL_global(i_SSP) % dim
          read(unit_SSP, *) used_SL_global(i_SSP) % val(i_SL)
       enddo
       call close_file(unit_SSP)
    enddo

  end subroutine read_SSPs_set

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

  subroutine read_SSP_Z(time_step, dim_output_age, output_age, &
       dim_convol_time, convol_time, &
       dim_SSP, i_SSP, SSP_file, Z_SSP, close_bin_frac, max_dim_spec, &
       dim_lambda_stel, &
       L_bol_SSP, lum_SSP, stellar_mass_SSP, inv_time, beta, &
       LC_rate_SSP, &
       ejec_rate_tot_SSP, ejec_rate_elem_SSP, carb_dust_prod_rate_SSP, &
       sil_dust_prod_rate_SSP, BHNS_mass_prod_rate_SSP, &
       WD_mass_prod_rate_SSP, stel_lib_file, used_SL_global, &
       dim_SL, &
       time_SSP, stel_lib, CCSN_rate_SSP, SNIa_rate_SSP, dim_elem, elem_id, &
       header_SSPs, LC_power_SSP)

    use mod_types
    use mod_linked_list
    use mod_read_dust_evol_param
    use mod_directories, only : SSPs_dir
    use mod_file_access, only : open_file, close_file, skip_lines, path_file
    use mod_convert_type, only : to_string
    use mod_stel_lib, only : spectra_read_stel_lib2, struct_stel_lib
    
    implicit none
    integer, intent(in) :: dim_SSP, i_SSP
    character(len=*), dimension(:), intent(in) :: SSP_file
    real(CDR), intent(in) :: close_bin_frac
    integer, intent(in) :: dim_lambda_stel, max_dim_spec
    real(CDR), intent(out) :: time_step
    integer, intent(inout) :: dim_output_age
    real(CDR), dimension(:), pointer :: output_age
    integer, intent(out) :: dim_convol_time
    real(CDR), dimension(:), pointer :: convol_time
    real(CDR), dimension(:, :), pointer :: L_bol_SSP
    real(CDR), dimension(:, :, :), pointer :: lum_SSP
    real(CDR), dimension(:, :), pointer :: stellar_mass_SSP
    integer, dimension(:), pointer :: inv_time
    real(CDR), dimension(:), pointer :: beta
    real(CDR), dimension(:, :), pointer :: LC_rate_SSP
    real(CDR), dimension(:, :), pointer :: ejec_rate_tot_SSP
    real(CDR), dimension(:, :, :), pointer :: ejec_rate_elem_SSP
    real(CDR), dimension(:, :), pointer :: carb_dust_prod_rate_SSP, &
         sil_dust_prod_rate_SSP
    real(CDR), dimension(:, :), pointer :: BHNS_mass_prod_rate_SSP, &
         WD_mass_prod_rate_SSP

    character(len=*), dimension(:), intent(in) :: stel_lib_file
    type(irreg_array_int), dimension(:), intent(in) :: used_SL_global
    integer, intent(in) :: dim_SL
    real(CDR), dimension(:), pointer :: time_SSP
    real(CDR), dimension(:), pointer :: Z_SSP
    real(CDR), dimension(:,:), pointer :: CCSN_rate_SSP, SNIa_rate_SSP
    integer, intent(out) :: dim_elem
    character(len=*), dimension(:), pointer :: elem_id
    type(struct_stel_lib), dimension(:), intent(inout) :: stel_lib

    type(lk_lst_long_string), dimension(:), pointer :: header_SSPs
    type(lk_lst_long_string), pointer :: header_node => null()

    real(CDR), dimension(:, :), pointer :: LC_power_SSP
!#......................................................................
    integer :: i_time_SSP, dim_time_SSP, unit_SSP
    real(CDR) :: x
    real(DPR) :: HI_rate_SSP, HI_rate_SSP_prev, HI_power_SSP, HI_power_SSP_prev
    real(CDR), dimension(max_dim_spec) :: L_spec
    real(CDR) :: nb_CCSN_IS, nb_CCSN_CB, nb_SNIa_int, mass_BHNS_SSP_IS, &
         mass_BHNS_SSP_CB, mass_WD_SSP_IS, mass_WD_SSP_CB
    real(CDR) :: ejec_tot_IS, ejec_tot_CB
    real(CDR), dimension(:), allocatable :: ejec_elem_IS, ejec_elem_CB
    real(CDR) :: ejec_carb_LMW_IS, ejec_sil_LMW_IS
    real(CDR) :: ejec_carb_HMW_IS, ejec_sil_HMW_IS, &
         ejec_carb_CCSN_IS, ejec_sil_CCSN_IS
    real(CDR) :: ejec_carb_LMW_CB, ejec_sil_LMW_CB
    real(CDR) :: ejec_carb_HMW_CB, ejec_sil_HMW_CB, &
         ejec_carb_CCSN_CB, ejec_sil_CCSN_CB, ejec_carb_SNIa, &
         ejec_sil_SNIa

    real(CDR) :: ejec_dust_O_LMW_IS, ejec_dust_O_HMW_IS, &
         ejec_dust_O_CCSN_IS, ejec_dust_O_LMW_CB, &
         ejec_dust_O_HMW_CB, ejec_dust_O_CCSN_CB, ejec_dust_O_SNIa

    real(CDR) :: delta_time, time, last_time_SSP

    integer :: n_used_SL, i_used_SL, i_SL, n_used_spec, i_spec
    integer, dimension(max_dim_spec) :: i_used_spec
    integer :: i_lambda
    character(len=len(header_SSPs(:) % val)) :: string
    integer, save :: dim_elem1
    character(len=std_string), dimension(:), allocatable, save :: elem1
    integer :: i_elem, i_convol
    integer, save :: dim_time_SSP1
    real(CDR), dimension(:), allocatable, save :: time_SSP1
    integer :: dim_time_tmp
    real(CDR), dimension(:), allocatable :: time_tmp

    character(len=std_string) :: version_id, version_date

    logical, dimension(:), allocatable, save :: SL_already_read
    logical, dimension(:), allocatable, save :: SL_needed
    logical, dimension(:), allocatable, save :: SL_must_read
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
    
!# Read stellar libraries used for this SSP which have not been read
!# previously for another SSP.

    if (i_SSP == 1) then
       if (associated(Z_SSP)) deallocate(Z_SSP)
       allocate(Z_SSP(dim_SSP))

       if (associated(header_SSPs)) deallocate(header_SSPs)
       allocate(header_SSPs(dim_SSP))

       if (allocated(SL_already_read)) deallocate(SL_already_read)
       allocate(SL_already_read(dim_SL))
       SL_already_read(:) = .false.

       if (allocated(SL_needed)) deallocate(SL_needed)
       allocate(SL_needed(dim_SL))

       if (allocated(SL_must_read)) deallocate(SL_must_read)
       allocate(SL_must_read(dim_SL))
    endif

    do i_SL = 1, dim_SL
       if (any(used_SL_global(i_SSP) % val(:) == i_SL)) then
          SL_needed(i_SL) = .true.
       else
          SL_needed(i_SL) = .false.
       endif
    enddo
    do i_SL = 1, dim_SL
       if (SL_needed(i_SL)) then
          if (SL_already_read(i_SL)) then
             SL_must_read(i_SL) = .false.
          else
             SL_must_read(i_SL) = .true.
             SL_already_read(i_SL) = .true. !# Anticipating...
          endif
       else
          if (SL_already_read(i_SL)) deallocate(stel_lib(i_SL) % lum_star)
          SL_must_read(i_SL) = .false.
          SL_already_read(i_SL) = .false. !# Once memory for the `i_SL`-th SL \
!#                                           has been freed.
       endif
    enddo

    do i_SL = 1, dim_SL
       if (SL_must_read(i_SL)) then
          call spectra_read_stel_lib2(stel_lib_file(i_SL), dim_lambda_stel, &
               stel_lib(i_SL) % lum_star)
       endif
    enddo
    
!# ??? Change notations? Read `L_spec` (contribution of stellar spectra to an SSP) 
!# and compute `lum_SSP` (monochromatic luminosity of an SSP).

    call open_file(unit_SSP, path_file(SSPs_dir, SSP_file(i_SSP)), skip = .false.)
    read(unit_SSP,*) version_id
    read(unit_SSP,*) version_date 
    call lk_lst_initialize(header_SSPs(i_SSP))
    do
       read(unit_SSP, "(a)") string !# Not `read(unit_SSP, *) string`, otherwise \
!#                                     everything is lost after the first space.
       string = adjustl(string)
       if (string(1:1) == "!") then
          call lk_lst_new_node(header_SSPs(i_SSP), header_node)
          header_node % val = string
       else
          backspace(unit_SSP)
          exit
       endif
    enddo
    read(unit_SSP, *) Z_SSP(i_SSP), dim_time_SSP, time_step, last_time_SSP, dim_elem
    if (i_SSP == 1) then
       if (associated(L_bol_SSP)) deallocate(L_bol_SSP)
       allocate(L_bol_SSP(dim_SSP, dim_time_SSP))

       if (associated(CCSN_rate_SSP)) deallocate(CCSN_rate_SSP)
       allocate(CCSN_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(SNIa_rate_SSP)) deallocate(SNIa_rate_SSP)
       allocate(SNIa_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(ejec_rate_tot_SSP)) deallocate(ejec_rate_tot_SSP)
       allocate(ejec_rate_tot_SSP(dim_SSP, dim_time_SSP))

       if (associated(carb_dust_prod_rate_SSP)) &
            deallocate(carb_dust_prod_rate_SSP)
       allocate(carb_dust_prod_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(sil_dust_prod_rate_SSP)) &
            deallocate(sil_dust_prod_rate_SSP)
       allocate(sil_dust_prod_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(BHNS_mass_prod_rate_SSP)) &
            deallocate(BHNS_mass_prod_rate_SSP)
       allocate(BHNS_mass_prod_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(WD_mass_prod_rate_SSP)) deallocate(WD_mass_prod_rate_SSP)
       allocate(WD_mass_prod_rate_SSP(dim_SSP, dim_time_SSP))

       if (associated(time_SSP)) deallocate(time_SSP)
       allocate(time_SSP(dim_time_SSP))

       if (associated(lum_SSP)) deallocate(lum_SSP)
       allocate(lum_SSP(dim_SSP, dim_time_SSP, dim_lambda_stel))

       if (associated(elem_id)) deallocate(elem_id)
       allocate(elem_id(dim_elem))

       if (associated(ejec_rate_elem_SSP)) deallocate(ejec_rate_elem_SSP)
       allocate(ejec_rate_elem_SSP(dim_SSP, dim_time_SSP, 0:dim_elem))

       dim_convol_time = ceiling(last_time_SSP/time_step)+1

       if (associated(convol_time)) deallocate(convol_time)
       allocate(convol_time(dim_convol_time+1))
       convol_time(:) = ((/(i_convol, i_convol = 1, dim_convol_time+1)/)-1) * time_step

       if (associated(stellar_mass_SSP)) deallocate(stellar_mass_SSP)
       allocate(stellar_mass_SSP(dim_SSP, dim_convol_time))

       if (associated(LC_rate_SSP)) deallocate(LC_rate_SSP)
       allocate(LC_rate_SSP(dim_SSP, dim_convol_time))

       if (associated(inv_time)) deallocate(inv_time)
       allocate(inv_time(dim_convol_time))

       if (associated(beta)) deallocate(beta)
       allocate(beta(dim_convol_time))

       if (associated(LC_power_SSP)) deallocate(LC_power_SSP)
       allocate(LC_power_SSP(dim_SSP, dim_convol_time))

    else
       if (Z_SSP(i_SSP) < Z_SSP(i_SSP-1)) then
          write(*, "(/a)") "Files of SSPs should be ordered by increasing metallicies:"
          write(*, "(a)") "the metallicity of """ // trim(SSP_file(i_SSP)) // &
               """ (" // to_string(Z_SSP(i_SSP)) // ")", &
               "is less than that of """ // trim(SSP_file(i_SSP-1)) // &
               """ (" // to_string(Z_SSP(i_SSP-1)) // "). ", &
               "Stopped."
          stop
       end if
    endif
    lum_SSP(i_SSP, :, :) = 0

    read(unit_SSP, *) elem_id(1:dim_elem)

    if (i_SSP == 1) then
       dim_elem1 = dim_elem
       if (allocated(elem1)) deallocate(elem1)
       allocate(elem1(dim_elem1))
       elem1(1:dim_elem1) = elem_id(1:dim_elem)
    else
       if (dim_elem1 /= dim_elem) then
          write(*, "(/,(a))") &
               "The number of chemical elements used in file of SSPs """ // &
               trim(SSP_file(i_SSP)) // """ (" // to_string(dim_elem) // ") ", &
               "is not the same as in """ // trim(SSP_file(1)) // """ (" // &
               to_string(dim_elem1) // "). ", &
               "Stopped."
          stop
       endif
       do i_elem = 1, dim_elem
          if (elem_id(i_elem) /= elem1(i_elem)) then
             write(*, "(/,(a))") "Chemical element #" // to_string(i_elem) // &
                  " used in file of SSPs """ // trim(SSP_file(i_SSP)) // &
                  """ (" // trim(elem_id(i_elem)) // ") ", &
                  "is not the same as in """ // trim(SSP_file(1)) // &
                  """ (" // trim(elem1(i_elem)) // "). ", &
                  "Stopped."
             stop
          endif
       end do

       if (i_SSP == dim_SSP) deallocate(elem1)
    endif

    if (allocated(ejec_elem_IS)) deallocate(ejec_elem_IS)
    allocate(ejec_elem_IS(0:dim_elem))
    if (allocated(ejec_elem_CB)) deallocate(ejec_elem_CB)
    allocate(ejec_elem_CB(0:dim_elem))

!# First age.

    i_time_SSP = 1
    read(unit_SSP, *) time_SSP(i_time_SSP), x, L_bol_SSP(i_SSP, i_time_SSP), &
         HI_rate_SSP_prev, x, x, HI_power_SSP_prev
    if (i_SSP > 1) then
       if (time_SSP(i_time_SSP) /= time_SSP1(i_time_SSP)) then
          write(*, "(/a)") "Files of SSPs should be computed at the same ages:"
          write(*, "(a)") "at time-step #" // to_string(i_time_SSP) // &
               ", the age is " // to_string(time_SSP(i_time_SSP)) // &
               " Myr for """ // trim(SSP_file(i_SSP)) // """ ", &
               "and " // to_string(time_SSP1(i_time_SSP)) // " Myr for """ // &
               trim(SSP_file(1)) // """. ", &
               "Stopped."
          stop
       endif
    endif
    read(unit_SSP, *) !# `nb_CCSN_IS`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_tot_IS`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_carb_LMW_IS`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_carb_LMW_CB`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_dust_O_LMW_IS`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_dust_O_LMW_CB`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_carb_SNIa`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_elem_IS`, etc. Skipped.
    read(unit_SSP, *) !# `ejec_elem_CB`, etc. Skipped.
    read(unit_SSP, *) n_used_SL
    do i_used_SL = 1, n_used_SL
       read(unit_SSP, *) i_SL, n_used_spec
       read(unit_SSP, *) (i_used_spec(i_spec), L_spec(i_spec), &
            i_spec = 1, n_used_spec)
       do i_lambda = 1, dim_lambda_stel
          lum_SSP(i_SSP, i_time_SSP, i_lambda) = &
               lum_SSP(i_SSP, i_time_SSP, i_lambda) &
               + sum(L_spec(1:n_used_spec) * &
               stel_lib(i_SL) % lum_star(i_lambda, &
               i_used_spec(1:n_used_spec)))
       enddo
    end do

!# Following ages.

    i_convol = 1
    time = convol_time(i_convol)
    stellar_mass_SSP(i_SSP, i_convol) = 1

    do i_time_SSP = 1, dim_time_SSP-1
       read(unit_SSP, *) time_SSP(i_time_SSP+1), x, &
            L_bol_SSP(i_SSP, i_time_SSP+1), HI_rate_SSP, x, x, HI_power_SSP
       if (i_SSP > 1) then
          if (time_SSP(i_time_SSP+1) /= time_SSP1(i_time_SSP+1)) then
             write(*, "(/a)") "Files of SSPs should be computed at the same ages:"
             write(*, "(a)") "at time-step #" // to_string(i_time_SSP+1) // &
                  ", the age is " // to_string(time_SSP(i_time_SSP+1)) // &
                  " Myr for """ // trim(SSP_file(i_SSP)) // """ ", &
                  "and " // to_string(time_SSP1(i_time_SSP+1)) // " Myr for """ // &
                  trim(SSP_file(1)) // """. ", &
                  "Stopped."
             stop
          endif
       endif
!# Quantities produced (integrated over time, not rates) between
!# `time_SSP(i_time_SSP)` and `time_SSP(i_time_SSP+1)`:
!# {
       read(unit_SSP, *) nb_CCSN_IS, nb_CCSN_CB, nb_SNIa_int, mass_BHNS_SSP_IS, &
            mass_BHNS_SSP_CB, mass_WD_SSP_IS, mass_WD_SSP_CB
       read(unit_SSP, *) ejec_tot_IS, ejec_tot_CB, ejec_elem_IS(0), &
            ejec_elem_CB(0)
       read(unit_SSP, *) ejec_carb_LMW_IS, ejec_sil_LMW_IS, &
            ejec_carb_HMW_IS, ejec_sil_HMW_IS, &
            ejec_carb_CCSN_IS, ejec_sil_CCSN_IS
       read(unit_SSP, *) ejec_carb_LMW_CB, ejec_sil_LMW_CB, &
            ejec_carb_HMW_CB, ejec_sil_HMW_CB, &
            ejec_carb_CCSN_CB, ejec_sil_CCSN_CB
       read(unit_SSP, *) ejec_dust_O_LMW_IS, ejec_dust_O_HMW_IS, &
            ejec_dust_O_CCSN_IS
       read(unit_SSP, *) ejec_dust_O_LMW_CB, &
            ejec_dust_O_HMW_CB, ejec_dust_O_CCSN_CB
       read(unit_SSP, *) ejec_carb_SNIa, ejec_sil_SNIa, &
            ejec_dust_O_SNIa
       read(unit_SSP, *) ejec_elem_IS(1:dim_elem)
       read(unit_SSP, *) ejec_elem_CB(1:dim_elem)
!# }.
       delta_time = time_SSP(i_time_SSP+1)-time_SSP(i_time_SSP)
!# Mean rates between `time_SSP(i_time_SSP)` and `time_SSP(i_time_SSP+1)`:
!# {
       CCSN_rate_SSP(i_SSP, i_time_SSP) = ((1-close_bin_frac)*nb_CCSN_IS &
            + close_bin_frac*nb_CCSN_CB)/delta_time
       SNIa_rate_SSP(i_SSP, i_time_SSP) = close_bin_frac*nb_SNIa_int/delta_time
       BHNS_mass_prod_rate_SSP(i_SSP, i_time_SSP) = &
            ( (1-close_bin_frac) * mass_BHNS_SSP_IS &
            + close_bin_frac * mass_BHNS_SSP_CB )/delta_time
       WD_mass_prod_rate_SSP(i_SSP, i_time_SSP) = &
            ( (1-close_bin_frac) * mass_WD_SSP_IS &
            + close_bin_frac * mass_WD_SSP_CB )/delta_time
       ejec_rate_tot_SSP(i_SSP, i_time_SSP) = &
            ( (1-close_bin_frac) * ejec_tot_IS &
            + close_bin_frac * ejec_tot_CB )/delta_time
       ejec_rate_elem_SSP(i_SSP, i_time_SSP,0:dim_elem) = &
            ( (1-close_bin_frac) * ejec_elem_IS(0:dim_elem) &
            + close_bin_frac * ejec_elem_CB(0:dim_elem) )/delta_time
       carb_dust_prod_rate_SSP(i_SSP, i_time_SSP) = &
            ((1-close_bin_frac) * &
            ( LMW_carb_deplet * ejec_carb_LMW_IS &
            + HMW_carb_deplet * ejec_carb_HMW_IS &
            + CCSN_carb_deplet * ejec_carb_CCSN_IS) &
            + close_bin_frac * &
            ( LMW_carb_deplet * ejec_carb_LMW_CB &
            + HMW_carb_deplet * ejec_carb_HMW_CB &
            + CCSN_carb_deplet * ejec_carb_CCSN_CB &
            + SNIa_carb_deplet * ejec_carb_SNIa)) &
            /delta_time

       sil_dust_prod_rate_SSP(i_SSP, i_time_SSP) = &
            ((1-close_bin_frac) * &
            ( LMW_sil_deplet * (ejec_sil_LMW_IS + &
            O_sil_ratio*ejec_dust_O_LMW_IS) &
            + HMW_sil_deplet * (ejec_sil_HMW_IS + &
            O_sil_ratio*ejec_dust_O_HMW_IS) &
            + CCSN_sil_deplet * (ejec_sil_CCSN_IS + &
            O_sil_ratio*ejec_dust_O_CCSN_IS) ) &
            + close_bin_frac * &
            ( LMW_sil_deplet * (ejec_sil_LMW_CB + &
            O_sil_ratio*ejec_dust_O_LMW_CB) &
            + HMW_sil_deplet * (ejec_sil_HMW_CB + &
            O_sil_ratio*ejec_dust_O_HMW_CB) &
            + CCSN_sil_deplet * (ejec_sil_CCSN_CB + &
            O_sil_ratio*ejec_dust_O_CCSN_CB) &
            + SNIa_sil_deplet * (ejec_sil_SNIa + &
            O_sil_ratio*ejec_dust_O_SNIa) )) &
            /delta_time

!# }.
       read(unit_SSP, *) n_used_SL
       do i_used_SL = 1, n_used_SL
          read(unit_SSP, *) i_SL, n_used_spec
          read(unit_SSP, *) (i_used_spec(i_spec), L_spec(i_spec), &
               i_spec = 1, n_used_spec)
          do i_lambda = 1, dim_lambda_stel
             lum_SSP(i_SSP, i_time_SSP+1, i_lambda) = &
                  lum_SSP(i_SSP, i_time_SSP+1, i_lambda) &
                  + sum( L_spec(1:n_used_spec) * &
                  stel_lib(i_SL) % lum_star(i_lambda, &
                  i_used_spec(1:n_used_spec)))
          enddo
       end do

       do
          if (time >= time_SSP(i_time_SSP+1)) exit
          inv_time(i_convol) = i_time_SSP
          beta(i_convol) = (time_SSP(i_time_SSP+1)-time)/delta_time
          LC_rate_SSP(i_SSP, i_convol) = &
               HI_rate_SSP_prev + (HI_rate_SSP-HI_rate_SSP_prev)*(time-time_SSP(i_time_SSP))/ &
               delta_time

          LC_power_SSP(i_SSP,i_convol) = HI_power_SSP_prev + (HI_power_SSP-HI_power_SSP_prev)* &
               (time-time_SSP(i_time_SSP))/delta_time

          stellar_mass_SSP(i_SSP, i_convol+1) = stellar_mass_SSP(i_SSP, i_convol) - & !# ??? Inaccurate?
               ( ejec_rate_tot_SSP(i_SSP, i_time_SSP) &
               + BHNS_mass_prod_rate_SSP(i_SSP, i_time_SSP) &
               + WD_mass_prod_rate_SSP(i_SSP, i_time_SSP) ) &
               * time_step
          i_convol = i_convol+1
          if (i_convol > dim_convol_time) exit
          time = convol_time(i_convol)
       end do
       HI_rate_SSP_prev = HI_rate_SSP
       HI_power_SSP_prev = HI_power_SSP
    end do

!#{ Values at `dim_time_SSP`-1 are extrapolated at `dim_time_SSP`.
    CCSN_rate_SSP(i_SSP, dim_time_SSP) = CCSN_rate_SSP(i_SSP, dim_time_SSP-1)
    SNIa_rate_SSP(i_SSP, dim_time_SSP) = SNIa_rate_SSP(i_SSP, dim_time_SSP-1)
    ejec_rate_tot_SSP(i_SSP, dim_time_SSP) = ejec_rate_tot_SSP(i_SSP, dim_time_SSP-1)
    carb_dust_prod_rate_SSP(i_SSP, dim_time_SSP) = carb_dust_prod_rate_SSP(i_SSP, dim_time_SSP-1)
    sil_dust_prod_rate_SSP(i_SSP, dim_time_SSP) = sil_dust_prod_rate_SSP(i_SSP, dim_time_SSP-1)
    BHNS_mass_prod_rate_SSP(i_SSP, dim_time_SSP) = BHNS_mass_prod_rate_SSP(i_SSP, dim_time_SSP-1)
    WD_mass_prod_rate_SSP(i_SSP, dim_time_SSP) = WD_mass_prod_rate_SSP(i_SSP, dim_time_SSP-1)
    ejec_rate_elem_SSP(i_SSP, dim_time_SSP, :) = ejec_rate_elem_SSP(i_SSP, dim_time_SSP-1, :)
!#}
    
    call close_file(unit_SSP)

    inv_time(i_convol) = dim_time_SSP-1
    beta(i_convol) = 0

    deallocate(ejec_elem_IS, ejec_elem_CB)

    if (i_SSP == 1) then
       dim_time_SSP1 = dim_time_SSP
       if (allocated(time_SSP1)) deallocate(time_SSP1)
       allocate(time_SSP1(dim_time_SSP1))
       time_SSP1(1:dim_time_SSP1) = time_SSP(1:dim_time_SSP)

!# `output_age` must not be larger than the final `time_SSP`:
       if (output_age(dim_output_age) > time_SSP(dim_time_SSP)) then
          do dim_time_tmp = 0, dim_output_age-1
             if (output_age(dim_time_tmp+1) > time_SSP(dim_time_SSP)) exit
          enddo
          allocate(time_tmp(dim_time_tmp))
          time_tmp(1:dim_time_tmp) = output_age(1:dim_time_tmp)
          deallocate(output_age)
          allocate(output_age(dim_time_tmp))
          output_age(:) = time_tmp(:)
          deallocate(time_tmp)
          dim_output_age = dim_time_tmp
       endif
    else
       if (i_SSP == dim_SSP) then
          deallocate(time_SSP1)
          deallocate(SL_already_read)
          deallocate(SL_must_read)
          deallocate(SL_needed)
       end if
    endif

  end subroutine read_SSP_Z

end module mod_read_SSPs
