diff --git a/Trigger/TrigValidation/TrigAnalysisTest/python/TrigAnalysisSteps.py b/Trigger/TrigValidation/TrigAnalysisTest/python/TrigAnalysisSteps.py index 247d9d51b9d9deeb8c1aa757418735a8cd186080..1d0eede3af941e6bb77083bd52eef70cc07d5055 100644 --- a/Trigger/TrigValidation/TrigAnalysisTest/python/TrigAnalysisSteps.py +++ b/Trigger/TrigValidation/TrigAnalysisTest/python/TrigAnalysisSteps.py @@ -7,8 +7,11 @@ Definitions of additional validation steps in Trigger ART tests relevant only fo The main common check steps are defined in the TrigValSteering.CheckSteps module. ''' +from TrigValTools.TrigValSteering.Step import Step from TrigValTools.TrigValSteering.ExecStep import ExecStep from TrigValTools.TrigValSteering.CheckSteps import CheckFileStep, InputDependentStep, LogMergeStep +import os +import re ################################################## # Additional exec steps @@ -66,6 +69,92 @@ class CheckFileTrigSizeStep(CheckFileStep): self.input_file = 'AOD.pool.root,ESD.pool.root,RDO_TRIG.pool.root' self.executable = 'checkFileTrigSize_RTT.py' +class PhysValWebStep(Step): + ''' + Execute physval_make_web_display.py to make PhysVal web display from NTUP_PHYSVAL.root + ''' + def __init__(self, name='PhysValWeb'): + super(PhysValWebStep, self).__init__(name) + self.input_file = 'NTUP_PHYSVAL.pool.root' + self.executable = 'physval_make_web_display.py' + self.refdir = None + self.sig = None + self.args = '--ratio --drawopt HISTPE --refdrawopt HIST --title Test ' + self.auto_report_result = True + self.timeout = 30*60 + self.required = True # whether the full test should fail if physval_make_web_display fails + self.required_no_red = False # whether the full test should fail if red histograms are found + + def configure(self, test): + assert self.sig, 'sig is a required parameter' + outargs = ' --outdir PHYSVAL_WEB/'+self.sig + dirargs = ' --startpath run_1/HLT/'+self.sig + self.args += ' '+outargs+' '+dirargs + super(PhysValWebStep, self).configure(test) + + def get_refdir(self): + if self.refdir: + return + for fname in os.listdir('.'): + if fname.startswith('ref-') and os.path.isdir(fname): + self.refdir = fname + + def run(self, dry_run=False): + if not dry_run and not os.path.exists(self.input_file): + self.log.error('Input file does not exist: %s', self.input_file) + self.result = 1 + if self.auto_report_result: + self.report_result() + return self.result, '# (internal) {} -> failed'.format(self.name) + + if not os.path.exists('PHYSVAL_WEB'): + os.mkdir('PHYSVAL_WEB') + + self.get_refdir() + if self.refdir: + ref_file = self.refdir+'/'+self.input_file + if not dry_run and not os.path.exists(ref_file): + self.log.warning('Reference file %s does not exist, running without reference', ref_file) + else: + self.args += ' --reffile Ref:'+ref_file + self.args += ' '+self.input_file + + do_report_result = self.auto_report_result + self.auto_report_result = False # don't report yet, only after further checks below + self.result, cmd = super(PhysValWebStep, self).run(dry_run) + cmd += ' # Plus internal post-exec checks' + if dry_run: + if do_report_result: + self.report_result() + return self.result, cmd + + fname = 'PHYSVAL_WEB/'+self.sig+'/index.html' + if not os.path.exists(fname): + self.log.error('Missing output file %s', fname) + self.result += 1000 + if do_report_result: + self.report_result() + return self.result, cmd + + nred_all = 0 + with open(fname, 'r') as f: + red_lines = re.findall('Red.*$', f.read(), re.MULTILINE) + nred = len(red_lines) + nred_all += nred + if nred > 0: + msg = 'Red histograms in display for slice %s: %d' + if self.required_no_red: + self.log.error(msg, self.sig, nred) + else: + self.log.info(msg, self.sig, nred) + + if do_report_result: + self.report_result(self.result + nred_all) + if self.required_no_red: + self.result += nred_all + + return self.result, cmd + ################################################## # Getter functions ################################################## @@ -86,13 +175,28 @@ def add_analysis_steps(test, input_file='AOD.pool.root'): test.check_steps.extend(trig_analysis_check_steps()) # Add the analysis exec step logs for merging - logmerge = None - for step in test.check_steps: - if type(step) == LogMergeStep: - logmerge = step - break + logmerge = test.get_step_by_type(LogMergeStep) if not logmerge: test.log.warning('LogMerge step not found, cannot add TrigAnalysisSteps exec step log files for merging') else: for step in analysis_exec_steps: logmerge.log_files.append(step.get_log_file_name()) + +def add_physvalweb_steps(test, slice_names, download_step=None): + # Collect the steps + steps = [download_step] if download_step else [] + for slice_name in slice_names: + sliceweb = PhysValWebStep('PhysValWeb'+slice_name) + sliceweb.sig = slice_name + steps.append(sliceweb) + + # Add the steps at the beginning of check_steps list + test.check_steps = steps + test.check_steps + + # Add the step logs for merging + logmerge = test.get_step_by_type(LogMergeStep) + if not logmerge: + test.log.warning('LogMerge step not found, cannot add PhysValWeb step log files for merging') + else: + for step in steps: + logmerge.log_files.append(step.get_log_file_name()) diff --git a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_grid.py b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_grid.py index ad5e54d785513008a52f6d33eef553b206c31de0..70d873a2f3456063ee91ff8e8a329719c1ea2c09 100755 --- a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_grid.py +++ b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_grid.py @@ -23,6 +23,7 @@ # art-html: PHYSVAL_WEB from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps +from TrigAnalysisTest.TrigAnalysisSteps import add_physvalweb_steps import os # To run single-process transform on MCORE sites @@ -50,38 +51,13 @@ test.art_type = 'grid' test.exec_steps = [rdo2aod,physval] test.check_steps = CheckSteps.default_check_steps(test) +# Add web display steps +slice_names = [ + 'JetMon', 'TauMon', 'MuonMon', 'IDMon', + 'BphysMon', 'HLTCaloESD', 'ResultMon', 'BjetMon', + 'METMon', 'MinBiasMon', 'Egamma'] +download = CheckSteps.DownloadRefStep() +add_physvalweb_steps(test, slice_names, download) -download=CheckSteps.DownloadRefStep() -download.artpackage = 'TrigAnalysisTest' -download.artjobname = 'test_trigAna_PhysValWeb_grid.py' -download.required=True -test.check_steps.append(download) - - -if not os.path.exists('PHYSVAL_WEB'): - os.mkdir('PHYSVAL_WEB') - - -pv=[] -pv.append(['Jet','JetMon']) -pv.append(['Tau','TauMon']) -pv.append(['Muon','MuonMon']) -pv.append(['ID','IDMon']) -pv.append(['Bphys','BphysMon']) -pv.append(['HLTCalo','HLTCaloESD']) -pv.append(['Result','ResultMon']) -pv.append(['Bjet','BjetMon']) -pv.append(['MET','METMon']) -pv.append(['MinBias','MinBiasMon']) -pv.append(['Egamma','Egamma']) - -for slice in pv: - name='PhysValWeb'+slice[0] - sliceweb=CheckSteps.PhysValWebStep(name) - sliceweb.sig=slice[1] - sliceweb.required=True - test.check_steps.append(sliceweb) - import sys sys.exit(test.run()) - diff --git a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_compLegacy_grid.py b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_compLegacy_grid.py index c7314633b91bdde0d0f912f49e14adc7705731b8..2aa9c0cfd7c2311bb14ee76119c0f060acf45553 100755 --- a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_compLegacy_grid.py +++ b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_compLegacy_grid.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# art-description: Test of transform RDO->RDO_TRIG->ESD->AOD with AthenaMT and AOD->NTUP_PHYSVAL with serial athena to produce webdisplay (comparing with legacy menu) +# art-description: Produce web display comparing Run-3 trigger to Run-2 (legacy) trigger using legacy monitoring NTUP_PHYSVAL from previous nightlies # art-type: grid # art-include: master/Athena # art-output: *.txt @@ -22,67 +22,29 @@ # art-output: PHYSVAL_WEB # art-html: PHYSVAL_WEB -from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps -import os +from TrigValTools.TrigValSteering import Test, CheckSteps +from TrigAnalysisTest.TrigAnalysisSteps import add_physvalweb_steps -# To run single-process transform on MCORE sites -if 'ATHENA_NPROC_NUM' in os.environ: - del os.environ['ATHENA_NPROC_NUM'] +downloadLegacyTrig = CheckSteps.DownloadRefStep('DownloadLegacyTriggerNTUP') +downloadLegacyTrig.artjobname = 'test_trigAna_PhysValWeb_grid.py' -rdo2aod = ExecStep.ExecStep('RDOtoAOD') -rdo2aod.type = 'Reco_tf' -rdo2aod.input = 'ttbar' -rdo2aod.threads = 1 -rdo2aod.max_events = 500 -rdo2aod.args = '--outputAODFile=AOD.pool.root --steering="doRDO_TRIG" --valid=True' -rdo2aod.args += ' --preExec="all:from TriggerJobOpts.TriggerFlags import TriggerFlags; TriggerFlags.AODEDMSet.set_Value_and_Lock(\\\"AODFULL\\\");"' - -physval = ExecStep.ExecStep('PhysVal') -physval.type = 'Reco_tf' -physval.input = '' -physval.explicit_input = True -physval.args = '--inputAODFile=AOD.pool.root --outputNTUP_PHYSVALFile=NTUP_PHYSVAL.pool.root --valid=True' - -validationFlags = 'doTrigEgamma,doTrigBphys,doTrigMET,doTrigJet,doTrigMuon,doTrigHLTResult,doTrigCalo,doTrigMinBias,doTrigTau,doTrigIDtrk,doTrigBjet' -physval.args += ' --validationFlags="{:s}"'.format(validationFlags) +downloadRun3Trig = CheckSteps.DownloadRefStep('DownloadRun3TriggerNTUP') +downloadRun3Trig.artjobname = 'test_trigAna_PhysValWeb_mt1_grid.py' +downloadRun3Trig.args += ' --dst="."' test = Test.Test() test.art_type = 'grid' -test.exec_steps = [rdo2aod,physval] -test.check_steps = CheckSteps.default_check_steps(test) - - -download=CheckSteps.DownloadRefStep() -download.artpackage = 'TrigAnalysisTest' -download.artjobname = 'test_trigAna_PhysValWeb_grid.py' -download.required=True -test.check_steps.append(download) - +test.exec_steps = [downloadLegacyTrig,downloadRun3Trig] +# Only keep relevant checks from the defaults +test.check_steps = [chk for chk in CheckSteps.default_check_steps(test) + if type(chk) in (CheckSteps.LogMergeStep, CheckSteps.CheckLogStep)] + +# Add web display steps +slice_names = [ + 'JetMon', 'TauMon', 'MuonMon', 'IDMon', + 'BphysMon', 'HLTCaloESD', 'ResultMon', 'BjetMon', + 'METMon', 'MinBiasMon', 'Egamma'] +add_physvalweb_steps(test, slice_names) -if not os.path.exists('PHYSVAL_WEB'): - os.mkdir('PHYSVAL_WEB') - - -pv=[] -pv.append(['Jet','JetMon']) -pv.append(['Tau','TauMon']) -pv.append(['Muon','MuonMon']) -pv.append(['ID','IDMon']) -pv.append(['Bphys','BphysMon']) -pv.append(['HLTCalo','HLTCaloESD']) -pv.append(['Result','ResultMon']) -pv.append(['Bjet','BjetMon']) -pv.append(['MET','METMon']) -pv.append(['MinBias','MinBiasMon']) -pv.append(['Egamma','Egamma']) - -for slice in pv: - name='PhysValWeb'+slice[0] - sliceweb=CheckSteps.PhysValWebStep(name) - sliceweb.sig=slice[1] - sliceweb.required=True - test.check_steps.append(sliceweb) - import sys sys.exit(test.run()) - diff --git a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_grid.py b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_grid.py index 4b6491272d040944e7949398babe8904747c772d..412ce230290ed8ad9c653765cf9135f6bf3ffefb 100755 --- a/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_grid.py +++ b/Trigger/TrigValidation/TrigAnalysisTest/test/test_trigAna_PhysValWeb_mt1_grid.py @@ -23,6 +23,7 @@ # art-html: PHYSVAL_WEB from TrigValTools.TrigValSteering import Test, ExecStep, CheckSteps +from TrigAnalysisTest.TrigAnalysisSteps import add_physvalweb_steps import os # To run single-process transform on MCORE sites @@ -51,38 +52,13 @@ test.art_type = 'grid' test.exec_steps = [rdo2aod,physval] test.check_steps = CheckSteps.default_check_steps(test) +# Add web display steps +slice_names = [ + 'JetMon', 'TauMon', 'MuonMon', 'IDMon', + 'BphysMon', 'HLTCaloESD', 'ResultMon', 'BjetMon', + 'METMon', 'MinBiasMon', 'Egamma'] +download = CheckSteps.DownloadRefStep() +add_physvalweb_steps(test, slice_names, download) -download=CheckSteps.DownloadRefStep() -download.artpackage = 'TrigAnalysisTest' -download.artjobname = 'test_trigAna_PhysValWeb_mt1_grid.py' -download.required=True -test.check_steps.append(download) - - -if not os.path.exists('PHYSVAL_WEB'): - os.mkdir('PHYSVAL_WEB') - - -pv=[] -pv.append(['Jet','JetMon']) -pv.append(['Tau','TauMon']) -pv.append(['Muon','MuonMon']) -pv.append(['ID','IDMon']) -pv.append(['Bphys','BphysMon']) -pv.append(['HLTCalo','HLTCaloESD']) -pv.append(['Result','ResultMon']) -pv.append(['Bjet','BjetMon']) -pv.append(['MET','METMon']) -pv.append(['MinBias','MinBiasMon']) -pv.append(['Egamma','Egamma']) - -for slice in pv: - name='PhysValWeb'+slice[0] - sliceweb=CheckSteps.PhysValWebStep(name) - sliceweb.sig=slice[1] - sliceweb.required=True - test.check_steps.append(sliceweb) - import sys sys.exit(test.run()) - diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py index 563525ef541a6453e1d180c97271d2cf112170f7..624f35c396a4e0acb449bcbe5398d0c8c3dbd3c0 100644 --- a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py +++ b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/CheckSteps.py @@ -423,25 +423,29 @@ class TailStep(Step): self.args += ' >'+self.output_name super(TailStep, self).configure(test) + class DownloadRefStep(Step): - '''Execute art.py download to downlaod results from previous day ''' + '''Execute art.py download to get results from previous days''' - def __init__(self, name='DownloadRefWeb'): + def __init__(self, name='DownloadRef'): super(DownloadRefStep, self).__init__(name) self.executable = 'art.py' - self.artpackage = ' ' - self.artjobname = ' ' - self.args = 'download ' + self.args = 'download' + self.artpackage = None + self.artjobname = None self.timeout = 20*60 self.required = True self.auto_report_result = True def configure(self, test): + if not self.artpackage: + self.artpackage = test.package_name + if not self.artjobname: + self.artjobname = 'test_'+test.name+'.py' self.args += ' '+self.artpackage+' '+self.artjobname super(DownloadRefStep, self).configure(test) - class HistCountStep(InputDependentStep): '''Execute histSizes.py to count histograms in a ROOT file''' @@ -456,50 +460,6 @@ class HistCountStep(InputDependentStep): super(HistCountStep, self).configure(test) -class PhysValWebStep(InputDependentStep): - '''Execute physval_make_web_display.py to make PhysVal web display from NTUP_PHYSVAL.root''' - - def __init__(self, name='PhysValWeb'): - super(PhysValWebStep, self).__init__(name) - self.input_file = 'NTUP_PHYSVAL.pool.root' - self.executable = 'physval_make_web_display.py' - self.refdir = ' ' - self.sig=' ' - self.args = '--ratio --drawopt HISTPE --refdrawopt HIST --title Test ' - self.auto_report_result = True - self.timeout = 30*60 - self.required = True - - def configure(self, test): - outargs = ' --outdir PHYSVAL_WEB/'+self.sig - dirargs = ' --startpath run_1/HLT/'+self.sig - self.args += ' '+outargs+' '+dirargs - super(PhysValWebStep, self).configure(test) - - def run(self, dry_run=False): - for fname in os.listdir('.'): - if fname.startswith('ref-'): - self.refdir = fname - refargs = ' --reffile Ref:'+self.refdir+'/NTUP_PHYSVAL.pool.root ' - self.args += ' '+refargs+' '+self.input_file - retcode, cmd = super(PhysValWebStep, self).run(dry_run) - fname='PHYSVAL_WEB/'+self.sig+'/index.html' - if os.path.exists(fname): - f=open(fname,"r") - nred=0 - for line in f: - if (line.find('Red') != -1): - nred+=1 - if nred > 0: - self.log.debug("red histograms in display for slice %s %d",self.sig,nred) - retcode+=nred - else: - retcode+=1000 - self.log.debug("missing index.html file for slice: %s ",self.sig) - self.report_result(retcode,"CheckWeb"+self.sig) - return retcode, cmd - - class ChainDumpStep(InputDependentStep): ''' Execute chainDump.py to print trigger counts from histograms to text files diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Step.py b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Step.py index d8348957484ac6c7f5c69325d78ba842e9bab711..58bcaf906843d30d39bef4365ec1a50ee7984bb9 100644 --- a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Step.py +++ b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Step.py @@ -219,3 +219,14 @@ def get_step_from_list(step_name, step_list): if step.name is not None and step_name in step.name: return step return None + + +def get_step_type_from_list(step_type, step_list): + ''' + Retrieve the first test matching the type from the list. Returns None if + no match is found. + ''' + for step in step_list: + if isinstance(step, step_type): + return step + return None diff --git a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Test.py b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Test.py index 99127722069aaa181af6a0eb550710201482761f..9edb3268b47006bcdf479f4c21aeebd0e2e1f762 100644 --- a/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Test.py +++ b/Trigger/TrigValidation/TrigValTools/python/TrigValSteering/Test.py @@ -13,7 +13,7 @@ import subprocess from collections import OrderedDict from TrigValTools.TrigValSteering.Common import get_logger, art_result, clear_art_summary, package_prefix_dict -from TrigValTools.TrigValSteering.Step import get_step_from_list +from TrigValTools.TrigValSteering.Step import get_step_from_list, get_step_type_from_list class Test(object): @@ -196,6 +196,12 @@ class Test(object): step = get_step_from_list(step_name, self.check_steps) return step + def get_step_by_type(self, step_type): + step = get_step_type_from_list(step_type, self.exec_steps) + if step is None: + step = get_step_type_from_list(step_type, self.check_steps) + return step + def pre_exec(self): '''Extra pre-exec function executed just before the steps''' cmd_list = []