ATLAS Offline Software
DependencyHelper.py
Go to the documentation of this file.
1 # Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2 """
3 
4 Functions to solve dependencies of Jet reco components.
5 
6 Jet reco components are objects described by classes in JetDefinition.py (including JetDefinition, JetModifier,...)
7 and the dependencies of each instance are set as (list of) string aliases refering to other components.
8 
9 The functions here are scanning recursively all the aliases, building the corresponding component objects and
10 collecting them in a JetDefinition.
11 
12 """
13 from .JetDefinition import JetInputExternal, JetInputConstit, JetModifier, JetInputConstitSeq
15  def __init__(self):
16  self._prereqDic = {}
17  self._prereqOrder = []
18 
19 
20 def solveDependencies( jetdef0, flags ):
21  """ Retrieve recursively all dependencies described by str aliases (from modifiers, ghosts, etc..) within jetdef0.
22  The aliases are converted in to proper config objects (like JetModifier, JetInputConstit,...) and are collected into
23  a cloned version of jetdef0.
24 
25  The cloned version is returned and contains all the necessary information to build the actual C++ tools and algs.
26  (in particular, the _prereqDic and _prereqOrder internal members of the clone are filled).
27  The cloned version also has its member '._cflags' set to the given config flags (might be used to instantiate the dependencies).
28  If jetdef0.context=='default' than the cloned version has its context set according to flags
29  """
30 
31  # create a clone onto which we can set internal variables to keep track of dependencies
32  jetdef = jetdef0.clone()
33  jetdef._cflags = flags
34  jetdef._contextDic = flags.Jet.Context[jetdef0.context]
35 
36  solveConstitDependencies(jetdef.inputdef, jetdef, inplace=True)
37 
38  jetdef._prereqDic['input:'+jetdef.inputdef.name] = jetdef.inputdef
39  jetdef._prereqOrder.append('input:'+jetdef.inputdef.name)
40 
41  for g in jetdef.extrainputs:
42  gInstance = aliasToInputDef( g , jetdef)
43  jetdef._prereqDic['input:'+g] = gInstance
44  jetdef._prereqOrder.append('input:'+g)
45 
46  for g in jetdef.ghostdefs:
47  gInstance = aliasToInputDef( g , jetdef)
48  jetdef._prereqDic['input:'+g] = gInstance
49  jetdef._prereqOrder.append('input:'+g)
50  jetdef._prereqDic['ghost:'+g] = gInstance
51  jetdef._prereqOrder.append('ghost:'+g)
52 
53  for mod in jetdef.modifiers:
54  modInstance = aliasToModDef(mod, jetdef)
55  jetdef._prereqDic['mod:'+mod] = modInstance
56  jetdef._prereqOrder.append('mod:'+mod)
57 
58  # Deduplicate the prereq (with python > 3.6 dict is ordered so the trick is guaranteed to work) :
59  jetdef._prereqOrder[:] = list(dict.fromkeys(jetdef._prereqOrder) )
60 
61  return jetdef
62 
63 
64 def solveGroomingDependencies( groomdef0, flags ):
65  """Retrieve all dependencies described by str aliases in groomdef0.modifiers.
66 
67  The aliases are converted in to proper config objects (like JetModifier, JetInputConstit,...) and are collected into
68  a cloned version of groomdef0.
69  The cloned version is returned and contains all the necessary information to build the actual C++ tools and algs.
70  (in particular, the _prereqDic and _prereqOrder internal members of the clone are filled).
71  """
72 
73  # if the context is "default", translate it into an actual context according to flags
74  groomdef = groomdef0.clone()
75  groomdef._cflags = flags
76  groomdef._contextDic = flags.Jet.Context[groomdef0.context]
77 
78  for mod in groomdef.modifiers:
79  modInstance = aliasToModDef(mod, groomdef)
80  groomdef._prereqDic['mod:'+mod] = modInstance
81  groomdef._prereqOrder.append('mod:'+mod)
82  return groomdef
83 
84 
85 def aliasToInputDef(alias, parentjetdef=None, canBeConstit=True):
86  """convert a string alias to a full config object, either a JetInputConstitSeq or a JetInputExternal according to the alias.
87 
88  This also recursively translate all aliases which are dependencies of this alias. All these dependencies are
89  collected into the 'parentjetdef' (JetDefinition ).
90 
91  if canBeConstit==false, the alias is not searched amongst known JetInputConstitSeq (in stdConstitDic),
92  """
93  parentjetdef = parentjetdef or _dummyJetDef()
94  # ----------------
95  # support the cases where alias is not a string but directly a config object
96  if isinstance(alias, JetInputConstit):
97  solveConstitDependencies(alias, parentjetdef, inplace=True)
98  return alias
99  if isinstance(alias, JetInputExternal):
100  solveInputExternalDependencies(alias, parentjetdef, inplace=True)
101  return alias
102 
103  # else assume it's a string
104 
105  # import the known dictionnary in which we'll look up for the alias
106  from .StandardJetConstits import stdConstitDic, stdInputExtDic
107 
108  if canBeConstit and alias in stdConstitDic:
109  # it is a JetInputConstit or JetInputConstitSeq instance :
110  return solveConstitDependencies(stdConstitDic[alias], parentjetdef)
111  elif alias in stdInputExtDic :
112  # it is a JetInputExternal instance :
113  return solveInputExternalDependencies(stdInputExtDic[alias], parentjetdef)
114 
115  raise Exception(f"Could not match a known jet input definition for '{alias}' ")
116 
117 def solveConstitDependencies(constitseq, parentjetdef, inplace=False):
118  """Recursively translate all aliases appearing in the prereqs of constitseq into proper config objects.
119  All are collected into the parentjetdef for which this JetInputConstitSeq is being configured.
120  Then instantiates all aliases for JetConstitModifier
121  """
122 
123  if not inplace:
124  constitseq = constitseq.clone()
125 
126  from .StandardJetConstits import stdInputExtDic, stdContitModifDic
127  # we technically need a JetInputExternal for constitseq.inputname : conveniently declare it if not existing :
128  stdInputExtDic.setdefault( constitseq.inputname, JetInputExternal( constitseq.inputname, constitseq.basetype) )
129 
130  # bellow, we'll use 'solveInputExternalDependencies()' to instantiate the prereqs
131  # so make sure our inputname is part of prereqs. Here, internally, use 'extinput' rather 'input' to mark
132  # the prereq is necessarily a JetInputExternal (and thus avoid issues when the same alias appears in stdInputExtDic and stdConstitDic)
133  if callable(constitseq.inputname):
134  constitseq.prereqs += ['ext'+constitseq.inputname(parentjetdef)]
135  else:
136  constitseq.prereqs += ['extinput:'+constitseq.inputname]
137 
138  if isinstance( constitseq, JetInputConstitSeq):
139  # instantiate the JetConstitModifier and add their dependencies to the actual constit sequence
140  for mod in constitseq.modifiers:
141  modInstance = stdContitModifDic[ mod ].clone()
142  parentjetdef._prereqDic[f'cmod:{mod}'] = modInstance
143  solveInputExternalDependencies( modInstance, parentjetdef, inplace=True)
144  # the rest of dependencies are handled similarly as JetInputExternal :
145  solveInputExternalDependencies( constitseq, parentjetdef)
146 
147  return constitseq
148 
149 def solveInputExternalDependencies(jetinputext, parentjetdef, inplace=False):
150  """Recursively translate all aliases appearing in the prereqs of jetinputext into proper config objects.
151  All are collected into the parentjetdef for which this JetInputConstitSeq is being configured.
152  """
153  if not inplace:
154  jetinputext = jetinputext.clone()
155 
156  # Prerequisite definitions may contain context-dependent functions instead of plain string.
157  # solve the context dependencence by calling these functions now :
158  if callable(jetinputext.prereqs):
159  # it's a function : call it to get the context-dependent list of prerequisites
160  jetinputext.prereqs = jetinputext.prereqs(parentjetdef)
161  # build the final list by building context-dependent prereq if needed :
162  jetinputext.prereqs = [ prereq(parentjetdef) if callable(prereq)
163  else prereq
164  for prereq in jetinputext.prereqs ]
165 
166  # at this point, jetinputext.prereqs contains only strings representing the final prerequisites
167  for prereq in jetinputext.prereqs :
168  reqInstance = parentjetdef._prereqDic.get( prereq, None)
169  if reqInstance is None:
170  reqType , inputkey = prereq.split(':') #
171  reqInstance = aliasToInputDef(inputkey, parentjetdef,
172  canBeConstit = (reqType != "extinput") )
173  parentjetdef._prereqDic[prereq] = reqInstance
174  parentjetdef._prereqOrder.append(prereq)
175 
176  return jetinputext
177 
178 
179 
180 
181 def prereqToDef(prereq, parentjetdef):
182  """translate a prereq string in the form 'type:alias' into a known config object.
183  """
184  str_prereq = prereq(parentjetdef) if callable(prereq) else prereq
185  reqtype, reqkey = str_prereq.split(':',1)
186  if reqtype=='mod':
187  reqInstance = aliasToModDef(reqkey, parentjetdef)
188  else:
189  reqInstance = aliasToInputDef(reqkey, parentjetdef)
190  return reqInstance
191 
192 def aliasToModDef(alias, parentjetdef ):
193  """return a JetModifier config object corresponding to alias, also recursively translating all aliases in the dependencies of this JetModifier."""
194  if isinstance(alias, JetModifier):
195  return alias
196  # else assume it's a string
197 
198  # split it, to extract the optional specifiers
199  modL = alias.split(":")
200  modkey = modL[0]
201  modspec = ':'.join(modL[1:])
202 
203  # retrieve an instance from the known modifiers in StandardJetMods :
204  from .StandardJetMods import stdJetModifiers
205  moddef = stdJetModifiers[modkey].clone( modspec = modspec)
206 
207 
208  if callable(moddef.prereqs):
209  moddef.prereqs = moddef.prereqs( modspec, parentjetdef )
210 
211  for prereq in moddef.prereqs:
212  str_prereq = prereq(parentjetdef) if callable(prereq) else prereq
213  reqInstance = parentjetdef._prereqDic.get( str_prereq, None)
214  if reqInstance is None:
215  reqInstance = prereqToDef(str_prereq, parentjetdef)
216 
217  if str_prereq.startswith('ghost:'):
218  # then it is also an input : register this requirement also as an input
219  prereqN = str_prereq.split(':')[1]
220  parentjetdef._prereqOrder.append('input:'+prereqN)
221  parentjetdef._prereqDic['input:'+prereqN] = reqInstance # the input config instance is identical for input and ghost (only the PseudoJet will differ)
222 
223  parentjetdef._prereqOrder.append(str_prereq)
224  parentjetdef._prereqDic[str_prereq] = reqInstance
225 
226  return moddef
python.DependencyHelper._dummyJetDef.__init__
def __init__(self)
Definition: DependencyHelper.py:15
python.DependencyHelper.solveInputExternalDependencies
def solveInputExternalDependencies(jetinputext, parentjetdef, inplace=False)
Definition: DependencyHelper.py:149
python.DependencyHelper._dummyJetDef._prereqDic
_prereqDic
Definition: DependencyHelper.py:16
python.DependencyHelper.prereqToDef
def prereqToDef(prereq, parentjetdef)
Definition: DependencyHelper.py:181
python.JetDefinition.JetInputExternal
Definition: JetDefinition.py:347
python.Utilities.clone
clone
Definition: Utilities.py:134
python.DependencyHelper._dummyJetDef
Definition: DependencyHelper.py:14
python.DependencyHelper.aliasToModDef
def aliasToModDef(alias, parentjetdef)
Definition: DependencyHelper.py:192
histSizes.list
def list(name, path='/')
Definition: histSizes.py:38
python.DependencyHelper.solveDependencies
def solveDependencies(jetdef0, flags)
Definition: DependencyHelper.py:20
python.DependencyHelper.solveConstitDependencies
def solveConstitDependencies(constitseq, parentjetdef, inplace=False)
Definition: DependencyHelper.py:117
TCS::join
std::string join(const std::vector< std::string > &v, const char c=',')
Definition: Trigger/TrigT1/L1Topo/L1TopoCommon/Root/StringUtils.cxx:10
python.DependencyHelper.aliasToInputDef
def aliasToInputDef(alias, parentjetdef=None, canBeConstit=True)
Definition: DependencyHelper.py:85
python.DependencyHelper._dummyJetDef._prereqOrder
_prereqOrder
Definition: DependencyHelper.py:17
python.DependencyHelper.solveGroomingDependencies
def solveGroomingDependencies(groomdef0, flags)
Definition: DependencyHelper.py:64