#!/bin/bash

# inifor - The Mesoscale Interface for Initializing and Forcing PALM

#--------------------------------------------------------------------------------#
# This file is part of the PALM model system.
#
# PALM is free software: you can redistribute it and/or modify it under the terms
# of the GNU General Public License as published by the Free Software Foundation,
# either version 3 of the License, or (at your option) any later version.
#
# PALM is distributed in the hope that it will be useful, but WITHOUT ANY
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
# A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along with
# PALM. If not, see <http://www.gnu.org/licenses/>.
#
# Copyright 2017-2018  Leibniz Universitaet Hannover
#--------------------------------------------------------------------------------#
#
# Current revisions:
# ------------------
# initial revision
# 
# Former revisions:
# -----------------
# $Id$
# 
#--------------------------------------------------------------------------------#
# inifor - script for running the inifor executable
#--------------------------------------------------------------------------------#


 
    # DECLARATION OF VARIABLES AND THEIR DEFAULT VALUES

 set +o allexport    # SUPPRESS EXPORT OF ALL VARIABLES, SINCE IN THE PAST THIS
                     # LEAD TO PROBLEMS IN ROUTINES CALLED BY PALMRUN
                     # (TOO MANY ARGUMENTS - PROBLEM)
 set +o noclobber    # EXISTING FILES ARE ALLOWED TO BE OVERWRITTEN

 typeset -i  i iec=0

 activation_string_list="inifor"
 configuration_identifier="default"
 delete_temporary_catalog=true
 fileconnection_file=trunk/SCRIPTS/.palm.iofiles
 locat=normal
 run_identifier=test
 silent=false
 version="inifor  0.1 Rev$Rev$"
 working_directory=`pwd`


    # ERROR HANDLING IN CASE OF EXIT
 trap 'if [[ $locat != normal  &&  $locat != control_c ]]
       then

              # CARRY OUT ERROR-COMMANDS GIVEN IN THE CONFIGURATION FILE (EC:)
          (( i = 0 ))
          while (( i < iec ))
          do
             (( i = i + 1 ))
             printf "\n  *** Execution of ERROR-command:\n"
             printf "  >>> ${err_command[$i]}\n"
             eval  ${err_command[$i]}
          done
          [[ $delete_temporary_catalog = true ]]  &&  (cd; rm -rf $tempdir)
          printf "\n\n+++ inifor crashed \n\n"
          exit 1
       elif [[ $locat != normal ]]
       then
          [[ $delete_temporary_catalog = true ]]  &&  (cd; rm -rf $tempdir)
          printf "\n+++ inifor killed by \"^C\" \n\n"
          exit 2
       else
          printf "\n --> inifor finished\n\n"
          exit 0
       fi' exit


    # ACTIONS IN CASE OF TERMINAL-BREAK (CONTROL-C):
 trap 'locat=control_c
       exit 1
      ' 2


    # READ SHELLSCRIPT-OPTIONS
    # TODO: add additional inifor options
 while  getopts  :a:Bc:r:v  option
 do
   case  $option  in
       (a)   activation_string_list=$OPTARG;;
       (B)   delete_temporary_catalog=false;;
       (c)   configuration_identifier=$OPTARG;;
       (r)   run_identifier=$OPTARG;;
       (v)   silent=true;;
       (\?)  printf "\n  +++ unknown option $OPTARG \n"
             printf "\n  --> type \"$0 ?\" for available options \n"
             locat=parameter;exit;;
   esac
 done


    # SKIP GIVEN OPTIONS TO READ POSITIONAL PARAMETER, IF GIVEN
    # CURRENTLY ONLY PARAMETER ? (TO OUTPUT A SHORT COMMAND INFO) IS ALLOWED
 (( to_shift = $OPTIND - 1 ))
 shift $to_shift

    # PRINT SHORT DESCRIPTION OF PALMRUN OPTIONS
    # TODO: add description of additional inifor options
 if [[ "$1" = "?" ]]
 then
   (printf "\n  *** Description of available palmrun options:\n"
    printf "\n      Option  Description                              Default-Value"
    printf "\n        -a    activation string list                   \"\" "
    printf "\n        -c    configuration identifier                 \"default\" "
    printf "\n        -r    run identifier                           test"
    printf "\n        -v    no prompt for confirmation               ---"
    printf "\n "
    printf "\n      Possible values of positional parameter <modus>:"
    printf "\n        \"?\"       -  this outline \n\n") | more
    exit
 elif [[ "$1" != "" ]]
 then
    printf "\n  +++ positional parameter $1 unknown \n"
    locat=parameter; exit
 fi



    # SHORT STARTING MESSAGE
 printf "\n*** $version "
 printf "\n    will be executed.     Please wait ..."


    # BUILD THE CONFIGURATION-FILE NAME AND THE SOURCES_FOR_RUN-FOLDER NAME
 config_file=.palm.config.$configuration_identifier
 sources_for_run_catalog=SOURCES_FOR_RUN_${configuration_identifier}_$run_identifier


    # CHECK, IF CONFIGURATION FILE EXISTS
 if [[ ! -f $config_file ]]
 then

    printf "\n\n  +++ configuration file: "
    printf "\n           $config_file"
    printf "\n      does not exist"
    locat=connect; exit

 fi


    # CHECK, IF USER PROVIDES OWN FILE CONNECTION FILE
 if [[ -f .palm.iofiles ]]
 then

       # CHECK VERSION MISMATCH
    if [[ $(head -n1 $fileconnection_file) != $(head -n1 .palm.iofiles) ]]
    then
       printf "\n\n  +++ WARNING: A file connection file has been found in your"
       printf "\n               working directory, but its revision does not match"
       printf "\n               the revision of the default (trunk) version."
       printf "\n               You may need to update your connection file"
       printf "\n               \"${working_directory}/.palm.iofiles\" !"
    fi

    fileconnection_file=.palm.iofiles

 fi


    # CHECK, IF FILE CONNECTION FILE EXISTS
 if [[ ! -f $fileconnection_file ]]
 then
    printf "\n\n  +++ file connection file: "
    printf "\n           $fileconnection_file"
    printf "\n      does not exist"
    locat=connect; exit  
 fi


    # CHECK, IF THE ACTIVATION_STRING_LIST HAS BEEN GIVEN
    # TODO: I suggest to use/extend the .palm.iofiles file to set the inifor I/O files,
    #       activation string could be "inifor"
 if [[ "$activation_string_list" = "" ]]
 then
    printf "\n\n  +++ no activation string list given: "
    printf "\n        please set palmrun option \"-a\" "
    locat=palmrun_option; exit  
 fi


    # READ AND EVALUATE THE CONFIGURATION-FILE
    # TODO: we can think about if it is really required tio read and interpret the whole file
    #       since many settings are not relevant for inifor. Instead, we could read only lines
    #       inifor-specific variables are set (like it is done in palmbuild)
 [[ $silent = false ]]  &&  printf "\n\n    Reading the configuration file... "


    # READ VARIABLE SETTINGS FROM CONFIG FILE LINE BY LINE
 while  read line
 do

       # FIRST REPLACE ENVIRONMENT-VARIABLES BY THEIR RESPECTIVE VALUES
    eval  line=\"$line\"


       # INTERPRET THE LINE
    if [[ "$(echo $line)" = "" ]]
    then

          # EMPTY LINE, NO ACTION
       continue

    elif [[ "$(echo $line | cut -c1)"  =  "#" ]]
    then

          # LINE IS A COMMENT LINE
       continue

    elif [[ "$(echo $line | cut -c1)"  =  "%" ]]
    then

          # LINE DEFINES AN ENVIRONMENT-VARIABLE
       var=`echo $line | cut -d" " -s -f1 | cut -c2-`
       value=`echo $line | cut -d" " -s -f2-`


          # VALUE FROM THE CONFIGURATION-FILE IS ASSIGNED TO THE
          # ENVIRONMENT-VARIABLE, BUT ONLY IF NO VALUE HAS BEEN ALREADY
          # ASSIGNED WITHIN THIS SCRIPT (E.G. BY SCRIPT-OPTIONS).
          # NON-ASSIGNED VARIABLES HAVE VALUE "" OR 0 (IN CASE OF INTEGER).
          # HENCE THE GENERAL RULE IS: SCRIPT-OPTION OVERWRITES THE
          # CONFIGURATION-FILE.
       if [[ "$(eval echo \$$var)" = ""  ||  "$(eval echo \$$var)" = "0" ]]
       then
          eval  export  $var="\$value"

             # TERMINAL OUTPUT OF ENVIRONMENT-VARIABLES, IF TRACEBACK IS SWITCHED on
          if [[ $do_trace = true ]]
          then
             printf "\n*** ENVIRONMENT-VARIABLE $var = $value"
          fi
       fi

    elif [[ "$(echo $line | cut -c1-3)" = "BD:" ]]
    then

          # LINE DEFINES BATCH-DIRECTIVE
       (( ibd = ibd + 1 ))
       line=$(echo $line | cut -c4-)
       batch_directive[$ibd]="$line"

    elif [[ "$(echo $line | cut -c1-4)" = "BDT:" ]]
    then

          # LINE DEFINES BATCH-DIRECTIVE FOR SENDING BACK THE JOBFILE FROM A
          # REMOTE TO A LOCAL HOST
       (( ibdt = ibdt + 1 ))
       line=$(echo $line | cut -c5-)
       batch_directive_transfer[$ibdt]="$line"

    elif [[ "$(echo $line | cut -c1-3)" = "EC:" ]]
    then

          # LINE DEFINES ERROR-COMMAND
       (( iec = iec + 1 ))
       line=$(echo $line | cut -c4-)
       err_command[$iec]="$line"

    elif [[ "$(echo $line | cut -c1-3)" = "IC:" ]]
    then

          # LINE DEFINES INPUT-COMMAND
       (( iic = iic + 1 ))
       line=$(echo $line | cut -c4-)
       in_command[$iic]="$line"

    elif [[ "$(echo $line | cut -c1-3)" = "OC:" ]]
    then

          # LINE DEFINES OUTPUT-COMMAND
       (( ioc = ioc + 1 ))
       line=$(echo $line | cut -c4-)
       out_command[$ioc]="$line"

    else

          # SKIP ALL OTHER LINES
       continue

    fi

 done < $config_file


    # CHECK SETTING OF REQUIRED PARAMETERS
    # TODO: we probably need to include such a line in the configuration file
 if [[ "$execute_command_inifor" = "" ]]
 then
    printf "\n  +++ no execute command found for inifor in $config_file"
    printf "\n      Please add line \"execute_command_inifor ...\" to that file."
    locat=config_file; exit
 fi


    # DETERMINE THE CALL STATUS
 if [[ "$remote_ip" != "" ]]
 then
    run_on_remote=true
 else
    run_on_remote=false
 fi


    # READ AND EVALUATE THE I/O-FILE LIST
 [[ $silent = false ]]  &&  printf "\n    Reading the I/O files... "


    # READ THE FILE CONNECTION FILE LINE BY LINE
 while  read line
 do

       # REPLACE REPEATING SPACES BETWEEN THE COLUMNS BY A SINGLE SPACE
       # HERE, TR IS USED INSTEAD OF SED TO GUARANTEE MAC COMPATIBILITY
    line=`echo "$line" | tr -s " "`

       # INTERPRET THE LINE
    if [[ "$(echo $line)" = "" ]]
    then
          # EMPTY LINE, NO ACTION
       continue

    elif [[ "$(echo $line | cut -c1)"  =  "#" ]]
    then

          # LINE IS A COMMENT LINE
       true

    else

          # LINE DEFINES FILE CONNECTION. READ THE FILE ATTRIBUTES.
          # s2a: in/out - field
          # s2b: action - field (optional)
       s1=`echo "$line" | cut -d" " -f1`
       s2=`echo "$line" | cut -d" " -s -f2`
       if [[ $(echo $s2 | grep -c ":") = 0 ]]
       then
          s2a=$s2
          s2b=""
       else
          s2a=`echo $s2 | cut -d":" -f1`
          s2b=`echo $s2 | cut -d":" -f2`
       fi
       s3=`echo "$line" | cut -d" " -f3 | sed 's/*/wildcard /g'`
       s4=`echo "$line" | cut -d" " -s -f4`
       eval s4=\"$s4\"    # REPLACE ENVIRONMENT-VARIABLES IN PATH BY THEIR RESPECTIVE VALUES
       s5=`echo "$line" | cut -d" " -s -f5`
       s6=`echo "$line" | cut -d" " -s -f6`

       
          # STORE FILE CONNECTION, IF ACTIVATED BY ACTIVATION-STRING FROM
          # INPUT- OR OUTPUT-LIST.
          # VARIABLE S3 MAY CONTAIN A LIST OF ACTIVATION STRINGS (FIELD-SEPERATOR ":").
          # IF EXECUTION IS SCHEDULED FOR A REMOTE-MACHINE AND THE FILE IS ONLY
          # LOCALLY REQUIRED ON THAT MACHINE (I.E. s2b != tr), THE FILE CONNECTION
          # IS NOT CHECKED AND STORED.
       IFSALT="$IFS"; IFS="$IFS:"      # ADD ":" AS FIELD SEPARATOR
       if [[ ( "$s2a" = in  || "$s2a" = inopt )  &&  ! ( $create_remote_batch_job = true  &&  "$s2b" != tr ) ]]
       then
          found=false
          for  actual  in  $activation_string_list
          do
             for  formal  in  $s3
             do
                [[ $actual = $formal  ||  "$formal" = "-" ]]  &&  found=true
             done
          done
          if [[ $found = true ]]
          then
             (( iin = iin + 1 ))
             localin_pre[$iin]=$s1; actionin_pre[$iin]=$s2b;
             pathin_pre[$iin]=$s4; endin_pre[$iin]=$s5; extin_pre[$iin]=$s6
             if [[ "$s2a" = inopt ]]
             then
                optin_pre[$iin]=yes
             else
                optin_pre[$iin]=no
             fi 

                # FILES WITH JOB-ATTRIBUTE ARE STORED IN THE SOURCES_FOR_RUN
                # FOLDER IF THE JOB IS RUNNING ON A REMOTE HOST
             if [[ $running_on_remote = true  &&  "$s2b" = tr ]]
             then
                pathin_pre[$iin]=${fast_io_catalog}/${sources_for_run_catalog}
             fi

                # CHECK FOR MULTIPLE FILES, SET A RESPECTIVE FLAG AND REMOVE
                # THE WILDCARD FROM THE ENDING
             if [[ "${s5: -1}" = "*" ]]
             then
                if [[ "$s2b" = "di" ]]
                then
                   printf "\n    +++ wildcards (*) not allowed with \"di\" file attribute."
                   printf "\n        see file \"$fileconnection_file\", line"
                   printf "\n$line"
                   locat=iofiles_file; exit
                fi
                multin[$iin]=true
                string=${endin_pre[$iin]}
                endin_pre[$iin]="${string%?}"
             else
                multin[$iin]=false
             fi
          fi
       elif [[ "$s2a" = out  &&  ! ( $create_remote_batch_job = true ) ]]
       then
          found=false
          for  actual  in  $activation_string_list
          do
             for  formal  in  $s3  
             do
                [[ $actual = $formal  ||  $formal = wildcard  ]]  &&  found=true
             done
          done
          if [[ $found = true ]]
          then
             (( iout = iout + 1 ))
             localout_pre[$iout]=$s1; actionout_pre[$iout]=$s2b
             pathout_pre[$iout]=$s4; endout_pre[$iout]=$s5; extout_pre[$iout]=$s6

                # CHECK IF WILDCARD IS USED AS ACTIVATION STRING
                # IN SUCH CASES, NO WARNING WILL LATER BE OUTPUT IF LOCAL FILES DO NOT EXIST
             if [[ $formal = wildcard  ]]
             then
                warnout_pre[$iout]=false
             else
                warnout_pre[$iout]=true
             fi

                # CHECK FOR MULTIPLE FILES, SET A RESPECTIVE FLAG AND REMOVE
                # THE WILDCARD FROM THE LOCAL FILENAME
             if [[ "${s1: -1}" = "*" ]]
             then
                if [[ "$s2b" = "di" ]]
                then
                   printf "\n    +++ wildcards (*) not allowed with \"di\" file attribute."
                   printf "\n        see file \"$fileconnection_file\", line"
                   printf "\n$line"
                   locat=iofiles_file; exit
                fi
                multout[$iout]=true
                string=${localout_pre[$iout]}
                localout_pre[$iout]="${string%?}"
             else
                multout[$iout]=false
             fi
          fi
       elif [[ "$s2a" != in  &&  "$s2a" != inopt  &&  "$s2a" != out ]]
       then
          printf "\n  +++ I/O-attribute in file $fileconnection_file has invalid"
          printf "\n      value \"$s2\". Only \"in\", \"inopt\", and \"out\" are allowed!"
          locat=connect; exit
       fi
       IFS="$IFSALT"
    fi

 done < $fileconnection_file



    # VALUES OF INIFOR-OPTIONS OVERWRITE THOSE FROM THE CONFIGURATION-FILE
    # next line is just an example
    # TODO: default values for inifor script options could be set in the configuration file
    #       (if it makes sense)
 [[ "$inifor_cores"  != "" ]]  &&  cores=$inifor_cores



    # CHECK IF INIFOR EXECUTABLE EXISTS
 if [[ $run_on_remote = false ]]
 then
 
    if [[ ! -f ${base_directory}/MAKE_DEPOSITORY_${configuration_identifier}/inifor ]]
    then
       printf "\n  +++ no inifor executable found in folder"
       printf "\n      \"${base_directory}/MAKE_DEPOSITORY_${configuration_identifier}\" "
       printf "\n      You may run \"palmbuild -c ${configuration_identifier}\" to create"
       printf "\n      the utility routines."
       locat=connect; exit
    fi

 else

    printf "\n  +++ remote call of inifor not realized yet"
    locat=inifor_remote; exit

 fi



    # GET THE GLOBAL REVISION-NUMBER OF THE SVN-REPOSITORY
    # (HANDED OVER TO RESTART-RUNS USING OPTION -G)
 if [[ "$global_revision" = "" ]]
 then
    global_revision=`svnversion $source_path  2>/dev/null`
    global_revision="Rev: $global_revision"
 fi



    # SET PORT NUMBER OPTION FOR CALLS OF SSH/SCP AND batch_scp SCRIPT
 if [[ "$scp_port" != "" ]]
 then
    PORTOPT="-P $scp_port"
    SSH_PORTOPT="-p $scp_port"
 fi


    # DETERMINE THE SSH-OPTION IN CASE THAT AN SSH-KEY IS EXPLICITLY GIVEN IN THE
    # CONFIG-FILE
 if [[ "$ssh_key" != "" ]]
 then
    ssh_key="-i $HOME/.ssh/$ssh_key"
 fi


    # GENERATE FULL FILENAMES OF INPUT-FILES, INCLUDING THEIR PATH
    # CHECK, IF INPUT-FILES EXIST, AND DETERMINE HIGHEST CYCLE NUMBER (IF CYCLES EXIST)
 (( i = 0 ))
 (( nr_of_input_files = 0 ))
 while (( i < iin ))
 do
    (( i = i + 1 ))

       # GENERATE PATH AND FULL FILE NAME (then-BRANCH: FIXED FULL NAME IS GIVEN, I.E. THE
       # FILE IDENTIFIER IS NOT PART OF THE FILENAME))
    if [[ "${actionin_pre[$i]}" = di ]]
    then
       eval filename=${pathin_pre[$i]}/${endin_pre[$i]}
    else
       eval filename=${pathin_pre[$i]}/${run_identifier}${endin_pre[$i]}
    fi


       # CHECK IF FILE EXISTS
    if ! ls $filename* 1>/dev/null 2>&1
    then

          # FILES WITH ATTRIBUTE opt ARE OPTIONAL. NO ABORT, IF THEY DO NOT EXIST.
       if [[ "${optin_pre[$i]}" != "yes" ]]
       then
          printf "\n\n  +++ INPUT-file: "
          if [[ "${extin_pre[$i]}" = ""  ||  "${extin_pre[$i]}" = " " ]]
          then
             printf "\n           $filename"
          else
             printf "\n           $filename.${extin_pre[$i]}"
          fi
          printf "\n      does not exist\n"
          locat=input; exit
       else
          (( nr_of_input_files = nr_of_input_files + 1 ))
          localin[$nr_of_input_files]="${localin_pre[$i]}"
          optin[$nr_of_input_files]="${optin_pre[$i]}"
          actionin[$nr_of_input_files]="unavailable"
          pathin[$nr_of_input_files]="${pathin_pre[$i]}"
          endin[$nr_of_input_files]="${endin_pre[$i]}"
          extin[$nr_of_input_files]="${extin_pre[$i]}"
       fi

    else

          # FIRST CHECK FOR MULTIPLE NAMES WITH THE SAME BASENAME
          # ($run_identifier) AND CREATE A LIST FOR THE DETECTED BASENAME
          # ENDINGS
       if [[ "${multin[$i]}" = true ]]
       then
             # DETERMINE THE EXISTING EXTENSIONS FROM THE LIST OF FILES
          ls -1 -d ${filename}    >   filelist  2>/dev/null
          ls -1 -d ${filename}.*  >>  filelist  2>/dev/null
          ls -1 -d ${filename}_*  >>  filelist  2>/dev/null

          endings=""
          while  read line
          do
                 # filename without path (i.e. after the last "/")
              basefilename=$(basename ${line})

                 # check if there is an extension and remove it
              ext=${basefilename##*.}
              if [[ "$ext" = "${extin_pre[$i]}" ]]
              then
                 basefilename=${basefilename%.*}
              fi

                 # check for an existing cycle number and remove it
              cycle=${basefilename##*.}
              if [[ $cycle =~ ^-?[0-9]+$ ]]
              then
                 basefilename=${basefilename%.*}
              fi

                 # remove the run_identifier from the beginning
              length_run_identifier=${#run_identifier}
              ending=${basefilename:${length_run_identifier}}

                 # remove the ending given in the .iofiles from the beginning
              endingstring="${endin_pre[$i]}"
              length_ending=${#endingstring}
              ending=${ending:${length_ending}}

              if [[ "$ending" = "" ]]
              then
                    # standard ending as given in the .iofiles
                 if [[ $(echo $endings | grep -c DEFAULT) = 0 ]]
                 then
                    endings="$endings DEFAULT"
                 fi
              else
                    # ending must start with "_", otherwise its a different file
                 if [[ "${ending:0:1}" = "_" ]]
                 then
                    if [[ $(echo $endings | grep -c "$ending") = 0 ]]
                    then
                       endings="$endings $ending"
                    fi
                 fi
              fi
 
          done <filelist

          rm filelist

       else

             # SINGLE NAME
          endings=DEFAULT

       fi

          # FOR EACH BASENAME ENDING CREATE AN ENTRY IN THE FINAL INPUT FILE LIST
       for  ending  in  $endings
       do

             # DEFAULT MEANS THAT THE ENDING GIVEN IN .iofiles SHALL BE USED
          if [[ $ending = DEFAULT ]]
          then
             ending=""
          fi

             # NEW ENTRY (ENDING IS ALSO ADDED TO LOCAL FILENAME READ BY PALM!)
          (( nr_of_input_files = nr_of_input_files + 1 ))
          localin[$nr_of_input_files]="${localin_pre[$i]}"$ending
          optin[$nr_of_input_files]="${optin_pre[$i]}"
          actionin[$nr_of_input_files]="${actionin_pre[$i]}"
          pathin[$nr_of_input_files]="${pathin_pre[$i]}"
          endin[$nr_of_input_files]="${endin_pre[$i]}"$ending
          extin[$nr_of_input_files]="${extin_pre[$i]}"


             # GENERATE PATH AND FULL FILE NAME (then-BRANCH: FIXED FULL NAME IS GIVEN, I.E. THE
             # FILE IDENTIFIER IS NOT PART OF THE FILENAME))
          if [[ "${actionin[$nr_of_input_files]}" = di ]]
          then
             eval filename=${pathin[$nr_of_input_files]}/${endin[$nr_of_input_files]}
          else
             eval filename=${pathin[$nr_of_input_files]}/${run_identifier}${endin[$nr_of_input_files]}
          fi

             # DETERMINE THE FILE'S CYCLE NUMBER
          (( maxcycle = 0 ))
          ls -1 -d $filename    >   filelist  2>/dev/null
          ls -1 -d $filename.*  >>  filelist  2>/dev/null
          while  read line
          do
                 # filename without path (i.e. after the last "/")
              basefilename=$(basename ${line})
   
                 # check if there is an extension
              extension=${basefilename##*.}
              if [[ "$extension" = "${extin[$nr_of_input_files]}" ]]
              then
                 basefilename=${basefilename%.*}
              fi
   
                 # check for an existing cycle number
              cycle=${basefilename##*.}
              if [[ $cycle =~ ^-?[0-9]+$ ]]
              then
                    # NUMBERS WITH LEADING ZEROS ARE INTERPRETED AS OCTAL NUMBERS
                    # 10# EXPLICITLY SPECIFIES THE NUMBER BASE AS 10
                 (( icycle = $((10#$cycle)) ))
              else
                 (( icycle = 0 ))
              fi
   
              if (( icycle > maxcycle ))
              then
                 (( maxcycle = icycle ))
   
                    # FOR COMPATIBILITY REASONS WITH OLDER VERSIONS
                    # CHECK IF CYCLE NUMBER CONTAINS LEADING ZEROS
                 if [[ $(echo $cycle | cut -c1) = 0 ]]
                 then
                    leading_zero=true
                 else
                    leading_zero=false
                 fi
              fi
   
          done <filelist
          rm filelist
   
             # MAKE CYCLE NUMBER THREE DIGITS WIDE
          if [[ $leading_zero = true ]]
          then
             cyclestring=`printf "%03d" $maxcycle`
          else
             cyclestring=$maxcycle
          fi
   
             # APPEND CYCLE NUMBER TO FILENAME
          if (( maxcycle > 0 ))
          then
             if [[ "${extin[$nr_of_input_files]}" != " "  &&   "${extin[$nr_of_input_files]}" != "" ]]
             then
                filename=${filename}.$cyclestring.${extin[$nr_of_input_files]}
             else
                filename=${filename}.$cyclestring
             fi
          else
             if [[ "${extin[$nr_of_input_files]}" != " "  &&   "${extin[$nr_of_input_files]}" != "" ]]
             then
                filename=${filename}.${extin[$nr_of_input_files]}
             fi
          fi
          
             # STORE FILENAME WITHOUT PATH BUT WITH CYCLE NUMBER,
             # IS LATER USED FOR TRANSFERRING FILES WIHIN THE JOB (SEE END OF FILE)
          absnamein[$nr_of_input_files]=$filename
          if (( maxcycle > 0 ))
          then
             if [[ "${actionin[$nr_of_input_files]}" = di ]]
             then
                frelin[$nr_of_input_files]=${endin[$nr_of_input_files]}.$cyclestring
             else
                frelin[$nr_of_input_files]=${run_identifier}${endin[$nr_of_input_files]}.$cyclestring
             fi
          else
             if [[ "${actionin[$nr_of_input_files]}" = di ]]
             then
                frelin[$nr_of_input_files]=${endin[$nr_of_input_files]}
             else
                frelin[$nr_of_input_files]=${run_identifier}${endin[$nr_of_input_files]}
             fi
          fi

       done

    fi

 done


    # GENERATE FULL FILENAMES OF OUTPUT-FILES (WITHOUT $ OR ~),
    # CHECK, IF OUTPUT-FILES EXIST, AND DETERMINE HIGHEST CYCLE NUMBER (IF CYCLES EXIST),
    # OR, IN CASE THAT FILE DOES NOT EXIST, CHECK, IF IT CAN BE CREATED  
    # THESE ACTIONS ARE NOT CARRIED OUT, IF FILES SHALL BE TRANSFERRED FROM THE REMOTE TO
    # THE LOCAL HOST (BECAUSE THEIR IS NO DIRECT ACCESS TO THE LOCAL DIRECTORIES FROM THE
    # REMOTE HOST)
 (( i = 0 ))
 while (( i < iout ))
 do
    (( i = i + 1 ))
    if [[ ! ( $running_on_remote = true  &&  ( "${actionout_pre[$i]}" = tr || "${actionout_pre[$i]}" = tra || "${actionout_pre[$i]}" = trpe ) ) ]]
    then
       if [[ "${actionout_pre[$i]}" = tr ]]
       then
          actionout_pre[$i]=""
       elif [[ "${actionout_pre[$i]}" = trpe ]]
       then
          actionout_pre[$i]=pe
       elif [[ "${actionout_pre[$i]}" = tra ]]
       then
          actionout_pre[$i]=a
       fi
       (( maxcycle = 0 ))
       eval filename=${pathout_pre[$i]}/${run_identifier}${endout_pre[$i]}
       eval catalogname=${pathout_pre[$i]}
       if ! ls $filename* 1>/dev/null 2>&1
       then
      
             # IF OUTPUT-FILE DOES NOT EXIST CHECK, IF IT CAN BE CREATED
          if  cat /dev/null > $filename  
          then
             rm  $filename
          else

                # CHECK, IF THE DIRECTORY WHERE FILE SHALL BE COPIED TO EXISTS
                # IF IT DOES NOT EXIST, TRY TO CREATE IT
             if [[ ! -d $catalogname ]]
             then
                if  mkdir -p  $catalogname
                then
                   printf "\n\n  *** directory:"
                   printf "\n           $catalogname"
                   printf "\n      was created\n"
                else
                   printf "\n\n  +++ OUTPUT-file:"
                   printf "\n           $filename"
                   printf "\n      cannot be created, because directory does not exist"
                   printf "\n      and cannot be created either"
                   printf "\n"
                   locat=output  ; exit
                fi 2>/dev/null 
             else
                printf "\n\n  +++ OUTPUT-file:"
                printf "\n           $filename"
                printf "\n      cannot be created, although directory exists"
                printf "\n"
                locat=output  ; exit
             fi
          fi 2>/dev/null

       fi

    fi
 done


    # DETERMINE THE NAME OF INIFOR'S TEMPORARY WORKING DIRECTORY
 run_id_number=$RANDOM
 run_id=${run_identifier}.$run_id_number
 tempdir=$fast_io_catalog/$run_id




    # OUTPUT OF THE INIFOR-HEADER
 calltime=$(date)
 printf "\n"
 printf "#------------------------------------------------------------------------# \n"
 printf "| %-35s%35s | \n" "$version" "$calltime"
 printf "| %-35s%35s | \n" "PALM code    $global_revision" " "
 printf "|                                                                        | \n"
 column1="called on:"; column2=$(hostname)
 printf "| %-25s%-45s | \n" "$column1" "$column2"
 if [[ $run_on_remote = true ]]
 then
    column1="config. identifier:"; column2="$configuration_identifier (execute on IP: $remote_ip)"
 else
    column1="config. identifier:"; column2="$configuration_identifier (execute on IP: $local_ip)"
 fi
 printf "| %-25s%-45s | \n" "$column1" "$column2"


 if [[ "$login_init_cmd" != "" ]]
 then
    column1="login init commands:"; column2=$(echo "$login_init_cmd" | cut -c-45)
    printf "| %-25s%-45s | \n" "$column1" "$column2"
    line=$(echo "$login_init_cmd" | cut -c46-)
    while [[ "$line" != "" ]]
    do
       column1=""
       column2=$(echo "$line" | cut -c-45)
       printf "| %-25s%-45s | \n" "$column1" "$column2"
       line=$(echo "$line" | cut -c46-)
    done
 fi

 if [[ "$module_commands" != "" ]]
 then
    column1="module commands:"; column2=$(echo "$module_commands" | cut -c-45)
    printf "| %-25s%-45s | \n" "$column1" "$column2"
    line=$(echo "$module_commands" | cut -c46-)
    while [[ "$line" != "" ]]
    do
       column1=""
       column2=$(echo "$line" | cut -c-45)
       printf "| %-25s%-45s | \n" "$column1" "$column2"
       line=$(echo "$line" | cut -c46-)
    done
 fi
 printf "|                                                                        | \n"
 column1="run identifier:"; column2=$run_identifier
 printf "| %-25s%-45s | \n" "$column1" "$column2"
 column1="activation string list:"; column2=$(echo $activation_string_list)
 printf "| %-25s%-45s | \n" "$column1" "$column2"

 printf "#------------------------------------------------------------------------#"




    # QUERY FOR CONTINUE
 if [[ $silent = false ]]
 then
    antwort=dummy
    printf "\n\n"
    printf " >>> everything o.k. (y/n) ?  "
    while  read antwort
    do
       if [[ "$antwort" != y  &&  "$antwort" != Y  &&  "$antwort" != n  &&  "$antwort" != N ]]
       then
          printf " >>> everything o.k. (y/n) ?  "
       else
          break
       fi
    done
    if [[ $antwort = n  ||  $antwort = N ]]
    then
       locat=user_abort; (( iec = 0 )); exit
    fi
    if [[ $run_on_remote ]]
    then
       printf "\n ***  inifor will now run on remote"
    else
       printf "\n ***  inifor will now continue to execute on this machine"
    fi
 fi

 
    # NOW PERFORM THOSE ACTIONS REQUIRED TO EXECUTE INIFOR ON THIS MACHINE (COPYING I/O FILES)
    # CHANGE TO THE TEMPORARY WORKING DIRECTORY

 mkdir -p  $tempdir
 chmod  go+rx  $tempdir
 cd  $tempdir

 printf "\n  *** changed to temporary directory: $tempdir"



    # PROVIDE THE INPUT FILES
    # LOOP OVER ALL ACTIVATED FILES (LISTED IN THE CONFIGURATION FILE)
 optional_files_missing=false
 (( i = 0 ))
 while (( i < nr_of_input_files ))
 do
    (( i = i + 1 ))
    if (( i == 1 ))
    then
       printf "\n\n  *** providing INPUT-files:\n$dashes"
    fi


       # SKIP OPTIONAL FILES, IF THEY DO NOT EXIST
    if [[ "${actionin[$i]}" = unavailable ]]
    then
       optional_files_missing=true
       continue
    fi

       # CHECK FOR SINGLE FILE (SERIAL RUN) OR DIRECTORY (ONE FILE PER CORE FOR PARELLEL EXECUTION)
    files_for_cores=false; filetype=file
    if [[ "${actionin[$i]}" = pe  &&  -n $cores ]]
    then
       files_for_cores=true; filetype=files
       actionin[$i]=""
    elif [[ "${actionin[$i]}" = pe  &&  ! -n $cores ]]
    then
       actionin[$i]=""
    elif [[ "${actionin[$i]}" = lnpe  &&  -n $cores ]]
    then
       files_for_cores=true; filetype=files
       actionin[$i]="ln"
    elif [[ "${actionin[$i]}" = lnpe  &&  ! -n $cores ]]
    then
       actionin[$i]="ln"
    fi

    if [[ $files_for_cores = true ]]
    then
       printf "\n  >>> INPUT: ${absnamein[$i]}/....  to  ${localin[$i]}"
    else
       printf "\n  >>> INPUT: ${absnamein[$i]}  to  ${localin[$i]}"
    fi

       # INPUT-FILES TO BE LINKED
    if [[ "${actionin[$i]}" = ln ]]
    then

       printf "\n      $filetype will be linked"
       if [[ $files_for_cores = false ]]
       then
          if [[ -f "${absnamein[$i]}" ]]
          then
             ln  ${absnamein[$i]}  ${localin[$i]}
             got_tmp[$i]=true
          fi
       else
          if [[ -d "${absnamein[$i]}" ]]
          then
             mkdir -p ${localin[$i]}
             cd ${absnamein[$i]}
             for file in $(ls *)
             do
                ln $file $tempdir/${localin[$i]}
             done >|/dev/null 2>&1
             cd $tempdir
          fi

             # IF "ln -f" HAS FAILED DO A NORMAL COPY "cp -r"
          if [[ ! -f "${localin[$i]}/_000000" ]]
          then
             printf "\n  --- WARNING: ln failed, using cp instead (might be time consuming...)"
             cp -r  ${absnamein[$i]}/*  ${localin[$i]}
          fi

          got_tmp[$i]=true
       fi
    fi

       # FILE IS STORED IN THE RESPECTIVE DIRECTORY GIVEN IN THE CONFIGURATION FILE
    if [[ "${actionin[$i]}" = ""  ||  "${actionin[$i]}" = "di"  ||  "${actionin[$i]}" = "tr"  ||  "${actionin[$i]}" = "npe" ]]
    then

       if [[ "${actionin[$i]}" = "npe"  &&  -n $cores ]]
       then

             # FILE COPIES ARE PROVIDED FOR ALL CORES
             # EACH FILE GETS A UNIQUE FILENAME WITH A FOUR DIGIT NUMBER
          printf "\n      file will be provided for $cores processors"
          mkdir -p ${localin[$i]}
          ival=$cores
          (( ii = 0 ))
          while (( ii <= ival-1 ))
          do
             if (( ii < 10 ))
             then
                cp  ${absnamein[$i]}  ${localin[$i]}/_000$ii
             elif (( ii < 100 ))
             then
                cp  ${absnamein[$i]}  ${localin[$i]}/_00$ii
             elif (( ii < 1000 ))
             then
                cp  ${absnamein[$i]}  ${localin[$i]}/_0$ii
             else
                cp  ${absnamein[$i]}  ${localin[$i]}/_$ii
             fi
             (( ii = ii + 1 ))
          done

       else

          if [[ $files_for_cores = true ]]
          then

                # PROVIDE FILES FOR EACH CORE
                # FIRST CREATE THE LOCAL DIRECTORY, THEN COPY FILES
                # FROM THE PERMANENT DIRECTORY BY LINKING THEM TO THE LOCAL ONE
             printf "\n      providing $cores files for the respective cores"
             mkdir -p ${localin[$i]}
            	if [[ $link_local_input = true ]]
             then
                printf "      files will be linked\n"
                cd ${absnamein[$i]}
                for file in $(ls *)
                do
                   ln -f $file  ${localin[$i]}
                done
                cd $tempdir
             fi

                # IF "ln -f" FAILED OR IF "$link_local_input = false" DO A NORMAL "cp -r"
             if [[ ! -f "${localin[$i]}/_000000" ]]
             then
                if [[ $link_local_input = true ]]
               	then
                 		printf "\n  --- WARNING: ln failed, using cp instead (might be time consuming...)"
                fi
                cp -r  ${absnamein[$i]}/*  ${localin[$i]}
             fi

          else

                # PROVIDE FILE FOR RUNS ON A SINGLE CORE
           		if [[ $link_local_input = true ]]
            	then
                printf "      file will be linked\n"
                ln -f  ${absnamein[$i]}  ${localin[$i]}
            	fi
               	# If "ln -f" fails or if "$link_local_input = false" do a normal "cp"
            	if [[ ! -f "${localin[$i]}" ]]
             then
                if [[ $link_local_input = true ]]
                then
                   printf "\n  --- WARNING: ln failed, using cp instead (might be time consuming...)"
                fi
                if [[ $running_on_remote = true  &&  "${actionin[$i]}" = tr ]]
                then
                   mv  ${absnamein[$i]}  ${localin[$i]}
                else
		                 cp  ${absnamein[$i]}  ${localin[$i]}
                fi
             fi
          fi
       fi
    fi

 done
 if (( i != 0 ))
 then
    if [[ $optional_files_missing = true ]]
    then
       printf "\n  *** INFORMATIVE: some optional INPUT-files are not present"
    fi
    printf "\n$dashes\n  *** all INPUT-files provided \n"
 fi


    # EXECUTE INPUT-COMMANDS GIVEN IN THE CONFIGURATION FILE
 (( i = 0 ))
 while (( i < iic ))
 do
    (( i = i + 1 ))
    if (( i == 1 ))
    then
       printf "\n\n  *** execution of INPUT-commands:\n$dashes"
    fi
    printf "\n  >>> ${in_command[$i]}"
    eval  ${in_command[$i]}
    if (( i == iic ))
    then
       printf "\n$dashes\n"
    fi
 done


       # CREATE THE NAMELIST-FILE WITH VALUES OF ENVIRONMENT-VARIABLES REQUIRED BY PALM
       # (FILE ENVPAR WILL BE READ BY PALM)
       # TODO: this has to be adjusted for inifor, i.e. the values of the script options
       #       have to be converted to NAMELIST variables which are then read by inifor.
       #       Required PALM parameters could also be extracted from local file PARIN
       #       and added here 
    cat  >  ENVPAR  <<  EOF
 &envpar  run_identifier = '$run_identifier', host = '$configuration_identifier',
          write_svf = .${write_svf}., write_binary = .${write_binary}., 
          read_svf = .${read_svf}., tasks_per_node = $tasks_per_node,
          maximum_parallel_io_streams = $maximum_parallel_io_streams,
          maximum_cpu_time_allowed = ${cpumax}.,
          revision = '$global_revision',
          progress_bar_disabled = .${progress_bar_disabled}. /

EOF

    # TODO: this is just an example for a possible access of the PALM parameters
 grep -Eo '(\s*\&(initialization_parameters|inipar|runtime_parameters|d3par)\s*)|(([nd][xyz]|end_time|longitude|latitude|dz_stretch_level|dz_stretch_factor|dz_max)\s*\=\s*[0-9]*\.*\,*)|((dz_stretch_level_start|dz_stretch_level_end)\s*\=(\s*[0-9]*\.*\,*)*)|\/' PARIN

    # COPY EXECUTABLE TO THIS TEMPORARY FOLDER
 cp  ${base_directory}/MAKE_DEPOSITORY_${configuration_identifier}/inifor  .

    # STARTING THE EXECUTABLE
 printf "\n\n  *** inifor starts in directory\n      \"`pwd`\"\n$dashes\n"
 PATH=$PATH:$tempdir


    # REPLACE PARAMETERS IN THE EXECUTION COMMAND WITH REAL VALUES
 line=`echo  "${execute_command_inifor}" | sed 's/{{/$/g' | sed 's/}}//g'`
 eval line=\"$line\"
 execute_command="$line"



    # SET THE NUMBER OF OPENMP-THREADS
 if [[ $use_openmp = true ]]
 then
    export OMP_NUM_THREADS=$threads_per_task
    printf "\n  *** number of OpenMP threads per MPI-task: $OMP_NUM_THREADS"
 else
    export OMP_NUM_THREADS=1
 fi


 printf "\n  *** execute command:"
 printf "\n      \"$execute_command\" \n\n"


 $execute_command    &> >(tee STDOUT)
 exit_code=${PIPESTATUS[0]}

 if [[ ${exit_code} != 0 ]]
 then

        # ABORT IN CASE OF RUNTIME ERRORS
    printf "\n  +++ runtime error occured"
    locat=execution
    exit

 else

    printf "\n$dashes\n  *** execution finished \n"

 fi


    # EXECUTE OUTPUT-COMMANDS GIVEN IN THE CONFIGURATION FILE
 (( i = 0 ))
 while (( i < ioc ))
 do
    (( i = i + 1 ))
    if (( i == 1 ))
    then
       printf "\n\n  *** execution of OUTPUT-commands:\n$dashes"
    fi

       # REPLACE PARAMETERS IN THE OUTPUT COMMAND WITH REAL VALUES
    out_command[$i]=`echo  "${out_command[$i]}" | sed 's/{{/$/g' | sed 's/}}//g'`

    printf "\n  >>> ${out_command[$i]}"
    eval  ${out_command[$i]}
    if (( i == ioc ))
    then
       printf "\n$dashes\n"
    fi
 done


    # IN A FIRST PASS, ADD ADDITIONAL OUTPUT FILE CONNECTIONS IN CASE OF
    # WILDCARDS
 (( i = 0 ))
 (( nr_of_output_files = 0 ))

 while (( i < iout ))
 do

    (( i = i + 1 ))

       # FIRST CHECK FOR MULTIPLE NAMES WITH THE SAME LOCAL NAME AND
       # CREATE A LIST FOR THE DETECTED ENDINGS
    if [[ "${multout[$i]}" = true ]]
    then
          # DETERMINE THE EXISTING EXTENSIONS FROM THE LIST OF FILES
       ls -1 -d ${localout_pre[$i]}    >   filelist  2>/dev/null
       ls -1 -d ${localout_pre[$i]}_*  >>  filelist  2>/dev/null

       endings="DEFAULT"
       while  read line
       do
              # remove the local name from the beginning
           localnamestring="${localout_pre[$i]}"
           length_localname=${#localnamestring}
           ending=${line:${length_localname}}

           if [[ "$ending" != "" ]]
           then
              endings="$endings $ending"
           fi
 
       done <filelist

       rm filelist

    else

          # SINGLE NAME
       endings=DEFAULT

    fi

       # FOR EACH BASENAME ENDING CREATE AN ENTRY IN THE FINAL OUTPUT FILE LIST
    for  ending  in  $endings
    do

          # DEFAULT MEANS THAT THE ENDING GIVEN IN .iofiles SHALL BE USED
       if [[ $ending = DEFAULT ]]
       then
          ending=""
       fi

          # NEW ENTRY (ENDING IS ALSO ADDED TO LOCAL FILENAME READ BY PALM!)
       (( nr_of_output_files = nr_of_output_files + 1 ))
       localout[$nr_of_output_files]="${localout_pre[$i]}"$ending
       transout[$nr_of_output_files]="${transout_pre[$i]}"
       actionout[$nr_of_output_files]="${actionout_pre[$i]}"
       pathout[$nr_of_output_files]="${pathout_pre[$i]}"
       endout[$nr_of_output_files]="${endout_pre[$i]}"$ending
       extout[$nr_of_output_files]="${extout_pre[$i]}"
       warnout[$nr_of_output_files]="${warnout_pre[$i]}"

    done

 done


    # COPY LOCAL OUTPUT-FILES TO THEIR PERMANENT DESTINATIONS
 (( i = 0 ))
 while (( i < nr_of_output_files ))
 do
    (( i = i + 1 ))
    if (( i == 1 ))
    then
       printf "\n\n  *** saving OUTPUT-files:"

          # GET RUN NUMBER ASSIGNED BY PALM
       if [[ -f RUN_NUMBER ]]
       then
           read  run_number  <  RUN_NUMBER
           printf "\n  *** PALM generated run_number = "$run_number" will be used as unified cycle number for all output files"
           usecycle_option="-U $run_number"
       else
           run_number=0
           usecycle_option=""
       fi
       if [[ $running_on_remote = true  &&  "$remote_loginnode" != "" ]]
       then
          printf "\n  *** in case of SCP transfers to local host"
          printf "\n      they will be done via remote login-node \"$remote_loginnode\" "
       fi
       printf "\n$dashes"
    fi

    if [[ ! ( $running_on_remote = true  &&  ( "${actionout[$i]}" = tr || "${actionout[$i]}" = tra || "${actionout[$i]}" = trpe ) ) ]]
    then

       eval filename=${pathout[$i]}/${run_identifier}${endout[$i]}

          # DETERMINE THE CYCLE NUMBER
       ls -1 -d $filename    >   filelist  2>/dev/null
       ls -1 -d $filename.*  >>  filelist  2>/dev/null
       while  read line
       do
   
             # filename without path (i.e. after the last "/")
          basefilename=$(basename ${line})
   
             # check if there is an extension
          extension=${basefilename##*.}
          if [[ "$extension" = "${extout[$i]}" ]]
          then
             basefilename=${basefilename%.*}
          fi
   
             # check for an existing cycle number
          cycle=${basefilename##*.}
          if [[ $cycle =~ ^-?[0-9]+$ ]]
          then
                # NUMBERS WITH LEADING ZEROS ARE INTERPRETED AS OCTAL NUMBERS
                # 10# EXPLICITLY SPECIFIES THE NUMBER BASE AS 10
             (( icycle = $((10#$cycle)) + 1 ))
          else
             (( icycle = 1 ))
          fi
   
          if (( icycle > maxcycle ))
          then
             (( maxcycle = icycle ))
          fi
   
       done <filelist
       rm filelist

   
          # SET THE CYCLE NUMBER
          # IN CASE OF FILE-APPEND, IT MUST BE THE HIGHEST EXISTING CYCLE NUMBER
       if [[ "${actionout[$i]}" = a ]]
       then
          (( maxcycle = maxcycle - 1 ))
       fi
          
       (( cycnum[$i] = maxcycle ))
       pathout[$i]=$filename


          # ADD CYCLE NUMBER TO FILENAME
          # IN APPEND MODE, FILES KEEP THEIR CURRENT CYCLE NUMBER
       if [[ "${actionout[$i]}" != "a" ]]
       then
             # SET RUN NUMBER AS CYCLE NUMBER, IF THERE IS NOT A CONFLICT
             # WITH AN EXISTING CYCLE NUMBER
          if (( run_number >= cycnum[$i] ))
          then
             (( cycnum[$i] = run_number ))
          else
             if (( run_number > 0 ))
             then
                printf "\n  --- INFORMATIVE: The following file cannot get a unified cycle number"
             fi
          fi
       fi
       if (( cycnum[$i] > 0 ))
       then
          cyclestring=`printf "%03d" ${cycnum[$i]}`
          pathout[$i]=${pathout[$i]}.$cyclestring
       fi
    fi           

       # CHECK FOR SINGLE FILE (SERIAL RUN) OR DIRECTORY (ONE FILE PER CORE FOR PARELLEL EXECUTION)
    files_for_cores=false; filetype=file
    link_local_output=false
    if [[ "${actionout[$i]}" = pe  &&  -n $cores ]]
    then
       files_for_cores=true; filetype=directory
       actionout[$i]=""
    elif [[ "${actionout[$i]}" = pe  &&  ! -n $cores ]]
    then
       actionout[$i]=""
    elif [[ "${actionout[$i]}" = lnpe  &&  -n $cores ]]
    then
       files_for_cores=true; filetype=directory
       link_local_output=true
       actionout[$i]=""
    elif [[ "${actionout[$i]}" = lnpe  &&  ! -n $cores ]]
    then
       link_local_output
       actionout[$i]=""
    elif [[ "${actionout[$i]}" = trpe  &&  -n $cores ]]
    then
       files_for_cores=true; filetype=directory
       actionout[$i]="tr"
    elif [[ "${actionout[$i]}" = trpe  &&  ! -n $cores ]]
    then
       actionout[$i]="tr"
    fi

    if [[ ! -f ${localout[$i]}  &&  $files_for_cores = false ]]
    then
       if [[ ${warnout[$i]} = true ]]
       then
          printf "\n  +++ temporary OUTPUT-file  ${localout[$i]}  does not exist\n"
       fi
    elif [[ ! -d ${localout[$i]}  &&  $files_for_cores = true ]]
    then
       if [[ ${warnout[$i]} = true ]]
       then
          printf "\n  +++ temporary OUTPUT-file  ${localout[$i]}/....  does not exist\n"
       fi
    else


          # COPY VIA SCP TO LOCAL HOST (ALWAYS IN BINARY MODE USING batch_scp option -m)
          # IF TARGET DIRECTORY DOES NOT EXISTS, TRY TO CREATE IT
       if [[ "${actionout[$i]}" = tr  ||  "${actionout[$i]}" = tra ]]
       then
          if [[ $running_on_remote = true ]]
          then

                # SET OPTIONS FOR TRANSFER
             if [[ "${actionout[$i]}" = tr ]]
             then
                if [[ $files_for_cores = false ]]
                then
                   catalog_option=""
                   catalog_string=""
                else
                   catalog_option="-c"
                   catalog_string="/"
                fi
                append_option=""
                append_string=""
             else
                append_option="-A"
                append_string="append"
             fi

             transfer_failed=false
             printf "\n  >>> OUTPUT: ${localout[$i]}$catalog_string  $append_string by SCP to"
             printf "\n              ${pathout[$i]}/${configuration_identifier}_${run_identifier}${endout[$i]}$catalog_string\n"

                # TRANSFER VIA SCP
             if [[ "$remote_loginnode" != "" ]]
             then
                ssh -q $remote_username@$remote_loginnode  "cd $tempdir; ${fast_io_catalog}/${sources_for_run_catalog}/batch_scp $PORTOPT $catalog_option $append_option -b -m $usecycle_option -u $local_username $return_address  ${localout[$i]} \"${pathout[$i]}\" ${configuration_identifier}_${run_identifier}${endout[$i]}  ${extout[$i]}"
             else
                batch_scp $PORTOPT $catalog_option $append_option -b -m $usecycle_option -u $local_username $return_address  ${localout[$i]} "${pathout[$i]}" ${configuration_identifier}_${run_identifier}${endout[$i]}  ${extout[$i]}
             fi
             [[ ${PIPESTATUS[0]} != 0 ]]  &&  transfer_failed=true


                # IF TRANSFER FAILED, CREATE BACKUP COPY ON THIS MACHINE
             if [[ $transfer_failed = true ]]
             then
                printf "  +++ transfer failed. Trying to save a copy on this host under:\n"
                printf "      ${pathout[$i]}/${configuration_identifier}_${run_identifier}${endout[$i]}_$run_id_number\n"

                   # FIRST CHECK, IF DIRECTORY EXISTS, AND CREATE IT, IF NECESSARY
                eval  local_catalog=${pathout[$i]}
                if [[ ! -d $local_catalog ]]
                then
                   printf "  *** local directory does not exist. Trying to create:\n"
                   printf "      $local_catalog \n"
                   mkdir -p  $local_catalog
                fi
                eval  cp  ${localout[$i]}  ${pathout[$i]}/${configuration_identifier}_${run_identifier}${endout[$i]}_$run_id_number
                transfer_problems=true
             fi

          else

                # UNSET actionout. DUE TO THIS SETTING, FILE WILL LATER JUST
                # BE COPIED OR APPENDED ON THIS MACHINE
             if [[ "${actionout[$i]}" = tr ]]
             then
                actionout[$i]=""
             else
                actionout[$i]="a"
             fi
          fi
       fi


          # APPEND ON THIS MACHINE
       if [[ "${actionout[$i]}" = "a" ]]
       then
          if [[ "${extout[$i]}" != " "  &&  "${extout[$i]}" != "" ]]
          then
             printf "\n  >>> OUTPUT: ${localout[$i]}  append to"
             printf "\n              ${pathout[$i]}.${extout[$i]}\n"
             cat  ${localout[$i]}  >>  ${pathout[$i]}.${extout[$i]}
          else
             printf "\n  >>> OUTPUT: ${localout[$i]}  append to"
             printf "\n              ${pathout[$i]}\n"
             cat  ${localout[$i]}  >>  ${pathout[$i]}
          fi
       fi

          # COPY ON THIS MACHINE
          # COPY HAS TO BE USED, BECAUSE MOVE DOES NOT WORK IF FILE-ORIGIN AND TARGET ARE
          # ON DIFFERENT FILE-SYSTEMS
       if [[ "${actionout[$i]}" = ""  &&  $files_for_cores = false ]]
       then

             # COPY IN CASE OF RUNS ON SINGLE CORES
          if [[ "${extout[$i]}" != " "  &&  "${extout[$i]}" != "" ]]
          then
             printf "\n  >>> OUTPUT: ${localout[$i]}  to"
             printf "\n              ${pathout[$i]}.${extout[$i]}\n"
             if [[ $link_local_output = true ]]
             then
                printf "      file will be linked\n"
                ln -f  ${localout[$i]}  ${pathout[$i]}.${extout[$i]}
             fi
                # If "ln -f" fails of if "$link_local_output = false" do a normal "cp"
             if [[ ! -f "${pathout[$i]}.${extout[$i]}" ]]
             then
                if [[ $link_local_output = true ]]
                then
                   printf "  --- WARNING: ln failed, using cp instead (might be time consuming...)\n"
                fi
                cp  ${localout[$i]}  ${pathout[$i]}.${extout[$i]}
             else
                printf "+++ no copy because file ${pathout[$i]}.${extout[$i]} exists\n"
             fi
          else
             printf "\n  >>> OUTPUT: ${localout[$i]}  to"
             printf "\n              ${pathout[$i]}\n"
             if [[ $link_local_output = true ]]
             then
                printf "      file will be linked\n"
                ln -f  ${localout[$i]}  ${pathout[$i]}
             fi
                # If "ln -f" fails of if "$link_local_output = false" do a normal "cp"
            	if [[ ! -f "${pathout[$i]}" ]]
             then
                if [[ $link_local_output = true ]]
                then
                   printf "  --- WARNING: ln failed, using cp instead (might be time consuming...)\n"
                fi
                cp  ${localout[$i]}  ${pathout[$i]}
             else
                printf "+++ no copy because file ${pathout[$i]} exists\n"
             fi
          fi

       elif [[ "${actionout[$i]}" = ""  &&  $files_for_cores = true ]]
       then

             # FILES FROM THE DIFFERENT CORES ARE MOVED WITH ln-COMMAND TO THE PERMANENT DIRECTORY
             # AS A FIRST STEP, THE PERMANENT DIRECTORY IS CREATED
          printf "\n  >>> OUTPUT: ${localout[$i]}/_....  to"
          printf "\n              ${pathout[$i]}\n"
          if [[ $link_local_output = true ]]
          then
             printf "      files will be linked\n"
             mkdir -p ${pathout[$i]}
             cd ${localout[$i]}
             for file in $(ls *)
             do
                ln -f $file  ${pathout[$i]}
             done >|/dev/null 2>&1
             cd $tempdir
          fi

             # IF "ln -f" HAS FAILED OR IF "$link_local_output = false" DO A NORMAL COPY "cp -r"
          if [[ ! -f "${pathout[$i]}/_000000" ]]
          then
             if [[ $link_local_output = true ]]
             then
                printf "  --- WARNING: ln failed, using cp instead (might be time consuming...)\n"
             fi
             [[ ! -d "${pathout[$i]}" ]]  &&  mkdir  ${pathout[$i]}
             cp -r  ${localout[$i]}/*  ${pathout[$i]}
    	     fi

       fi
    fi
 done

 if (( i != 0 ))
 then
    if [[ $transfer_problems = true ]]
    then
       printf "\n$dashes\n  *** OUTPUT-files saved"
       printf "\n  +++ WARNING: some data transfers failed! \n"
    else
       printf "\n$dashes\n  *** all OUTPUT-files saved \n"
    fi
 fi




    # ALL ACTIONS FINISHED, TEMPORARY WORKING-DIRECTORY CAN BE DELETED
 cd  -
 [[ $delete_temporary_catalog = true ]]  &&  rm -rf $tempdir
