! =======================================================================================================
! public subroutine: read the control file
! =======================================================================================================


! *********************************************************************
! subroutine: solve advection-diffuision equation (ade)
! *********************************************************************


! *********************************************************************
! subroutine: compute normalized UH from Saint-Venant Eq. at sim. time step
!             for all the upstream segment
! *********************************************************************


! *********************************************************************
! subroutine: perform accumulate immediate upstream flow
! *********************************************************************


! **********************************************************************************************
! public subroutine: open file
! **********************************************************************************************


! **********************************************************************************************
! public subroutine: split a line of characters into an vector of "words"
! **********************************************************************************************


! **********************************************************************************************
! public function: convert string to lower case
! **********************************************************************************************


! *********************************************************************
! subroutine: perform one segment route KW routing
! *********************************************************************


! ----------------------------------------------------------------------------------------
! Tributary related routines/functions
! ----------------------------------------------------------------------------------------


! ----------------------------------------------------------------------------------------
! Other pfafstetter decoding routines/functions
! ----------------------------------------------------------------------------------------


! *********************************************************************
! subroutine: perform muskingum-cunge routing for one segment
! *********************************************************************


! *********************************************************************
! subroutine: solve muskingum equation
! *********************************************************************


! *********************************************************************
! public subroutine: augment river network data
! *********************************************************************


! *********************************************************************
! public subroutine: check network data is physically valid
! *********************************************************************


! *********************************************************************
! public subroutine: populate old data strucutures
! *********************************************************************
! ---------- temporary code: populate old data structures --------------------------------------------------


! -----
! check relational logic between two datetime
! -----


! -------------------------------
! no type-bound procedure
! -------------------------------
! ***************************************************************************************
! public subroutine compJulday: convert datetime to julian day (units of days)
! ***************************************************************************************


! ******************************************************************************************
! public subroutine extractTime: extract year/month/day/hour/minute/second from units string
! ******************************************************************************************


! internal subroutine extract: extract substring


! *********************************************************************
! subroutine: initialize ParallelIO system
! *********************************************************************


! *********************************************************************
! subroutine: PIO domain decomposition data
! *********************************************************************


! -----------------------------
! Reading routine
! -----------------------------
! ---------------------------------------------------------------
! read distributed a vector into 1D data


! ---------------------------------------------------------------
! read distributed a vector into 1D data


! -----------------------------
! Writing routine
! -----------------------------
! ---------------------------------------------------------------
! write attributes


! ---------------------------------------------------------------
! write global scalar


! ---------------------------------------------------------------
! write global character vector into 1D variable


! ---------------------------------------------------------------
! write global integer vector into 1D variable


! ---------------------------------------------------------------
! write global integer 2D into 2D variable


! ---------------------------------------------------------------
! write distributed vector into 1D variable


! ---------------------------------------------------------------
! write distributed 2D array into 2D variable


! ---------------------------------------------------------------
! write distributed 3D array into 2D variable


!
! Writing distributed data in nc variable with record dimension
!
! ---------------------------------------------------------------
! write distributed vector into 2D variable with record dimension


! ---------------------------------------------------------------
! write distributed integer 2D array into 3D variable with record dimension


! ---------------------------------------------------------------
! write distributed integer 3D array into 4D variable with record dimension


! *********************************************************************
! new subroutine: get ancillary data for HRUs and stream segments
! *********************************************************************


! ----------------------------------
! SEND-RECV - real array element
! ----------------------------------


! ----------------------------------
! BROADCAST - integer allocatable array
! ----------------------------------


! ----------------------------------
! BROADCAST - real allocatable array
! ----------------------------------


! ----------------------------------
! BROADCAST - logical allocatable array
! ----------------------------------


! ----------------------------------
! BROADCAST - character allocatable array (fixed character length)
! ----------------------------------


! ----------------------------------
! SCATTERV - 1D integer array
! ----------------------------------


! ----------------------------------
! SCATTERV - 1D double precision array
! ----------------------------------


! ----------------------------------
! SCATTERV - 1D logical array
! ----------------------------------


! ----------------------------------
! GATHERV - 1D integer array
! ----------------------------------


! ----------------------------------
! GATHERV - 1D real8 array
! ----------------------------------


! ----------------------------------
! GATHERV - 1D logical array
! ----------------------------------


! ALLGATHER
! ----------------------------------
! ALLGATHER - 1D integer array
! ----------------------------------


!-------------------------------------------------------------------------------
! PURPOSE: MPI number of tasks
!-------------------------------------------------------------------------------


!-------------------------------------------------------------------------------
! PURPOSE: mpi barrier (wait for the other procs to catch up)
!-------------------------------------------------------------------------------


!-------------------------------------------------------------------------------
! PURPOSE: layer on MPI error checking
!-------------------------------------------------------------------------------


!-------------------------------------------------------------------------------
! handle non-MPI error codes
!-------------------------------------------------------------------------------


! *********************************************************************
! public subroutine: main routine to define new output file
! *********************************************************************


! ******************************************************************************************************************************
! public function gammp: compute cumulative probability using the Gamma distribution
! ******************************************************************************************************************************


! ******************************************************************************************************************************
! private function gser: series development of the incomplete Gamma function
! ******************************************************************************************************************************


! ******************************************************************************************************************************
! private function gcf: continued fraction development of the incomplete Gamma function
! ******************************************************************************************************************************


! ******************************************************************************************************************************
! private function gammln: gamma function
! ******************************************************************************************************************************


! *********************************************************************
! public function: top channel width [m]
! *********************************************************************


! *********************************************************************
! public function: wetted perimeter [m]
! *********************************************************************


! *********************************************************************
! public function: flow area [m2]
! *********************************************************************


! *********************************************************************
! public function: water height if you know flow area [m]
! *********************************************************************


! *********************************************************************
! public function: channel storage [m3]
! *********************************************************************


! *********************************************************************
! public function: uniform flow [m3/s]
! *********************************************************************


! *********************************************************************
! public function: flow depth [m]
! *********************************************************************


! *********************************************************************
! public function: wave celerity [m/s]
! *********************************************************************


! *********************************************************************
! public function: wave diffusivity [m2/s]
! *********************************************************************


! *********************************************************************
! public subroutine: modification of river/lake variable I/O options
! *********************************************************************


! *********************************************************************
! new subroutine: write ancillary data for HRUs and stream segments
! *********************************************************************


! *********************************************************************
! new subroutine: create NetCDF output file
! *********************************************************************


! *********************************************************************
! new subroutine: define variable in NetCDF file
! *********************************************************************


! *********************************************************************
! new subroutine: write variables to NetCDF file (double precision)
! *********************************************************************


! *********************************************************************
! new subroutine: write variables to NetCDF file (integer)
! *********************************************************************


! *********************************************************************
! new subroutine: write variables to NetCDF file (character array)
! *********************************************************************


! *********************************************************************
! subroutine: main subroutine for per-reach solute routing
! *********************************************************************


! *********************************************************************
! subroutine: solve advection-diffusion equation within a reach
! *********************************************************************


! *********************************************************************
! subroutine: perform one segment route UH routing
! *********************************************************************


! *********************************************************************
! subroutine: Compute delayed runoff from the upstream segments
! *********************************************************************


! *************************************************************************************************
! * the arth function, used to build a vector of regularly spaced numbers
! *************************************************************************************************


! *************************************************************************************************
! * sort function, used to sort numbers in ascending order
! *************************************************************************************************


! ************************************************************************************************
! findIndex: find the first index within a vector
! ************************************************************************************************


! *************************************************************************************************
! Return indices of True in TF array
! *************************************************************************************************


! *************************************************************************************************
! Find unique elements and indices given array
! *************************************************************************************************


! *************************************************************************************************
! * size of array, if not allocated, return zero
! *************************************************************************************************


! ************************************************************************************************
! match_index: find array1 indix for each array2 element if array2 includes matching element in array1
! ************************************************************************************************


! ---------------------------------------------------------------
! finalize output variable (compute mean)
! ---------------------------------------------------------------


! ---------------------------------------------------------------
! re-initialzae intantiated data structure
! ---------------------------------------------------------------


! ---------------------------------------------------------------
! Release memory (deallocate array)
! ---------------------------------------------------------------


! ---------------------------------------------------------------
! instantiate histVars by reading restart file
! ---------------------------------------------------------------


! ---------------------------------------------------------------------------------------
! Public subroutine main driver for basin routing
! ---------------------------------------------------------------------------------------


! *********************************************************************
! subroutine: perform one basin UH routing to a iSeg reach at one time
! *********************************************************************


! ---------------------------------------------------------------------------------------
! Private subroutine: Perform UH convolutions
! ---------------------------------------------------------------------------------------


! ***************************************************************
! private subroutine: Domain decomposition
! ***************************************************************


! ***************************************************************
! private subroutine: Assign decomposed domain into procs
! ***************************************************************


! *********************************************************************
! public subroutine: output history file
! *********************************************************************


! *********************************************************************
! private subroutine: close all history files
! *********************************************************************


! *********************************************************************
! public subroutine: initialize history file for contiue run
! *********************************************************************


! *********************************************************************
! public subroutine: initialize history variable buffers
! *********************************************************************


! *********************************************************************
! new subroutine: compute correspondence between HRUs and segments
! *********************************************************************


! *********************************************************************
! new subroutine: mapping between upstream and downstream segments
! *********************************************************************


! *********************************************************************
! public subroutine: find ID and index of target reach for each reach
! *********************************************************************


! *********************************************************************
! new subroutine: define index of downstream reach
! *********************************************************************


! *********************************************************************
! subroutine: define processing order for the individual
!                 stream segments in the river network
! *********************************************************************


! *********************************************************************
! public subroutine: compute Shreve stream order for each segment
! *********************************************************************


! *********************************************************************
! new subroutine: identify all reaches above the current reach
! *********************************************************************


! *********************************************************************
! new subroutine: identify all reaches above a given reach
! *********************************************************************


! *********************************************************************
! public subroutine: identify lake inlet reach
! *********************************************************************


! for a given upstream reach, add a downstream reach index to the list


! ---------------------------------------------------------------
! Create history netCDF and define dimension and variables
! ---------------------------------------------------------------


! ---------------------------------
! writing location (hru and/or rch)
! ---------------------------------


! ---------------------------------
! writing time variables
! ---------------------------------


! ---------------------------------
! PIO sync - flush files
! ---------------------------------


! ---------------------------------
! PIO write hru flux variables
! ---------------------------------


! ---------------------------------
! PIO write reach flux variables
! ---------------------------------


! *********************************************************************
! public subroutine: initialize MPI for stand-alone program
! *********************************************************************


! *********************************************************************
! public subroutine: initialize all the data - For stand-alone
! *********************************************************************


! *********************************************************************
! private subroutine: initiate the reading of the netcdf files for runoff
! or abstraction or injection
! *********************************************************************


! *********************************************************************
! private subroutine: read the name of the netcdf that is specified
! in a text file, populates the filed of inFiledata dataType
! *********************************************************************


! *********************************************************************
! private subroutine: initialize time data
! *********************************************************************


! ********************************************************************************
! private subroutine: initialize runoff, and runoff-mapping data - For stand-alone
! ********************************************************************************


! *****
! private subroutine: get 2D runoff (hru, time) with long integer runoff hru_id  metadata...
! ******************************************


! *****
! private subroutine: get 2D runoff (hru, time) with integer runoff hru_id  metadata...
! ******************************************


! *****
! private subroutine: get 3D runoff (lat, lon, time) metadata...
! ******************************************


! *****
! private subroutine: get forcing attributes ...
! ******************************************


! *********************************************************************
! public subroutine: main interface for forcing data reading
! *********************************************************************


! *********************************************************************
! private subroutine: read 1D forcing data
! *********************************************************************


! *********************************************************************
! private subroutine: read 2D forcing data
! *********************************************************************


! *****
! public subroutine: check spatial weight files
! ********************************************************************************


! *********************************************************************
! private subroutine: initialize simulation time
! *********************************************************************


! *********************************************************************
! private subroutine: scale and offset of forcing input
! *********************************************************************


! SH functions for m=0


!-----------------------------------------------
! ELASTIC
!-----------------------------------------------
!---------------------------------
! Orthotropic grains
!---------------------------------
!--------------
! Crystallographic axis definitions
!--------------
! qlm_1 := b
! qlm_2 := n
! qlm_3 := v
!--------------
! Parameter definitions
!--------------
! alpha:      Reuss--Voigt homogenization weight
! Lame_grain: Monocrystal Lame parameters (lam11,lam22,lam33, lam23,lam13,lam12, mu1,mu2,mu3) w.r.t. qi=(b,n,v) axes.
!--------------


!---------------------------------
! Transversely isotropic grains
!---------------------------------


!---------------------------------
! COMPRESSIBLE (POROUS) ISOTROPIC RHEOLOGY
!---------------------------------


!---------------------------------
! TRANSVERSELY ISOTROPIC RHEOLOGY
!---------------------------------


!---------------------------------
! ORTHOTROPIC RHEOLOGY
! ... with Pettit's hypothesis that the *fluidity* is orientation independent
!---------------------------------


!---------------------------------
! ORTHOTROPIC RHEOLOGY
! ... with Martin's hypothesis that the *viscosity* is orientation independent
!---------------------------------


! Equivalent isotropic enhancement factors


! Overloaded versions acting on an array of CPO states


!    function rheo_fwd_tranisotropic_sachshomo(tau, nlm, Eij_grain,n_grain) result(eps)
!        use specfabpy_const
!        implicit none
!        complex(kind=dp), intent(in) :: nlm(:)
!        real(kind=dp), intent(in)    :: Eij_grain(2), tau(3,3)
!        integer, intent(in)          :: n_grain
!        real(kind=dp)                :: eps(3,3)
!
!        eps = rheo_fwd_tranisotropic_sachshomo__sf(tau, nlm, Eij_grain,n_grain)
!    end
!---------------------------------
! ORTHOTROPIC RHEOLOGY
!---------------------------------


! Pettit's hypothesis that the fluidity is orientation independent.


! Martin's hypothesis that the viscosity is orientation independent.


!---------------------------------
! TRANSVERSELY ISOTROPIC ELASTICITY
!---------------------------------


!---------------------------------
! ELASTIC PHASE VELOCITIES
!---------------------------------
! For a composite material consisting of orthotropic grains


! For a composite material consisting of transversely isotropic grains


!---------------------------------
! ELECTROMAGNETIC PHASE VELOCITIES
!---------------------------------


!---------------------------------
! ORTHOTROPIC ELASTICITY
!---------------------------------
! TO BE IMPLEMENTED
!---------------------------------
! AUX ROUTINES
!---------------------------------


!---------------------------------
! Convert fabric dynamics operators to work on reduced form of nlm
!---------------------------------


!   *** DEPRECATED, USE reduce_M() ***
!    function dndt_to_drndt(dndt) result (drndt)
!
!        ! *** Convert dndt_ij (full matrix) to drndt_ij (reduced matrix) such that: d/dt (rnlm)_i = drndt_ij (rnlm)_j
!        ! NOTICE: x-y rotation will make rnlm_j complex valued, in which case drndt_ij does not work as intended (i.e. the full problem involving dndt_ij and nlm_j must be solved).
!        implicit none
!        complex(kind=dp), intent(in) :: dndt(nlm_len,nlm_len)
!        real(kind=dp)                :: drndt(rnlm_len,rnlm_len)
!        integer                      :: kk
!        drndt = 0.0d0
!        do ii = 1, rnlm_len
!            do jj = 1, nlm_len
!
!                kk = I_full(jj)
!
!                if (lm(2,jj) >= 0) then ! m >= 0
!                    drndt(ii,kk) = drndt(ii,kk) + real(dndt(I_all(ii), jj))
!                else ! m < 0
!                    if (MOD(lm(2,jj),2) .eq. 0) then ! m even
!                        drndt(ii,kk) = drndt(ii,kk) + real(dndt(I_all(ii), jj))
!                    else ! m odd
!                        drndt(ii,kk) = drndt(ii,kk) - real(dndt(I_all(ii), jj))
!                    end if
!                end if
!
!            end do
!        end do
!    end
!---------------------------------
! Convert between reduced and full forms
!---------------------------------


!---------------------------------
! For validation purposes only
!---------------------------------


!---------------------------------
! VISCOUS -- Transversely isotropic grains
!---------------------------------


!    function rheo_fwd_tranisotropic_HSPhomo(tau, nlm, Eij_grain,beta,n_grain) result(eps)
!
!        ! Grain-averaged forward rheology subject to HSP homogenization
!
!        implicit none
!
!        complex(kind=dp), intent(in) :: nlm(:)
!        real(kind=dp), intent(in)    :: Eij_grain(2), tau(3,3), beta
!        integer, intent(in)          :: n_grain
!
!        real(kind=dp)                :: eps_Sachs(3,3), eps_fluc(3,3), eps(3,3)
!        real(kind=dp)                :: D0, D2(3,3), D4(3,3,3,3), coefA,coefB,coefC
!        if (n_grain .eq. 1) then
!            call rheo_params_tranisotropic(Eij_grain,3,DFLOAT(n_grain),1, coefA,coefB,coefC)
!            eps_Sachs = rheo_fwd_tranisotropic_sachshomo(tau, nlm, Eij_grain,n_grain)
!            D0 = ev_D2(nlm, tau)
!            call ev_D_ck(nlm, tau, D2, D4)
!            eps_fluc = D0*tau - coefA*doubleinner22(D2,tau)*identity + coefB*doubleinner42(D4,tau) + coefC*(matmul(tau,D2)+matmul(D2,tau))
!            eps = eps_Sachs + beta*(eps_fluc - D0*eps_Sachs)
!        else
!            print *, "n'=", n_grain
!            stop "specfab error: unsupported n'"
!        end if
!    end


!---------------------------------
! VISCOUS -- Orthotropic grains
!---------------------------------


!    function rheo_fwd_orthotropic_taylorhomo(tau, nlm_1, nlm_2, nlm_3, Eij_grain,n_grain) result(eps)
!
!        ! Grain-averaged forward orthotropic rheology subject to Taylor homogenization (constant strain rate over all grains).
!
!        ! *** IN DEVELOPMENT -- @TODO: MATRIX INVERSION NOT WELL BEHAVING ***
!
!        implicit none
!
!        real(kind=dp), intent(in)    :: tau(3,3), Eij_grain(6)
!        complex(kind=dp), intent(in) :: nlm_1(:), nlm_2(:), nlm_3(:)
!        integer, intent(in)          :: n_grain
!        real(kind=dp)                :: eps(3,3), lami(6), ci(6), gam
!        real(kind=dp)                :: a2_i(3, 3,3), a4_ii(3, 3,3,3,3), a4_jk(3, 3,3,3,3)
!        real(kind=dp)                :: P2(3, 3,3,3,3), H2(3, 3,3,3,3), Q(3,3,3,3)
!
!        integer, parameter           :: d = 6 ! dimension
!        real(kind=dp) :: tau_vec(d,1), P(d,d), P_reg(d,d), tau_vec_reg(d,1)
!        integer       :: info
!!        integer :: ipiv(9), work
!
!        ! Tensorial coefficients
!        call rheo_params_orthotropic(Eij_grain, DFLOAT(n_grain), lami, gam)
!        ci(1:3) = 4.0d0/3 * lami(1:3)/gam
!        ci(4:6) =       2 * 1/lami(4:6)
!        ! Tensors
!        call ai_orthotropic(nlm_1, nlm_2, nlm_3, a2_i, a4_ii, a4_jk)
!        do ii=1,3
!            P2(ii, :,:,:,:) = (outerprodmat2(identity,identity) -3*outerprodmat2(identity,a2_i(ii, :,:)) -3*outerprodmat2(a2_i(ii, :,:),identity) + 9*a4_ii(ii, :,:,:,:))/4
!!            P2(ii, :,:,:,:) = (-3.0d0/2)*(outerprodmat2(identity,a2_i(ii, :,:))  - 3*a4_ii(ii, :,:,:,:))/2
!            H2(ii, :,:,:,:) =  a4_sym4(a4_jk(ii, :,:,:,:))
!        end do
!        ! Linear grain viscosity
!        if (n_grain .eq. 1) then
!            Q = ci(1)*P2(1,:,:,:,:) + ci(2)*P2(2,:,:,:,:) + ci(3)*P2(3,:,:,:,:) + &
!                ci(4)*H2(1,:,:,:,:) + ci(5)*H2(2,:,:,:,:) + ci(6)*H2(3,:,:,:,:)
!
!            P = a4_to_mat(Q)
!            ! Solve inverse problem; we are seeking eps given tau in tau = matmul(P, eps).
!            tau_vec(:,1) = mat_to_vec(tau)
!            call dposv('L', 6, 1, P, 6, tau_vec, 6, info) ! tau_vec is now "eps_vec" solution. For some reason, "U" does not work.
!            ! Ill posed? => Regularization needed.
!            if (info /= 0) then
!                P_reg       = matmul(TRANSPOSE(P),P) + 1e-6*identity6
!                tau_vec_reg = matmul(TRANSPOSE(P),tau_vec)
!                call dposv('L', 6, 1, P_reg, 6, tau_vec_reg, 6, info)
!                tau_vec = tau_vec_reg
!                if (info /= 0) then
!                    stop 'specfab error: Taylor viscosity matrix inversion failed! Please check the CPO is correct (reducing the fabric integration time-step, and/or increasing regularization, for transient problems can often help).'
!                end if
!            end if
!            ! Revert solution to 3x3
!            eps = vec_to_mat(tau_vec)
!        else
!            eps(:,:) = 0.0d0 ! n_grain not supported, silently return 0
!        end if
!    end
!---------------------------------
! ELASTIC
!---------------------------------
!function elas_fwd_tranisotropic_voigthomo(strain, nlm, lam,mu, Elam,Emu,Egam) result(strain)
! N/A
!end


!    subroutine frame(nlm, ftype, e1,e2,e3, eigvals)
!        implicit none
!        complex(kind=dp), intent(in) :: nlm(:)
!        character*1, intent(in)      :: ftype ! 'x','e','p' (Cartesian frame, a2 eigenframe, 45deg rotated eigenframe)
!        real(kind=dp), intent(out)   :: e1(3),e2(3),e3(3), eigvals(3)
!        real(kind=dp)                :: p(3),q(3)
!
!        ! Cartesian frame
!        if (ftype == 'x') then
!            e1 = [1,0,0]
!            e2 = [0,1,0]
!            e3 = [0,0,1]
!
!        else
!            ! a2 eigen frame
!            call eig3(a2(nlm), e1,e2,e3, eigvals)
!
!            ! Rotated a2 eigen frame
!            if (ftype == 'p') then
!                p = (e1+e2)/sqrt(2.0)
!                q = (e1-e2)/sqrt(2.0)
!                e1 = p
!                e2 = q
!                ! cross product
!                e3(1) = p(2) * q(3) - p(3) * q(2)
!                e3(2) = p(3) * q(1) - p(1) * q(3)
!                e3(3) = p(1) * q(2) - p(2) * q(1)
!            end if
!
!        end if
!    end


!---------------------------------
! Conversion between nlm and <c^k>
!---------------------------------


!---------------------------------
! Conversion from ri to nlm
!---------------------------------


!---- DEBUG NEW LATROT FORMULATION ----


!---------------------------------
! BOUNDS AND POWER SPECTRUM
!---------------------------------


!---------------------------------
! VISCOUS ENHANCEMENT FACTORS
!---------------------------------
! Transversely isotropic grains


!---------------------------------
! EQUIVALENT ISOTROPIC ENHANCEMENT FACTOR FOR GLACIER ICE
!---------------------------------


!    function E_CAFFE(nlm, eps, Emin, Emax, n_grain)  result(E)
!
!        ! Implements Placidi et al. (2010)
!        implicit none
!        complex(kind=dp), intent(in) :: nlm(:)
!        real(kind=dp), intent(in)    :: eps(3,3), Emin, Emax
!        integer, intent(in)          :: n_grain
!        real(kind=dp)                :: E, Davg, p
!        Davg = ev_D(nlm, eps, n_grain) ! Average deformability, <D>
!!        Davg = abs(Davg) ! numerical errors cause this to be -1e-15 for a single max CPO when it should be zero.
!        E = E_CAFFE_Davg(Davg, Emin, Emax)
!!        if (Davg .lt. 1) then
!!            p = 8.0d0/21 * (Emax-1)/(1-Emin)
!!            E = Emin + (1-Emin)*Davg**p
!!        else
!!            E = (4*Davg**2*(Emax-1) + 25 -4*Emax)/21.0d0
!!        end if
!    end


!---------------------------------
! ELASTIC ENHANCEMENT FACTORS
!---------------------------------
! N/A
!---------------------------------
! SYNTHETIC STRESS STATES
!---------------------------------


! D. A. Lilien and N. M. Rathmann, 2019-2023
!-------------------
! AUX
!-------------------


!
! IBOF.f90
! Copyright (C) 2021 dlilien <dlilien@hozideh>
!
! Distributed under terms of the MIT license.
!


!  (C) Copr. 1986-92 Numerical Recipes Software


!-----------------------------------------------------------
!                     find_z
!  This suborutine finds the projected distance between
!  the star and planet centers. Eq. (5), ( z = r_sky) from
!  Winn, 2010, Transit and Occultations.
!------------------------------------------------------------


!------------------------------------------------------------
!This subrouotine finds the time of periastron passage
!by knowing the transit time
!------------------------------------------------------------


!------------------------------------------------------------
!This subroutine finds the true anomaly of an eccentric orbit
!by using the Newton-Raphson (NR)  algorithm
!The input parameters are:
! man -> mean anomaly, ec -> eccentricity, delta -> NR limit
! imax -> iteration limit for NR, dman -> man dimension
!The output parameters are:
! ta -> True anomaly (vector with the same dimension that man)
!------------------------------------------------------------


! Derived subroutines
! Reads the first record only


!>
!! @brief Allocates and initialises various arrays needed for the nse calculation
!!
!! This subroutine also writes the content of \ref global_class::isotope
!! into shorter variables, such as \ref aa, \ref nn, and \ref gg. In
!! addition it calculates the binding energy
!! \f[ Be(i) = Z(i) \cdot (Z_{me} + e_{m}) + N(i) \cdot N_{me} - M_{exc}(i) \f]
!! with the mass excess of protons (Z), neutrons (N), and the isotope (i), \f$ Z_{me} \f$,
!! \f$ N_{me} \f$, and \f$ M_{exc} \f$. The mass of the electrons (e) is given by \f$ e_{m} \f$.
!! Furthermore it calculates \f$ 1 + 2 \cdot J \f$ with J being the spin
!! of the ground state.
!!
!! \b Edited: 12.01.14


!>
!! @brief Calculate NSE composition with an initial guess.
!!
!! The subroutine tries to calculate nse with an initial guess and if it does
!! not converge, it descends from a high temperature. This routine is used
!! if the parameter \ref parameter_class::nse_calc_every is not equal to zero.
!!
!! @author Moritz Reichert


!>
!! @brief This routine descends from an initially high temperature, at which
!! the NSE abudances can be accurately predicted, to the desired
!! temperature
!!
!! At high temperatures, the solution is more stable and the solution of NSE
!! at a high temperature can be used as an initial guess of a lower temperature.
!! This increases the stability of the calculation and it can iterate to the
!! input temperature "t9fnl". The temperature step is adaptive in this process,
!! however, if it becomes too small (\f$ 10^{-20} \f$ GK) an error is raised.
!!


!> Solves the nse-equations.
!!
!! This subroutine solves the NSE equations. It hereby
!! choses between two different solvers as defined by the
!! parameter \ref parameter_class::nse_solver that is defined as
!! in the following table:
!! | nse_solver | Solver                 |
!! |:----------:|:----------------------:|
!! | 0          | Newton-Raphson         |
!! | 1          | Powell's hybrid method |
!!.
!! @author M. Reichert
!! @date   14.06.23


!> Solves the nse-equations using the Powell hybrid method.
!!
!! This subroutine solves the NSE equations. It's two dimensional as the unknowns
!! are the neutron abundances Yn and proton abundances Yp. The underlying
!! constraints are mass conservation \f$ \sum X_i = \sum Y_i \cdot A_i = 1 \f$
!! and charge conservation \f$ \sum Y_i \cdot Z_i = y_e \f$.
!! The subroutine makes use of the minpack routine fsolve.
!!
!! @author M. Reichert
!! @date   14.06.23


!>
!! @brief Solves the nse-equations using a 2-dimensional newton-raphson scheme
!!
!! This subroutine solves the NSE equations. It's two dimensional as the unknowns
!! are the neutron abundances Yn and proton abundances Yp. The underlying
!! constraints are mass conservation \f$ \sum X_i = \sum Y_i \cdot A_i = 1 \f$
!! and charge conservation \f$ \sum Y_i \cdot Z_i = y_e \f$.
!! Furthermore it uses the so called saha equation:
!! \f[
!! Y(N,Z) = G_{N,Z}(\rho N_A)^{N+Z-1}\frac{\left( N +Z \right)^{3/2}}{2^{N+Z}}\left(\frac{2\pi \hbar}
!!           {m_\mathrm{u} k_{\mathrm{B}}T}\right)^{\frac{3}{2}(N+Z-1)} \mathrm{exp}(B_{N,Z}/
!!           k_B T)Y^{N}_\mathrm{n} Y^Z_\mathrm{p},
!!\f]
!!
!! @warning Here, the abundance of neutrons and protons are used explicitely.
!! A simulation without neutrons and protons specified in the sunet
!! that tries to calculate NSE will result in an error!
!!
!! @see wincnse_calc
!!
!! \b Edited:
!!     - 12.01.14
!!     - 15.01.21
!!     - 23.01.21 MR, Fixed overflows in this routine
!! .


!>
!! @brief Calls screening subroutine and adds subsequent proton capture screening
!! corrections in scrn(1:zmax).
!!
!! This subroutine iterates over all possible amount of protons of a nucleus
!! (up to \ref zmax). It uses the subroutine \ref screen to calculate the
!! screening corrections. After it has been called, the array \ref scrn contains
!! summed screening corrections for proton captures from z=1 to z=i for scrn(i)
!! on symmetric nuclei (\f$ A = 2 \cdot Z \f$).
!!
!! \b Edited:
!!    - 12.01.14
!! .


!>
!! Calculates the nse coefficients C, as given in
!! [Hix,Thielemann '99](https://ui.adsabs.harvard.edu/abs/1999JCoAM.109..321H/abstract), Eq.25
!!
!! This subroutine calculates:
!! \f[ \frac{G(^A Z)}{2^A} \left( \frac{ \rho N_A }{\theta} \right)^{A-1} A^{\frac{3}{2}}
!! \exp{ \left( \frac{B(^A Z)}{k_B T} \right)} \f]
!! ,where \f$ G \f$ are the partition functions, A the mass number, \f$ \rho \f$
!! the density, \f$ N_A \f$ avogadros number, B the binding energy, \f$ k_B \f$
!! the boltzman constant, and T the temperature. Theta is a helper variable and given
!! by:
!! \f[ \theta = \left( \frac{m_u k_B T}{2\pi \hbar^2} \right) \f]
!! The result is stored in the array \ref cnse.
!!
!! \b Edited:
!!   - 12.01.14
!! .


!> Determines the mass and charge conservation for the NSE calculation
!!
!! This subroutine calculates the mass and charge conservation for the NSE
!! calculation. It is used in the Powell hybrid method to solve the system of
!! equations.
!! The first entry of fvec will contain
!! \f[ \sum_i Z_i Y_i - y_e \f]
!! and the second entry will contain
!! \f[ \sum_i A_i Y_i - 1 \f]
!! where \f$ Z_i \f$ is the proton number, \f$ A_i \f$ the mass number, \f$ Y_i \f$
!! the abundance of the isotope i, and \f$ y_e \f$ the electron fraction.
!!
!! @author M. Reichert
!! @date 14.06.23


!>
!! Declares values for the elements in unit_type
!!


!>
!! This function reads the parameter file
!!
!! Blank lines as well as comment lines are skipped.
!! The parameters are read into the proper variable
!! that are declarated at the beginning of the file.
!!
!! \b Edited:
!!   - 01.02.14
!! .


!> Converts a string to an integer
!!
!! If the string is not a valid integer, an error message is raised.
!!
!! @author Moritz Reichert
!! @date 22.01.21


!> Converts a string to an float
!!
!! If the string is not a valid float, an error message is raised.
!!
!! @author Moritz Reichert
!! @date 22.01.21


!>
!! Output parameters to a file
!!
!! Parameters are sorted in alphabetical order
!!


!>
!! Check for consistency of parameter
!!
!! Some parameters might not work together or might cause inconsistencies.
!! This routine checks the user input and complains.
!!
!! @author: M. Reichert
!!
!! \b Edited:
!!      - 21.05.19, MR
!! .


!> Search for similar existing parameters.
!!
!! Takes a list of parameters that are separated by ":" and a comparison
!! parameter and returns the most similar parameter from the list. Furthermore,
!! a score is returned that gives a measure of the similarity of the strings.
!! This function is only called if a user specified parameter was not included
!! in the list of possible parameters.
!!
!! @author M. Reichert
!! @date 02.11.22


!> Calculates the Levenshtein distance between two strings
!!
!! The Levenshtein distance gives a measure of the similarity between
!! two strings. The similarity is expressed in terms of a float afterwards.
!! This routine follows the pseudocode [here](https://en.wikipedia.org/wiki/Levenshtein_distance)
!!
!! @author M. Reichert
!! @date 02.11.22


!> Read important parameters from a binary file and check for consistency
!!
!! This routine reads important parameters from a binary file and checks
!! if they are consistent with the current run. This is done to check if
!! the binary files are compatible with the current parameter file.
!!
!! @note This routine is only called if the parameter "use_prepared_network"
!!      is set to ".true."
!!
!! @author M. Reichert
!! @date 21.07.23


!>
!! Output relevant parameters to a file in the prepared network path
!!
!! Parameters are sorted according to category
!!


!> Output the parameter data to a binary file
!!
!! This routine outputs important parameters to a binary file.
!! This is exclusively done to check later when reading the binary
!! rate files.
!!
!! @author M. Reichert
!! @date 21.07.23


!>
!! Converts .TRUE.->"yes", .FALSE. -> "no"
!!


!> Subroutine to calculate the reaction rates
!!
!! The calculation depends on the source flag of the reaction rate.
!! While reaclib rates are done by a simple fit formula, tabulated rates
!! have to be interpolated, theoretical weak rates have to interpolate
!! on a temperature-density grid, etc.
!!
!! @see reaclib_rate_module::calculate_reacl_rate, tabulated_rate_module::calculate_tab_rate,
!!      tw_rate_module::calculate_twr_rate
!!
!! \b Edited:
!!   - 26.07.22, MR: Created this subroutine from code snippets
!!                   that were flying around in Jacobi_init and abchange.
!! .


!>
!! This subroutine calculates the change in abundances (dYdt) due to
!! reaction rates at given temperature (temp) and density (rho).
!!
!! The underlying differential equation is given by:
!!
!! \f[
!! \mathrm{dYdt}_i = \underbrace{\sum _j N_j ^i \lambda _j Y_j}_\text{Decays and photodisintegrations} +
!! \underbrace{\sum _{j,k} \frac{N^i _{j,k}}{1+\delta _{jk}}\rho N_{\mathrm{A}} \langle \sigma v
!! \rangle _{j,k}Y_jY_k}_\text{two-body reactions}+\underbrace{\sum _{j,k,l}\frac{N^i_{j,k,l}}
!! {1+\Delta_{jkl}}\rho ^2N_{\mathrm{A}}^2\langle \sigma v\rangle _{j,k,l} Y_j Y_k Y_l}_\text{three-body reactions}
!! \f]
!!
!! where the amount of synthesized and destroyed nuclei N_j is stored in
!! global_class::rrate\%ch_amount, the reaction rates come from various sources,
!! but mostly from reaclib (see \ref network_init_module::network_init, nucstuff_class::calc_t9_pow).
!! The individual terms in the equation above are treated with the help of the reaclib chapters,
!! the first term is given by chapter 1-3, the second one by 4-7, the third one 8-9
!! (see also [Reaclib chapters](https://reaclib.jinaweb.org/help.php?topic=reaclib_format&intCurrentNum=0)).
!!

!!
Reaclib chapters

!!
 Chapter    Equation
!!
 1          \f$ e_1             \rightarrow e_2                 \f$
!!
 2          \f$ e_1             \rightarrow e_2 + e_3           \f$
!!
 3          \f$ e_1             \rightarrow e_2 + e_3 + e_4     \f$
!!
 4          \f$ e_1 + e_2       \rightarrow e_3                 \f$
!!
 5          \f$ e_1 + e_2       \rightarrow e_3 + e_4           \f$
!!
 6          \f$ e_1 + e_2       \rightarrow e_3 + e_4 + e_5     \f$
!!
 7          \f$ e_1 + e_2       \rightarrow e_3 + e_4 + e_5 +e_6\f$
!!
 8          \f$ e_1 + e_2 + e_3 \rightarrow e_4 (+ e_5 + e_6)   \f$
!!

!!
!! @note When single_zone_vars::evolution_mode is equal to EM_NSE,
!! this subroutine will ignore strong reactions and only
!! calculate the contribution of weak reactions.
!!
!! @note This routine can be used to calculate the jacobian of the original Reaclib format
!!       without chapter 9-11 as well as the modern format with chapter 9-11.
!!
!! @see jacobi_init,
!!      [Hix & Thielemann 1999](https://ui.adsabs.harvard.edu/abs/1999JCoAM.109..321H/abstract),
!!      [Winteler 2013](https://edoc.unibas.ch/29895/),
!!      [Lippuner & Roberts 2017](https://ui.adsabs.harvard.edu/abs/2017ApJS..233...18L/abstract)
!!
!! \b Edited:
!!     - 12.01.14
!!     - 26.07.22, MR: Cleaned up the subroutine
!!     - 06.02.23, MR: Implemented parameter freeze_rate_temp.
!! .


!> Function to decide whether a rate can contribute or not
!!
!! This function returns true if the rate should not
!! be considered in the differential equation.
!! This can happen by a small value of the rate or
!! by zero abundance of the reactants.
!!
!! @author M. Reichert
!! @date 14.02.23


!>
!! This subroutine calculates the entries in the jacobian and the
!! right-hand side of the numerical integration scheme (rhs).
!!
!! The jacobian is calculated by
!! \f[ J = \frac{\mathrm{dYdt}}{dY}.  \f]
!! The values are directly stored into a sparse format (see \ref pardiso_class::vals).
!!
!! @note When single_zone_vars::evolution_mode is equal to EM_NSE,
!! this subroutine will ignore strong reactions and only
!! calculate the contribution of weak reactions.
!!
!! @note This routine can be used to calculate the jacobian of the original Reaclib format
!!       without chapter 9-11 as well as the modern format with chapter 9-11.
!!
!! @see abchange,
!!      [Hix & Thielemann 1999](https://ui.adsabs.harvard.edu/abs/1999JCoAM.109..321H/abstract),
!!      [Winteler 2013](https://edoc.unibas.ch/29895/),
!!      [Lippuner & Roberts 2017](https://ui.adsabs.harvard.edu/abs/2017ApJS..233...18L/abstract)
!!
!! \b Edited:
!!     - 26.07.22, MR: Cleaned up the subroutine
!!     - 06.02.23, MR: Implemented parameter freeze_rate_temp.
!! .


!>
!! Open files, write headers, allocate space etc.
!!


!>
!! Output first step
!!
!! This routine calls output_iteration at the first step
!!
!! @see output_final_step


!>
!! Output final step
!!
!! This routine calls output_iteration at the last step
!!
!! @see output_final_step
!!
!! \b Edited: OK 26.08.2017


!>
!! Periodic output of analysis data for current iteration
!!
!! Prints various outputs depending on the input parameter.
!!
!! \b Edited:
!!       - MR : 19.01.21
!! .


!> Output the abundances of specific nuclei
!!
!! First column is always the time, followed by the abundances of
!! nuclei given in "track_nuclei_file". An example of the file looks like:
!! \l_file{
!! # time[s]                    Y(     n )                  Y(   o24 )                  Y(   f24 )
!!  0.0000000000000000E+00      0.0000000000000000E+00      2.0833333333333332E-02      0.0000000000000000E+00
!!  1.9999999999999999E-20      8.5150206007805894E-19      2.0833333333333332E-02      1.8661570495808601E-21
!!  5.9999999999999994E-20      2.5545061802341771E-18      2.0833333333333332E-02      5.5984711487425806E-21
!!  1.3999999999999998E-19      5.9605144205464133E-18      2.0833333333333332E-02      1.3063099347066021E-20
!! ...}
!!
!! @author: Moritz Reichert
!!
!! \b Edited:
!!      - 09.06.17
!! .


!> Output the energy that enters and leaves the system
!!
!! Outputs the energy that enters and leaves the system when
!! nuclear_heating is turned on.
!! This output is controlled by the parameter \ref nu_loss_every .
!! The output is written to the file "nu_loss_gain_file".
!! An example of the file could look like:
!! \file{
!! \# File containing the neutrino loss/gain for the nuclear heating.
!! \# Negative values mean that energy is added to the system.
!! \# Neutrino energies are given in MeV/baryon/s.
!! \#           time[s]                 T[GK]            rho[g/cm3]                 R[km]              nu_total  ...
!!         1.10385E+00           1.00000E+01           4.89334E+07           3.55626E+02           0.00000E+00  ...
!!         1.10385E+00           1.00000E+01           4.89334E+07           3.55626E+02          -5.05524E+00  ...
!!         1.10385E+00           1.00000E+01           4.89334E+07           3.55626E+02          -5.05524E+00  ...
!!         1.10385E+00           1.00000E+01           4.89334E+07           3.55626E+02          -5.05524E+00  ...
!! ...}
!! @author Moritz Reichert
!! @date   12.04.2023


!>
!! Output Snapshot files
!!
!! Snapshots store the abundances and mass fractions of all nuclei
!! at certain times. An example file looks like:
!! \file{
!! time    temp    dens
!! 9.77198412010000E-02   9.99927332947922E+00   3.88380373937259E+06
!!  nin     zin       y       x
!! 1    0     5.72194135572689E-01   5.72194135572689E-01
!! 0    1     3.92194484636783E-01   3.92194484636783E-01
!! 1    1     7.83033243870819E-05   1.56606648774164E-04
!! ...}
!!
!! \b Edited:
!!           - 03.04.18, M. Jacobi
!! .


!>
!! Output flow files
!!
!! \b Edited:
!!           - 19.02.20, M. Jacobi


!>
!! Output of the Newton-Raphson loop diagnostics
!!
!! The diagnostic output contains NR iterations, timesteps,
!! the nucleus that restricts the timestep and more.
!! An example file looks like:
!! \l_file{
!! # Newton-Raphson diagnostic output
!! # 1 : global iteration count (cnt)
!! # 2 : global time [s]
!! # 3 : temperature T9 [GK]
!! # 4 : adapt stepsize loop counter (k)
!! # 5 : NR loop counter (nr_count)
!! # 6 : global timestep [s]
!! # 7 : mass conservation error
!! # 8 : maximal abundance change (eps)
!! # 9 : most rapidly evolving isotope (epsl)
!! # 10: abundance of the isotope epsl, y(epsl)
!!       0   5.20740000000E-22   7.42450000000E+00    0    1   5.20740000000E-22   9.32587340685E-15   2.22044604925E-16 cl42   2.43899441583E-08
!!       0   5.20740000000E-22   7.42450000000E+00    0    2   5.20740000000E-22   9.32587340685E-15   2.22044604925E-16  s40   2.73320077046E-08
!!       1   1.56220000000E-21   7.42450000000E+00    0    1   1.04146000000E-21   9.32587340685E-15   2.22044604925E-16  he4   3.13811866442E-03
!!       1   1.56220000000E-21   7.42450000000E+00    0    2   1.04146000000E-21   9.32587340685E-15   2.22044604925E-16 mg30   1.57736344914E-10
!! ...}


!>
!! Print final statistics
!!
!! An example looks like:
!! \file{
!! Final time reached.
!! Final time:  2.000000000000E+17
!! Total number of iterations:       5334
!! Elapsed time [s]:  5.41572E+02
!! }
!!
!! \b Edited:
!!  - 2023-02-06, M.R. took care of wrapping of the simulation time
!!                     that could lead to negative simulation times.
!! .


!>
!! Print current snapshot
!!
!! Snapshots store the abundances and mass fractions of all nuclei
!! at certain times. An example file looks like:
!! \file{
!! time    temp    dens
!! 9.77198412010000E-02   9.99927332947922E+00   3.88380373937259E+06
!!  nin     zin       y       x
!! 1    0     5.72194135572689E-01   5.72194135572689E-01
!! 0    1     3.92194484636783E-01   3.92194484636783E-01
!! 1    1     7.83033243870819E-05   1.56606648774164E-04
!! ...}


!>
!! Calculates average neutron separation energy
!!
!! This neutron separation energy is printed in the mainout when
!! parameter_class::calc_nsep_energy was set to "yes" and
!! a valid file for parameter_class::nsep_energies_file.


!>
!! @brief: Calculate the generated energy for each class of reactions separately.
!!
!! This subroutine calculates the generated energy of the nuclear reactions
!! with the help of the Q-values. This energy is written to an output only.
!! It is not fed back to the temperature and has therefore
!! no impact on the final result. Also, depending on the input the
!! subroutine can calculate the top contributors to the energy generation.
!! These top contributors can be reactions and isotopes.
!!
!! @see \ref nuclear_heating
!!
!! @author: Moritz Reichert
!! @date   29.02.20
!!
!! \b Edited:
!!  - 08.05.24: M.R. Moved the top list calculation from the nuclear heating to this subroutine.
!! .


!>
!! Calculate average timescales of different classes of reactions
!!
!! These timescales are calculated as in
!! [Arcones et al. 2012](https://ui.adsabs.harvard.edu/abs/2012ApJ...750...18A/abstract)
!! (Eq. 1-6). The (p,gamma) timescale is given by e.g.,
!! \f[
!! \tau_{p\gamma} = \left[ \frac{\rho Y_p}{Y_h}N_A \sum \langle \sigma \nu \rangle_{p,\gamma}(Z,A)Y(Z,A) \right]^{-1}
!! \f]
!!
!! An example file looks like:
!! \l_file{
!! # time[s]     Temperature [GK]     tau_ng [s]     tau_gn [s]     tau_pg [s]     tau_gp [s]     tau_np [s]     tau_pn [s]     tau_an [s]     tau_na [s]     tau_beta [s]     tau_alpha [s]     tau_nfiss [s]     tau_sfiss [s]     tau_bfiss [s]
!!  1.1130000000000000E+00    9.1821750000000009E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    1.2642767370327558E+01    2.9487624276191804E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00
!!  1.1220000000000001E+00    8.2638489999999951E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00    1.0557999180036711E+02    2.5923655028366777E+01    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00
!!  1.1247618491767180E+00    7.9904974735555152E+00    9.5690472538317728E-13    5.3150487750907188E-11    7.4419112944811684E-10    9.8479480155439862E-08    1.9792689873245490E-12    1.9444248037144314E-12    4.8686627517806918E-10    3.9657685448682009E-12    1.4600540103519526E+01    5.2634156341152767E+01    0.0000000000000000E+00    0.0000000000000000E+00    0.0000000000000000E+00
!! ...}


!>
!! Compute final abundances and write final output
!!
!! There are three files written _finabsum.dat_
!! containing abundances summed over equal A,
!! _finab.dat_ containing all final abundances,
!! _finabelem.dat_ containing all abundances
!! summed over equal Z.


!>
!! auxiliary sorting subroutine
!!


!>
!! Close files at the end of the calculation
!!
!! @author: Moritz Reichert
!!
!! \b Edited:
!!     - 01.03.17
!!     - 25.01.21
!! .


!>
!! Initialize the mergesort module and open files for debugging.
!!
!! The file _debug_tabln.dat_ is created in case of
!! verbose_level>2.
!!
!! @author Moritz Reichert
!!
!! \b Edited:
!!       - 06.06.17
!! .


!>
!! Merges two tables of neutrino rates (of type global_class::nurate_type).
!!
!! Parameter r is a flag with the following meaning:
!!
!!

!!
Explanation of the flag "r"

!!
 r mode     Behavior
!!
 1          Values of y replace corresponding values of x
!!
 2          Values of x replace corresponding values of y
!!
 other      Both values are stored one after the other\
!!

!!
!! @remark At the moment, this function is only called with \f$ r=0 \f$
!!         i.e., case "other".
!!
!! @see rrate_ms, network_init_module::network_init
!!
!! \b Edited:
!!        - 11.01.14
!! .


!>
!! Merges two tables of rates (of type global_class::reactionrate_type).
!!
!! Parameter r is a flag with the following meaning:
!!
!!

!!
Evolution mode switches

!!
 r mode     Behavior
!!
 1          Values of y replace corresponding values of x
!!
 2          Values of x replace corresponding values of y
!!
 other      Both values are stored one after the other\
!!

!!
!! In case of theoretical weak rates that get merged, this function counts
!! the amount of rates that get replaced.
!!
!! @remark The function is used to merge the rate array with theoretical weak rates
!!         (with r=1) and neutrino rates (r=0).
!!
!!
!! @see nurate_ms, network_init_module::network_init
!!
!! \b Edited:
!!      - 17.02.14
!!      - 27.01.21, MR - introduced "rate_out" instead of writing directly to rrate
!!      - 04.08.22, MR - removed hardcoded " ffn" flag and replaced it with "rrs_twr"
!! .


!> Wrapper around the quicksort subroutine
!!
!! This subroutine is able to replace rates that appear with
!! multiple entries in the REACLIB (e.g., because it has a resonance)
!! with a tabulated rate. In debug mode, the file debug_tabln.dat
!! is written to debug this subroutine.
!!
!! @see qsort
!!
!! @author D. Martin
!!
!! \b Edited:
!!     - 15.04.15
!!     - 07.06.17
!!     - 04.08.22, MR: removed hardcoded "tabl" flag and replaced it with "rrs_tabl"
!!     - 05.08.22, MR: fixed bug and gave a new array as output (out_array)
!! .


!> Modified quicksort algorithm
!!
!! A quicksort is a recursive sorting algorithm. An illustration of it is shown
!! in the following (Source en.wikipedia):
!! @image html https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Illustration of the quicksort" width=300
!! In this gif, the red indicated number is the so called pivot-element.
!!
!! @see [Rosettacode](http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran),
!!      rateSortKey, rrate_qs_replace
!!
!! \b Edited:
!!       -  15.04.15
!!       -  25.4.19, M.R.
!! .


!> Close files and finalize this module
!!
!! This subroutine closes the debug file "debug_tabln.dat"
!!
!! @author: Moritz Reichert
!!
!! \b Edited:
!!     - 07.06.17
!! .


!> Sorts chapter one of the rate array
!!
!! The sorting is based on the second nucleus in the rate array.
!!
!! ### Example
!!

!! Rate 1: cl34 (Z=17) ->  s34 (Z=16)
!! Rate 2: cl36 (Z=17) -> ar36 (Z=18)
!! Rate 3: cl36 (Z=17) ->  s36 (Z=16)
!! Rate 4: cl38 (Z=17) -> ar38 (Z=18)
!!

!! will switch the order of the rates to:
!!

!! Rate 1: cl34 (Z=17) ->  s34 (Z=16)
!! Rate 3: cl36 (Z=17) ->  s36 (Z=16)
!! Rate 2: cl36 (Z=17) -> ar36 (Z=18)
!! Rate 4: cl38 (Z=17) -> ar38 (Z=18)
!!

!! In case the sunet is ordered by proton number.
!!
!! @todo Expand and change this subroutine
!!
!! @warning This subroutine assumes a certain ordering of the
!!          sunet!


!> Bubblesort of array.
!!
!! This subroutine performs a bubblesort of an array. See the following
!! illustration (from wikipedia):
!! @image html https://upload.wikimedia.org/wikipedia/commons/c/c8/Bubble-sort-example-300px.gif "Illustration of a bubblesort" width=300
!! The subroutine is able to run in 2 modes,
!! - mode 0 : Ascending order
!! - mode 1 : Descending order
!! .
!! Furthermore, a second array can be given which will return the indices of
!! the changes within the first array.
!!
!! @see reorder, tw_rate_module::readweak_logft
!!
!! @author M. Reichert


!> Quicksort of array.
!!
!! This subroutine performs a quicksort of an array.
!! A quicksort is a recursive sorting algorithm. An illustration of it is shown
!! in the following (Source en.wikipedia):
!! @image html https://upload.wikimedia.org/wikipedia/commons/6/6a/Sorting_quicksort_anim.gif "Illustration of the quicksort" width=300
!! In this gif, the red indicated number is the so called pivot-element.
!! In contrast to \ref QSort, this subroutine is able to sort an array that is not a derived type and comes in form of
!! an array of doubles.
!! The subroutine is able to run in 2 modes,
!! - mode 0 : Ascending order
!! - mode 1 : Descending order
!! .
!! Furthermore, a second array can be given which will return the indices of
!! the changes within the first array.
!!
!! @see [Rosettacode](http://rosettacode.org/wiki/Sorting_algorithms/Quicksort#Fortran),
!!
!! @see reorder
!!
!! @author M. Reichert
!! @date 08.05.24


!> Takes an array and an array with indices to reorder the first array
!!
!! @see bubblesort, tw_rate_module::readweak_logft
!!
!! @author M. Reichert


!> Takes an array and an array with indices to reorder the first array
!!
!! Same as \ref reorder, but for integer arrays.
!!
!! @see bubblesort, tw_rate_module::readweak_logft
!!
!! @author M. Reichert


!>
!! Returns a key for sorting a rate array by concatenating isotope indices.
!!
!! Rule: order of elements depends on chapter. \n
!! The here produced string is compared for
!! being lexically greater or smaller in \ref qsort.
!!
!! @returns String with that determines the ordering of an isotope
!!
!! @see qsort
!!
!! \b Edited:
!!      - 15.04.15
!!      - 28.07.22, MR: Introduced new chapters
!! .


!>
!! Initialize nuflux module
!!
!! Calculates the Schwarzschild radius
!! and opens debug files and writes headers to them.
!! Furthermore it reads the neutrino reactions
!!
!! \b Edited:
!!    - 12.04.17
!!    - 25.01.21, MR - Moved the reading of the nu-rates to this place
!!  .


!>
!! Determines neutrino flux for current time (in units of cm^-2 s^-1).
!!
!! The flux is hereby either based on an analytic forumlas of the
!! neutrino luminosities and energies or on the trajectory file.
!!
!! @note In previous versions, also GR corrections were applied here, c.f.,
!! [Otsuki et al. 2000](https://ui.adsabs.harvard.edu/abs/2000ApJ...533..424O/abstract).
!!
!! \b Edited:
!!         - 11.01.14
!!         - MR 18.12.20
!! .


!> Calculates the cross section times the neutrino flux.
!!
!! This subroutine calculates the cross section times
!! the neutrino flux for a given neutrino reaction. Here,
!! the different neutrino types are distinguised.
!! 1: CC reaction (electron neutrino)
!! 2: CC reaction (anti-electron neutrino)
!! 3: NC reaction (all neutrinos)
!! 4: NC reaction (all anti-neutrinos)
!! .
!!
!! \b Edited:
!!        - 12.02.23 MR: Moved this from the jacobian class here
!! .


!>
!! Interpolate neutrino cross sections
!!
!! The subroutine lin-log interpolates the neutrino cross sections
!! depending on the neutrino temperature (stored in \ref tempnu).
!! For this it also uses the temperature grid \ref sigtempnu.
!! The final interpolated cross sections are stored in
!! \ref global_class::nurate\%rcs.
!!
!! @returns reaction cross sections for neutrino reactions into
!! \ref global_class::nurate\%rcs.
!!
!! \b Edited:
!!       - 13.01.14
!!       - 27.01.21
!!       - 19.07.22, M.R., removed small bug when at the interpolation boundary
!!       - 22.02.23, M.R., removed possible division by zero
!! .


!>
!! @brief Calculates (anti-) neutrino temperatures.
!!
!! The determination depends on the \ref parameter_class::neutrino_mode.
!! In case of an analytic expression for the neutrino temperatures (or energies)
!! it evaluates and parses a string. In case of a trajectory determining the
!! temperatures, this subroutine lin-log interpolates (inside, e.g.,
!! \ref ztime and \ref tnue). The subroutine also
!! ensures that the temperature does not become negative.
!!
!! \b Edited:
!!         - 13.01.14
!!         - MR: 18.12.20
!! .


!> Write the amount of individual reactions to the out
!!
!! The rates are always counted, for a certain verbose level they
!! are also printed to the OUT file
!!
!! @author M. Reichert
!! @date 27.01.21


!> Read neutrino reactions and fill the global_class::nurate array
!!
!! Depending on the nuflag parameter, different files will be opened and
!! read.
!!
!! @see readnucs
!!
!! \b Edited:
!!     -  23.01.21, MR - Moved it to this subroutine from network_init_module
!!  .


!> Read the reactions from a file in binary format
!!
!! This subroutine reads neutrino reactions and all
!! neutrino data from a binary file. This file has
!! to be previously prepared.
!!
!! @author M. Reichert
!! @date 21.06.2023


!> Write the reactions to a file in binary format
!!
!! This subroutine writes the reactions to a file in binary format.
!! This is done for preparing a folder with all reaction rates that
!! can be read in later on from many tracers.
!!
!! @author M. Reichert
!! @date 21.06.2023


!> Read the reactions from a file in the format of Sieverding et al 2018
!!
!! This subroutine reads the reactions from a file in the format
!! of [Sieverding et al 2018](https://ui.adsabs.harvard.edu/abs/2018ApJ...865..143S/abstract).
!! The file contains the reaction rates for charged and neutral
!! current neutrino reactions on heavy nuclei.
!! An example of the file looks like:
!! \file{
!!  000  Z = 2    A = 4   channels:  6
!!  002  1.099778E-03  7.960983E-03  2.308440E-02  1.163089E-01  5.736357E-01  2.100826E+00  6.820661E+00
!!  023  1.145175E-03  7.713879E-03  2.115540E-02  9.541441E-02  4.077819E-01  1.295820E+00  3.633845E+00
!!  ...
!! }
!! Here the first line contains the atomic number, the mass number and the amount of reactions.
!! The second line contains the channel specified in the channel file (see \ref read_channels)
!! followed by the reaction rates. The reaction rates are tabulated on a (neutrino) temperature grid
!! of Tnu (MeV) = 2.800 3.500 4.000 5.000 6.400 8.000 10.000.
!!
!! @author M. Reichert
!! @date 12.02.2023


!> This function returns a string with the reaction information
!!
!! The string starts with the kind of reaction
!! (1: cc with nue, 2: cc wit anue, 3: nc with nux, 4: nc with anux)
!! followed by the reactant and the products seperated by "=>".
!!
!! The function is only used for debugging purposes.
!!
!! @author Moritz Reichert
!! @date 12.02.2023


!> Read the channels from a file in the format of Sieverding et al 2018
!!
!! This subroutine reads in the channels from a file in the format of
!! Sieverding et al 2018. The file is read in line by line and the
!! information is stored in the global variable nuchannels.
!!
!! An example of the file looks like:
!! \file{
!! id    type     particle emission
!! \n
!! 001 nue    (cc)  0p 0n 0a
!! 002 nue    (cc)  1p 0n 0a
!! 003 nue    (cc)  0p 1n 0a
!! 004 nue    (cc)  0p 0n 1a
!! 005 nue    (cc)  2p 0n 0a
!! ...}
!! where the type "cc" stands for charged current and "nc" for neutral
!! current. The particle emission is the number of particles emitted
!! in the reaction. The first line is a header line and is ignored.
!!
!! @see [Sieverding et al 2018](https://iopscience.iop.org/article/10.3847/1538-4357/aadd48),
!!      \ref read_reactions_sieverding
!!
!! @author M. Reichert
!! @date 12.02.2023


!>
!! Reads neutrino-nuclei reaction file
!!
!! This subroutine reads in neutrino reactions depending on the
!! input typ. The type of the call is dependent on parameter_class::nuflag.
!! For nuflag = 1, this subroutine is called with typ 1 only, for e.g.,
!! nuflag = 2 it is called 3 times with types 1, 2, and 3.
!!
!!

!!
typ translation

!!
 typ  Example filename   Meaning
!!
 1    _neunucleons.dat_  Reads (anti-)neutrino reactions on neutrons and protons
!!
 2    _neunuclei.dat_    Reads neutrino reactions on nuclei
!!
 3    _aneunuclei.dat_   Reads Antineutrino reactions on nuclei
!!

!! The file _neunucleons.dat_ looks like:
!! \file{
!! n    p                             nen
!! 12.37     18.61     23.85     36.32     58.26     89.82    139.06
!! p    n                            nebp
!! 6.96     11.14     14.63     22.82     36.66     55.40     82.45  }
!!
!! The file _neunuclei.dat_:
!!
!! \file{
!! Cross sections for (nue,e-) reactions on nuclei for alpha=0.0
!! \=============================================================
!! \n
!!   T [MeV]              2.8          3.5          4.0         5.0          6.4          8.0          10.0
!! \n
!!  N =  2  Z =  2    (4He  )
!!  Integrated           0.00         0.01         0.03         0.15         0.71         2.50         7.91
!! ... }
!!
!! and the file _aneunuclei.dat_:
!!
!! \file{
!! T [MeV]              2.8          3.5          4.0         5.0          6.4          8.0          10.0
!! \n
!! N =  2  Z =  2    (4He  )
!! Integrated           0.00         0.01         0.02         0.09         0.41         1.29         3.64
!! ...}
!!
!!
!! @returns Array of neutrino reactions, depending on input typ either
!!          global_class::nurate (typ 1), global_class::nunuc (typ 2),
!!          or global_class::anunuc (typ 3).
!!
!! @see [Bruenn et al. 2002](https://arxiv.org/pdf/astro-ph/0211404.pdf),
!!      [Froehlich et al. 2006](https://ui.adsabs.harvard.edu/abs/2006ApJ...637..415F/abstract)
!!      [Langanke & Kolbe 2001](https://ui.adsabs.harvard.edu/abs/2001ADNDT..79..293L/abstract)
!!
!! \b Edited:
!!      - 12.01.14
!!      - 23.01.21, MR - moved it from network_init_module
!!
!! @remark This routine is used to read the reactions on nucleons only (typ 1).
!! .


!> Routine to merge neutrino rates into rrate array
!!
!! This subroutine merges the neutrino rates into a larger rate
!! array via a mergesort (see \ref mergesort_module::rrate_ms)
!!
!! @remark This used to be done after reading chapter 2 in the reaclib
!!         while the reaclib file is still open. Now it is done
!!         afterwards which may be not as efficient, but more clear.
!!
!! @author M. Reichert
!! @date 27.01.21


!> Initialize the screening module
!!
!! Allocates screening correction arrays.
!!
!! @author M. Reichert
!! @date 26.07.22


!> @brief This function calculates the screening coefficients hv.
!!
!! It serves as interface between the subroutine \ref screening and
!! the \ref jacobian_class.
!!
!! @author Urs Frischknecht
!!
!! \b Edited:
!!       - 12.01.14
!!       - 26.07.22, MR: Made hv, htv, and hpv module variables.
!!       - 28.07.22, MR: Introduced new chapters
!! .


!> Free energy according to parametrization of Kravchuk and Yakovlev
!!
!! This function calculates the free energy of a one-component plasma
!! according to equation 19 of Kravchuk & Yakovlev (2014).
!!
!! @see [Kravchuk & Yakovlev 2014](https://ui.adsabs.harvard.edu/abs/2014PhRvC..89a5802K/abstract)
!!
!! @author M. Reichert
!! @date 03.04.2023


!> Interface for the screening.
!!
!! This subroutine is an interface for the different
!! screening prescriptions.
!!
!! @author M. Reichert
!! @date 03.04.2023


!> Screening function according to Kravchuk & Yakovlev (2014)
!!
!! This function calculates the screening function according to
!! equation 62 of Kravchuk & Yakovlev (2014) using the "combined" model.
!!
!! @note  This function is in principle only valid for the strong
!!        screening regime does however not deviate too much for the weak
!!        screening as well.
!!
!! @author M. Reichert
!! @date 03.04.2023


!> Initialize nucstuff class
!!
!! Allocate the partition function array.
!!
!! @author M. Reichert
!! @date 26.07.22


!> Function to decide whether a given isotope is stable or not
!!
!! ### Example
!!~~~~~~~~~~~~~~.f90
!! b = is_stable(2,2)
!!~~~~~~~~~~~~~~
!! b will be true.
!!
!! @author M. Reichert


!>
!! @brief Calculates partition function
!!
!! The partition functions are interpolated from
!! the temperature grid (stored in \ref t9_data, read from the winvn in
!! \ref benam_class::get_nuclear_properties (index 1-24) and the htpf file
!! in \ref benam_class::read_htpf (index 25-72)) and the tabulated
!! partition functions \ref global_class::isotope\%part_func.
!!
!! \b Edited:
!!       - MR : 19.01.2021 - set ntgp to 72
!! .


!>
!! A helper to compute powers of temperature used in the reaction rates
!!
!! The reaclib reaction rates are calculated with the following fit formula:
!! \f[
!! \lambda = \mathrm{exp} \left[ a_0 + \sum \limits _{i=1} ^5 a_i T_9 ^{\frac{2i-5}{3}} a_6 \, \mathrm{ln} T_9 \right].
!! \f]
!! The helper array \ref t9_pow stores the powers of the temperature used for this calculation
!! (starting with index 2 for i=1, index 1 stores unity). The \ref t9_pow array is after the call given
!! by \f[ \mathrm{t9\_pow} = [ T_9 ^{0}, T_9 ^{-1}, T_9 ^{-1/3}, T_9 ^{1/3}, T_9 ^{1},
!! T_9 ^{5/3}, \log T_9, T_9 ^{7/3}, T_9 ^{9/3} ] \f]
!!
!! @returns Array (\ref t9_pow) that contains the temperature with different exponents
!!
!! \b Edited:
!!       - MR : 19.01.2021 - renamed subroutine and removed rho as input
!! .


!>
!! Computes the electron fraction
!!
!! The electron fraction is defined as:
!! \f[ Y_e = \sum Z(i) \cdot Y(i) \f],
!! with the number of protons Z and the abundance Y
!! of each isotope i.
!!
!! \b Edited:
!!       - MR : 19.01.2021
!! .


!> Total mass used to check the mass conservation
!!
!! This subroutine calculates
!! \f[ \mathrm{m\_tot} = \sum A_i \cdot Y_i \f]
!!
!! @note This subroutine used to calculate the neutron excess as well
!!       and it can be commented in again.
!!
!! \b Edited:
!!      - MR : 20.01.21 - Removed neutron excess
!! .


!> Analyze a string and split it with delimiter ";"
!!
!! This routine is used to analyze the parameters
!! parameter_class::detailed_balance_src_ignore, parameter_class::detailed_balance_src_q_reac,
!! parameter_class::detailed_balance_src_q_winvn. It takes a string and splits it
!! if there is a ";" in it. Afterwards it returns an array with the splitted strings.
!!
!! ### Example
!!~~~~~~~~~~~~~~.f90
!! a = "rath; pkrF;abc"
!! b = "ths8"
!! call analyze_src_string(a,c,d)
!! call analyze_src_string(b,e,f)
!!~~~~~~~~~~~~~~
!! Afterwards, c will be an array containing (/"rath", "pkrF", " abc"/), d will be 3,
!! e will be (/"ths8"/), and f will be 1.
!!
!! @author M. Reichert
!! @date 04.08.22


!> Write the header of the standard output (usually _OUT_)
!!
!! This subroutine writes the first header of the out file.
!! This looks e.g., like:
!! \file{
!! WinNet - Nuclear reaction network
!! \n
!! \n
!! Option                                   :      Value     Unit
!! \-------------------------------------------------------------- }
!!
!! \b Edited:
!!   - 08.08.22, M.R: Implemented git version
!! .
!!
!! @author Moritz Reichert
!! @date 27.01.21


!> Write the final stats for rate creation
!!
!! This subroutine writes the final stats when
!! only creating a folder with prepared binary data.
!!
!! @author M. Reichert
!! @date 22.07.23


!> Write data to the standard output (usually _OUT_)
!!
!! This subroutine formats the output to a uniform design.
!! an example line is:
!! \file{
!! Network size                             :       6545         }
!!
!! @author Moritz Reichert
!! @date 27.01.21


!> Converts a string to an integer
!!
!! If the string is not a valid integer, an error message is raised.
!!
!! @author Moritz Reichert
!! @date 01.06.22


!> Converts a string to a float
!!
!! If the string is not a valid integer, an error message is raised.
!!
!! @author Moritz Reichert
!! @date 01.06.22


!>
!! Converts a given real to a string with format "(1pE10.2)".
!!
!! This function is often used in error messages as it is useful to convert
!! a number to a string in the message directly
!!
!! @author  Moritz Reichert


!>
!! Converts a given integer to a string.
!!
!! This function is often used in error messages as it is useful to convert
!! a number to a string in the message directly.
!!
!! @author  Moritz Reichert


!>
!! Raise a exception with a given error message
!!
!! This subroutine is called when some inconsistency occured. It prints
!! a message to the OUT file that an error occured and prints the rest to the
!! standard error unit (usually file ERR in WinNet). This subroutine
!! also terminates the program.
!!
!! @author  Moritz Reichert


!> Initialize external beta decay rates.
!!
!! This subroutine counts and reads the rates into the array
!! \ref beta_decays.
!!
!! @author M. Reichert
!! @date 25.01.21


!> Merge external beta decays into the larger rate array.
!!
!! The return value of this routine will be a larger rate array
!! and a new length
!!
!! @author M. Reichert
!! @date 25.01.21


!> Subroutine to remove weak rates from the beta decay rate array
!!
!! This subroutine ensures that \ref parameter_class::beta_decay_src_ignore
!! is working. It removes all reactions from the array \ref beta_pn
!! that are listed in \ref parameter_class::beta_decay_src_ignore.
!!
!! @author M. Reichert


!> Count the amount of external beta decays.
!!
!! After this routine has been called, nbeta will contain the amount of
!! external beta decay rates.
!!
!! @author M. Reichert
!! @date 25.01.21


!> Remove beta decays from the rate array
!!
!! This routine removes beta decays in case that they exist in
!! another format ( see parameter_class::use_beta_decay_file ).
!!
!! @author Moritz Reichert


!> Convert \ref beta_pn_type to \ref reactionrate_type
!!
!! Creates a reactionrate_type array from the beta_pn_type array.
!! Rates with Pn of 0 will not result in an extra rate.
!!
!! @author Moritz Reichert
!! @date 28.02.2023


!>
!! Reads beta decays from a separate file.
!!
!! This routine is thought to read beta decays in a different format than reaclib.
!! An advantage of this is that we can implement more than the P2n channel.
!! The new format allows beta delayed neutrons up to 10 neutrons that become more
!! important close to stability.
!! An example input file could look like:
!!\file{
!! ca73    6.200000e-04
!! 0.0000   0.0100   0.0200   0.0100   0.2800   0.0800   0.4000   0.0700   0.1100   0.0100   0.0100 }
!! which will replace the decay of ca73 with a half life of 6.2e-04s and the listet Pn probabilities.
!! Additionally, the average Q-Value and the average neutrino Q-Value can be given optionally in the first line.
!! In this case an entry could look like:
!! ca73    1.268195e-03  2.443690e+01  9.034672e+00
!! 0.0030   0.0000   0.0010   0.0000   0.0020   0.9950   0.0000   0.0000   0.0000   0.0000   0.0000    }
!! where the first line gives the name of the parent nucleus, the half life, the average Q-Value and the
!! average neutrino Q-Value.
!!
!! @author Moritz Reichert
!!
!! \b Edited:
!!         - 20.05.19
!! .


!> Initialize alpha decay rates.
!!
!! This subroutine counts and reads the rates into the array
!! \ref beta_decays.
!!
!! @author M. Reichert
!! @date 25.01.21


!> Creates a file with the decays
!!
!! This file is created for verbose_levels greater than 2. An example
!! could look like
!! \file{
!!  Alpha decay rates that additionally have been added
!! po181 =>   he4 + pb177  T_1/2: 1.49E-09 s;  a0: 2.00E+01  Qa: 1.02E+01
!! po182 =>   he4 + pb178  T_1/2: 3.89E-09 s;  a0: 1.90E+01  Qa: 9.56E+00
!! ..
!! }
!! @author M. Reichert
!! @date 10.03.23


!>
!! @brief Return a string to represent a given reaction
!!
!! This routine is useful for error messages in case
!! a rate is not working as intented and is used for
!! verbose output only.
!!
!! ### Example
!! For rrate(i) being the alpha-decay of po181
!! ~~~~~~~~~~~.f90
!! a = reaction_string(rrate(i))
!! ~~~~~~~~~~~
!! will return a="po181 =>   he4 + pb177  T_1/2: 1.49E-09 s;  a0: 2.00E+01  Qa: 1.02E+01".
!!
!! @author Moritz Reichert


!> Merge alpha decays into the larger rate array.
!!
!! The return value of this routine will be a larger rate array
!! and a new length
!!
!! @author M. Reichert
!! @date 25.01.21


!> Merge reaclib rates and alpha decays into one array.
!!
!! Hereby the rates can be taken as addition or also replace the reaclib rates.
!!
!! @author M. Reichert
!! @date 25.01.21


!> Count the amount of possible alpha decays
!!
!! Check which isotopes between \ref alpha_decay_zmin and \ref alpha_decay_zmax should
!! have an alpha decay.
!!
!! @author M. Reichert
!! @date 10.03.23


!> Read the alpha decays
!!
!! All isotopes between \ref alpha_decay_zmin and \ref alpha_decay_zmax should
!! have an alpha decay. This subroutine reads the file \ref alpha_decay_file
!! and creates the alpha decay rate array.
!! An example of the file could look like:
!! \file{
!! sb103   7.84058e+10
!! sb104   4.29655e+05
!! sb105   1.37511e+10
!! sb106   1.03780e+17
!! te103   8.30806e+02
!! ...
!! }
!!
!! @author M. Reichert
!! @date 14.03.23


!>
!! Initialise flow subroutine
!!
!! This subroutine counts the number of possible flows
!! and allocates the \ref flows array.
!!
!! \b Edited:
!!          - 11.01.14
!!          - 03.04.18, M. Jacobi


!>
!! Flow calculation from jacobian. It is calculated with the help of the Jacobian.
!! \f[
!! F_{ij} = |(1/h - J_{ij}) \times Y_i - (1/h - J_{ji}) \times Y_j|
!! \f]
!!
!! @note Using the jacobian directly has the advantage
!!       that the flow will be correct if the calculation
!!       is correct. In previous versions, the flow
!!       was not calculated by using the jacobian.
!!
!! \b Edited:
!!          - 03.04.18, M. Jacobi
!! .


!> Bring flows to correct format
!!
!! Make the flows positive and swap ingoing neutron and proton numbers
!! in case of negative flows.


!>
!! Output reaction flows to a file
!!
!! An example of this file may look like:
!!\file{
!! time    temp    dens
!! 1.03895957612263E-01   7.19136097013393E+00   1.40977753502083E+06
!!  nin     zin     yin    nout    zout    yout    flow
!! 2   1   4.81807892321990E-08   1   1   2.13994533749120E-06   0.00000000000000E+00
!! 1   2   1.26489216252989E-09   1   1   2.13994533749120E-06   0.00000000000000E+00
!! 1   2   1.26489216252989E-09   2   1   4.81807892321990E-08   1.58426675189734E-10
!! 4   2   9.86495465952053E-13   3   3   2.15833022688002E-11   8.53665754802155E-13
!! ...}
!!
!! \b Edited:
!!         - 11.01.14
!!         - 03.04.18, M. Jacobi
!! .


!>
!! Nuclear heating initialization routine
!!
!! This subroutine creates some files (e.g., debug_engen.dat_) and
!! prepares the header for the _engen.dat_ file
!!
!! \b Edited:
!!    - MR: 20.01.21 - Gave toplist file a header
!!    - MR: 07.05.24 - Removed toplist and moved it to analysis module
!! .


!> Initialize the entrop and temperature for the heating


!> Reset the qdot variable.
!!
!! This is called by the Jacobian init whenever recalculating the
!! jacobian.
!!
!! @author M. Reichert


!< Calculate the energy radiated away by neutrinos or added to the system
!!
!! This subroutine calculates the energy radiated away by neutrinos or added to the system
!! and saves it in the variable qdot.
!! The fraction of energy is either set by a user defined input file (\ref neutrino_loss_file),
!! by the beta decay file (\ref beta_decay_file),
!! by the ffn_type rates (\ref weak_rates_file),
!! or by a user defined variable (\ref heating_frac).
!!
!! @author M. Reichert
!! @date 02.04.2023


!> Output the heating fractions to a debug file
!!
!! This subroutine outputs the heating fractions to a debug file. This is
!! useful for debugging purposes. The file is called debug_heating_nufrac.dat
!! and is located in the output directory. An example could look like
!! \file{
!! Group     Isotope      Source     Nu_frac     Q_value
!!     1           n        wc12     0.40000     0.78230
!!     1           t        wc12     0.40000     0.01860
!!     1         he3          ec     0.40000    -0.01900
!!     1         he6        wc12     0.55394     3.50510
!!     1         li9        wc12     0.45403    13.60600
!!...}
!!
!! @author M. Reichert
!! @date   30.03.2023


!>
!! Modifies the temperature and entropy to account for nuclear heating
!!
!! The temperature/entropy is solved (explicitely) in the same Newton-Raphson
!! scheme as used for the abundances in e.g.,
!! \ref timestep_module::advance_implicit_euler and
!! \ref timestep_module::advance_gear.
!!
!! There are 3 different heating modes:
!!

!!
Heating modes

!!
 Value      Evolved variable        Additional source term
!!
 0          No heating              -
!!
 1          Entropy                 adiabatic
!!
 2          Temperature             trajectory
!!
 3          Temperature             adiabatic
!!

!!
!! @author M. Reichert
!! @date 10.02.23
!! .


!>
!! Modifies the temperature to account for nuclear heating
!!
!! Here, an additional equation is calculated for the temperature.
!! The temperature is calculated by:
!! \f[ \dot{T}_\mathrm{nuc} = \frac{1}{c_v} \sum_i M_i dY_i   \f]
!! with the symbols defined as:
!! <pre style="line-height:.5">
!!  - M_i     : mass excess [MeV] (see \ref global_class::isotope\%mass_exc)
!!  - cv      : Specific heat capacity at constant volume
!! .
!! </pre>
!!
!! For heating_mode 2, the temperature is calculated by:
!! \f[ \dot{T}_\mathrm{nuc} = \dot{T}_\mathrm{nuc} + \dot{T}_\mathrm{tr} \f]
!! where \f$\dot{T}_\mathrm{tr}\f$ is the temperature change of the external conditions,
!! i.e., the trajectory or the analytic equation.
!! For heating_mode 3, the temperature is calculated by:
!! \f[ \dot{T}_\mathrm{nuc} = \dot{T}_\mathrm{nuc} + \dot{T}_\mathrm{ad} \f]
!! where \f$\dot{T}_\mathrm{ad}\f$ is the temperature change assuming adiabatic conditions.
!!
!! @author M. Reichert
!! @date 10.02.23
!!
!! @see [Lippuner & Roberts 2017](https://ui.adsabs.harvard.edu/abs/2017ApJS..233...18L/abstract),
!!      [XNet](https://github.com/starkiller-astro/XNet)
!! .


!>
!! Modifies the temperature and ent_p to account for nuclear heating
!!
!! Here, an additional equation is calculated for the entropy.
!! The entropy is calculated by:
!! \f[ E_\mathrm{gen} = \sum_i (m_i c^2 + \mu_i + Z_i \mu_e) dY_i  -\Delta q \f]
!! , where \f$ \mu_i \f$ is given by
!! \f[
!! \mu_i = -k_B T \log \left( \frac{g_i G_i}{\rho N_A Y_i}
!!          \left(\frac{2 \pi m_ic^2 k_B T}{h^2 c^2}\right)^{1.5} \right)
!! \f]
!! and the nuclear mass defined by the atomic mass excess:
!! \f[ m_ic^2 = M_i +Am_uc^2 - Z_i m_e c^2 .\f]
!! The symbols are defined as:
!! <pre style="line-height:.5">
!!  - M_i         : mass excess [MeV] (see \ref global_class::isotope\%mass_exc)
!!  - m_ic^2      : nuclear mass (see \ref global_class::isotope\%mass [MeV])
!!  - kB          : Boltzman constant (see \ref parameter_class::unit\%k_mev)
!!  - g_i         : 2 * spin + 1 ( see \ref global_class::isotope\%spin )
!!  - G_i         : normalized partition function of isotope i
!!  - rho         : Density [cgs]
!!  - \f$mu_e\f$  : Electron chemical potential
!!  - Z_i         : Proton number of isotope i
!!  - Navo        : Avogadro constant (see \ref parameter_class::unit\%n_a)
!!  - Y_i         : Abundance [mol/g]
!!  - h           : Planck constant [MeV*s] (see \ref parameter_class::unit\%h_mevs)
!!  - c           : Speed of light [cm/s] (see \ref parameter_class::unit\%clight)
!! .
!! </pre>
!! The entropy is converted to a temperature via the equation of state at the
!! end of this subroutine. Furthermore, \f$ \Delta q \f$ is the energy loss due
!! neutrinos that won't thermalize (\ref parameter_class::heating_frac ,
!! \ref beta_decay_file , \ref neutrino_loss_file).
!!
!! @see
!! [Freiburghaus et al. 1999, Eq. 2](https://ui.adsabs.harvard.edu/abs/1999ApJ...525L.121F/abstract)
!! [Mueller 1986](https://ui.adsabs.harvard.edu/abs/1986A%26A...162..103M/abstract)
!!
!! @author O. Korobkin
!!
!! \b Edited:
!!    - MR: 20.01.21 - Separated top contributor to independent subroutine
!! .


!>
!! Output data related to nuclear heating
!!
!! For example the energy generation in the file _engen.dat_
!!

!!

!! # 1:iteration 2:time[s] 3:timestep[s] 4:E_gen(tot) [erg/g] 5:E_gen(t) [erg/(g*s )] 6:E_gen(t) [MeV/(baryon*s)]
!!         0  0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
!!         0  2.000000000000000E-12  2.000000000000000E-12  2.100942703338183E+08  5.252356611052194E+19  5.443684205322992E+01
!!         1  6.000000000000000E-12  4.000000000000000E-12  6.302695988823750E+08  5.252191701420075E+19  5.443513288527704E+01
!! ...

!!
!! \b Edited:
!!   - MR: 20.1.21  - Modified format of _toplist.dat_
!!   - MR: 07.5.24  - Removed _toplist.dat_ from here
!! .


!> @brief Initialize the hdf5 module
!!
!! Create the file and the datasets. Furthermore, initialize arrays.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> Initialize the flow output


!> Initialize neutrino loss/gain output


!>
!! Write neutrino gain and loss
!!
!! These values are stored in a separate group (called snapshots) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 12.04.23


!>
!! @brief Write the neutrino loss/gain into the hdf5 file
!!
!! These values are stored in a separate group (called nu_loss_gain) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 12.04.23


!> Initialize energy generation output


!>
!! @brief Subroutine to write the energy generation per reaction type
!!
!! @author Moritz Reichert
!! @date 22.03.21


!>
!! @brief Write energy generations and time into the hdf5 file
!!
!! These values are stored in a separate group (called energy) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 22.03.21


!> Extend the flow in the file
!! With every call a new group is created and the flows are written in this
!! group. The group is named after the calls (the third call is then located
!! in flows/3)


!> Initialize the snapshot hdf5 group.
!!
!! This subroutine creates a snapshot group and writes mass number
!! proton number and neutron number into it. Furthermore, it creates a dataspace
!! for the abundances and the time. In addition a array that stores
!! the abundances is initialized. This array is used to create larger chunks
!! and reduce the IO when writing to the file on the cost of memory usage.


!> Initialize the tracked_nuclei hdf5 group.
!!
!! This subroutine creates a tracked_nuclei group and creates the dataspaces for
!! all included abundances and the time. Furthermore, it allocates a
!! array to store the abundances over several iterations.


!> Initialize the timescales hdf5 group.
!!
!! This subroutine creates a timescales group and creates the dataspaces for
!! all included timescales and the time.


!> @brief Write the units of the individual entries into the hdf5 file
!!
!! For example: \n
!! Temperature - GK\n
!! Entropy     - kB/nuc
!!
!! @note This subroutine is never used
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> Write final abundances into hdf5 file
!!
!! This routine writes the final abundances of all nuclei (group:finab/finab),
!! the final abundances summed over mass number (group:finab/finabsum),
!! and the final abundances summed over equal proton numbers (group:finab/finabelem).
!! These entries are similar to the ascii version the output (finabelem.dat,..)
!!
!! @author M. Reichert
!! @date  05.03.21


!> @brief Gets a dataset name and creates it
!!
!! Creates a 1d dataset in the hdf5 and returns its
!! dataset ID.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> @brief Gets a dataset name and creates an integer dataset
!!
!! Creates a 1d dataset in the hdf5 and returns its
!! dataset ID.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> @brief Create a hdf5 entry with constant values
!!
!! This is used for mass number, proton number, and
!! neutron number.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> @brief Create a hdf5 entry with constant values
!!
!! This is used for e.g., the flows
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> @brief Extend a previously created 1D - dataset
!!
!! The necessary input is the value and the
!! id of the dataset only.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> @brief Extend a previously created 1D integer - dataset
!!
!! The necessary input is the value and the
!! id of the dataset only.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!>
!! @brief Subroutine to write the average timescales (1/s) into the hdf5
!!
!! @author Moritz Reichert
!! @date 5.02.21


!>
!! @brief Write average timescales and time into the hdf5 file
!!
!! These values are stored in a separate group (called timescales) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 5.02.21


!>
!! @brief Write tracked abundances and time into the hdf5 file
!!
!! These values are stored in a separate group (called tracked_nuclei) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 5.02.21


!> Write the abundances of track nuclei into a file
!!
!! When this subroutine is called depends on the chunk size.
!!
!! @author Moritz Reichert
!! @date 09.02.21


!>
!! Write abundances and time into the hdf5 file
!!
!! These values are stored in a separate group (called snapshots) that is initialized
!! in \ref init_hdf5_module.
!!
!! @author Moritz Reichert
!! @date 5.02.21


!> Write the abundances of all nuclei into a file
!!
!! When this subroutine is called depends on the chunk size.
!!
!! @author Moritz Reichert
!! @date 09.02.21


!> @brief Extend the Y dataset for the net timestep.
!!
!! The dimension of this is given by global_class::net_size and the current
!! iteration \ref iter.
!!
!! @see extend_1d_dataset, extend_1d_int_dataset
!! @author Moritz Reichert
!! @date 28.01.21


!> Finalize the hdf5 module
!!
!! This subroutine closes all datasets, dataspaces, files
!! and other things.
!!
!! @author Moritz Reichert
!! @date 28.01.21


!> Shorthand for opening a new unformatted file for writing (output file)


!> Open an unformatted file for reading


!> Shorthand for opening a new file for writing (output file)
!!
!! This function is used to open a file in order
!! to write into it. It will also complain if it is
!! not possible.


!> Same for reading (input file)
!!
!! This function is used for read input files
!! and complain if it does not work.


!> Close an external file
!!
!! This function is used to close a file and
!! complain if it does not work.


!> Delete a file
!!
!! This function is used to delete a file. If the file does not
!! exist and raise_error is present, an error is raised.
!!
!! @author M. Reichert


!>
!! Initialize iteration variables
!!
!! Here, all necessary allocations are done. And
!! the initial abundance is written into the abundance
!! history array (\ref z(1,:)).
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Initialize dYdt component of the Nordsieck vector.
!!
!! Stores h * dYdt in the Nordsieck vector \ref z(2,:).
!!
!! @author D. Martin
!! @date   01.08.17


!> Revert a timestep
!!
!! This routine reverts the timestep of Gear
!! to the previous timestep.
!! It is used in case the result did not converge
!!
!! @see timestep_module::advance_gear
!!
!! @author M. Reichert


!>
!! Shifts tau vector and controls the current time
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Nordsieck vector-matrix product
!!
!! This calculates:
!! \f[
!! \vec{z}_{n+1}^{(0)} = \mathbf{A} \cdot \vec{z}_n
!! \f]
!! and stores the result in \ref z_new.
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Stepsize and order control to pepare the next step
!!
!! @author D. Martin
!! @date   01.08.17


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!!! Error functions
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!>
!! Calculate the errors for the current order
!!
!! The error is defined as:
!! \f[
!! \vec{E}_{n+1}(q) = -\frac{1}{\ell _1}\left[ 1+ \prod _{i=2}^{q}\left(
!! \frac{t_{n+1}-t_{n+1-i}}{t_{n}-t_{n+1-i}} \right) \right] ^{-1} \vec{e}_{n+1}
!! \f]
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Calculate the errors for the order (q-1)
!!
!! The error is defined as:
!! \f[
!! \vec{E}_{n+1}(q-1) = - \frac{\prod \limits _{i=1}^{q-1} \xi _i }
!!                       {\ell _1 (q-1)}  \frac{h^q \vec{y}_{n+1}^{(q)}}{q!}
!! \f]
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Calculate the errors for the order (q+1)
!!
!! The error is defined as:
!! \f[
!! \vec{E}_{n+1}(q+1) = \frac{-\xi_{q+1}(\vec{e}_{n+1}-Q_{n+1}\vec{e}_n) }
!!                      {(q+2)\ell _1 (q+1)\left[1+ \prod \limits_{i=2}^{q} \frac{t_{n+1}-t_{n+1-i}}
!!                      {t_n-t_{n+1-i}} \right] }
!! \f]
!!
!! @author D. Martin
!! @date   01.08.17


!> Calculate Helper function Q
!!
!! Q is defined as:
!! \f[
!! Q_{n+1} =\frac{C_{n+1}}{C_n}\left( \frac{h_{n+1}}{h_n}\right)^{q+1} \\
!! \f]
!!
!! @author D. Martin
!! @date   01.08.17


!> Calculate helper function C
!!
!! The function is defined as:
!! \f[
!! C_{n+1} = \frac{\prod \limits _{i=1}^{q} \xi _{i}}{(q+1)!}\left[1+ \prod
!!           \limits _{i=2}^{q} \frac{t_{n+1} - t_{n+1-i}}{t_n -t_{n+1-i}} \right].
!! \f]
!!
!! @author D. Martin
!! @date   01.08.17


!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!>
!! Adjusts the order, if possible and necessary.
!! This is done every qth step, or earlier in case the time
!! step was modified.
!!
!!
!! @author D. Martin
!! @date   01.08.17


!>
!! Linear interpolation in lin-log space.
!!
!! This routine assumes that the x and y arrays are given
!! in the form of {x_i, log(y_i)}.
!! An optional argument flin allows to control the return value:
!!  - if flin is absent: return exp(log(y)) = y;
!!  - if flin is present: return log(y).
!!
!! \b Edited:
!!       - 11.01.14
!! .