<commit_before>#!/bin/bash
#include benchmark.config

# this script runs the CPass0/CPass1 train
# produced OCDB updates are local

main()
{
  #run in proper mode depending on the selection
  if [[ $# -lt 1 ]]; then
    if [[ ! "${0}" =~ "bash" ]]; then
      echo "uses makeflow:"
      echo " ${0} \"run\" productionID inputList configFile [extraOpts]"
      echo "uses a batch system (SGE):"
      echo " ${0} \"submit\" productionID inputList configFile [extraOpts]"
      echo "extraOpts if non-empty override the config file, e.g.:"
      echo " ${0} submit test1 benchmark.list benchmark.config runNumber=169123 nEvents=10"
    fi
    return
  fi

  #define some aliases - default is to call one of the functions directly
  runMode=${1}
  umask 0002
  shift
  case ${runMode} in
    "CPass0") goCPass0 "$@";;
    "CPass1") goCPass1 "$@";;
    "MakeLocalOCDBaccessConfig") goMakeLocalOCDBaccessConfig "$@";;
    "MergeCPass0") goMergeCPass0 "$@";;
    "MergeCPass1") goMergeCPass1 "$@";;
    "MakeFilteredTrees") goMakeFilteredTrees "$@";;
    "MakeSummary") goMakeSummary "$@";;
    "run") goSubmitMakeflow "$@";;
    "submit") goSubmitBatch "$@";;
    "test") goTest "$@";;
    "GenerateMakeflow") goGenerateMakeflow "$@";;
    "PrintValues") goPrintValues "$@";;
    "CreateQAplots") goCreateQAplots "$@";;
    "WaitForOutput") goWaitForOutput "$@";;
    "Merge") goMerge "$@";;
    *) 
      ${runMode} "$@"
    ;;
  esac
  return 0
}

generateMC()
{
  #generate one raw chunk in current directory
  SEED=${JOB_ID}${SGE_TASK_ID}
  export CONFIG_SEED=${SEED}
  runNumber=${1}
  OCDBpath=${2}
  nEventsim=${3}
  if [[ -n ${pretend} ]]; then
    touch galice.root
  else
    if [[ -f sim.C && -f Config.C ]] ; then
        time aliroot -b -q -x sim.C\(${runNumber},\"${OCDBpath}\",${nEventsim}\) >sim.log 2>&1
        mv syswatch.log simwatch.log
    fi
  fi
}

goCPass0()
{
  umask 0002
  
  targetDirectory=${1}
  inputList=${2}
  nEvents=${3}
  ocdbPath=${4}
  configFile=${5}
  runNumber=${6}
  jobindex=${7}
  shift 7
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  #use the jobindex only if set and non-negative
  if [[ -z ${jobindex} || ${jobindex} -lt 0 ]]; then
    [[ -n "${LSB_JOBINDEX}" ]] && jobindex=${LSB_JOBINDEX}
    [[ -n "${SGE_TASK_ID}" ]] && jobindex=${SGE_TASK_ID}
  fi

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/cpass0.job${jobindex}.run${runNumber}.done"

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}
  
  if [[ -n ${ALIROOT_FORCE_COREDUMP} ]]; then
    ulimit -c unlimited 
    export ALIROOT_FORCE_COREDUMP
  fi

  #the contents of this is stored in the tree and used later (e.g. AliAnalysisTaskPIDResponse)!
  #at the QA stage the pass number is guessed from the path stored here.
  #The Format is:
  #Packages= ;OutputDir= ;LPMPass= ;TriggerAlias= ;LPMRunNumber= ;LPMProductionType= ;LPMInteractionType= ;LPMProductionTag= ;LPMAnchorRun= ;LPMAnchorProduction= ;LPMAnchorYear= 
  export PRODUCTION_METADATA="OutputDir=cpass0"

  if [[ "${inputList}" =~ \.root$ ]]; then
    infile=${inputList}
  else
    infile=$(sed -ne "${jobindex}p" ${inputList} | egrep '\s*\w*/\w*')
  fi
  chunkName=${infile##*/}

  outputDir=${targetDirectory}/${jobindex}_${chunkName%.*}
  mkdir -p ${outputDir}
  [[ ! -d ${outputDir} ]] && echo "cannot make ${outputDir}" && touch ${doneFile} && return 1  
  
  #runpath=${PWD}/rundir_cpass0_${runNumber}_${jobindex}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)
  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "cannot make runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  #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}

  #####MC
  if [[ -n ${generateMC} ]]; then
    olddir=${PWD}
    outputDirMC=${commonOutputPath}/000${runNumber}/sim/${jobindex}
    simrunpath=${outputDirMC}
    [[ ${simulateInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && simrunpath=${TMPDIR}
    [[ ${simulateInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && simrunpath=$(mktemp -d)
    mkdir -p ${outputDirMC}
    mkdir -p ${simrunpath}
    cd ${simrunpath}

    filesMC=( 
              "${batchWorkingDirectory}/sim.C"
              "${batchWorkingDirectory}/rec.C"
              "${batchWorkingDirectory}/Config.C"
              "${batchWorkingDirectory}/OCDB_*.root"
    )
    for file in ${filesMC[*]}; do
      [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    done

    generateMC ${runNumber} ${ocdbPath} ${nEvents}

    [[ ! "${simrunpath}" =~ "${outputDirMC}" ]] && mv * ${outputDirMC} #TODO check if it works
    cd ${olddir}
    
    ln -s ${outputDirMC}/* ${runpath}/ 
    
    inputList=${outputDirMC}/galice.root #TODO not valid outside shell !!!
    infile=""
  fi
  ######
  
  [[ ! -f ${inputList} && -z ${pretend} ]] && echo "input file ${inputList} not found, exiting..." && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 1> ${logOutputDir}/stdout
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 2> ${logOutputDir}/stderr
  echo "${0} $*"

  echo "#####################"
  echo CPass0:
  echo JOB setup
  echo nEvents            ${nEvents}
  echo runNumber          ${runNumber}
  echo ocdbPath           ${ocdbPath}
  echo infile             ${infile}
  echo chunkName          ${chunkName}
  echo jobindex           ${jobindex}
  echo recoTriggerOptions ${recoTriggerOptions}
  echo targetDirectory    ${targetDirectory}
  echo commonOutputPath         ${commonOutputPath}
  echo doneFile      ${doneFile}
  echo runpath            ${runpath}  
  echo outputDir          ${outputDir}
  echo ALICE_ROOT         ${ALICE_ROOT}
  echo PWD                ${PWD}
  echo "########## ###########"

  alirootInfo > ALICE_ROOT.log

  filesCPass0=( 
               "${batchWorkingDirectory}/runCPass0.sh"
               "${batchWorkingDirectory}/recCPass0.C"
               "${batchWorkingDirectory}/runCalibTrain.C"
               "${batchWorkingDirectory}/localOCDBaccessConfig.C"
               "${batchWorkingDirectory}/OCDB.root"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/runCPass0.sh"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/recCPass0.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/runCalibTrain.C"
  )

  for file in ${filesCPass0[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo
  chmod u+x runCPass0.sh

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  if [[ -n ${postSetUpActionCPass0} ]]; then
    echo "running ${postSetUpActionCPass0}"
    eval ${postSetUpActionCPass0}
  fi

  #run CPass0
  echo "${runpath}/runCPass0.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
  if [[ -n ${pretend} ]]; then
    touch AliESDs.root
    touch AliESDfriends.root
    touch AliESDfriends_v1.root
    touch rec.log
    touch calib.log
  else
    echo ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
    ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
  fi
  
  #move stuff to final destination
  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo

  echo rm -f ./${chunkName}
  rm -f ./${chunkName}
  echo "cp --recursive ${runpath}/* ${outputDir}"
  cp -p --recursive ${runpath}/* ${outputDir}
  echo
  
  #validate CPass0
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f ${outputDirMC}/galice.root ]] && echo "sim ${outputDirMC}/galice.root" >> ${doneFile}
    [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFile}
    [[ -f AliESDs.root ]] && echo "esd ${outputDir}/AliESDs.root" >> ${doneFile}
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goCPass1()
{
  umask 0002
  
  targetDirectory=${1}
  inputList=${2}
  nEvents=${3}
  ocdbPath=${4}
  configFile=${5}
  runNumber=${6}
  jobindex=${7}
  shift 7
  extraOpts=("$@")
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  #use the jobindex only if set and non-negative
  if [[ -z ${jobindex} || ${jobindex} -lt 0 ]]; then
    [[ -n "${LSB_JOBINDEX}" ]] && jobindex=${LSB_JOBINDEX}
    [[ -n "${SGE_TASK_ID}" ]] && jobindex=${SGE_TASK_ID}
  fi

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/cpass1.job${jobindex}.run${runNumber}.done"

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}
  
  if [[ -n ${ALIROOT_FORCE_COREDUMP} ]]; then
    ulimit -c unlimited 
    export ALIROOT_FORCE_COREDUMP
  fi

  #the contents of this is stored in the tree and used later (e.g. AliAnalysisTaskPIDResponse)!
  #at the QA stage the pass number is guessed from the path stored here.
  #The Format is:
  #Packages= ;OutputDir= ;LPMPass= ;TriggerAlias= ;LPMRunNumber= ;LPMProductionType= ;LPMInteractionType= ;LPMProductionTag= ;LPMAnchorRun= ;LPMAnchorProduction= ;LPMAnchorYear= 
  export PRODUCTION_METADATA="OutputDir=cpass1"

  [[ ! -f ${inputList} && -z ${pretend} ]] && echo "input file ${inputList} not found, exiting..." && touch ${doneFile} && return 1
  if [[ "${inputList}" =~ \.root$ ]]; then
    infile=${inputList}
  else
    infile=$(sed -ne "${jobindex}p" ${inputList} | egrep '\s*\w*/\w*')
  fi
  chunkName=${infile##*/}

  outputDir=${targetDirectory}/${jobindex}_${chunkName%.*}
  mkdir -p ${outputDir}
  [[ ! -d ${outputDir} ]] && echo "cannot make ${outputDir}" && touch ${doneFile} && return 1
  
  #runpath=${PWD}/rundir_cpass1_${runNumber}_${jobindex}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  #MC
  if [[ "${infile}" =~ galice\.root ]]; then
    ln -s ${inputList%/*}/* ${runpath}
    infile=""
  fi

  #init the running path
  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "cannot make runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  #this is needed for runCPass1.sh
  ln -s ${infile} ${runpath}/${chunkName}

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 1> ${logOutputDir}/stdout
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 2> ${logOutputDir}/stderr
  echo "${0} $*"

  echo "#####################"
  echo CPass1:
  echo JOB setup
  echo nEvents            ${nEvents}
  echo runNumber          ${runNumber}
  echo ocdbPath           ${ocdbPath}
  echo infile             ${infile}
  echo chunkName          ${chunkName}
  echo jobindex           ${jobindex}
  echo recoTriggerOptions ${recoTriggerOptions}
  echo targetDirectory    ${targetDirectory}
  echo commonOutputPath         ${commonOutputPath}
  echo doneFile      ${doneFile}
  echo runpath            ${runpath}  
  echo outputDir          ${outputDir}
  echo ALICE_ROOT         ${ALICE_ROOT}
  echo PWD                ${PWD}
  echo "########## ###########"

  alirootInfo > ALICE_ROOT.log

  filesCPass1=( 
               "${batchWorkingDirectory}/runCPass1.sh"
               "${batchWorkingDirectory}/recCPass1.C"
               "${batchWorkingDirectory}/recCPass1_OuterDet.C"
               "${batchWorkingDirectory}/runCalibTrain.C"
               "${batchWorkingDirectory}/QAtrain_duo.C"
               "${batchWorkingDirectory}/localOCDBaccessConfig.C"
               "${commonOutputPath}/meta/cpass0.localOCDB.${runNumber}.tgz"
               "${batchWorkingDirectory}/OCDB.root"
               "${trustedQAtrainMacro}"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/runCPass1.sh"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/recCPass1.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/recCPass1_OuterDet.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/runCalibTrain.C"
               "${ALICE_ROOT}/ANALYSIS/macros/QAtrain_duo.C"
  )

  for file in ${filesCPass1[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  if [[ -n ${postSetUpActionCPass1} ]]; then
    echo "running ${postSetUpActionCPass1}"
    eval ${postSetUpActionCPass1}
    echo
  fi

  #configure local OCDB storage from CPass0 (creates the localOCDBaccessConfig.C script)
  if [[ -f cpass0.localOCDB.${runNumber}.tgz ]]; then
    echo goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
    goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
  else
    echo "WARNING: file cpass0.localOCDB.${runNumber}.tgz not found!"
  fi

  if [[ ! $(/bin/ls -1 OCDB/*/*/*/*.root 2>/dev/null) ]]; then
    echo "cpass0 produced no calibration! exiting..."
    touch ${doneFile}
    return 1
  fi

  #create the Barrel and OuterDet directories for CPass1 and link the local OCDB directory
  #there to make the localOCDBaccessConfig.C file work, since it may point to the OCDB
  #entries using a relative path, e.g. local://./OCDB
  mkdir Barrel OuterDet
  ln -s ../OCDB Barrel/OCDB
  ln -s ../OCDB OuterDet/OCDB

  #setup the filtering
  #the following option enables the filtering task inside the QAtrain_duo.C
  [[ -n $runESDfiltering ]] && export QA_TaskFilteredTree=1
  #set the downscaling factors during the filtering fro expert QA (overrides the previous values)
  if [[ -n ${filteringFactorHighPt} ]]; then
    export AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF=${filteringFactorHighPt}
  fi
  if [[ -n ${filteringFactorV0s} ]]; then
    export AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF=${filteringFactorV0s} 
  fi

  #run CPass1
  chmod u+x runCPass1.sh
  echo "${runpath}/runCPass1.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
  if [[ -n ${pretend} ]]; then
    touch AliESDs_Barrel.root
    touch AliESDfriends_Barrel.root
    touch AliESDfriends_v1.root
    touch QAresults_barrel.root
    touch EventStat_temp_barrel.root
    touch AODtpITS.root
    touch AliESDs_Outer.root
    touch AliESDfriends_Outer.root
    touch QAresults_outer.root
    touch EventStat_temp_outer.root
    touch rec.log
    touch calib.log
    touch qa.log
    touch filtering.log FilterEvents_Trees.root
  else
    ./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
    [[ ! -f AliESDfriends_v1.root && -f Barrel/AliESDfriends_v1.root ]] && mv Barrel/AliESDfriends_v1.root .
    [[ ! -f QAresults_barrel.root && -f Barrel/QAresults_barrel.root ]] && mv Barrel/QAresults_barrel.root .
    [[ ! -f AliESDs_Outer.root && -f OuterDet/AliESDs.root ]] && mv OuterDet/AliESDs.root AliESDs_Outer.root
    [[ ! -f AliESDfriends_Outer.root && -f OuterDet/AliESDfriends.root ]] && mv OuterDet/AliESDfriends.root AliESDfriends_Outer.root
    [[ ! -f QAresults_outer.root && -f OuterDet/QAresults_outer.root ]] && mv OuterDet/QAresults_outer.root .
    [[ ! -f FilterEvents_Trees.root && -f Barrel/FilterEvents_Trees.root ]] && mv Barrel/FilterEvents_Trees.root .

    #make the filtered tree (if requested and not already produced by QA
    [[ -f AliESDs_Barrel.root ]] && echo "AliESDs_Barrel.root" > filtered.list
    if [[ -n ${runESDfiltering} && ! -f FilterEvents_Trees.root ]]; then 
      goMakeFilteredTrees ${PWD} ${runNumber} "filtered.list" ${filteringFactorHighPt} ${filteringFactorV0s} ${ocdbPath} 1000000 0 10000000 0 ${configFile} AliESDs_Barrel.root "${extraOpts[@]}"
    fi

  fi

  ##handle possible crashes in QA (happens often in trunk)
  ##rerun QA with a trusted aliroot version
  #if [[ $(validateLog qa_barrel.log) ]]; then
  #  echo "qa_barrel.log not validated!"
  #fi
  #if [[ ! -f QAresults_barrel.root && -f ${setupTrustedAliROOTenvInCurrentShell} || $(validateLog qa_barrel.log) ]]; then
  #  echo "WARNING: using trusted QA aliroot ${ALICE_ROOT}"
  #  source ${setupTrustedAliROOTenvInCurrentShell}
  #  cd Barrel
  #  rm QAresults_barrel.root
  #  rm EventStat_temp_barrel.root
  #  rm AODtpITS.root
  #  [[ ! -f AliESDs.root ]] && ln -s ../AliESDs_Barrel.root AliESDs.root
  #  [[ ! -f AliESDfriends.root ]] && ln -s ../AliESDfriends_Barrel.root AliESDfriends.root
  #  if [[ -n ${trustedQAtrainMacro} ]]; then
  #    eval "cp ${trustedQAtrainMacro} QAtrain_duo_trusted.C"
  #  fi
  #  echo executing aliroot -b -q "QAtrain_duo_trusted.C(\"_barrel\",${runNumber},\"wn.xml\",0,\"${ocdbPath}\")"
  #  time aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"wn.xml\",0,\"${ocdbPath}\")" &> ../qa_barrel_trusted.log
  #  cd ../
  #fi

  #move stuff to final destination
  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo rm -f ./${chunkName}
  rm -f ./${chunkName}
  echo "cp --recursive ${runpath}/* ${outputDir}"
  cp -pf --recursive ${runpath}/* ${outputDir}
  echo

  #validate CPass1
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f AliESDs_Barrel.root ]] && echo "esd ${outputDir}/AliESDs_Barrel.root" >> ${doneFile}
    [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFile}
    [[ -f QAresults_Barrel.root ]] && echo "qafile ${outputDir}/QAresults_Barrel.root" >> ${doneFile}
    [[ -f QAresults_Outer.root ]] && echo "qafile ${outputDir}/QAresults_Outer.root" >> ${doneFile}
    [[ -f QAresults_barrel.root ]] && echo "qafile ${outputDir}/QAresults_barrel.root" >> ${doneFile}
    [[ -f QAresults_outer.root ]] && echo "qafile ${outputDir}/QAresults_outer.root" >> ${doneFile}
    [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}


goMergeCPass0()
{
  #
  # find the output files and merge them
  #

  outputDir=${1}
  ocdbStorage=${2}
  configFile=${3}
  runNumber=${4}
  calibrationFilesToMerge=${5}  #can be a non-existent file, will then be produced on the fly
  shift 5
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/merge.cpass0.run${runNumber}.done"

  umask 0002
  ulimit -c unlimited 

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}

  #runpath=${PWD}/rundir_cpass0_Merge_${runNumber}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "not able to make the runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec &> ${logOutputDir}/mergeMakeOCDB.log
  echo "${0} $*"

  mergingScript="mergeMakeOCDB.byComponent.sh"

  echo goMergeCPass0 SETUP:
  echo runNumber=${runNumber}
  echo outputDir=${outputDir}
  echo ocdbStorage=${ocdbStorage}
  echo calibrationFilesToMerge=${calibrationFilesToMerge}
  echo mergingScript=${mergingScript}
  echo commonOutputPath=${commonOutputPath}
  echo runpath=${runpath}
  
  # copy files in case they are not already there
  filesMergeCPass0=(
                    "${batchWorkingDirectory}/${calibrationFilesToMerge}"
                    "${batchWorkingDirectory}/OCDB.root"
                    "${batchWorkingDirectory}/localOCDBaccessConfig.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeMakeOCDB.byComponent.sh"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeByComponent.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/makeOCDB.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/merge.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeMakeOCDB.sh"
  )
  for file in ${filesMergeCPass0[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done
  
  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  alirootInfo > ALICE_ROOT.log

  #
  echo "PWD"
  /bin/ls
  echo "PWD/.."
  /bin/ls ../


  #merge calibration
  chmod u+x ${mergingScript}  
  mkdir -p ./OCDB
  if [[ ! -f ${calibrationFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root > ${calibrationFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root 2>/dev/null > ${calibrationFilesToMerge}
  fi
  
  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB ${ocdbStorage}"
  if [[ -n ${pretend} ]]; then
    touch CalibObjects.root
    touch ocdb.log
    touch merge.log
    touch dcsTime.root
    mkdir -p ./OCDB/TPC/Calib/TimeGain/
    mkdir -p ./OCDB/TPC/Calib/TimeDrift/
    touch ./OCDB/TPC/Calib/TimeGain/someCalibObject_0-999999_cpass0.root
    touch ./OCDB/TPC/Calib/TimeDrift/otherCalibObject_0-999999_cpass0.root
  else
    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage}

    #produce the calib trees for expert QA (dcsTime.root)
    goMakeLocalOCDBaccessConfig ./OCDB
    echo aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
    aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
  fi
  
  ### produce the output
  #tar the produced OCDB for reuse
  tar czf ${commonOutputPath}/meta/cpass0.localOCDB.${runNumber}.tgz ./OCDB

  /bin/ls

  #copy all to output dir
  cp -pf --recursive ${runpath}/* ${outputDir}

  if [[ -n ${generateMC} ]]; then
    goPrintValues sim ${commonOutputPath}/meta/sim.run${runNumber}.list ${commonOutputPath}/meta/cpass0.job*.run${runNumber}.done
  fi

  #validate merging cpass0
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFile}
    [[ -f dcsTime.root ]] && echo "dcsTree ${outputDir}/dcsTime.root" >> ${doneFile}
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goMergeCPass1()
{
  #
  # find the output files and merge them
  #

  outputDir=${1}
  ocdbStorage=${2}
  configFile=${3}
  runNumber=${4}
  calibrationFilesToMerge=${5}
  qaFilesToMerge=${6}
  filteredFilesToMerge=${7}
  shift 7
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/merge.cpass1.run${runNumber}.done"

  umask 0002
  ulimit -c unlimited 

  #clean up first:
  rm -f ${outputDir}/*.log
  rm -f ${outputDir}/*.root
  rm -f ${outputDir}/*done

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}

  #runpath=${PWD}/rundir_cpass1_Merge_${runNumber}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "not able to make the runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec &> ${logOutputDir}/mergeMakeOCDB.log
  echo "${0} $*"

  calibrationOutputFileName='AliESDfriends_v1.root'
  qaOutputFileName='QAresults*.root'
  mergingScript="mergeMakeOCDB.byComponent.sh"
  #important to have the string "Stage.txt" in the filename to trigger the merging
  #it has to be a list of directories containing the files
  qaMergedOutputFileName="QAresults_merged.root"

  echo goMergeCPass1 SETUP:
  echo runNumber=${runNumber}
  echo outputDir=${outputDir}
  echo ocdbStorage=${ocdbStorage}
  echo calibrationFilesToMerge=$calibrationFilesToMerge
  echo qaFilesToMerge=$qaFilesToMerge
  echo calibrationOutputFileName=${calibrationOutputFileName}
  echo mergingScript=${mergingScript}
  
  # copy files in case they are not already there
  filesMergeCPass1=(
                    "${batchWorkingDirectory}/${calibrationFilesToMerge}"
                    "${batchWorkingDirectory}/${qaFilesToMerge}"
                    "${batchWorkingDirectory}/OCDB.root"
                    "${batchWorkingDirectory}/localOCDBaccessConfig.C"
                    "${batchWorkingDirectory}/meta/cpass0.localOCDB.${runNumber}.tgz"
                    "${batchWorkingDirectory}/QAtrain_duo.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeMakeOCDB.byComponent.sh"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeByComponent.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/makeOCDB.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/merge.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeMakeOCDB.sh"
                    "${trustedQAtrainMacro}"
                    "${ALICE_ROOT}/ANALYSIS/macros/QAtrain_duo.C"
  )
  for file in ${filesMergeCPass1[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  #configure local OCDB storage from CPass0 (creates the localOCDBaccessConfig.C script)
  if [[ -f cpass0.localOCDB.${runNumber}.tgz ]]; then
    echo goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
    goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
  else
    echo "WARNING: file cpass0.localOCDB.${runNumber}.tgz not found!"
  fi

  alirootInfo > ALICE_ROOT.log

  #
  /bin/ls

  #merge calibration
  chmod u+x ${mergingScript}  
  mkdir -p OCDB
  
  #if not provided, create the lists of files to merge
  if [[ ! -f ${filteredFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/FilterEvents_Trees.root > ${filteredFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/FilterEvents_Trees.root 2>/dev/null > ${filteredFilesToMerge}
  fi
  if [[ ! -f ${calibrationFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root > ${calibrationFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root 2>/dev/null > ${calibrationFilesToMerge}
  fi
  if [[ ! -f ${qaFilesToMerge} ]]; then
    #find the files, but only store the directories (QAtrain_duo.C requires this)
    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}"
  if [[ -n ${pretend} ]]; then
    touch ocdb.log
    touch cpass1.localOCDB.${runNumber}.tgz
    touch ${qaMergedOutputFileName}
    touch merge.log
    touch trending.root
    touch FilterEvents_Trees.root
    touch CalibObjects.root
    touch dcsTime.root
    touch ${qaMergedOutputFileName}
    mkdir -p OCDB
  else
    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage}

    #merge QA (and filtered trees)
    [[ -n ${AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF} ]] && export AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF
    [[ -n ${AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF} ]] && export AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF

    #echo aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    echo aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"${qaFilesToMerge}\",1,\"${ocdbStorage}\")"
    #aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"${qaFilesToMerge}\",1,\"${ocdbStorage}\")" > mergeQA.log
    mv QAresults_barrel.root ${qaMergedOutputFileName}
    mv trending_barrel.root trending.root

    #merge filtered trees
    echo aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    aliroot -l -b -q "merge.C(\"${filteredFilesToMerge}\",\"\",kFALSE,\"FilterEvents_Trees.root\")"

    #produce the calib trees for expert QA
    echo aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
    aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
  fi

  tar czf ${commonOutputPath}/meta/cpass1.localOCDB.${runNumber}.tgz ./OCDB

  /bin/ls

  #copy all to output dir
  cp -pf --recursive ${runpath}/* ${outputDir}
  
  #validate merge cpass1
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >>  ${doneFile}; then
    [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFile}
    [[ -f ${qaMergedOutputFileName} ]] && echo "qafile ${outputDir}/${qaMergedOutputFileName}" >> ${doneFile}
    [[ -f trending.root ]] && echo "trendingfile ${outputDir}/trending.root" >> ${doneFile}
    [[ -f dcsTime.root ]] && echo "dcsTree ${outputDir}/dcsTime.root" >> ${doneFile}
    [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
  fi
      
  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goMerge()
{<commit_msg>try to always provide input data for QA, even in case of crashes in makeOCDB<commit_after>#!/bin/bash
#include benchmark.config

# this script runs the CPass0/CPass1 train
# produced OCDB updates are local

main()
{
  #run in proper mode depending on the selection
  if [[ $# -lt 1 ]]; then
    if [[ ! "${0}" =~ "bash" ]]; then
      echo "uses makeflow:"
      echo " ${0} \"run\" productionID inputList configFile [extraOpts]"
      echo "uses a batch system (SGE):"
      echo " ${0} \"submit\" productionID inputList configFile [extraOpts]"
      echo "extraOpts if non-empty override the config file, e.g.:"
      echo " ${0} submit test1 benchmark.list benchmark.config runNumber=169123 nEvents=10"
    fi
    return
  fi

  #define some aliases - default is to call one of the functions directly
  runMode=${1}
  umask 0002
  shift
  case ${runMode} in
    "CPass0") goCPass0 "$@";;
    "CPass1") goCPass1 "$@";;
    "MakeLocalOCDBaccessConfig") goMakeLocalOCDBaccessConfig "$@";;
    "MergeCPass0") goMergeCPass0 "$@";;
    "MergeCPass1") goMergeCPass1 "$@";;
    "MakeFilteredTrees") goMakeFilteredTrees "$@";;
    "MakeSummary") goMakeSummary "$@";;
    "run") goSubmitMakeflow "$@";;
    "submit") goSubmitBatch "$@";;
    "test") goTest "$@";;
    "GenerateMakeflow") goGenerateMakeflow "$@";;
    "PrintValues") goPrintValues "$@";;
    "CreateQAplots") goCreateQAplots "$@";;
    "WaitForOutput") goWaitForOutput "$@";;
    "Merge") goMerge "$@";;
    *) 
      ${runMode} "$@"
    ;;
  esac
  return 0
}

generateMC()
{
  #generate one raw chunk in current directory
  SEED=${JOB_ID}${SGE_TASK_ID}
  export CONFIG_SEED=${SEED}
  runNumber=${1}
  OCDBpath=${2}
  nEventsim=${3}
  if [[ -n ${pretend} ]]; then
    touch galice.root
  else
    if [[ -f sim.C && -f Config.C ]] ; then
        time aliroot -b -q -x sim.C\(${runNumber},\"${OCDBpath}\",${nEventsim}\) >sim.log 2>&1
        mv syswatch.log simwatch.log
    fi
  fi
}

goCPass0()
{
  umask 0002
  
  targetDirectory=${1}
  inputList=${2}
  nEvents=${3}
  ocdbPath=${4}
  configFile=${5}
  runNumber=${6}
  jobindex=${7}
  shift 7
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  #use the jobindex only if set and non-negative
  if [[ -z ${jobindex} || ${jobindex} -lt 0 ]]; then
    [[ -n "${LSB_JOBINDEX}" ]] && jobindex=${LSB_JOBINDEX}
    [[ -n "${SGE_TASK_ID}" ]] && jobindex=${SGE_TASK_ID}
  fi

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/cpass0.job${jobindex}.run${runNumber}.done"

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}
  
  if [[ -n ${ALIROOT_FORCE_COREDUMP} ]]; then
    ulimit -c unlimited 
    export ALIROOT_FORCE_COREDUMP
  fi

  #the contents of this is stored in the tree and used later (e.g. AliAnalysisTaskPIDResponse)!
  #at the QA stage the pass number is guessed from the path stored here.
  #The Format is:
  #Packages= ;OutputDir= ;LPMPass= ;TriggerAlias= ;LPMRunNumber= ;LPMProductionType= ;LPMInteractionType= ;LPMProductionTag= ;LPMAnchorRun= ;LPMAnchorProduction= ;LPMAnchorYear= 
  export PRODUCTION_METADATA="OutputDir=cpass0"

  if [[ "${inputList}" =~ \.root$ ]]; then
    infile=${inputList}
  else
    infile=$(sed -ne "${jobindex}p" ${inputList} | egrep '\s*\w*/\w*')
  fi
  chunkName=${infile##*/}

  outputDir=${targetDirectory}/${jobindex}_${chunkName%.*}
  mkdir -p ${outputDir}
  [[ ! -d ${outputDir} ]] && echo "cannot make ${outputDir}" && touch ${doneFile} && return 1  
  
  #runpath=${PWD}/rundir_cpass0_${runNumber}_${jobindex}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)
  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "cannot make runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  #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}

  #####MC
  if [[ -n ${generateMC} ]]; then
    olddir=${PWD}
    outputDirMC=${commonOutputPath}/000${runNumber}/sim/${jobindex}
    simrunpath=${outputDirMC}
    [[ ${simulateInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && simrunpath=${TMPDIR}
    [[ ${simulateInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && simrunpath=$(mktemp -d)
    mkdir -p ${outputDirMC}
    mkdir -p ${simrunpath}
    cd ${simrunpath}

    filesMC=( 
              "${batchWorkingDirectory}/sim.C"
              "${batchWorkingDirectory}/rec.C"
              "${batchWorkingDirectory}/Config.C"
              "${batchWorkingDirectory}/OCDB_*.root"
    )
    for file in ${filesMC[*]}; do
      [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    done

    generateMC ${runNumber} ${ocdbPath} ${nEvents}

    [[ ! "${simrunpath}" =~ "${outputDirMC}" ]] && mv * ${outputDirMC} #TODO check if it works
    cd ${olddir}
    
    ln -s ${outputDirMC}/* ${runpath}/ 
    
    inputList=${outputDirMC}/galice.root #TODO not valid outside shell !!!
    infile=""
  fi
  ######
  
  [[ ! -f ${inputList} && -z ${pretend} ]] && echo "input file ${inputList} not found, exiting..." && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 1> ${logOutputDir}/stdout
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 2> ${logOutputDir}/stderr
  echo "${0} $*"

  echo "#####################"
  echo CPass0:
  echo JOB setup
  echo nEvents            ${nEvents}
  echo runNumber          ${runNumber}
  echo ocdbPath           ${ocdbPath}
  echo infile             ${infile}
  echo chunkName          ${chunkName}
  echo jobindex           ${jobindex}
  echo recoTriggerOptions ${recoTriggerOptions}
  echo targetDirectory    ${targetDirectory}
  echo commonOutputPath         ${commonOutputPath}
  echo doneFile      ${doneFile}
  echo runpath            ${runpath}  
  echo outputDir          ${outputDir}
  echo ALICE_ROOT         ${ALICE_ROOT}
  echo PWD                ${PWD}
  echo "########## ###########"

  alirootInfo > ALICE_ROOT.log

  filesCPass0=( 
               "${batchWorkingDirectory}/runCPass0.sh"
               "${batchWorkingDirectory}/recCPass0.C"
               "${batchWorkingDirectory}/runCalibTrain.C"
               "${batchWorkingDirectory}/localOCDBaccessConfig.C"
               "${batchWorkingDirectory}/OCDB.root"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/runCPass0.sh"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/recCPass0.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/runCalibTrain.C"
  )

  for file in ${filesCPass0[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo
  chmod u+x runCPass0.sh

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  if [[ -n ${postSetUpActionCPass0} ]]; then
    echo "running ${postSetUpActionCPass0}"
    eval ${postSetUpActionCPass0}
  fi

  #run CPass0
  echo "${runpath}/runCPass0.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
  if [[ -n ${pretend} ]]; then
    touch AliESDs.root
    touch AliESDfriends.root
    touch AliESDfriends_v1.root
    touch rec.log
    touch calib.log
  else
    echo ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
    ./runCPass0.sh "${infile}" "${nEvents}" "${runNumber}" "${ocdbPath}" "${recoTriggerOptions}"
  fi
  
  #move stuff to final destination
  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo

  echo rm -f ./${chunkName}
  rm -f ./${chunkName}
  echo "cp --recursive ${runpath}/* ${outputDir}"
  cp -p --recursive ${runpath}/* ${outputDir}
  echo
  
  #validate CPass0
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f ${outputDirMC}/galice.root ]] && echo "sim ${outputDirMC}/galice.root" >> ${doneFile}
    [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFile}
    [[ -f AliESDs.root ]] && echo "esd ${outputDir}/AliESDs.root" >> ${doneFile}
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goCPass1()
{
  umask 0002
  
  targetDirectory=${1}
  inputList=${2}
  nEvents=${3}
  ocdbPath=${4}
  configFile=${5}
  runNumber=${6}
  jobindex=${7}
  shift 7
  extraOpts=("$@")
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  #use the jobindex only if set and non-negative
  if [[ -z ${jobindex} || ${jobindex} -lt 0 ]]; then
    [[ -n "${LSB_JOBINDEX}" ]] && jobindex=${LSB_JOBINDEX}
    [[ -n "${SGE_TASK_ID}" ]] && jobindex=${SGE_TASK_ID}
  fi

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/cpass1.job${jobindex}.run${runNumber}.done"

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}
  
  if [[ -n ${ALIROOT_FORCE_COREDUMP} ]]; then
    ulimit -c unlimited 
    export ALIROOT_FORCE_COREDUMP
  fi

  #the contents of this is stored in the tree and used later (e.g. AliAnalysisTaskPIDResponse)!
  #at the QA stage the pass number is guessed from the path stored here.
  #The Format is:
  #Packages= ;OutputDir= ;LPMPass= ;TriggerAlias= ;LPMRunNumber= ;LPMProductionType= ;LPMInteractionType= ;LPMProductionTag= ;LPMAnchorRun= ;LPMAnchorProduction= ;LPMAnchorYear= 
  export PRODUCTION_METADATA="OutputDir=cpass1"

  [[ ! -f ${inputList} && -z ${pretend} ]] && echo "input file ${inputList} not found, exiting..." && touch ${doneFile} && return 1
  if [[ "${inputList}" =~ \.root$ ]]; then
    infile=${inputList}
  else
    infile=$(sed -ne "${jobindex}p" ${inputList} | egrep '\s*\w*/\w*')
  fi
  chunkName=${infile##*/}

  outputDir=${targetDirectory}/${jobindex}_${chunkName%.*}
  mkdir -p ${outputDir}
  [[ ! -d ${outputDir} ]] && echo "cannot make ${outputDir}" && touch ${doneFile} && return 1
  
  #runpath=${PWD}/rundir_cpass1_${runNumber}_${jobindex}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  #MC
  if [[ "${infile}" =~ galice\.root ]]; then
    ln -s ${inputList%/*}/* ${runpath}
    infile=""
  fi

  #init the running path
  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "cannot make runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  #this is needed for runCPass1.sh
  ln -s ${infile} ${runpath}/${chunkName}

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 1> ${logOutputDir}/stdout
  [[ -z ${dontRedirectStdOutToLog} ]] && exec 2> ${logOutputDir}/stderr
  echo "${0} $*"

  echo "#####################"
  echo CPass1:
  echo JOB setup
  echo nEvents            ${nEvents}
  echo runNumber          ${runNumber}
  echo ocdbPath           ${ocdbPath}
  echo infile             ${infile}
  echo chunkName          ${chunkName}
  echo jobindex           ${jobindex}
  echo recoTriggerOptions ${recoTriggerOptions}
  echo targetDirectory    ${targetDirectory}
  echo commonOutputPath         ${commonOutputPath}
  echo doneFile      ${doneFile}
  echo runpath            ${runpath}  
  echo outputDir          ${outputDir}
  echo ALICE_ROOT         ${ALICE_ROOT}
  echo PWD                ${PWD}
  echo "########## ###########"

  alirootInfo > ALICE_ROOT.log

  filesCPass1=( 
               "${batchWorkingDirectory}/runCPass1.sh"
               "${batchWorkingDirectory}/recCPass1.C"
               "${batchWorkingDirectory}/recCPass1_OuterDet.C"
               "${batchWorkingDirectory}/runCalibTrain.C"
               "${batchWorkingDirectory}/QAtrain_duo.C"
               "${batchWorkingDirectory}/localOCDBaccessConfig.C"
               "${commonOutputPath}/meta/cpass0.localOCDB.${runNumber}.tgz"
               "${batchWorkingDirectory}/OCDB.root"
               "${trustedQAtrainMacro}"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/runCPass1.sh"
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/recCPass1.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/recCPass1_OuterDet.C" 
               "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/runCalibTrain.C"
               "${ALICE_ROOT}/ANALYSIS/macros/QAtrain_duo.C"
  )

  for file in ${filesCPass1[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  if [[ -n ${postSetUpActionCPass1} ]]; then
    echo "running ${postSetUpActionCPass1}"
    eval ${postSetUpActionCPass1}
    echo
  fi

  #configure local OCDB storage from CPass0 (creates the localOCDBaccessConfig.C script)
  if [[ -f cpass0.localOCDB.${runNumber}.tgz ]]; then
    echo goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
    goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
  else
    echo "WARNING: file cpass0.localOCDB.${runNumber}.tgz not found!"
  fi

  if [[ ! $(/bin/ls -1 OCDB/*/*/*/*.root 2>/dev/null) ]]; then
    echo "cpass0 produced no calibration! exiting..."
    touch ${doneFile}
    return 1
  fi

  #create the Barrel and OuterDet directories for CPass1 and link the local OCDB directory
  #there to make the localOCDBaccessConfig.C file work, since it may point to the OCDB
  #entries using a relative path, e.g. local://./OCDB
  mkdir Barrel OuterDet
  ln -s ../OCDB Barrel/OCDB
  ln -s ../OCDB OuterDet/OCDB

  #setup the filtering
  #the following option enables the filtering task inside the QAtrain_duo.C
  [[ -n $runESDfiltering ]] && export QA_TaskFilteredTree=1
  #set the downscaling factors during the filtering fro expert QA (overrides the previous values)
  if [[ -n ${filteringFactorHighPt} ]]; then
    export AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF=${filteringFactorHighPt}
  fi
  if [[ -n ${filteringFactorV0s} ]]; then
    export AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF=${filteringFactorV0s} 
  fi

  #run CPass1
  chmod u+x runCPass1.sh
  echo "${runpath}/runCPass1.sh ${infile} ${nEvents} ${runNumber} ${ocdbPath} ${recoTriggerOptions}"
  if [[ -n ${pretend} ]]; then
    touch AliESDs_Barrel.root
    touch AliESDfriends_Barrel.root
    touch AliESDfriends_v1.root
    touch QAresults_barrel.root
    touch EventStat_temp_barrel.root
    touch AODtpITS.root
    touch AliESDs_Outer.root
    touch AliESDfriends_Outer.root
    touch QAresults_outer.root
    touch EventStat_temp_outer.root
    touch rec.log
    touch calib.log
    touch qa.log
    touch filtering.log FilterEvents_Trees.root
  else
    ./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
    [[ ! -f AliESDfriends_v1.root && -f Barrel/AliESDfriends_v1.root ]] && mv Barrel/AliESDfriends_v1.root .
    [[ ! -f QAresults_barrel.root && -f Barrel/QAresults_barrel.root ]] && mv Barrel/QAresults_barrel.root .
    [[ ! -f AliESDs_Outer.root && -f OuterDet/AliESDs.root ]] && mv OuterDet/AliESDs.root AliESDs_Outer.root
    [[ ! -f AliESDfriends_Outer.root && -f OuterDet/AliESDfriends.root ]] && mv OuterDet/AliESDfriends.root AliESDfriends_Outer.root
    [[ ! -f QAresults_outer.root && -f OuterDet/QAresults_outer.root ]] && mv OuterDet/QAresults_outer.root .
    [[ ! -f FilterEvents_Trees.root && -f Barrel/FilterEvents_Trees.root ]] && mv Barrel/FilterEvents_Trees.root .

    #make the filtered tree (if requested and not already produced by QA
    [[ -f AliESDs_Barrel.root ]] && echo "AliESDs_Barrel.root" > filtered.list
    if [[ -n ${runESDfiltering} && ! -f FilterEvents_Trees.root ]]; then 
      goMakeFilteredTrees ${PWD} ${runNumber} "filtered.list" ${filteringFactorHighPt} ${filteringFactorV0s} ${ocdbPath} 1000000 0 10000000 0 ${configFile} AliESDs_Barrel.root "${extraOpts[@]}" >filtering.log
    fi

  fi

  ##handle possible crashes in QA (happens often in trunk)
  ##rerun QA with a trusted aliroot version
  #if [[ $(validateLog qa_barrel.log) ]]; then
  #  echo "qa_barrel.log not validated!"
  #fi
  #if [[ ! -f QAresults_barrel.root && -f ${setupTrustedAliROOTenvInCurrentShell} || $(validateLog qa_barrel.log) ]]; then
  #  echo "WARNING: using trusted QA aliroot ${ALICE_ROOT}"
  #  source ${setupTrustedAliROOTenvInCurrentShell}
  #  cd Barrel
  #  rm QAresults_barrel.root
  #  rm EventStat_temp_barrel.root
  #  rm AODtpITS.root
  #  [[ ! -f AliESDs.root ]] && ln -s ../AliESDs_Barrel.root AliESDs.root
  #  [[ ! -f AliESDfriends.root ]] && ln -s ../AliESDfriends_Barrel.root AliESDfriends.root
  #  if [[ -n ${trustedQAtrainMacro} ]]; then
  #    eval "cp ${trustedQAtrainMacro} QAtrain_duo_trusted.C"
  #  fi
  #  echo executing aliroot -b -q "QAtrain_duo_trusted.C(\"_barrel\",${runNumber},\"wn.xml\",0,\"${ocdbPath}\")"
  #  time aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"wn.xml\",0,\"${ocdbPath}\")" &> ../qa_barrel_trusted.log
  #  cd ../
  #fi

  #move stuff to final destination
  echo "this directory (${PWD}) contents:"
  /bin/ls
  echo rm -f ./${chunkName}
  rm -f ./${chunkName}
  echo "cp --recursive ${runpath}/* ${outputDir}"
  cp -pf --recursive ${runpath}/* ${outputDir}
  echo

  #validate CPass1
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f AliESDs_Barrel.root ]] && echo "esd ${outputDir}/AliESDs_Barrel.root" >> ${doneFile}
    [[ -f AliESDfriends_v1.root ]] && echo "calibfile ${outputDir}/AliESDfriends_v1.root" >> ${doneFile}
    [[ -f QAresults_Barrel.root ]] && echo "qafile ${outputDir}/QAresults_Barrel.root" >> ${doneFile}
    [[ -f QAresults_Outer.root ]] && echo "qafile ${outputDir}/QAresults_Outer.root" >> ${doneFile}
    [[ -f QAresults_barrel.root ]] && echo "qafile ${outputDir}/QAresults_barrel.root" >> ${doneFile}
    [[ -f QAresults_outer.root ]] && echo "qafile ${outputDir}/QAresults_outer.root" >> ${doneFile}
    [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
  else
    if grep "qa_outer.log.*OK" ${doneFile} > /dev/null; then
      [[ -f QAresults_Outer.root ]] && echo "qafile ${outputDir}/QAresults_Outer.root" >> ${doneFile}
      [[ -f QAresults_outer.root ]] && echo "qafile ${outputDir}/QAresults_outer.root" >> ${doneFile}
    fi
    if grep "qa_barrel.log.*OK" ${doneFile} > /dev/null; then
      [[ -f QAresults_Barrel.root ]] && echo "qafile ${outputDir}/QAresults_Barrel.root" >> ${doneFile}
      [[ -f QAresults_barrel.root ]] && echo "qafile ${outputDir}/QAresults_barrel.root" >> ${doneFile}
    fi
    if grep "filtering.log.*OK" ${doneFile} > /dev/null; then
      [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
    fi
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}


goMergeCPass0()
{
  #
  # find the output files and merge them
  #

  outputDir=${1}
  ocdbStorage=${2}
  configFile=${3}
  runNumber=${4}
  calibrationFilesToMerge=${5}  #can be a non-existent file, will then be produced on the fly
  shift 5
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/merge.cpass0.run${runNumber}.done"

  umask 0002
  ulimit -c unlimited 

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}

  #runpath=${PWD}/rundir_cpass0_Merge_${runNumber}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "not able to make the runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec &> ${logOutputDir}/mergeMakeOCDB.log
  echo "${0} $*"

  mergingScript="mergeMakeOCDB.byComponent.sh"

  echo goMergeCPass0 SETUP:
  echo runNumber=${runNumber}
  echo outputDir=${outputDir}
  echo ocdbStorage=${ocdbStorage}
  echo calibrationFilesToMerge=${calibrationFilesToMerge}
  echo mergingScript=${mergingScript}
  echo commonOutputPath=${commonOutputPath}
  echo runpath=${runpath}
  
  # copy files in case they are not already there
  filesMergeCPass0=(
                    "${batchWorkingDirectory}/${calibrationFilesToMerge}"
                    "${batchWorkingDirectory}/OCDB.root"
                    "${batchWorkingDirectory}/localOCDBaccessConfig.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeMakeOCDB.byComponent.sh"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeByComponent.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/makeOCDB.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/merge.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass0/mergeMakeOCDB.sh"
  )
  for file in ${filesMergeCPass0[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done
  
  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  alirootInfo > ALICE_ROOT.log

  #
  echo "PWD"
  /bin/ls
  echo "PWD/.."
  /bin/ls ../


  #merge calibration
  chmod u+x ${mergingScript}  
  mkdir -p ./OCDB
  if [[ ! -f ${calibrationFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root > ${calibrationFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root 2>/dev/null > ${calibrationFilesToMerge}
  fi
  
  echo "${mergingScript} ${calibrationFilesToMerge} ${runNumber} local://./OCDB ${ocdbStorage}"
  if [[ -n ${pretend} ]]; then
    touch CalibObjects.root
    touch ocdb.log
    touch merge.log
    touch dcsTime.root
    mkdir -p ./OCDB/TPC/Calib/TimeGain/
    mkdir -p ./OCDB/TPC/Calib/TimeDrift/
    touch ./OCDB/TPC/Calib/TimeGain/someCalibObject_0-999999_cpass0.root
    touch ./OCDB/TPC/Calib/TimeDrift/otherCalibObject_0-999999_cpass0.root
  else
    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage}

    #produce the calib trees for expert QA (dcsTime.root)
    goMakeLocalOCDBaccessConfig ./OCDB
    echo aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
    aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
  fi
  
  ### produce the output
  #tar the produced OCDB for reuse
  tar czf ${commonOutputPath}/meta/cpass0.localOCDB.${runNumber}.tgz ./OCDB

  /bin/ls

  #copy all to output dir
  cp -pf --recursive ${runpath}/* ${outputDir}

  if [[ -n ${generateMC} ]]; then
    goPrintValues sim ${commonOutputPath}/meta/sim.run${runNumber}.list ${commonOutputPath}/meta/cpass0.job*.run${runNumber}.done
  fi

  #validate merging cpass0
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >> ${doneFile}; then
    [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFile}
    [[ -f dcsTime.root ]] && echo "dcsTree ${outputDir}/dcsTime.root" >> ${doneFile}
  fi

  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goMergeCPass1()
{
  #
  # find the output files and merge them
  #

  outputDir=${1}
  ocdbStorage=${2}
  configFile=${3}
  runNumber=${4}
  calibrationFilesToMerge=${5}
  qaFilesToMerge=${6}
  filteredFilesToMerge=${7}
  shift 7
  if ! parseConfig ${configFile} "$@"; then return 1; fi

  #record the working directory provided by the batch system
  batchWorkingDirectory=${PWD}

  [[ -z ${commonOutputPath} ]] && commonOutputPath=${PWD}
  doneFile="${commonOutputPath}/meta/merge.cpass1.run${runNumber}.done"

  umask 0002
  ulimit -c unlimited 

  #clean up first:
  rm -f ${outputDir}/*.log
  rm -f ${outputDir}/*.root
  rm -f ${outputDir}/*done

  [[ -f ${alirootSource} && -z ${ALICE_ROOT} ]] && source ${alirootSource}

  #runpath=${PWD}/rundir_cpass1_Merge_${runNumber}
  runpath=${outputDir}
  [[ ${reconstructInTemporaryDir} -eq 1 && -n ${TMPDIR} ]] && runpath=${TMPDIR}
  [[ ${reconstructInTemporaryDir} -eq 1 && -z ${TMPDIR} ]] && runpath=$(mktemp -d)

  mkdir -p ${runpath}
  [[ ! -d ${runpath} ]] && echo "not able to make the runpath ${runpath}" && touch ${doneFile} && return 1
  cd ${runpath}
  [[ ! ${PWD} =~ ${runpath} ]] && echo "PWD=$PWD is not the runpath=${runpath}" && touch ${doneFile} && return 1

  logOutputDir=${runpath}
  [[ -n ${logToFinalDestination} ]] && logOutputDir=${outputDir}
  [[ -z ${dontRedirectStdOutToLog} ]] && exec &> ${logOutputDir}/mergeMakeOCDB.log
  echo "${0} $*"

  calibrationOutputFileName='AliESDfriends_v1.root'
  qaOutputFileName='QAresults*.root'
  mergingScript="mergeMakeOCDB.byComponent.sh"
  #important to have the string "Stage.txt" in the filename to trigger the merging
  #it has to be a list of directories containing the files
  qaMergedOutputFileName="QAresults_merged.root"

  echo goMergeCPass1 SETUP:
  echo runNumber=${runNumber}
  echo outputDir=${outputDir}
  echo ocdbStorage=${ocdbStorage}
  echo calibrationFilesToMerge=$calibrationFilesToMerge
  echo qaFilesToMerge=$qaFilesToMerge
  echo calibrationOutputFileName=${calibrationOutputFileName}
  echo mergingScript=${mergingScript}
  
  # copy files in case they are not already there
  filesMergeCPass1=(
                    "${batchWorkingDirectory}/${calibrationFilesToMerge}"
                    "${batchWorkingDirectory}/${qaFilesToMerge}"
                    "${batchWorkingDirectory}/OCDB.root"
                    "${batchWorkingDirectory}/localOCDBaccessConfig.C"
                    "${batchWorkingDirectory}/meta/cpass0.localOCDB.${runNumber}.tgz"
                    "${batchWorkingDirectory}/QAtrain_duo.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeMakeOCDB.byComponent.sh"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeByComponent.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/makeOCDB.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/merge.C"
                    "${ALICE_ROOT}/PWGPP/CalibMacros/CPass1/mergeMakeOCDB.sh"
                    "${trustedQAtrainMacro}"
                    "${ALICE_ROOT}/ANALYSIS/macros/QAtrain_duo.C"
  )
  for file in ${filesMergeCPass1[*]}; do
    [[ ! -f ${file##*/} && -f ${file} ]] && echo "copying ${file}" && cp -f ${file} .
    [[ ${file##*/} =~ .*\.sh ]] && chmod +x ${file##*/}
  done

  sed -i '/.*root .*\.C/ s|\s*,\s*|,|g' *.sh

  #configure local OCDB storage from CPass0 (creates the localOCDBaccessConfig.C script)
  if [[ -f cpass0.localOCDB.${runNumber}.tgz ]]; then
    echo goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
    goMakeLocalOCDBaccessConfig "cpass0.localOCDB.${runNumber}.tgz"
  else
    echo "WARNING: file cpass0.localOCDB.${runNumber}.tgz not found!"
  fi

  alirootInfo > ALICE_ROOT.log

  #
  /bin/ls

  #merge calibration
  chmod u+x ${mergingScript}  
  mkdir -p OCDB
  
  #if not provided, create the lists of files to merge
  if [[ ! -f ${filteredFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/FilterEvents_Trees.root > ${filteredFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/FilterEvents_Trees.root 2>/dev/null > ${filteredFilesToMerge}
  fi
  if [[ ! -f ${calibrationFilesToMerge} ]]; then
    echo "/bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root > ${calibrationFilesToMerge}"
    /bin/ls -1 ${outputDir}/*/AliESDfriends_v1.root 2>/dev/null > ${calibrationFilesToMerge}
  fi
  if [[ ! -f ${qaFilesToMerge} ]]; then
    #find the files, but only store the directories (QAtrain_duo.C requires this)
    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}"
  if [[ -n ${pretend} ]]; then
    touch ocdb.log
    touch cpass1.localOCDB.${runNumber}.tgz
    touch ${qaMergedOutputFileName}
    touch merge.log
    touch trending.root
    touch FilterEvents_Trees.root
    touch CalibObjects.root
    touch dcsTime.root
    touch ${qaMergedOutputFileName}
    mkdir -p OCDB
  else
    ./${mergingScript} ${calibrationFilesToMerge} ${runNumber} "local://./OCDB" ${ocdbStorage}

    #merge QA (and filtered trees)
    [[ -n ${AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF} ]] && export AliAnalysisTaskFilteredTree_fLowPtTrackDownscaligF
    [[ -n ${AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF} ]] && export AliAnalysisTaskFilteredTree_fLowPtV0DownscaligF

    #echo aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    echo aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"${qaFilesToMerge}\",1,\"${ocdbStorage}\")"
    #aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    aliroot -b -q "QAtrain_duo.C(\"_barrel\",${runNumber},\"${qaFilesToMerge}\",1,\"${ocdbStorage}\")" > mergeQA.log
    mv QAresults_barrel.root ${qaMergedOutputFileName}
    mv trending_barrel.root trending.root

    #merge filtered trees
    echo aliroot -l -b -q "merge.C(\"${qaFilesToMerge}\",\"\",kFALSE,\"${qaMergedOutputFileName}\")"
    aliroot -l -b -q "merge.C(\"${filteredFilesToMerge}\",\"\",kFALSE,\"FilterEvents_Trees.root\")" > mergeFilteredTrees.log

    #produce the calib trees for expert QA
    echo aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")"
    aliroot -b -q "${ALICE_ROOT}/PWGPP/TPC/macros/CalibSummary.C(${runNumber},\"${ocdbStorage}\")" > calibTree.log
  fi

  tar czf ${commonOutputPath}/meta/cpass1.localOCDB.${runNumber}.tgz ./OCDB

  /bin/ls

  #copy all to output dir
  cp -pf --recursive ${runpath}/* ${outputDir}
  
  #validate merge cpass1
  cd ${outputDir}
  touch ${doneFile}
  echo "dir ${outputDir}" >> ${doneFile}
  if summarizeLogs >>  ${doneFile}; then
    [[ -f CalibObjects.root ]] && echo "calibfile ${outputDir}/CalibObjects.root" >> ${doneFile}
    [[ -f ${qaMergedOutputFileName} ]] && echo "qafile ${outputDir}/${qaMergedOutputFileName}" >> ${doneFile}
    [[ -f trending.root ]] && echo "trendingfile ${outputDir}/trending.root" >> ${doneFile}
    [[ -f dcsTime.root ]] && echo "dcsTree ${outputDir}/dcsTime.root" >> ${doneFile}
    [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
  else
    if grep "mergeQA.log.*OK" ${doneFile} > /dev/null; then
      [[ -f ${qaMergedOutputFileName} ]] && echo "qafile ${outputDir}/${qaMergedOutputFileName}" >> ${doneFile}
    fi
    if grep "mergeFilteredTrees.log.*OK" ${doneFile} > /dev/null; then
      [[ -f FilterEvents_Trees.root ]] && echo "filteredTree ${outputDir}/FilterEvents_Trees.root" >> ${doneFile}
    fi
  fi
      
  [[ "${runpath}" != "${outputDir}" ]] && rm -rf ${runpath}
  return 0
}

goMerge()
{
{'fraction_non_alphanumeric': 0.17190619553161146, 'fraction_numerical': 0.009095230549833624, 'mean_word_length': 3.462979987271056, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 179, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4864225', 'n_tokens_mistral': 23182, 'n_tokens_neox': 22387, 'n_words': 4804}