]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - PWGPP/benchmark/benchmark.sh
ATO-98 more verbose output for benchmark
[u/mrichter/AliRoot.git] / PWGPP / benchmark / benchmark.sh
index e71dd2e63bf73ba07022ba9bc993dbcfa6f7d00b..5dfcf2988f8f60a4b6ea45dbc544588cb7fbe3ba 100755 (executable)
@@ -1,6 +1,7 @@
 #!/bin/bash
 #include benchmark.config
 
+# blame: Mikolaj Krzewicki, mkrzewic@cern.ch
 # this script runs the CPass0/CPass1 train
 # produced OCDB updates are local
 
@@ -78,7 +79,7 @@ goCPass0()
   jobindex=${7}
   shift 7
   if ! parseConfig ${configFile} "$@"; then return 1; fi
-
+  echo Start: goCPass0
   #record the working directory provided by the batch system
   batchWorkingDirectory=${PWD}
 
@@ -154,7 +155,11 @@ goCPass0()
 
   #runCPassX/C expects the raw chunk to be linked in the run dir
   #despite it being accessed by the full path
-  ln -s ${infile} ${runpath}/${chunkName}
+  if [[ $copyInputData == 0 ]]; then
+    ln -s ${infile} ${runpath}/${chunkName}
+  else
+    copyFileToLocal ${infile} ${runpath}/${chunkName}
+  fi
 
   #####MC
   if [[ -n ${generateMC} ]]; then
@@ -190,7 +195,7 @@ goCPass0()
   fi
   ######
   
-  if [[ ! -f ${inputList} && -z ${pretend} ]]; then
+  if [[ "${inputList}" == "${inputList%%://*}" && ! -f "${inputList}" && -z ${pretend} ]]; then
     touch ${doneFileTmp}
     echo "input file ${inputList} not found, exiting..." >> ${doneFileTmp}
     cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
@@ -247,6 +252,9 @@ goCPass0()
   echo
   chmod u+x runCPass0.sh
 
+  #remove spaces from around arguments to root macros
+  #for example this sometimes fails: 
+  #  root 'macro.C(argument1, argument2)'
   sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh
 
   if [[ -n ${postSetUpActionCPass0} ]]; then
@@ -255,7 +263,7 @@ goCPass0()
   fi
 
   #run CPass0
-  echo "${runpath}/runCPass0.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
+  echo "${runpath}/runCPass0.sh /${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
   if [[ -n ${pretend} ]]; then
     sleep ${pretendDelay}
     touch AliESDs.root
@@ -264,8 +272,8 @@ goCPass0()
     touch rec.log
     touch calib.log
   else
-    echo ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
-    ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
+    #caveat: in the local case, first arg must start with a slash
+    ./runCPass0.sh "/${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
   fi
   
   #move stuff to final destination
@@ -282,8 +290,6 @@ goCPass0()
   
   #validate CPass0
   cd ${outputDir}
-  touch ${doneFileTmp}
-  echo "dir ${outputDir}" >> ${doneFileTmp}
   if summarizeLogs >> ${doneFileTmp}; then
     [[ -f ${outputDirMC}/galice.root ]] && echo "sim ${outputDirMC}/galice.root" >> ${doneFileTmp}
     [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFileTmp}
@@ -293,6 +299,7 @@ goCPass0()
   [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath} && echo "removing ${runpath}"
   cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
   [[ -n ${removeTMPdoneFile} ]] && rm -f ${doneFileTmp}
+  echo End: goCPass0
   return 0
 )
 
@@ -310,6 +317,7 @@ goCPass1()
   shift 7
   extraOpts=("$@")
   if ! parseConfig ${configFile} "$@"; then return 1; fi
+  echo Start: goCPass1
 
   #record the working directory provided by the batch system
   batchWorkingDirectory=${PWD}
@@ -348,7 +356,7 @@ goCPass1()
   #Packages= ;OutputDir= ;LPMPass= ;TriggerAlias= ;LPMRunNumber= ;LPMProductionType= ;LPMInteractionType= ;LPMProductionTag= ;LPMAnchorRun= ;LPMAnchorProduction= ;LPMAnchorYear= 
   export PRODUCTION_METADATA="OutputDir=cpass1"
 
-  if [[ ! -f ${inputList} && -z ${pretend} ]]; then
+  if [[ "${inputList}" == "${inputList%%://*}" && ! -f "${inputList}" && -z ${pretend} ]]; then
     touch ${doneFileTmp}
     echo "input file ${inputList} not found, exiting..." >> ${doneFileTmp}
     cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
@@ -400,7 +408,11 @@ goCPass1()
   fi
 
   #this is needed for runCPass1.sh
-  ln -s ${infile} ${runpath}/${chunkName}
+  if [[ $copyInputData == 0 ]]; then
+    ln -s ${infile} ${runpath}/${chunkName}
+  else
+    copyFileToLocal ${infile} ${runpath}/${chunkName}
+  fi
 
   logOutputDir=${runpath}
   [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
@@ -457,7 +469,9 @@ goCPass1()
   /bin/ls
   echo
 
-  #remove spaces around commas from calls to root
+  #remove spaces from around arguments to root macros
+  #for example this sometimes fails: 
+  #  root 'macro.C(argument1, argument2)'
   sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh
 
   if [[ -n ${postSetUpActionCPass1} ]]; then
@@ -504,7 +518,7 @@ goCPass1()
 
   #run CPass1
   chmod u+x runCPass1.sh
-  echo "${runpath}/runCPass1.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
+  echo "${runpath}/runCPass1.sh /${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
   if [[ -n ${pretend} ]]; then
     sleep ${pretendDelay}
     touch AliESDs_Barrel.root
@@ -522,7 +536,8 @@ goCPass1()
     touch qa.log
     touch filtering.log FilterEvents_Trees.root
   else
-    ./runCPass1.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
+    #caveat: in the local case, first arg must start with a slash
+    ./runCPass1.sh "/${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
     
     [[ ! -f AliESDs_Barrel.root && -f Barrel/AliESDs.root ]] && mv Barrel/AliESDs.root AliESDs_Barrel.root
     [[ ! -f AliESDfriends_Barrel.root && -f Barrel/AliESDfriends.root ]] && mv Barrel/AliESDfriends.root AliESDfriends_Barrel.root
@@ -576,8 +591,6 @@ goCPass1()
 
   #validate CPass1
   cd ${outputDir}
-  touch ${doneFileTmp}
-  echo "dir ${outputDir}" >> ${doneFileTmp}
   if summarizeLogs >> ${doneFileTmp}; then
     [[ -f AliESDs_Barrel.root ]] && echo "esd ${outputDir}/AliESDs_Barrel.root" >> ${doneFileTmp}
     [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFileTmp}
@@ -603,6 +616,7 @@ goCPass1()
   [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
   cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
   [[ -n ${removeTMPdoneFile} ]] && rm -f ${doneFileTmp}
+  echo End: goCPass1
   return 0
 )
 
@@ -620,6 +634,7 @@ goMergeCPass0()
   calibrationFilesToMerge=${5}  #can be a non-existent file, will then be produced on the fly
   shift 5
   if ! parseConfig ${configFile} "$@"; then return 1; fi
+  echo Start: goMergeCPass0
 
   #record the working directory provided by the batch system
   batchWorkingDirectory=${PWD}
@@ -691,6 +706,9 @@ goMergeCPass0()
     [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
   done
   
+  #remove spaces from around arguments to root macros
+  #for example this sometimes fails: 
+  #  root 'macro.C(argument1, argument2)'
   sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh
 
   alirootInfo > ALICE_ROOT.log
@@ -710,7 +728,7 @@ goMergeCPass0()
     /bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root 2>/dev/null > ${calibrationFilesToMerge}
   fi
   
-  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB ${ocdbStorage}"
+  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB defaultOCDB=${ocdbStorage} fileAccessMethod=nocopy"
   if [[ -n ${pretend} ]]; then
     sleep ${pretendDelay}
     touch CalibObjects.root
@@ -722,7 +740,7 @@ goMergeCPass0()
     echo "some calibration" >> ./OCDB/TPC/Calib/TimeGain/someCalibObject_0-999999_cpass0.root
     echo "some calibration" >> ./OCDB/TPC/Calib/TimeDrift/otherCalibObject_0-999999_cpass0.root
   else
-    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage} >> "mergeMakeOCDB.log"
+    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" defaultOCDB=${ocdbStorage} fileAccessMethod=nocopy >> "mergeMakeOCDB.log"
 
     #produce the calib trees for expert QA (dcsTime.root)
     goMakeLocalOCDBaccessConfig ./OCDB
@@ -753,8 +771,6 @@ goMergeCPass0()
 
   #validate merging cpass0
   cd ${outputDir}
-  touch ${doneFileTmp}
-  echo "dir ${outputDir}" >> ${doneFileTmp}
   if summarizeLogs >> ${doneFileTmp}; then
     [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFileTmp}
     [[ -f dcsTime.root ]] && echo "dcsTree ${outputDir}/dcsTime.root" >> ${doneFileTmp}
@@ -763,6 +779,7 @@ goMergeCPass0()
   [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
   cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
   [[ -n ${removeTMPdoneFile} ]] && rm -f ${doneFileTmp}
+  echo End: goMergeCPass0
   return 0
 )
 
@@ -781,6 +798,7 @@ goMergeCPass1()
   filteredFilesToMerge=${7}
   shift 7
   if ! parseConfig ${configFile} "$@"; then return 1; fi
+  echo Start: goMergeCPass1
 
   #record the working directory provided by the batch system
   batchWorkingDirectory=${PWD}
@@ -867,6 +885,9 @@ goMergeCPass1()
     [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
   done
 
+  #remove spaces from around arguments to root macros
+  #for example this sometimes fails: 
+  #  root 'macro.C(argument1, argument2)'
   sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh
 
   #configure local OCDB storage from CPass0 (creates the localOCDBaccessConfig.C script)
@@ -900,8 +921,8 @@ goMergeCPass1()
     echo "/bin/ls -1 ${outputDir}/*/QAresults*.root | while read x; do echo ${x%/*}; done | sort | uniq > ${qaFilesToMerge}"
     /bin/ls -1 ${outputDir}/*/QAresults*.root | while read x; do echo ${x%/*}; done | sort | uniq > ${qaFilesToMerge}
   fi
-  
-  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB ${ocdbStorage}"
+
+  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB defaultOCDB=${ocdbStorage} fileAccessMethod=nocopy"
   if [[ -n ${pretend} ]]; then
     sleep ${pretendDelay}
     touch ocdb.log
@@ -915,7 +936,7 @@ goMergeCPass1()
     touch ${qaMergedOutputFileName}
     mkdir -p OCDB
   else
-    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage}
+    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" defaultOCDB=${ocdbStorage} fileAccessMethod=nocopy
 
     #merge QA (and filtered trees)
     [[ -n ${AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF} ]] && export AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF
@@ -952,8 +973,6 @@ goMergeCPass1()
   
   #validate merge cpass1
   cd ${outputDir}
-  touch ${doneFileTmp}
-  echo "dir ${outputDir}" >> ${doneFileTmp}
   if summarizeLogs >>  ${doneFileTmp}; then
     [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFileTmp}
     [[ -f ${qaMergedOutputFileName} ]] && echo "qafile ${outputDir}/${qaMergedOutputFileName}" >> ${doneFileTmp}
@@ -972,6 +991,7 @@ goMergeCPass1()
   [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
   cp "$doneFileTmp" "$doneFile" || rm -f "$doneFileTmp" "$doneFile"
   [[ -n ${removeTMPdoneFile} ]] && rm -f ${doneFileTmp}
+  echo End: goMergeCPass1
   return 0
 )
 
@@ -1032,9 +1052,9 @@ goSubmitMakeflow()
   #if which greadlink; then self=$(greadlink -f "${0}"); fi
   
   #for reference copy the setup to the output dir
-  cp ${self} ${commonOutputPath}
-  cp ${configFile} ${commonOutputPath}
-  cp ${inputFileList} ${commonOutputPath}
+  paranoidCp ${self} ${commonOutputPath}
+  paranoidCp ${configFile} ${commonOutputPath}
+  paranoidCp ${inputFileList} ${commonOutputPath}
 
   #submit - use makeflow if available, fall back to old stuff when makeflow not there
   if which makeflow; then
@@ -1044,6 +1064,15 @@ goSubmitMakeflow()
   else 
     echo "no makeflow!"
   fi
+  
+  #summarize the run based on the makeflow log
+  #and add it to the end of summary log
+  awk '/STARTED/   {startTime=$3} 
+       /COMPLETED/ {endTime=$3} 
+       END         {print "makeflow running time: "(endTime-startTime)/1000000/3600" hours"}' \
+      benchmark.makeflow.makeflowlog | tee -a summary.log
+  paranoidCp summary.log ${commonOutputPath}
+
   return 0
 }
 
@@ -1435,6 +1464,9 @@ summarizeLogs()
             "stderr"
   )
 
+  #put dir information in the output
+  echo "dir $PWD"
+
   #check logs
   local logstatus=0
   for log in ${logFiles[*]}; do
@@ -1591,7 +1623,6 @@ EOF
   fi
   pwd
   /bin/ls
-  touch ${doneFile}
   summarizeLogs >>  ${doneFile}
   
   #echo mv -f * ${outputDir}
@@ -2063,7 +2094,8 @@ goSubmitBatch()
   echo "submit make a summary"
   echo
 
-  submit "${JOBID6}" 1 1 "${LASTJOB}" "${alirootEnv} ${self}" MakeSummary ${configFile}
+  [[ -z ${alirootEnvQA} ]] && alirootEnvQA=$(encSpaces "${alirootEnv}")
+  submit "${JOBID6}" 1 1 "${LASTJOB}" "${alirootEnvQA} ${self}" MakeSummary ${configFile} "commonOutputPath=${commonOutputPath}"
   LASTJOB=${JOBID6}
   #################################################################################
   
@@ -2077,6 +2109,7 @@ goWaitForOutput()
 (
   umask 0002
   [[ $# -lt 3 ]] && echo "goWaitForOutput() wrong number of arguments, exiting.." && return 1
+  echo Start:goWaitForOutput
   echo searchPath=${1}
   echo fileName=${2}
   echo numberOfFiles=${3}
@@ -2095,6 +2128,7 @@ goWaitForOutput()
     sleep 60
   done
   echo "DONE! exiting..."
+  echo End:goWaitForOutput
   return 0
 )
 
@@ -2195,11 +2229,17 @@ EOF
 
 stackTraceTree()
 (
-  # make stacktrace processing  in case of standard root crash log
-  # input is a (list of) text files with the stack trace (either gdb aoutput
-  # produced with e.g. gdb --batch --quiet -ex "bt" -ex "quit" aliroot core, or the root crash log), output is a TTree formatted table.
-# example usage:
-# benchmark.sh stackTraceTree /foo/*/rec.log
+  if [[ $# -lt 1 ]]; then
+    echo 'make stacktrace processing  in case of standard root crash log'
+    echo 'input is a (list of) text files with the stack trace (either gdb aoutput'
+    echo 'produced with e.g. gdb --batch --quiet -ex "bt" -ex "quit" aliroot core,'
+    echo 'or the root crash log), output is a TTree formatted table.'
+    echo 'example usage:'
+    echo 'benchmark.sh stackTraceTree /foo/*/rec.log'
+    echo 'benchmark.sh stackTraceTree $(cat file.list)'
+    echo 'benchmark.sh stackTraceTree `cat file.list`'
+    return 0
+  fi
   gawk '
        BEGIN { 
                print "frame/I:method/C:line/C:cpass/I:aliroot/I:file/C";
@@ -2227,6 +2267,7 @@ goMakeSummary()
   # will appear in the submission dir.
   #some defaults:
   log="summary.log"
+  jsonLog="summary.json"
   productionID="qa"
 
   configFile=${1}
@@ -2239,8 +2280,8 @@ goMakeSummary()
   #record the working directory provided by the batch system
   batchWorkingDirectory=${PWD}
 
-  logTmp=${batchWorkingDirectory}/${log}
-  logDest=${commonOutputPath}/${log}
+  logTmp="${batchWorkingDirectory}/${log}"
+  jsonLogTmp="${batchWorkingDirectory}/${jsonLog}"
   
   [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}
 
@@ -2249,8 +2290,7 @@ goMakeSummary()
   [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
 
   #copy some useful stuff
-  #and go to the commonOutputPath
-  cp ${configFile} ${commonOutputPath}
+  [ -f "${commonOutputPath}/${configFile}" ] || paranoidCp "${configFile}" "${commonOutputPath}"
 
   exec &> >(tee ${logTmp})
 
@@ -2263,6 +2303,9 @@ goMakeSummary()
   stackTraceTree ${commonOutputPath}/*/*/000*/cpass0/*/stacktrace* > stacktrace_cpass0.tree
   stackTraceTree ${commonOutputPath}/*/*/000*/cpass1/*/stacktrace* > stacktrace_cpass1.tree
 
+  # json header: open array of objects
+  echo '[' > "${jsonLogTmp}"
+
   echo total numbers for the production:
   echo
   awk 'BEGIN {nFiles=0;nCore=0;} 
@@ -2355,8 +2398,38 @@ do
   statusQA=$(awk '/mergeMakeOCDB.log/ {print $2}' ${x/cpass0/cpass1} 2>/dev/null)
 
   printf "%s\t ocdb.log cpass0: %s\t ocdb.log cpass1: %s\tqa.log:%s\t| cpass0: rec:%s/%s stderr:%s/%s calib:%s/%s cpass1: rec:%s/%s stderr:%s/%s calib:%s/%s QAbarrel:%s/%s QAouter:%s/%s\n" ${runNumber} ${statusOCDBcpass0} ${statusOCDBcpass1} ${statusQA} ${statusCPass0[0]} ${statusCPass0[1]} ${statusCPass0[2]} ${statusCPass0[3]} ${statusCPass0[4]} ${statusCPass0[5]} ${statusCPass1[0]} ${statusCPass1[1]} ${statusCPass1[2]} ${statusCPass1[3]} ${statusCPass1[4]} ${statusCPass1[5]} ${statusCPass1[6]} ${statusCPass1[7]} ${statusCPass1[8]} ${statusCPass1[9]}
+
+  # produce json summary
+  statusOCDBcpass0json=false
+  statusOCDBcpass1json=false
+  statusQAjson=false
+  [[ "$statusOCDBcpass0" == 'OK' ]] && statusOCDBcpass0json=true
+  [[ "$statusOCDBcpass1" == 'OK' ]] && statusOCDBcpass1json=true
+  [[ "$statusQA" == 'OK' ]] && statusQAjson=true
+  cat >> "$jsonLogTmp" <<EOF
+  {
+    run: ${runNumber},
+    status: { ocdb_pass0: ${statusOCDBcpass0json}, ocdb_pass1: ${statusOCDBcpass1json}, qa: ${statusQAjson} },
+    cpass0: {
+      reco: { n_ok: ${statusCPass0[0]}, n_bad: ${statusCPass0[1]} },
+      stderr: { n_ok: ${statusCPass0[2]}, n_bad: ${statusCPass0[3]} },
+      calib: { n_ok: ${statusCPass0[4]}, n_bad: ${statusCPass0[5]} }
+    },
+    cpass1: {
+      reco: { n_ok: ${statusCPass1[0]}, n_bad: ${statusCPass1[1]} },
+      stderr: { n_ok: ${statusCPass1[2]}, n_bad: ${statusCPass1[3]} },
+      calib: { n_ok: ${statusCPass1[4]}, n_bad: ${statusCPass1[5]} },
+      qabarrel: { n_ok: ${statusCPass1[6]}, n_bad: ${statusCPass1[7]} },
+      qarouter: { n_ok: ${statusCPass1[8]}, n_bad: ${statusCPass1[9]} }
+    }
+  },
+EOF
+
 done
 
+  # json footer: close array of objects
+  echo ']' >> "${jsonLogTmp}"
+
   #make lists with output files - QA, trending, filtering and calibration
   ### wait for the merging of all runs to be over ###
   rm -f qa.list
@@ -2387,14 +2460,17 @@ done
   #if set, email the summary
   [[ -n ${MAILTO} ]] && cat ${logTmp} | mail -s "benchmark ${productionID} done" ${MAILTO}
 
-  # Copy log to destination (delete all on failure to signal error)
-  cp "$logTmp" "$logDest" || rm -f "$logTmp" "$logDest"
+  #copy logs to destination
+  paranoidCp "$logTmp" "${commonOutputPath}"
+  paranoidCp "$jsonLogTmp" "${commonOutputPath}"
   
   #copy output files
+  exec &> >(tee fileCopy.log)
   paranoidCp QAplots ${commonOutputPath}
   paranoidCp *.list ${commonOutputPath}
   paranoidCp *.root ${commonOutputPath}
   paranoidCp *.log ${commonOutputPath}
+  paranoidCp fileCopy.log ${commonOutputPath}
 
   return 0
 )
@@ -2503,6 +2579,7 @@ goMakeSummaryTree()
 
 parseConfig()
 {
+  echo Start: parseConfig
   configFile=${1}
   shift
   args=("$@")
@@ -2543,6 +2620,7 @@ parseConfig()
   logToFinalDestination=1
   ALIROOT_FORCE_COREDUMP=1
   pretendDelay=0
+  copyInputData=0
 
   #first, source the config file
   if [ -f ${configFile} ]; then
@@ -2577,7 +2655,7 @@ parseConfig()
 
   #export the aliroot function if defined to override normal behaviour
   [[ $(type -t aliroot) =~ "function" ]] && export -f aliroot && echo "exporting aliroot() function..."
-
+  echo End: parseConfig
   return 0
 }
 
@@ -2599,6 +2677,60 @@ aliroot()
   return 0
 }
 
+copyFileToLocal()
+(
+  #copies a single file to a local destination: the file may either come from
+  #a local filesystem or from a remote location (whose protocol must be
+  #supported)
+  #copy is "robust" and it is repeated some times in case of failure before
+  #giving up (1 is returned in that case)
+  src="$1"
+  dst="$2"
+  ok=0
+  [[ -z "${maxCopyTries}" ]] && maxCopyTries=10
+
+  proto="${src%%://*}"
+
+  echo "copy file to local dest started: $src -> $dst"
+
+  for (( i=1 ; i<=maxCopyTries ; i++ )) ; do
+
+    echo "...attempt $i of $maxCopyTries"
+    rm -f "$dst"
+
+    if [[ "$proto" == "$src" ]]; then
+      cp "$src" "$dst"
+    else
+      case "$proto" in
+        root)
+          xrdcp -f "$src" "$dst"
+        ;;
+        http)
+          curl -L "$src" -O "$dst"
+        ;;
+        *)
+          echo "protocol not supported: $proto"
+          return 2
+        ;;
+      esac
+    fi
+
+    if [ $? == 0 ] ; then
+      ok=1
+      break
+    fi
+
+  done
+
+  if [[ "$ok" == 1 ]] ; then
+    echo "copy file to local dest OK after $i attempt(s): $src -> $dst"
+    return 0
+  fi
+
+  echo "copy file to local dest FAILED after $maxCopyTries attempt(s): $src -> $dst"
+  return 1
+)
+
 paranoidCp()
 (
   #recursively copy files and directories
@@ -2624,22 +2756,36 @@ paranoidCopyFile()
 (
   #copy a single file to a target in an existing dir
   #repeat a few times if copy fails
+  #returns 1 on failure, 0 on success
   src="${1}"
   dst="${2}"
+  ok=0
   [[ -d "${dst}" ]] && dst="${dst}/${src##*/}"
-  [[ -z "${maxCopyTries}" ]] && maxCopyTries=5
-  echo "maxCopyTries=${maxCopyTries}"
-  echo "cp ${src} ${dst}"
-  cp "${src}" "${dst}"
-  i=0
-  until cmp -s "${src}" "${dst}"; do
-    echo "try: ${i}"
-    [[ -f "${dst}" ]] && rm "${dst}"
-    cp "${src}" "${dst}"
-    [[ ${i} -gt ${maxCopyTries} ]] && ret=1 && return 1
-    (( i++ ))
+  [[ -z "${maxCopyTries}" ]] && maxCopyTries=10
+
+  echo "paranoid copy started: $src -> $dst"
+
+  for (( i=1 ; i<=maxCopyTries ; i++ )) ; do
+
+    echo "...attempt $i of $maxCopyTries"
+    rm -f "$dst"
+    cp "$src" "$dst"
+
+    cmp -s "$src" "$dst"
+    if [ $? == 0 ] ; then
+      ok=1
+      break
+    fi
+
   done
-  return 0
+
+  if [[ "$ok" == 1 ]] ; then
+    echo "paranoid copy OK after $i attempt(s): $src -> $dst"
+    return 0
+  fi
+
+  echo "paranoid copy FAILED after $maxCopyTries attempt(s): $src -> $dst"
+  return 1
 )
 
 guessRunData()