4 from AnalysisAlgorithmsConfig.ConfigBlock
import ConfigBlock
6 from AthenaConfiguration.Enums
import LHCPeriod
7 from AnalysisAlgorithmsConfig.ConfigAccumulator
import DataType
8 from TrigGlobalEfficiencyCorrection.TriggerLeg_DictHelpers
import TriggerDict, MapKeysDict
9 from Campaigns.Utils
import Campaign
10 from AthenaCommon.Logging
import logging
13 from xAODEgamma.xAODEgammaParameters
import xAOD
19 """the ConfigBlock for the electron four-momentum correction"""
22 super (ElectronCalibrationConfig, self).__init__ ()
23 self.setBlockName(
'Electrons')
24 self.addOption (
'containerName', containerName, type=str,
26 info=
"the name of the output container after calibration.")
27 self.addOption (
'ESModel',
'', type=str,
28 info=
"flag of egamma calibration recommendation.")
29 self.addOption (
'decorrelationModel',
'1NP_v1', type=str,
30 info=
"egamma energy scale decorrelationModel. The default is 1NP_v1. "
31 "Supported Model: 1NP_v1, FULL_v1.")
32 self.addOption (
'postfix',
'', type=str,
33 info=
"a postfix to apply to decorations and algorithm names. Typically "
34 "not needed here since the calibration is common to all electrons.")
35 self.addOption (
'crackVeto',
False, type=bool,
36 info=
"whether to perform LAr crack veto based on the cluster eta, "
37 "i.e. remove electrons within 1.37<|eta|<1.52. The default "
39 self.addOption (
'isolationCorrection',
False, type=bool,
40 info=
"whether or not to perform isolation corrections (leakage "
41 "corrections), i.e. set up an instance of "
42 "CP::EgammaIsolationCorrectionAlg.")
43 self.addOption (
'recalibratePhyslite',
True, type=bool,
44 info=
"whether to run the CP::EgammaCalibrationAndSmearingAlg on "
45 "PHYSLITE derivations. The default is True.")
46 self.addOption (
'minPt', 4.5*GeV, type=float,
47 info=
"the minimum pT cut to apply to calibrated electrons. "
48 "The default is 4.5 GeV.")
49 self.addOption (
'maxEta', 2.47, type=float,
50 info=
"maximum electron |eta| (float). The default is 2.47.")
51 self.addOption (
'forceFullSimConfig',
False, type=bool,
52 info=
"whether to force the tool to use the configuration meant for "
53 "full simulation samples. Only for testing purposes. The default "
56 self.addOption (
'splitCalibrationAndSmearing',
False, type=bool,
57 info=
"EXPERIMENTAL: This splits the EgammaCalibrationAndSmearingTool "
58 " into two steps. The first step applies a baseline calibration that "
59 "is not affected by systematics. The second step then applies the "
60 "systematics dependent corrections. The net effect is that the "
61 "slower first step only has to be run once, while the second is run "
62 "once per systematic. ATLASG-2358")
64 self.addOption (
'decorateTruth',
False, type=bool,
65 info=
"decorate truth particle information on the reconstructed one")
69 """Create the calibration and smearing algorithm
71 Factoring this out into its own function, as we want to
72 instantiate it in multiple places"""
74 alg = config.createAlgorithm(
'CP::EgammaCalibrationAndSmearingAlg', name + self.postfix )
75 config.addPrivateTool(
'calibrationAndSmearingTool',
76 'CP::EgammaCalibrationAndSmearingTool' )
79 alg.calibrationAndSmearingTool.ESModel = self.ESModel
81 if config.geometry()
is LHCPeriod.Run2:
82 alg.calibrationAndSmearingTool.ESModel =
'es2023_R22_Run2_v0'
83 elif config.geometry()
is LHCPeriod.Run3:
84 alg.calibrationAndSmearingTool.ESModel =
'es2022_R22_PRE'
85 elif config.geometry()
is LHCPeriod.Run4:
86 logging.warning(
"No ESModel set for Run4, using Run 3 model instead")
87 alg.calibrationAndSmearingTool.ESModel =
'es2022_R22_PRE'
89 raise ValueError (f
"Can't set up the ElectronCalibrationConfig with {config.geometry().value}, "
90 "there must be something wrong!")
92 alg.calibrationAndSmearingTool.decorrelationModel = self.decorrelationModel
93 alg.calibrationAndSmearingTool.useFastSim = (
94 0
if self.forceFullSimConfig
95 else int( config.dataType()
is DataType.FastSim ))
96 alg.egammas = config.readName (self.containerName)
97 alg.egammasOut = config.copyName (self.containerName)
98 alg.preselection = config.getPreselection (self.containerName,
'')
104 log = logging.getLogger(
'ElectronCalibrationConfig')
106 if self.forceFullSimConfig:
107 log.warning(
"You are running ElectronCalibrationConfig forcing full sim config")
108 log.warning(
" This is only intended to be used for testing purposes")
110 if config.isPhyslite() :
111 config.setSourceName (self.containerName,
"AnalysisElectrons")
113 config.setSourceName (self.containerName,
"Electrons")
116 if config.wantCopy (self.containerName) :
117 alg = config.createAlgorithm(
'CP::AsgShallowCopyAlg',
'ElectronShallowCopyAlg' + self.postfix )
118 alg.input = config.readName (self.containerName)
119 alg.output = config.copyName (self.containerName)
123 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronEtaCutAlg' + self.postfix )
124 alg.selectionDecoration =
'selectEta' + self.postfix +
',as_bits'
125 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
126 alg.selectionTool.maxEta = self.maxEta
128 alg.selectionTool.etaGapLow = 1.37
129 alg.selectionTool.etaGapHigh = 1.52
130 alg.selectionTool.useClusterEta =
True
131 alg.particles = config.readName (self.containerName)
132 alg.preselection = config.getPreselection (self.containerName,
'')
133 config.addSelection (self.containerName,
'', alg.selectionDecoration)
136 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronObjectQualityAlg' + self.postfix )
137 alg.selectionDecoration =
'goodOQ' + self.postfix +
',as_bits'
138 config.addPrivateTool(
'selectionTool',
'CP::EgammaIsGoodOQSelectionTool' )
139 alg.selectionTool.Mask = xAOD.EgammaParameters.BADCLUSELECTRON
140 alg.particles = config.readName (self.containerName)
141 alg.preselection = config.getPreselection (self.containerName,
'')
142 config.addSelection (self.containerName,
'', alg.selectionDecoration)
144 if not self.splitCalibrationAndSmearing :
147 if config.isPhyslite()
and not self.recalibratePhyslite :
148 alg.skipNominal =
True
169 alg.noToolSystematics =
True
171 alg.calibrationAndSmearingTool.doSmearing =
False
176 alg.calibrationAndSmearingTool.doScaleCorrection =
False
177 alg.calibrationAndSmearingTool.useMVACalibration =
False
181 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronPtCutAlg' + self.postfix )
182 alg.selectionDecoration =
'selectPt' + self.postfix +
',as_bits'
183 config.addPrivateTool(
'selectionTool',
'CP::AsgPtEtaSelectionTool' )
184 alg.selectionTool.minPt = self.minPt
185 alg.particles = config.readName (self.containerName)
186 alg.preselection = config.getPreselection (self.containerName,
'')
187 config.addSelection (self.containerName,
'', alg.selectionDecoration,
191 if self.isolationCorrection:
192 alg = config.createAlgorithm(
'CP::EgammaIsolationCorrectionAlg',
193 'ElectronIsolationCorrectionAlg' + self.postfix )
194 config.addPrivateTool(
'isolationCorrectionTool',
195 'CP::IsolationCorrectionTool' )
196 alg.isolationCorrectionTool.IsMC = config.dataType()
is not DataType.Data
197 alg.isolationCorrectionTool.AFII_corr = (
198 0
if self.forceFullSimConfig
199 else config.dataType()
is DataType.FastSim)
200 alg.egammas = config.readName (self.containerName)
201 alg.egammasOut = config.copyName (self.containerName)
202 alg.preselection = config.getPreselection (self.containerName,
'')
205 alg = config.createAlgorithm(
'CP::AsgEnergyDecoratorAlg',
'EnergyDecorator' + self.containerName + self.postfix )
206 alg.particles = config.readName(self.containerName)
208 config.addOutputVar (self.containerName,
'pt',
'pt')
209 config.addOutputVar (self.containerName,
'eta',
'eta', noSys=
True)
210 config.addOutputVar (self.containerName,
'phi',
'phi', noSys=
True)
211 config.addOutputVar (self.containerName,
'e_%SYS%',
'e')
212 config.addOutputVar (self.containerName,
'charge',
'charge', noSys=
True)
215 if self.decorateTruth
and config.dataType()
is not DataType.Data:
216 config.addOutputVar (self.containerName,
"truthType",
"truth_type", noSys=
True)
217 config.addOutputVar (self.containerName,
"truthOrigin",
"truth_origin", noSys=
True)
219 config.addOutputVar (self.containerName,
"firstEgMotherPdgId",
"truth_firstEgMotherPdgId", noSys=
True)
220 config.addOutputVar (self.containerName,
"firstEgMotherTruthOrigin",
"truth_firstEgMotherTruthOrigin", noSys=
True)
221 config.addOutputVar (self.containerName,
"firstEgMotherTruthType",
"truth_firstEgMotherTruthType", noSys=
True)
225 """the ConfigBlock for the electron working point
227 This may at some point be split into multiple blocks (29 Aug 22)."""
229 def __init__ (self, containerName='', selectionName='') :
230 super (ElectronWorkingPointConfig, self).__init__ ()
231 self.addOption (
'containerName', containerName, type=str,
233 info=
"the name of the input container.")
234 self.addOption (
'selectionName', selectionName, type=str,
236 info=
"the name of the electron selection to define (e.g. tight or "
238 self.addOption (
'postfix',
None, type=str,
239 info=
"a postfix to apply to decorations and algorithm names. "
240 "Typically not needed here as selectionName is used internally.")
241 self.addOption (
'trackSelection',
True, type=bool,
242 info=
"whether or not to set up an instance of "
243 "CP::AsgLeptonTrackSelectionAlg, with the recommended d_0 and "
244 "z_0 sin(theta) cuts. The default is True.")
245 self.addOption (
'maxD0Significance', 5, type=float,
246 info=
"maximum d0 significance used for the trackSelection"
248 self.addOption (
'maxDeltaZ0SinTheta', 0.5, type=float,
249 info=
"maximum z0sinTheta in mm used for the trackSelection"
250 "The default is 0.5 mm")
251 self.addOption (
'writeTrackD0Z0',
False, type = bool,
252 info=
"save the d0 significance and z0sinTheta variables so they can be written out")
253 self.addOption (
'identificationWP',
None, type=str,
254 info=
"the ID WP (string) to use. Supported ID WPs: TightLH, "
255 "MediumLH, LooseBLayerLH, TightDNN, MediumDNN, LooseDNN, "
256 "TightDNNnoCF, MediumDNNnoCF, VeryLooseDNNnoCF97.")
257 self.addOption (
'isolationWP',
None, type=str,
258 info=
"the isolation WP (string) to use. Supported isolation WPs: "
259 "HighPtCaloOnly, Loose_VarRad, Tight_VarRad, TightTrackOnly_"
260 "VarRad, TightTrackOnly_FixedRad, NonIso.")
261 self.addOption (
'addSelectionToPreselection',
True, type=bool,
262 info=
"whether to retain only electrons satisfying the working point "
263 "requirements. The default is True.")
264 self.addOption (
'closeByCorrection',
False, type=bool,
265 info=
"whether to use close-by-corrected isolation working points")
266 self.addOption (
'recomputeID',
False, type=bool,
267 info=
"whether to rerun the ID LH/DNN. The default is False, i.e. to use "
269 self.addOption (
'chargeIDSelectionRun2',
False, type=bool,
270 info=
"whether to run the ECIDS tool. Only available for run 2. "
271 "The default is False.")
272 self.addOption (
'recomputeChargeID',
False, type=bool,
273 info=
"whether to rerun the ECIDS. The default is False, i.e. to use "
275 self.addOption (
'doFSRSelection',
False, type=bool,
276 info=
"whether to accept additional electrons close to muons for "
277 "the purpose of FSR corrections to these muons. Expert feature "
278 "requested by the H4l analysis running on PHYSLITE. "
279 "The default is False.")
280 self.addOption (
'noEffSF',
False, type=bool,
281 info=
"disables the calculation of efficiencies and scale factors. "
282 "Experimental! only useful to test a new WP for which scale "
283 "factors are not available. The default is False.")
284 self.addOption (
'forceFullSimConfig',
False, type=bool,
285 info=
"whether to force the tool to use the configuration meant for "
286 "full simulation samples. Only for testing purposes. "
287 "The default is False.")
288 self.addOption (
'correlationModelId',
'SIMPLIFIED', type=str,
289 info=
"the correlation model (string) to use for ID scale factors "
290 "Supported models: SIMPLIFIED (default), FULL, TOTAL, TOYS")
291 self.addOption (
'correlationModelIso',
'SIMPLIFIED', type=str,
292 info=
"the correlation model (string) to use for isolation scale factors "
293 "Supported models: SIMPLIFIED (default), FULL, TOTAL, TOYS")
294 self.addOption (
'correlationModelReco',
'SIMPLIFIED', type=str,
295 info=
"the correlation model (string) to use for reconstruction scale factors "
296 "Supported models: SIMPLIFIED (default), FULL, TOTAL, TOYS")
301 log = logging.getLogger(
'ElectronWorkingPointConfig')
303 if self.forceFullSimConfig:
304 log.warning(
"You are running ElectronWorkingPointConfig forcing full sim config")
305 log.warning(
"This is only intended to be used for testing purposes")
307 selectionPostfix = self.selectionName
308 if selectionPostfix !=
'' and selectionPostfix[0] !=
'_' :
309 selectionPostfix =
'_' + selectionPostfix
312 if config.geometry()
is LHCPeriod.Run1:
313 raise ValueError (
"Can't set up the ElectronWorkingPointConfig with %s, there must be something wrong!" % config.geometry().value)
315 postfix = self.postfix
317 postfix = self.selectionName
318 if postfix !=
'' and postfix[0] !=
'_' :
319 postfix =
'_' + postfix
322 if self.writeTrackD0Z0
or self.trackSelection :
323 alg = config.createAlgorithm(
'CP::AsgLeptonTrackSelectionAlg',
324 'ElectronTrackSelectionAlg' + postfix )
325 alg.selectionDecoration =
'trackSelection' + postfix +
',as_bits'
326 alg.maxD0Significance = self.maxD0Significance
327 alg.maxDeltaZ0SinTheta = self.maxDeltaZ0SinTheta
328 alg.decorateTTVAVars = self.writeTrackD0Z0
329 alg.particles = config.readName (self.containerName)
330 alg.preselection = config.getPreselection (self.containerName,
'')
331 if self.trackSelection :
332 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
333 preselection=self.addSelectionToPreselection)
334 if self.writeTrackD0Z0 :
335 alg.d0sigDecoration =
'd0sig' + postfix
336 alg.z0sinthetaDecoration =
'z0sintheta' + postfix
337 config.addOutputVar (self.containerName, alg.d0sigDecoration, alg.d0sigDecoration,noSys=
True)
338 config.addOutputVar (self.containerName, alg.z0sinthetaDecoration, alg.z0sinthetaDecoration,noSys=
True)
340 if 'LH' in self.identificationWP:
343 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronLikelihoodAlg' + postfix )
344 alg.selectionDecoration =
'selectLikelihood' + selectionPostfix +
',as_char'
347 config.addPrivateTool(
'selectionTool',
'AsgElectronLikelihoodTool' )
348 alg.selectionTool.primaryVertexContainer =
'PrimaryVertices'
351 if config.geometry() >= LHCPeriod.Run3:
352 alg.selectionTool.WorkingPoint = self.identificationWP.
replace(
"BLayer",
"BL") +
'Electron'
353 elif config.geometry()
is LHCPeriod.Run2:
354 alg.selectionTool.WorkingPoint = self.identificationWP.
replace(
"BLayer",
"BL") +
'Electron_Run2'
357 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
358 dfFlag =
"DFCommonElectronsLH" + self.identificationWP.
split(
'LH')[0]
359 dfFlag = dfFlag.replace(
"BLayer",
"BL")
360 alg.selectionTool.selectionFlags = [dfFlag]
361 elif 'SiHit' in self.identificationWP:
363 algVeto = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronLikelihoodAlgVeto' + postfix +
'Veto')
364 algVeto.selectionDecoration =
'selectLikelihoodVeto' + postfix +
',as_char'
365 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
366 algVeto.selectionTool.selectionFlags = [
"DFCommonElectronsLHLoose"]
367 algVeto.selectionTool.invertFlags = [
True]
368 algVeto.particles = config.readName (self.containerName)
369 algVeto.preselection = config.getPreselection (self.containerName, self.selectionName)
371 config.addSelection (self.containerName, self.selectionName, algVeto.selectionDecoration,
372 preselection=self.addSelectionToPreselection)
375 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronLikelihoodAlg' + postfix )
376 alg.selectionDecoration =
'selectSiHit' + selectionPostfix +
',as_char'
378 config.addPrivateTool(
'selectionTool',
'CP::AsgMaskSelectionTool' )
379 dfVar =
"DFCommonElectronsLHLooseBLIsEMValue"
380 alg.selectionTool.selectionVars = [dfVar]
381 mask =
int( 0 | 0x1 << 1 | 0x1 << 2)
382 alg.selectionTool.selectionMasks = [mask]
383 elif 'DNN' in self.identificationWP:
384 if self.chargeIDSelectionRun2:
385 raise ValueError(
'DNN is not intended to be used with '
386 '`chargeIDSelectionRun2` option as there are '
387 'DNN WPs containing charge flip rejection.')
389 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
'ElectronDNNAlg' + postfix )
390 alg.selectionDecoration =
'selectDNN' + selectionPostfix +
',as_char'
393 config.addPrivateTool(
'selectionTool',
'AsgElectronSelectorTool' )
395 if config.geometry()
is LHCPeriod.Run3:
396 raise ValueError (
"DNN working points are not available for Run 3 yet.")
398 alg.selectionTool.WorkingPoint = self.identificationWP +
'Electron'
401 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
402 dfFlag =
"DFCommonElectronsDNN" + self.identificationWP.
split(
'DNN')[0]
403 alg.selectionTool.selectionFlags = [dfFlag]
405 alg.particles = config.readName (self.containerName)
406 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
407 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
408 preselection=self.addSelectionToPreselection)
411 if 'SiHit' in self.identificationWP:
413 algDec = config.createAlgorithm(
'CP::ElectronSiHitDecAlg',
'ElectronSiHitDecAlg' + postfix )
414 selDec =
'siHitEvtHasLeptonPair' + selectionPostfix +
',as_char'
415 algDec.selectionName = selDec.split(
",")[0]
416 algDec.ElectronContainer = config.readName (self.containerName)
418 algDec.RequireTwoLeptons =
True
419 config.addSelection (self.containerName, self.selectionName, selDec,
420 preselection=self.addSelectionToPreselection)
423 if self.doFSRSelection :
425 wpFlag = alg.selectionDecoration.split(
",")[0]
426 alg = config.createAlgorithm(
'CP::EgammaFSRForMuonsCollectorAlg',
'EgammaFSRForMuonsCollectorAlg' + postfix )
427 alg.selectionDecoration = wpFlag
428 alg.ElectronOrPhotonContKey = config.readName (self.containerName)
432 if 'SiHit' in self.identificationWP:
436 if self.isolationWP !=
'NonIso' :
437 alg = config.createAlgorithm(
'CP::EgammaIsolationSelectionAlg',
438 'ElectronIsolationSelectionAlg' + postfix )
439 alg.selectionDecoration =
'isolated' + selectionPostfix +
',as_char'
440 config.addPrivateTool(
'selectionTool',
'CP::IsolationSelectionTool' )
441 alg.selectionTool.ElectronWP = self.isolationWP
442 if self.closeByCorrection:
443 alg.selectionTool.IsoDecSuffix =
"CloseByCorr"
444 alg.egammas = config.readName (self.containerName)
445 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
446 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
447 preselection=self.addSelectionToPreselection)
449 if self.chargeIDSelectionRun2
and config.geometry() >= LHCPeriod.Run3:
450 log.warning(
"ECIDS is only available for Run 2 and will not have effect in run 3.")
453 if self.chargeIDSelectionRun2
and config.geometry() < LHCPeriod.Run3:
454 alg = config.createAlgorithm(
'CP::AsgSelectionAlg',
455 'ElectronChargeIDSelectionAlg' + postfix )
456 alg.selectionDecoration =
'chargeID' + selectionPostfix +
',as_char'
457 if self.recomputeChargeID:
459 config.addPrivateTool(
'selectionTool',
460 'AsgElectronChargeIDSelectorTool' )
461 alg.selectionTool.TrainingFile = \
462 'ElectronPhotonSelectorTools/ChargeID/ECIDS_20180731rel21Summer2018.root'
463 alg.selectionTool.WorkingPoint =
'Loose'
464 alg.selectionTool.CutOnBDT = -0.337671
467 config.addPrivateTool(
'selectionTool',
'CP::AsgFlagSelectionTool' )
468 alg.selectionTool.selectionFlags = [
"DFCommonElectronsECIDS"]
470 alg.particles = config.readName (self.containerName)
471 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
472 config.addSelection (self.containerName, self.selectionName, alg.selectionDecoration,
473 preselection=self.addSelectionToPreselection)
475 correlationModels = [
"SIMPLIFIED",
"FULL",
"TOTAL",
"TOYS"]
478 if config.dataType()
is not DataType.Data
and not self.noEffSF:
480 if config.geometry()
is LHCPeriod.Run2:
481 raise ValueError(
'Run 2 does not yet have efficiency correction, '
482 'please disable it by setting `noEffSF` to True.')
483 if 'DNN' in self.identificationWP:
484 raise ValueError(
'DNN does not yet have efficiency correction, '
485 'please disable it by setting `noEffSF` to True.')
487 alg = config.createAlgorithm(
'CP::ElectronEfficiencyCorrectionAlg',
488 'ElectronEfficiencyCorrectionAlgReco' + postfix )
489 config.addPrivateTool(
'efficiencyCorrectionTool',
490 'AsgElectronEfficiencyCorrectionTool' )
491 alg.scaleFactorDecoration =
'el_reco_effSF' + selectionPostfix +
'_%SYS%'
492 alg.efficiencyCorrectionTool.RecoKey =
"Reconstruction"
493 if self.correlationModelReco
not in correlationModels:
494 raise ValueError(
'Invalid correlation model for reconstruction efficiency, '
495 f
'has to be one of: {", ".join(correlationModels)}')
496 if config.geometry() >= LHCPeriod.Run3
and self.correlationModelReco !=
"TOTAL":
497 log.warning(
"Only TOTAL correlation model is currently supported "
498 "for reconstruction efficiency correction in Run 3.")
499 alg.efficiencyCorrectionTool.CorrelationModel =
"TOTAL"
501 alg.efficiencyCorrectionTool.CorrelationModel = self.correlationModelReco
502 if config.dataType()
is DataType.FastSim:
503 alg.efficiencyCorrectionTool.ForceDataType = (
504 PATCore.ParticleDataType.Full
if self.forceFullSimConfig
505 else PATCore.ParticleDataType.Fast)
506 elif config.dataType()
is DataType.FullSim:
507 alg.efficiencyCorrectionTool.ForceDataType = \
508 PATCore.ParticleDataType.Full
509 alg.outOfValidity = 2
510 alg.outOfValidityDeco =
'el_reco_bad_eff' + selectionPostfix
511 alg.electrons = config.readName (self.containerName)
512 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
513 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
'reco_effSF' + postfix)
516 if config.dataType()
is not DataType.Data
and not self.noEffSF:
517 alg = config.createAlgorithm(
'CP::ElectronEfficiencyCorrectionAlg',
518 'ElectronEfficiencyCorrectionAlgID' + postfix )
519 config.addPrivateTool(
'efficiencyCorrectionTool',
520 'AsgElectronEfficiencyCorrectionTool' )
521 alg.scaleFactorDecoration =
'el_id_effSF' + selectionPostfix +
'_%SYS%'
522 alg.efficiencyCorrectionTool.IdKey = self.identificationWP.
replace(
"LH",
"")
523 if self.correlationModelId
not in correlationModels:
524 raise ValueError(
'Invalid correlation model for identification efficiency, '
525 f
'has to be one of: {", ".join(correlationModels)}')
526 alg.efficiencyCorrectionTool.CorrelationModel = self.correlationModelId
527 if config.dataType()
is DataType.FastSim:
528 alg.efficiencyCorrectionTool.ForceDataType = (
529 PATCore.ParticleDataType.Full
if self.forceFullSimConfig
530 else PATCore.ParticleDataType.Fast)
531 elif config.dataType()
is DataType.FullSim:
532 alg.efficiencyCorrectionTool.ForceDataType = \
533 PATCore.ParticleDataType.Full
534 alg.outOfValidity = 2
535 alg.outOfValidityDeco =
'el_id_bad_eff' + selectionPostfix
536 alg.electrons = config.readName (self.containerName)
537 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
538 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
'id_effSF' + postfix)
541 if config.dataType()
is not DataType.Data
and self.isolationWP !=
'NonIso' and not self.noEffSF:
542 alg = config.createAlgorithm(
'CP::ElectronEfficiencyCorrectionAlg',
543 'ElectronEfficiencyCorrectionAlgIsol' + postfix )
544 config.addPrivateTool(
'efficiencyCorrectionTool',
545 'AsgElectronEfficiencyCorrectionTool' )
546 alg.scaleFactorDecoration =
'el_isol_effSF' + selectionPostfix +
'_%SYS%'
547 alg.efficiencyCorrectionTool.IdKey = self.identificationWP.
replace(
"LH",
"")
548 alg.efficiencyCorrectionTool.IsoKey = self.isolationWP
549 if self.correlationModelIso
not in correlationModels:
550 raise ValueError(
'Invalid correlation model for isolation efficiency, '
551 f
'has to be one of: {", ".join(correlationModels)}')
552 if config.geometry() >= LHCPeriod.Run3:
553 log.warning(
"Only TOTAL correlation model is currently supported "
554 "for isolation efficiency correction in Run 3.")
555 alg.efficiencyCorrectionTool.CorrelationModel =
"TOTAL"
557 alg.efficiencyCorrectionTool.CorrelationModel = self.correlationModelIso
558 if config.dataType()
is DataType.FastSim:
559 alg.efficiencyCorrectionTool.ForceDataType = (
560 PATCore.ParticleDataType.Full
if self.forceFullSimConfig
561 else PATCore.ParticleDataType.Fast)
562 elif config.dataType()
is DataType.FullSim:
563 alg.efficiencyCorrectionTool.ForceDataType = \
564 PATCore.ParticleDataType.Full
565 alg.outOfValidity = 2
566 alg.outOfValidityDeco =
'el_isol_bad_eff' + selectionPostfix
567 alg.electrons = config.readName (self.containerName)
568 alg.preselection = config.getPreselection (self.containerName, self.selectionName)
569 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
'isol_effSF' + postfix)
573 if self.chargeIDSelectionRun2:
581 isolationCorrection = None,
582 forceFullSimConfig = None):
583 """Create electron calibration configuration blocks
585 This makes all the algorithms that need to be run first befor
586 all working point specific algorithms and that can be shared
587 between the working points.
590 postfix -- a postfix to apply to decorations and algorithm
591 names. this is mostly used/needed when using this
592 sequence with multiple working points to ensure all
594 isolationCorrection -- Whether or not to perform isolation correction
595 forceFullSimConfig -- imposes full-sim config for FastSim for testing
598 config = ElectronCalibrationConfig (containerName)
599 config.setOptionValue (
'crackVeto', crackVeto)
600 config.setOptionValue (
'isolationCorrection', isolationCorrection)
601 config.setOptionValue (
'forceFullSimConfig', forceFullSimConfig)
611 chargeIDSelectionRun2 = None,
612 recomputeChargeID = None,
614 forceFullSimConfig = None):
615 """Create electron analysis configuration blocks
618 workingPoint -- The working point to use
619 selectionName -- a postfix to apply to decorations and algorithm
620 names. this is mostly used/needed when using this
621 sequence with multiple working points to ensure all
623 recomputeID -- Whether to rerun the LH/DNN ID. If not, use derivation flags
624 chargeIDSelectionRun2 -- Whether or not to perform charge ID/flip selection
625 recomputeChargeID -- Whether to rerun the ECIDS. If not, use derivation flags
626 noEffSF -- Disables the calculation of efficiencies and scale factors
627 forceFullSimConfig -- imposes full-sim config for FastSim for testing
631 config = ElectronWorkingPointConfig (containerName, selectionName)
632 if workingPoint
is not None :
633 splitWP = workingPoint.split (
'.')
634 if len (splitWP) != 2 :
635 raise ValueError (
'working point should be of format "likelihood.isolation", not ' + workingPoint)
636 config.setOptionValue (
'identificationWP', splitWP[0])
637 config.setOptionValue (
'isolationWP', splitWP[1])
638 config.setOptionValue (
'recomputeID', recomputeID)
639 config.setOptionValue (
'chargeIDSelectionRun2', chargeIDSelectionRun2)
640 config.setOptionValue (
'recomputeChargeID', recomputeChargeID)
641 config.setOptionValue (
'noEffSF', noEffSF)
642 config.setOptionValue (
'forceFullSimConfig', forceFullSimConfig)
649 super (ElectronTriggerAnalysisSFBlock, self).__init__ ()
651 self.addOption (
'triggerChainsPerYear', {}, type=
None,
652 info=
"a dictionary with key (string) the year and value (list of "
653 "strings) the trigger chains. The default is {} (empty dictionary).")
654 self.addOption (
'electronID',
'', type=str,
655 info=
"the electron ID WP (string) to use.")
656 self.addOption (
'electronIsol',
'', type=str,
657 info=
"the electron isolation WP (string) to use.")
658 self.addOption (
'saveEff',
False, type=bool,
659 info=
"define whether we decorate also the trigger scale efficiency "
660 "The default is false.")
661 self.addOption (
'containerName',
'', type=str,
662 info=
"the input electron container, with a possible selection, in "
663 "the format container or container.selection.")
667 if config.dataType()
is not DataType.Data:
674 version = (
"2015_2018/rel21.2/Precision_Summer2020_v1"
675 if config.geometry()
is LHCPeriod.Run2
else
676 "2015_2025/rel22.2/2022_Summer_Prerecom_v1")
682 if config.campaign()
is Campaign.MC20a:
684 elif config.campaign()
is Campaign.MC20d:
686 elif config.campaign()
is Campaign.MC20e:
688 elif config.campaign()
in [Campaign.MC21a, Campaign.MC23a]:
690 elif config.campaign()
in [Campaign.MC23c, Campaign.MC23d]:
695 triggerChains = self.triggerChainsPerYear.
get(
int(year), self.triggerChainsPerYear.
get(
str(year), []))
696 for chain
in triggerChains:
697 chain = chain.replace(
"HLT_",
"").
replace(
" || ",
"_OR_")
698 legs = triggerDict[chain]
700 if chain[0]==
'e' and chain[1].isdigit:
701 triggerConfigs[chain] = mapKeysDict[year +
'_' + chain]
704 if leg[0]==
'e' and leg[1].isdigit:
705 triggerConfigs[leg] = mapKeysDict[year +
'_' + leg]
707 decorations = [
'EffSF']
709 decorations += [
'Eff']
711 for trig, conf
in triggerConfigs.items():
712 for deco
in decorations:
713 alg = config.createAlgorithm(
'CP::ElectronEfficiencyCorrectionAlg',
714 'EleTrigEfficiencyCorrectionsAlg' + deco +
716 config.addPrivateTool(
'efficiencyCorrectionTool',
717 'AsgElectronEfficiencyCorrectionTool' )
720 alg.efficiencyCorrectionTool.MapFilePath =
"ElectronEfficiencyCorrection/" + version +
"/map4.txt"
721 alg.efficiencyCorrectionTool.IdKey = self.electronID.
replace(
"LH",
"")
722 alg.efficiencyCorrectionTool.IsoKey = self.electronIsol
723 alg.efficiencyCorrectionTool.TriggerKey = (
724 (
"Eff_" if "SF" not in deco
else "") + conf[0])
725 alg.efficiencyCorrectionTool.CorrelationModel =
"TOTAL"
726 alg.efficiencyCorrectionTool.ForceDataType = \
727 PATCore.ParticleDataType.Full
729 alg.scaleFactorDecoration = (
730 'el_trig' + deco +
'_' + trig +
'_%SYS%')
731 alg.outOfValidity = 2
732 alg.outOfValidityDeco =
'bad_eff_eletrig' + deco +
'_' + trig
733 alg.electrons = config.readName (self.containerName)
734 alg.preselection = config.getPreselection (self.containerName,
'')
735 config.addOutputVar (self.containerName, alg.scaleFactorDecoration,
'trig' + deco +
'_' + trig)