!# 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.
!#====================================================================== 

program SSPs

  use mod_types
  use mod_convert_type
  use mod_strings
  use mod_directories, only : tracks_dir, SSPs_dir, stel_lib_dir, ages_dir, &
       yields_dir, IMFs_dir, bin_dir
  use mod_dir_access, only : dir_sep
  use mod_select_file, only : select_single_file
  use mod_read_file_list, only : read_file_list
  use mod_constants, only : dim_elem, elem_id
  use mod_SSPs_constants, only : tracks_sets_list, SSPs_ages_list, &
       yields_list, &
       d_l10_m_ejec, SSPs_sets_list, stel_lib_sets_list, &
       P2_metal_conv, P2_Z_Sun
  use mod_IMF, only : choose_IMF, LN_C1, LN_C2
  use mod_stel_lib, only : SSP_read_stel_lib, struct_stel_lib
  use mod_tracks, only : read_tracks, connect_tracks, white_dwarfs_tracks, &
       struct_track
  use mod_yields, only : read_yields, compute_yields, fn_IRA_yield, struct_yield
  use mod_isochrone, only : compute_isochrone, compute_isochrone_WD, struct_isoch
  use mod_remnants_ejec_SN, only : isolated_stars, close_binaries, &
       reset_remnants_ejec_SN
  use mod_SSP_emission, only : SSP_emission
  use mod_file_access, only : open_file, close_file, path_file, extract_path, &
       base_name
  use mod_interp, only : bracket, interp_lin_lin
  use mod_SSPs_ages
  use mod_code_version, only : version_id, version_date
  use mod_compiler, only : compiler
  use mod_ISO_8601, only : ISO_8601

  implicit none
!#......................................................................
  integer :: dim_time_SSP
  real(CDR), dimension(:), pointer :: time_SSP => null()
  real(CDR) :: time_step
  character(std_string) :: IMF_file
  integer :: IMF_dim_slope
  real(DPR), dimension(:), pointer :: IMF_bin_coeff => null(), &
       IMF_bin_bottom_mass => null(), IMF_bin_slope => null()
  real(DPR) :: IMF_mass_min, IMF_mass_max, IMF_norm

  character(std_string) :: SSP_file, SSPs_set, yields_set
  character(std_string) :: SSPs_ages_file
  character(long_string) :: prefix
  integer :: i_bin, n_bins, unit, unit2
  integer :: i_time, i_tracks_file
  real(CDR) :: time
  integer :: dim_isoch !# Not used currently, but might be useful if \
!# isochrones were output. ???
  type(struct_isoch) :: isoch
  type(struct_isoch), pointer :: isoch_node
  real(DPR) :: top_isoch_mass
  real(DPR) :: d_l10_m, l10_mass
  real(DPR) :: m_end, IRA_yield
  integer :: i_SL, i_spec, n_used_SL
  type(irreg_array_int), dimension(:), allocatable :: used_spec
  logical, dimension(:), allocatable :: used_SL
  real(DPR) :: HI_rate_SSP, HeI_rate_SSP, HeII_rate_SSP, &
       HI_power_SSP, HeI_power_SSP, HeII_power_SSP, L_bol_tot
  type(irreg_array_DPR), dimension(:), allocatable :: L_spec
  real(DPR) :: nb_CCSN_IS, nb_CCSN_CB, nb_SNIa
  real(DPR) :: ejec_carb_LMW_IS, &
       ejec_sil_LMW_IS, ejec_carb_HMW_IS, ejec_sil_HMW_IS, &
       ejec_carb_CCSN_IS, ejec_sil_CCSN_IS
  real(DPR) :: ejec_carb_LMW_CB, &
       ejec_sil_LMW_CB, ejec_carb_HMW_CB, ejec_sil_HMW_CB, &
       ejec_carb_CCSN_CB, ejec_sil_CCSN_CB, &
       ejec_carb_SNIa, ejec_sil_SNIa

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

  real(DPR) :: mass_BHNS_IS, mass_BHNS_CB, mass_WD_IS, mass_WD_CB
  integer, dimension(:), pointer :: dim_spec => null()
  real(DPR), dimension(:), allocatable :: P2_Z_SL
  real(DPR), dimension(:), pointer :: M_over_H_SL => null(), &
       T_SL_max => null(), &
       T_SL_min => null()
  integer :: dim_SL, dim_low_T, dim_high_T
  type(struct_stel_lib), dimension(:), pointer :: stel_lib => null()
  integer :: dim_elem_SNIa, dim_elem_sol
  type(struct_yield), dimension(:), pointer :: yield_LMW => null(), &
       yield_HMW => null(), &
       yield_CCSN => null()
  real(DPR), dimension(:), pointer :: gross_ejec_SNIa => null()
  character(len=std_string), dimension(:), pointer :: elem_SNIa => null()
  real(DPR), dimension(:), pointer :: abund_sol => null()
  character(len=std_string), dimension(:), pointer :: elem_sol => null()
  integer :: dim_tracks_file
  integer :: dim_mass_yields
  real(DPR) :: carb_dust_SNIa, sil_dust_SNIa, O_dust_SNIa
  real(DPR), dimension(:), pointer :: ejec_tot => null()
  real(DPR), dimension(:, :), pointer :: ejec_elem => null()
  real(DPR), dimension(:), pointer :: mass_yields => null(), &
       carb_dust_LMW => null(), &
       sil_dust_LMW => null(), &
       carb_dust_HMW => null(), &
       sil_dust_HMW => null(), &
       carb_dust_CCSN => null(), &
       sil_dust_CCSN => null(), &
       O_dust_LMW => null(), &
       O_dust_HMW => null(), &
       O_dust_CCSN => null()
  real(DPR) :: ejec_tot_SNIa
  real(DPR), dimension(0:dim_elem) :: ejec_elem_SNIa
  real(DPR) :: ejec_tot_IS, ejec_tot_CB

  real(DPR), dimension(0:dim_elem) :: ejec_elem_IS, ejec_elem_CB

  character(std_string), dimension(:), pointer :: tracks_file => null()

  integer :: n_MS, n_He_flash, n_HB, n_VLM, dim_age_WD
  real(DPR) :: Y_track, Z_track, M_over_H_track, min_mass_CCSN, mass_Ch, X_sol, Y_sol, Z_sol
  type(struct_track), dimension(:), pointer :: std_track => null()
  integer :: dim_WD
  type(struct_track), dimension(:), pointer :: WD_track => null()

  character(len=std_string) :: tracks_set, stel_lib_set, answer

  integer :: i_elem
  logical :: exist, prefix_dir

  integer :: unit_compiler
  integer :: length
  character(len=25) :: run_begin_time
  character(len=14) :: time_stamp_value
!#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::

!# Create time-stamp:
  call ISO_8601(local_time_extended = run_begin_time, UTC_time_basic = time_stamp_value)
  write(*,"(/a,a)") "Time-stamp: ", quote_string(time_stamp_value)

  call open_file(unit_compiler, path_file(bin_dir, "compil_SSPs.txt"))
  read(unit_compiler,*) compiler
  call close_file(unit_compiler)

  write(*, "(/a)") "When a default value is proposed, press the &
       &<RETURN>/<ENTER> key to select it."

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "Initial mass function?"
  call select_single_file(dir = IMFs_dir, list = "list_IMFs.txt", &
       selected_file = IMF_file, object = "IMF", objects = "IMFs", &
       print_first_line = .true.)
  call choose_IMF(IMF_file, IMF_dim_slope, IMF_bin_coeff, IMF_bin_bottom_mass, &
       IMF_bin_slope, IMF_mass_min, IMF_mass_max, IMF_norm)

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "Set of evolutionary tracks?"
  call select_single_file(dir = tracks_dir, list = tracks_sets_list, &
       selected_file = tracks_set, object = "set of tracks", &
       objects = "sets of tracks")
  call read_file_list(dir = tracks_dir, list = tracks_set, &
       file = tracks_file, n_files = dim_tracks_file)

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "Set of yields for high-mass stars?"
  call select_single_file(dir = yields_dir, list = yields_list, &
       selected_file = yields_set, object = "set of yields", &
       objects = "sets of yields")

  call read_yields(yields_set, &
       mass_Ch, dim_elem_SNIa, gross_ejec_SNIa, elem_SNIa, &
       X_sol, Y_sol, Z_sol, dim_elem_sol, abund_sol, elem_sol, dim_tracks_file, &
       yield_LMW, yield_HMW, yield_CCSN)

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "Set of stellar libraries?"
  call select_single_file(dir = stel_lib_dir, list = stel_lib_sets_list, &
       selected_file = stel_lib_set, object="set of stellar libraries", &
       objects="sets of stellar libraries")
  call SSP_read_stel_lib(dim_low_T, dim_high_T, stel_lib, &
       M_over_H_SL, dim_SL, T_SL_max, T_SL_min, dim_spec, stel_lib_set)

  if (allocated(used_spec)) deallocate(used_spec)
  allocate(used_spec(dim_SL))
  do i_SL = 1, dim_SL
     if (associated(used_spec(i_SL) % val)) deallocate(used_spec(i_SL) % val)
     allocate(used_spec(i_SL) % val(dim_spec(i_SL)))
     used_spec(i_SL) % val(:) = 0
  enddo

  if (allocated(used_SL)) deallocate(used_SL)
  allocate(used_SL(dim_SL))

  if (allocated(L_spec)) deallocate(L_spec)
  allocate(L_spec(dim_SL))
  do i_SL = 1, dim_SL
     if (associated(L_spec(i_SL) % val)) deallocate(L_spec(i_SL) % val)
     allocate(L_spec(i_SL) % val(0:dim_spec(i_SL)))
  enddo

  if (allocated(P2_Z_SL)) deallocate(P2_Z_SL)
  allocate(P2_Z_SL(dim_SL))

  P2_Z_SL(:) = P2_Z_Sun * 10**M_over_H_SL(:)

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "File defining the output ages of code ""SSPs""?"
  call select_single_file(dir = ages_dir, list = SSPs_ages_list, &
       selected_file = SSPs_ages_file, object = "sequence of ages", &
       objects = "sequences of ages")
  call read_SSPs_ages(SSPs_ages_file, time_step, dim_time_SSP, time_SSP)

  write(*, "(/a)") repeat("=",80)
  write(*, "(a)") "Identifier prefixed to the output files of code ""SSPs""?"
  write(*,"(a,a)") "Default: ", quote_string(time_stamp_value)
  prefix_loop: do
     read(*, "(a)") prefix
     prefix = unquote_string(prefix)
     if (prefix == "") prefix = time_stamp_value

     prefix_dir = .false.
     length = len_trim(prefix)
     if (length > 0) then
        if (prefix(length:length) == dir_sep) then
           prefix_dir = .true.
        endif
     endif
     if (prefix_dir) then
        inquire(file = path_file(SSPs_dir, prefix), exist=exist)
        if (.not.exist) then
           write(*, "(a)") "Directory """ // &
                trim(extract_path(SSPs_dir, prefix)) // &
                """ does not exist yet."
           write(*, "(a/a)") "Please create it by yourself; " // &
                "once created, press the <RETURN/ENTER> key to continue.", &
                "Otherwise, press <TAB>, then <RETURN> to select another &
                &prefix/directory."
           do
              read(*,"(a)") answer
              if (answer == "") then
                 inquire(file = path_file(SSPs_dir, prefix), exist=exist)
                 if (.not.exist) then
                    write(*, "(a)") "Directory """ // &
                         trim(extract_path(SSPs_dir, prefix)) // &
                         """ has not been created."
                    write(*, "(a/a)") "Please create it by yourself; " // &
                         "once created, press the <RETURN/ENTER> key to &
                         &continue.", &
                         "Otherwise, press <TAB>, then <RETURN> to select &
                         &another prefix/directory."
                    cycle
                 else
                    exit
                 endif
              else if (answer == HT) then
                 write(*, "(a)") "Identifier prefixed to the output files &
                      &of code ""SSPs""?"
                 cycle prefix_loop
              else
                 write(*,"(a)") "Press either the <RETURN/ENTER> key &
                      &to continue, or <TAB>, then <RETURN> to select another &
                      &prefix/directory!"
                 cycle
              endif
           enddo
        endif
        SSPs_set = trim(prefix) // "SSPs.txt"
     else
        SSPs_set = trim(prefix) // "_SSPs.txt"
     endif
     inquire(file = path_file(SSPs_dir, SSPs_set), exist=exist)
     if (.not.exist) then
        exit
     else !# File already exists.
        write(*, "(a)") "File """ // trim(base_name(SSPs_set)) // &
             """ already exists in directory """ // &
             trim(extract_path(SSPs_dir, SSPs_set)) // &
             """. Please enter another identifier to prefix the &
             &output files."
     endif
  enddo prefix_loop

  write(*, "(/a/)") repeat("*", 80)

!# Add the name of the new set of SSPs to the list of SSPs sets.
  call open_file(unit, path_file(SSPs_dir, SSPs_sets_list), status = "old", &
       position = "append", action = "write")
  write(unit, "(a)") trim(SSPs_set)
  call close_file(unit)

  call open_file(unit, path_file(SSPs_dir, SSPs_set), status = "new")
  write(unit, "(a)") quote_string(version_id) // " !# `version_id`."
  write(unit, "(a)") quote_string(version_date) // " !# `version_date`."
  write(unit, "(a)") "!# Code ""SSPs"" executed at " // trim(run_begin_time) // "."
  write(unit, "(a)") quote_string(stel_lib_set) // " !# Set of stellar spectra."
  write(unit, "(a)") "!# Files of SSPs:"

  do i_tracks_file = 1, dim_tracks_file
     write(*, "(a)") "Calculations for track """ // &
          trim(adjustl(tracks_file(i_tracks_file))) // """."

     used_SL(:) = .false.

     call read_tracks(tracks_file(i_tracks_file), X_sol, Z_sol, &
          n_MS, n_He_flash, n_HB, n_VLM, dim_age_WD, &
          Y_track, Z_track, M_over_H_track, &
          min_mass_CCSN, std_track)

     call connect_tracks(n_MS, n_VLM, n_He_flash, n_HB, dim_age_WD, &
          std_track)

     call white_dwarfs_tracks(dim_WD, n_MS, n_HB, n_VLM, n_He_flash, &
          dim_age_WD, &
          WD_track, std_track)

     call compute_yields(i_tracks_file, Y_track, Z_track, yields_set, &
          yield_LMW, yield_HMW, yield_CCSN, &
          gross_ejec_SNIa, elem_SNIa, &
          mass_Ch, Z_sol, abund_sol, elem_sol, &
          dim_mass_yields, mass_yields, ejec_tot, ejec_elem, ejec_tot_SNIa, &
          ejec_elem_SNIa, carb_dust_LMW, &
          sil_dust_LMW, carb_dust_HMW, sil_dust_HMW, carb_dust_CCSN, sil_dust_CCSN, &
          carb_dust_SNIa, sil_dust_SNIa, &
          O_dust_LMW, O_dust_HMW, O_dust_CCSN, O_dust_SNIa)

!# Indicative value of the total yield of metals, assuming instantaneous recycling (IRA).

     IRA_yield = fn_IRA_yield(IMF_file, IMF_dim_slope, IMF_bin_coeff, &
          IMF_bin_bottom_mass, IMF_bin_slope, &
          IMF_mass_min, IMF_mass_max, dim_mass_yields, mass_yields, ejec_tot(1:dim_mass_yields), &
          ejec_elem(1:dim_mass_yields, 0), IMF_norm)

     if (prefix_dir) then
        SSP_file = trim(prefix) // tracks_file(i_tracks_file)
     else
        SSP_file = trim(prefix) // "_" // tracks_file(i_tracks_file)
     endif

     call open_file(unit2, path_file(SSPs_dir, SSP_file), status = "new")
     write(unit, "(a)") quote_string(SSP_file)
     write(unit2, "(a)") quote_string(version_id) // " !# `version_id`."
     write(unit2, "(a)") quote_string(version_date) // " !# `version_date`."
     write(unit2, "(a)") "!# Code ""SSPs"" executed at " // trim(run_begin_time) // "."
     write(unit2, "(a)") "!# Compiler for ""SSPs"": " // &
          trim(compiler) // "."
     write(unit2, "(a)") "!# Ages: " // quote_string(SSPs_ages_file) // "."
     write(unit2, "(a)") "!# Evolutionary tracks: " // &
          quote_string(tracks_file(i_tracks_file)) // "."
     write(unit2, "(a,f7.4,a)") "!# Metallicity (mass fraction): ", Z_track, "."
     write(unit2, "(a)") "!# High-mass yields: " // &
          quote_string(yields_set) // "."
     write(unit2, "(a)") "!# Initial mass function: " // quote_string(IMF_file) // &
          " from " // to_string(IMF_mass_min,fmt="(f6.2)") // &
          " to " // to_string(IMF_mass_max,fmt="(f6.2)") // " solar masses."
     if (IMF_file == "IMF_log_normal.txt") then
        write(unit2, "(a)") "!# `LN_C1` = " // to_string(LN_C1) // "."
        write(unit2, "(a)") "!# `LN_C2` = " // to_string(LN_C2) // "."
     endif

     write(unit2, "(a)") "!# Set of stellar spectra: " // &
          quote_string(stel_lib_set) // "."

     write(unit2, "(f7.4,tr1, i5, 2(tr1, f10.4), tr1, i2, tr1, es10.3)") &
          Z_track, dim_time_SSP, time_step, time_SSP(dim_time_SSP), dim_elem, IRA_yield

     write(unit2, "(" // int_to_string(dim_elem) // "(a,tr1))") &
          (quote_string(elem_id(i_elem)), i_elem = 1, dim_elem)

!# Computation of the isochrones.
!# `time` in Myr
     m_end = std_track(n_MS) % l10_init_mass

     do i_time = 1, dim_time_SSP
        time = time_SSP(i_time)

        call compute_isochrone(time, dim_isoch, isoch, isoch_node, &
             top_isoch_mass, std_track, n_VLM, n_He_flash, n_MS, n_HB)

        if (10**top_isoch_mass > WD_track(1) % init_mass) then
           call compute_isochrone_WD(time, dim_isoch, isoch, isoch_node, &
                dim_WD, WD_track, dim_age_WD)
        end if

        if (P2_metal_conv) then !# Use Pégase.2 conversion of metallicity of \
!#                                 stellar spectra.
           call SSP_emission(Z_track, IMF_file, IMF_dim_slope, &
                IMF_bin_coeff, IMF_bin_bottom_mass, IMF_bin_slope, &
                IMF_mass_min, IMF_mass_max, IMF_norm, &
                dim_isoch, isoch, &
                HI_rate_SSP, HeI_rate_SSP, HeII_rate_SSP, &
                HI_power_SSP, HeI_power_SSP, HeII_power_SSP, L_bol_tot, &
                L_spec, &
                dim_low_T, P2_Z_SL, dim_SL, T_SL_max, T_SL_min, &
                dim_spec, stel_lib)
        else !# Pégase.3 default.
           call SSP_emission(M_over_H_track, IMF_file, IMF_dim_slope, &
                IMF_bin_coeff, IMF_bin_bottom_mass, IMF_bin_slope, &
                IMF_mass_min, IMF_mass_max, IMF_norm, &
                dim_isoch, isoch, &
                HI_rate_SSP, HeI_rate_SSP, HeII_rate_SSP, &
                HI_power_SSP, HeI_power_SSP, HeII_power_SSP, L_bol_tot, &
                L_spec, &
                dim_low_T, M_over_H_SL, dim_SL, T_SL_max, T_SL_min, &
                dim_spec, stel_lib)
        endif

        call reset_remnants_ejec_SN(nb_CCSN_IS, nb_CCSN_CB, nb_SNIa, &
             ejec_tot_IS, ejec_elem_IS, ejec_tot_CB, ejec_elem_CB, &
             ejec_carb_LMW_IS, ejec_sil_LMW_IS, &
             ejec_carb_HMW_IS, ejec_sil_HMW_IS, &
             ejec_carb_CCSN_IS, ejec_sil_CCSN_IS, &
             ejec_carb_LMW_CB, ejec_sil_LMW_CB, &
             ejec_carb_HMW_CB, ejec_sil_HMW_CB, &
             ejec_carb_CCSN_CB, ejec_sil_CCSN_CB, &
             ejec_carb_SNIa, ejec_sil_SNIa, &
             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, &
             mass_BHNS_IS, &
             mass_BHNS_CB, mass_WD_IS, mass_WD_CB)

        n_bins = int((m_end-top_isoch_mass)/d_l10_m_ejec+1)
        d_l10_m = (m_end-top_isoch_mass)/n_bins
        do i_bin = 0, n_bins-1
           l10_mass = top_isoch_mass+(i_bin+0.5_DPR)*d_l10_m

           call isolated_stars(l10_mass, d_l10_m, IMF_file, IMF_dim_slope, &
                IMF_bin_coeff, IMF_bin_bottom_mass, &
                IMF_bin_slope, IMF_mass_min, IMF_mass_max, IMF_norm, &
                ejec_tot_IS, ejec_elem_IS, &
                ejec_carb_LMW_IS, ejec_sil_LMW_IS, &
                ejec_carb_HMW_IS, ejec_sil_HMW_IS, &
                ejec_carb_CCSN_IS, ejec_sil_CCSN_IS, &
                ejec_dust_O_LMW_IS, ejec_dust_O_HMW_IS, &
                ejec_dust_O_CCSN_IS, &
                nb_CCSN_IS, mass_BHNS_IS, mass_WD_IS, dim_mass_yields, mass_yields, ejec_tot, ejec_elem, &
                carb_dust_LMW, sil_dust_LMW, carb_dust_HMW, sil_dust_HMW, &
                carb_dust_CCSN, sil_dust_CCSN, &
                O_dust_LMW, O_dust_HMW, O_dust_CCSN, &
                min_mass_CCSN)

!# Note: there is some inconsistency here: close binaries are taken into
!# account for the chemical evolution, but not for the spectral evolution. !!!

           call close_binaries(l10_mass, d_l10_m, IMF_file, IMF_dim_slope, &
                IMF_bin_coeff, IMF_bin_bottom_mass, &
                IMF_bin_slope, IMF_mass_min, IMF_mass_max, IMF_norm, mass_Ch, &
                ejec_tot_CB, ejec_elem_CB, &
                ejec_carb_LMW_CB, ejec_sil_LMW_CB, &
                ejec_carb_HMW_CB, ejec_sil_HMW_CB, &
                ejec_carb_CCSN_CB, ejec_sil_CCSN_CB, &
                ejec_carb_SNIa, ejec_sil_SNIa, &
                ejec_dust_O_LMW_CB, ejec_dust_O_HMW_CB, &
                ejec_dust_O_CCSN_CB, ejec_dust_O_SNIa, &
                nb_CCSN_CB, mass_BHNS_CB, mass_WD_CB, nb_SNIa, dim_mass_yields, mass_yields, ejec_tot, &
                ejec_elem, carb_dust_LMW, sil_dust_LMW, &
                carb_dust_HMW, sil_dust_HMW, carb_dust_CCSN, sil_dust_CCSN, &
                carb_dust_SNIa, sil_dust_SNIa, &
                O_dust_LMW, O_dust_HMW, O_dust_CCSN, O_dust_SNIa, &
                ejec_tot_SNIa, ejec_elem_SNIa, min_mass_CCSN)
        end do

        m_end = top_isoch_mass

        write(unit2, "(f10.4, tr2, 8(es11.4,tr1))") time, 10**m_end, L_bol_tot, &
             HI_rate_SSP, HeI_rate_SSP, HeII_rate_SSP, &
             HI_power_SSP, HeI_power_SSP, HeII_power_SSP
        write(unit2, "(7(es11.4,tr1))") nb_CCSN_IS, nb_CCSN_CB, nb_SNIa, &
             mass_BHNS_IS, mass_BHNS_CB, mass_WD_IS, mass_WD_CB
        write(unit2, "(4(es11.4,tr1))") ejec_tot_IS, ejec_tot_CB, &
             ejec_elem_IS(0), ejec_elem_CB(0)
        write(unit2, "(6(es11.4,tr1))") ejec_carb_LMW_IS, &
             ejec_sil_LMW_IS, ejec_carb_HMW_IS, &
             ejec_sil_HMW_IS, ejec_carb_CCSN_IS, &
             ejec_sil_CCSN_IS
        write(unit2, "(6(es11.4,tr1))") ejec_carb_LMW_CB, &
             ejec_sil_LMW_CB, ejec_carb_HMW_CB, &
             ejec_sil_HMW_CB, ejec_carb_CCSN_CB, &
             ejec_sil_CCSN_CB
        write(unit2, "(3(es11.4,tr1))") ejec_dust_O_LMW_IS, &
             ejec_dust_O_HMW_IS, ejec_dust_O_CCSN_IS
        write(unit2, "(3(es11.4,tr1))") ejec_dust_O_LMW_CB, &
             ejec_dust_O_HMW_CB, ejec_dust_O_CCSN_CB
        write(unit2, "(3(es11.4,tr1))") ejec_carb_SNIa, &
             ejec_sil_SNIa, ejec_dust_O_SNIa
        write(unit2, "(" // int_to_string(dim_elem) // "(es11.4,tr1))") &
             ejec_elem_IS(1:)
        write(unit2, "(" // int_to_string(dim_elem) // "(es11.4,tr1))") &
             ejec_elem_CB(1:)
        used_spec(:) % dim = 0
        do i_SL = 1, dim_SL
           do i_spec = 1, dim_spec(i_SL)
              if (L_spec(i_SL) % val(i_spec) > 0) then
                 used_spec(i_SL) % dim = used_spec(i_SL) % dim + 1
                 used_spec(i_SL) % val(used_spec(i_SL) % dim) = i_spec
              endif
           enddo
        enddo
        n_used_SL = count(used_spec(1:dim_SL) % dim > 0)
        used_SL(1:dim_SL) = used_SL(1:dim_SL) .or. used_spec(1:dim_SL) % dim > 0

        write(unit2, "(i2)") n_used_SL
        do i_SL = 1, dim_SL
           if (used_spec(i_SL) % dim > 0) then
              write(unit2, "(i2, tr1, i4)") i_SL, used_spec(i_SL) % dim
              write(unit2, "(5(i4, tr1, es11.5, tr1))") &
                   (used_spec(i_SL) % val(i_spec), &
                   L_spec(i_SL) % val(used_spec(i_SL) % val(i_spec)), &
                   i_spec = 1, used_spec(i_SL) % dim)
           endif
        enddo
     end do

     do i_SL = 1, dim_SL
        if (used_SL(i_SL)) write(unit2, "(i0)") i_SL
     enddo
     write(unit2, "(i0)") count(used_SL(1:dim_SL))

     call close_file(unit2)

  enddo
  call close_file(unit)

end program SSPs
