Raw File
009_Fisher_calculator_SN.f90
!----------------------------------------------------------------------------------------
!
! This file is part of CosmicFish.
!
! Copyright (C) 2015-2017 by the CosmicFish authors
!
! The CosmicFish code is free software;
! You can use it, redistribute it, and/or modify it under the terms
! of the GNU General Public License as published by the Free Software Foundation;
! either version 3 of the License, or (at your option) any later version.
! The full text of the license can be found in the file LICENSE at
! the top level of the CosmicFish distribution.
!
!----------------------------------------------------------------------------------------

!> @file 009_Fisher_calculator_SN.f90
!! This file contains the code that computes the Fisher matrix for Supernovae measurements.

!----------------------------------------------------------------------------------------
!> This module contains the code that computes the Fisher matrix for Supernovae measurements.

!> @author Marco Raveri

module Fisher_calculator_SN

    use precision
    use ModelParams
    use cosmicfish_types
    use omp_lib
    use cosmicfish_utilities
    use cosmicfish_camb_interface

#ifdef COSMICFISH_EFTCAMB
    use EFTinitialization
#endif

    implicit none

    private

    public Observed_SN_Magnitude, Generate_SN_Mock_Data, Generate_SN_Mock_Covariance, save_sn_mock_to_file, &
        & Observed_SN_Magnitude_derivative, Fisher_SN

contains

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine returns the observed magnitude of a set of supernovae based on the input
    !! cosmological parameters.
    subroutine Observed_SN_Magnitude( P, FP, sn_magnitude, redshift, color, stretch, num, err )

        implicit none

        Type(CAMBparams)      , intent(in)  :: P            !< Input CAMBparams
        Type(cosmicfish_params), intent(in)  :: FP           !< Input Cosmicfish params
        real(dl), dimension(:), intent(out) :: sn_magnitude !< Output array with the supernovae magnitude
        real(dl), dimension(:), intent(in)  :: redshift     !< Input array with the values of redshift
        real(dl), dimension(:), intent(in)  :: color        !< Input array with the values of color
        real(dl), dimension(:), intent(in)  :: stretch      !< Input array with the values of stretch
        integer               , intent(in)  :: num          !< number of supernovae.
                                                            !< Length of the sn_magnitude,
                                                            !< redshift, color, stretch vectors
        integer, intent(out)    :: err                      !< Output error code:
                                                            !< 0 = all fine
                                                            !< 1 = error in input
                                                            !< 2 = error in computation
                                                            !< 3 = error in quality
                                                            !< 4 = routine specific

        ! other definitions:
        integer  :: i
        real(dl) :: alpha, beta, zero_mag
        logical  :: EFTsuccess
        ! initialization:
        sn_magnitude = 0._dl
        err          = 0

        call CAMBParams_Set(P)

#ifdef COSMICFISH_EFTCAMB
        ! check stability if EFTCAMB is used
        if (P%EFTflag /= 0) then
            call EFTCAMB_initialization(EFTsuccess)
            if (.not. EFTsuccess) then
                write(*,*) 'EFTCAMB: unstable model'
                err = 4
                return
            end if
        end if
#endif

        alpha    = FP%fisher_SN%alpha_SN
        beta     = FP%fisher_SN%alpha_SN
        zero_mag = FP%fisher_SN%M0_SN

        ! compute the supernova magnitude array:
        do i=1, num
            sn_magnitude(i) = 5._dl*log10( LuminosityDistance(redshift(i)) ) &
                & -alpha*stretch(i) +beta*color(i) + zero_mag -25._dl
        end do

    end subroutine Observed_SN_Magnitude

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine generates a mock SN data set compilation based on the input specifications
    !> contained in the CosmicFish parameters.
    subroutine Generate_SN_Mock_Data( P, FP, sn_mock )

        use Random_utilities

        implicit none

        Type(CAMBparams)        , intent(in)  :: P            !< Input CAMBparams
        Type(cosmicfish_params)  , intent(in)  :: FP           !< Input Cosmicfish params
        real(dl), dimension(:,:), intent(out) :: sn_mock      !< Output supernovae mock
                                                              !< This array has to be allocated
                                                              !< with dimension 3 x (FP%fisher_SN%total_SN_number)

        ! other definitions:
        integer  :: i, j, k

        ! initialize the random number generator:
        Rand_Feedback = 0
        call initRandom()

        ! generate the mock data:
        i = 1
        do j=1, FP%fisher_SN%number_SN_windows
            do k=1, FP%fisher_SN%SN_number(j)
                sn_mock(1,i) = random_uniform( FP%fisher_SN%SN_redshift_start(j), FP%fisher_SN%SN_redshift_end(j)) ! mock redshift
                sn_mock(2,i) = random_gaussian( 0._dl, FP%fisher_SN%color_dispersion )                             ! mock color
                sn_mock(3,i) = random_gaussian( 0._dl, FP%fisher_SN%stretch_dispersion )                           ! mock stretch
                i = i + 1
            end do
        end do

    end subroutine Generate_SN_Mock_Data

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine generates a mock SN covariance based on the input specifications
    !> contained in the CosmicFish parameters and the SN mock.
    subroutine Generate_SN_Mock_Covariance( P, FP, sn_mock, sn_mock_covariance )

        use constants, only : c

        implicit none

        Type(CAMBparams)        , intent(in)  :: P            !< Input CAMBparams
        Type(cosmicfish_params)  , intent(in)  :: FP           !< Input Cosmicfish params
        real(dl), dimension(:,:), intent(in)  :: sn_mock      !< Input supernovae mock
                                                              !< This array has to be allocated
                                                              !< with dimension 3 x (FP%fisher_SN%total_SN_number)
        real(dl), dimension(:)  , intent(out) :: sn_mock_covariance !< SN mock covariance array (assumed diagonal)
                                                                    !< of size FP%fisher_SN%total_SN_number

        ! other definitions:
        integer  :: i, j, k

        ! generate the mock covariance first terms:
        do i=1, FP%fisher_SN%total_SN_number
            sn_mock_covariance(i) = (FP%fisher_SN%magnitude_sigma)**2 &
                & +(FP%fisher_SN%sigma_lens_0*sn_mock(1,i))**2 & ! lensing term
                & +(5._dl/sn_mock(1,i)/log(10._dl)*FP%fisher_SN%c_sigmaz/c*1000._dl)**2 ! redshift term
        end do

        ! add the systematic effects to the covariance:
        do i=1, FP%fisher_SN%total_SN_number
            sn_mock_covariance(i) = sn_mock_covariance(i) &
                & + FP%fisher_SN%beta_SN**2*(FP%fisher_SN%dcolor_offset+FP%fisher_SN%dcolor_zcorr*sn_mock(1,i)**2)**2  &
                & + FP%fisher_SN%alpha_SN**2*(FP%fisher_SN%dshape_offset+FP%fisher_SN%dshape_zcorr*sn_mock(1,i)**2)**2  &
                & + 2._dl*FP%fisher_SN%alpha_SN*(FP%fisher_SN%cov_ms_offset+FP%fisher_SN%cov_ms_zcorr*sn_mock(1,i)**2)     &
                & - 2._dl*FP%fisher_SN%beta_SN*(FP%fisher_SN%cov_mc_offset+FP%fisher_SN%cov_mc_zcorr*sn_mock(1,i)**2)     &
                & - 2._dl*FP%fisher_SN%alpha_SN*FP%fisher_SN%beta_SN*(FP%fisher_SN%cov_sc_offset+FP%fisher_SN%cov_sc_zcorr*sn_mock(1,i)**2)
        end do

    end subroutine Generate_SN_Mock_Covariance

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine outputs to file a SN covariance.
    subroutine Save_Sn_Mock_To_File( mock_size, sn_mock_data, sn_mock_covariance, filename, magnitude )

        implicit none

        integer                 , intent(in) :: mock_size           !< Total length of the SN mock data set
        real(dl), dimension(:,:), intent(in) :: sn_mock_data        !< SN mock data, of dimension 3 x mock_size
        real(dl), dimension(:)  , intent(in) :: sn_mock_covariance  !< SN mock covariance, diagonal, of dimension mock_size
        character(len=*)        , intent(in) :: filename            !< Name of the file where the SN mock will be saved

        real(dl), dimension(:)  , intent(in), optional :: magnitude !< Optionally the array with the magnitude of the SN catalog
                                                                    !< can be written to file

        ! other definitions:
        integer  :: i

        ! write the mock:
        open(unit=666, FILE=filename, ACTION="write", STATUS="replace")

        if ( present(magnitude) ) then

            write(666,'(a)') "# number of the SN, redshift, magnitude, color, stretch, covariance "
            do i = 1, mock_size
                write(666,'(I10,5E15.5)') i, sn_mock_data(1,i), magnitude(i), sn_mock_data(2,i), sn_mock_data(3,i), sn_mock_covariance(i)
            end do

        else

            write(666,'(a)') "# number of the SN, redshift, color, stretch, covariance "
            do i = 1, mock_size
                write(666,'(I10,4E15.5)') i, sn_mock_data(1,i), sn_mock_data(2,i), sn_mock_data(3,i), sn_mock_covariance(i)
            end do

        end if

        close(666)

    end subroutine save_sn_mock_to_file

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine computes the derivative of the observed magnitude of a set of supernovae.
    !! The calculation is carried out with a fixed stepsize finite difference formula or by
    !! the Richardson’s deferred approach to the limit.
    subroutine Observed_SN_Magnitude_derivative( P, FP, param_num, &
        & mag_initial, mag_derivative, mag_der_error, &
        & sn_mock, &
        & initial_step, &
        & num_param, &
        & error_code  )

        implicit none

        Type(CAMBparams)       , intent(in) :: P       !< Input CAMBparams
        Type(cosmicfish_params) , intent(in) :: FP      !< Input Cosmicfish params

        integer , intent(in)  :: param_num  !< Input number of the parameter wrt the derivative is computed
        integer , intent(in)  :: num_param  !< Input number of parameters involved in the calculation

        real(dl), dimension(:), intent(in)  :: mag_initial     !< SN magnitude computed for h=0
        real(dl), dimension(:), intent(out) :: mag_derivative  !< Output returns the derivative of the SN magnitude vector
        real(dl), dimension(:), intent(out) :: mag_der_error   !< Output returns the error on the megnitude derivative

        real(dl), dimension(:,:), intent(in) :: sn_mock        !< Input supernovae mock. Three columns with SN redshift, color and stretch

        real(dl), intent(in)  :: initial_step  !< Input initial value of h. Does not need to be small for the adaptive algorithm.
        integer , intent(out) :: error_code    !< Output error code. When run the code will not stop on error but report it
                                               !<  0 = everything was fine computation exited correctly
                                               !<  1 = error on input parameters
                                               !<  2 = error on computation
                                               !<  3 = error on quality of the results

        ! definitions:
        real(dl), dimension(:), allocatable :: sn_temp_1, sn_temp_2, errt
        integer , dimension(:), allocatable :: accept_mask
        real(dl), dimension(:,:,:), allocatable :: a
        real(dl), dimension(num_param) :: param_vector, fiducial_param_vector, temp_param_vector
        ! parameters of the algorithm:
        real(dl), parameter :: con  = 1.4_dl  ! parameter that decides the decrease in the stepsize h
        real(dl), parameter :: big  = 1.d+30  ! a big number used to fill the error array initially
        real(dl), parameter :: safe = 2._dl   ! parameter used to define the stopping cryterium
        integer , parameter :: ntab = 30      ! maximum number of Cls computation
        real(dl) :: con2 = con*con
        integer  :: i, j, k, l, m, side, err, AllocateStatus
        real(dl) :: fac, hh
        real(dl) :: temp1, temp2, temp3
        Type(CAMBparams) :: P_temp
        Type(cosmicfish_params) :: FP_temp
        integer  :: accepted
        real(dl) :: acceptance
        integer  :: mock_sn_size
        real(dl), dimension(:), allocatable :: redshift, color, stretch

        ! initialize output variables:
        error_code     = 0
        mag_derivative = 0._dl
        mag_der_error  = 0._dl

        ! check input values are correct
        if ( initial_step == 0._dl ) then
            stop 'Observed_SN_Magnitude_derivative initial stepsize is zero'
        end if

        mock_sn_size = FP%fisher_SN%total_SN_number

        ! allocate the arrays:
        if ( FP%adaptivity ) then
            allocate( sn_temp_1(mock_sn_size),  &
                & sn_temp_2(mock_sn_size),  &
                & errt(mock_sn_size),       &
                & accept_mask(mock_sn_size),&
                & stat = AllocateStatus )
            if (AllocateStatus /= 0) stop "Observed_SN_Magnitude_derivative: Allocation failed. Not enough memory"
            allocate( a(ntab, ntab, mock_sn_size) , stat = AllocateStatus )
            if (AllocateStatus /= 0) stop "Observed_SN_Magnitude_derivative: Allocation failed. Not enough memory for the derivative array"
        else
            allocate( sn_temp_1(mock_sn_size),  &
                & sn_temp_2(mock_sn_size),  &
                & stat = AllocateStatus )
            if (AllocateStatus /= 0) stop "Observed_SN_Magnitude_derivative: Allocation failed. Not enough memory"
            allocate( a(1,1, mock_sn_size) , stat = AllocateStatus )
            if (AllocateStatus /= 0) stop "Observed_SN_Magnitude_derivative: Allocation failed. Not enough memory for the derivative array"
        end if

        allocate( redshift(mock_sn_size),       &
            & color(mock_sn_size),       &
            & stretch(mock_sn_size),     &
            & stat = AllocateStatus )

        ! copy the data from the sn mock:
        redshift(:) = sn_mock(1,:)
        color(:)    = sn_mock(2,:)
        stretch(:)  = sn_mock(3,:)

        ! initialize the parameter array:
        P_temp  = P
        FP_temp = FP

        call CAMB_params_to_params_array( P_temp, FP, num_param, param_vector )

        fiducial_param_vector = param_vector
        temp_param_vector     = param_vector

        ! initialize the computation:
        hh            = initial_step
        mag_der_error = big
        side          = 0 ! both sides
        if ( FP%adaptivity ) accept_mask = 0

        ! do the initial step on the right:
        param_vector(param_num)      = fiducial_param_vector(param_num) + hh
        call params_array_to_CAMB_param( P_temp, FP_temp, num_param, param_vector )
        call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_1, redshift, color, stretch, mock_sn_size, err )
        ! if on the right we cannot go we go to the left:
        if ( err /= 0 ) side = 1
        ! do the initial step on the left:
        temp_param_vector(param_num) = fiducial_param_vector(param_num) - hh
        call params_array_to_CAMB_param( P_temp, FP_temp, num_param, temp_param_vector )
        call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_2, redshift, color, stretch, mock_sn_size, err )

        ! if on the left we cannot go decide what to do:
        if ( err /= 0 ) then
            if ( side == 1 ) then ! we cannot go to the left nor to the right. Return derivative zero with error code.
                error_code      = 4
                mag_der_error   = 0.0_dl
                mag_derivative   = 0.0_dl
                return
            else if ( side == 0 ) then ! we cannot go to the left but we can go to the right:
                side = 2
            end if
        end if

        ! store the results based on the side we decided to go:
        if (side == 0) then ! both sides
            a(1,1,:) = (sn_temp_1(:) - sn_temp_2(:))/(2.0_dl*hh)
        else if (side == 1) then ! left side: increment negative
            a(1,1,:) = (sn_temp_2(:) - mag_initial(:))/(-hh)
        else if (side == 2) then ! right side: increment positive
            a(1,1,:) = (sn_temp_1(:) - mag_initial(:))/(hh)
        end if

        ! fixed stepsize derivative if adaptivity is not wanted:
        if ( .not. FP%adaptivity ) then
            mag_derivative(:) = a(1,1,:)
            mag_der_error     = 0.0_dl
            deallocate( sn_temp_1, sn_temp_2, a )
            return
        end if

        ! start the derivative computation:
        do i = 2, ntab

            ! feedback for the adaptive derivative:
            if ( FP%cosmicfish_feedback >= 2 ) then
                accepted   = sum(accept_mask)
                acceptance = REAL(accepted)/REAL(mock_sn_size)
                print*, 'iteration:', i
                print*, '  stepsize:', hh
                print*, '  accepted elements', accepted, 'accepted ratio', acceptance
            end if

            ! decrease the stepsize:
            hh = hh/con

            ! compute the finite difference:
            if (side == 0) then
                param_vector(param_num)      = fiducial_param_vector(param_num) + hh
                temp_param_vector(param_num) = fiducial_param_vector(param_num) - hh
                ! compute for + hh
                call params_array_to_CAMB_param( P_temp, FP_temp, num_param, param_vector )
                call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_1, redshift, color, stretch, mock_sn_size, err )
                if ( err /= 0 ) then
                    error_code     = 4
                    mag_der_error  = 0.0_dl
                    mag_derivative = 0.0_dl
                    return
                end if
                ! compute for - hh
                call params_array_to_CAMB_param( P_temp, FP_temp, num_param, temp_param_vector )
                call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_2, redshift, color, stretch, mock_sn_size, err )
                if ( err /= 0 ) then
                    error_code     = 4
                    mag_der_error  = 0.0_dl
                    mag_derivative = 0.0_dl
                    return
                end if
                ! store the result
                a(1,i,:) = (sn_temp_1(:) - sn_temp_2(:))/(2.0_dl*hh)
            else if (side==1) then
                param_vector(param_num)      = fiducial_param_vector(param_num) - hh
                call params_array_to_CAMB_param( P_temp, FP_temp, num_param, param_vector )
                call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_1, redshift, color, stretch, mock_sn_size, err )
                if ( err /= 0 ) then
                    error_code     = 4
                    mag_der_error  = 0.0_dl
                    mag_derivative = 0.0_dl
                    return
                end if
                ! store the result
                a(1,i,:) = (sn_temp_1(:) - mag_initial(:))/(-hh)
            else if (side==2) then
                param_vector(param_num)      = fiducial_param_vector(param_num) + hh
                call params_array_to_CAMB_param( P_temp, FP_temp, num_param, param_vector )
                call Observed_SN_Magnitude( P_temp, FP_temp, sn_temp_1, redshift, color, stretch, mock_sn_size, err )
                if ( err /= 0 ) then
                    error_code     = 4
                    mag_der_error  = 0.0_dl
                    mag_derivative = 0.0_dl
                    return
                end if
                ! store the result
                a(1,i,:) = (sn_temp_1(:) - mag_initial(:))/(hh)
            end if

            ! now do the extrapolation table:
            fac=CON2
            do j = 2, i

                forall ( k = 1:mock_sn_size, accept_mask(k) == 0 )
                    ! compute the interpolation table:
                    a(j,i,k) = (a(j-1,i,k)*fac-a(j-1,i-1,k))/(fac-1._dl)
                    ! estimate the error:
                    errt(k)  = max( abs(a(j,i,k)-a(j-1,i,k)), &
                        & abs(a(j,i,k)-a(j-1,i-1,k)))
                end forall

                fac=CON2*fac

                ! if there is an improvement save the result:

                forall ( k = 1:mock_sn_size, &
                    & errt(k) .le. mag_der_error(k) .and. accept_mask(k) == 0 )

                    mag_der_error(k) = errt(k)
                    mag_derivative(k) = a(j,i,k)
                end forall

            end do
            ! accept a value of the derivative if the value of the extrapolation is stable
            ! Store this information into the mask matrix
            ! so that the value contained in cl_error and cl_derivative is not overwritten.
            forall ( k = 1:mock_sn_size, &
                & accept_mask(k) == 0 .and. &
                & (a(i,i,k) - a(i-1,i-1,k)) .ge. safe*mag_der_error(k) )

                accept_mask(k) = 1
            end forall

            ! if all the entries match the required accuracy exit the loop
            if ( sum(accept_mask) == mock_sn_size ) exit

        end do

        ! quality check on the results:
        if ( sum(accept_mask) /= mock_sn_size ) then
            error_code = 3
        end if

        ! deallocate the arrays:
        if ( FP%adaptivity ) then
            deallocate( sn_temp_1, sn_temp_2, errt, accept_mask, a )
        end if

        return

    end subroutine Observed_SN_Magnitude_derivative

    ! ---------------------------------------------------------------------------------------------
    !> This subroutine computes the SN Fisher matrix.
    subroutine Fisher_SN( P, FP, num_param, Fisher_Matrix, outroot )

        implicit none

        Type(CAMBparams)       , intent(in) :: P       !< Input CAMBparams
        Type(cosmicfish_params) , intent(in) :: FP      !< Input Cosmicfish params

        integer , intent(in)  :: num_param                                        !< Input dimension of the Fisher matrix
        real(dl), dimension(num_param,num_param), intent(out) :: Fisher_Matrix    !< Output Fisher matrix
        character(len=*), intent(in), optional :: outroot                         !< Optional input: filename that will be used to dump to file optional output if feedback is greater than 1.

        real(dl) :: time_1, time_2, time_1_MC, time_2_MC
        real(dl) :: initial_step, temp, temp1, temp2
        integer  :: AllocateStatus, err, ind, ind2
        integer  :: i, j, k, l, number
        real(dl), allocatable :: param_array(:)
        real(dl), allocatable, dimension(:,:) :: sn_mock
        real(dl), allocatable, dimension(:)   :: sn_mock_covariance
        real(dl), allocatable, dimension(:)   :: sn_fiducial, sn_derivative, sn_temp
        real(dl), allocatable, dimension(:,:) :: sn_derivative_array

        integer  :: MC_i
        real(dl), dimension(num_param,num_param) :: MC_Fisher_Matrix

        ! allocate a parameter array:
        allocate( param_array(num_param) )
        ! write the parameters in the parameter array:
        call CAMB_params_to_params_array( P, FP, num_param, param_array )

        number = FP%fisher_SN%total_SN_number

        ! allocation:
        allocate( sn_mock(3,number), stat = AllocateStatus )
        if (AllocateStatus /= 0) stop "Allocation failed. Not enough memory to allocate SN mock."
        allocate( sn_mock_covariance(number), stat = AllocateStatus )
        if (AllocateStatus /= 0) stop "Allocation failed. Not enough memory to allocate SN mock covariance."
        allocate( sn_fiducial(number), sn_derivative(number), sn_temp(number), stat = AllocateStatus )
        if (AllocateStatus /= 0) stop "Allocation failed. Not enough memory to allocate SN fiducial."
        allocate( sn_derivative_array( num_param, number ), stat = AllocateStatus)
        if (AllocateStatus /= 0) stop "Allocation failed. Not enough memory to allocate sn_derivative_array"

        ! do the Monte Carlo:

        MC_Fisher_Matrix = 0._dl

        time_1_MC = omp_get_wtime()
        do MC_i=1, FP%fisher_SN%SN_Fisher_MC_samples

            ! generate the SN mock:
            call Generate_SN_Mock_Data( P, FP, sn_mock )

            ! generate the mock covariance:
            call Generate_SN_Mock_Covariance( P, FP, sn_mock, sn_mock_covariance )

            ! compute the fiducial:
            time_1 = omp_get_wtime()
            call Observed_SN_Magnitude( P, FP, sn_fiducial, sn_mock(1,:), sn_mock(2,:), sn_mock(3,:), &
                & number, err )
            time_2 = omp_get_wtime() - time_1

            if ( present(outroot) ) call save_sn_mock_to_file( number, sn_mock, sn_mock_covariance, &
                & filename=TRIM(outroot)//'sn_fiducial_'//trim(adjustl(integer_to_string(MC_i)))//'.dat', magnitude = sn_fiducial )

            if ( err == 0 ) then
            else if ( err == 4 ) then
                write(*,*) 'Fiducial model unstable. Calculation cannot proceed.'
                stop
            else
                write(*,*) 'Error in computing the fiducial. Calculation cannot proceed.'
                stop
            end if

            ! print some feedback
            if ( MC_i==1 .and. FP%cosmicfish_feedback >= 1 ) then
                write(*,'(a)')         '**************************************************************'
                write(*,'(a,i10)')         'Number of supernovae         : ', number
                write(*,'(a,i10)')         'Number of parameters         : ', num_param
                write(*,'(a,i10)')         'Number of MC repetitions     : ', FP%fisher_SN%SN_Fisher_MC_samples
                write(*,'(a,f10.3,a)')     'Time taken for SN calculation: ', time_2, ' (s)'
                write(*,'(a,i10)')         'Number of omp processes      : ', OMP_GET_MAX_THREADS()
                if ( FP%adaptivity ) then
                    write(*,'(a,f10.3,a)') 'Estimated completion time    : ', FP%fisher_SN%SN_Fisher_MC_samples*time_2*20._dl*num_param, ' (s)'
                else
                    write(*,'(a,f10.3,a)') 'Estimated completion time    : ', FP%fisher_SN%SN_Fisher_MC_samples*time_2*2._dl*num_param, ' (s)'
                end if
                write(*,'(a)')         '**************************************************************'
            end if

            if ( MC_i>1 .and. FP%cosmicfish_feedback >= 1 ) then
                write(*,'(a)') '**************************************************************'
                write(*,'(a,i10)') 'Doing MC computation of SN Fisher sample: ', MC_i
                write(*,'(a)') '**************************************************************'
            end if

            ! compute the derivatives of the Cls:
            if ( FP%cosmicfish_feedback >= 1 ) then
                write(*,'(a)') 'Computation of the SN magnitude derivatives'
            end if

            time_1 = omp_get_wtime()
            do ind = 1, num_param

                if ( FP%cosmicfish_feedback >= 1 ) then
                    write(*,'(a,i5,a,E15.5)') 'Doing parameter number: ', ind, ' value: ', param_array(ind)
                end if

                if ( param_array(ind) /= 0._dl ) then
                    initial_step = param_array(ind)*3.0_dl/100._dl
                else
                    initial_step = 3.0_dl/100._dl
                end if

                call Observed_SN_Magnitude_derivative( P, FP, ind, &
                    & sn_fiducial, sn_derivative, sn_temp, &
                    & sn_mock, &
                    & initial_step, &
                    & num_param, &
                    & err  )

                if (err /= 0) print*, 'WARNING: something went wrong with the SN derivative of parameter:', ind, 'Error code:', err

                if ( MC_i==1 .and. present(outroot) .and. FP%cosmicfish_feedback >= 2 ) then
                    call save_sn_mock_to_file( number, sn_mock, sn_mock_covariance, &
                        & filename=TRIM(outroot)//'sn_derivative_'//trim(adjustl(integer_to_string(ind)))//'.dat', magnitude = sn_derivative )
                end if

                sn_derivative_array(ind,:) = sn_derivative(:)

            end do
            time_2 = omp_get_wtime() - time_1

            if ( FP%cosmicfish_feedback >= 1 ) then
                write(*,*)
                write(*,'(a,f8.3,a)') 'Time to compute all the derivatives:', time_2, ' (s)'
            end if

            ! compute the Fisher:
            do ind = 1, num_param
                do ind2 = 1, num_param

                    temp2 = 0._dl

                    do k = 1, number
                        temp2 = temp2 + sn_derivative_array(ind,k)*sn_derivative_array(ind2,k)/sn_mock_covariance(k)
                    end do

                    MC_Fisher_Matrix(ind, ind2) = MC_Fisher_Matrix(ind, ind2) + temp2

                end do
            end do
            time_2 = omp_get_wtime() - time_1

            if ( FP%cosmicfish_feedback >= 1 ) then
                write(*,'(a,f8.3,a)') 'Time to compute the Fisher matrix:', time_2, ' (s)'
            end if

        end do
        time_2_MC = omp_get_wtime() - time_1

        Fisher_Matrix = MC_Fisher_Matrix/FP%fisher_SN%SN_Fisher_MC_samples

        if ( FP%cosmicfish_feedback >= 1 ) then
            write(*,'(a)') '**************************************************************'
            write(*,'(a,f8.3,a)') 'Time to compute the MC Fisher matrix:', time_2_MC, ' (s)'
            write(*,'(a)') '**************************************************************'
        end if

    end subroutine Fisher_SN

    ! ---------------------------------------------------------------------------------------------

end module Fisher_calculator_SN

!----------------------------------------------------------------------------------------

back to top