cmsRun within Condor

A few different scripts used to generate condor_submit and CMSSW configurations for submitting CMSSW jobs to our condor cluster.

Example usage:

perl condor_filelist.perl \
  python/ConfFile_MyCmsConfif_cfg.py \
  datafiles/ListOfFiles.txt \
  {CMS run options} \
  --prodSpace /local/cms/user/{username}/jobName \
  --batch 10 \
  --jobname JobName

You must run cmsenv (in your desired CMSSW distribution!) before calling condor_filelist.perl. condor_filelist.perl will then group the files in your input file list into batches based on the batch size, and generate cfg files for each job in <prodSpace>/<jobName>/cfg. Upon submission to condor, batch_cmsRun (which expects to be moved to ~/bin/batch_cmsRun) will be called for each job to set up the environment and run cmssw.

This version is set up for running on the UMN cluster, and uses the built-in file transferring utilities of condor to move the input files. In addition, each job generates a new executable named after the job name which calls batch_cmsRun from within a slc7 cmssw singularity container.

batch_cmsRun

#!/bin/sh

SCRAM_ARCH=$1
RELSPACE=$2
WORKSPACE=$3
FILE=$4
STARTDIR=$(pwd)
echo ${STARTDIR} 
if [ $# -gt "4" ]
then
    LOG=$5
else
    LOG=${FILE%%.cfg}.log
fi

if [ $# -gt "5" ]
then
    ELOG=$6
else
    ELOG=${FILE%%.cfg}.elog
fi

if [ $# -gt "6" ]
then
    /bin/rm -f $7
fi

CMSRUN_ARGUMENTS=""
for var in "${@:9}"
do
     CMSRUN_ARGUMENTS="${CMSRUN_ARGUMENTS} $var"
done

mkdir -p ${WORKSPACE} 
cd ${WORKSPACE}
/bin/hostname 
echo "INSIDE batch_cmsRun" 
echo ${RELSPACE} 
echo ${CMSRUN_ARGUMENTS} 
pwd 
# This version uses the locally installed versions of CMSSW
#source /local/cms/sw/cmsset_${SCRAM_ARCH}.sh >> ${LOG} 2>> ${ELOG}
# This version uses the remotely mounted drives at CERN
#echo "TESTING" >> ${LOG}
#set >> ${LOG}
cd ${RELSPACE}
#echo ======================== >> ${LOG}
#scram runtime -sh >> ${LOG} 2>>${ELOG}
#echo ======================== >> ${LOG}
eval 'cmsenv' 
#echo ======================== >> ${LOG}
#set >> ${LOG}
cd ${STARTDIR}
cmsRun ${FILE} ${CMSRUN_ARGUMENTS} 

condor_filelist.perl

#!/usr/bin/perl

use Getopt::Long;
use File::Basename;

#------------------------
#$prodSpace=$ENV{"HOME"}."/work";
$prodSpace="/data/whybee0b/user/".$ENV{"USER"};
$batch=10;
$startPoint=0;
$nosubmit='';
$use_xrootd=''; # '' is false in perl


$rt=$ENV{"LOCALRT"};
$arch=$ENV{"SCRAM_ARCH"};

$jobBase="default";

GetOptions(
    "batch=i" => \$batch,
    "start=i" => \$startPoint,
    "nosubmit" => \$nosubmit,
    "prodspace=s" => \$prodSpace,
    "jobname=s" => \$jobBase,
    "xrootd" => \$use_xrootd,
    "nice" => \$nice_user,
    "resubmit" => \$resub
);

$executable="$prodSpace/$jobBase/cfg/$jobBase";
print "$executable\n";
open(OUTP,">$executable");
print OUTP "#!/bin/sh\n";
print OUTP "source /local/cms/sw/cmsset_default.sh\n";
print OUTP "pwd\n";
print OUTP "hostname\n";
print OUTP "export SINGULARITY_BIND=\"/local/,/export/scratch/,/home/\"\n";
print OUTP "cmssw-cc7 --command-to-run ".$ENV{"HOME"}."/bin/batch_cmsRun \$@";
close(OUTP);
chmod 0755,$executable;
print "$#ARGV\n";
$nargs = $#ARGV;

$basecfg=shift @ARGV;
$filelist=shift @ARGV;
$cmsRunArguments=shift @ARGV;
for(my $i = 0; $i <= $nargs-3; $i++)
{  
   $nextArg=shift @ARGV;
   $cmsRunArguments=$cmsRunArguments." ".$nextArg;    
}
print "cmsRun Arguments: $cmsRunArguments\n";

if ($jobBase eq "default") {
    my $stub3=$basecfg;
    $stub3=~s|.*/||g;
    $stub3=~s|_cfg.py||;
    $stub3=~s|[.]py||;
    $jobBase=$stub3;
}

if (length($rt)<2) {
    print "You must run \"cmsenv\" in the right release area\n";
    print "before running this script!\n";
   exit(1);
}

if ($use_xrootd) {
    # Try to find the user's proxy file
    open(VOMSY,"voms-proxy-info|");
    while (<VOMSY>) {
        if (/path\s+:\s+(\S+)/) {
            $voms_proxy=$1;
        }
    }
    close(VOMSY);
}
#------------------------

print "Setting up a job based on $basecfg into $jobBase using $filelist\n";
if ($nosubmit) {
    print "  Will not actually submit this job\n";
}
if ($resub) {
	print " Resubmitting failed jobs\n";
} else {

$cfg=$basecfg;

system("mkdir -p $prodSpace/$jobBase");
mkdir("$prodSpace/$jobBase/cfg");
mkdir("$prodSpace/$jobBase/log");
}
$linearn=0;

srand(); # make sure rand is ready to go
if ($nosubmit) {
    open(SUBMIT,">condor_submit.txt");
} else {
    open(SUBMIT,"|condor_submit");
}
print(SUBMIT "Executable = $executable\n");
print(SUBMIT "Arguments = \"$cmsRunArguments\"\n");
print(SUBMIT "Universe = vanilla\n");
print(SUBMIT "initialdir = $prodSpace/$jobBase\n");
print(SUBMIT "Output = $prodSpace/$jobBase/log/output.\$(Process)\n");
print(SUBMIT "Error = $prodSpace/$jobBase/log/error.\$(Process)\n");
print(SUBMIT "request_memory = 1G\n");
print(SUBMIT "should_transfer_files = YES\n");
if ($use_xrootd) {
    # If the proxy file exists and is a normal file, we use it
    if (-f $voms_proxy) {
        print("Found voms proxy: $voms_proxy\n");
        print(SUBMIT "should_transfer_files = YES\n");
        print(SUBMIT "transfer_input_files = $voms_proxy\n");
        print(SUBMIT "X509UserProxy = $voms_proxy\n");
    }
    # Invalid file
    else {
        print("No voms proxy found! Please run `voms-proxy-init` and confirm that the file exists at /tmp/x509*\n");
        exit(1);
    }
}
if ($nice_user) {
    print(SUBMIT "nice_user = True\n");
}

open(FLIST,$filelist);
while (<FLIST>) {
    chomp;
    push @flist,$_;
}
close(FLIST);

$i=0;
$ii=$startPoint-1;

while ($i<=$#flist) {
    $ii++;

    @jobf=();
    for ($j=0; $j<$batch && $i<=$#flist; $j++) {
        if ($flist[$i]=~/file:/){
           $flist[$i]=~s|file:||;
        }
        push @jobf,$flist[$i];
        $i++;
    }
    if($resub)
    {    
       $stub2=$jobBase;
       $stub2.=sprintf("_%03d",$ii);
       $fname=$stub2.".root";
       $jobCfg="$prodSpace/$jobBase/cfg/".$stub2."_cfg.py";
       unless(-e "$prodSpace/$jobBase/$fname") {print("Resubmitting $stub2\n")}
    } else {
       $jobCfg=specializeCfg($cfg,$ii,@jobf);
    }
    unless($resub and -e "$prodSpace/$jobBase/$fname")
    {
       $stub=$jobCfg;
       $stub=~s|.*/([^/]+)_cfg.py$|$1|;
       $log="$prodSpace/$jobBase/log/$stub.log";
       $elog="$prodSpace/$jobBase/log/$stub.err";
       $sleep=(($ii*2) % 60)+2;  # Never sleep more than a ~minute, but always sleep at least 2
       print(SUBMIT "Arguments = $arch $rt $prodSpace/$jobBase $jobCfg $log $elog $fname $sleep $cmsRunArguments\n");
       print(SUBMIT "transfer_input_files = ");
       for ($jobNum=0; $jobNum<=$#jobf-1; $jobNum++) {
       	print(SUBMIT "$jobf[$jobNum],");
       }
       print(SUBMIT "$jobf[$#jobf]\n");
       print(SUBMIT "Queue\n");
    }
}

close(SUBMIT);


sub specializeCfg($$@) {
    my ($inp, $index, @files)=@_;


    $stub2=$jobBase;
    $stub2.=sprintf("_%03d",$index);

    $mycfg="$prodSpace/$jobBase/cfg/".$stub2."_cfg.py";
    print "   $inp $index --> $stub2 ($mycfg) \n";
    #print "$inp $text\n";
    open(INP,$inp);
    open(OUTP,">$mycfg");
    $sector=0;
    $had2=0;
    $had3=0;
    while(<INP>) {
        if (/TFileService/) {
            $sector=2;
            $had2=1;
        }
        if (/PoolOutputModule/) {
            $sector=3;
            $had3=1;
        }
        if (/[.]Source/) {
            $sector=1;
        }
        if (/rivetAnalyzer[.]OutputFile/) {
            $sector=4;
        }
        # TFile Service Block
        if ($sector==2 && /^[^\#]*fileName\s*=/) {
            if ($had3==1) {
                $fname=$stub2."-hist.root";
            } else {
                $fname=$stub2.".root";
            }
            unlink($fname);
            print OUTP "       fileName = cms.string(\"$fname\"),\n";
            # PoolOutputModule Block
        } elsif ($sector==3 && /^[^\#]*fileName\s*=/) {
            if ($had2==1) {
                $fname="$prodSpace/$jobBase/".$stub2."-pool.root";
            } else {
                $fname=$stub2.".root";
            }
            unlink($fname);
            print OUTP "       fileName = cms.untracked.string(\"$fname\"),\n";
            # *Source Block (PoolSource, etc.)
        } elsif ($sector==4 && /^[^\#]*rivetAnalyzer[.]OutputFile\s*=/) {          
                $fname="$prodSpace/$jobBase/".$stub2.".yoda";
            unlink($fname);
            print OUTP "process.rivetAnalyzer.OutputFile = cms.string(\"$fname\")\n";
            # PoolOutputModule Block
        } elsif ($sector==1 && /^[^\#]*fileNames\s*=/) {
            print OUTP "    fileNames=cms.untracked.vstring(\n";
            for ($qq=0; $qq<=$#files; $qq++) {
                $storefile=$files[$qq];
                if ($storefile=~/store/) {
                    if ($use_xrootd) {
                        $storefile=~s|.*/store|root://cmsxrootd.fnal.gov//store|;
                    } else {
                        $storefile=~s|.*/store|/store|;
                    }
                } else {
                    my($filename, $dirs, $suffix) = fileparse($storefile);
                    $storefile="file:".$filename;
                }

                print OUTP "         '".$storefile."'";
                print OUTP "," if ($qq!=$#files);
                print OUTP "\n";
            }
            print OUTP "     )\n";
        } else {
            print OUTP;
        }

        $depth++ if (/\{/ && $sector!=0);
        if (/\}/ && $sector!=0) {
            $depth--;
            $sector=0 if ($depth==0);
        }
#   printf("%d %d %s",$sector,$depth,$_);

    }
    close(OUTP);
    close(INP);
    return $mycfg;
}