ATLAS Offline Software
Loading...
Searching...
No Matches
Electrons.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// This source file implements all of the functions related to Electrons
6// in the SUSYObjDef_xAOD class
7
8// Local include(s):
10
14
25
28//disable #include "IsolationSelection/IIsolationLowPtPLVTool.h"
29
31
32//disable #include "PATCore/TResult.h"
33
34// For getting the beam spot information
36
37#ifndef XAOD_STANDALONE // For now metadata is Athena-only
39#endif
40
41namespace ST {
42
43 const static SG::Decorator<char> dec_passSignalID("passSignalID");
44 const static SG::ConstAccessor<char> acc_passSignalID("passSignalID");
45
46 const static SG::Decorator<char> dec_passChID("passChID");
47 const static SG::ConstAccessor<char> acc_passChID("passChID");
48 const static SG::Decorator<double> dec_ecisBDT("ecisBDT");
49
50 const static SG::Decorator<float> dec_sfChIDEff("chargeIDEffiSF"); //tools' default
51 const static SG::ConstAccessor<float> acc_sfChIDEff("chargeIDEffiSF"); //tools' default
52
53 const static SG::Decorator<float> dec_z0sinTheta("z0sinTheta");
54 const static SG::Decorator<float> dec_d0sig("d0sig");
55 const static SG::Decorator<char> dec_isLRT("isLRT");
56 const static SG::ConstAccessor<char> acc_isLRT("isLRT");
57
58 const static SG::ConstAccessor<char> acc_passECIDS("DFCommonElectronsECIDS"); // Loose 97% WP
59
60
61StatusCode SUSYObjDef_xAOD::MergeElectrons(const xAOD::ElectronContainer & electrons, xAOD::ElectronContainer* outputCol, const std::set<const xAOD::Electron *> &ElectronsToRemove) const{
62
63 if (electrons.empty()) return StatusCode::SUCCESS;
64 for (const xAOD::Electron* electron: electrons) {
65 if (ElectronsToRemove.find(electron) != ElectronsToRemove.end()){
66 ATH_MSG_DEBUG( "Removing electron from output collection (isLRT?) : ("<< static_cast<int>(acc_isLRT(*electron)) << ")" );
67 ATH_MSG_DEBUG( "ELECTRON cl eta: " << electron->caloCluster()->eta());
68 ATH_MSG_DEBUG( "ELECTRON cl phi: " << electron->caloCluster()->phi());
69 continue;
70 // add electron into output
71 } else {
72 ATH_MSG_DEBUG( "Adding electron to output collection (isLRT?) : (" << static_cast<int>(acc_isLRT(*electron)) << ")" );
73 ATH_MSG_DEBUG( "ELECTRON cl eta: " << electron->caloCluster()->eta());
74 ATH_MSG_DEBUG( "ELECTRON cl phi: " << electron->caloCluster()->phi());
75 auto newElectron = new xAOD::Electron(*electron);
76
77 if ( getOriginalObject(*electron) != nullptr ) {
79 } else {
80 setOriginalObjectLink(*electron, *newElectron);
81 }
82
83 outputCol->push_back(newElectron);
84 }
85 }
86 return StatusCode::SUCCESS;
87}
88
89
91 for (const xAOD::Electron *electron: *inElectrons){
92 const xAOD::TrackParticle* idtrack = electron->trackParticle();
93
94 // Save electron if the id track passes the LRT filter
95 if ( acc_lrtFilter.isAvailable(*idtrack) )
96 {
97 if ( static_cast<int>(acc_lrtFilter(*idtrack) ) ){
98 std::unique_ptr<xAOD::Electron> copyElectron = std::make_unique<xAOD::Electron>(*electron);
99
100 // transfer original electron link
101
102 setOriginalObjectLink(*electron, *copyElectron);
103 copy->push_back( std::move(copyElectron) );
104 }
105 }
106 else // Keep electron if flag is not available
107 {
108 std::unique_ptr<xAOD::Electron> copyElectron = std::make_unique<xAOD::Electron>(*electron);
109
110 setOriginalObjectLink(*electron, *copyElectron);
111 copy->push_back( std::move(copyElectron) );
112 }
113 }
114 return StatusCode::SUCCESS;
115}
116
117
118StatusCode SUSYObjDef_xAOD::GetElectrons(xAOD::ElectronContainer*& copy, xAOD::ShallowAuxContainer*& copyaux, bool recordSG, const std::string& elekey, const std::string& lrtelekey, const xAOD::ElectronContainer* containerToBeCopied)
119{
120 if (!m_tool_init) {
121 ATH_MSG_ERROR("SUSYTools was not initialized!!");
122 return StatusCode::FAILURE;
123 }
124
125 // Initializing prompt/LRT OR procedure
126 auto outputCol = std::make_unique<xAOD::ElectronContainer>();
127 std::unique_ptr<xAOD::ElectronAuxContainer> outputAuxCol;
128 outputAuxCol = std::make_unique<xAOD::ElectronAuxContainer>();
129 outputCol->setStore(outputAuxCol.get());
130 ATH_CHECK( m_outElectronLocation.initialize() );
131
132 if (bool(m_eleLRT) && !lrtelekey.empty() && evtStore()->contains<xAOD::ElectronContainer>(lrtelekey)){
133 ATH_MSG_DEBUG("Applying prompt/LRT electron OR procedure");
134
135 // First identify if merged container has already been made (for instances where GetElectrons() is called more than once)
136 if (evtStore()->contains<xAOD::ElectronContainer>("StdWithLRTElectrons")) {
137 ATH_MSG_DEBUG("Merged prompt/LRT container already created in TStore");
138 } else {
139 ATH_MSG_DEBUG("Creating merged prompt/LRT container in TStore");
140
141 // Retrieve prompt and LRT electrons from TStore
142 ATH_CHECK( evtStore()->retrieve(prompt_electrons, elekey) );
143 ATH_CHECK( evtStore()->retrieve(lrt_electrons, lrtelekey) );
144
145 // Remove LRT electrons as flagged by filter for uncertainty
146 auto filtered_electrons = std::make_unique<xAOD::ElectronContainer>();
147 std::unique_ptr<xAOD::ElectronAuxContainer> filtered_electrons_aux = std::make_unique<xAOD::ElectronAuxContainer>();
148 filtered_electrons->setStore(filtered_electrons_aux.get());
149 ATH_CHECK(prepareLRTElectrons(lrt_electrons, filtered_electrons.get()));
150
151 // Check overlap between prompt and LRT collections
152 std::set<const xAOD::Electron *> ElectronsToRemove;
153 m_elecLRTORTool->checkOverlap(*prompt_electrons, *filtered_electrons, ElectronsToRemove);
154
155 // Decorate electrons with prompt/LRT
156 for (const xAOD::Electron* el : *prompt_electrons) dec_isLRT(*el) = 0;
157 for (const xAOD::Electron* el : *filtered_electrons) dec_isLRT(*el) = 1;
158
159 // Create merged StdWithLRTElectrons container
160 outputCol->reserve(prompt_electrons->size() + filtered_electrons->size());
161 ATH_CHECK(MergeElectrons(*prompt_electrons, outputCol.get(), ElectronsToRemove ));
162 ATH_CHECK(MergeElectrons(*filtered_electrons, outputCol.get(), ElectronsToRemove ));
163
164 // Save merged StdWithLRTElectrons container to TStore
165 ATH_CHECK(evtStore()->record(std::move(outputCol), m_outElectronLocation.key()));
166 ATH_CHECK(evtStore()->record(std::move(outputAuxCol), m_outElectronLocation.key() + "Aux.") );
167 }
168 } else if (!lrtelekey.empty()) {
169 if(evtStore()->contains<xAOD::ElectronContainer>(lrtelekey) == false && bool(m_eleLRT) == true) ATH_MSG_WARNING("prompt/LRT OR procedure attempted but " << lrtelekey << " not in ROOT file, check config!");
170 ATH_MSG_DEBUG("Not applying prompt/LRT electron OR procedure");
171 }
172
173 if (m_isPHYSLITE && elekey.find("AnalysisElectrons")==std::string::npos){
174 ATH_MSG_ERROR("You are running on PHYSLITE derivation. Please change the Electrons container to 'AnalysisElectrons'");
175 return StatusCode::FAILURE;
176 }
177
178 const xAOD::ElectronContainer* electrons = nullptr;
179 if (bool(m_eleLRT) && evtStore()->contains<xAOD::ElectronContainer>(lrtelekey)){
180 ATH_MSG_DEBUG("Using container: " << m_outElectronLocation.key());
181 ATH_CHECK( evtStore()->retrieve(electrons, m_outElectronLocation.key()));
182 }
183 else {
184 if (copy==nullptr) { // empty container provided
185 ATH_MSG_DEBUG("Empty container provided");
186 if (containerToBeCopied != nullptr) {
187 ATH_MSG_DEBUG("Containter to be copied not nullptr");
188 electrons = containerToBeCopied;
189 }
190 else {
191 ATH_MSG_DEBUG("Getting Electrons collection");
192 ATH_CHECK( evtStore()->retrieve(electrons, elekey) );
193 }
194 }
195 }
196
197 if (copy==nullptr) { // empty container provided
198 std::pair<xAOD::ElectronContainer*, xAOD::ShallowAuxContainer*> shallowcopy = xAOD::shallowCopyContainer(*electrons);
199 copy = shallowcopy.first;
200 copyaux = shallowcopy.second;
201 bool setLinks = xAOD::setOriginalObjectLink(*electrons, *copy);
202 if (!setLinks) {
203 ATH_MSG_WARNING("Failed to set original object links on " << elekey);
204 }
205 } else { // use the user-supplied collection instead
206 ATH_MSG_DEBUG("Not retrieving electron collection, using existing one provided by user");
207 electrons=copy; // this does nothing
208 }
209
210 for (const auto electron : *copy) {
213 }
214
215 if (recordSG) {
216 ATH_CHECK( evtStore()->record(copy, "STCalib" + elekey + m_currentSyst.name()) );
217 ATH_CHECK( evtStore()->record(copyaux, "STCalib" + elekey + m_currentSyst.name() + "Aux.") );
218 }
219 return StatusCode::SUCCESS;
220}
221
222
223StatusCode SUSYObjDef_xAOD::FillElectron(xAOD::Electron& input, float etcut, float etacut) {
224
225 ATH_MSG_VERBOSE( "Starting FillElectron on el with pre-calibration pt=" << input.pt() );
226
227 // According to https://twiki.cern.ch/twiki/bin/view/AtlasProtected/EGammaIdentificationRun2#Electron_identification:
228 // "Please apply the identification to uncalibrated electron object. ID scale factors are to be applied to calibrated objects."
229 dec_baseline(input) = false;
230 dec_selected(input) = 0;
231 dec_signal(input) = false;
232 dec_isol(input) = false;
233 dec_isolHighPt(input) = false;
234 dec_passSignalID(input) = false;
235 dec_passChID(input) = false;
236 dec_ecisBDT(input) = -999.;
237
238 const xAOD::EventInfo* evtInfo = nullptr;
239 ATH_CHECK( evtStore()->retrieve( evtInfo, "EventInfo" ) );
240 const xAOD::Vertex* pv = this->GetPrimVtx();
241 const xAOD::TrackParticle* track = input.trackParticle();
242 if (!track) {
243 ATH_MSG_DEBUG("No primary track particle for this electron. Skipping.");
244 return StatusCode::SUCCESS;
245 }
246 double primvertex_z = pv ? pv->z() : 0;
247 double el_z0 = track->z0() + track->vz() - primvertex_z;
248 dec_z0sinTheta(input) = el_z0 * TMath::Sin(input.p4().Theta());
249 //protect against exception thrown for null or negative d0sig
250 try{
252 }
253 catch(...){
254 float d0sigError = -99.;
255 ATH_MSG_WARNING("FillElectron : Exception catched from d0significance() calculation. Setting dummy decoration d0sig=" << d0sigError );
256 dec_d0sig(input) = d0sigError;
257 }
258
259 // don't bother calibrating or computing WP
260 if ( input.pt() < 4e3 ) return StatusCode::SUCCESS;
261 if ( !input.caloCluster() ) { ATH_MSG_WARNING( "FillElectron: no caloCluster found: " << input.caloCluster() ); return StatusCode::SUCCESS; }
262
263 //Check DeadHVCellRemoval
264 bool pass_deadHVTool = m_deadHVTool->accept(&input);
265
266 if (m_debug) {
267 unsigned char el_nPixHits(0), el_nSCTHits(0);
268 input.trackParticle()->summaryValue(el_nPixHits, xAOD::numberOfPixelHits);
269 input.trackParticle()->summaryValue(el_nSCTHits, xAOD::numberOfSCTHits);
270
271 ATH_MSG_INFO( "ELECTRON eta: " << input.eta());
272 ATH_MSG_INFO( "ELECTRON phi: " << input.phi());
273 ATH_MSG_INFO( "ELECTRON cl eta: " << input.caloCluster()->eta());
274 ATH_MSG_INFO( "ELECTRON cl phi: " << input.caloCluster()->phi());
275 ATH_MSG_INFO( "ELECTRON cl e: " << input.caloCluster()->e());
276 ATH_MSG_INFO( "ELECTRON trk eta: " << input.trackParticle()->eta());
277 ATH_MSG_INFO( "ELECTRON trk phi: " << input.trackParticle()->phi());
278 ATH_MSG_INFO( "ELECTRON author: " << input.author());
279 ATH_MSG_INFO( "ELECTRON OQ: " << acc_OQ(input));
280 ATH_MSG_INFO( "ELECTRON nPixHits: " << static_cast<int>(el_nPixHits));
281 ATH_MSG_INFO( "ELECTRON nSCTHits: " << static_cast<int>(el_nSCTHits));
282 ATH_MSG_INFO( "ELECTRON deadHVTools: " << static_cast<bool>(pass_deadHVTool));
283 }
284
285 if (!pass_deadHVTool) return StatusCode::SUCCESS;
286 if (!input.isGoodOQ(xAOD::EgammaParameters::BADCLUSELECTRON)) return StatusCode::SUCCESS;
287
288 if ( m_elecSelLikelihoodBaseline.empty()) {
289 ATH_MSG_ERROR("No baseline electron selector defined!");
290 return StatusCode::FAILURE;
291 }
292
293 bool passBaseID = false;
294 if (m_eleIdExpert) {
295 passBaseID = bool(m_elecSelLikelihoodBaseline->accept(&input));
296 } else {
297 if (m_acc_eleIdBaseline.isAvailable(input)) {
298 passBaseID = m_acc_eleIdBaseline(input);
299 } else {
300 ATH_MSG_VERBOSE ("DFCommonElectronsLHxxx variables are not found. Calculating the ID from LH tool..");
301 passBaseID = bool(m_elecSelLikelihoodBaseline->accept(&input));
302 }
303 }
304
305 if ( !passBaseID && !m_force_noElId ) return StatusCode::SUCCESS;
306
307 //baseline ID decoration for TauEl OR
308 //dec_passBaseID(input) = true;
309
310 // calibrate the electron 4-vector here only if within eta window
311 if (std::abs(input.caloCluster()->etaBE(2)) >= etacut) return StatusCode::SUCCESS;
312
314 if ( std::abs( input.caloCluster()->etaBE(2) ) >1.37 && std::abs( input.caloCluster()->etaBE(2) ) <1.52) {
315 return StatusCode::SUCCESS;
316 }
317 }
318
319 // corrections described in https://twiki.cern.ch/twiki/bin/view/AtlasProtected/EGammaCalibrationRun2
320 if ( m_egammaCalibTool->applyCorrection(input) != CP::CorrectionCode::Ok)
321 ATH_MSG_ERROR( "FillElectron: EgammaCalibTool applyCorrection failed ");
322
323 if (m_isoCorrTool->applyCorrection(input) != CP::CorrectionCode::Ok)
324 ATH_MSG_ERROR("FillElectron: IsolationCorrectionTool applyCorrection failed");
325
326 ATH_MSG_VERBOSE( "FillElectron: post-calibration pt=" << input.pt() );
327
328 if (input.pt() < etcut) return StatusCode::SUCCESS;
329
330 if (m_elebaselinez0>0. && std::abs(acc_z0sinTheta(input))>m_elebaselinez0) return StatusCode::SUCCESS;
331 if (m_elebaselined0sig>0. && std::abs(acc_d0sig(input))>m_elebaselined0sig) return StatusCode::SUCCESS;
332
333 //--- Do baseline isolation check
334 if ( !( m_eleBaselineIso_WP.empty() ) && !( m_isoBaselineTool->accept(input) ) ) return StatusCode::SUCCESS;
335
336 dec_baseline(input) = true;
337 dec_selected(input) = 2;
338 //disable if (!m_eleIso_WP.empty() && m_eleIso_WP.find("PLV")!=std::string::npos) ATH_CHECK( ->augmentPLV(input) );
339 if (!m_eleIso_WP.empty()) dec_isol(input) = bool(m_isoTool->accept(input));
340 if (!m_eleIsoHighPt_WP.empty()) dec_isolHighPt(input) = bool(m_isoHighPtTool->accept(input));
341
342 //ChargeIDSelector
343 if( m_runECIS ){
344 if (acc_passECIDS.isAvailable(input)) {
345 dec_passChID(input) = acc_passECIDS(input); // Loose 97% WP!
346 } else {
347 dec_passChID(input) = bool(m_elecChargeIDSelectorTool->accept(&input));
348 //disable double bdt = m_elecChargeIDSelectorTool->calculate(&input).getResult("bdt");
349 //disable dec_ecisBDT(input) = bdt;
350 }
351 }
352 else{
353 dec_passChID(input) = true;
354 }
355
356 ATH_MSG_VERBOSE( "FillElectron: passed baseline selection" );
357
358 return StatusCode::SUCCESS;
359}
360
361
362bool SUSYObjDef_xAOD::IsSignalElectron(const xAOD::Electron & input, float etcut, float d0sigcut, float z0cut, float etacut) const
363{
364 if (!acc_baseline(input)) return false;
365
366 dec_passSignalID(input) = false;
367
368 if (m_eleIdExpert) {
369 if ( !m_elecSelLikelihood.empty() && m_elecSelLikelihood->accept(&input) ) dec_passSignalID(input) = true;
370 }
371 else {
372 if (m_acc_eleId.isAvailable(input)) {
373 dec_passSignalID(input) = m_acc_eleId(input);
374 } else {
375 ATH_MSG_VERBOSE ("DFCommonElectronsLHxxx variables are not found. Calculating the ID from LH tool..");
376 if ( !m_elecSelLikelihood.empty() && m_elecSelLikelihood->accept(&input) ) dec_passSignalID(input) = true;
377 }
378 }
379
380 //overwrite ID selection if forced by user
381 if(m_force_noElId) dec_passSignalID(input) = true;
382
383 if (!acc_passSignalID(input)) return false;
384
385 if (input.p4().Perp2() <= etcut * etcut || input.p4().Perp2() == 0) return false; // eT cut (might be necessary for leading electron to pass trigger)
386 if ( etacut==DUMMYDEF ){
387 if(std::abs(input.caloCluster()->etaBE(2)) > m_eleEta ) return false;
388 }
389 else if ( std::abs(input.caloCluster()->etaBE(2)) > etacut ) return false;
390
391 if (m_eleCrackVeto){
392 if ( std::abs( input.caloCluster()->etaBE(2) ) >1.37 && std::abs( input.caloCluster()->etaBE(2) ) <1.52) {
393 return false;
394 }
395 }
396
397 if (acc_d0sig(input) != 0) {
398 if (d0sigcut > 0.0 && std::abs(acc_d0sig(input)) > d0sigcut) return false; // transverse IP cut
399 }
400
401 if (z0cut > 0.0 && std::abs(acc_z0sinTheta(input)) > z0cut) return false; // longitudinal IP cut
402
403
404 ATH_MSG_VERBOSE( "IsSignalElectron: " << m_eleId << " " << acc_passSignalID(input) << " d0sig " << acc_d0sig(input) << " z0 sin(theta) " << acc_z0sinTheta(input) );
405
406 if (m_doElIsoSignal) {
407 if ( !( (acc_isol(input) && input.pt()<m_eleIsoHighPtThresh) || (acc_isolHighPt(input) && input.pt()>m_eleIsoHighPtThresh)) ) return false;
408 ATH_MSG_VERBOSE( "IsSignalElectron: passed isolation" );
409 }
410
411 if(m_eleChID_signal && !acc_passChID(input)) return false; //add charge flip check to signal definition
412
413 dec_signal(input) = true;
414
415 ATH_MSG_VERBOSE( "IsSignalElectron: passed selection" );
416 return true;
417}
418
419
421 const bool recoSF,
422 const bool idSF,
423 const bool triggerSF,
424 const bool isoSF,
425 const std::string& trigExpr,
426 const bool ecidsSF,
427 const bool cidSF ) {
428
429 if ((m_eleId == "VeryLooseLLH" || m_eleId == "LooseLLH" || m_eleId == "Loose" || m_eleId == "Medium" || m_eleId == "Tight") && (idSF || triggerSF || isoSF)) {
430 ATH_MSG_ERROR("No signal electron ID or trigger scale factors provided for the selected working point!");
431 ATH_MSG_ERROR("I will now die messily.");
432 }
433
434 //shortcut keys for trigger SF config
435 std::string singleLepStr = "singleLepton";
436 std::string diLepStr = "diLepton";
437 std::string multiLepStr = "multiLepton";
438
439 float sf(1.);
440
441 if (recoSF) {
442 double reco_sf(1.);
443
444 CP::CorrectionCode result = m_elecEfficiencySFTool_reco->getEfficiencyScaleFactor(el, reco_sf);
445 switch (result) {
447 sf *= reco_sf;
448 break;
450 ATH_MSG_ERROR( "Failed to retrieve signal electron reco SF");
451 break;
453 ATH_MSG_VERBOSE( "OutOfValidityRange found for signal electron reco SF");
454 break;
455 default:
456 ATH_MSG_WARNING( "Don't know what to do for signal electron reco SF");
457 }
458 }
459
460 if (idSF) {
461 double id_sf(1.);
462
463 CP::CorrectionCode result = m_elecEfficiencySFTool_id->getEfficiencyScaleFactor(el, id_sf);
464 switch (result) {
466 sf *= id_sf;
467 break;
469 ATH_MSG_ERROR( "Failed to retrieve signal electron id SF");
470 break;
472 ATH_MSG_VERBOSE( "OutOfValidityRange found for signal electron id SF");
473 break;
474 default:
475 ATH_MSG_WARNING( "Don't know what to do for signal electron id SF");
476 }
477 }
478
479 if (triggerSF) {
480
481 std::vector<std::string> trigMChains={};
482 std::string theExpr ("");
483 if(trigExpr==singleLepStr) {
484 if (this->treatAsYear()==2015) trigMChains = m_v_trigs15_cache_singleEle;
485 else if (this->treatAsYear()==2016) trigMChains = m_v_trigs16_cache_singleEle;
486 else if (this->treatAsYear()==2017) trigMChains = m_v_trigs17_cache_singleEle;
487 else if (this->treatAsYear()==2018) trigMChains = m_v_trigs18_cache_singleEle;
488 else if (this->treatAsYear()==2022) trigMChains = m_v_trigs22_cache_singleEle;
489 else if (this->treatAsYear()==2023) trigMChains = m_v_trigs23_cache_singleEle;
490 else trigMChains = m_v_trigs24_cache_singleEle;
492 }
493 else{
494 ATH_MSG_WARNING( "Only single lepton trigger SFs are supported in GetSignalElecSF(). Use GetTriggerGlobalEfficiencySF() for dilepton or multilepton triggers!");
495 }
496
497 //check matching
498 this->TrigMatch({&el}, trigMChains);
499
500 if(!acc_trigmatched(el)){
501 ATH_MSG_DEBUG( "Electron was not matched to trigger " << theExpr << " - scale factor does not apply (year " << this->treatAsYear() << ") Returning 1." );
502 }
503 else{ //is trig-matched electron, go for it!
504 if (trigExpr==multiLepStr || trigExpr==diLepStr) {
505 ATH_MSG_WARNING( "The dilepton or multilepton trigger SFs are not supported in GetSignalElecSF(). Use GetTriggerGlobalEfficiencySF()!");
506 }
507 else {
508 double trig_sf = GetEleTriggerEfficiencySF( el , theExpr );
509 sf *= trig_sf;
510 }
511 }
512 }
513
514 if (isoSF) {
515 double iso_sf(1.);
517 if (acc_isolHighPt(el) && el.pt()>m_eleIsoHighPtThresh)
518 result = m_elecEfficiencySFTool_isoHighPt->getEfficiencyScaleFactor(el, iso_sf);
519 else
520 result = m_elecEfficiencySFTool_iso->getEfficiencyScaleFactor(el, iso_sf);
521
522 switch (result) {
524 sf *= iso_sf;
525 break;
527 ATH_MSG_ERROR( "Failed to retrieve signal electron iso SF");
528 break;
530 ATH_MSG_VERBOSE( "OutOfValidityRange found for signal electron iso SF");
531 break;
532 default:
533 ATH_MSG_WARNING( "Don't know what to do for signal electron iso SF");
534 }
535 }
536
537 // Charge flip SF: combined ECIDs & charge ID
538 if ( ecidsSF || cidSF ) {
539 double chf_sf(1.);
540 // 1. ECIDs SF
541 if ( ecidsSF ) {
542 sf *= chf_sf;
543 ATH_MSG_WARNING( "ECID SF ARE NOT YET SUPPORTED IN R22" );
544 }
545 // 2. CID SF
546 if ( cidSF ) {
547 sf *= chf_sf;
548 dec_sfChIDEff(el) = chf_sf;
549 ATH_MSG_WARNING( "CID SF ARE NOT YET SUPPORTED IN R22" );
550 }
551 }
552
553 dec_effscalefact(el) = sf;
554 return sf;
555}
556
557
558double SUSYObjDef_xAOD::GetEleTriggerEfficiencySF(const xAOD::Electron& el, const std::string& trigExpr) const {
559
560 double trig_sf(1.);
561
562 std::string single_str = "SINGLE_E";
563 std::string single_Run3 = "202";
564 std::string dilep_str = "DI_E";
565 std::string multi_str = "MULTI_L";
566
568 if ( trigExpr.find(single_str) != std::string::npos || trigExpr.find(single_Run3) != std::string::npos)
569 result = m_elecEfficiencySFTool_trig_singleLep->getEfficiencyScaleFactor(el, trig_sf);
570 else if ( trigExpr.find(dilep_str) != std::string::npos )
571 ATH_MSG_ERROR( "Use GetTriggerGlobalEfficiency for logical OR of lepton triggers");
572 else if ( trigExpr.find(multi_str) != std::string::npos )
573 ATH_MSG_ERROR( "Use GetTriggerGlobalEfficiency for logical OR of lepton triggers");
574 else
575 ATH_MSG_ERROR( "The trigger expression (" << trigExpr << ") is not supported by the electron trigger SF!");
576
577 switch (result) {
579 ATH_MSG_ERROR( "Failed to retrieve signal electron trigger SF");
580 return 1.;
582 ATH_MSG_VERBOSE( "OutOfValidityRange found for signal electron trigger SF");
583 return 1.;
584 default:
585 break;
586 }
587
588 return trig_sf;
589}
590
591
592double SUSYObjDef_xAOD::GetEleTriggerEfficiency(const xAOD::Electron& el, const std::string& trigExpr) const {
593
594 std::string single_str = "SINGLE_E";
595 std::string single_Run3 = "202";
596 std::string dilep_str = "DI_E";
597 std::string multi_str = "MULTI_L";
598
599 double trig_eff(1.);
600
602 if ( trigExpr.find(single_str) != std::string::npos || trigExpr.find(single_Run3) != std::string::npos)
603 result = m_elecEfficiencySFTool_trigEff_singleLep->getEfficiencyScaleFactor(el, trig_eff);
604 else if ( trigExpr.find(dilep_str) != std::string::npos )
605 ATH_MSG_ERROR( "Use GetTriggerGlobalEfficiency for logical OR of lepton triggers");
606 else if ( trigExpr.find(multi_str) != std::string::npos )
607 ATH_MSG_ERROR( "Use GetTriggerGlobalEfficiency for logical OR of lepton triggers");
608 else
609 ATH_MSG_ERROR( "The trigger expression (" << trigExpr << ") is not supported by the electron trigger efficiency!");
610
611 switch (result) {
613 ATH_MSG_ERROR( "Failed to retrieve signal electron trigger efficiency");
614 return 1.;
616 ATH_MSG_VERBOSE( "OutOfValidityRange found for signal electron trigger efficiency");
617 return 1.;
618 default:
619 break;
620 }
621
622 return trig_eff;
623}
624
625
626
627float SUSYObjDef_xAOD::GetTotalElectronSF(const xAOD::ElectronContainer& electrons, const bool recoSF, const bool idSF, const bool triggerSF, const bool isoSF, const std::string& trigExpr, const bool ecidsSF, const bool cidSF) {
628 float sf(1.);
629
630 for (const xAOD::Electron* electron : electrons) {
631 if (!acc_passOR(*electron)) continue;
632 if (acc_signal(*electron)) { sf *= this->GetSignalElecSF(*electron, recoSF, idSF, triggerSF, isoSF, trigExpr, ecidsSF, cidSF); }
633 else { this->GetSignalElecSF(*electron, recoSF, idSF, triggerSF, isoSF, trigExpr, ecidsSF, cidSF); }
634 }
635
636 return sf;
637}
638
639
640 float SUSYObjDef_xAOD::GetTotalElectronSFsys(const xAOD::ElectronContainer& electrons, const CP::SystematicSet& systConfig, const bool recoSF, const bool idSF, const bool triggerSF, const bool isoSF, const std::string& trigExpr, const bool ecidsSF, const bool cidSF) {
641 float sf(1.);
642
643 //Set the new systematic variation
644 StatusCode ret(StatusCode::SUCCESS);
645 if(!m_elecEfficiencySFTool_reco.empty()){
646 ret = m_elecEfficiencySFTool_reco->applySystematicVariation(systConfig);
647 if (ret != StatusCode::SUCCESS) {
648 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (reco) for systematic var. " << systConfig.name() );
649 }
650 }
651
652 if(!m_elecEfficiencySFTool_id.empty()){
653 ret = m_elecEfficiencySFTool_id->applySystematicVariation(systConfig);
654 if (ret != StatusCode::SUCCESS) {
655 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (id) for systematic var. " << systConfig.name() );
656 }
657 }
658
660 ret = m_elecEfficiencySFTool_trig_singleLep->applySystematicVariation(systConfig);
661 if (ret != StatusCode::SUCCESS) {
662 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
663 }
664 }
665
666 if(!m_elecEfficiencySFTool_iso.empty()){
667 ret = m_elecEfficiencySFTool_iso->applySystematicVariation(systConfig);
668 if (ret != StatusCode::SUCCESS) {
669 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (iso) for systematic var. " << systConfig.name() );
670 }
671 }
672
674 ret = m_elecEfficiencySFTool_isoHighPt->applySystematicVariation(systConfig);
675 if (ret != StatusCode::SUCCESS) {
676 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (iso high-pt) for systematic var. " << systConfig.name() );
677 }
678 }
679
680 if(!m_elecChargeEffCorrTool.empty()){
681 ret = m_elecChargeEffCorrTool->applySystematicVariation(systConfig);
682 if (ret != StatusCode::SUCCESS) {
683 ATH_MSG_ERROR("Cannot configure ElectronChargeEfficiencyCorrectionTool for systematic var. " << systConfig.name() );
684 }
685 }
686
687
688 //Get the total SF for new config
689 sf = GetTotalElectronSF(electrons, recoSF, idSF, triggerSF, isoSF, trigExpr, ecidsSF, cidSF);
690
691 //Roll back to default
692 if(!m_elecEfficiencySFTool_reco.empty()){
693 ret = m_elecEfficiencySFTool_reco->applySystematicVariation(m_currentSyst);
694 if (ret != StatusCode::SUCCESS) {
695 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (reco) back to default.");
696 }
697 }
698
699 if(!m_elecEfficiencySFTool_id.empty()){
700 ret = m_elecEfficiencySFTool_id->applySystematicVariation(m_currentSyst);
701 if (ret != StatusCode::SUCCESS) {
702 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (id) back to default.");
703 }
704 }
705
707 ret = m_elecEfficiencySFTool_trig_singleLep->applySystematicVariation(m_currentSyst);
708 if (ret != StatusCode::SUCCESS) {
709 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (trigger) back to default.");
710 }
711 }
712
713 if(!m_elecEfficiencySFTool_iso.empty()){
714 ret = m_elecEfficiencySFTool_iso->applySystematicVariation(m_currentSyst);
715 if (ret != StatusCode::SUCCESS) {
716 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (iso) back to default.");
717 }
718 }
719
721 ret = m_elecEfficiencySFTool_isoHighPt->applySystematicVariation(m_currentSyst);
722 if (ret != StatusCode::SUCCESS) {
723 ATH_MSG_ERROR("Cannot configure AsgElectronEfficiencyCorrectionTool (iso high-pt) back to default.");
724 }
725 }
726
727 if(!m_elecChargeEffCorrTool.empty()){
728 ret = m_elecChargeEffCorrTool->applySystematicVariation(m_currentSyst);
729 if (ret != StatusCode::SUCCESS) {
730 ATH_MSG_ERROR("Cannot configure ElectronChargeEfficiencyCorrectionTool back to default.");
731 }
732 }
733
734 return sf;
735}
736
737}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_VERBOSE(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
DataVector adapter that acts like it holds const pointers.
ServiceHandle< StoreGateSvc > & evtStore()
Return value from object correction CP tools.
@ Error
Some error happened during the object correction.
@ OutOfValidityRange
Input object is out of validity range.
@ Ok
The correction was done successfully.
Class to wrap a set of SystematicVariations.
std::string name() const
returns: the systematics joined into a single string.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
Helper class to provide constant type-safe access to aux data.
Helper class to provide type-safe access to aux data.
Definition Decorator.h:59
std::vector< std::string > m_v_trigs24_cache_singleEle
StatusCode FillElectron(xAOD::Electron &input, const float etcut, const float etacut) override final
asg::AnaToolHandle< CP::IElectronLRTOverlapRemovalTool > m_elecLRTORTool
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoBaselineTool
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_isoHighPt
asg::AnaToolHandle< IAsgElectronLikelihoodTool > m_elecSelLikelihood
StatusCode prepareLRTElectrons(const xAOD::ElectronContainer *inMuons, xAOD::ElectronContainer *copy) const override final
Definition Electrons.cxx:90
std::vector< std::string > m_v_trigs15_cache_singleEle
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoHighPtTool
asg::AnaToolHandle< IAsgElectronLikelihoodTool > m_elecSelLikelihoodBaseline
double GetEleTriggerEfficiencySF(const xAOD::Electron &el, const std::string &trigExpr="SINGLE_E_2015_e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose_2016_2018_e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0") const override final
StatusCode MergeElectrons(const xAOD::ElectronContainer &electrons, xAOD::ElectronContainer *outputCol, const std::set< const xAOD::Electron * > &ElectronsToRemove) const override final
Definition Electrons.cxx:61
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_id
const xAOD::ElectronContainer * lrt_electrons
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoTool
SG::ConstAccessor< char > m_acc_eleId
asg::AnaToolHandle< IAsgElectronLikelihoodTool > m_elecChargeIDSelectorTool
SG::WriteHandleKey< xAOD::ElectronContainer > m_outElectronLocation
std::vector< std::string > m_v_trigs23_cache_singleEle
double GetEleTriggerEfficiency(const xAOD::Electron &el, const std::string &trigExpr="SINGLE_E_2015_e24_lhmedium_L1EM20VH_OR_e60_lhmedium_OR_e120_lhloose_2016_2018_e26_lhtight_nod0_ivarloose_OR_e60_lhmedium_nod0_OR_e140_lhloose_nod0") const override final
const xAOD::ElectronContainer * prompt_electrons
std::vector< std::string > m_v_trigs18_cache_singleEle
int treatAsYear(const int runNumber=-1) const override final
asg::AnaToolHandle< IAsgDeadHVCellRemovalTool > m_deadHVTool
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_trigEff_singleLep
CP::SystematicSet m_currentSyst
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecChargeEffCorrTool
std::string m_eleIsoHighPt_WP
asg::AnaToolHandle< CP::IIsolationCorrectionTool > m_isoCorrTool
float GetSignalElecSF(const xAOD::Electron &el, const bool recoSF=true, const bool idSF=true, const bool triggerSF=true, const bool isoSF=true, const std::string &trigExpr="singleLepton", const bool ecidsSF=false, const bool cidSF=false) override final
SG::ConstAccessor< char > m_acc_eleIdBaseline
StatusCode GetElectrons(xAOD::ElectronContainer *&copy, xAOD::ShallowAuxContainer *&copyaux, const bool recordSG=true, const std::string &elekey="Electrons", const std::string &lrtelekey="LRTElectrons", const xAOD::ElectronContainer *containerToBeCopied=nullptr) override final
std::vector< std::string > m_v_trigs22_cache_singleEle
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_reco
Combined muon collection.
float GetTotalElectronSF(const xAOD::ElectronContainer &electrons, const bool recoSF=true, const bool idSF=true, const bool triggerSF=true, const bool isoSF=true, const std::string &trigExpr="singleLepton", const bool ecidsSF=false, const bool cidSF=false) override final
const xAOD::Vertex * GetPrimVtx() const override final
std::vector< std::string > m_v_trigs17_cache_singleEle
std::vector< std::string > m_v_trigs16_cache_singleEle
bool IsSignalElectron(const xAOD::Electron &input, const float etcut, const float d0sigcut, const float z0cut, const float etacut=DUMMYDEF) const override final
asg::AnaToolHandle< CP::IEgammaCalibrationAndSmearingTool > m_egammaCalibTool
Combined electron collection.
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_trig_singleLep
asg::AnaToolHandle< IAsgElectronEfficiencyCorrectionTool > m_elecEfficiencySFTool_iso
float GetTotalElectronSFsys(const xAOD::ElectronContainer &electrons, const CP::SystematicSet &systConfig, const bool recoSF=true, const bool idSF=true, const bool triggerSF=true, const bool isoSF=true, const std::string &trigExpr="singleLepton", const bool ecidsSF=false, const bool cidSF=false) override final
std::string m_eleBaselineIso_WP
std::string m_electronTriggerSFStringSingle
float beamPosSigmaY() const
The width of the beam spot in the Y direction.
float beamPosSigmaXY() const
The beam spot shape's X-Y correlation.
float beamPosSigmaX() const
The width of the beam spot in the X direction.
Class creating a shallow copy of an existing auxiliary container.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:114
static const SG::ConstAccessor< float > acc_d0sig("d0sig")
static const SG::ConstAccessor< char > acc_isolHighPt("isolHighPt")
static const SG::Decorator< double > dec_effscalefact("effscalefact")
static const SG::Decorator< char > dec_baseline("baseline")
static const SG::Decorator< char > dec_isolHighPt("isolHighPt")
static const SG::ConstAccessor< float > acc_z0sinTheta("z0sinTheta")
static const SG::Decorator< float > dec_d0sig("d0sig")
static const SG::Decorator< float > dec_sfChIDEff("chargeIDEffiSF")
static const SG::ConstAccessor< char > acc_passSignalID("passSignalID")
static const SG::Decorator< char > dec_isLRT("isLRT")
static const SG::ConstAccessor< char > acc_passECIDS("DFCommonElectronsECIDS")
static const SG::Decorator< double > dec_ecisBDT("ecisBDT")
static const SG::ConstAccessor< char > acc_trigmatched("trigmatched")
static const SG::ConstAccessor< unsigned int > acc_OQ("OQ")
static const SG::ConstAccessor< float > acc_sfChIDEff("chargeIDEffiSF")
static const SG::ConstAccessor< char > acc_signal("signal")
static const SG::ConstAccessor< char > acc_baseline("baseline")
static const SG::Decorator< char > dec_passSignalID("passSignalID")
static const double DUMMYDEF
static const SG::ConstAccessor< char > acc_passOR("passOR")
static const SG::ConstAccessor< char > acc_isLRT("isLRT")
static const SG::ConstAccessor< char > acc_lrtFilter("passLRTFilter")
static const SG::Decorator< char > dec_passChID("passChID")
static const SG::ConstAccessor< char > acc_isol("isol")
static const SG::Decorator< char > dec_isol("isol")
static const SG::ConstAccessor< char > acc_passChID("passChID")
static const SG::Decorator< char > dec_signal("signal")
static const SG::Decorator< char > dec_selected("selected")
static const SG::Decorator< float > dec_z0sinTheta("z0sinTheta")
helper namespace for calculating deltaR for unknown object types
const uint32_t BADCLUSELECTRON
Definition EgammaDefs.h:116
double d0significance(const xAOD::TrackParticle *tp, double d0_uncert_beam_spot_2)
ElectronContainer_v1 ElectronContainer
Definition of the current "electron container version".
EventInfo_v1 EventInfo
Definition of the latest event info version.
std::pair< std::unique_ptr< T >, std::unique_ptr< ShallowAuxContainer > > shallowCopyContainer(const T &cont, const EventContext &ctx)
Function making a shallow copy of a constant container.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
const IParticle * getOriginalObject(const IParticle &copy)
This function can be used to conveniently get a pointer back to the original object from which a copy...
Vertex_v1 Vertex
Define the latest version of the vertex class.
bool setOriginalObjectLink(const IParticle &original, IParticle &copy)
This function should be used by CP tools when they make a deep copy of an object in their correctedCo...
setBGCode setTAP setLVL2ErrorBits bool
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
Electron_v1 Electron
Definition of the current "egamma version".