ATLAS Offline Software
JetAnalysisCommon.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
2 
3 
4 """
5 JetAnalysisCommon
6 
7 This module defines various components to be used in AnalysisBase releases.
8 These components (classes, submodules...) can be used in place of some Athena components
9 they are replacing, so athena-style configuration can be used unchanged in AnalysisBase
10 
11 This module is thus designed ONLY for AnalysisBase and to run EventLoop jobs.
12 
13 IMPORTANT : this module is only designed so the jet configuration works. There's no guarantee it won't mess up
14 when used with other part of Athena configuration.
15 
16 Internally, the athena-style configurations of algorithms are translated to AnaReentrantAlgorithmConfig or
17 AnaAlgorithmConfig. The configuration of AsgTools are translated to call to AnaAlgorithmConfig.addPrivateTool()
18 or AnaAlgorithmConfig.setPropertyFromString()
19 
20 This module allows to write python config for EventLoop exactly as one would do for Athena :
21 
22 alg1 = CompFactory.MyAlg("algname",
23  InputContainer = "SomeJets".
24  Aparameter=4.305,
25  AprivateTool = CompFactory.SomeTool("tool", AToolparam =0.21), )
26 alg2 = CompFactory.AnOtherAlg( ... )
27 
28 job = ROOT.EL.Jon()
29  ...
30 job.addManyAlgs([alg1, alg2]) # specific call allowed by this module
31 
32 driver = ROOT.EL.DirectDriver()
33 driver.submit( job, "out")
34 
35 """
36 
37 
38 from types import ModuleType
39 import ROOT
40 
41 
42 # #*******************************************************************
43 # reset the base logging class : the one set by xAH breaks AthenaCommon.Logging
44 import logging
45 logging.setLoggerClass( logging.Logger )
46 
47 # #*******************************************************************
48 def stringPropValue( value ):
49  """Helper function producing a string property value"""
50 
51  stringValue = str( value )
52  if isinstance( value, bool ):
53  stringValue = str( int( value ) )
54  pass
55  return stringValue
56 
57 
58 class ConfArray:
59 
60  """A simplistic array of Configured (see below) to replace the ToolHandleArray of Athena """
61  def __init__(self, key, conflist , parent):
62  self.key = key
63  self._parent = parent
64  self.conflist=[]
65  self += conflist
66 
67  def __iadd__(self, conflist):
68  self.conflist += conflist
69  for conf in conflist:
70  conf.setparent(self._parent)
71  conf._name = self.key
72 
73  def __iter__(self):
74  return iter(self.conflist)
75 
76  def append(self, conf):
77  self += [conf]
78 
79  def assignAllProperties(self, anaAlg):
80  self._anaAlg = anaAlg
81  for conf in self.conflist:
82  tool = anaAlg.addPrivateToolInArray(conf.fullname(), conf.type)
83  conf._name = tool._prefix.split('.')[-1] # because AnaAlgorithmConfig will assign it's own naming scheme
84  conf.assignAllProperties(anaAlg)
85 
86 
87 class Configured:
88 
89  """A replacement for Athena auto-generated Configured python class.
90  Configured has the same interface as its Athena counterpart and can describe both Tools and Algorithms
91 
92  This is a base class. The system replacing CompFactory will generate a derived class for each c++ Tool/Algorithm
93  to hold the configuration of such tool/alg (see generateConfigured())
94  """
95  _properties=set()
96  _propTypes={}
97  _parent = None
98  _anaAlg = None
99  # the list of properties and attribute memeber which are allowed to be set.
100  # The full list will be generated for each class when actual classes are build in generateConfigured
101  _allowed = ['_properties', '_name', '_parent', '_anaAlg']
102 
103  def __init__(self, name, **props):
104 
105  self._name = name
106  self._properties = set()
107  for k,v in props.items():
108  setattr(self,k,v)
109 
110  def __setattr__(self, k, v):
111  if k in self._allowed:
112  self._setattrImpl(k,v)
113  else:
114  raise AttributeError("Configuration of Tool {} / {} . can't set attribute : {}".format(self.type, self._name, k) )
115 
116  def _setattrImpl(self, k, v) :
117  super().__setattr__(k,v)
118  if k[0] == '_' :
119  # this is not a Property
120  return
121 
122  if isinstance(v, Configured):
123  if k in self._properties:
124  raise RuntimeError( "Configuring {} / {} : Tool for property {} already exists".format(self.type, self._name, k) )
125  # it's a tool:
126  v.setparent(self)
127  v._name = k
128  elif isinstance(v, (list, tuple) ):
129  if isinstance(v[0], Configured):
130  v = ConfArray(k,v, self)
131  super().__setattr__(k,v)
132  self._properties.add(k)
133  if self._anaAlg:
134  self.setPropToAnaAlg( k , v)
135 
136 
137  def getName(self):
138  return self._name
139 
140  def setparent(self, parent):
141  self._parent = parent
142 
143  def prefixed(self, k):
144  if self._parent is None: return k
145  return self.fullname()+'.'+k
146 
147  def ancestors(self):
148  if self._parent is None : return [self]
149  return self._parent.ancestors()+[self]
150 
151  def fullname(self):
152  parents = self.ancestors()[1:]
153  return '.'.join([p._name for p in parents])
154 
155  def properties(self):
156  return [ (k, getattr(self,k)) for k in self._properties]
157 
158  def typeAndName(self):
159  return self.type+'/'+self._name
160 
161 
162  def asAnaAlg(self):
163  """Returns this configured alg as an instance of Ana(Reentrant)AlgorithmConfig
164  """
165  if issubclass(self._cppclass, ROOT.EL.AnaReentrantAlgorithm):
166  alg=ROOT.EL.AnaReentrantAlgorithmConfig()
167  else:
168  alg=ROOT.EL.AnaAlgorithmConfig()
169 
170  alg.setTypeAndName( self.typeAndName() )
171  self.assignAllProperties(alg)
172  return alg
173 
174 
175  def toToolInAnaAlg(self, anaAlg, handlename):
176  """If self represents a configured AlgTool,
177  this call will configure the AnaAlgorithmConfig 'anaAlg' so
178  its ToolHandle property 'handlename' is configured with self
179  """
180  props = {handlename:self, }
181  klass=type('TmpConf', (Configured,), dict(_allowed=self._allowed+[handlename], _propTypes={},
182  type=anaAlg.getType(),_cppclass='none') )
183 
184  c=klass(anaAlg.name(), **props)
185  c.assignAllProperties(anaAlg)
186 
187  def assignAllProperties(self, anaAlg):
188  """ Transfer all the configuration in self to anaAlg
189  where anaAlg is an AnaAlgorithmConfig."""
190  self._anaAlg = anaAlg
191  for (k,v) in self.properties():
192  self.setPropToAnaAlg(k,v)
193 
194  def setPropToAnaAlg(self, k, v):
195  alg=self._anaAlg
196  if isinstance(v , Configured):
197  # it must be a Tool :
198  alg.addPrivateTool(v.fullname(), v.type)
199  v.assignAllProperties(alg)
200  elif isinstance(v, ConfArray ):
201  # it is a Tool array
202  v.assignAllProperties(alg)
203  else:
204  # any other type :
205  cpptype = self._propTypes[k]
206  alg.setProperty[cpptype](self.prefixed(k) , v)
207 
208  def getType(self):
209  return self.type
210 
211 
212 def generateConfigured(classname, cppclass, prefix=""):
213  import cppyy
214 
215  # get an instance of the class :
216  if issubclass(cppclass, cppyy.gbl.asg.IAsgTool):
217  dummy = cppclass('dummy')
218  else: # then it's an Algorithm
219  dummy = cppclass('dummy', 0)
220 
221  # find all the properties of the Tool/Algorithm
222  pm = dummy.getPropertyMgr()
223  propkeys = [str(k) for k,p in pm.getProperties() ]
224  propTypes = dict( (k,propertyType(pm.getProperty(k)) ) for k in propkeys)
225  allowedProp = Configured._allowed + [k for k in propkeys]
226  # generate the class derived from Configured for this Tool/Alg
227  klass=type(classname+'Conf', (Configured,), dict(_allowed=allowedProp, _propTypes=propTypes,
228  type=prefix+classname,_cppclass=cppclass) )
229 
230  return klass
231 
233  """Guess the type of the TProperty p.
234  p is a C++ instance of a TProperty.
235 
236  This simply interpret the cpp name as set by cppyy...
237  """
238  clsname = p.__class__.__cpp_name__
239  # clsname is in the form : 'TProperty<vector<double> >'
240  typ = clsname[10:-1].strip()
241  if 'Handle' in typ:
242  typ='string'
243  return typ
244 
245 
247  """A namespace able to automatically generate Configured when quering attributes :
248  Used to replace CompFactory so that expressions like :
249  tool = CompFactory.Trk.SomeTrkTool("tname", Prop=2.345)
250  tool = CompFactory.getComp("Trk::SomeTrkTool")("tname", Prop=2.345)
251  works.
252  In the above 2 examples both CompFactory and Trk are ConfNameSpace
253  """
254  def __init__(self, name=""):
255  self.prefix=name+"::" if name !="" else ""
256 
257  def __getattr__(self, t):
258  return self.getComp(t)
259 
260  def getComp(self, classname):
261  """generates a new Configured class for the C++ class ROOT.classname .
262  This implies there must be a dictionnary for classname.
263  """
264 
265  # if we already generated the class, return it :
266  c = self.__dict__.get(classname, None)
267  if c is not None:
268  return c
269 
270  # look for the c++ class from ROOT :
271  c=getattr(ROOT, self.prefix+classname, None)
272 
273  if c is None:
274  print("JetAnalysisCommon ERROR : ",classname," is not a known C++ tool, alg, or namespace ")
275  raise
276 
277  if hasattr(c,'getPropertyMgr'):
278  conf = generateConfigured(classname,c,self.prefix)
279  else:
280  # not a configurable. Must be a namespace
281  conf = ConfNameSpace(self.prefix+classname)
282 
283  # save this new class onto self :
284  setattr(self, classname, conf)
285  return conf
286 
287  def addNameSpaces(self, *nsList):
288  for ns in nsList:
289  setattr(self, ns, ConfNameSpace(self.prefix+ns))
290 
291 
292 
293 # ----------------------------
294 # A replacement for CompFactory
295 CompFactory = ConfNameSpace()
296 # Add known namespaces :
297 CompFactory.addNameSpaces( 'Analysis', 'Trk', 'Jet', 'Sim',)
298 
299 # Make a pseudo-Module :
300 ComponentFactory = ModuleType("ComponentFactory")
301 ComponentFactory.CompFactory = CompFactory
302 
303 ComponentFactory.isComponentAccumulatorCfg = lambda : True
304 
305 
306 #*******************************************************************
307 # replacements for CFElements
308 def parOR(name):
309  pass
310 CFElements = ModuleType("CFElements")
311 CFElements.parOR = parOR
312 
313 
314 #*******************************************************************
315 
317  """Provdide similar interface than AthenaConfiguration.ComponentAccumulator and also very simplistic
318  merging of list of algorithms
319  """
320  def __init__(self, name="ca"):
321  self.name = name
322  self.algs = []
323 
324  def __iter__(self):
325  return iter(self.algs)
326 
327  def addSequence(self, seqName):
328  pass
329  def addEventAlgo(self, alg, primary=False, sequenceName=""):
330  self.algs +=[alg]
331  setattr(self, alg._name, alg)
332 
333  def merge(self, ca, sequenceName=""):
334  myTNs = set( alg.typeAndName() for alg in self.algs)
335  for alg in ca.algs:
336  tn = alg.typeAndName()
337  if tn not in myTNs:
338  self.algs.append(alg)
339  setattr(self, alg._name, alg)
340 
341 
342 ComponentAccumulator = ModuleType("ComponentAccumulator")
343 ComponentAccumulator.ComponentAccumulator = ComponentAccumulatorMockUp
344 
345 
346 
347 
348 #*******************************************************************
349 #
350 def addManyAlgs(job, algList):
351  """a little configuration function added from the python module JetAnalysisCommon.py to easily schedule
352  # a list of Configured algs as defined by this module."""
353  for alg in algList:
354  job.algsAdd( alg.asAnaAlg() )
355 
356 ROOT.EL.Job.addManyAlgs = addManyAlgs
357 
358 
359 #*******************************************************************
360 # hack the list of modules in sys so that the Athena config modules are found and redirected
361 # to what we have defined in this module
362 import sys
363 JetAnalysisCommon = sys.modules[__name__]
364 
365 #import AthenaConfiguration, AthenaCommon
366 sys.modules['AthenaConfiguration.ComponentFactory'] = JetAnalysisCommon.ComponentFactory
367 sys.modules['AthenaConfiguration.ComponentAccumulator'] = JetAnalysisCommon.ComponentAccumulator
368 sys.modules['AthenaCommon.CFElements'] = JetAnalysisCommon.CFElements
369 
370 
372  """Allows to ignore JetRecTools in case this package is not checked out on top of AnalysisBase"""
373  sys.modules['JetRecTools'] = ModuleType('JetRecTools')
374  sys.modules['JetRecTools.JetRecToolsConfig'] = ModuleType('JetRecToolsConfig')
375 
376 
377 
378 #*******************************************************************
379 # hacks specific to jets
380 
381 import JetRecConfig.JetRecConfig as JetRecConfig
382 
383 # In Athena the jet config relies on the automatic scheduling of algorithms
384 # which relies on Read/WriteHandles to correctly order them.
385 # There's no such automatic ordering in EventLoop.
386 # We thus need to add a step in AnalysisBase to make sure inputs algs to jet finder are
387 # correctly ordered.
388 # For this we redefine the original JetRecConfig.JetRecCfg function.
389 
390 JetRecConfig.JetRecCfg_original = JetRecConfig.JetRecCfg
391 def JetRecCfg_reorder(jetdef, flags, returnFinalJetDef=False):
392  """Builds the algs with JetRecConfig.JetRecCfg and then make sure
393  they are in proper order.
394  Re-ordering is done manually, according to various input alg type.
395  """
396  res = JetRecConfig.JetRecCfg_original(flags, jetdef , returnFinalJetDef)
397 
398  acc , _ = res if returnFinalJetDef else (res,None)
399  algs = acc.algs
400 
401  # ************
402  # reorder EventDensity and PseudoJetAlg
403  if not hasattr(ROOT, 'EventDensityAthAlg'):
404  return res
405  evtDensityAlgs = [ (i,alg) for (i,alg) in enumerate(algs) if alg._cppclass == ROOT.EventDensityAthAlg ]
406  pjAlgs = [ (i,alg) for (i,alg) in enumerate(algs) if alg._cppclass == ROOT.PseudoJetAlgorithm ]
407  pairsToswap = []
408  for i,edalg in evtDensityAlgs:
409  edInput = edalg.EventDensityTool.InputContainer
410  for j,pjalg in pjAlgs:
411  if j<i: continue
412  if edInput == pjalg.OutputContainer:
413  pairsToswap.append( (i,j) )
414  for (i,j) in pairsToswap:
415  algs[i], algs[j] = algs[j], algs[i]
416 
417  # ************
418  # if there were other types of alg which need re-rordering
419  # we could add the specific re-ordering code below ...
420 
421  return res
422 
423 JetRecConfig.JetRecCfg = JetRecCfg_reorder
python.JetAnalysisCommon.Configured.asAnaAlg
def asAnaAlg(self)
Definition: JetAnalysisCommon.py:162
python.JetAnalysisCommon.ConfNameSpace
Definition: JetAnalysisCommon.py:246
createLinkingScheme.iter
iter
Definition: createLinkingScheme.py:62
python.JetAnalysisCommon.Configured
Definition: JetAnalysisCommon.py:87
SCT_Parameters::ModuleType
ModuleType
Enums for module and chip type.
Definition: SCT_ReadoutData.h:33
vtune_athena.format
format
Definition: vtune_athena.py:14
python.JetAnalysisCommon.ConfArray.__iter__
def __iter__(self)
Definition: JetAnalysisCommon.py:73
python.JetAnalysisCommon.Configured.getType
def getType(self)
Definition: JetAnalysisCommon.py:208
python.JetAnalysisCommon.Configured._properties
_properties
Definition: JetAnalysisCommon.py:95
python.JetAnalysisCommon.Configured.__setattr__
def __setattr__(self, k, v)
Definition: JetAnalysisCommon.py:110
python.JetAnalysisCommon.ConfArray.__iadd__
def __iadd__(self, conflist)
Definition: JetAnalysisCommon.py:67
python.JetAnalysisCommon.Configured.assignAllProperties
def assignAllProperties(self, anaAlg)
Definition: JetAnalysisCommon.py:187
python.JetAnalysisCommon.ComponentAccumulatorMockUp.addEventAlgo
def addEventAlgo(self, alg, primary=False, sequenceName="")
Definition: JetAnalysisCommon.py:329
python.ComponentAccumulator.ComponentAccumulator
Definition: ComponentAccumulator.py:73
python.JetAnalysisCommon.Configured.toToolInAnaAlg
def toToolInAnaAlg(self, anaAlg, handlename)
Definition: JetAnalysisCommon.py:175
python.JetAnalysisCommon.Configured._name
_name
Definition: JetAnalysisCommon.py:105
python.JetAnalysisCommon.ComponentAccumulatorMockUp.__iter__
def __iter__(self)
Definition: JetAnalysisCommon.py:324
python.JetAnalysisCommon.ConfArray.append
def append(self, conf)
Definition: JetAnalysisCommon.py:76
python.JetAnalysisCommon.ConfNameSpace.addNameSpaces
def addNameSpaces(self, *nsList)
Definition: JetAnalysisCommon.py:287
python.JetAnalysisCommon.Configured._allowed
list _allowed
Definition: JetAnalysisCommon.py:101
dumpHVPathFromNtuple.append
bool append
Definition: dumpHVPathFromNtuple.py:91
python.JetAnalysisCommon.Configured.fullname
def fullname(self)
Definition: JetAnalysisCommon.py:151
python.JetAnalysisCommon.ConfArray
Definition: JetAnalysisCommon.py:58
python.CaloAddPedShiftConfig.type
type
Definition: CaloAddPedShiftConfig.py:42
klass
This class describe the base functionalities of a HypoTool used by the ComboAlg.
python.JetAnalysisCommon.ConfArray._parent
_parent
Definition: JetAnalysisCommon.py:63
python.JetAnalysisCommon.ConfNameSpace.__init__
def __init__(self, name="")
Definition: JetAnalysisCommon.py:254
python.JetAnalysisCommon.ComponentAccumulatorMockUp.algs
algs
Definition: JetAnalysisCommon.py:322
python.JetAnalysisCommon.ConfArray.conflist
conflist
Definition: JetAnalysisCommon.py:64
python.JetAnalysisCommon.Configured.ancestors
def ancestors(self)
Definition: JetAnalysisCommon.py:147
python.JetAnalysisCommon.ConfNameSpace.getComp
def getComp(self, classname)
Definition: JetAnalysisCommon.py:260
python.JetAnalysisCommon.ComponentAccumulatorMockUp.__init__
def __init__(self, name="ca")
Definition: JetAnalysisCommon.py:320
python.JetAnalysisCommon.ConfArray.key
key
Definition: JetAnalysisCommon.py:62
python.JetAnalysisCommon.ConfNameSpace.__getattr__
def __getattr__(self, t)
Definition: JetAnalysisCommon.py:257
python.JetAnalysisCommon.parOR
parOR
Definition: JetAnalysisCommon.py:311
python.JetAnalysisCommon.stringPropValue
def stringPropValue(value)
Definition: JetAnalysisCommon.py:48
python.JetAnalysisCommon.Configured.setparent
def setparent(self, parent)
Definition: JetAnalysisCommon.py:140
python.JetAnalysisCommon.Configured._anaAlg
_anaAlg
Definition: JetAnalysisCommon.py:98
python.JetAnalysisCommon.ComponentAccumulatorMockUp
Definition: JetAnalysisCommon.py:316
python.JetAnalysisCommon.ConfNameSpace.prefix
prefix
Definition: JetAnalysisCommon.py:255
add
bool add(const std::string &hname, TKey *tobj)
Definition: fastadd.cxx:55
python.JetAnalysisCommon.ComponentAccumulatorMockUp.addSequence
def addSequence(self, seqName)
Definition: JetAnalysisCommon.py:327
python.JetAnalysisCommon.Configured._setattrImpl
def _setattrImpl(self, k, v)
Definition: JetAnalysisCommon.py:116
python.JetAnalysisCommon.mock_JetRecTools
def mock_JetRecTools()
Definition: JetAnalysisCommon.py:371
python.JetAnalysisCommon.ConfArray.assignAllProperties
def assignAllProperties(self, anaAlg)
Definition: JetAnalysisCommon.py:79
python.JetAnalysisCommon.ComponentAccumulatorMockUp.name
name
Definition: JetAnalysisCommon.py:321
python.JetAnalysisCommon.ConfArray.__init__
def __init__(self, key, conflist, parent)
Definition: JetAnalysisCommon.py:61
CxxUtils::set
constexpr std::enable_if_t< is_bitmask_v< E >, E & > set(E &lhs, E rhs)
Convenience function to set bits in a class enum bitmask.
Definition: bitmask.h:232
print
void print(char *figname, TCanvas *c1)
Definition: TRTCalib_StrawStatusPlots.cxx:26
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.JetAnalysisCommon.Configured.properties
def properties(self)
Definition: JetAnalysisCommon.py:155
python.JetAnalysisCommon.Configured.typeAndName
def typeAndName(self)
Definition: JetAnalysisCommon.py:158
python.JetAnalysisCommon.Configured.__init__
def __init__(self, name, **props)
Definition: JetAnalysisCommon.py:103
python.JetAnalysisCommon.JetRecCfg_reorder
def JetRecCfg_reorder(jetdef, flags, returnFinalJetDef=False)
Definition: JetAnalysisCommon.py:391
python.JetAnalysisCommon.ComponentAccumulatorMockUp.merge
def merge(self, ca, sequenceName="")
Definition: JetAnalysisCommon.py:333
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.JetAnalysisCommon.Configured._propTypes
dictionary _propTypes
Definition: JetAnalysisCommon.py:96
get
T * get(TKey *tobj)
get a TObject* from a TKey* (why can't a TObject be a TKey?)
Definition: hcg.cxx:130
python.JetAnalysisCommon.generateConfigured
def generateConfigured(classname, cppclass, prefix="")
Definition: JetAnalysisCommon.py:212
python.JetAnalysisCommon.propertyType
def propertyType(p)
Definition: JetAnalysisCommon.py:232
str
Definition: BTagTrackIpAccessor.cxx:11
python.JetAnalysisCommon.addManyAlgs
def addManyAlgs(job, algList)
Definition: JetAnalysisCommon.py:350
python.JetAnalysisCommon.Configured._parent
_parent
Definition: JetAnalysisCommon.py:97
python.JetAnalysisCommon.Configured.prefixed
def prefixed(self, k)
Definition: JetAnalysisCommon.py:143
python.JetAnalysisCommon.Configured.setPropToAnaAlg
def setPropToAnaAlg(self, k, v)
Definition: JetAnalysisCommon.py:194
python.JetAnalysisCommon.Configured.getName
def getName(self)
Definition: JetAnalysisCommon.py:137
python.JetAnalysisCommon.ConfArray._anaAlg
_anaAlg
Definition: JetAnalysisCommon.py:80