Back to home page

Project CMSSW displayed by LXR

 
 

    


File indexing completed on 2024-06-25 22:34:46

0001 #!/usr/bin/env python3
0002 from __future__ import print_function
0003 import sys, os
0004 
0005 from Configuration.PyReleaseValidation.MatrixReader import MatrixReader
0006 from Configuration.PyReleaseValidation.MatrixRunner import MatrixRunner
0007 from Configuration.PyReleaseValidation.MatrixInjector import MatrixInjector,performInjectionOptionTest
0008 
0009 # ================================================================================
0010 
0011 def showRaw(opt):
0012 
0013     mrd = MatrixReader(opt)
0014     mrd.showRaw(opt.useInput, opt.refRel, opt.fromScratch, opt.raw, opt.step1Only, selected=opt.testList)
0015 
0016     return 0
0017 
0018 # ================================================================================
0019 
0020 def runSelected(opt):
0021 
0022     mrd = MatrixReader(opt)
0023     mrd.prepare(opt.useInput, opt.refRel, opt.fromScratch)
0024 
0025     # test for wrong input workflows
0026     if opt.testList:
0027         definedWf = [dwf.numId for dwf in mrd.workFlows]
0028         definedSet = set(definedWf)
0029         testSet = set(opt.testList)
0030         undefSet = testSet - definedSet
0031         if len(undefSet)>0: raise ValueError('Undefined workflows: '+', '.join(map(str,list(undefSet))))
0032         duplicates = [wf for wf in testSet if definedWf.count(wf)>1 ]
0033         if len(duplicates)>0: raise ValueError('Duplicated workflows: '+', '.join(map(str,list(duplicates))))
0034 
0035     ret = 0
0036     if opt.show:
0037         mrd.show(opt.testList, opt.extended, opt.cafVeto)
0038         if opt.testList : print('selected items:', opt.testList)
0039     else:
0040         mRunnerHi = MatrixRunner(mrd.workFlows, opt.nProcs, opt.nThreads)
0041         ret = mRunnerHi.runTests(opt)
0042 
0043     if opt.wmcontrol:
0044         if ret!=0:
0045             print('Cannot go on with wmagent injection with failing workflows')
0046         else:
0047             wfInjector = MatrixInjector(opt,mode=opt.wmcontrol,options=opt.wmoptions)
0048             ret= wfInjector.prepare(mrd,
0049                                     mRunnerHi.runDirs)
0050             if ret==0:
0051                 wfInjector.upload()
0052                 wfInjector.submit()
0053     return ret
0054 
0055 # ================================================================================
0056 
0057 if __name__ == '__main__':
0058 
0059     #this can get out of here
0060     predefinedSet={
0061         'limited' : [
0062                     # See README for further details
0063                     ###### MC (generated from scratch or from RelVals)
0064                     ### FullSim
0065                     # Run1 
0066                     5.1,        # TTbar_8TeV_TuneCUETP8M1       FastSim                                 
0067                     8,          # RelValBeamHalo                Cosmics
0068                     9.0,        # RelValHiggs200ChargedTaus             
0069                     25,         # RelValTTbar                           
0070                     101.0,      # SingleElectronE120EHCAL       + ECALHCAL.customise + fullMixCustomize_cff.setCrossingFrameOn
0071                     
0072                     # Run2
0073                     7.3,        # UndergroundCosmicSPLooseMu            
0074                     1306.0,     # RelValSingleMuPt1_UP15                
0075                     1330,       # RelValZMM_13                          
0076                     135.4,      # ZEE_13TeV_TuneCUETP8M1                
0077                     25202.0,    # RelValTTbar_13                PU = AVE_35_BX_25ns
0078                     250202.181, # RelValTTbar_13                PREMIX   
0079 
0080                     # Run3
0081                     11634.0,    # TTbar_14TeV                   2021
0082                     13234.0,    # RelValTTbar_14TeV             2021 FastsSim
0083                     12434.0,    # RelValTTbar_14TeV             2023
0084                     12834.0,    # RelValTTbar_14TeV             2024
0085                     12846.0,    # RelValZEE_13                  2024
0086                     13034.0,    # RelValTTbar_14TeV             2024 PU = Run3_Flat55To75_PoissonOOTPU
0087                     12834.7,    # RelValTTbar_14TeV             2024 mkFit
0088                     14034.0,    # RelValTTbar_14TeV             Run3_2023_FastSim 
0089                     14234.0,    # RelValTTbar_14TeV             Run3_2023_FastSim   PU = Run3_Flat55To75_PoissonOOTPU
0090                     2500.4,     # RelValTTbar_14TeV             NanoAOD from existing MINI
0091 
0092                     # Phase2
0093                     29634.0,    # RelValTTbar_14TeV                     phase2_realistic_T33        Extended2026D110         (Phase-2 baseline)   
0094                     29634.911,  # TTbar_14TeV_TuneCP5                   phase2_realistic_T33        DD4hepExtended2026D110   DD4Hep (HLLHC14TeV BeamSpot) 
0095                     29834.999,  # RelValTTbar_14TeV (PREMIX)            phase2_realistic_T33        Extended2026D110         AVE_50_BX_25ns_m3p3     
0096                     29696.0,    # RelValCloseByPGun_CE_E_Front_120um    phase2_realistic_T33        Extended2026D110
0097                     29700.0,    # RelValCloseByPGun_CE_H_Coarse_Scint   phase2_realistic_T33        Extended2026D110  
0098                     23234.0,    # TTbar_14TeV_TuneCP5                   phase2_realistic_T21        Extended2026D94         (exercise with HFNose) 
0099                     
0100 
0101                     ###### pp Data
0102                     ## Run1
0103                     4.22,       # Run2011A  Cosmics 
0104                     4.53,       # Run2012B  Photon                      miniAODs
0105                     1000,       # Run2011A  MinimumBias Prompt          RecoTLR.customisePrompt
0106                     1001,       # Run2011A  MinimumBias                 Data+Express
0107                     ## Run2
0108                     136.731,    # Run2016B SinglePhoton  
0109                     136.7611,   # Run2016E JetHT (reMINIAOD)            Run2_2016_HIPM + run2_miniAOD_80XLegacy
0110                     136.8311,   # Run2017F JetHT (reMINIAOD)            run2_miniAOD_94XFall17
0111                     136.88811,  # Run2018D JetHT (reMINIAOD)            run2_miniAOD_UL_preSummer20 (UL MINI)
0112                     136.793,    # Run2017C DoubleEG                      
0113                     136.874,    # Run2018C EGamma
0114                      
0115                     ## Run3
0116                     # 2021
0117                     139.001,    # Run2021  MinimumBias                  Commissioning2021   
0118                     
0119                     # 2022
0120                     140.023,    # Run2022B ZeroBias 
0121                     140.043,    # Run2022C ZeroBias 
0122                     140.063,    # Run2022D ZeroBias 
0123 
0124                     # 2023
0125                     141.044,    # Run2023D JetMET0
0126                     141.042,    # Run2023D ZeroBias
0127                     141.046,    # Run2023D EGamma0
0128 
0129                     ###### Heavy Ions
0130                     ## Data
0131                     # Run2   
0132                     140.56,    # HIRun2018A HIHardProbes                    Run2_2018_pp_on_AA 
0133                     ## MC
0134                     158.01,    # RelValHydjetQ_B12_5020GeV_2018_ppReco      (reMINIAOD) (HI MC with pp-like reco)
0135                     312.0,     # Pyquen_ZeemumuJets_pt10_2760GeV            PU : HiMixGEN 
0136 
0137                      ],
0138         'jetmc': [5.1, 13, 15, 25, 38, 39], #MC
0139         'metmc' : [5.1, 15, 25, 37, 38, 39], #MC
0140         'muonmc' : [5.1, 124.4, 124.5, 20, 21, 22, 23, 25, 30], #MC
0141         }
0142 
0143 
0144     import argparse
0145     usage = 'usage: runTheMatrix.py --show -s '
0146 
0147     parser = argparse.ArgumentParser(usage,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
0148 
0149     parser.add_argument('-b','--batchName',
0150                         help='relval batch: suffix to be appended to Campaign name',
0151                         dest='batchName',
0152                         default='')
0153 
0154     parser.add_argument('-m','--memoryOffset',
0155                         help='memory of the wf for single core',
0156                         dest='memoryOffset',
0157                         type=int,
0158                         default=3000)
0159 
0160     parser.add_argument('--addMemPerCore',
0161                         help='increase of memory per each n > 1 core:  memory(n_core) = memoryOffset + (n_core-1) * memPerCore',
0162                         dest='memPerCore',
0163                         type=int,
0164                         default=1500)
0165 
0166     parser.add_argument('-j','--nproc',
0167                         help='number of processes. 0 Will use 4 processes, not execute anything but create the wfs',
0168                         dest='nProcs',
0169                         type=int,
0170                         default=4)
0171 
0172     parser.add_argument('-t','--nThreads',
0173                         help='number of threads per process to use in cmsRun.',
0174                         dest='nThreads',
0175                         type=int,
0176                         default=1)
0177 
0178     parser.add_argument('--nStreams',
0179                         help='number of streams to use in cmsRun.',
0180                         dest='nStreams',
0181                         type=int,
0182                         default=0)
0183 
0184     parser.add_argument('--nEvents',
0185                         help='number of events to process in cmsRun. If 0 will use the standard 10 events.',
0186                         dest='nEvents',
0187                         type=int,
0188                         default=0)
0189 
0190     parser.add_argument('--numberEventsInLuminosityBlock',
0191                         help='number of events in a luminosity block',
0192                         dest='numberEventsInLuminosityBlock',
0193                         type=int,
0194                         default=-1)
0195 
0196     parser.add_argument('-n','--showMatrix',
0197                         help='Only show the worflows. Use --ext to show more',
0198                         dest='show',
0199                         default=False,
0200                         action='store_true')
0201 
0202     parser.add_argument('-e','--extended',
0203                         help='Show details of workflows, used with --show',
0204                         dest='extended',
0205                         default=False,
0206                         action='store_true')
0207 
0208     parser.add_argument('-s','--selected',
0209                         help='Run a pre-defined selected matrix of wf. Deprecated, please use -l limited',
0210                         dest='restricted',
0211                         default=False,
0212                         action='store_true')
0213 
0214     parser.add_argument('-l','--list',
0215                         help='Comma separated list of workflow to be shown or ran. Possible keys are also '+str(predefinedSet.keys())+'. and wild card like muon, or mc',
0216                         dest='testList',
0217                         default=None)
0218 
0219     parser.add_argument('-f','--failed-from',
0220                         help='Provide a matrix report to specify the workflows to be run again. Augments the -l option if specified already',
0221                         dest='failed_from',
0222                         default=None)
0223 
0224     parser.add_argument('-r','--raw',
0225                         help='Temporary dump the .txt needed for prodAgent interface. To be discontinued soon. Argument must be the name of the set (standard, pileup,...)',
0226                         dest='raw')
0227 
0228     parser.add_argument('-i','--useInput',
0229                         help='Use recyling where available. Either all, or a comma separated list of wf number.',
0230                         dest='useInput',
0231                         type=lambda x: x.split(','),
0232                         default=None)
0233 
0234     parser.add_argument('-w','--what',
0235                         help='Specify the set to be used. Argument must be the name of a set (standard, pileup,...) or multiple sets separated by commas (--what standard,pileup )',
0236                         dest='what',
0237                         default='all')
0238 
0239     parser.add_argument('--step1',
0240                         help='Used with --raw. Limit the production to step1',
0241                         dest='step1Only',
0242                         default=False)
0243 
0244     parser.add_argument('--maxSteps',
0245                         help='Only run maximum on maxSteps. Used when we are only interested in first n steps.',
0246                         dest='maxSteps',
0247                         default=9999,
0248                         type=int)
0249 
0250     parser.add_argument('--fromScratch',
0251                         help='Comma separated list of wf to be run without recycling. all is not supported as default.',
0252                         dest='fromScratch',
0253                         type=lambda x: x.split(','),
0254                         default=None)
0255 
0256     parser.add_argument('--refRelease',
0257                         help='Allow to modify the recycling dataset version',
0258                         dest='refRel',
0259                         default=None)
0260 
0261     parser.add_argument('--wmcontrol',
0262                         help='Create the workflows for injection to WMAgent. In the WORKING. -wmcontrol init will create the the workflows, -wmcontrol test will dryRun a test, -wmcontrol submit will submit to wmagent',
0263                         choices=['init','test','submit','force'],
0264                         dest='wmcontrol',
0265                         default=None)
0266 
0267     parser.add_argument('--revertDqmio',
0268                         help='When submitting workflows to wmcontrol, force DQM outout to use pool and not DQMIO',
0269                         choices=['yes','no'],
0270                         dest='revertDqmio',
0271                         default='no')
0272 
0273     parser.add_argument('--optionswm',
0274                         help='Specify a few things for wm injection',
0275                         default='',
0276                         dest='wmoptions')
0277 
0278     parser.add_argument('--keep',
0279                         help='allow to specify for which comma separated steps the output is needed',
0280                         default=None)
0281 
0282     parser.add_argument('--label',
0283                         help='allow to give a special label to the output dataset name',
0284                         default='')
0285 
0286     parser.add_argument('--command',
0287                         help='provide a way to add additional command to all of the cmsDriver commands in the matrix',
0288                         dest='command',
0289                         action='append',
0290                         default=None)
0291 
0292     parser.add_argument('--apply',
0293                         help='allow to use the --command only for 1 comma separeated',
0294                         dest='apply',
0295                         default=None)
0296 
0297     parser.add_argument('--workflow',
0298                         help='define a workflow to be created or altered from the matrix',
0299                         action='append',
0300                         dest='workflow',
0301                         default=None)
0302 
0303     parser.add_argument('--dryRun',
0304                         help='do not run the wf at all',
0305                         action='store_true',
0306                         dest='dryRun',
0307                         default=False)
0308 
0309     parser.add_argument('--testbed',
0310                         help='workflow injection to cmswebtest (you need dedicated rqmgr account)',
0311                         dest='testbed',
0312                         default=False,
0313                         action='store_true')
0314 
0315     parser.add_argument('--noCafVeto',
0316                         help='Run from any source, ignoring the CAF label',
0317                         dest='cafVeto',
0318                         default=True,
0319                         action='store_false')
0320 
0321     parser.add_argument('--overWrite',
0322                         help='Change the content of a step for another. List of pairs.',
0323                         dest='overWrite',
0324                         default=None)
0325 
0326     parser.add_argument('--noRun',
0327                         help='Remove all run list selection from wfs',
0328                         dest='noRun',
0329                         default=False,
0330                         action='store_true')
0331 
0332     parser.add_argument('--das-options',
0333                         help='Options to be passed to dasgoclient.',
0334                         dest='dasOptions',
0335                         default="--limit 0",
0336                         action='store')
0337 
0338     parser.add_argument('--job-reports',
0339                         help='Dump framework job reports',
0340                         dest='jobReports',
0341                         default=False,
0342                         action='store_true')
0343 
0344     parser.add_argument('--ibeos',
0345                         help='Use IB EOS site configuration',
0346                         dest='IBEos',
0347                         default=False,
0348                         action='store_true')
0349 
0350     parser.add_argument('--sites',
0351                         help='Run DAS query to get data from a specific site. Set it to empty string to search all sites.',
0352                         dest='dasSites',
0353                         default='T2_CH_CERN',
0354                         action='store')
0355 
0356     parser.add_argument('--interactive',
0357                         help="Open the Matrix interactive shell",
0358                         action='store_true',
0359                         default=False)
0360 
0361     parser.add_argument('--dbs-url',
0362                         help='Overwrite DbsUrl value in JSON submitted to ReqMgr2',
0363                         dest='dbsUrl',
0364                         default=None,
0365                         action='store')
0366 
0367     gpugroup = parser.add_argument_group('GPU-related options','These options are only meaningful when --gpu is used, and is not set to forbidden.')
0368 
0369     gpugroup.add_argument('--gpu','--requires-gpu',
0370                           help='Enable GPU workflows. Possible options are "forbidden" (default), "required" (implied if no argument is given), or "optional".',
0371                           dest='gpu',
0372                           choices=['forbidden', 'optional', 'required'],
0373                           nargs='?',
0374                           const='required',
0375                           default='forbidden',
0376                           action='store')
0377 
0378     gpugroup.add_argument('--gpu-memory',
0379                           help='Specify the minimum amount of GPU memory required by the job, in MB.',
0380                           dest='GPUMemoryMB',
0381                           type=int,
0382                           default=8000)
0383 
0384     gpugroup.add_argument('--cuda-capabilities',
0385                           help='Specify a comma-separated list of CUDA "compute capabilities", or GPU hardware architectures, that the job can use.',
0386                           dest='CUDACapabilities',
0387                           type=lambda x: x.split(','),
0388                           default='6.0,6.1,6.2,7.0,7.2,7.5,8.0,8.6')
0389 
0390     # read the CUDA runtime version included in CMSSW
0391     cudart_version = None
0392     libcudart = os.path.realpath(os.path.expandvars('$CMSSW_RELEASE_BASE/external/$SCRAM_ARCH/lib/libcudart.so'))
0393     if os.path.isfile(libcudart):
0394         cudart_basename = os.path.basename(libcudart)
0395         cudart_version = '.'.join(cudart_basename.split('.')[2:4])
0396     gpugroup.add_argument('--cuda-runtime',
0397                           help='Specify major and minor version of the CUDA runtime used to build the application.',
0398                           dest='CUDARuntime',
0399                           default=cudart_version)
0400 
0401     gpugroup.add_argument('--force-gpu-name',
0402                           help='Request a specific GPU model, e.g. "Tesla T4" or "NVIDIA GeForce RTX 2080". The default behaviour is to accept any supported GPU.',
0403                           dest='GPUName',
0404                           default='')
0405 
0406     gpugroup.add_argument('--force-cuda-driver-version',
0407                           help='Request a specific CUDA driver version, e.g. 470.57.02. The default behaviour is to accept any supported CUDA driver version.',
0408                           dest='CUDADriverVersion',
0409                           default='')
0410 
0411     gpugroup.add_argument('--force-cuda-runtime-version',
0412                           help='Request a specific CUDA runtime version, e.g. 11.4. The default behaviour is to accept any supported CUDA runtime version.',
0413                           dest='CUDARuntimeVersion',
0414                           default='')
0415 
0416     opt = parser.parse_args()
0417     if opt.command: opt.command = ' '.join(opt.command)
0418     os.environ["CMSSW_DAS_QUERY_SITES"]=opt.dasSites
0419     if opt.failed_from:
0420         rerunthese=[]
0421         with open(opt.failed_from,'r') as report:
0422             for report_line in report:
0423                 if 'FAILED' in report_line:
0424                     to_run,_=report_line.split('_',1)
0425                     rerunthese.append(to_run)
0426         if opt.testList:
0427             opt.testList+=','.join(['']+rerunthese)
0428         else:
0429             opt.testList = ','.join(rerunthese)
0430 
0431     if opt.IBEos:
0432       from subprocess import getstatusoutput as run_cmd
0433 
0434       ibeos_cache = os.path.join(os.getenv("LOCALRT"), "ibeos_cache.txt")
0435       if not os.path.exists(ibeos_cache):
0436         err, out = run_cmd("curl -L -s -o %s https://raw.githubusercontent.com/cms-sw/cms-sw.github.io/master/das_queries/ibeos.txt" % ibeos_cache)
0437         if err:
0438           run_cmd("rm -f %s" % ibeos_cache)
0439           print("Error: Unable to download ibeos cache information")
0440           print(out)
0441           sys.exit(err)
0442 
0443       for cmssw_env in [ "CMSSW_BASE", "CMSSW_RELEASE_BASE" ]:
0444         cmssw_base = os.getenv(cmssw_env,None)
0445         if not cmssw_base: continue
0446         cmssw_base = os.path.join(cmssw_base,"src/Utilities/General/ibeos")
0447         if os.path.exists(cmssw_base):
0448           os.environ["PATH"]=cmssw_base+":"+os.getenv("PATH")
0449           os.environ["CMS_PATH"]="/cvmfs/cms-ib.cern.ch"
0450           os.environ["SITECONFIG_PATH"]="/cvmfs/cms-ib.cern.ch/SITECONF/local"
0451           os.environ["CMSSW_USE_IBEOS"]="true"
0452           print(">> WARNING: You are using SITECONF from /cvmfs/cms-ib.cern.ch")
0453           break
0454     if opt.restricted:
0455         print('Deprecated, please use -l limited')
0456         if opt.testList:            opt.testList+=',limited'
0457         else:            opt.testList='limited'
0458 
0459     def stepOrIndex(s):
0460         if s.isdigit():
0461             return int(s)
0462         else:
0463             return s
0464     if opt.apply:
0465         opt.apply=map(stepOrIndex,opt.apply.split(','))
0466     if opt.keep:
0467         opt.keep=map(stepOrIndex,opt.keep.split(','))
0468 
0469     if opt.testList:
0470         testList=[]
0471         for entry in opt.testList.split(','):
0472             if not entry: continue
0473             mapped=False
0474             for k in predefinedSet:
0475                 if k.lower().startswith(entry.lower()) or k.lower().endswith(entry.lower()):
0476                     testList.extend(predefinedSet[k])
0477                     mapped=True
0478                     break
0479             if not mapped:
0480                 try:
0481                     testList.append(float(entry))
0482                 except:
0483                     print(entry,'is not a possible selected entry')
0484 
0485         opt.testList = list(set(testList))
0486 
0487     if opt.wmcontrol:
0488         performInjectionOptionTest(opt)
0489     if opt.overWrite:
0490         opt.overWrite=eval(opt.overWrite)
0491     if opt.interactive:
0492         import cmd
0493         from colorama import Fore, Style
0494         from os import isatty
0495         import subprocess
0496         import time
0497 
0498         class TheMatrix(cmd.Cmd):
0499             intro = "Welcome to the Matrix (? for help)"
0500             prompt = "matrix> "
0501 
0502             def __init__(self, opt):
0503                 cmd.Cmd.__init__(self)
0504                 self.opt_ = opt
0505                 self.matrices_ = {}
0506                 tmp = MatrixReader(self.opt_)
0507                 self.processes_ = dict()
0508                 for what in tmp.files:
0509                     what = what.replace('relval_','')
0510                     self.opt_.what = what
0511                     self.matrices_[what] = MatrixReader(self.opt_)
0512                     self.matrices_[what].prepare(self.opt_.useInput, self.opt_.refRel,
0513                                                 self.opt_.fromScratch)
0514                 os.system("clear")
0515 
0516             def do_clear(self, arg):
0517                 """Clear the screen, put prompt at the top"""
0518                 os.system("clear")
0519 
0520             def do_exit(self, arg):
0521                 print("Leaving the Matrix")
0522                 return True
0523 
0524             def default(self, inp):
0525                 if inp == 'x' or inp == 'q':
0526                     return self.do_exit(inp)
0527                 else:
0528                     is_pipe = not isatty(sys.stdin.fileno())
0529                     print(Fore.RED + "Error: " + Fore.RESET + "unrecognized command.")
0530                     # Quit only if given a piped command.
0531                     if is_pipe:
0532                       sys.exit(1)
0533 
0534             def help_predefined(self):
0535                 print("\n".join(["predefined [predef1 [...]]\n",
0536                 "Run w/o argument, it will print the list of known predefined workflows.",
0537                 "Run with space-separated predefined workflows, it will print the workflow-ids registered to them"]))
0538 
0539             def complete_predefined(self, text, line, start_idx, end_idx):
0540                 if text and len(text) > 0:
0541                     return [t for t in predefinedSet.keys() if t.startswith(text)]
0542                 else:
0543                     return predefinedSet.keys()
0544 
0545             def do_predefined(self, arg):
0546                 """Print the list of predefined workflows"""
0547                 print("List of predefined workflows")
0548                 if arg:
0549                     for w in arg.split():
0550                         if w in predefinedSet.keys():
0551                             print("Predefined Set: %s" % w)
0552                             print(predefinedSet[w])
0553                         else:
0554                             print("Unknown Set: %s" % w)
0555                 else:
0556                     print("[ " + Fore.RED + ", ".join([str(k) for k in predefinedSet.keys()]) + Fore.RESET + " ]")
0557 
0558             def help_showWorkflow(self):
0559                 print("\n".join(["showWorkflow [workflow1 [...]]\n",
0560                     "Run w/o arguments, it will print the list of registered macro-workflows.",
0561                     "Run with space-separated workflows, it will print the full list of workflow-ids registered to them"]))
0562 
0563             def complete_showWorkflow(self, text, line, start_idx, end_idx):
0564                 if text and len(text) > 0:
0565                     return [t for t in self.matrices_.keys() if t.startswith(text)]
0566                 else:
0567                     return self.matrices_.keys()
0568 
0569             def do_showWorkflow(self, arg):
0570                 if arg == '':
0571                     print("Available workflows:")
0572                     for k in self.matrices_.keys():
0573                         print(Fore.RED + Style.BRIGHT + k)
0574                     print(Style.RESET_ALL)
0575                 else:
0576                     selected = arg.split()
0577                     for k in selected:
0578                         if k not in self.matrices_.keys():
0579                             print("Unknown workflow %s: skipping" % k)
0580                         else:
0581                             for wfl in self.matrices_[k].workFlows:
0582                                 print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
0583                                                               Fore.GREEN + wfl.nameId + Fore.RESET))
0584                             print("%s contains %d workflows" % (Fore.RED + k + Fore.RESET, len(self.matrices_[k].workFlows)))
0585 
0586             def do_runWorkflow(self, arg):
0587                 # Split the input arguments into a list
0588                 args = arg.split()
0589                 if len(args) < 2:
0590                     print(Fore.RED + Style.BRIGHT + "Wrong number of parameters passed")
0591                     print(Style.RESET_ALL)
0592                     return
0593                 workflow_class = args[0]
0594                 workflow_id = args[1]
0595                 passed_down_args = list()
0596                 if len(args) > 2:
0597                   passed_down_args = args[2:]
0598                 print(Fore.YELLOW + Style.BRIGHT + "Running with the following options:\n")
0599                 print(Fore.GREEN + Style.BRIGHT + "Workflow class: {}".format(workflow_class))
0600                 print(Fore.GREEN + Style.BRIGHT + "Workflow ID:    {}".format(workflow_id))
0601                 print(Fore.GREEN + Style.BRIGHT + "Additional runTheMatrix options: {}".format(passed_down_args))
0602                 print(Style.RESET_ALL)
0603                 if workflow_class not in self.matrices_.keys():
0604                     print(Fore.RED + Style.BRIGHT + "Unknown workflow selected: {}".format(workflow_class))
0605                     print("Available workflows:")
0606                     for k in self.matrices_.keys():
0607                          print(Fore.RED + Style.BRIGHT + k)
0608                     print(Style.RESET_ALL)
0609                     return
0610                 wflnums = [x.numId for x in self.matrices_[workflow_class].workFlows]
0611                 if float(workflow_id) not in wflnums:
0612                     print(Fore.RED + Style.BRIGHT + "Unknown workflow {}".format(workflow_id))
0613                     print(Fore.GREEN + Style.BRIGHT)
0614                     print(wflnums)
0615                     print(Style.RESET_ALL)
0616                     return
0617                 if workflow_id in self.processes_.keys():
0618                     # Check if the process is still active
0619                     if self.processes_[workflow_id][0].poll() is None:
0620                         print(Fore.RED + Style.BRIGHT + "Workflow {} already running!".format(workflow_id))
0621                         print(Style.RESET_ALL)
0622                         return
0623                 # If it was there but it's gone, proceeed and update the value for the same key
0624                 # run a job, redirecting standard output and error to files
0625                 lognames = ['stdout', 'stderr']
0626                 logfiles = tuple('%s_%s_%s.log' % (workflow_class, workflow_id, name) for name in lognames)
0627                 stdout = open(logfiles[0], 'w')
0628                 stderr = open(logfiles[1], 'w')
0629                 command = ('runTheMatrix.py', '-w', workflow_class, '-l', workflow_id)
0630                 if len(passed_down_args) > 0:
0631                   command += tuple(passed_down_args)
0632                 print(command)
0633                 p = subprocess.Popen(command,
0634                     stdout = stdout,
0635                     stderr = stderr)
0636                 self.processes_[workflow_id] = (p, time.time())
0637 
0638 
0639             def complete_runWorkflow(self, text, line, start_idx, end_idx):
0640                 if text and len(text) > 0:
0641                     return [t for t in self.matrices_.keys() if t.startswith(text)]
0642                 else:
0643                     return self.matrices_.keys()
0644 
0645             def help_runWorkflow(self):
0646               print("\n".join(["runWorkflow workflow_class workflow_id\n",
0647                 "This command will launch a new and independent process that invokes",
0648                 "the command:\n",
0649                 "runTheMatrix.py -w workflow_class -l workflow_id [runTheMatrix.py options]",
0650                 "\nYou can specify just one workflow_class and workflow_id per invocation.",
0651                 "The job will continue even after quitting the interactive session.",
0652                 "stdout and stderr of the new process will be automatically",
0653                 "redirected to 2 logfiles whose names contain the workflow_class",
0654                 "and workflow_id. Mutiple command can be issued one after the other.",
0655                 "The working directory of the new process will be the directory",
0656                 "from which the interactive session has started.",
0657                 "Autocompletion is available for workflow_class, but",
0658                 "not for workflow_id. Supplying a wrong workflow_class or",
0659                 "a non-existing workflow_id for a valid workflow_class",
0660                 "will trigger an error and no process will be invoked.",
0661                 "The interactive shell will keep track of all active processes",
0662                 "and will prevent the accidental resubmission of an already",
0663                 "active jobs."]))
0664 
0665             def do_jobs(self, args):
0666                 print(Fore.GREEN + Style.BRIGHT + "List of jobs:")
0667                 for w in self.processes_.keys():
0668                     if self.processes_[w][0].poll() is None:
0669                       print(Fore.YELLOW + Style.BRIGHT + "Active job: {} since {:.2f} seconds.".format(w, time.time() - self.processes_[w][1]))
0670                     else:
0671                         print(Fore.RED + Style.BRIGHT + "Done job: {}".format(w))
0672                 print(Style.RESET_ALL)
0673 
0674             def help_jobs(self):
0675               print("\n".join(["Print a full list of active and done jobs submitted",
0676                 "in the ongoing interactive session"]))
0677 
0678             def help_searchInWorkflow(self):
0679                 print("\n".join(["searchInWorkflow wfl_name search_regexp\n",
0680                     "This command will search for a match within all workflows registered to wfl_name.",
0681                     "The search is done on both the workflow name and the names of steps registered to it."]))
0682 
0683             def complete_searchInWorkflow(self, text, line, start_idx, end_idx):
0684                 if text and len(text) > 0:
0685                     return [t for t in self.matrices_.keys() if t.startswith(text)]
0686                 else:
0687                     return self.matrices_.keys()
0688 
0689             def do_searchInWorkflow(self, arg):
0690                 args = arg.split()
0691                 if len(args) < 2:
0692                     print("searchInWorkflow name regexp")
0693                     return
0694                 if args[0] not in self.matrices_.keys():
0695                     print("Unknown workflow")
0696                     return
0697                 import re
0698                 pattern = None
0699                 try:
0700                     pattern = re.compile(args[1])
0701                 except:
0702                     print("Failed to compile regexp %s" % args[1])
0703                     return
0704                 counter = 0
0705                 for wfl in self.matrices_[args[0]].workFlows:
0706                     if re.match(pattern, wfl.nameId):
0707                       print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
0708                                        Fore.GREEN + wfl.nameId + Fore.RESET))
0709                       counter +=1
0710                 print("Found %s compatible workflows inside %s" % (Fore.RED + str(counter) + Fore.RESET,
0711                                                                    Fore.YELLOW + str(args[0])) + Fore.RESET)
0712 
0713             def help_search(self):
0714                 print("\n".join(["search search_regexp\n",
0715                     "This command will search for a match within all workflows registered.",
0716                     "The search is done on both the workflow name and the names of steps registered to it."]))
0717 
0718             def do_search(self, arg):
0719                 args = arg.split()
0720                 if len(args) < 1:
0721                     print("search regexp")
0722                     return
0723                 for wfl in self.matrices_.keys():
0724                     self.do_searchInWorkflow(' '.join([wfl, args[0]]))
0725 
0726             def help_dumpWorkflowId(self):
0727                 print("\n".join(["dumpWorkflowId [wfl-id1 [...]]\n",
0728                     "Dumps the details (cmsDriver commands for all steps) of the space-separated workflow-ids in input."]))
0729 
0730             def do_dumpWorkflowId(self, arg):
0731                 wflids = arg.split()
0732                 if len(wflids) == 0:
0733                     print("dumpWorkflowId [wfl-id1 [...]]")
0734                     return
0735 
0736                 fmt   = "[%s]: %s\n"
0737                 maxLen = 100
0738                 for wflid in wflids:
0739                     dump = True
0740                     for key, mrd in self.matrices_.items():
0741                         for wfl in mrd.workFlows:
0742                             if wfl.numId == float(wflid):
0743                                 if dump:
0744                                     dump = False
0745                                     print(Fore.GREEN + str(wfl.numId) + Fore.RESET + " " + Fore.YELLOW + wfl.nameId + Fore.RESET)
0746                                     for i,s in enumerate(wfl.cmds):
0747                                         print(fmt % (Fore.RED + str(i+1) + Fore.RESET,
0748                                           (str(s)+' ')))
0749                                     print("\nWorkflow found in %s." % key)
0750                                 else:
0751                                     print("Workflow also found in %s." % key)
0752 
0753             do_EOF = do_exit
0754 
0755         TheMatrix(opt).cmdloop()
0756         sys.exit(0)
0757 
0758     if opt.raw and opt.show: ###prodAgent to be discontinued
0759         ret = showRaw(opt)
0760     else:
0761         ret = runSelected(opt)
0762 
0763 
0764     sys.exit(ret)