ATLAS Offline Software
Loading...
Searching...
No Matches
JetChainConfiguration.py
Go to the documentation of this file.
1# Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
2
3import re
4from AthenaCommon.Logging import logging
5logging.getLogger().info("Importing %s",__name__)
6log = logging.getLogger(__name__)
7
8from ..Config.ChainConfigurationBase import ChainConfigurationBase
9
10from .JetRecoSequencesConfig import JetRecoDataDeps
11
12from .JetMenuSequencesConfig import (
13 jetCaloHypoMenuSequenceGenCfg,
14 jetRoITrackJetTagHypoMenuSequenceGenCfg,
15 jetFSTrackingHypoMenuSequenceGenCfg,
16 jetCaloRecoMenuSequenceGenCfg,
17 jetCaloPreselMenuSequenceGenCfg,
18 jetHICaloHypoMenuSequenceGenCfg,
19)
20from .ExoticJetSequencesConfig import jetEJsMenuSequenceGenCfg, jetCRVARMenuSequenceGenCfg,jetCRMenuSequenceGenCfg
21
22from . import JetRecoCommon
23from . import JetPresel
24
25from TrigEDMConfig.TriggerEDM import recordable
26
27import copy
28
29#----------------------------------------------------------------
30# Class to configure chain
31#----------------------------------------------------------------
32class JetChainConfiguration(ChainConfigurationBase):
33
34 def __init__(self, chainDict):
35 # we deliberately don't call base class constructore, since this assumes a single chain part
36 # which is not the case for jets
37
38 self.dict = copy.deepcopy(chainDict)
39
40 self.chainName = self.dict['chainName']
41 self.chainL1Item = self.dict['L1item']
42
43 self.chainPart = self.dict['chainParts']
44 self.L1Threshold = ''
45 self.mult = 1 # from the framework point of view I think the multiplicity is 1, internally the jet hypo has to figure out what to actually do
46
47 # these properties are in the base class, but I don't think we need them for jets
48 #self.chainPartName = ''
49 #self.chainPartNameNoMult = ''
50 #self.chainPartNameNoMultwL1 = ''
51
52 # expect that the L1 seed is the same for all jet parts, otherwise we have a problem
53 jChainParts = JetRecoCommon.jetChainParts(self.chainPart)
54 # Register if this is a performance chain, in which case the HLT should be exactly j0_perf
55 self.isPerf = False
56 # Exotic hypo (emerging-jets, trackless jets)
57 self.exotHypo = ''
58 # Check if we intend to preselect events with calo jets in step 1
59 self.trkpresel = "nopresel"
60
61 for ip,p in enumerate(jChainParts):
62 # Check if there is exactly one exotic hypothesis defined
63 if len(p['exotHypo']) > 1:
64 raise RuntimeError('emerging chains currently not configurable with more than one emerging selection!')
65 if p['exotHypo']:
66 self.exotHypo = p['exotHypo'][0]
67
68 if 'perf' in p['addInfo']:
69 # Need to ensure a few conditions to ensure there is no selection bias:
70 # No preselection, no special hypo
71 # Only one chainPart is permitted
72 verify_null_str = [ p[k]!='' for k in ['jvt','momCuts','timing','bsel','bTag', 'tausel']]
73 verify_null_list = [ p[k]!=[] for k in ['prefilters','exotHypo'] ]
74 if (
75 p['trkpresel']!='nopresel' or p['hypoScenario']!='simple'
76 or any(verify_null_str) or any(verify_null_list)
77 or p['smc']!='nosmc'
78 or ip>0
79 ):
80 raise RuntimeError(f'Invalid jet \'perf\' chain "{self.chainName}": No additional selection is permitted!')
81 self.isPerf = True
82 l1th = p['L1threshold']
83 if self.L1Threshold != '' and self.L1Threshold != l1th:
84 raise RuntimeError('Cannot configure a jet chain with different L1 thresholds')
85 self.L1Threshold = l1th
86 # Verify that the preselection is defined only once
87 if p["trkpresel"]!="nopresel" and ip+1!=len(jChainParts): # Last jet chainPart, presel should go here
88 log.error("Likely inconsistency encountered in preselection specification for %s",self.chainName)
89 raise RuntimeError("Preselection %s specified earlier than in the last chainPart!",p["trkpresel"])
90
91 self.trkpresel = JetPresel.extractPreselection(self.dict)
92 self.trkpresel_parsed_reco = {key:p[key] for key in ['recoAlg']} #Storing here the reco options from last chain part that we want to propagate to preselection (e.g. jet radius)
93
94 self.recoDict = JetRecoCommon.extractRecoDict(jChainParts)
95 self.jetName = None
96 self.jetDefDict = None
97
98
99 # ----------------------
100 # Precompute the data dependencies i.e. jet collections to generate
101 # ----------------------
102 def prepareDataDependencies(self, flags):
103 self.jetDefDict = JetRecoDataDeps(flags, **self.recoDict)
104 jetsOut, jetDef = self.jetDefDict['final']
105 self.jetName = recordable(jetDef.fullname())
106
107
108 # ----------------------
109 # Assemble the chain depending on information from chainName
110 # ----------------------
111 def assembleChainImpl(self, flags):
112 log.debug("Assembling chain %s", self.chainName)
113
114 # --------------------
115 # define here the names of the steps and obtain the chainStep configuration
116 # --------------------
117 chainSteps = []
118 if self.recoDict["ionopt"] in ['ion', 'ionp']:
119 jetHICaloHypoStep = self.getJetHICaloHypoChainStep(flags)
120 chainSteps.append( jetHICaloHypoStep )
121 elif self.recoDict["trkopt"]=="roiftf":
122 # Can't work w/o calo presel jets to seed RoIs
123 if self.trkpresel=="nopresel":
124 raise RuntimeError("RoI FTF jet tracking requested with no jet preselection to provide RoIs")
125 # Set up calo preselection step first
126 preselJetDef, jetPreselStep = self.getJetCaloPreselChainStep(flags)
127 chainSteps.append( jetPreselStep )
128 # Standard tracking step, configure the tracking instance differently
129
130 jetRoITrackJetTagHypoStep = self.getJetRoITrackJetTagHypoChainStep(flags, preselJetDef)
131 chainSteps.append( jetRoITrackJetTagHypoStep )
132 elif self.recoDict["trkopt"]=="ftf":
133 if self.trkpresel=="nopresel":
134 # Passthrough calo reco -- only for prescaled chains due to CPU cost
135 caloRecoStep = self.getJetCaloRecoChainStep(flags)
136 chainSteps.append( caloRecoStep )
137 #Add empty step to align with preselection step
138 roitrkPreselStep = self.getEmptyStep('RoIFTFEmptyStep')
139 else:
140 # Add calo preselection step
141 preselJetDef, jetPreselStep = self.getJetCaloPreselChainStep(flags)
142 chainSteps.append( jetPreselStep )
143
144 if re.match(r'.*((b|bg|bgtwo)\d\d)|.*Z|.*gntau|.*uht', self.trkpresel):
145 # Preselection with super-RoI tracking for b-tagging, tau-tagging or pileup tagging
146 roitrkPreselStep = self.getJetRoITrackJetTagPreselChainStep(flags, preselJetDef)
147 else:
148 # Empty step for alignment if no roiftf preselection defined
149 roitrkPreselStep=self.getEmptyStep('RoIFTFEmptyStep')
150
151 chainSteps.append(roitrkPreselStep)
152 # Final selection with FS tracking
153 jetFSTrackingHypoStep = self.getJetFSTrackingHypoChainStep(flags)
154 chainSteps.append( jetFSTrackingHypoStep )
155 else:
156 # No special options, just EMTopo jet reconstruction going straight to final rejection
157 jetCaloHypoStep = self.getJetCaloHypoChainStep(flags)
158 chainSteps.append( jetCaloHypoStep )
159
160 # Add exotic jets hypo
161 if self.exotHypo != '' and ("emerging" in self.exotHypo or "trackless" in self.exotHypo):
162 EJsStep = self.getJetEJsChainStep(flags, self.jetName, self.exotHypo)
163 chainSteps+= [EJsStep]
164 elif self.exotHypo != '' and ("calratiovar" in self.exotHypo):
165 CRVARStep = self.getJetCRVARChainStep(flags, self.jetName, self.exotHypo)
166 chainSteps+= [ CRVARStep]
167 elif self.exotHypo != '' and ("calratio" in self.exotHypo):
168 CRStep = self.getJetCRChainStep(flags, self.jetName, self.exotHypo)
169 chainSteps+= [self.getEmptyStep('RoIFTFEmptyStep'), CRStep]
170
171 myChain = self.buildChain(chainSteps)
172
173 return myChain
174
175
176 # --------------------
177 # Configuration of steps
178 # --------------------
179
180 # These ChainStep generators all pass information between steps
181 def getJetCaloHypoChainStep(self, flags):
182 stepName = f"MainStep_jet_{self.recoDict['jetDefStr']}"
183
184 if self.isPerf:
185 stepName += '_perf'
186
187 jetStep = self.getStep(flags, stepName, [jetCaloHypoMenuSequenceGenCfg], isPerf=self.isPerf, **self.jetDefDict)
188 return jetStep
189
191 stepName = f"MainStep_HIjet_{self.recoDict['jetDefStr']}"
192 if self.isPerf:
193 stepName += '_perf'
194
195 jetStep = self.getStep(
196 flags, stepName, [jetHICaloHypoMenuSequenceGenCfg],
197 isPerf=self.isPerf, **self.recoDict,
198 )
199 return jetStep
200
202 stepName = "MainStep_jet_"+self.recoDict['jetDefStr']
203 if self.isPerf:
204 stepName += '_perf'
205
206 jetStep = self.getStep(
207 flags, stepName, [jetFSTrackingHypoMenuSequenceGenCfg],
208 isPerf=self.isPerf,
209 **self.jetDefDict
210 )
211 return jetStep
212
213 def getJetCaloRecoChainStep(self, flags):
214 clusterCalib = self.recoDict["clusterCalib"]
215 stepName = "CaloRecoPTStep_jet_"+clusterCalib
216
217 return self.getStep(flags, stepName, [jetCaloRecoMenuSequenceGenCfg], clusterCalib=clusterCalib)
218
220
221 #Find if a a4 or a10 calo jet needs to be used in the pre-selection from the last chain dict
222 assert 'recoAlg' in self.trkpresel_parsed_reco.keys(), "Impossible to find \'recoAlg\' key in last chain dictionary for preselection"
223 #Want to match now only a4 and a10 in the original reco algorithm. We don't want to use a10sd or a10t in the preselection
224 matched_reco = re.match(r'^a\d?\d?', self.trkpresel_parsed_reco['recoAlg'])
225 assert matched_reco is not None, "Impossible to get matched reco algorithm for jet trigger preselection The reco expression {0} seems to be impossible to be parsed.".format(self.trkpresel_parsed_reco['recoAlg'])
226
227 #Getting the outcome of the regex reco option (it should correspond to a4 or a10 depending by which chain you are configuring)
228 preselRecoDict = JetPresel.getPreselRecoDict(matched_reco.group())
229
230 preselJetDefDict = JetRecoDataDeps(flags, **preselRecoDict)
231 preselJetsOut, preselJetDef = preselJetDefDict["final"]
232
233 stepName = "PreselStep_jet_"+preselRecoDict['jetDefStr']
234 jetStep = self.getStep(flags, stepName, [jetCaloPreselMenuSequenceGenCfg], **preselJetDefDict)
235
236 return preselJetDef, jetStep
237
238 # From here, only return ChainStep, no passing around of data dependencies
239 def getJetRoITrackJetTagHypoChainStep(self, flags, preselJetDef):
240 stepName = "RoIFTFStep_jet_sel_"+self.recoDict['jetDefStr']
241 return self.getStep(flags, stepName, [jetRoITrackJetTagHypoMenuSequenceGenCfg], jetDef=preselJetDef, isPresel=False)
242
243 def getJetRoITrackJetTagPreselChainStep(self, flags, jetDef):
244
245 #Find if a a4 or a10 calo jet needs to be used in the pre-selection from the last chain dict
246 assert 'recoAlg' in self.trkpresel_parsed_reco.keys(), "Impossible to find \'recoAlg\' key in last chain dictionary for preselection"
247 #Want to match now only a4 and a10 in the original reco algorithm. We don't want to use a10sd or a10t in the preselection
248 matched_reco = re.match(
249 r'^a\d?\d?', self.trkpresel_parsed_reco['recoAlg'])
250 assert matched_reco is not None, "Impossible to get matched reco algorithm for jet trigger preselection The reco expression {0} seems to be impossible to be parsed.".format(
251 self.trkpresel_parsed_reco['recoAlg'])
252
253 #Getting the outcome of the regex reco option (it should correspond to a4 or a10 depending by which chain you are configuring)
254 preselRecoDict = JetPresel.getPreselRecoDict(matched_reco.group(),roiftf=True)
255
256 assert preselRecoDict['trkopt'] == 'roiftf', 'getJetRoITrackJetTagPreselChainStep: you requested a RoI tracking preselection but the reco dictionary has \'trkopt\' set to {0}'.format(preselRecoDict['trkopt'])
257
258 stepName = "RoIFTFStep_jet_"+self.recoDict['jetDefStr']
259 return self.getStep(flags, stepName, [jetRoITrackJetTagHypoMenuSequenceGenCfg], jetDef=jetDef, isPresel=True)
260
261 def getJetEJsChainStep(self, flags, jetCollectionName, exotdictstring):
262
263 # Must be configured similar to : emergingPTF0p0dR1p2 or tracklessdR1p2
264 if 'emerging' in exotdictstring and ('dR' not in exotdictstring \
265 or 'PTF' not in exotdictstring):
266 log.error('Misconfiguration of exotic jet chain - need dR and PTF options')
267 exit(1)
268 if 'trackless' in exotdictstring and 'dR' not in exotdictstring:
269 log.error('Misconfiguration of trackless exotic jet chain - need dR option')
270 exit(1)
271
272 trackless = int(0)
273 if 'emerging' in exotdictstring:
274 ptf = float(exotdictstring.split('PTF')[1].split('dR')[0].replace('p', '.'))
275 dr = float(exotdictstring.split('dR')[1].split('_')[0].replace('p', '.'))
276 elif 'trackless' in exotdictstring:
277 trackless = int(1)
278 ptf = 0.0
279 dr = float(exotdictstring.split('dR')[1].split('_')[0].replace('p', '.'))
280 else:
281 log.error('Misconfiguration of trackless exotic jet chain - need emerging or trackless selection')
282 exit(1)
283
284 log.debug("Running exotic jets with ptf: " + str(ptf) + "\tdR: " + str(dr) + "\ttrackless: " + str(trackless) + "\thypo: " + exotdictstring)
285
286 stepName = "EJsStep"
287
288 return self.getStep(flags, stepName, [jetEJsMenuSequenceGenCfg], jetsIn=jetCollectionName)
289
290 def getJetCRVARChainStep(self, flags, jetCollectionName, exotdictstring):
291
292 if 'calratiovar' in exotdictstring:
293 MinjetlogR = 1.2
294 if 'calratiovarrmbib' in exotdictstring:
295 doBIBremoval = int(1)
296 else:
297 doBIBremoval = int(0)
298 else:
299 log.error('Misconfiguration of trackless exotic jet chain - need calratiovar selection')
300 exit(1)
301
302 log.debug("Running exotic jets with MinjetlogR: " + str(MinjetlogR) + "\t BIB rm " + str(doBIBremoval) + "\thypo: " + exotdictstring)
303
304 return self.getStep(flags, "CRVARStep", [jetCRVARMenuSequenceGenCfg], jetsIn=jetCollectionName)
305
306 def getJetCRChainStep(self, flags, jetCollectionName, exotdictstring):
307
308 if 'calratio' in exotdictstring and ('calratiovar' not in exotdictstring):
309 MinjetlogR = 1.2
310 if 'calratiormbib' in exotdictstring:
311 doBIBremoval = int(1)
312 else:
313 doBIBremoval = int(0)
314 else:
315 log.error('Misconfiguration of trackless exotic jet chain - need calratio selection')
316 exit(1)
317
318 log.debug("Running exotic jets with MinjetlogR: " + str(MinjetlogR) + "\t BIB rm " + str(doBIBremoval) + "\thypo: " + exotdictstring)
319
320 return self.getStep(flags, "CRStep", [jetCRMenuSequenceGenCfg], jetsIn=jetCollectionName)
getJetEJsChainStep(self, flags, jetCollectionName, exotdictstring)
getJetCRChainStep(self, flags, jetCollectionName, exotdictstring)
getJetCRVARChainStep(self, flags, jetCollectionName, exotdictstring)
std::string replace(std::string s, const std::string &s2, const std::string &s3)
Definition hcg.cxx:310
std::vector< std::string > split(const std::string &s, const std::string &t=":")
Definition hcg.cxx:177