#!/bin/bash

NumberOfWorkingThreads=$((`nproc`-2))
CurWorkDir=`pwd`

function NoVerbosePrint {
   echo -ne "${1}"
}

function VerbosePrint {
   [[ ${VerboseOutput} ]] && NoVerbosePrint "${1}"
   [[ ${LogFile} ]] && echo -ne "${1}" >> ${LogFile}
}

function ScriptExit {
   case ${1} in
      0)
         VerbosePrint "Success!!!\n"
         exit ${1}
         ;;
      1)
         # Illegal option
         ;;
      2)
         NoVerbosePrint "\nRequested number of parallel jobs (${NumberOfWorkingThreads}) must be an integer in the range (1-`nproc`).\n" >&2
         ;;
      3)
         NoVerbosePrint "\nRequested number of parallel jobs (${NumberOfWorkingThreads}) is out of range (1-`nproc`).\n" >&2
         ;;
      4)
         NoVerbosePrint "\nYou have provided more than 1 (${#@}) input files.\n" >&2
         ;;
      5)
         NoVerbosePrint "\nMasses files where not found in folder ${find_dir}.\n" >&2
         ;;
      6)
         NoVerbosePrint "\nYou haven't given any input!!!\nExiting!!!\nRun Again the Program!!!\n" >&2
         ;;
      7)
         NoVerbosePrint "\nDirectory ${TalysWorkDir} doesn't exist and could not be created!!!\nExiting!!!\n" >&2
         ;;
      8)
         NoVerbosePrint "\nFile ${UserInputFileName} does not exist or is empty.\nPlease check the filename provided and run again\n" >&2
         ;;
      9)
         NoVerbosePrint "\nDirectory ${InputWorkDir} doesn't exist and could not be created!!!\nExiting!!!\n" >&2
         ;;
      10)
         NoVerbosePrint "\nDirectory ${LogDir} doesn't exist and could not be created!!!\nExiting!!!\n" >&2
         ;;
      11)
         NoVerbosePrint "\nPlease input at least one nucleus\nExiting!!!\n" >&2
         ;;
      12)
         NoVerbosePrint "\nPlease input at least one projectile\nExiting!!!\n" >&2
         ;;
      13)
         NoVerbosePrint "\nYou asked to run Talys but you have not given the energy values for the calculation!!!\nExiting!!!\n" >&2
         ;;
   esac
   NoVerbosePrint "\n" >&2
   print_usage >&2
   exit ${1}
}

function print_usage {
   cat << END_OF_HELP
Usage: `basename $0` [OPTION]... [InputFile]...
Run talys and talys related functions according to the [InputFile] provided.
NOTE: All actions will be processed in the Lab system

END_OF_HELP

   PreFlagSpaces=2
   DescriptionColumnStart=32

   PreFlagSpace=`printf "%${PreFlagSpaces}s"`
   NewLineSpace=`printf "%${DescriptionColumnStart}s"`

   for (( i = 0 ; i < ${#ShortOptions} ; i++ )) ; do
      LocalOption=${ShortOptions:$i:1}
      LocalLongOption=""
      PostFlagSpaces=$(( ${DescriptionColumnStart} - ${PreFlagSpaces} - 2 ))
      [[ "${LocalOption}" == ":" ]] && continue

      for LOpt in "${!LongOptions[@]}" ; do
         [[ "${LongOptions[$LOpt]}" != "${LocalOption}" ]] && continue
         LocalLongOption+=", --${LOpt}"
         [[ "${ShortOptions:$((i+1)):1}" == ":" ]] && LocalLongOption+="[ |=]value"
      done
      unset LOpt

      PostFlagSpaces=$(( ${PostFlagSpaces} - ${#LocalLongOption} ))
      PostFlagSpace=`printf "%${PostFlagSpaces}s"`

      echo -ne "${PreFlagSpace}-${LocalOption}"
      echo -ne "${LocalLongOption}"
      echo -ne "${PostFlagSpace}"
      echo -e "${OptionHelp[${LocalOption}]//\\n/\\n${NewLineSpace}}"

      unset LocalOption
      unset LocalLongOption
      unset PostFlagSpaces
      unset PostFlagSpace
   done
   echo ""

   unset PreFlagSpaces
   unset DescriptionColumnStart
   unset PreFlagSpace
   unset NewLineSpace
}

function Set_massesDir {
   find_dir="/usr/share/"
   find_dir="$(find ${find_dir} -iname "talys-*" -print 2>/dev/null | sort | tail -1)"
   [ -d ${find_dir} ] || find_dir="${HOME}"
   massesDir=$(find ${find_dir} \( -iname "ame2*" -or -iname "audi" \) -print -quit 2>/dev/null)
   [ -d "${massesDir}" ] && VerbosePrint "The masses files used for cm and/or chi2 calculations are located in folder ${massesDir}\n"
   [ -d "${massesDir}" ] || ScriptExit 5
   unset find_dir
}

function Set_cmFlag {
   Set_massesDir
   cmFlag=1
}

function SetTalysWorkDir {
   if [ ! ${TalysWorkDir} ] ; then
      NoVerbosePrint "TalysWorkDir is not defined.\n"
      read -p "Give full path of the folder for Talys calculations and data " TalysWorkDir
      [ ! ${TalysWorkDir} ] && ScriptExit 6
      NoVerbosePrint "Setting ${TalysWorkDir} as TalysWorkDir in bashrc\n"
      echo "export TalysWorkDir=${TalysWorkDir}" >> ~/.bashrc
   fi

   [ ! -d ${TalysWorkDir} ] && mkdir -p ${TalysWorkDir}
   [ ! -d ${TalysWorkDir}/data ] && mkdir -p ${TalysWorkDir}/data
   [ ! -d ${TalysWorkDir}/inputs ] && mkdir -p ${TalysWorkDir}/inputs
   [ ! -d ${TalysWorkDir} ] && ScriptExit 7
}

function CreateSampleInput {
   NoVerbosePrint "Making SampleInput in folder ${TalysWorkDir}/inputs\n"
   SampleInputFileName="${TalysWorkDir}/inputs/SampleInput"
   [ -f ${SampleInputFileName} ] && ( chmod 775 ${SampleInputFileName} ; rm -rf ${SampleInputFileName} )
   cat > ${SampleInputFileName} <<_EOF_
################################################################################
#####  Configuration section                                               #####
#####  Empty Talys Version means plain talys command will be executed      #####
#####  If Talys Version is given, command talys-<TalysVersion> must exist  #####
################################################################################
_EOF_
   for Option in ${ConfigOptions[@]} ; do
      echo "${ConfigOptionsSetText[${Option}]} : ${ConfigOptionsSettedValue[${Option}]}" >> ${SampleInputFileName}
   done
   cat >> ${SampleInputFileName} <<_EOF_

################################################################################
#####  Basic configuration of input file                                   #####
#####  Empty lines will be ignored, thus default values will be used       #####
#####  Keywords relativistic, filechannels and channels will be set to     #####
#####  n, y and y respectively anyhow!                                     #####
################################################################################
_EOF_
   for Option in ${InputFileOptions[@]} ; do
      echo "${InputFileOptionsSetText[${Option}]} : ${InputFileOptionsSettedValue[${Option}]}" >> ${SampleInputFileName}
   done
   cat >> ${SampleInputFileName} <<_EOF_

################################################################################
#####  Additional keywords to be added to the input file                   #####
#####  The following three formats are recognized                          #####
#####  1. keyword p1 p2 ...                                                #####
#####  2. keyword p1 <p2_value1 p2_value2 p2_value3 ...> p3 p4 ...         #####
#####  3. keyword p1 p2 <range p3Min p3Max p3step> p4 ...                  #####
#####  where pi is the ith parameter needed for the additional keyword     #####
################################################################################
##### Beginning of additional keywords

##### End of additional keywords
_EOF_
   unset Option
   chmod 444 ${SampleInputFileName}
   unset SampleInputFileName
   ScriptExit 0
}

function ReadInputFile {
# Bug when absolute path given...
   [ ! -s ${CurWorkDir}/${UserInputFileName} ] && [ ! -s ${UserInputFileName} ] && ScriptExit 8
   InputFileName=`basename "${UserInputFileName}"`
   InputWorkDir=${TalysWorkDir}/${InputFileName}
   if [ ! -d ${InputWorkDir} ] ; then 
      mkdir -p ${InputWorkDir}
      [ ! -d ${InputWorkDir} ] && ScriptExit 9
   fi
   LogDir=${InputWorkDir}/logs
   if [ ! -d ${LogDir} ] ; then 
      mkdir -p ${LogDir}
      [ ! -d ${LogDir} ] && ScriptExit 10
      InputRunNumber="0"
   else
      InputRunNumber=$(( `ls -art ${LogDir}/${InputFileName}*.log | tail -1 |  sed "s|.\+run\([0-9]\+\).*|\1|"` + 1 ))
   fi
   
   InputFile="${InputWorkDir}/${InputFileName}_run${InputRunNumber}"
   [ -s ${CurWorkDir}/${UserInputFileName} ] && cp -f ${CurWorkDir}/${UserInputFileName} ${InputFile} || cp -f ${UserInputFileName} ${InputFile}
   LogFile=${LogDir}/${InputFileName}_run${InputRunNumber}.$$.log
   unset LogDir

   VerbosePrint "Running $(basename $0) for input ${InputFileName}\n"
   VerbosePrint "################################################################################\n"
   VerbosePrint "Reading input file for run ${InputRunNumber}\n"

   for Option in ${ConfigOptions[@]} ; do
      ReadText=$(grep "`echo "${ConfigOptionsSetText[${Option}]}" | sed "s|\ |\ *|g"`" ${InputFile} | sed "s|.*:\ *\(.*\)|\1|" | sed "s|\ \+|\||g")
      case ${Option} in
         "RunTalysFlag")
            [ "${ReadText}" == "y" ] && RunTalysFlag=1
            ;;
         "TalysVersions")
            [ "${ReadText}" ] && IFS=' ' read -a  TalysVersions <<< ${ReadText} || TalysVersions=( "default" )
            ;;
         "RangesFlag")
            [ "${ReadText}" == "y" ] && RangesFlag=1
            ;;
         "ChiFlag")
            [ "${ReadText}" == "y" ] && ChiFlag=1 && Set_massesDir
            ;;
         "PartialRanges")
            [ "${ReadText}" ] && IFS=' ' read -a  PartialRanges <<< ${ReadText}
            ;;
         "Ratios")
            if [ "${ReadText}" ] ; then
               IFS='/' read -a  Ratios <<< ${ReadText}
               Ratios[0]=${Ratios[0]%?}
               Ratios[1]=${Ratios[1]#?}
               if [ ! ${#Ratios[@]} -eq 2 ] ; then
                  NoVerbosePrint "\nWarning: The ratio values in the input file are not correct and will be discarded!!!\n"
                  echo -ne "\nWarning: The ratio values in the input file are not correct and will be discarded!!!\n" >> ${LogFile}
                  unset Ratios
               fi
            fi
            ;;
         "ElAngDistFlag")
            [ "${ReadText}" == "y" ] && ElAngDistFlag=1
            ;;
      esac
      unset ReadText
      unset IFS
   done
   unset ConfigOptionsSetText
   unset ConfigOptionsSettedValue
   unset ConfigOptions

   for Option in ${InputFileOptions[@]} ; do
      ReadText=$(grep "`echo "${InputFileOptionsSetText[${Option}]}" | sed "s|\ |\ *|g"`" ${InputFile} | sed "s|.*:\ *\(.*\)|\1|" | xargs)
      case ${Option} in
         "Nuclei")
            if [ "${ReadText}" ] ; then
               IFS=' ' read -a  Nuclei <<< ${ReadText}
            else
               ScriptExit 11
            fi
            ;;
         "Projectiles")
            if [ "${ReadText}" ] ; then
               ConfiguredKeywords+=( "${InputFileOptionsKeywords[${Option}]}" )
               ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="${ReadText// /|}"
            else
               ScriptExit 12
            fi
            ;;
         "Energy")
            if [ "${ReadText}" ] ; then
               ConfiguredKeywords+=( "${InputFileOptionsKeywords[${Option}]}" )
               ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="${ReadText}"
            else
               [ ${RunTalysFlag} ] && ScriptExit 13
            fi
            ;;
         *)
            if [ "${ReadText}" ] ; then
               ConfiguredKeywords+=( "${InputFileOptionsKeywords[${Option}]}" )
               ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="${ReadText// /|}"
            fi
            ;;
      esac
      unset ReadText
      unset IFS
   done
   unset Option
   unset InputFileOptionsSetText
   unset InputFileOptionsSettedValue
   unset InputFileOptionsKeywords
   unset InputFileOptions

   ConfiguredKeywords+=("relativistic")
   ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="n"
   ConfiguredKeywords+=("filechannels")
   ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="y"
   ConfiguredKeywords+=("channels")
   ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="y"

   if [ ${ElAngDistFlag} ] ; then
      ConfiguredKeywords+=( "fileelastic" )
      ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="y"
      ConfiguredKeywords+=( "outangle" )
      ConfiguredKeywordsValues[${ConfiguredKeywords[-1]}]="y"
   fi
   unset ElAngDistFlag

   ConfiguredKeywords+=($(sed -n "/#.*Beginning/,/#.*End/p" ${InputFile} | sed "/^#/d" | cut -f1 -d' '))

   additional_keywords=($(sed -n "/#.*Beginning/,/#.*End/p" ${InputFile} | sed "/^#/d" | cut -f1 -d' '))
   for keyword in ${additional_keywords[@]} ; do
      ReadText=$(grep "${keyword}" ${InputFile} | sed "s|${keyword}\ *\(.*\)|\1|" | sed "s|\ \+|\ |g")
      if [[ ${ReadText} == *\<* ]] ; then
         if [[ ${ReadText} == *\<range* ]] ; then
            IFS=' ' read -a rangeParams <<< $(echo ${ReadText} | sed "s/.*<range\(.*\)>.*/\1/")
            currentRangeValue=${rangeParams[0]}
            while (( $(echo "${currentRangeValue}<=${rangeParams[1]}" | bc -l) )) ; do
               ConfiguredKeywordsValues[${keyword}]+=$(echo ${ReadText} | sed "s/\(.*\)<range.*>\(.*\)/\1 ${currentRangeValue} \2|/" | sed "s/ \+/_/g" | sed "s|^_||" | sed "s|_$||")
               currentRangeValue="$(echo "${currentRangeValue}+${rangeParams[2]}" | bc -l)"
            done
            unset rangeParams
            unset currentRangeValue
         else
            for multparam in $(echo ${ReadText} | sed "s/.*<\(.*\)>.*/\1/") ; do
               ConfiguredKeywordsValues[${keyword}]+=$(echo ${ReadText} | sed "s/\(.*\)<.*>\(.*\)/\1 ${multparam} \2|/" | sed "s/ \+/_/g" | sed "s|^_||" | sed "s|_$||")
            done
            unset multparam
         fi
         ConfiguredKeywordsValues[${keyword}]="${ConfiguredKeywordsValues[${keyword}]%|}"
      else
         ConfiguredKeywordsValues[${keyword}]="${ReadText}"
      fi
      unset ReadText
   done
   unset additional_keywords

   VerbosePrint "################################################################################\n"
   [ ${RunTalysFlag} ] && [ ${TalysVersions} ] && VerbosePrint "Will run talys calculations with versions: ${TalysVersions[@]//|/, }\n"
   [ ${ForceRunTalys} ] && VerbosePrint "Will force run talys calculations\n"
   [ ${RunTalysFlag} ] && [ ${Nuclei} ] && VerbosePrint "Will run talys calculations for nuclei: $(echo ${Nuclei[@]})\n"
   [ ${RangesFlag} ] && VerbosePrint "Will calculate ranges\n"
   [ ${ChiFlag} ] && VerbosePrint "Will calculate chi squares\n"
   [ ${PartialRanges} ] && VerbosePrint "Will calculate partial ranges for: ${PartialRanges[@]//|/ } \n"
   [ ${Ratios} ] && VerbosePrint "Will calculate ratios for: ${Ratios[0]//|/, } / ${Ratios[1]//|/, }\n"
   VerbosePrint "################################################################################\n"
   VerbosePrint "The input will include the following keywords.\n"
   for keyword in "${ConfiguredKeywords[@]}" ; do
      VerbosePrint "${keyword}: $(echo "${ConfiguredKeywordsValues[${keyword}]//|/, }" | sed "s/_/ /g")\n"
      if echo "${ConfiguredKeywordsValues[${keyword}]}" | grep -q \| ; then
         local dummy=${ConfiguredKeywordsValues[${keyword}]//[^|]}
         NumberOfCompinations=$((${NumberOfCompinations} * (${#dummy} + 1) ))
         MultKeywords+=( ${keyword} )
         unset dummy
      fi
   done
   unset keyword
   VerbosePrint "################################################################################\n"
}

function DefineCompinationDirectory {
   local dummy
   local variable="projectile"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   CompinationWorkDir="${dummy}-"
   variable="alphaomp"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ ! ${dummy} ] && dummy="0"
   CompinationWorkDir+="a${dummy}"
   variable="jlmomp"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ ! ${dummy} ] && dummy="0"
   CompinationWorkDir+="p${dummy}"
   variable="ldmodel"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ ! ${dummy} ] && dummy="0"
   CompinationWorkDir+="l${dummy}"
   variable="strength"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ ! ${dummy} ] && dummy="0"
   CompinationWorkDir+="s${dummy}"
   variable="strengthm1"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ ! ${dummy} ] && dummy="0"
   CompinationWorkDir+="m${dummy}"
   variable="astro"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ "${dummy}" == "n" ] && unset dummy
   [ ${dummy} ] && dummy="-rr"
   CompinationWorkDir+="${dummy}"
   variable="astrogs"
   [ ${CurrentMultKeywordValue[${variable}]} ] && dummy=${CurrentMultKeywordValue[${variable}]} || dummy=${ConfiguredKeywordsValues[${variable}]}
   [ "${dummy}" == "n" ] && unset dummy
   [ ${dummy} ] && dummy="gs"
   CompinationWorkDir+="${dummy}"
   local key
   for key in ${MultKeywords[@]} ; do
      [ "${key}" == "projectile" ] || [ "${key}" == "alphaomp" ] || [ "${key}" == "jlmomp" ] || [ "${key}" == "ldmodel" ] || [ "${key}" == "strength" ] || [ "${key}" == "strengthm1" ] || [ "${key}" == "astro" ] || [ "${key}" == "astrogs" ] && continue
      CompinationWorkDir+="-${key}_$(echo ${CurrentMultKeywordValue[${key}]} | sed "s| |_|g")"
   done

   CompinationWorkDir="${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/${CompinationWorkDir}"
   VerbosePrint "####\tPreparing to process compination ${NucleusCurrentCompinationIndex} of ${NumberOfCompinations}\n"
   if [ ! -d ${CompinationWorkDir} ] ; then
      mkdir -p ${CompinationWorkDir}
      VerbosePrint "\t($(PrintCombinationIndex)) Creating folder $(basename ${CompinationWorkDir})\n"
   else
      VerbosePrint "\t($(PrintCombinationIndex)) Folder $(basename ${CompinationWorkDir}) already exists!!!\n"
   fi

   unset dummy
   unset variable
   unset key
}

function PrintCombinationIndex {
   echo "${NucleusCurrentCompinationIndex}/${NumberOfCompinations} - ${CurrentCompinationIndex}/${TotalNumberOfCompinations}"
}

function MakeCompinationInput {
   local CompinationInputFile="${CompinationWorkDir}/input"
   if [ -f ${CompinationInputFile} ] ; then
      VerbosePrint "\t($(PrintCombinationIndex)) Input file in $(basename ${CompinationWorkDir}) already exists!!!\n"
      if [ ${ForceRunTalys} ] ; then
         VerbosePrint "\t($(PrintCombinationIndex)) Force running talys... erasing input file in $(basename ${CompinationWorkDir})!!!\n"
         find ${CompinationWorkDir} -type f -exec rm -f {} +
      else
         CompinationInputFile+="-new"
      fi
   fi
   local key
   VerbosePrint "\t($(PrintCombinationIndex)) Creating input file $(basename ${CompinationInputFile}) in $(basename ${CompinationWorkDir})\n"
   echo "mass ${NucleusA}" > ${CompinationInputFile}
   echo "element ${NucleusSymbol}" >> ${CompinationInputFile}
   for key in "${ConfiguredKeywords[@]}" ; do
      local keyvalue
      [ "${CurrentMultKeywordValue[${key}]}" ] && keyvalue=${CurrentMultKeywordValue[${key}]} || keyvalue=${ConfiguredKeywordsValues[${key}]}
      echo "${key} ${keyvalue}" >> ${CompinationInputFile}
      unset keyvalue
   done
   unset CompinationInputFile
   unset key
}

function CheckIfNeedToRunTalys {
   diff input input-new >/dev/null 2>&1
   if [ $? -ne 0 ] ; then
      VerbosePrint "\t($(PrintCombinationIndex)) Different input file from previous run. Rerunning talys Calculations!!!\n"
   else
      if [ -f output ] ; then
         if grep -q successful output ; then
            VerbosePrint "\t($(PrintCombinationIndex)) Same input file and completed previous run. Nothing to do!!!\n"
            VerbosePrint "\t($(PrintCombinationIndex)) Finished processing ${TalysExecutable} in folder $(basename ${CompinationWorkDir}) for ${NucleusA}${NucleusSymbol}\n"
            return
         fi
      fi
      VerbosePrint "\t($(PrintCombinationIndex)) Same input file but incomplet previous run. Rerunning talys Calculations!!!\n"
   fi
   find . ! -name 'input-new' -type f -exec rm -f {} +
   mv input-new input
}

function RunTalys {
   VerbosePrint "\t($(PrintCombinationIndex)) Running ${TalysExecutable} in folder $(basename ${CompinationWorkDir}) for ${NucleusA}${NucleusSymbol}\n"
   ${TalysExecutable} < input > output
   VerbosePrint "\t($(PrintCombinationIndex)) Finished running ${TalysExecutable} in folder $(basename ${CompinationWorkDir}) for ${NucleusA}${NucleusSymbol}\n"

   if grep -q "\-rrgs" <<< "$(basename ${CompinationWorkDir})" ; then
      for file in astrorate.* ; do mv ${file} ${file}_gs ; done
      unset file
      VerbosePrint "\t($(PrintCombinationIndex)) Added _gs extention to astrorate files in folder $(basename ${CompinationWorkDir}) for ${NucleusA}${NucleusSymbol}\n"
   fi
}

function RunTalysCompination {
   local originalDir=$(pwd)
   cd "${CompinationWorkDir}"
   [ -f input-new ] && CheckIfNeedToRunTalys
   if [ -f input-new ] ; then
      rm -f input-new
   else
      RunTalys
   fi
   cd "${originalDir}"
   unset originalDir
}

function PrepareAndRunRatios {
   local enum
   while [[ ! $(grep "${NucleusCurrentCompinationIndex}\/${NumberOfCompinations}.*Finished.*${TalysExecutable}.*$(basename ${CompinationWorkDir}).*${NucleusA}${NucleusSymbol}" ${LogFile} ) ]] ; do sleep 1 ; done
   for numeratorFile in ${Ratios[0]//|/ } ; do
      [ ! -e "${CompinationWorkDir}/${numeratorFile}" ] && VerbosePrint "\t($(PrintCombinationIndex)) Numerator file ${numeratorFile} doesn't exist in folder $(basename ${CompinationWorkDir}). Skipping ratio calculation!!!\n" && continue
      for denominatorFile in ${Ratios[1]//|/ } ; do
         [ ! -e "${CompinationWorkDir}/${denominatorFile}" ] && VerbosePrint "\t($(PrintCombinationIndex)) Denominator file ${denominatorFile} doesn't exist in folder $(basename ${CompinationWorkDir}). Skipping ratio calculation!!!\n" && continue
         [ "${numeratorFile}" == "${denominatorFile}" ] && VerbosePrint "\t($(PrintCombinationIndex)) Identical numerator and denominator file ${denominatorFile}. Skipping ratio calculation!!!\n" && continue
         local RatioCalcDir="${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/Ratios/$(basename ${CompinationWorkDir})"
         [ ! -d ${RatioCalcDir} ] && VerbosePrint "\t($(PrintCombinationIndex)) Creating ratio folder ${RatioCalcDir}\n" && mkdir -p ${RatioCalcDir}
         VerbosePrint "\t($(PrintCombinationIndex)) Calculating ratio ${numeratorFile} over ${denominatorFile} in ${RatioCalcDir}\n"
         ratio "${CompinationWorkDir}/${numeratorFile}" "${CompinationWorkDir}/${denominatorFile}" > "${RatioCalcDir}/${numeratorFile}_over_${denominatorFile}"
         unset RatioCalcDir
      done
   done
   unset numeratorFile
   unset denominatorFile
}

function loopMultiKeywords {
   local keys="$@"
   local key
   for key in ${keys[@]} ; do
      for keyvalue in ${ConfiguredKeywordsValues[${key}]//|/ } ; do
         CurrentMultKeywordValue[${key}]=$(echo ${keyvalue} | sed "s|_| |g")
         if [ "${key}" != "${MultKeywords[-1]}" ] ; then
            loopMultiKeywords ${keys#*${key}} 
         else
            if [ "${CurrentMultKeywordValue["astrogs"]}" == "y" ] || [ "${ConfiguredKeywordsValues["astrogs"]}" == "y" ] ; then
               if [ "${CurrentMultKeywordValue["astro"]}" == "n" ] || [ "${ConfiguredKeywordsValues["astro"]}" == "n" ] || [ ! ${ConfiguredKeywordsValues["astro"]} ] ; then
                  VerbosePrint "\t($(PrintCombinationIndex)) Compination with astrogs keyword set, but no astro keyword. Skipping it!!!\n"
                  NucleusCurrentCompinationIndex=$((${NucleusCurrentCompinationIndex}+1))
                  CurrentCompinationIndex=$((${CurrentCompinationIndex}+1))
                  continue
               fi
            fi
            sleep 0.5 ; while (( $(jobs -rp | wc -l) >= ${NumberOfWorkingThreads} )) ; do sleep 1 ; done
            (
               DefineCompinationDirectory
               if [ ${RunTalysFlag} ] ; then
                  MakeCompinationInput
                  RunTalysCompination
               fi
               [ ${Ratios} ] && PrepareAndRunRatios
            ) &
            NucleusCurrentCompinationIndex=$((${NucleusCurrentCompinationIndex}+1))
            CurrentCompinationIndex=$((${CurrentCompinationIndex}+1))
         fi
      done
      return
   done
   unset keys
   unset key
   unset keyvalue
}

function PrepareAndRunTalys {
   [ ! ${RunTalysFlag} ] && [ ! ${Ratios} ] && VerbosePrint "Skipping running talys calculations in ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}\n" && return
   VerbosePrint "Preparing to run ${NumberOfCompinations} talys calculations\n"
   declare -A CurrentMultKeywordValue
   NucleusCurrentCompinationIndex=1
   loopMultiKeywords ${MultKeywords[@]}
   unset NucleusCurrentCompinationIndex
}

function RunCalculateRanges {
   local RangesSearchFolder=${1}
   local RangesFolder=${2}
   local RangesFolderPattern=${3}
   local RangesFilePattern=${4}
   local Description=${5}
   [ -d "${RangesSearchFolder}" ] && [ ! -d "${RangesFolder}" ] && mkdir -p ${RangesFolder} && VerbosePrint "Created ${Description} folder ${RangesFolder}\n"
   [ ! -d "${RangesFolder}" ] && return
   rm -rf ${RangesFolder}/*-ranges
   local proj
   for proj in $(ls ${RangesSearchFolder} | sed "s|^\([[:alpha:]]\)-.*|\1|" | sed "s|[[:alpha:]][[:alpha:]]\+||" | sort -u) ; do
      local rangeFiles
      local HelperRangeFolder="*${RangesSearchFolder}/${proj}-"
      rangeFiles=`find ${RangesSearchFolder} \( -ipath ${HelperRangeFolder}${RangesFolderPattern// /* -or -ipath ${HelperRangeFolder}}* \) \( -iname ${RangesFilePattern// / -or -iname } \) -exec basename {} \; | sort -u`
      local file
      for file in ${rangeFiles} ; do
         VerbosePrint "Calculating ${Description} for file ${proj}-${file} in folder ${RangesFolder//${InputWorkDir}\/}\n"
         rm -rf ${RangesFolder}/${proj}-${file}-ranges*
         find ${RangesSearchFolder} \( -ipath ${HelperRangeFolder}${RangesFolderPattern// /* -or -ipath ${HelperRangeFolder}}* \) \( -iname ${file} \) -exec cat {} >> ${RangesFolder}/${proj}-${file}-ranges-dum \;
         sed -i "/#/d" ${RangesFolder}/${proj}-${file}-ranges-dum
         sed -i "s|^[[:blank:]]*||g" ${RangesFolder}/${proj}-${file}-ranges-dum
         sed -i "s|[[:blank:]]\+| |g" ${RangesFolder}/${proj}-${file}-ranges-dum
         cut -f1-2 -d' ' ${RangesFolder}/${proj}-${file}-ranges-dum > ${RangesFolder}/${proj}-${file}-ranges
         sort -g -k2 ${RangesFolder}/${proj}-${file}-ranges | sort -g -u > ${RangesFolder}/${proj}-${file}-ranges-min
         sort -g -k2 -r ${RangesFolder}/${proj}-${file}-ranges | sort -g -u > ${RangesFolder}/${proj}-${file}-ranges-max
         paste -d' ' ${RangesFolder}/${proj}-${file}-ranges-min - <<< $(cut -f2 -d' ' ${RangesFolder}/${proj}-${file}-ranges-max) > ${RangesFolder}/${proj}-${file}-ranges
         rm -rf "${RangesFolder}"/${proj}-${file}-ranges-*
         local line
         while read line ; do
            local ener=$(echo ${line} | cut -f1 -d' ')
            local min=$(echo ${line} | cut -f2 -d' ')
            local max=$(echo ${line} | cut -f3 -d' ')
            [[ "${min}" == "${max}" ]] && continue
            local minfiles=$(grep -l "${ener}\ *${min}" ${RangesSearchFolder}/${proj}-*/${file} | sed "s|/${file}||" | tr '\n' ' ' )
            minfiles="$(basename -a ${minfiles} | tr '\n' ' ' )"
            local maxfiles=$(grep -l "${ener}\ *${max}" ${RangesSearchFolder}/${proj}-*/${file} | sed "s|/${file}||" | tr '\n' ' ' )
            maxfiles="$(basename -a ${maxfiles} | tr '\n' ' ' )"
            sed -i "/^${line}/c${line} MINIMUM IN ${minfiles} MAXIMUM IN ${maxfiles}" ${RangesFolder}/${proj}-${file}-ranges
            unset ener
            unset min
            unset max
            unset minfiles
            unset maxfiles
         done < ${RangesFolder}/${proj}-${file}-ranges &
         unset line
         VerbosePrint "Finished calculating ${Description} for file ${proj}-${file} in folder ${RangesFolder//${InputWorkDir}\/}\n"
      done
      unset rangeFiles
      unset HelperRangeFolder
      unset file
   done
   unset proj
   unset RangesFolder
   unset RangesSearchFolder
   unset SearchPattern
   unset Description
}

function CalculateRanges {
   local searchFolder=${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}
   local rangesFolder=${searchFolder}/Ranges
   local rangesFolderPatern="*"
   local rangesFilePattern="[rx][ps]*.[tL][o0-9][t0-9] astrorate.*"
   local rangesDescription='ranges'
   RunCalculateRanges "${searchFolder}" "${rangesFolder}" "${rangesFolderPatern}" "${rangesFilePattern}" "${rangesDescription}"
   unset searchFolder
   unset rangesFolder
   unset searchPattern
   unset rangesDescription
}

function CalculateRatiosRanges {
   local searchFolder=${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/Ratios
   local rangesFolder=${searchFolder}/Ranges
   local rangesFolderPatern="*"
   local rangesFilePattern="*_over_*"
   local rangesDescription='ratio ranges'
   RunCalculateRanges "${searchFolder}" "${rangesFolder}" "${rangesFolderPatern}" "${rangesFilePattern}" "${rangesDescription}"
   unset searchFolder
   unset rangesFolder
   unset searchPattern
   unset rangesDescription
}

function CalculatePartialRanges {
   local searchFolder=${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}
   local rangesFolder=${searchFolder}/PartialRanges/${PartialRanges[@]}
   local rangesFolderPatern="${PartialRanges[@]//|/ }"
   local rangesFilePattern="[rx][ps]*.[tL][o0-9][t0-9] astrorate.*"
   local rangesDescription='partial ranges'
   RunCalculateRanges "${searchFolder}" "${rangesFolder}" "${rangesFolderPatern}" "${rangesFilePattern}" "${rangesDescription}"
   unset searchFolder
   unset rangesFolder
   unset searchPattern
   unset rangesDescription
}

function CalculateChis {
   [ -d ${TalysWorkDir}/data/${NucleusA}${NucleusSymbol} ] && [ -d ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol} ] && VerbosePrint "Calculating chi2 for nucleus ${NucleusA}${NucleusSymbol} in folder ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/chi2\n" || return
   [ ! -d ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/chi2 ] && mkdir -p ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/chi2
   rm -rf ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/chi2/*
   local expFiles=$(find "${TalysWorkDir}/data/${NucleusA}${NucleusSymbol}" -type f -iname *_[pan][gpan]_*.[tL][o0-9][t0-9])
   local ztar=$(grep \ ${NucleusA}\  ${massesDir}/${NucleusSymbol}.mass | cut -f3 -d' ')
   local mtar=$(grep \ ${NucleusA}\  ${massesDir}/${NucleusSymbol}.mass | cut -f8 -d' ')
   local expfile
   for expfile in ${expFiles[@]} ; do
      local reaction=$(echo ${expfile} | sed "s/.*\_\([pan][gnpa]\)\_.*/\1/g") #"
	   local expfilestate=$(echo ${expfile} | grep -oh [Lt][o0-9][t0-9])
      local beam
      local zDiff
      local ADiff
      local reaction_xsfile
      local csfiles
         case ${reaction} in
            pg )
               beam=p
               zDiff=1
               ADiff=1
               reaction_xsfile=xs000000
               ;;
            pn )
               beam=p
               zDiff=1
               ADiff=0
               reaction_xsfile=xs100000
               ;;
            pp )
               beam=p
               zDiff=0
               ADiff=0
               reaction_xsfile=xs010000
               ;;
            pa )
               beam=p
               zDiff=-1
               ADiff=-3
               reaction_xsfile=xs000001
               ;;
            ag )
               beam=a
               zDiff=2
               ADiff=4
               reaction_xsfile=xs000000
               ;;
            an )
               beam=a
               zDiff=2
               ADiff=3
               reaction_xsfile=xs100000
               ;;
            ap )
               beam=a
               zDiff=1
               ADiff=3
               reaction_xsfile=xs010000
               ;;
            aa )
               beam=a
               zDiff=0
               ADiff=0
               reaction_xsfile=xs000001
               ;;
            ng )
               beam=n
               zDiff=0
               ADiff=1
               reaction_xsfile=xs000000
               ;;
            nn )
               beam=n
               zDiff=0
               ADiff=0
               reaction_xsfile=xs100000
               ;;
            np )
               beam=n
               zDiff=-1
               ADiff=0
               reaction_xsfile=xs010000
               ;;
            na )
               beam=n
               zDiff=-2
               ADiff=-3
               reaction_xsfile=xs000001
               ;;
         esac

         csfiles=$(ls ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/${beam}-*/rp*$((${ztar}+${zDiff}))*$((${NucleusA}+${ADiff}))*.${expfilestate} 2>/dev/null)
         csfiles+=" $(ls ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/${beam}-*/${reaction_xsfile}.${expfilestate} 2>/dev/null)"

         local csfile
         for csfile in ${csfiles[@]} ; do
            [ ! ${cmFlag} ] && unset mtar && unset beam
            chi_calc ${csfile} ${expfile} ${mtar} ${beam} >> ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}/chi2/${reaction}-$(basename ${expfile})-$(basename ${csfile})
         done
         unset csfile
         unset csfiles
         unset beam
         unset reaction
         unset expfilestate
         unset zDiff
         unset ADiff
         unset reaction_xsfile
      done
      unset expFiles
      unset expfile
      unset mtar
      unset ztar
}

declare -A LongOptions
declare -A OptionHelp

ShortOptions="h"
LongOptions[help]="h"
OptionHelp[h]="display this help and exit"
function argR[h] {
   print_usage
   ScriptExit 0
}

ShortOptions+="v"
LongOptions[verbose]="v"
OptionHelp[v]="increase the information printed"
function argR[v] {
   VerboseOutput=1
}

ShortOptions+="f"
LongOptions[force]="f"
OptionHelp[f]="force run talys even if files exist"
function argR[f] {
   ForceRunTalys=1
}

ShortOptions+="t:"
LongOptions[parallel-jobs]="t"
OptionHelp[t]="set nb of parallel jobs\nNOTE: default value is $((`nproc`-2))"
function argR[t] {
   NumberOfWorkingThreads=${OPTARG}
   [[ ${NumberOfWorkingThreads} =~ ^[0-9]+$ ]] || ScriptExit 2
   [[ ${NumberOfWorkingThreads} -lt 1 || ${NumberOfWorkingThreads} -gt `nproc` ]] && ScriptExit 3
   VerbosePrint "You have asked for ${NumberOfWorkingThreads} parallel jobs.\n"
}

ShortOptions+="c"
LongOptions[cm]="c"
OptionHelp[c]="set if data are given in center of mass system.\nNOTE: default value is Lab\nNOTE: It is used only in the case of chi square calculations and the masses files must be availiable."
function argR[c] {
   Set_cmFlag
}

declare -A ConfigOptionsSetText
declare -A ConfigOptionsSettedValue

ConfigOptions=( "RunTalysFlag" )
ConfigOptionsSetText[RunTalysFlag]="Run Talys y/n"
ConfigOptionsSettedValue[RunTalysFlag]="n"

ConfigOptions+=( "TalysVersions" )
ConfigOptionsSetText[TalysVersions]="Give Talys Versions (see notes above)"
ConfigOptionsSettedValue[TalysVersions]="1.96"

ConfigOptions+=( "RangesFlag" )
ConfigOptionsSetText[RangesFlag]="Calculate Ranges y/n"
ConfigOptionsSettedValue[RangesFlag]="n"

ConfigOptions+=( "ChiFlag" )
ConfigOptionsSetText[ChiFlag]="Calculate Chi y/n"
ConfigOptionsSettedValue[ChiFlag]="n"

ConfigOptions+=( "PartialRanges" )
ConfigOptionsSetText[PartialRanges]="Calculate Partial Ranges (optional)"
ConfigOptionsSettedValue[PartialRanges]="a2pnl*s3m[13] a2pnl*s3m[13]"

ConfigOptions+=( "Ratios" )
ConfigOptionsSetText[Ratios]="Calculate ratio (numerators / denominators) (both can be more than one)"
ConfigOptionsSettedValue[Ratios]="rp035080.L00 / rp035080.tot"

ConfigOptions+=( "ElAngDistFlag" )
ConfigOptionsSetText[ElAngDistFlag]="Calculate elastic angular distributions (y/n, ONLY ONE) (optional, default n)"
ConfigOptionsSettedValue[ElAngDistFlag]="n"

declare -A InputFileOptionsSetText
declare -A InputFileOptionsSettedValue
declare -A InputFileOptionsKeywords

InputFileOptions=( "Nuclei" )
InputFileOptionsSetText[Nuclei]="Give Nuclei (In either form 78Se Se78) (can be more than one)"
InputFileOptionsSettedValue[Nuclei]="Se78"

InputFileOptions+=( "Projectiles" )
InputFileOptionsSetText[Projectiles]="Give projectile (can be more than one of n p d t h a g)"
InputFileOptionsSettedValue[Projectiles]="p a"
InputFileOptionsKeywords[Projectiles]="projectile"

InputFileOptions+=( "AlphaOmps" )
InputFileOptionsSetText[AlphaOmps]="Give alphaomps (valid alpha OMP number) (optional, can be empty or more)"
InputFileOptionsSettedValue[AlphaOmps]="1 2"
InputFileOptionsKeywords[AlphaOmps]="alphaomp"

InputFileOptions+=( "jlmOmp" )
InputFileOptionsSetText[jlmOmp]="jlmomp (y/n) (optional, can be empty or more)"
InputFileOptionsSettedValue[jlmOmp]="y n"
InputFileOptionsKeywords[jlmOmp]="jlmomp"

InputFileOptions+=( "ldModels" )
InputFileOptionsSetText[ldModels]="Give ldmodels (valid ldmodels number) (optional, can be empty or more)"
InputFileOptionsSettedValue[ldModels]="5 6"
InputFileOptionsKeywords[ldModels]="ldmodel"

InputFileOptions+=( "Strengths" )
InputFileOptionsSetText[Strengths]="Give strengths (valid strengths number) (optional, can be empty or more)"
InputFileOptionsSettedValue[Strengths]="1 3 7"
InputFileOptionsKeywords[Strengths]="strength"

InputFileOptions+=( "StrengthsM1" )
InputFileOptionsSetText[StrengthsM1]="Give strengthsM1 (valid strengthsM1 number) (optional, can be empty or more)"
InputFileOptionsSettedValue[StrengthsM1]="1 3 8"
InputFileOptionsKeywords[StrengthsM1]="strengthm1"

InputFileOptions+=( "Energy" )
InputFileOptionsSetText[Energy]="Give energy range and step (in MeV, it has to be <Min> <Max> <step>) or single energy"
InputFileOptionsSettedValue[Energy]="4 11 .5"
InputFileOptionsKeywords[Energy]="energy"

InputFileOptions+=( "Cbreakp" )
InputFileOptionsSetText[Cbreakp]="Give Cbreak p (optional, ONLY ONE)"
InputFileOptionsSettedValue[Cbreakp]=" "
InputFileOptionsKeywords[Cbreakp]="cbreak p"

InputFileOptions+=( "Cbreakn" )
InputFileOptionsSetText[Cbreakn]="Give Cbreak n (optional, ONLY ONE)"
InputFileOptionsSettedValue[Cbreakn]=" "
InputFileOptionsKeywords[Cbreakn]="cbreak n"

InputFileOptions+=( "transeps" )
InputFileOptionsSetText[transeps]="Give transeps (optional, ONLY ONE)"
InputFileOptionsSettedValue[transeps]=" "
InputFileOptionsKeywords[transeps]="transeps"

InputFileOptions+=( "popeps" )
InputFileOptionsSetText[popeps]="Give popeps (optional, ONLY ONE)"
InputFileOptionsSettedValue[popeps]=" "
InputFileOptionsKeywords[popeps]="popeps"

InputFileOptions+=( "xseps" )
InputFileOptionsSetText[xseps]="Give xseps (optional, ONLY ONE)"
InputFileOptionsSettedValue[xseps]=" "
InputFileOptionsKeywords[xseps]="xseps"

InputFileOptions+=( "isomer" )
InputFileOptionsSetText[isomer]="Give isomer (optional, ONLY ONE)"
InputFileOptionsSettedValue[isomer]=" "
InputFileOptionsKeywords[isomer]="isomer"

InputFileOptions+=( "astro" )
InputFileOptionsSetText[astro]="astro y/n (can be more than one) (optional, default n)"
InputFileOptionsSettedValue[astro]="n"
InputFileOptionsKeywords[astro]="astro"

InputFileOptions+=( "astrogs" )
InputFileOptionsSetText[astrogs]="astrogs y/n (can be more than one) (optional, default n, if set without astro keyword it will be SKIPPED!!!)"
InputFileOptionsSettedValue[astrogs]="n"
InputFileOptionsKeywords[astrogs]="astrogs"

for arg in "$@"; do
   shift
   ARG=${arg%=*}
   ARG2=${arg#*=}
   ARG2=${ARG2/${ARG}/}
   ARG=${ARG/--/}
   if [[ -n "${LongOptions[${ARG}]}" ]] ; then
      set -- "$@" "-${LongOptions[${ARG}]}"
      if [[ -n "${ARG2}" ]] ; then
         set -- "$@" "${ARG2}"
      fi
   else
      set -- "$@" "${arg}"
   fi

   unset ARG
   unset ARG2
done
unset arg

OPTIND=1
while getopts ${ShortOptions} opt ; do
   case "${opt}" in
      [^?]*) 
         argR[${opt}]
      ;;
      '?')
         ScriptExit 1
      ;;
   esac
done
shift $(expr $OPTIND - 1) # remove options from positional parameters
unset OPTIND
unset opt

[[ ${#@} > 1 ]] && ScriptExit 4

SetTalysWorkDir

[[ ${#@} == 0 ]] && CreateSampleInput

UserInputFileName="$1"
ConfiguredKeywords=()
declare -A ConfiguredKeywordsValues
declare -a MultKeywords
declare NumberOfCompinations=1
ReadInputFile
unset UserInputFileName

TalysVersions=( ${TalysVersions[@]//|/ } )
TalysVersionIndex=1
CurrentCompinationIndex=1
TotalNumberOfCompinations=$((${NumberOfCompinations}*${#Nuclei[@]}*${#TalysVersions[@]}))
for TalysVersion in ${TalysVersions[@]} ; do
   [ "${TalysVersion}" == "default" ] && TalysExecutable=talys || TalysExecutable=talys-${TalysVersion}
   NucleusIndex=1
   if ! command -v ${TalysExecutable} 2>&1 >/dev/null ;then
      VerbosePrint "Talys version ${TalysVersion} (command ${TalysExecutable}) (${TalysVersionIndex}/${#TalysVersions[@]}) not found. Skipping it!\n"
      VerbosePrint "################################################################################\n"
      TalysVersionIndex=$((${TalysVersionIndex}+1))
      CurrentCompinationIndex=$(( ${CurrentCompinationIndex} + ( ${NumberOfCompinations}*${#Nuclei[@]} ) ))
      continue
   fi
   for Nucleus in ${Nuclei[@]} ; do
      NucleusA=${Nucleus//[[:alpha:]]}
      NucleusSymbol=${Nucleus//[[:digit:]]}
      VerbosePrint "Preparing to process isotope ${NucleusA}${NucleusSymbol} (${NucleusIndex}/${#Nuclei[@]}) for talys version ${TalysVersion} (${TalysVersionIndex}/${#TalysVersions[@]})\n"
      [ ! -d ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol} ] && mkdir -p ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol} && VerbosePrint "Created folder ${InputWorkDir}/${TalysExecutable}/${NucleusA}${NucleusSymbol}\n"
      PrepareAndRunTalys
      VerbosePrint "################################################################################\n"
      NucleusIndex=$((${NucleusIndex}+1))
   done
   TalysVersionIndex=$((${TalysVersionIndex}+1))
   unset Nucleus
   unset NucleusA
   unset NucleusSymbol
   unset NucleusIndex
done
unset TalysVersionIndex
unset TotalNumberOfCompinations
unset CurrentCompinationIndex

wait
VerbosePrint "################################################################################\n"
VerbosePrint "Finished talys and ratios calculations. Starting calculating ranges and chis if any.\n"
VerbosePrint "################################################################################\n"

for TalysVersion in ${TalysVersions[@]} ; do
   [ "${TalysVersion}" == "default" ] && TalysExecutable=talys || TalysExecutable=talys-${TalysVersion}
   ! command -v ${TalysExecutable} 2>&1 >/dev/null && continue
   for Nucleus in ${Nuclei[@]} ; do
      NucleusA=${Nucleus//[[:alpha:]]}
      NucleusSymbol=${Nucleus//[[:digit:]]}
      [ ${RangesFlag} ] && CalculateRanges
      [ ${RangesFlag} ] && [ ${Ratios} ] && CalculateRatiosRanges
      [ ${PartialRanges} ] && CalculatePartialRanges
      [ ${ChiFlag} ] && CalculateChis
      
   done
   unset Nucleus
   unset NucleusA
   unset NucleusSymbol
done

unset TalysVersion
unset TalysExecutable
unset MultKeywords
unset NumberOfCompinations

wait

VerbosePrint "################################################################################\n"
VerbosePrint "Finished running $(basename $0) for input ${InputFileName}, run ${InputRunNumber}\n"

unset NumberOfWorkingThreads
unset CurWorkDir
unset ShortOptions
unset LongOptions
unset OptionHelp
unset VerboseOutput
unset ForceRunTalys
unset cmFlag
unset massesDir
unset InputFileName
unset InputWorkDir
unset LogFile
unset InputRunNumber
unset ConfigOptions
unset ConfigOptionsSetText
unset ConfigOptionsSettedValue
unset InputFileOptions
unset InputFileOptionsSetText
unset InputFileOptionsSettedValue

ScriptExit 0
