ATLAS Offline Software
Loading...
Searching...
No Matches
LVL1CaloMonitoringConfig.py
Go to the documentation of this file.
2# Copyright (C) 2002-2022 CERN for the benefit of the ATLAS collaboration
3#
4
6
7 """
8 This class is designed to handle registering all of L1Calo's monitoring histograms and trees in a
9 coherent way. It will also generate the han config file for all the histograms.
10 """
11
12
13
14 from collections import defaultdict
15 hanConfigs = {} # nested structure as required, keys will be either "dir XXX" or "hist YYY"
16 hanAlgConfigs = {}
17 hanThresholdConfigs = {}
18 xmlConfigs = {} # flat dictionary of histograms that are in the shifter folders, so are used for online monitoring
19 embargoed = [] # list of embargoed dqdm plots
20
21 SIGNATURES = ["gJ","gLJ","gLJRho","gXEJWOJ","gXEJWOJMHT","gXEJWOJMST","gTEJWOJ","gXENC","gTENC","gXERHO","gTERHO","jJ","jEM","jTAU","jXE","jTE","eTAU","eEM"]
22 HELPURL = "" #"https://codimd.web.cern.ch/s/678H65Tk9" No longer adding a help url
23
24 @staticmethod
26 # First create the DQAlgorithm config file
27 import config
28 db = config.Configuration()
29 db.create_db("l1calo_gen_phase1.data.xml",["daq/schema/dqm.schema.xml","daq/sw/dqm-algorithms.data.xml","daq/sw/repository.data.xml","daq/sw/dqm-default-streams.data.xml"])
30
31 # first ensure all the algorithms exist
32 for confName,conf in L1CaloMonitorCfgHelper.hanAlgConfigs.items():
33 # only need algorithms for Shifter histograms
34 algUsed = False
35 for histPath,value in L1CaloMonitorCfgHelper.xmlConfigs.items():
36 if value.get("algorithm","") == confName:
37 algUsed = True
38 break
39 if not algUsed: continue
40 updated = False
41 try:
42 dqAlgo = db.get_dal("DQAlgorithm",conf["name"])
43 except RuntimeError:
44 # algorithm doesn't exist, create it ...
45 updated=True
46 db.create_obj("DQAlgorithm",conf["name"])
47 dqAlgo = db.get_dal("DQAlgorithm",conf["name"])
48 dqAlgo.LibraryName = conf["libname"]
49 print("Created dqAlgo",conf["name"])
50 # ensure all parameters appear in ParametersNames, and thresholds in ThresholdsNames
51 for par,val in conf.items():
52 if par=="thresholds" and val in L1CaloMonitorCfgHelper.hanThresholdConfigs:
53 for thresh,vals in L1CaloMonitorCfgHelper.hanThresholdConfigs[val].items():
54 if thresh not in dqAlgo.ThresholdsNames:
55 updated=True
56 dqAlgo.ThresholdsNames += [thresh]
57 print("Added",thresh,"to",conf["name"],"ThresholdNames")
58 elif par not in ["name","libname","thresholds"]+dqAlgo.ParametersNames:
59 updated=True
60 dqAlgo.ParametersNames += [par]
61 print("Added",par,"to",conf["name"],"ParameterNames")
62 if updated:
63 db.update_dal(dqAlgo)
64
65
66 # now create DQParameter object for each histogram with a DQ algorithm
67 # need to have them all in a DQRegion that belongs to a DQLayout
68 db.create_obj("DQShape","L1CaloShapeDeveloper")
69 db.create_obj("DQLayout","L1CaloLayoutDeveloper")
70 db.create_obj("DQRegion","L1CaloRegionDeveloper")
71 dqLayout = db.get_dal("DQLayout","L1CaloLayoutDeveloper")
72 dqLayout.DefaultChildrenShape = db.get_dal("DQShape","L1CaloShapeDeveloper")
73 db.update_dal(dqLayout)
74 dqRegion = db.get_dal("DQRegion","L1CaloRegionDeveloper")
75 dqRegion.Description = "L1Calo Monitoring Development Folder"
76 dqRegion.Label = "Developer"
77 dqRegion.DQLayout = dqLayout
78 dqRegion.DQSummaryMaker = db.get_dal("DQSummaryMaker","WorstCaseSummary")
79
80 for histPath,value in L1CaloMonitorCfgHelper.xmlConfigs.items():
81 if "algorithm" not in value.keys(): continue # only add histograms that have an algorithm
82
83 name = "_".join(histPath.split("/"))
84 db.create_obj("DQParameter",name)
85 dqPar = db.get_dal("DQParameter",name)
86 dqPar.InputDataSource = ["Histogramming.l1calo-athenaHLT-Phase1./"+histPath]
87 dqPar.Description = value["description"]
88
89 if value["algorithm"] in L1CaloMonitorCfgHelper.hanAlgConfigs:
90 algConf = L1CaloMonitorCfgHelper.hanAlgConfigs[value["algorithm"]]
91 dqPar.DQAlgorithm = db.get_dal("DQAlgorithm",algConf["name"])
92 for par,val in algConf.items():
93 if par in dqPar.DQAlgorithm.ParametersNames:
94 dqPar.Parameters += [f"{par}={val}"]
95 if "thresholds" in algConf:
96 for thresh,vals in L1CaloMonitorCfgHelper.hanThresholdConfigs[algConf["thresholds"]].items():
97 dqPar.GreenThresholds += [f"{thresh}={vals['warning']}"]
98 dqPar.RedThresholds += [f"{thresh}={vals['error']}"]
99 else:
100 dqPar.DQAlgorithm = db.get_dal("DQAlgorithm",value["algorithm"]) # catches cases of e.g. predefined parameterless alg like Histogram_Empty
101
102 dqRegion.DQParameters += [dqPar]
103 db.update_dal(dqPar)
104
105 db.update_dal(dqRegion)
106 db.commit("Autogenerated")
107
108
109 @staticmethod
110 def printHanConfig(filename="collisions_run.config"):
111 L1CaloMonitorCfgHelper.createXmls()
112 from contextlib import redirect_stdout
113 from PathResolver import PathResolver
114 header = PathResolver.FindCalibFile("TrigT1CaloMonitoring/hanConfig_header.txt")
115 with open(filename,'w') as f:
116 # copy the header if we have one
117 if header != "":
118 with open(header,'r') as fh:
119 for line in fh: f.write(line)
120 with redirect_stdout(f):
121 # Note: common configs (see common dir in DataQualityConfiguration) provides following algorithms by default:
122 # algorithm All_Bins_Filled
123 # algorithm Histogram_Effective_Empty
124 # algorithm Histogram_Empty
125 # algorithm Histogram_Not_Empty
126 # algorithm No_OverFlows
127 # algorithm No_UnderFlows
128
129 outputs = set()
130 algorithms = set()
131 def printConf(d,prefix="",currentOutput=""):
132 for key,value in d.items():
133 if type(value)==dict:
134 print(prefix,key,"{")
135 newCurrentOutput=str(currentOutput)
136 if(key=="dir detail" or key=="dir Developer"):
137 print(prefix+" algorithm = GatherData") # define GatherData as default algo for all of these hists
138 if key.startswith("dir ") and any([x.startswith("hist ") for x in value.keys()]):
139 # this is a dir with hists, so specify output as the path .. take from the first hist child
140 for childKey,childVal in value.items():
141 if childKey.startswith("hist ") and "output" in childVal:
142 print(prefix+" output = "+childVal["output"])
143 newCurrentOutput = str(childVal["output"])
144 break
145 printConf(value,prefix + " ",newCurrentOutput)
146 print(prefix,"}")
147 else:
148 # save all output paths to add to output block (don't need to print here b.c. specified at dir level
149 # exception is if plot was embargoed!
150 if key == "output": outputs.add(value)
151 if key != "output" or value != currentOutput: print(prefix,key,"=",value)
152 if key == "algorithm": algorithms.add(value)
153
154
155 print("#inputs")
156 print("dir L1Calo {")
157 printConf(L1CaloMonitorCfgHelper.hanConfigs," ")
158 print("}")
159 print("#outputs")
160 print("output top_level {")
161 print(" output L1Calo {")
162
163 # go through outputs set, build a nested dictionary of paths
164 outputsDict = {}
165 for o in outputs:
166 theDict = outputsDict
167 for p in o.split("/"):
168 if p not in theDict: theDict[p] = {}
169 theDict = theDict[p]
170 def printOutputs(d,prefix=""):
171 for key,value in d.items():
172 print(prefix,"output",key,"{")
173 if key=="detail" or key=="Developer": print(prefix," algorithm = L1Calo_AlwaysUndefinedSummary")
174 printOutputs(value,prefix + " ")
175 print(prefix,"}")
176 printOutputs(outputsDict["L1Calo"]," ")
177 print(" }")
178 print("}")
179 # include example of adding algorithms and thresholds
180 print("""
181#algorithms
182algorithm AnyNonZeroBinIsError {
183 # Use this algo if want error on any non-zero bin content
184 libname = libdqm_summaries.so
185 name = Bins_NotEqual_Threshold
186 BinThreshold = 0.
187 thresholds = th_AnyBinIsError
188}
189algorithm L1Calo_AlwaysUndefinedSummary {
190 libname = libdqm_summaries.so
191 name = AlwaysUndefinedSummary
192}
193""")
194 thresholds = set()
195 for algName,algProps in L1CaloMonitorCfgHelper.hanAlgConfigs.items():
196 if algName not in algorithms: continue # only print the algorithms that were used
197 print(f"algorithm {algName} {{")
198 for propName,propVal in algProps.items():
199 if propName == "thresholds": thresholds.add(propVal)
200 print(f" {propName} = {propVal}")
201 print(" }")
202 print("""
203#thresholds
204thresholds th_AnyBinIsError {
205 limits NBins {
206 warning = 0
207 error = 1
208 }
209}
210""")
211 for threshName,threshProps in L1CaloMonitorCfgHelper.hanThresholdConfigs.items():
212 if threshName not in thresholds: continue # only print used thresholds
213 print(f"thresholds {threshName} {{")
214 for parName,parLims in threshProps.items():
215 print(f" limits {parName} {{")
216 for limName,limVal in parLims.items():
217 print(f" {limName} = {limVal}")
218 print(" }")
219 print("}")
220
221
222
223 def __init__(self, flags, algClassOrObj = None, name = None, *args, **kwargs):
224 '''
225 Create the configuration helper.
226
227 Arguments:
228 flags -- the configuration flag object
229 algClassOrObj -- the name you want to assign the family of algorithms
230 '''
231 from AthenaMonitoring import AthMonitorCfgHelper
232 self.helper = AthMonitorCfgHelper(flags,monName="L1CaloMon")
233 kwargs.setdefault("addToSubSequence", False)
234 self.alg = self.helper.addAlgorithm(algClassOrObj,name,*args, **kwargs) if algClassOrObj is not None else None
235 self.fillGroups = {}
236 self.dqEnv = flags.DQ.Environment # used to decide if should defineTree or not ...
237
238 def defineDQAlgorithm(self,name,hanConfig,thresholdConfig=None):
239
240 """
241
242 :param name: name of algorithm
243 :param hanConfig: dict of algo properties
244 :param thresholdConfig: dict of thresholds, key = ParName, value = pair of thresholds [warning,error]
245 :return:
246 """
247
248 # note: this method will replace any existing alg definition
249
250 #thresNum = len(self.hanThresholdConfigs)
251 if thresholdConfig is not None:
252 hanConfig["thresholds"] = f"{name}Thresholds"
253 threshDict = {}
254 for parName,limVals in thresholdConfig.items():
255 if len(limVals) != 2:
256 raise Exception("must specify two limits: warning and error")
257 if parName not in threshDict: threshDict[parName] = {}
258 threshDict[parName]["warning"] = limVals[0]
259 threshDict[parName]["error"] = limVals[1]
260 # see if any existing thresholds are identical, if so we can reuse
261 for threshName,thresh in self.hanThresholdConfigs.items():
262 if str(thresh)==str(threshDict):
263 threshDict = None
264 hanConfig["thresholds"] = threshName
265 break
266 if threshDict is not None: self.hanThresholdConfigs[hanConfig["thresholds"]] = threshDict
267 self.hanAlgConfigs[name] = hanConfig
268
269 return
270
271
272 def defineHistogram(self,*args,fillGroup=None,hanConfig={},paths=[],**kwargs):
273 '''
274
275 :param path:
276 :param fillGroup:
277 :param args:
278 :param kwargs:
279 :return:
280 '''
281
282 hanConfig = dict(hanConfig) # create a copy since will modify below (otherwise we end up modifying the default empty dict)
283
284 if paths != []:
285 for path in paths:
286 if self.dqEnv=='online' and any([x.startswith("Shifter/") for x in paths]) and not path.startswith("Shifter/"): continue # only fill Shifter folder copies online
287 # create a copy of the histogram in each of the extra locations
288 self.defineHistogram(*args,fillGroup=fillGroup,hanConfig=hanConfig,paths=[],path=path,**kwargs)
289 return None
290
291 argsCopy = list(args) # need to convert tuple to list to convert it
292 if ";" not in args[0]:
293 argsCopy[0] += ";h_" + argsCopy[0].replace(":","_")
294
295 if kwargs.get("path",None) is None:
296 # put in the Developer path, under the name of the algorithm
297 kwargs["path"] = "Developer/" + self.alg.name
298 elif kwargs["path"][-1] == '/':
299 kwargs["path"] = kwargs["path"][:-1] # strip trailing slash
300 # verify path obeys convention
301 splitPath = kwargs["path"].split("/")
302 if splitPath[0] not in ["Shifter","Expert","Developer"]:
303 raise Exception("Path of histogram invalid, does not start with one of the allowed audiences (Shifter,Expert,Developer)")
304
305 # don't bother registering Shifter plots in tier0 ... only needed in p1 and user environments
306 if splitPath[0]=="Shifter" and self.dqEnv == 'tier0':
307 return None
308
309 # require a hanConfig not in Developer or a detail dir
310 if splitPath[0] != "Developer" and splitPath[-1] != "detail" and ("algorithm" not in hanConfig) and (splitPath[0]+"/algorithm" not in hanConfig):
311 # will default to using GatherData as long as there is a description
312 if "description" not in hanConfig and splitPath[0]+"/description" not in hanConfig:
313 raise Exception("Must specify a hanConfig for a Shifter or Expert (non-detail) histogram")
314 else:
315 hanConfig["algorithm"] = "GatherData" # must have an algo, otherwise wont be valid han config
316 elif "algorithm" in hanConfig and hanConfig["algorithm"] not in self.hanAlgConfigs and hanConfig["algorithm"] not in ["All_Bins_Filled","Histogram_Effective_Empty","Histogram_Empty","Histogram_Not_Empty","No_OverFlows","No_UnderFlows"]:
317 # if algorithm specified, must have been defined
318 raise Exception(f'DQ Algorithm {hanConfig["algorithm"]} for histogram {args[0]} not defined. Please use defineDQAlgorithm method to define it')
319 elif splitPath[0]+"/algorithm" in hanConfig and hanConfig[splitPath[0]+"/algorithm"] not in self.hanAlgConfigs and hanConfig[splitPath[0]+"/algorithm"] not in ["All_Bins_Filled","Histogram_Effective_Empty","Histogram_Empty","Histogram_Not_Empty","No_OverFlows","No_UnderFlows"]:
320 # if algorithm specified, must have been defined
321 raise Exception(f'{splitPath[0]} DQ Algorithm {hanConfig[splitPath[0]+"/algorithm"]} for histogram {args[0]} not defined. Please use defineDQAlgorithm method to define it')
322
323 if fillGroup is None: fillGroup = self.alg.name + "_fillGroup"
324 if fillGroup not in self.fillGroups:
325 self.fillGroups[fillGroup] = self.helper.addGroup(self.alg,fillGroup,topPath="L1Calo")
326
327
328 if "merge" not in kwargs and kwargs.get("type","") !="TEfficiency":
329 kwargs["merge"] = "merge" # ensures we don't get a warning about not specifying merge method
330 out = self.fillGroups[fillGroup].defineHistogram(*argsCopy,**kwargs)
331 histName = argsCopy[0].split(";")[-1]
332
333 # add help link for all expert plots
334 if splitPath[0] == "Expert" and self.HELPURL!="":
335 linkUrl = self.HELPURL + "#" + "".join(splitPath[1:]+[histName])
336 linkUrl = f"<a href=\"{linkUrl}\">Help</a>"
337 if "description" not in hanConfig and "Expert/descripton" not in hanConfig: hanConfig["description"] = linkUrl
338 elif "description" in hanConfig: hanConfig["description"] += " - " + linkUrl
339 else: hanConfig["Expert/description"] += " - " + linkUrl
340
341 # only add to hanConfig if in Expert or Developer folder
342 if splitPath[0] == "Expert" or splitPath[0] == "Developer":
343 splitPathWithHist = splitPath + [histName]
344 # check if hist is in the embargoed list
345 embargo = ("/".join(splitPathWithHist) in L1CaloMonitorCfgHelper.embargoed)
346 if embargo:
347 if "Expert/description" not in hanConfig: hanConfig["description"] = "<b>EMBARGOED PLOT</b> - " + (hanConfig.get("description",""))
348 else: hanConfig["Expert/description"] = "<b>EMBARGOED PLOT</b> - " + (hanConfig.get("Expert/description",""))
349 if "description" in hanConfig and hanConfig["description"]=="":
350 del hanConfig["description"]
351 if splitPath[0]+"/description" in hanConfig and hanConfig[splitPath[0]+"/description"]=="":
352 del hanConfig[splitPath[0]+"/description"]
353 x = L1CaloMonitorCfgHelper.hanConfigs
354 for i,p in enumerate(splitPathWithHist):
355 key = ("dir " if i!=len(splitPathWithHist)-1 else "hist ") + p
356 if key not in x:
357 x[key] = {}
358 x = x[key]
359 hanConfig["output"] = "/".join(["L1Calo"]+[splitPath[0] if not embargo else "Developer"]+splitPath[1:]) #embargoed plots appear in developer folder in DQDM, but come from Expert folder in ROOT file
360 # create a copy of the hanConfig and remove any keys beginning with "Shifter/", which means its a shifter-only config attribute
361 myConfig = {}
362 for k,v in hanConfig.items():
363 if k.startswith("Shifter/"): continue
364 # strip Expert/ prefix if it exists
365 myConfig[str(k).replace("Expert/","")] = v
366 if "algorithm" in myConfig and myConfig["algorithm"] in self.hanAlgConfigs:
367 # if there are any string parameters in the config, add them to the description
368 # need this until WebDisplay shows string parameters
369 for pName,pVal in self.hanAlgConfigs[myConfig["algorithm"]].items():
370 if len(str(pVal))>0 and str(pVal)[0]=="\"":
371 myConfig["description"] += f"<br>{pName} : {pVal[1:-1]}"
372 x.update(myConfig)
373 elif splitPath[0] == "Shifter": # record shifter histograms in another map, for generating xmls
374 # create a copy of the hanConfig and remove any keys beginning with "Expert/", which means its a expert-only config attribute
375 myConfig = {}
376 for k,v in hanConfig.items():
377 if k.startswith("Expert/"): continue
378 # strip Shifter/ prefix if it exists
379 myConfig[str(k).replace("Shifter/","")] = v
380 L1CaloMonitorCfgHelper.xmlConfigs["/".join(["L1Calo"]+splitPath+[histName])] = {}
381 L1CaloMonitorCfgHelper.xmlConfigs["/".join(["L1Calo"]+splitPath+[histName])].update(myConfig) # copy in the config
382
383 return out
384
385 def defineTree(self,*args,fillGroup=None,**kwargs):
386
387 if ";" not in args[0]:
388 raise Exception("Must specify a tree name using ';name' suffix")
389 treeName = args[0].split(";")[-1]
390
391 if "," in args[1]: # catch a subtle typo that can screw up monitoring
392 raise Exception("Should not have comma in list of branch names and types")
393
394 if kwargs.get("path",None) is None:
395 # put in the Developer path, under the name of the algorithm
396 kwargs["path"] = "Developer/" + self.alg.name
397
398 # verify path obeys convention
399 splitPath = kwargs["path"].split("/")
400 if splitPath[0] not in ["Developer"]:
401 raise Exception("Path of tree invalid, must be in the audience=Developer directory")
402
403
404 if fillGroup is None: fillGroup = self.alg.name + "_fillGroup"
405 if fillGroup not in self.fillGroups:
406 self.fillGroups[fillGroup] = self.helper.addGroup(self.alg,fillGroup,topPath="L1Calo")
407
408 # always define a histogram to go with the tree, which will indicate how many entries there are
409 # this also ensures we satisfy the requirement that every fillGroup has an object defined
410 # (in the cases of running online/tier0 the defineTrees are blocked, but we still need a hist then)
411 histName = "h_" + treeName + "_entries"
412 argsCopy = list(args)
413 argsCopy[0] = argsCopy[0].replace(";"+treeName,";"+histName)
414 kwargsCopy = dict(kwargs)
415 kwargsCopy["title"] = f"Number of Entries in {treeName} TTree" + ";" + ";".join(kwargsCopy.get("title","").split(";")[1:])
416 kwargsCopy["opt"] = ['kCanRebin','kAddBinsDynamically','kAlwaysCreate']
417 kwargsCopy["merge"] = "merge"
418 is2d = (kwargsCopy["title"].count(";")>1)
419 # take the right number of variables for defining the histogram
420 if is2d:
421 argsCopy[0] = argsCopy[0].split(",")[0] + "," + argsCopy[0].split(",")[1] + ";" + argsCopy[0].rsplit(";",1)[-1]
422 else:
423 argsCopy[0] = argsCopy[0].split(",")[0] + ";" + argsCopy[0].rsplit(";",1)[-1]
424 self.defineHistogram(argsCopy[0],type="TH2I" if is2d else "TH1I",xbins=1,xmin=0,xmax=1,ybins=1 if is2d else None,ymin=0,ymax=1,fillGroup=fillGroup,**kwargsCopy)
425 if not any([x in self.dqEnv for x in ['tier0','online']]):
426 out = self.fillGroups[fillGroup].defineTree(*args,**kwargs)
427 else:
428 out = None
429 return out
430
431 def result(self):
432 return self.helper.result()
433
434
436 '''Function to call l1calo DQ monitoring algorithms'''
437 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
438 from AthenaConfiguration.Enums import Format
439 import logging
440
441 # local printing
442 local_logger = logging.getLogger('AthenaMonitoringCfg')
443 info = local_logger.info
444 info('In LVL1CaloMonitoringConfig')
445
446 result = ComponentAccumulator()
447
448 # If we're not putting trigger objects in event store, can't monitor them
449 if not flags.Trigger.Online.isPartition:
450 if not flags.DQ.triggerDataAvailable:
451 return result
452
453 isData = not flags.Input.isMC
454
455 # check if validation requested
456 validation=flags.DQ.Steering.LVL1Calo.doValidation
457
458 # monitoring algorithm configs
459 # do not run on MC or RAW->ESD(tier0), or AOD-only
460 if not validation and isData and flags.DQ.Environment not in ('tier0Raw', 'AOD'):
461
462 from TrigT1CaloMonitoring.PprMonitorAlgorithm import PprMonitoringConfig
463 from TrigT1CaloMonitoring.JepJemMonitorAlgorithm import JepJemMonitoringConfig
464
465 # Use metadata to check Run3 compatible trigger info is available
466 from AthenaConfiguration.AutoConfigFlags import GetFileMD
467 md = GetFileMD(flags.Input.Files)
468 inputContainsRun3FormatConfigMetadata = ("metadata_items" in md and any(('TriggerMenuJson' in key) for key in md["metadata_items"].keys()))
469 result.merge(PprMonitoringConfig(flags))
470 result.merge(JepJemMonitoringConfig(flags))
471 if flags.Input.Format is not Format.POOL or inputContainsRun3FormatConfigMetadata:
472 # L1 menu available in the POOL file
473
474 # since the legacy system started getting turned off in 2024, use detMask to determine
475 # which things are included, and therefore need monitoring ...
476 import eformat
477 detMask=eformat.helper.DetectorMask(f'{md.get("detectorMask",[0x0])[0]:032x}') #DetectorMask constructor swallows two 64bit ints
478 hasCPM = detMask.is_set(eformat.helper.SubDetector.TDAQ_CALO_CLUSTER_PROC_DAQ)
479 hasJEP = detMask.is_set(eformat.helper.SubDetector.TDAQ_CALO_JET_PROC_DAQ)
480
481 if hasCPM:
482 from TrigT1CaloMonitoring.CpmMonitorAlgorithm import CpmMonitoringConfig
483 from TrigT1CaloMonitoring.CpmSimMonitorAlgorithm import CpmSimMonitoringConfig
484 result.merge(CpmMonitoringConfig(flags))
485 result.merge(CpmSimMonitoringConfig(flags))
486
487 if hasJEP:
488 from TrigT1CaloMonitoring.JepCmxMonitorAlgorithm import JepCmxMonitoringConfig
489 result.merge(JepCmxMonitoringConfig(flags))
490
491 from TrigT1CaloMonitoring.OverviewMonitorAlgorithm import OverviewMonitoringConfig
492 from TrigT1CaloMonitoring.PPMSimBSMonitorAlgorithm import PPMSimBSMonitoringConfig
493 result.merge(PPMSimBSMonitoringConfig(flags))
494 result.merge(OverviewMonitoringConfig(flags))
495
496 if not hasCPM:
497 # CPM was disabled for run 480893 onwards, so stop monitoring that part
498 OverviewMonAlg = result.getEventAlgo("OverviewMonAlg")
499 OverviewMonAlg.CPMErrorLocation = ""
500 OverviewMonAlg.CPMMismatchLocation = ""
501
502 if flags.Input.TriggerStream == "physics_Mistimed":
503 from TrigT1CaloMonitoring.MistimedStreamMonitorAlgorithm import MistimedStreamMonitorConfig
504 result.merge(MistimedStreamMonitorConfig(flags))
505
506 # For running on bytestream data
507 if flags.Input.Format is Format.BS:
508 from TrigT1CaloByteStream.LVL1CaloRun2ByteStreamConfig import LVL1CaloRun2ReadBSCfg
509 result.merge(LVL1CaloRun2ReadBSCfg(flags))
510
511 # Phase 1 monitoring of inputs and sim-vs-hw
512 if flags.Trigger.enableL1CaloPhase1 and flags.Input.Format is not Format.POOL:
513
514 # run the L1Calo simulation (causes conflicts with DAOD)
515 from L1CaloFEXSim.L1CaloFEXSimCfg import L1CaloFEXSimCfg
516 result.merge(L1CaloFEXSimCfg(flags))
517
518 #efex monitoring
519 if flags.Trigger.L1.doeFex:
520 from TrigT1CaloMonitoring.EfexInputMonitorAlgorithm import EfexInputMonitoringConfig
521 result.merge(EfexInputMonitoringConfig(flags))
522
523 # monitoring of simulation vs hardware
524 from TrigT1CaloMonitoring.EfexSimMonitorAlgorithm import EfexSimMonitoringConfig
525 result.merge(EfexSimMonitoringConfig(flags))
526
527 #gfex monitoring
528 if flags.Trigger.L1.dogFex:
529 #gfex input monitoring
530 from TrigT1CaloMonitoring.GfexInputMonitorAlgorithm import GfexInputMonitoringConfig
531 result.merge(GfexInputMonitoringConfig(flags))
532
533 from TrigT1CaloMonitoring.GfexSimMonitorAlgorithm import GfexSimMonitoringConfig
534 result.merge(GfexSimMonitoringConfig(flags))
535
536 #jfex monitoring
537 if flags.Trigger.L1.dojFex:
538 #jfex monitoring for input data
539 from TrigT1CaloMonitoring.JfexInputMonitorAlgorithm import JfexInputMonitoringConfig
540 result.merge(JfexInputMonitoringConfig(flags))
541
542 #jfex monitoring for Data Vs Simulation
543 from TrigT1CaloMonitoring.JfexSimMonitorAlgorithm import JfexSimMonitoringConfig
544 JfexSimMonitoring = JfexSimMonitoringConfig(flags)
545 result.merge(JfexSimMonitoring)
546
547 if flags.Trigger.L1.doTopo and isData:
548 #L1TopoSimulation (with monitoring Off to avoid clash with next call)
549 from L1TopoSimulation.L1TopoSimulationConfig import L1TopoSimulationCfg
550 result.merge(L1TopoSimulationCfg(flags,readMuCTPI=True,doMonitoring=False, useMuonDecoder=True, writeMuonRoIs = False))
551 #L1TopoOnlineMonitoring specific for L1Calo DQPlots
552 from L1TopoOnlineMonitoring.L1TopoOnlineMonitoringConfig import Phase1TopoMonitoringCfg
553 result.merge(Phase1TopoMonitoringCfg(flags))
554
555 # run FEX output monitoring if doing validation or running on data not @ tier0 or on AOD
556 if validation or (isData and flags.DQ.Environment not in ('tier0Raw', 'AOD')):
557
558 if validation:
559 # only run this monitoring if doing validation
560 from TrigT1CaloMonitoring.L1CaloLegacyEDMMonitorAlgorithm import L1CaloLegacyEDMMonitoringConfig
561 result.merge(L1CaloLegacyEDMMonitoringConfig(flags))
562
563 #efex monitoring
564 if flags.Trigger.L1.doeFex:
565 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringConfig
566 result.merge(EfexMonitoringConfig(flags))
567 from TrigT1CaloMonitoring.EfexMonitorAlgorithm import EfexMonitoringHistConfig
568 result.merge(EfexMonitoringHistConfig(flags,result.getEventAlgo('EfexMonAlg')))
569
570 #gfex monitoring
571 if flags.Trigger.L1.dogFex:
572 from TrigT1CaloMonitoring.GfexMonitorAlgorithm import GfexMonitoringConfig
573 result.merge(GfexMonitoringConfig(flags))
574
575 #jfex monitoring
576 if flags.Trigger.L1.dojFex:
577 from TrigT1CaloMonitoring.JfexMonitorAlgorithm import JfexMonitoringConfig
578 result.merge(JfexMonitoringConfig(flags))
579
580 # jet efficiency monitoring -- needs either gfex or jfex to be worth scheduling
581 if flags.Trigger.L1.dojFex or flags.Trigger.L1.dogFex:
582 from TrigT1CaloMonitoring.JetEfficiencyMonitorAlgorithm import JetEfficiencyMonitoringConfig
583 result.merge(JetEfficiencyMonitoringConfig(flags))
584
585 result.printConfig( withDetails= True )
586
587 return result
588
589if __name__ == '__main__':
590 from AthenaConfiguration.AllConfigFlags import initConfigFlags
591 from AthenaConfiguration.ComponentFactory import CompFactory
592 from AthenaMonitoring.DQConfigFlags import DQDataType
593 flags = initConfigFlags()
594 flags.DQ.useTrigger = False
595 flags.DQ.Environment = "user"
596 flags.DQ.DataType = DQDataType.MC
597 flags.DQ.enableLumiAccess = False
598 flags.lock()
599 h = L1CaloMonitorCfgHelper(flags,CompFactory.JfexSimMonitorAlgorithm,"MyAlg")
600 h.defineHistogram("x,y;h_myHist",type='TH2D',path="Shifter/Blah",hanConfig={"algorithm":"blah"})
601 h.defineHistogram("x,y;h_myHis2t",type='TH2D',path="Shifter/Blah",hanConfig={"algorithm":"blah2"})
602 h.defineHistogram("x;anotherHist",type='TH1D',path="Developer/whatever",hanConfig={"aaa":2})
603 h.defineTree("x,y,z,a,b;myTree","x/i:y/i:z/i:a/I:b/I",path="Developer/whatever")
604
605 # example of an algorithm requiring all bins to be empty
606 h.defineDQAlgorithm("MyAlgo",
607 hanConfig={"libname":"libdqm_summaries.so","name":"Bins_NotEqual_Threshold","BinThreshold":"0."},
608 thresholdConfig={"NBins":[1,1]}) # first number if warning threshold, second is error threshold
609
610 L1CaloMonitorCfgHelper.printHanConfig()
void print(char *figname, TCanvas *c1)
defineDQAlgorithm(self, name, hanConfig, thresholdConfig=None)
defineTree(self, *args, fillGroup=None, **kwargs)
defineHistogram(self, *args, fillGroup=None, hanConfig={}, paths=[], **kwargs)
__init__(self, flags, algClassOrObj=None, name=None, *args, **kwargs)
static std::string FindCalibFile(const std::string &logical_file_name)
STL class.
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
int count(std::string s, const std::string &regx)
count how many occurances of a regx are in a string
Definition hcg.cxx:146
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177