CMS 3D CMS Logo

runTheMatrix.py
Go to the documentation of this file.
1 #!/usr/bin/env python3
2 from __future__ import print_function
3 import sys, os
4 
5 from Configuration.PyReleaseValidation.MatrixReader import MatrixReader
6 from Configuration.PyReleaseValidation.MatrixRunner import MatrixRunner
7 from Configuration.PyReleaseValidation.MatrixInjector import MatrixInjector,performInjectionOptionTest
8 
9 # ================================================================================
10 
11 def showRaw(opt):
12 
13  mrd = MatrixReader(opt)
14  mrd.showRaw(opt.useInput, opt.refRel, opt.fromScratch, opt.raw, opt.step1Only, selected=opt.testList)
15 
16  return 0
17 
18 # ================================================================================
19 
20 def runSelected(opt):
21 
22  mrd = MatrixReader(opt)
23  mrd.prepare(opt.useInput, opt.refRel, opt.fromScratch)
24 
25  # test for wrong input workflows
26  if opt.testList:
27  definedWf = [dwf.numId for dwf in mrd.workFlows]
28  definedSet = set(definedWf)
29  testSet = set(opt.testList)
30  undefSet = testSet - definedSet
31  if len(undefSet)>0: raise ValueError('Undefined workflows: '+', '.join(map(str,list(undefSet))))
32  duplicates = [wf for wf in testSet if definedWf.count(wf)>1 ]
33  if len(duplicates)>0: raise ValueError('Duplicated workflows: '+', '.join(map(str,list(duplicates))))
34 
35  ret = 0
36  if opt.show:
37  mrd.show(opt.testList, opt.extended, opt.cafVeto)
38  if opt.testList : print('testListected items:', opt.testList)
39  else:
40  mRunnerHi = MatrixRunner(mrd.workFlows, opt.nProcs, opt.nThreads)
41  ret = mRunnerHi.runTests(opt)
42 
43  if opt.wmcontrol:
44  if ret!=0:
45  print('Cannot go on with wmagent injection with failing workflows')
46  else:
47  wfInjector = MatrixInjector(opt,mode=opt.wmcontrol,options=opt.wmoptions)
48  ret= wfInjector.prepare(mrd,
49  mRunnerHi.runDirs)
50  if ret==0:
51  wfInjector.upload()
52  wfInjector.submit()
53  return ret
54 
55 # ================================================================================
56 
57 if __name__ == '__main__':
58 
59  #this can get out of here
60  predefinedSet={
61  'limited' : [5.1, #FastSim ttbar
62  7.3, #CosmicsSPLoose_UP17
63  8, #BH/Cosmic MC
64  25, #MC ttbar
65  4.22, #cosmic data
66  4.53, #run1 data + miniAOD
67  9.0, #Higgs200 charged taus
68  1000, #data+prompt
69  1001, #data+express
70  101.0, #SingleElectron120E120EHCAL
71  136.731, #2016B Photon data
72  136.7611, #2016E JetHT reMINIAOD from 80X legacy
73  136.8311, #2017F JetHT reMINIAOD from 94X reprocessing
74  136.88811,#2018D JetHT reMINIAOD from UL processing
75  136.793, #2017C DoubleEG
76  136.874, #2018C EGamma
77  138.4, #2021 MinimumBias prompt reco
78  138.5, #2021 MinimumBias express
79  139.001, #2021 MinimumBias offline with HLT step
80  140.53, #2011 HI data
81  140.56, #2018 HI data
82  158.01, #reMiniAOD of 2018 HI MC with pp-like reco
83  312.0, #2021/Run3 HI MC Pyquen_ZeemumuJets_pt10 with pp-like reco
84  1306.0, #SingleMu Pt1 UP15
85  2500.601, #test NanoAOD from existing MINI
86  1330, #Run2 2015/2016 MC Zmm
87  135.4, #Run 2 2015/2016 Zee ttbar fastsim
88  10042.0, #2017 ZMM
89  10024.0, #2017 ttbar
90  10824.0, #2018 ttbar
91  2018.1, #2018 ttbar fastsim
92  11634.911, #2021 DD4hep ttbar reading geometry from XML
93  11634.914, #2021 DDD ttbar reading geometry from the DB
94  11634.0, #2021 ttbar (switching to DD4hep by default)
95  11834.0, #2021 ttbar PU
96  13234.0, #2021 ttbar fastsim
97  13434.0, #2021 ttbar PU fastsim
98  12434.0, #2023 ttbar
99  12434.7, #2023 ttbar mkFit
100  20834.0, #2026D88 ttbar (2022 new baseline)
101  20834.75, #2026D88 ttbar with HLT75e33
102  20834.76, #2026D88 ttbar with HLT75e33 in the same step as DIGI+L1
103  #20834.911, #2026D88 ttbar DD4hep XML
104  21034.999, #2026D88 ttbar premixing stage1+stage2, PU50
105  20896.0, #CE_E_Front_120um D88
106  20900.0, #CE_H_Coarse_Scint D88
107  23234.0, #2026D94 ttbar (exercise with HFNose)
108  25202.0, #2016 ttbar UP15 PU
109  250202.181, #2018 ttbar stage1 + stage2 premix
110  ],
111  'jetmc': [5.1, 13, 15, 25, 38, 39], #MC
112  'metmc' : [5.1, 15, 25, 37, 38, 39], #MC
113  'muonmc' : [5.1, 124.4, 124.5, 20, 21, 22, 23, 25, 30], #MC
114  }
115 
116 
117  import argparse
118  usage = 'usage: runTheMatrix.py --show -s '
119 
120  parser = argparse.ArgumentParser(usage,formatter_class=argparse.ArgumentDefaultsHelpFormatter)
121 
122  parser.add_argument('-b','--batchName',
123  help='relval batch: suffix to be appended to Campaign name',
124  dest='batchName',
125  default='')
126 
127  parser.add_argument('-m','--memoryOffset',
128  help='memory of the wf for single core',
129  dest='memoryOffset',
130  type=int,
131  default=3000)
132 
133  parser.add_argument('--addMemPerCore',
134  help='increase of memory per each n > 1 core: memory(n_core) = memoryOffset + (n_core-1) * memPerCore',
135  dest='memPerCore',
136  type=int,
137  default=1500)
138 
139  parser.add_argument('-j','--nproc',
140  help='number of processes. 0 Will use 4 processes, not execute anything but create the wfs',
141  dest='nProcs',
142  type=int,
143  default=4)
144 
145  parser.add_argument('-t','--nThreads',
146  help='number of threads per process to use in cmsRun.',
147  dest='nThreads',
148  type=int,
149  default=1)
150 
151  parser.add_argument('--nStreams',
152  help='number of streams to use in cmsRun.',
153  dest='nStreams',
154  type=int,
155  default=0)
156 
157  parser.add_argument('--numberEventsInLuminosityBlock',
158  help='number of events in a luminosity block',
159  dest='numberEventsInLuminosityBlock',
160  type=int,
161  default=-1)
162 
163  parser.add_argument('-n','--showMatrix',
164  help='Only show the worflows. Use --ext to show more',
165  dest='show',
166  default=False,
167  action='store_true')
168 
169  parser.add_argument('-e','--extended',
170  help='Show details of workflows, used with --show',
171  dest='extended',
172  default=False,
173  action='store_true')
174 
175  parser.add_argument('-s','--selected',
176  help='Run a pre-defined selected matrix of wf. Deprecated, please use -l limited',
177  dest='restricted',
178  default=False,
179  action='store_true')
180 
181  parser.add_argument('-l','--list',
182  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',
183  dest='testList',
184  default=None)
185 
186  parser.add_argument('-f','--failed-from',
187  help='Provide a matrix report to specify the workflows to be run again. Augments the -l option if specified already',
188  dest='failed_from',
189  default=None)
190 
191  parser.add_argument('-r','--raw',
192  help='Temporary dump the .txt needed for prodAgent interface. To be discontinued soon. Argument must be the name of the set (standard, pileup,...)',
193  dest='raw')
194 
195  parser.add_argument('-i','--useInput',
196  help='Use recyling where available. Either all, or a comma separated list of wf number.',
197  dest='useInput',
198  type=lambda x: x.split(','),
199  default=None)
200 
201  parser.add_argument('-w','--what',
202  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 )',
203  dest='what',
204  default='all')
205 
206  parser.add_argument('--step1',
207  help='Used with --raw. Limit the production to step1',
208  dest='step1Only',
209  default=False)
210 
211  parser.add_argument('--maxSteps',
212  help='Only run maximum on maxSteps. Used when we are only interested in first n steps.',
213  dest='maxSteps',
214  default=9999,
215  type=int)
216 
217  parser.add_argument('--fromScratch',
218  help='Comma separated list of wf to be run without recycling. all is not supported as default.',
219  dest='fromScratch',
220  type=lambda x: x.split(','),
221  default=None)
222 
223  parser.add_argument('--refRelease',
224  help='Allow to modify the recycling dataset version',
225  dest='refRel',
226  default=None)
227 
228  parser.add_argument('--wmcontrol',
229  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',
230  choices=['init','test','submit','force'],
231  dest='wmcontrol',
232  default=None)
233 
234  parser.add_argument('--revertDqmio',
235  help='When submitting workflows to wmcontrol, force DQM outout to use pool and not DQMIO',
236  choices=['yes','no'],
237  dest='revertDqmio',
238  default='no')
239 
240  parser.add_argument('--optionswm',
241  help='Specify a few things for wm injection',
242  default='',
243  dest='wmoptions')
244 
245  parser.add_argument('--keep',
246  help='allow to specify for which comma separated steps the output is needed',
247  default=None)
248 
249  parser.add_argument('--label',
250  help='allow to give a special label to the output dataset name',
251  default='')
252 
253  parser.add_argument('--command',
254  help='provide a way to add additional command to all of the cmsDriver commands in the matrix',
255  dest='command',
256  action='append',
257  default=None)
258 
259  parser.add_argument('--apply',
260  help='allow to use the --command only for 1 comma separeated',
261  dest='apply',
262  default=None)
263 
264  parser.add_argument('--workflow',
265  help='define a workflow to be created or altered from the matrix',
266  action='append',
267  dest='workflow',
268  default=None)
269 
270  parser.add_argument('--dryRun',
271  help='do not run the wf at all',
272  action='store_true',
273  dest='dryRun',
274  default=False)
275 
276  parser.add_argument('--testbed',
277  help='workflow injection to cmswebtest (you need dedicated rqmgr account)',
278  dest='testbed',
279  default=False,
280  action='store_true')
281 
282  parser.add_argument('--noCafVeto',
283  help='Run from any source, ignoring the CAF label',
284  dest='cafVeto',
285  default=True,
286  action='store_false')
287 
288  parser.add_argument('--overWrite',
289  help='Change the content of a step for another. List of pairs.',
290  dest='overWrite',
291  default=None)
292 
293  parser.add_argument('--noRun',
294  help='Remove all run list selection from wfs',
295  dest='noRun',
296  default=False,
297  action='store_true')
298 
299  parser.add_argument('--das-options',
300  help='Options to be passed to dasgoclient.',
301  dest='dasOptions',
302  default="--limit 0",
303  action='store')
304 
305  parser.add_argument('--job-reports',
306  help='Dump framework job reports',
307  dest='jobReports',
308  default=False,
309  action='store_true')
310 
311  parser.add_argument('--ibeos',
312  help='Use IB EOS site configuration',
313  dest='IBEos',
314  default=False,
315  action='store_true')
316 
317  parser.add_argument('--sites',
318  help='Run DAS query to get data from a specific site. Set it to empty string to search all sites.',
319  dest='dasSites',
320  default='T2_CH_CERN',
321  action='store')
322 
323  parser.add_argument('--interactive',
324  help="Open the Matrix interactive shell",
325  action='store_true',
326  default=False)
327 
328  parser.add_argument('--dbs-url',
329  help='Overwrite DbsUrl value in JSON submitted to ReqMgr2',
330  dest='dbsUrl',
331  default=None,
332  action='store')
333 
334  gpugroup = parser.add_argument_group('GPU-related options','These options are only meaningful when --gpu is used, and is not set to forbidden.')
335 
336  gpugroup.add_argument('--gpu','--requires-gpu',
337  help='Enable GPU workflows. Possible options are "forbidden" (default), "required" (implied if no argument is given), or "optional".',
338  dest='gpu',
339  choices=['forbidden', 'optional', 'required'],
340  nargs='?',
341  const='required',
342  default='forbidden',
343  action='store')
344 
345  gpugroup.add_argument('--gpu-memory',
346  help='Specify the minimum amount of GPU memory required by the job, in MB.',
347  dest='GPUMemoryMB',
348  type=int,
349  default=8000)
350 
351  gpugroup.add_argument('--cuda-capabilities',
352  help='Specify a comma-separated list of CUDA "compute capabilities", or GPU hardware architectures, that the job can use.',
353  dest='CUDACapabilities',
354  type=lambda x: x.split(','),
355  default='6.0,6.1,6.2,7.0,7.2,7.5,8.0,8.6')
356 
357  # read the CUDA runtime version included in CMSSW
358  cudart_version = None
359  libcudart = os.path.realpath(os.path.expandvars('$CMSSW_RELEASE_BASE/external/$SCRAM_ARCH/lib/libcudart.so'))
360  if os.path.isfile(libcudart):
361  cudart_basename = os.path.basename(libcudart)
362  cudart_version = '.'.join(cudart_basename.split('.')[2:4])
363  gpugroup.add_argument('--cuda-runtime',
364  help='Specify major and minor version of the CUDA runtime used to build the application.',
365  dest='CUDARuntime',
366  default=cudart_version)
367 
368  gpugroup.add_argument('--force-gpu-name',
369  help='Request a specific GPU model, e.g. "Tesla T4" or "NVIDIA GeForce RTX 2080". The default behaviour is to accept any supported GPU.',
370  dest='GPUName',
371  default='')
372 
373  gpugroup.add_argument('--force-cuda-driver-version',
374  help='Request a specific CUDA driver version, e.g. 470.57.02. The default behaviour is to accept any supported CUDA driver version.',
375  dest='CUDADriverVersion',
376  default='')
377 
378  gpugroup.add_argument('--force-cuda-runtime-version',
379  help='Request a specific CUDA runtime version, e.g. 11.4. The default behaviour is to accept any supported CUDA runtime version.',
380  dest='CUDARuntimeVersion',
381  default='')
382 
383  opt = parser.parse_args()
384  if opt.command: opt.command = ' '.join(opt.command)
385  os.environ["CMSSW_DAS_QUERY_SITES"]=opt.dasSites
386  if opt.failed_from:
387  rerunthese=[]
388  with open(opt.failed_from,'r') as report:
389  for report_line in report:
390  if 'FAILED' in report_line:
391  to_run,_=report_line.split('_',1)
392  rerunthese.append(to_run)
393  if opt.testList:
394  opt.testList+=','.join(['']+rerunthese)
395  else:
396  opt.testList = ','.join(rerunthese)
397 
398  if opt.IBEos:
399  from subprocess import getstatusoutput as run_cmd
400 
401  ibeos_cache = os.path.join(os.getenv("LOCALRT"), "ibeos_cache.txt")
402  if not os.path.exists(ibeos_cache):
403  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)
404  if err:
405  run_cmd("rm -f %s" % ibeos_cache)
406  print("Error: Unable to download ibeos cache information")
407  print(out)
408  sys.exit(err)
409 
410  for cmssw_env in [ "CMSSW_BASE", "CMSSW_RELEASE_BASE" ]:
411  cmssw_base = os.getenv(cmssw_env,None)
412  if not cmssw_base: continue
413  cmssw_base = os.path.join(cmssw_base,"src/Utilities/General/ibeos")
414  if os.path.exists(cmssw_base):
415  os.environ["PATH"]=cmssw_base+":"+os.getenv("PATH")
416  os.environ["CMS_PATH"]="/cvmfs/cms-ib.cern.ch"
417  os.environ["SITECONFIG_PATH"]="/cvmfs/cms-ib.cern.ch/SITECONF/local"
418  os.environ["CMSSW_USE_IBEOS"]="true"
419  print(">> WARNING: You are using SITECONF from /cvmfs/cms-ib.cern.ch")
420  break
421  if opt.restricted:
422  print('Deprecated, please use -l limited')
423  if opt.testList: opt.testList+=',limited'
424  else: opt.testList='limited'
425 
426  def stepOrIndex(s):
427  if s.isdigit():
428  return int(s)
429  else:
430  return s
431  if opt.apply:
432  opt.apply=map(stepOrIndex,opt.apply.split(','))
433  if opt.keep:
434  opt.keep=map(stepOrIndex,opt.keep.split(','))
435 
436  if opt.testList:
437  testList=[]
438  for entry in opt.testList.split(','):
439  if not entry: continue
440  mapped=False
441  for k in predefinedSet:
442  if k.lower().startswith(entry.lower()) or k.lower().endswith(entry.lower()):
443  testList.extend(predefinedSet[k])
444  mapped=True
445  break
446  if not mapped:
447  try:
448  testList.append(float(entry))
449  except:
450  print(entry,'is not a possible selected entry')
451 
452  opt.testList = list(set(testList))
453 
454  if opt.wmcontrol:
456  if opt.overWrite:
457  opt.overWrite=eval(opt.overWrite)
458  if opt.interactive:
459  import cmd
460  from colorama import Fore, Style
461  from os import isatty
462 
463  class TheMatrix(cmd.Cmd):
464  intro = "Welcome to the Matrix (? for help)"
465  prompt = "matrix> "
466 
467  def __init__(self, opt):
468  cmd.Cmd.__init__(self)
469  self.opt_ = opt
470  self.matrices_ = {}
471  tmp = MatrixReader(self.opt_)
472  for what in tmp.files:
473  what = what.replace('relval_','')
474  self.opt_.what = what
475  self.matrices_[what] = MatrixReader(self.opt_)
476  self.matrices_[what].prepare(self.opt_.useInput, self.opt_.refRel,
477  self.opt_.fromScratch)
478  os.system("clear")
479 
480  def do_clear(self, arg):
481  """Clear the screen, put prompt at the top"""
482  os.system("clear")
483 
484  def do_exit(self, arg):
485  print("Leaving the Matrix")
486  return True
487 
488  def default(self, inp):
489  if inp == 'x' or inp == 'q':
490  return self.do_exit(inp)
491  else:
492  is_pipe = not isatty(sys.stdin.fileno())
493  print(Fore.RED + "Error: " + Fore.RESET + "unrecognized command.")
494  # Quit only if given a piped command.
495  if is_pipe:
496  sys.exit(1)
497 
498  def help_predefined(self):
499  print("\n".join(["predefined [predef1 [...]]\n",
500  "Run w/o argument, it will print the list of known predefined workflows.",
501  "Run with space-separated predefined workflows, it will print the workflow-ids registered to them"]))
502 
503  def complete_predefined(self, text, line, start_idx, end_idx):
504  if text and len(text) > 0:
505  return [t for t in predefinedSet.keys() if t.startswith(text)]
506  else:
507  return predefinedSet.keys()
508 
509  def do_predefined(self, arg):
510  """Print the list of predefined workflows"""
511  print("List of predefined workflows")
512  if arg:
513  for w in arg.split():
514  if w in predefinedSet.keys():
515  print("Predefined Set: %s" % w)
516  print(predefinedSet[w])
517  else:
518  print("Unknown Set: %s" % w)
519  else:
520  print("[ " + Fore.RED + ", ".join([str(k) for k in predefinedSet.keys()]) + Fore.RESET + " ]")
521 
522  def help_showWorkflow(self):
523  print("\n".join(["showWorkflow [workflow1 [...]]\n",
524  "Run w/o arguments, it will print the list of registered macro-workflows.",
525  "Run with space-separated workflows, it will print the full list of workflow-ids registered to them"]))
526 
527  def complete_showWorkflow(self, text, line, start_idx, end_idx):
528  if text and len(text) > 0:
529  return [t for t in self.matrices_.keys() if t.startswith(text)]
530  else:
531  return self.matrices_.keys()
532 
533  def do_showWorkflow(self, arg):
534  if arg == '':
535  print("Available workflows:")
536  for k in self.matrices_.keys():
537  print(Fore.RED + Style.BRIGHT + k)
538  print(Style.RESET_ALL)
539  else:
540  selected = arg.split()
541  for k in selected:
542  if k not in self.matrices_.keys():
543  print("Unknown workflow %s: skipping" % k)
544  else:
545  for wfl in self.matrices_[k].workFlows:
546  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
547  Fore.GREEN + wfl.nameId + Fore.RESET))
548  print("%s contains %d workflows" % (Fore.RED + k + Fore.RESET, len(self.matrices_[k].workFlows)))
549 
551  print("\n".join(["searchInWorkflow wfl_name search_regexp\n",
552  "This command will search for a match within all workflows registered to wfl_name.",
553  "The search is done on both the workflow name and the names of steps registered to it."]))
554 
555  def complete_searchInWorkflow(self, text, line, start_idx, end_idx):
556  if text and len(text) > 0:
557  return [t for t in self.matrices_.keys() if t.startswith(text)]
558  else:
559  return self.matrices_.keys()
560 
561  def do_searchInWorkflow(self, arg):
562  args = arg.split()
563  if len(args) < 2:
564  print("searchInWorkflow name regexp")
565  return
566  if args[0] not in self.matrices_.keys():
567  print("Unknown workflow")
568  return
569  import re
570  pattern = None
571  try:
572  pattern = re.compile(args[1])
573  except:
574  print("Failed to compile regexp %s" % args[1])
575  return
576  counter = 0
577  for wfl in self.matrices_[args[0]].workFlows:
578  if re.match(pattern, wfl.nameId):
579  print("%s %s" % (Fore.BLUE + str(wfl.numId) + Fore.RESET,
580  Fore.GREEN + wfl.nameId + Fore.RESET))
581  counter +=1
582  print("Found %s compatible workflows inside %s" % (Fore.RED + str(counter) + Fore.RESET,
583  Fore.YELLOW + str(args[0])) + Fore.RESET)
584 
585  def help_search(self):
586  print("\n".join(["search search_regexp\n",
587  "This command will search for a match within all workflows registered.",
588  "The search is done on both the workflow name and the names of steps registered to it."]))
589 
590  def do_search(self, arg):
591  args = arg.split()
592  if len(args) < 1:
593  print("search regexp")
594  return
595  for wfl in self.matrices_.keys():
596  self.do_searchInWorkflow(' '.join([wfl, args[0]]))
597 
599  print("\n".join(["dumpWorkflowId [wfl-id1 [...]]\n",
600  "Dumps the details (cmsDriver commands for all steps) of the space-separated workflow-ids in input."]))
601 
602  def do_dumpWorkflowId(self, arg):
603  wflids = arg.split()
604  if len(wflids) == 0:
605  print("dumpWorkflowId [wfl-id1 [...]]")
606  return
607 
608  fmt = "[%s]: %s\n"
609  maxLen = 100
610  for wflid in wflids:
611  dump = True
612  for key, mrd in self.matrices_.items():
613  for wfl in mrd.workFlows:
614  if wfl.numId == float(wflid):
615  if dump:
616  dump = False
617  print(Fore.GREEN + str(wfl.numId) + Fore.RESET + " " + Fore.YELLOW + wfl.nameId + Fore.RESET)
618  for i,s in enumerate(wfl.cmds):
619  print(fmt % (Fore.RED + str(i+1) + Fore.RESET,
620  (str(s)+' ')))
621  print("\nWorkflow found in %s." % key)
622  else:
623  print("Workflow also found in %s." % key)
624 
625  do_EOF = do_exit
626 
627  TheMatrix(opt).cmdloop()
628  sys.exit(0)
629 
630  if opt.raw and opt.show:
631  ret = showRaw(opt)
632  else:
633  ret = runSelected(opt)
634 
635 
636  sys.exit(ret)
def performInjectionOptionTest(opt)
def runSelected(opt)
Definition: runTheMatrix.py:20
def do_predefined(self, arg)
def do_showWorkflow(self, arg)
def complete_showWorkflow(self, text, line, start_idx, end_idx)
def do_search(self, arg)
def showRaw(opt)
Definition: runTheMatrix.py:11
def do_clear(self, arg)
def help_dumpWorkflowId(self)
def complete_predefined(self, text, line, start_idx, end_idx)
def help_searchInWorkflow(self)
def do_dumpWorkflowId(self, arg)
void print(TMatrixD &m, const char *label=nullptr, bool mathematicaFormat=false)
Definition: Utilities.cc:47
def __init__(self, opt)
static std::string join(char **cmd)
Definition: RemoteFile.cc:19
def do_exit(self, arg)
def default(self, inp)
def complete_searchInWorkflow(self, text, line, start_idx, end_idx)
def stepOrIndex(s)
#define str(s)
def do_searchInWorkflow(self, arg)