# Copyright (C) 2002-2019 CERN for the benefit of the ATLAS collaboration from collections import OrderedDict as odict from AthenaCommon.Logging import logging from TriggerJobOpts.TriggerFlags import TriggerFlags import re from .ThresholdType import ThrType log = logging.getLogger(__name__) ## ## These classes are base classes for the auto-generated algorithm python representations ## ## C++ L1Topo algorithms are defined in Trigger/TrigT1/L1Topo/L1TopoAlgorithms ## During the build, from each class a python class is generated and put in the release ## Those generated python classes derive fro SortingAlgo and DecisionAlgo below. class TopoAlgo(object): _availableVars = [] #__slots__ = ['_name', '_selection', '_value', '_generic'] def __init__(self, classtype, name, algoId=-1): self.classtype = classtype self.name = name self.algoId = algoId self.generics = [] self.variables = [] def __str__(self): return self.name def isSortingAlg(self): return False def isDecisionAlg(self): return False def isMultiplicityAlg(self): return False def setThresholds(self, thresholds): # link to all thresholds in the menu need for configuration self.menuThr = thresholds def addvariable(self, name, value, selection = -1): if name in self._availableVars: self.variables += [ Variable(name, selection, value) ] else: raise RuntimeError("Variable parameter '%s' does not exist for algorithm %s of type %s,\navailable parameters are %r" % (name,self.name, self.classtype, self._availableVars)) return self def addgeneric(self, name, value): if name in self._availableVars: self.generics += [ Generic(name, value) ] else: raise RuntimeError("Generic parameter '%s' does not exist for algorithm %s of type %s,\navailable parameters are %r" % (name,self.name, self.classtype, self._availableVars)) return self def json(self): confObj = odict() confObj["algId"] = self.algoId confObj["klass"] = self.classtype return confObj def getScaleToCountsEM(self): # legacy Et conversion!! tw = self.menuThr.typeWideThresholdConfig(ThrType["EM"]) return 1000 // tw["resolutionMeV"] class Variable(object): def __init__(self, name, selection, value): self.name = name self.selection = int(selection) self.value = int(value) class Generic(object): def __init__(self, name, value): self.name = name from L1TopoHardware.L1TopoHardware import HardwareConstrainedParameter if isinstance(value,HardwareConstrainedParameter): self.value = ":%s:" % value.name else: self.value = value class SortingAlgo(TopoAlgo): def __init__(self, classtype, name, inputs, outputs, algoId): super(SortingAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId) self.inputs = inputs self.outputs = outputs self.inputvalue= self.inputs if self.inputs.find("Cluster")>=0: # to extract inputvalue (for FW) from output name if self.outputs.find("TAU")>=0: self.inputvalue= self.inputvalue.replace("Cluster","Tau") if self.outputs.find("EM")>=0: self.inputvalue= self.inputvalue.replace("Cluster","Em") def isSortingAlg(self): return True def json(self): confObj = super(SortingAlgo, self).json() confObj["input"] = self.inputvalue confObj["output"] = self.outputs confObj["fixedParameters"] = odict() confObj["fixedParameters"]["generics"] = odict() for (pos, genParm) in enumerate(self.generics): confObj["fixedParameters"]["generics"][genParm.name] = odict([("value", genParm.value), ("position", pos)]) confObj["variableParameters"] = list() _emscale_for_decision = self.getScaleToCountsEM() # for legacy algos _mu_for_decision= 10 # MU4->3GeV, MU6->5GeV, MU10->9GeV because selection is done by pt>X in 100 MeV units for Run3 muons if "MUCTP-" in self.name: _mu_for_decision= 1 for (pos, variable) in enumerate(self.variables): if variable.name == "MinET": if "e" in self.outputs or "j" in self.outputs or "g" in self.outputs: variable.value *= 1 # no conversion needed in Run3 algo elif "TAU" in self.outputs or "EM" in self.outputs: variable.value *= _emscale_for_decision if "MU" in self.outputs: variable.value = ((variable.value - _mu_for_decision ) if variable.value>0 else variable.value) confObj["variableParameters"].append(odict([("name", variable.name),("value", variable.value)])) if type(variable.value) == float: raise RuntimeError("In algorithm %s the variable %s with value %r is of type float but must be int" % (self.name,variable.name,variable.value)) return confObj def xml(self): _emscale_for_decision=2 _mu_for_decision=1 # MU4->3GeV, MU6->5GeV, MU10->9GeV if hasattr(TriggerFlags, 'useRun1CaloEnergyScale'): if TriggerFlags.useRun1CaloEnergyScale : _emscale_for_decision=1 log.info("Changed mscale_for_decision %s for Run1CaloEnergyScale", _emscale_for_decision) s=' \n' % (self.classtype, self.name, self.outputs, self.algoId) s+=' \n' s+=' \n' % (self.inputs, self.inputvalue) s+=' \n' % (self.outputs) for gene in self.generics: s += ' \n' % (gene.name, gene.value) s+=' \n' s+=' \n' for (pos, variable) in enumerate(self.variables): # scale MinET if outputs match with EM or TAU if variable.name=="MinET" and (self.outputs.find("TAU")>=0 or self.outputs.find("EM")>=0): variable.value = variable.value * _emscale_for_decision if variable.name=="MinET" and self.outputs.find("MU")>=0: variable.value = ((variable.value - _mu_for_decision) if variable.value>0 else variable.value) s+=' \n' % ( pos, variable.name, variable.value ) s+=' \n' s+=' \n' return s class DecisionAlgo(TopoAlgo): def __init__(self, classtype, name, inputs, outputs, algoId): super(DecisionAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId) self.inputs = inputs if type(inputs)==list else [inputs] self.outputs = outputs if type(outputs)==list else [outputs] def isDecisionAlg(self): return True def json(self): confObj = super(DecisionAlgo, self).json() confObj["input"] = self.inputs # list of input names confObj["output"] = self.outputs # list of output names # fixed parameters confObj["fixedParameters"] = odict() confObj["fixedParameters"]["generics"] = odict() for (pos, genParm) in enumerate(self.generics): confObj["fixedParameters"]["generics"][genParm.name] = odict([("value", genParm.value), ("position", pos)]) # variable parameters confObj["variableParameters"] = list() _emscale_for_decision = self.getScaleToCountsEM() # for legacy algos _mu_for_decision= 10 # MU4->3GeV, MU6->5GeV, MU10->9GeV because selection is done by pt>X in 100 MeV units for Run3 muons if "MUCTP-" in self.name: _mu_for_decision= 1 for (pos, variable) in enumerate(self.variables): # scale MinET if inputs match with EM or TAU for _minet in ["MinET"]: if variable.name==_minet+"1" or variable.name==_minet+"2" or variable.name==_minet+"3" or variable.name==_minet: for (tobid, _input) in enumerate(self.inputs): if (_input.find("e")>=0 or _input.find("j")>=0 or _input.find("g")>=0): variable.value *= 1 # no conversion needed in Run3 algo elif (_input.find("TAU")>=0 or _input.find("EM")>=0): if (len(self.inputs)>1 and (variable.name==_minet+str(tobid+1) or (tobid==0 and variable.name==_minet))) or (len(self.inputs)==1 and (variable.name.find(_minet)>=0)): variable.value *= _emscale_for_decision if _input.find("MU")>=0: if (len(self.inputs)>1 and (variable.name==_minet+str(tobid+1) or (tobid==0 and variable.name==_minet))) or (len(self.inputs)==1 and (variable.name.find(_minet)>=0)): variable.value = ((variable.value - _mu_for_decision ) if variable.value>0 else variable.value) if type(variable.value) == float: raise RuntimeError("In algorithm %s the variable %s with value %r is of type float but must be int" % (self.name,variable.name,variable.value)) if variable.selection >= 0: confObj["variableParameters"].append(odict([("name", variable.name), ("selection",variable.selection), ("value", variable.value)])) else: confObj["variableParameters"].append(odict([("name", variable.name), ("value", variable.value)])) return confObj def xml(self): _emscale_for_decision=2 _mu_for_decision=1 if hasattr(TriggerFlags, 'useRun1CaloEnergyScale'): if TriggerFlags.useRun1CaloEnergyScale : _emscale_for_decision=1 log.info("Changed mscale_for_decision %s for Run1CaloEnergyScale", _emscale_for_decision) s=' \n' % (self.classtype, self.name, self.algoId ) s+=' \n' input_woovlp = [] for (tobid, _input) in enumerate(self.inputs): if len(self.inputs)>1: if _input not in input_woovlp: s+=' \n' % (str(tobid+1), _input, str(tobid)) input_woovlp += [_input] else: s+=' \n' % (str(tobid+1), _input, str(tobid)) else: s+=' \n' % (_input, str(tobid)) s+=' \n' % str(len(self.outputs)) for (bitid, _output) in enumerate(self.outputs): s+=' \n' % (str(bitid), _output) s+=' \n' for gene in self.generics: s += ' \n' % (gene.name, gene.value) s+=' \n' s+=' \n' for (pos, variable) in enumerate(self.variables): # scale MinET if inputs match with EM or TAU for _minet in ["MinET"]: if variable.name==_minet+"1" or variable.name==_minet+"2" or variable.name==_minet+"3" or variable.name==_minet: for (tobid, _input) in enumerate(self.inputs): if (_input.find("TAU")>=0 or _input.find("EM")>=0): if (len(self.inputs)>1 and (variable.name==_minet+str(tobid+1) or (tobid==0 and variable.name==_minet))) or (len(self.inputs)==1 and (variable.name.find(_minet)>=0)): variable.value = variable.value * _emscale_for_decision if _input.find("MU")>=0: if (len(self.inputs)>1 and (variable.name==_minet+str(tobid+1) or (tobid==0 and variable.name==_minet))) or (len(self.inputs)==1 and (variable.name.find(_minet)>=0)): variable.value = ((variable.value - _mu_for_decision ) if variable.value>0 else variable.value) s+=' \n' % ( pos, variable.name, ((' selection="%i"'%variable.selection) if (variable.selection>=0) else ""), variable.value ) s+=' \n' s+=' \n' return s class MultiplicityAlgo(TopoAlgo): def __init__(self, classtype, name, algoId, threshold, input, output, nbits): super(MultiplicityAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId) self.threshold = threshold self.input = input self.outputs = output self.nbits = nbits def isMultiplicityAlg(self): return True def configureFromThreshold(self, thr): pass def json(self): confObj = super(MultiplicityAlgo, self).json() confObj["threshold"] = self.threshold confObj["input"] = self.input confObj["output"] = self.outputs confObj["nbits"] = self.nbits return confObj class eEmMultiplicityAlgo(MultiplicityAlgo): def __init__(self, name, algoId, threshold, nbits, classtype ): super(eEmMultiplicityAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId, threshold = threshold, input=None, output="%s" % threshold, nbits=nbits) mres = re.match("(?P[A-z]*)[0-9]*(?P[VHILMT]*)",threshold).groupdict() self.input = mres["type"] class TauMultiplicityAlgo(MultiplicityAlgo): def __init__(self, name, algoId, threshold, nbits, classtype ): super(TauMultiplicityAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId, threshold = threshold, input=None, output="%s" % threshold, nbits=nbits) mres = re.match("(?P[A-z]*)[0-9]*(?P[HLMT]*)",threshold).groupdict() self.input = mres["type"] class JetMultiplicityAlgo(MultiplicityAlgo): def __init__(self, name, algoId, threshold, nbits, classtype ): super(JetMultiplicityAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId, threshold = threshold, input=None, output="%s" % threshold, nbits=nbits) mres = re.match("(?P[A-z]*)[0-9]*(?P[A-z]*)",threshold).groupdict() self.input = mres["type"] class XEMultiplicityAlgo(MultiplicityAlgo): def __init__(self, name, algoId, threshold, nbits, classtype = "EnergyThreshold"): super(XEMultiplicityAlgo, self).__init__( classtype = classtype, name=name, algoId = algoId, threshold = threshold, input=None, output="%s" % threshold, nbits=nbits) class MuMultiplicityAlgo(MultiplicityAlgo): def __init__(self, classtype, name, algoId, input, output, nbits): super(MuMultiplicityAlgo, self).__init__(classtype=classtype, name=name, algoId=algoId, input=input, output=output, nbits=nbits) def configureFromThreshold(self, thr): pass