ATLAS Offline Software
JetRecConfig.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 
3 """
4 JetRecConfig: A helper module for configuring jet reconstruction
5 
6 The functions defined here turn JetDefinition object into ComponentAccumulator or list of algs fully configured
7 and ready to be inserted in the framework sequence.
8 
9 Author: TJ Khoo, P-A Delsart
10 """
11 
12 
13 from AthenaCommon import Logging
14 jetlog = Logging.logging.getLogger('JetRecConfig')
15 
16 from ROOT import xAODType
17 xAODType.ObjectType
18 
19 from AthenaConfiguration.ComponentAccumulator import ComponentAccumulator
20 from AthenaConfiguration.ComponentFactory import CompFactory
21 
22 
23 from JetRecConfig.JetDefinition import JetDefinition, JetInputConstitSeq, JetInputConstit, JetInputExternal
24 from JetRecConfig.JetGrooming import GroomingDefinition
25 from JetRecConfig.DependencyHelper import solveDependencies, solveGroomingDependencies, aliasToModDef
26 
27 
28 __all__ = ["JetRecCfg", "JetInputCfg"]
29 
30 
31 
32 
35 
36 def JetRecCfg( flags, jetdef, returnConfiguredDef=False):
37  """Top-level function for running jet finding or grooming.
38 
39  This returns a ComponentAccumulator that can be merged with others
40  from elsewhere in the job and which provides everything needed to
41  reconstruct one jet collection.
42 
43  arguments :
44  - jetdef : jet or grooming definition
45  - flags : the configuration flags instance, mainly for input file
46  peeking such that we don't attempt to reproduce stuff that's already
47  in the input file. And also to be able to invoke building of inputs outside of Jet domain during reco from RAW/RDO.
48  - returnConfiguredDef : is for debugging. It will also returns the cloned JetDefinition which contains the calculated dependencies.
49 
50  """
51 
52  sequenceName = jetdef.fullname()
53  jetlog.info("******************")
54  jetlog.info("Setting up to find {0}".format(sequenceName))
55 
56  components = ComponentAccumulator()
57  from AthenaCommon.CFElements import parOR
58  components.addSequence( parOR(sequenceName) )
59 
60  # call the relevant function according to jetdef_i type
61  if isinstance(jetdef, JetDefinition):
62  algs, jetdef_i = getJetDefAlgs(flags, jetdef , True)
63  elif isinstance(jetdef, GroomingDefinition):
64  algs, jetdef_i = getJetGroomAlgs(flags, jetdef, True)
65 
66  # FIXME temporarily reorder for serial running
67  if flags.Concurrency.NumThreads <= 0:
68  jetlog.info("Reordering algorithms in sequence {0}".format(sequenceName))
69  algs, ca = reOrderAlgs(algs)
70  components.merge(ca)
71 
72  for a in algs:
73 
74  if isinstance(a, ComponentAccumulator):
75  components.merge(a )
76  else:
77  components.addEventAlgo( a , sequenceName = sequenceName )
78 
79  if returnConfiguredDef: return components, jetdef_i
80  return components
81 
82 
83 def JetInputCfg(flags,jetOrConstitdef , context="default"):
84  """Returns a ComponentAccumulator containing algs needed to build inputs to jet finding as defined by jetOrConstitdef
85 
86  jetOrConstitdef can either be
87  * a JetDefinition : this happens when called from JetRecCfg, then the jetdef._prereqDic/Order are used.
88  * a JetInputConstit : to allow scheduling the corresponding constituents algs independently of any jet alg.
89 
90  context is only used if jetOrConstitdef is not a JetDefinition and must refer to a context in StandardJetContext
91  """
92  components = ComponentAccumulator()
93 
94  algs = getInputAlgs(jetOrConstitdef, flags, context)
95 
96  for a in algs:
97 
98  if isinstance(a, ComponentAccumulator):
99  components.merge(a)
100  else:
101  components.addEventAlgo(a)
102 
103  return components
104 
105 def PseudoJetCfg(jetdef):
106  """Builds a ComponentAccumulator for creating PseudoJetContainer needed by jetdef.
107  THIS updates jetdef._internalAtt['finalPJContainer']
108  """
109  components = ComponentAccumulator()
110  pjalglist = getPseudoJetAlgs(jetdef)
111  for pjalg in pjalglist:
112  components.addEventAlgo(pjalg)
113  return components
114 
115 
116 
120 
121 
122 def getJetDefAlgs(flags, jetdef , returnConfiguredDef=False, monTool=None):
123  """ Create the algorithms necessary to build the jet collection defined by jetdef.
124 
125  This internally finds all the dependencies declared into jetdef (through input, ghosts & modifiers)
126  and returns a list of all necessary algs.
127 
128  if returnConfiguredDef==True, also returns the fully configured clone of jetdef containing solved dependencies (debugging)
129 
130  monTool is to allow the trigger config to pass a monitoring tool.
131 
132  returns a list containing either algs or ComponentAccumulator
133  (ComponentAccumulator occurs only (?) in reco from RDO/RAW when we need to build externals such as clusters or tracks : in this case we call the main config functions from external packages)
134  """
135 
136  # Scan the dependencies of this jetdef, also converting all aliases it contains
137  # into config objects and returning a fully configured copy.
138 
139  jetdef_i = solveDependencies(jetdef, flags=flags)
140 
141 
142  # check if the conditions are compatible with the inputs & modifiers of this jetdef_i.
143  # if in reco job we will remove whatever is incompatible and still try to run
144  # if not, we raise an exception
145  canrun = removeComponentFailingConditions(jetdef_i, raiseOnFailure= flags.Jet.strictMode)
146  if not canrun :
147  if returnConfiguredDef:
148  return [], jetdef_i
149  return []
150 
151  algs = []
152 
153  # With jetdef_i, we can now instantiate the proper c++ tools and algs.
154 
155  # algs needed to build the various inputs (constituents, track selection, event density, ...)
156  algs += getInputAlgs(jetdef_i, flags , monTool=monTool)
157 
158  # algs to create fastjet::PseudoJet objects out of the inputs
159  algs += getPseudoJetAlgs(jetdef_i)
160 
161  # Generate a JetRecAlg to run the jet finding and modifiers
162  algs += [getJetRecAlg(jetdef_i, monTool=monTool)]
163 
164  jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(jetdef_i.fullname()))
165 
166  if returnConfiguredDef:
167  return algs, jetdef_i
168  return algs
169 
170 def getJetGroomAlgs(flags, groomdef, returnConfiguredDef=False, monTool=None):
171  """Instantiate and schedule all the algorithms needed to run the grooming alg 'groomdef' and
172  add them in the ComponentAccumulator 'components'
173 
174  This function is meant to be called from the top-level JetRecConfig.JetRecCfg
175  (groomdef is expected to be non locked and will be modified).
176 
177  monTool is to allow the trigger config to pass a monitoring tool.
178  """
179 
180  # Find dependencies from modifier aliases and get a fully configured groomdef
181  # ( This also detects input dependencies, see below)
182  groomdef_i = solveGroomingDependencies(groomdef, flags)
183 
184  # Transfer the input & ghost dependencies onto the parent jet alg,
185  # so they are handled when instatiating the parent jet algs
186  for prereq in groomdef_i._prereqOrder:
187  #Protection for some modifiers that have three 'arguments'
188  if len(prereq.split(':')) > 2:
189  continue
190  reqType, reqKey = prereq.split(':')
191  if reqType=='ghost':
192  groomdef_i.ungroomeddef.ghostdefs.append(reqKey)
193  elif reqType.endswith('input') : # can be extinput or input
194  groomdef_i.ungroomeddef.extrainputs.append(reqKey)
195 
196  jetlog.info("Scheduling parent alg {} for {} ".format(groomdef.ungroomeddef.fullname(), groomdef.fullname()))
197 
198  # Retrieve algs needed to build the parent (ungroomed) jets
199  # (we always want it even if the parent jets are already in the input file because
200  # we need to rebuild the pseudoJet)
201  algs, ungroomeddef_i = getJetDefAlgs(flags, groomdef_i.ungroomeddef , True)
202  groomdef_i._ungroomeddef = ungroomeddef_i # set directly the internal members to avoid complication. This is fine, since we've been cloning definitions.
203 
204  #Filter the modifiers based on the flags
205  removeGroomModifFailingConditions(groomdef_i, flags, raiseOnFailure = flags.Jet.strictMode)
206 
207  algs += [ getJetRecGroomAlg(groomdef_i, monTool=monTool) ]
208 
209 
210  jetlog.info("Scheduled JetAlgorithm instance \"jetalg_{0}\"".format(groomdef_i.fullname()))
211 
212  if returnConfiguredDef: return algs, groomdef_i
213  return algs
214 
215 
216 def getJetAlgs(flags, jetdef, returnConfiguredDef=False, monTool=None):
217  # Useful helper function For Run-II config style
218  if isinstance(jetdef, JetDefinition):
219  func = getJetDefAlgs
220  elif isinstance(jetdef, GroomingDefinition):
221  func = getJetGroomAlgs
222 
223  return func(flags, jetdef, returnConfiguredDef, monTool)
224 
225 
226 
231 
232 
233 def getPseudoJetAlgs(jetdef):
234  """ Builds the list of configured PseudoJetAlgorithm needed for this jetdef.
235  THIS updates jetdef._internalAtt['finalPJContainer']
236  (this function is factorized out of PseudoJetCfg so it can be used standalone in the trigger config)
237  """
238 
239  constitpjalg = getConstitPJGAlg(jetdef.inputdef , suffix=None , flags=jetdef._cflags, parent_jetdef = jetdef)
240 
241  finalPJContainer = str(constitpjalg.OutputContainer)
242  pjalglist = [constitpjalg]
243 
244  # Schedule the ghost PseudoJetAlgs
245  ghostlist = [ key for key in jetdef._prereqOrder if key.startswith('ghost:')]
246  if ghostlist != []:
247  # then we need to schedule a PseudoJetAlg for each ghost collections...
248  pjContNames = [finalPJContainer]
249  for ghostkey in sorted(ghostlist):
250  ghostdef = jetdef._prereqDic[ghostkey]
251  ghostpjalg = getGhostPJGAlg( ghostdef, jetdef )
252  pjalglist.append(ghostpjalg)
253  pjContNames.append( str(ghostpjalg.OutputContainer) ) #
254 
255  # .. and merge them together with the input constituents
256  mergeId = mergedPJId( pjContNames )
257  finalPJContainer = str(finalPJContainer)+"_merged"+mergeId
258  mergerName = "PJMerger_id"+mergeId
259  mergeAlg =CompFactory.PseudoJetMerger(
260  mergerName,
261  InputPJContainers = pjContNames,
262  OutputContainer = finalPJContainer,
263  )
264  pjalglist.append(mergeAlg)
265 
266  # set the name of the complete,merged input PseudoJets, so it can be re-used downstream
267  jetdef._internalAtt['finalPJContainer'] = finalPJContainer
268  return pjalglist
269 
270 
271 _mergedPJContainers = dict()
272 def mergedPJId(pjList):
273  """returns a simple unique ID for the list of PseudoJet container in pjList"""
274  t = tuple(str(n) for n in pjList) # make sure it is string (it can be DataHandle in old style config)
275  currentSize = len(_mergedPJContainers)
276  return str(_mergedPJContainers.setdefault(t, currentSize))
277 
278 
279 def getInputAlgs(jetOrConstitdef, flags, context="default", monTool=None):
280  """Returns the list of configured algs needed to build inputs to jet finding as defined by jetOrConstitdef
281 
282  jetOrConstitdef can either be
283  * a JetDefinition : this happens when called from JetRecCfg or getJetDefAlgs then the jetdef._prereqDic/Order are used.
284  * a JetInputConstit : to allow scheduling the corresponding constituents algs independently of any jet alg.
285 
286  context is only used if jetOrConstitdef is not a JetDefinition and must refer to a context in StandardJetContext.
287 
288  The returned list may contain several algs, including constituent modifications algs, track selection, copying of
289  input truth particles and event density calculations
290  It may also contain ComponentAccumulator, only (?) in reco from RDO/RAW when we need to build externals such as clusters or tracks : in this case we call the main config functions from external packages)
291 
292  """
293 
294  from .JetDefinition import JetInputConstit, JetDefinition
295  if isinstance(jetOrConstitdef, JetInputConstit):
296  # technically we need a JetDefinition, so just build an empty one only containing our JetInputConstit
297  jetlog.info("Setting up jet inputs from JetInputConstit : "+jetOrConstitdef.name)
298  jetdef = solveDependencies( JetDefinition('Kt', 0., jetOrConstitdef, context=context), flags )
299  canrun = removeComponentFailingConditions(jetdef, raiseOnFailure = flags.Jet.strictMode)
300  if not canrun:
301  return []
302  else:
303  jetdef = jetOrConstitdef
304 
305  jetlog.info("Inspecting input file contents")
306 
307  # We won't prepare an alg if the input already exists in the in input file
308  try:
309  filecontents = jetdef._cflags.Input.Collections
310  except Exception:
311  filecontents = []
312  # local function to check if the container of the JetInputXXXX 'c' is already in filecontents :
313  def isInInput( c ):
314  cname = c.containername if isinstance(c, JetInputConstit) else c.containername(jetdef,c.specs)
315  return cname in filecontents
316 
317  # Loop over all inputs required by jetdefs and get the corresponding algs
318  inputdeps = [ inputkey for inputkey in jetdef._prereqOrder if inputkey.startswith('input:') or inputkey.startswith('extinput:') ]
319  algs = []
320  for inputfull in inputdeps:
321  inputInstance = jetdef._prereqDic[inputfull]
322  if isInInput( inputInstance ):
323  jetlog.info(f"Input container for {inputInstance} already in input file.")
324  continue
325 
326  # Get the input or external alg
327  if isinstance(inputInstance, JetInputConstit):
328  alg = getConstitModAlg(jetdef, inputInstance, monTool=monTool)
329  else: # it must be a JetInputExternal
330  alg = inputInstance.algoBuilder( jetdef, inputInstance.specs )
331 
332  if alg is not None:
333  algs.append(alg)
334 
335  return algs
336 
337 
338 
339 
340 
341 def getPJContName( jetOrConstitdef, suffix=None, parent_jetdef = None):
342  """Construct the name of the PseudoJetContainer defined by the given JetDef or JetInputConstit.
343  This name has to be constructed from various places, so we factorize the definition here.
344  """
345  cdef = jetOrConstitdef if isinstance(jetOrConstitdef, JetInputConstit) else jetOrConstitdef.inputdef
346  _str_containername = cdef.containername(parent_jetdef).split(':')[-1] if callable(cdef.containername) else cdef.containername
347  end = '' if suffix is None else f'_{suffix}'
348  return f'PseudoJet{_str_containername}{end}'
349 
350 def getConstitPJGAlg(constitdef, suffix=None, flags=None, parent_jetdef = None):
351  """returns a configured PseudoJetAlgorithm which converts the inputs defined by constitdef into fastjet::PseudoJet
352 
353  IMPORTANT : constitdef must have its dependencies solved (i.e. it must result from a solveDependencies() call)
354 
355  the flags argument is TEMPORARY and will be removed once further dev on PseudoJetAlgorithm is done (see comment below)
356  """
357  _str_containername = constitdef.containername(parent_jetdef).split(':')[-1] if callable(constitdef.containername) else constitdef.containername
358  jetlog.debug("Getting PseudoJetAlg for label {0} from {1}".format(constitdef.name,constitdef.inputname))
359  end = '' if suffix is None else f'_{suffix}'
360  full_label = constitdef.label + end
361  pjgalg = CompFactory.PseudoJetAlgorithm(
362  "pjgalg_"+_str_containername+end,
363  InputContainer = _str_containername,
364  OutputContainer =getPJContName(constitdef, suffix = suffix, parent_jetdef = parent_jetdef),
365  Label = full_label,
366  SkipNegativeEnergy=True,
367  DoByVertex=constitdef.byVertex
368  )
369 
370  # This is a terrible temporary hack to enable running in cosmic runs.
371  # There should not be any Properties setting here in a helper function.
372  # This will have to be fixed when all the filtering occuring in PseudoJetAlgorithm
373  # is removed and done as part of a JetConstituentModSequence.
374  if flags is not None:
375  from AthenaConfiguration.Enums import BeamType
376  pjgalg.UseChargedPV = (flags.Beam.Type == BeamType.Collisions)
377 
378  if suffix == 'PUSB':
379  pjgalg.UseChargedPV=False
380  pjgalg.UseChargedPUsideband=True
381  elif suffix == 'Neut':
382  pjgalg.UseCharged=False
383  # end of HAck
384 
385  return pjgalg
386 
387 def getGhostPJGAlg(ghostdef, parentjetdef = None):
388  """returns a configured PseudoJetAlgorithm which converts the inputs defined by constitdef into fastjet::PseudoJet
389 
390  The difference for the above is this is dedicated to ghosts which need variations for the Label and the muon segment cases.
391 
392  IMPORTANT : ghostdef must have its dependencies solved (i.e. it must result from a solveDependencies() call)
393  """
394  label = "Ghost"+ghostdef.label # IMPORTANT !! "Ghost" in the label will be interpreted by the C++ side !
395  _container_name = ghostdef.containername(parentjetdef).split(":")[1] if callable(ghostdef.containername) else ghostdef.containername
396  _output_cont_name_suffix = "" if parentjetdef.context == "default" or _container_name.endswith(parentjetdef.context) else ("_" + parentjetdef.context)
397 
398  kwargs = dict(
399  InputContainer = _container_name,
400  OutputContainer= "PseudoJetGhost"+_container_name + _output_cont_name_suffix,
401  Label= label,
402  SkipNegativeEnergy= True,
403  )
404 
405  pjaclass = CompFactory.PseudoJetAlgorithm
406  if ghostdef.basetype=="MuonSegment" or ghostdef.basetype=="UnAssocMuonSegment":
407  # Muon segments have a specialised type
408  pjaclass = CompFactory.MuonSegmentPseudoJetAlgorithm
409  kwargs.update( Pt =1e-20 ) # ??,)
410  kwargs.pop('SkipNegativeEnergy')
411 
412  pjgalg = pjaclass( "pjgalg_" + label + "_" + parentjetdef.context, **kwargs )
413  return pjgalg
414 
415 
416 def getJetRecAlg( jetdef, monTool = None, ftf_suffix = '', extraOutputs = []):
417  """Returns the configured JetRecAlg instance corresponding to jetdef
418 
419  IMPORTANT : jetdef must have its dependencies solved (i.e. it must result from solveDependencies() )
420  """
421  pjContNames = jetdef._internalAtt['finalPJContainer']
422 
423  kwargs = {
424  "JetAlgorithm": jetdef.algorithm,
425  "JetRadius": jetdef.radius,
426  "PtMin": jetdef.ptmin,
427  "InputPseudoJets": pjContNames,
428  "GhostArea": jetdef.ghostarea,
429  "JetInputType": int(jetdef.inputdef.jetinputtype),
430  "RandomOption": 1,
431  "VariableRMinRadius": jetdef.VRMinRadius,
432  "VariableRMassScale": jetdef.VRMassScale
433  }
434 
435  jetname = jetdef.fullname()
436  if jetdef.byVertex:
437  jclust = CompFactory.JetClustererByVertex(
438  "builder",
439  **kwargs
440  )
441  else:
442  jclust = CompFactory.JetClusterer(
443  "builder",
444  **kwargs
445  )
446 
447  mods = getJetModifierTools(jetdef)
448 
449  jra = CompFactory.JetRecAlg(
450  "jetrecalg_"+jetname+ftf_suffix,
451  Provider = jclust,
452  Modifiers = mods,
453  OutputContainer = jetname+ftf_suffix,
454  )
455  if monTool:
456  # this option can't be set in AnalysisBase -> set only if explicitly asked :
457  jra.MonTool = monTool
458 
459  # Explicitly register (ghost)associated branches for downstream dependency resolution
460  jra.ExtraOutputs = extraOutputs + [
461  ('xAOD::JetContainer',f'{jetname}.Ghost{ghost}') for ghost in jetdef.ghostdefs
462  ]
463  return jra
464 
465 
466 def getJetRecGroomAlg(groomdef,monTool=None,extraOutputs=[]):
467  """Returns a configured JetRecAlg set-up to perform the grooming defined by 'groomdef'
468  ('monTool' is a temporary placeholder, it is expected to be used in the trigger in the future)
469  """
470  jetlog.debug("Configuring grooming alg \"jetalg_{0}\"".format(groomdef.fullname()))
471 
472 
473  # the grooming tool (a IJetProvider instance)
474  groomClass = CompFactory.getComp(groomdef.tooltype)
475  groomer = groomClass(groomdef.groomalg,
476  UngroomedJets = groomdef.ungroomeddef.fullname(),
477  ParentPseudoJets = groomdef.ungroomeddef._internalAtt['finalPJContainer'],
478  **groomdef.properties)
479 
480  # get JetModifier list
481  mods = getJetModifierTools(groomdef)
482 
483  # put everything together in a JetRecAlg
484  jetname = groomdef.fullname()
485  jra = CompFactory.JetRecAlg(
486  "jetrecalg_"+jetname,
487  Provider = groomer,
488  Modifiers = mods,
489  ParentDecor = "Parent",
490  OutputContainer = jetname)
491 
492  if not isAnalysisRelease():
493  jra.MonTool = monTool
494 
495  # Explicitly register (ghost)associated branches for downstream dependency resolution
496  jra.ExtraOutputs = extraOutputs + [
497  ('xAOD::JetContainer',f'{jetname}.Ghost{ghost}') for ghost in groomdef.ungroomeddef.ghostdefs
498  ]
499 
500  return jra
501 
502 
503 
504 def getJetCopyAlg(jetsin, jetsoutdef, decorations=[], shallowcopy=True, shallowIO=True, monTool=None):
505  """
506  Get a JetRecAlg set up to copy a jet collection and apply mods
507  In this setup we do not resolve dependencies because typically
508  these may be set up already in the original jet collection
509  In future we may wish to add a toggle.
510 
511  The decoration list can be set in order for the decorations
512  (jet moments) on the original jets to be propagated to the
513  copy collection. Beware of circular dependencies!
514  """
515  jcopy = CompFactory.JetCopier(
516  "copier",
517  InputJets = jetsin,
518  DecorDeps=decorations,
519  ShallowCopy=shallowcopy,
520  ShallowIO=shallowIO)
521 
522  # Convert mod aliases into concrete tools
523  mods = []
524  for mod in jetsoutdef.modifiers:
525  moddef = aliasToModDef(mod,jetsoutdef)
526  mods.append(getModifier(jetsoutdef,moddef,moddef.modspec))
527 
528  jetsoutname = jetsoutdef.fullname()
529  jra = CompFactory.JetRecAlg(
530  "jetrecalg_copy_"+jetsoutname,
531  Provider = jcopy,
532  Modifiers = mods,
533  OutputContainer = jetsoutname)
534  if not isAnalysisRelease():
535  jra.MonTool = monTool
536 
537 
538  return jra
539 
540 
541 
542 def getConstitModAlg(parentjetdef, constitSeq, monTool=None):
543  """returns a configured JetConstituentModSequence or None if constit.modifiers == []
544 
545  The JetConstituentModSequence is determined by the JetInputConstitSeq constitSeq .
546  However, details of the configuration of the JetConstituentModSequence may depends on which JetDefinition
547  this JetConstituentModSequence is intended for. Thus the function also requires a parentjetdef JetDefinition input
548 
549  IMPORTANT : parentjetdef & constitSeq must have their dependencies solved (i.e. they must result from solveDependencies() )
550 
551  See also getConstitModAlg_nojetdef
552  """
553 
554  # JetInputConstit do not need any JetConstituentModSequence
555  # (they are only needed to trigger the building of the source container and a PJ algo)
556  if not isinstance(constitSeq, JetInputConstitSeq): return
557 
558 
559  inputtype = constitSeq.basetype
560 
561  sequence = constitSeq.modifiers
562 
563  modlist = []
564 
565  #if modlist == []: return
566  if constitSeq.inputname == constitSeq.containername: return
567 
568  for step in sequence:
569  modInstance = parentjetdef._prereqDic[ f'cmod:{step}' ]
570  if not modInstance.tooltype: continue
571 
572  toolclass = getattr( CompFactory, modInstance.tooltype)
573 
574  # update the properties : if some of them are function, just replace by calling this func :
575  for k,v in modInstance.properties.items():
576  if callable(v) :
577  modInstance.properties[k ] = v(parentjetdef, constitSeq )
578 
579  tool = toolclass(modInstance.name,**modInstance.properties)
580 
581  if (inputtype == xAODType.FlowElement or inputtype == xAODType.ParticleFlow) and modInstance.tooltype not in ["CorrectPFOTool","ChargedHadronSubtractionTool"]:
582  tool.IgnoreChargedPFO=True
583  tool.ApplyToChargedPFO=False
584  tool.InputType = inputtype
585  modlist.append(tool)
586 
587  sequenceshort = "".join(sequence)
588  seqname = "ConstitMod{0}_{1}".format(sequenceshort,constitSeq.name)
589  inputcontainer = str(constitSeq.inputname)
590  outputcontainer = str(constitSeq.containername)
591 
592  if (inputtype == xAODType.FlowElement or inputtype == xAODType.ParticleFlow):
593  # Tweak PF names because ConstModSequence needs to work with
594  # up to 4 containers
595  def chopPFO(thestring):
596  pfostr = "ParticleFlowObjects"
597  if thestring.endswith(pfostr):
598  return thestring[:-len(pfostr)]
599  return thestring
600  inputcontainer = chopPFO(inputcontainer)
601  outputcontainer = chopPFO(outputcontainer)
602 
603  doByVertex = constitSeq.byVertex
604 
605  inChargedFEDecorKeys = []
606  inNeutralFEDecorKeys = []
607 
608  if doByVertex:
609  # For by-vertex jet reconstruction, we are performing deep copies of neutral PFOs
610  # Need to schedule this algorithm after all decorations have been apllied by using ReadDecorHandleKeys
611 
612  # https://gitlab.cern.ch/atlas/athena/-/blob/main/Reconstruction/PFlow/PFlowUtils/src/PFlowCellCPDataDecoratorAlgorithm.h
613 
614  # https://gitlab.cern.ch/atlas/athena/-/blob/main/Reconstruction/PFlow/PFlowUtils/src/PFlowCalibPFODecoratorAlgorithm.h
615 
616  # https://gitlab.cern.ch/atlas/athena/-/blob/main/Reconstruction/eflowRec/eflowRec/PFEGamFlowElementAssoc.h
617 
618  # https://gitlab.cern.ch/atlas/athena/-/blob/main/Reconstruction/eflowRec/eflowRec/PFMuonFlowElementAssoc.h
619 
620  inChargedFEDecorKeys += ["cellCPData", "FE_ElectronLinks", "FE_PhotonLinks", "FE_MuonLinks"]
621  inNeutralFEDecorKeys += ["calpfo_NLeadingTruthParticleBarcodeEnergyPairs", "FE_ElectronLinks", "FE_PhotonLinks", "FE_MuonLinks"]
622 
623  modseq = CompFactory.JetConstituentModSequence(seqname,
624  InputType=inputtype,
625  OutputContainer = outputcontainer,
626  InputContainer= inputcontainer,
627  InChargedFEDecorKeys = inChargedFEDecorKeys,
628  InNeutralFEDecorKeys = inNeutralFEDecorKeys,
629  Modifiers = modlist,
630  DoByVertex = doByVertex
631  )
632  if monTool:
633  modseq.MonTool = monTool
634 
635  constitmodalg = CompFactory.JetAlgorithm("jetalg_{0}".format(modseq.getName()))
636  constitmodalg.Tools = [modseq]
637 
638  return constitmodalg
639 
640 def getConstitModAlg_nojetdef( constitSeq, flags,context="default", monTool=None):
641  """Same as getConstitModAlg.
642  This is a convenient function to obtain a JetConstituentModSequence when it is certain, no JetDef is needed.
643  This function just builds a dummy JetDefinition then calls getConstitModAlg
644  Needed in the trigger config.
645  """
646  jetdef = solveDependencies( JetDefinition('Kt', 0., constitSeq, context=context) , flags)
647  constitSeq = jetdef._prereqDic['input:'+constitSeq.name] # retrieve the fully configured version of constitSeq
648  return getConstitModAlg(jetdef, constitSeq, monTool=monTool)
649 
650 
651 def getJetModifierTools( jetdef ):
652  """returns the list of configured JetModifier tools needed by this jetdef.
653  This is done by instantiating the actual C++ tool as ordered in jetdef._prereqOrder
654  """
655  modlist = [ key for key in jetdef._prereqOrder if key.startswith('mod:')]
656 
657  mods = []
658  for modkey in modlist:
659  moddef = jetdef._prereqDic[modkey]
660  modkey = modkey[4:] # remove 'mod:'
661  modspec = '' if ':' not in modkey else modkey.split(':',1)[1]
662  mod = getModifier(jetdef,moddef,modspec)
663  mods.append(mod)
664 
665  return mods
666 
667 
668 def getModifier(jetdef, moddef, modspec, flags=None):
669  """Translate JetModifier into a concrete tool"""
670  jetlog.verbose("Retrieving modifier {0}".format(str(moddef)))
671 
672  if flags is not None:
673  # then we are called from non JetRecConfig functions: we must update the context according to flags
674  jetdef = jetdef.clone()
675  jetdef._cflags = flags
676  jetdef._contextDic = flags.Jet.Context[jetdef.context]
677 
678  # Get the modifier tool
679  try:
680  modtool = moddef.createfn(jetdef, modspec)
681  except Exception as e:
682  jetlog.error( f"Unhandled modifier specification {modspec} for mod {moddef} acting on jet def {jetdef.basename}!")
683  jetlog.error( f"Received exception \"{e}\"" )
684  jetlog.error( f"Helper function is \"{moddef.createfn}\"" )
685  raise ValueError( f"JetModConfig unable to handle mod {moddef} with spec \"{modspec}\"")
686 
687 
688  # now we overwrite the default properties of the tool, by those
689  # set in the moddef :
690  for k,v in moddef.properties.items():
691  if callable(v) :
692  # The value we got is a function : we call it to get the actual value we want to set on the tool
693  v = v(jetdef, modspec)
694  setattr(modtool, k, v)
695 
696  return modtool
697 
698 
699 
700 
701 def removeComponentFailingConditions(jetdef, flags=None, raiseOnFailure=True):
702  """Filters the lists jetdef.modifiers and jetdef.ghosts (and jetdef._prereqOrder), so only the components
703  comptatible with flags are selected.
704  If flags==None : assume jetdef._cflags is properly set (this is done by higher-level functions)
705  The compatibility is ultimately tested using the component 'filterfn' attributes.
706  Internally calls the function isComponentPassingConditions() (see below)
707  """
708  jetlog.info("Standard Reco mode : filtering components in "+str(jetdef))
709 
710  if jetdef._cflags is None:
711  jetdef._cflags = flags
712 
713 
716 
717  # ---------
718  # first check if the input can be obtained. If not return.
719  ok,reason = isComponentPassingConditions( jetdef.inputdef, jetdef._cflags, jetdef)
720  if not ok:
721  if raiseOnFailure:
722  raise Exception(f"JetDefinition {jetdef} can NOT be scheduled. Failure of input {jetdef.inputdef.name} reason={reason}" )
723  jetlog.info(f"IMPORTANT : removing {jetdef} because input incompatible with job conditions. Reason={reason} ")
724  return False
725 
726  if isinstance( jetdef.inputdef, JetInputConstitSeq):
727  # remove ConstitModifiers failing conditions.
728  jetdef.inputdef.modifiers = filterJetDefList(jetdef, jetdef.inputdef.modifiers, 'cmod', raiseOnFailure, jetdef._cflags)
729 
730 
731 
732  # call the helper function to perform filtering :
733  jetdef.ghostdefs = filterJetDefList(jetdef, jetdef.ghostdefs, "ghost", raiseOnFailure, jetdef._cflags)
734  jetdef.modifiers = filterJetDefList(jetdef, jetdef.modifiers, "mod", raiseOnFailure, jetdef._cflags)
735  # finally filter all possible intermediate dependency :
736  filterJetDefList(jetdef, list(jetdef._prereqOrder), "", raiseOnFailure, jetdef._cflags)
737  return True
738 
739 
740 
741 def removeGroomModifFailingConditions(groomdef, flags, raiseOnFailure=True):
742 
743  groomdef.modifiers = filterJetDefList(groomdef, groomdef.modifiers, "mod", raiseOnFailure, flags)
744  filterJetDefList(groomdef, list(groomdef._prereqOrder), "", raiseOnFailure, flags)
745 
746 
747 
748 # define a helper function to filter components from jet definition
749 def filterJetDefList(jetdef, inList, compType, raiseOnFailure, flags):
750 
751  nOut=0
752  outList=[]
753  basekey= compType+':' if compType!="" else ""
754 
755  fullname = jetdef.fullname()
756 
757  # loop over components in the list to be filtered
758  for comp in inList:
759  fullkey = basekey+comp
760  cInstance = jetdef._prereqDic[fullkey]
761  ok, reason = isComponentPassingConditions(cInstance, flags, jetdef)
762  if not ok :
763  if raiseOnFailure:
764  raise Exception("JetDefinition {} can NOT be scheduled. Failure of {} {} reason={}".format(
765  jetdef, compType, comp, reason) )
766 
767  nOut+=1
768  jetlog.info(f"{fullname} : removing {compType} {comp} reason={reason}")
769  if fullkey in jetdef._prereqOrder:
770  jetdef._prereqOrder.remove(fullkey)
771  if compType=='ghost':
772  removeFromList(jetdef._prereqOrder, 'input:'+comp)
773  removeFromList(jetdef._prereqOrder, 'extinput:'+comp)
774  else:
775  outList.append(comp)
776 
777  jetlog.info(" *** Number of {} filtered components = {} final list={}".format(compType, nOut, outList) )
778 
779  return outList
780 
781 
782 
783 
784 def isComponentPassingConditions(component, flags, jetdef):
785  """Test if component is compatible with flags.
786  This is done by calling component.filterfn AND testing all its prereqs.
787  """
788  for req in component.prereqs:
789  _str_req = req(jetdef) if callable(req) else req
790  if _str_req not in jetdef._prereqDic:
791  return False, "prereq "+_str_req+" not available"
792  reqInstance = jetdef._prereqDic[_str_req]
793  ok, reason = isComponentPassingConditions(reqInstance, flags, jetdef)
794  if not ok :
795  return False, "prereq "+str(reqInstance)+" failed because : "+reason
796 
797  ok, reason = component.filterfn(flags)
798  return ok, reason
799 
800 
802  from AthenaConfiguration.Enums import Project
803  return Project.determine() in( Project.AnalysisBase, Project.AthAnalysis)
804 
805 
806 def reOrderAlgs(algs):
807  """In runIII the scheduler automatically orders algs, so the JetRecConfig helpers do not try to enforce the correct ordering.
808  This is not the case in runII config for which this jobO is intended --> This function makes sure some jet-related algs are well ordered.
809  """
810  def _flatten_CA(cfg, sequence_name="AthAlgSeq"):
811  from AthenaConfiguration.ComponentAccumulator import ConfigurationError
812  if not isinstance(cfg, ComponentAccumulator):
813  raise ConfigurationError('It is not allowed to flatten with multiple top sequences')
814 
815  if len(cfg._allSequences) != 1:
816  raise ConfigurationError('It is not allowed to flatten with multiple top sequences')
817 
818  sequence = cfg.getSequence(sequence_name)
819  if sequence.Sequential:
820  raise ConfigurationError('It is not allowed to flatten sequential sequences')
821 
822  members = []
823  for member in sequence.Members:
824  if isinstance(member, CompFactory.AthSequencer):
825  members.extend(_flatten_CA(cfg, member.getName()))
826  else:
827  members.append(member)
828 
829  sequence.Members = members
830  return members
831 
832  algs_tmp = []
833  ca = ComponentAccumulator()
834  for a in algs:
835  if not isinstance(a, ComponentAccumulator) :
836  algs_tmp.append(a)
837  else:
838  _flatten_CA(a)
839  ca_algs = list(a._algorithms.keys())
840  for algo in ca_algs:
841  algs_tmp.append(a.popEventAlgo(algo))
842  ca.merge(a)
843 
844  algs = algs_tmp
845  evtDensityAlgs = [(i, alg) for (i, alg) in enumerate(algs) if alg and alg.getType() == 'EventDensityAthAlg' ]
846  pjAlgs = [(i, alg) for (i, alg) in enumerate(algs) if alg and alg.getType() == 'PseudoJetAlgorithm' ]
847  pairsToswap = []
848  for i, edalg in evtDensityAlgs:
849  edInput = edalg.EventDensityTool.InputContainer
850  for j, pjalg in pjAlgs:
851  if j < i:
852  continue
853  if edInput == str(pjalg.OutputContainer):
854  pairsToswap.append((i, j))
855  for i, j in pairsToswap:
856  algs[i], algs[j] = algs[j], algs[i]
857 
858  return algs, ca
859 
860 
861 
863  """Make the jet collection described by jetdef available as constituents to other jet finding
864 
865  Technically : create JetInputExternal and JetInputConstit and register them in the relevant look-up dictionnaries.
866  the JetInputConstit will have a algoBuilder to generate the JetContainer described by jetdef
867  """
868  from .StandardJetConstits import stdConstitDic, stdInputExtDic
869  jetname = jetdef.fullname()
870 
871  # define a function to generate the CA for this jetdef
872  def jetBuilder(largejetdef,spec):
873  return JetRecCfg(largejetdef._cflags, jetdef)
874 
875  stdInputExtDic[jetname] = JetInputExternal( jetname, jetname, algoBuilder=jetBuilder)
876  stdConstitDic[jetname] = JetInputConstit(jetname, xAODType.Jet, jetname )
877 
878 
879 def removeFromList(l, o):
880  if o in l:
881  l.remove(o)
882 
883 # Run test with command like "python -m JetRecConfig.JetRecConfig"
884 def JetRecConfigTest(flags=None):
885 
886  # Config flags steer the job at various levels
887  if flags is None:
888  from AthenaConfiguration.AllConfigFlags import initConfigFlags
889  flags = initConfigFlags()
890 
891  from AthenaConfiguration.TestDefaults import defaultTestFiles, defaultConditionsTags
892  flags.Input.Files = defaultTestFiles.LATEST_AOD_MC
893  flags.IOVDb.GlobalTag = defaultConditionsTags.LATEST_MC
894 
895  flags.lock()
896 
897  # Get a ComponentAccumulator setting up the fundamental Athena job
898  from AthenaConfiguration.MainServicesConfig import MainServicesCfg
899  cfg=MainServicesCfg(flags)
900 
901  # Add the components for reading in pool files
902  from AthenaPoolCnvSvc.PoolReadConfig import PoolReadCfg
903  cfg.merge(PoolReadCfg(flags))
904 
905  # Add the components from our jet reconstruction job
906  from JetRecConfig.StandardSmallRJets import AntiKt4EMTopo
907  cfg.merge(JetRecCfg(flags, AntiKt4EMTopo))
908 
909  cfg.printConfig(withDetails=False,summariseProps=True)
910  cfg.run(10)
911 
912 if __name__=="__main__":
914 
915 
916 
DerivationFramework::TriggerMatchingUtils::sorted
std::vector< typename R::value_type > sorted(const R &r, PROJ proj={})
Helper function to create a sorted vector from an unsorted range.
python.JetAnalysisCommon.ComponentAccumulator
ComponentAccumulator
Definition: JetAnalysisCommon.py:302
vtune_athena.format
format
Definition: vtune_athena.py:14
python.JetRecConfig.getInputAlgs
def getInputAlgs(jetOrConstitdef, flags, context="default", monTool=None)
Definition: JetRecConfig.py:279
python.JetRecConfig.getJetRecAlg
def getJetRecAlg(jetdef, monTool=None, ftf_suffix='', extraOutputs=[])
Definition: JetRecConfig.py:416
python.JetRecConfig.getConstitModAlg
def getConstitModAlg(parentjetdef, constitSeq, monTool=None)
Definition: JetRecConfig.py:542
python.JetRecConfig.reOrderAlgs
def reOrderAlgs(algs)
Definition: JetRecConfig.py:806
python.JetRecConfig.getModifier
def getModifier(jetdef, moddef, modspec, flags=None)
Definition: JetRecConfig.py:668
python.JetRecConfig.isAnalysisRelease
def isAnalysisRelease()
Definition: JetRecConfig.py:801
python.JetRecConfig.getJetAlgs
def getJetAlgs(flags, jetdef, returnConfiguredDef=False, monTool=None)
Definition: JetRecConfig.py:216
python.JetRecConfig.getJetGroomAlgs
def getJetGroomAlgs(flags, groomdef, returnConfiguredDef=False, monTool=None)
Definition: JetRecConfig.py:170
python.JetRecConfig.filterJetDefList
def filterJetDefList(jetdef, inList, compType, raiseOnFailure, flags)
Definition: JetRecConfig.py:749
python.JetRecConfig.registerAsInputConstit
def registerAsInputConstit(jetdef)
Definition: JetRecConfig.py:862
python.JetRecConfig.removeComponentFailingConditions
def removeComponentFailingConditions(jetdef, flags=None, raiseOnFailure=True)
Definition: JetRecConfig.py:701
python.JetRecConfig.getConstitModAlg_nojetdef
def getConstitModAlg_nojetdef(constitSeq, flags, context="default", monTool=None)
Definition: JetRecConfig.py:640
python.JetAnalysisCommon.parOR
parOR
Definition: JetAnalysisCommon.py:271
python.DependencyHelper.aliasToModDef
def aliasToModDef(alias, parentjetdef)
Definition: DependencyHelper.py:192
python.JetRecConfig.getJetModifierTools
def getJetModifierTools(jetdef)
Definition: JetRecConfig.py:651
python.JetRecConfig.JetRecCfg
def JetRecCfg(flags, jetdef, returnConfiguredDef=False)
Top level functions returning ComponentAccumulator out of JetDefinition.
Definition: JetRecConfig.py:36
python.JetRecConfig.mergedPJId
def mergedPJId(pjList)
Definition: JetRecConfig.py:272
python.MainServicesConfig.MainServicesCfg
def MainServicesCfg(flags, LoopMgr='AthenaEventLoopMgr')
Definition: MainServicesConfig.py:310
python.JetRecConfig.getGhostPJGAlg
def getGhostPJGAlg(ghostdef, parentjetdef=None)
Definition: JetRecConfig.py:387
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.JetRecConfig.getJetDefAlgs
def getJetDefAlgs(flags, jetdef, returnConfiguredDef=False, monTool=None)
Mid level functions returning list of algs out of JetDefinition.
Definition: JetRecConfig.py:122
python.DependencyHelper.solveDependencies
def solveDependencies(jetdef0, flags)
Definition: DependencyHelper.py:20
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.JetRecConfig.getPJContName
def getPJContName(jetOrConstitdef, suffix=None, parent_jetdef=None)
Definition: JetRecConfig.py:341
python.JetRecConfig.getConstitPJGAlg
def getConstitPJGAlg(constitdef, suffix=None, flags=None, parent_jetdef=None)
Definition: JetRecConfig.py:350
python.JetRecConfig.JetInputCfg
def JetInputCfg(flags, jetOrConstitdef, context="default")
Definition: JetRecConfig.py:83
python.JetRecConfig.removeGroomModifFailingConditions
def removeGroomModifFailingConditions(groomdef, flags, raiseOnFailure=True)
Definition: JetRecConfig.py:741
python.JetRecConfig.getJetCopyAlg
def getJetCopyAlg(jetsin, jetsoutdef, decorations=[], shallowcopy=True, shallowIO=True, monTool=None)
Definition: JetRecConfig.py:504
python.PyAthena.v
v
Definition: PyAthena.py:154
python.CaloAddPedShiftConfig.int
int
Definition: CaloAddPedShiftConfig.py:45
python.AllConfigFlags.initConfigFlags
def initConfigFlags()
Definition: AllConfigFlags.py:19
python.JetRecConfig.PseudoJetCfg
def PseudoJetCfg(jetdef)
Definition: JetRecConfig.py:105
python.DependencyHelper.solveGroomingDependencies
def solveGroomingDependencies(groomdef0, flags)
Definition: DependencyHelper.py:64
str
Definition: BTagTrackIpAccessor.cxx:11
python.JetRecConfig.getPseudoJetAlgs
def getPseudoJetAlgs(jetdef)
Mid level functions returning specific type of algs out of JetDefinition functions below assumines th...
Definition: JetRecConfig.py:233
python.JetRecConfig.isComponentPassingConditions
def isComponentPassingConditions(component, flags, jetdef)
Definition: JetRecConfig.py:784
python.JetRecConfig.JetRecConfigTest
def JetRecConfigTest(flags=None)
Definition: JetRecConfig.py:884
python.JetRecConfig.getJetRecGroomAlg
def getJetRecGroomAlg(groomdef, monTool=None, extraOutputs=[])
Definition: JetRecConfig.py:466
python.PoolReadConfig.PoolReadCfg
def PoolReadCfg(flags)
Definition: PoolReadConfig.py:71
python.JetRecConfig.removeFromList
def removeFromList(l, o)
Definition: JetRecConfig.py:879
Trk::split
@ split
Definition: LayerMaterialProperties.h:38