#!/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 .
#
# Copyright 2017-2021 Leibniz Universitaet Hannover
#--------------------------------------------------------------------------------#
#
# Current revisions:
# ------------------
#
#
# Former revisions:
# -----------------
# $Id$
# initial revision
#
#
#
#--------------------------------------------------------------------------------#
# 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 :"
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 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 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 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 = 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