ATLAS Offline Software
Loading...
Searching...
No Matches
Muons.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
5// This source file implements all of the functions related to Muons
6// in the SUSYObjDef_xAOD class
7
8// Local include(s):
10
16
18
25
28//disable #include "IsolationSelection/IIsolationLowPtPLVTool.h"
29
31
32#include <regex>
33#include <string_view>
34#include <ranges>
35
36#ifndef XAOD_STANDALONE // For now metadata is Athena-only
38#endif
39
40namespace ST {
41
42 const static SG::Decorator<char> dec_passedHighPtCuts("passedHighPtCuts");
43
44 const static SG::Decorator<char> dec_passSignalID("passSignalID");
45 const static SG::ConstAccessor<char> acc_passSignalID("passSignalID");
46
47 const static SG::Decorator<float> dec_DFCommonJetDr("DFCommonJetDr");
48 const static SG::ConstAccessor<float> acc_DFCommonJetDr("DFCommonJetDr");
49 const static SG::Decorator<float> dec_dRJet("dRJet");
50 const static SG::Decorator<float> dec_z0sinTheta("z0sinTheta");
51 const static SG::Decorator<float> dec_d0sig("d0sig");
52 const static SG::Decorator<char> dec_isLRT("isLRT");
53 const static SG::Decorator<char> dec_cosmic("cosmic");
54
55
56StatusCode SUSYObjDef_xAOD::MergeMuons(const xAOD::MuonContainer & muons, const std::vector<bool> &writeMuon, xAOD::MuonContainer* outputCol) const{
57 if (muons.empty()) return StatusCode::SUCCESS;
58 for (const xAOD::Muon* muon: muons) {
59 // add muon into output
60 if (writeMuon.at(muon->index())){
61 auto newMuon = new xAOD::Muon(*muon);
62
63 if ( getOriginalObject(*muon) != nullptr ) {
65 } else {
66 setOriginalObjectLink(*muon, *newMuon);
67 }
68 outputCol->push_back(newMuon);
69 }
70 }
71 return StatusCode::SUCCESS;
72}
73
75 for (const xAOD::Muon *muon: *inMuons){
76 const xAOD::TrackParticle* idtrack = muon->trackParticle(xAOD::Muon::InnerDetectorTrackParticle);
77
78 // Save muon if the id track passes the LRT filter
79 if ( acc_lrtFilter.isAvailable(*idtrack) )
80 {
81 if ( static_cast<int>(acc_lrtFilter(*idtrack) ) ){
82 std::unique_ptr<xAOD::Muon> copyMuon = std::make_unique<xAOD::Muon>(*muon);
83
84 // transfer original muon link
85 setOriginalObjectLink(*muon, *copyMuon);
86 copy->push_back( std::move(copyMuon) );
87 }
88 }
89 else // Keep muon if flag is not available
90 {
91 std::unique_ptr<xAOD::Muon> copyMuon = std::make_unique<xAOD::Muon>(*muon);
92
93 setOriginalObjectLink(*muon, *copyMuon);
94 copy->push_back( std::move(copyMuon) );
95 }
96
97 }
98 return StatusCode::SUCCESS;
99}
100
101StatusCode SUSYObjDef_xAOD::GetMuons(xAOD::MuonContainer*& copy, xAOD::ShallowAuxContainer*& copyaux, bool recordSG, const std::string& muonkey, const std::string& lrtmuonkey, const xAOD::MuonContainer* containerToBeCopied)
102{
103 if (!m_tool_init) {
104 ATH_MSG_ERROR("SUSYTools was not initialized!!");
105 return StatusCode::FAILURE;
106 }
107
108 // Initializing prompt/LRT OR procedure
109 auto outputCol = std::make_unique<xAOD::MuonContainer>();
110 std::unique_ptr<xAOD::MuonAuxContainer> outputAuxCol;
111 outputAuxCol = std::make_unique<xAOD::MuonAuxContainer>();
112 outputCol->setStore(outputAuxCol.get());
113 ATH_CHECK( m_outMuonLocation.initialize() );
114
115 if (bool(m_muLRT) && !lrtmuonkey.empty() && evtStore()->contains<xAOD::MuonContainer>(lrtmuonkey)){
116 ATH_MSG_DEBUG("Applying prompt/LRT muon OR procedure");
117
118 // First identify if merged container has already been made (for instances where GetMuons() is called more than once)
119 if (evtStore()->contains<xAOD::MuonContainer>("StdWithLRTMuons")) {
120 ATH_MSG_DEBUG("Merged prompt/LRT container already created in TStore");
121 } else {
122 ATH_MSG_DEBUG("Creating merged prompt/LRT container in TStore");
123
124 // Retrieve prompt and LRT muons from TStore
125 ATH_CHECK( evtStore()->retrieve(prompt_muons, muonkey) );
126 ATH_CHECK( evtStore()->retrieve(lrt_muons, lrtmuonkey) );
127
128 // Remove LRT muons as flagged by filter for uncertainty
129 auto filtered_muons = std::make_unique<xAOD::MuonContainer>();
130 std::unique_ptr<xAOD::MuonAuxContainer> filtered_muons_aux = std::make_unique<xAOD::MuonAuxContainer>();
131 filtered_muons->setStore(filtered_muons_aux.get());
132 ATH_CHECK(prepareLRTMuons(lrt_muons, filtered_muons.get()));
133
134 // Check overlap between prompt and LRT collections
135 std::vector<bool> writePromptMuon;
136 std::vector<bool> writeLRTMuon;
137 m_muonLRTORTool->checkOverlap(*prompt_muons, *filtered_muons, writePromptMuon, writeLRTMuon);
138
139 // Decorate muons with prompt/LRT
140 for (const xAOD::Muon* mu : *prompt_muons) dec_isLRT(*mu) = 0;
141 for (const xAOD::Muon* mu : *filtered_muons) dec_isLRT(*mu) = 1;
142
143 // Create merged StdWithLRTMuons container
144 outputCol->reserve(prompt_muons->size() + filtered_muons->size());
145 ATH_CHECK(MergeMuons(*prompt_muons, writePromptMuon, outputCol.get()) );
146 ATH_CHECK(MergeMuons(*filtered_muons, writeLRTMuon, outputCol.get()) );
147
148 // Save merged StdWithLRTMuons container to TStore
149 ATH_CHECK(evtStore()->record(std::move(outputCol), m_outMuonLocation.key()));
150 ATH_CHECK(evtStore()->record(std::move(outputAuxCol), m_outMuonLocation.key() + "Aux.") );
151
152 }
153 } else if (!lrtmuonkey.empty()) {
154 if (evtStore()->contains<xAOD::MuonContainer>(lrtmuonkey) == false && bool(m_muLRT) == true) ATH_MSG_WARNING("prompt/LRT OR procedure attempted but " << lrtmuonkey << " not in ROOT file, check config!");
155 ATH_MSG_DEBUG("Not applying prompt/LRT muon OR procedure");
156 }
157
158 if (m_isPHYSLITE && muonkey.find("AnalysisMuons")==std::string::npos){
159 ATH_MSG_ERROR("You are running on PHYSLITE derivation. Please change the Muons container to 'AnalysisMuons'");
160 return StatusCode::FAILURE;
161 }
162
163 const xAOD::MuonContainer* muons = nullptr;
164 if (bool(m_muLRT) && evtStore()->contains<xAOD::MuonContainer>(lrtmuonkey)){
165 ATH_MSG_DEBUG("Using container: " << m_outMuonLocation.key());
166 ATH_CHECK( evtStore()->retrieve(muons, m_outMuonLocation.key()));
167 }
168 else {
169 if (copy==nullptr) { // empty container provided
170 ATH_MSG_DEBUG("Empty container provided");
171 if (containerToBeCopied != nullptr) {
172 ATH_MSG_DEBUG("Containter to be copied not nullptr");
173 muons = containerToBeCopied;
174 }
175 else {
176 ATH_MSG_DEBUG("Getting Muons collection");
177 ATH_CHECK( evtStore()->retrieve(muons, muonkey) );
178 }
179 }
180 }
181
182 if (copy==nullptr) { // empty container provided
184 copy = shallowcopy.first.get();
185 copyaux = shallowcopy.second.get();
186 bool setLinks = xAOD::setOriginalObjectLink(*muons, *copy);
187 if (!setLinks) {
188 ATH_MSG_WARNING("Failed to set original object links on " << muonkey);
189 }
190 if (recordSG) {
191 ATH_CHECK( evtStore()->record(std::move(shallowcopy.first), "STCalib" + muonkey + m_currentSyst.name()) );
192 ATH_CHECK( evtStore()->record(std::move(shallowcopy.second), "STCalib" + muonkey + m_currentSyst.name() + "Aux.") );
193 } else {
194 ATH_MSG_ERROR("Shallow copy not recorded in StoreGate!");
195 return StatusCode::FAILURE;
196 }
197 } else { // use the user-supplied collection instead
198 ATH_MSG_DEBUG("Not retrieving muon collection, using existing one provided by user");
199 muons=copy; // this does nothing
200 }
201
202 for (const auto muon : *copy) {
207 }
208
209 return StatusCode::SUCCESS;
210}
211
212StatusCode SUSYObjDef_xAOD::FillMuon(xAOD::Muon& input, float ptcut, float etacut) {
213
214 ATH_MSG_VERBOSE( "Starting FillMuon on mu with pt=" << input.pt() );
215
216 dec_baseline(input) = false;
217 dec_selected(input) = 0;
218 dec_signal(input) = false;
219 dec_isol(input) = false;
220 dec_isolHighPt(input) = false;
221 dec_passedHighPtCuts(input) = false;
222 dec_passSignalID(input) = false;
223
224 if (m_muEffCorrForce1D) {
225 dec_DFCommonJetDr(input) = -2.0;
226 } else if (!acc_DFCommonJetDr.isAvailable(input)) {
227 dec_dRJet(input) = -2.0;
228 }
229
230 // don't bother calibrating or computing WP
231 if ( input.pt() < 3e3 ) return StatusCode::SUCCESS;
232
233 ATH_MSG_VERBOSE( "MUON pt before calibration " << input.pt() );
234
235 ATH_MSG_VERBOSE( "MUON eta = " << input.eta() );
236 ATH_MSG_VERBOSE( "MUON type = " << input.muonType() );
237 ATH_MSG_VERBOSE( "MUON author = " << input.author() );
238
239 if (m_muonCalibTool->applyCorrection( input ) == CP::CorrectionCode::OutOfValidityRange){
240 ATH_MSG_VERBOSE("FillMuon: applyCorrection out of validity range");
241 }
242
243 ATH_MSG_VERBOSE( "MUON pt after calibration " << input.pt() );
244
245 const xAOD::EventInfo* evtInfo = nullptr;
246 ATH_CHECK( evtStore()->retrieve( evtInfo, "EventInfo" ) );
247 const xAOD::Vertex* pv = this->GetPrimVtx();
248 double primvertex_z = pv ? pv->z() : 0;
249 //const xAOD::TrackParticle* track = input.primaryTrackParticle();
251 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
252 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
253 if (!track) return StatusCode::SUCCESS; // don't treat SAF muons without CB track further
254 }
255 else {
256 track = input.primaryTrackParticle();
257 }
258
259 //impact parameters (after applyCorrection() so to have the primaryTrack links restored in old buggy samples)
260 if (track){
261 dec_z0sinTheta(input) = (track->z0() + track->vz() - primvertex_z) * TMath::Sin(input.p4().Theta());
262 } else {
263 ATH_MSG_WARNING("FillMuon: Muon of pT and eta " << input.pt() << " MeV " << input.eta() << " has no associated track");
264 }
265 //protect against exception thrown for null or negative d0sig
266 try {
267 if (track)
269 else
270 dec_d0sig(input) = -99.;
271 }
272 catch (...) {
273 float d0sigError = -99.;
274 ATH_MSG_WARNING("FillMuon : Exception caught from d0significance() calculation. Setting dummy decoration d0sig=" << d0sigError );
275 dec_d0sig(input) = d0sigError;
276 }
277
278 if (m_debug) {
279 // Summary variables in
280 // /cvmfs/atlas.cern.ch/repo/sw/ASG/AnalysisBase/2.0.3/xAODTracking/Root/TrackSummaryAccessors_v1.cxx
281
282 unsigned char nBLHits(0), nPixHits(0), nPixelDeadSensors(0), nPixHoles(0),
283 nSCTHits(0), nSCTDeadSensors(0), nSCTHoles(0), nTRTHits(0), nTRTOutliers(0);
284
285 if (track){
286 track->summaryValue( nBLHits, xAOD::numberOfBLayerHits);
287 track->summaryValue( nPixHits, xAOD::numberOfPixelHits);
288 track->summaryValue( nPixelDeadSensors, xAOD::numberOfPixelDeadSensors);
289 track->summaryValue( nPixHoles, xAOD::numberOfPixelHoles);
290
291 track->summaryValue( nSCTHits, xAOD::numberOfSCTHits);
292 track->summaryValue( nSCTDeadSensors, xAOD::numberOfSCTDeadSensors);
293 track->summaryValue( nSCTHoles, xAOD::numberOfSCTHoles);
294
295 track->summaryValue( nTRTHits, xAOD::numberOfTRTHits);
296 track->summaryValue( nTRTOutliers, xAOD::numberOfTRTOutliers);
297 }
298
299 ATH_MSG_INFO( "MUON pt: " << input.pt() );
300 ATH_MSG_INFO( "MUON eta: " << input.eta() );
301 ATH_MSG_INFO( "MUON phi: " << input.phi() );
302 ATH_MSG_INFO( "MUON comb: " << (input.muonType() == xAOD::Muon::Combined));
303 ATH_MSG_INFO( "MUON sTag: " << (input.muonType() == xAOD::Muon::SegmentTagged));
304 ATH_MSG_INFO( "MUON loose:" << (input.quality() == xAOD::Muon::Loose));
305 ATH_MSG_INFO( "MUON bHit: " << static_cast<int>( nBLHits ));
306 ATH_MSG_INFO( "MUON pHit: " << static_cast<int>( nPixHits ));
307 ATH_MSG_INFO( "MUON pDead:" << static_cast<int>( nPixelDeadSensors ));
308 ATH_MSG_INFO( "MUON pHole:" << static_cast<int>( nPixHoles ));
309 ATH_MSG_INFO( "MUON sHit: " << static_cast<int>( nSCTHits));
310 ATH_MSG_INFO( "MUON sDead:" << static_cast<int>( nSCTDeadSensors ));
311 ATH_MSG_INFO( "MUON sHole:" << static_cast<int>( nSCTHoles ));
312 ATH_MSG_INFO( "MUON tHit: " << static_cast<int>( nTRTHits ));
313 ATH_MSG_INFO( "MUON tOut: " << static_cast<int>( nTRTOutliers ));
314
315 const xAOD::TrackParticle* idtrack =
316 input.trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
317
318 if ( !idtrack) {
319 ATH_MSG_VERBOSE( "No ID track!! " );
320 } else {
321 ATH_MSG_VERBOSE( "ID track pt: " << idtrack->pt());
322 }
323 }
324
325 if ( !m_force_noMuId && !m_muonSelectionToolBaseline->accept(input)) return StatusCode::SUCCESS;
326
327 if (input.pt() <= ptcut || std::abs(input.eta()) >= etacut) return StatusCode::SUCCESS;
328
329 if (m_mubaselinez0>0. && std::abs(acc_z0sinTheta(input))>m_mubaselinez0) return StatusCode::SUCCESS;
330 if (m_mubaselined0sig>0. && std::abs(acc_d0sig(input))>m_mubaselined0sig) return StatusCode::SUCCESS;
331
332 //--- Do baseline isolation check
333 if ( !( m_muBaselineIso_WP.empty() ) && !( m_isoBaselineTool->accept(input) ) ) return StatusCode::SUCCESS;
334
335 dec_baseline(input) = true;
336 dec_selected(input) = 2;
337
338 //disable if (!m_muIso_WP.empty() && m_muIso_WP.find("PLV")!=std::string::npos) ATH_CHECK( m_isoToolLowPtPLV->augmentPLV(input) );
339 if (!m_muIso_WP.empty()) dec_isol(input) = bool(m_isoTool->accept(input));
340 if (!m_muIsoHighPt_WP.empty()) dec_isolHighPt(input) = bool(m_isoHighPtTool->accept(input));
341 dec_passSignalID(input) = bool(m_muonSelectionTool->accept(input));
342
343 ATH_MSG_VERBOSE("FillMuon: passed baseline selection");
344 return StatusCode::SUCCESS;
345}
346
347
348bool SUSYObjDef_xAOD::IsSignalMuon(const xAOD::Muon & input, float ptcut, float d0sigcut, float z0cut, float etacut) const
349{
350 if (!acc_baseline(input)) return false;
351 if (!acc_passSignalID(input)) return false;
352
353 if (input.pt() <= ptcut || input.pt() == 0) return false; // pT cut (might be necessary for leading muon to pass trigger)
354 if ( etacut==DUMMYDEF ){
355 if(std::abs(input.eta()) > m_muEta ) return false;
356 }
357 else if ( std::abs(input.eta()) > etacut ) return false;
358
359 if (z0cut > 0.0 && std::abs(acc_z0sinTheta(input)) > z0cut) return false; // longitudinal IP cut
360 if (acc_d0sig(input) != 0) {
361 if (d0sigcut > 0.0 && std::abs(acc_d0sig(input)) > d0sigcut) return false; // transverse IP cut
362 }
363
364 if (m_doMuIsoSignal) {
365 if ( !( (acc_isol(input) && input.pt()<m_muIsoHighPtThresh) || (acc_isolHighPt(input) && input.pt()>m_muIsoHighPtThresh)) ) return false;
366 ATH_MSG_VERBOSE( "IsSignalMuon: passed isolation");
367 }
368
369 //set HighPtMuon decoration
370 IsHighPtMuon(input);
371
372 dec_signal(input) = true;
373
374 if (m_muId == 4) { //i.e. HighPt muons
375 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
376 << " signal? " << static_cast<int>(acc_signal(input))
377 << " isolation? " << static_cast<int>(acc_isol(input))
378 << " passedHighPtCuts? " << static_cast<int>(acc_passedHighPtCuts(input)));
379 } else {
380 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
381 << " signal? " << static_cast<int>( acc_signal(input))
382 << " isolation? " << static_cast<int>( acc_isol(input)));
383 // Don't show HighPtFlag ... we didn't set it!
384 }
385
386 return acc_signal(input);
387}
388
389
391// See https://indico.cern.ch/event/371499/contribution/1/material/slides/0.pdf and
392// https://indico.cern.ch/event/397325/contribution/19/material/slides/0.pdf and
393// https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionTool
394{
395 if (input.pt() < 3e3){
396 ATH_MSG_DEBUG("No HighPt check supported for muons below 3GeV! False.");
397 dec_passedHighPtCuts(input) = false;
398 return false;
399 }
400
401 bool isHighPt=false;
402 isHighPt = bool(m_muonSelectionHighPtTool->accept(input));
403 dec_passedHighPtCuts(input) = isHighPt;
404
405 return isHighPt;
406}
407
408
409bool SUSYObjDef_xAOD::IsBadMuon(const xAOD::Muon& input, float qopcut) const
410{
411 const static SG::Decorator<char> dec_bad("bad");
412 dec_bad(input) = false;
413
414 const static SG::Decorator<char> dec_bad_highPt("bad_highPt");
415 dec_bad_highPt(input) = false;
416
418 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
419 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
420 if (!track) return false; // don't treat SAF muons without CB track further
421 }
422 else{
423 track = input.primaryTrackParticle();
424 if (!track){
425 ATH_MSG_WARNING("Non-SAF muon without a track; cannot test IsBadMuon criteria");
426 return false;
427 }
428 }
429
430 float Rerr = Amg::error(track->definingParametersCovMatrix(), 4) / std::abs(track->qOverP());
431 ATH_MSG_VERBOSE( "Track momentum error (%): " << Rerr * 100 );
432 bool isbad = Rerr > qopcut;
433 bool isbadHighPt = Rerr > qopcut;
434
435 //new recommendation from MCP
436 isbad |= m_muonSelectionTool->isBadMuon(input);
437
438 //new recommendation from MCP (at HighPT)
439 isbadHighPt |= m_muonSelectionHighPtTool->isBadMuon(input);
440
441 dec_bad(input) = isbad;
442 dec_bad_highPt(input) = isbadHighPt;
443
444 ATH_MSG_VERBOSE( "MUON isbad?: " << isbad );
445 return isbad;
446}
447
448bool SUSYObjDef_xAOD::IsCosmicMuon(const xAOD::Muon& input, float z0cut, float d0cut) const
449{
450 dec_cosmic(input) = false;
451
452 const xAOD::TrackParticle* track(nullptr);
453 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
454 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
455 if (!track){
456 ATH_MSG_VERBOSE("WARNING: SAF muon without CB track found. Not possible to check cosmic muon criteria");
457 return false; // don't treat SAF muons without CB track further
458 }
459 }
460 else {
461 track = input.primaryTrackParticle();
462 if (!track){
463 ATH_MSG_WARNING("Non-SAF muon without primary track particle found. Not possible to check cosmic muon criteria");
464 return false;
465 }
466 }
467
468 double mu_d0 = track->d0();
469 const xAOD::Vertex* pv = this->GetPrimVtx();
470 double primvertex_z = pv ? pv->z() : 0;
471 double mu_z0_exPV = track->z0() + track->vz() - primvertex_z;
472
473 bool isCosmicMuon = (std::abs(mu_z0_exPV) >= z0cut || std::abs(mu_d0) >= d0cut);
474
475 if (isCosmicMuon) {
476 ATH_MSG_VERBOSE("COSMIC PV Z = " << primvertex_z << ", track z0 = " << mu_z0_exPV << ", track d0 = " << mu_d0);
477 }
478
479 dec_cosmic(input) = isCosmicMuon;
480 return isCosmicMuon;
481}
482
483
484 float SUSYObjDef_xAOD::GetSignalMuonSF(const xAOD::Muon& mu, const bool recoSF, const bool isoSF, const bool doBadMuonHP, const bool warnOVR)
485{
486 float sf(1.);
487
488 if (recoSF) {
489 float sf_reco(1.);
490 if (m_muonEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_reco ) == CP::CorrectionCode::OutOfValidityRange) {
491 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Reco getEfficiencyScaleFactor out of validity range");
492 }
493 ATH_MSG_VERBOSE( "MuonReco ScaleFactor " << sf_reco );
494 sf *= sf_reco;
495
496 float sf_ttva(1.);
497 if(m_doTTVAsf){
498 if (m_muonTTVAEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_ttva ) == CP::CorrectionCode::OutOfValidityRange) {
499 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: TTVA getEfficiencyScaleFactor out of validity range");
500 }
501 ATH_MSG_VERBOSE( "MuonTTVA ScaleFactor " << sf_ttva );
502 sf *= sf_ttva;
503 }
504
505 float sf_badHighPt(1.);
506 if(m_muId == 4 && doBadMuonHP){
507 if (m_muonEfficiencyBMHighPtSFTool->getEfficiencyScaleFactor( mu, sf_badHighPt ) == CP::CorrectionCode::OutOfValidityRange) {
508 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: BadMuonHighPt getEfficiencyScaleFactor out of validity range");
509 }
510 ATH_MSG_VERBOSE( "MuonBadMuonHighPt ScaleFactor " << sf_badHighPt );
511 sf *= sf_badHighPt;
512 }
513 }
514
515
516 if (isoSF) {
517 float sf_iso(1.);
518 if (acc_isolHighPt(mu) && mu.pt()>m_muIsoHighPtThresh) {
519 if (m_muonHighPtIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
520 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: high-pt Iso getEfficiencyScaleFactor out of validity range");
521 }
522 } else if (acc_isol(mu) && mu.pt()<m_muIsoHighPtThresh) {
523 if (m_muonIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
524 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Iso getEfficiencyScaleFactor out of validity range");
525 }
526 }
527 ATH_MSG_VERBOSE( "MuonIso ScaleFactor " << sf_iso );
528 sf *= sf_iso;
529 }
530
531
532 dec_effscalefact(mu) = sf;
533 return sf;
534}
535
536
537double SUSYObjDef_xAOD::GetMuonTriggerEfficiency(const xAOD::Muon& mu, const std::string& trigExpr, const bool isdata) {
538
539 double eff(1.);
540
541 if (m_muonTriggerSFTool->getTriggerEfficiency(mu, eff, trigExpr, isdata) != CP::CorrectionCode::Ok) {
542 ATH_MSG_WARNING("Problem retrieving signal muon trigger efficiency for " << trigExpr );
543 }
544 else{
545 ATH_MSG_DEBUG("Got efficiency " << eff << " for " << trigExpr );
546 }
547 return eff;
548}
549
550
551double SUSYObjDef_xAOD::GetTotalMuonTriggerSF(const xAOD::MuonContainer& sfmuons, const std::string& trigExpr) {
552
553 if (trigExpr.empty() || sfmuons.empty()) return 1.;
554
555
556 double trig_sf = 1.;
557
558 int mulegs = 0;
559 const char *tmp = trigExpr.c_str();
560 while( (tmp = strstr(tmp, "mu")) ){
561 mulegs++;
562 tmp++;
563 }
564
565 bool isdimuon = (trigExpr.find("2mu") != std::string::npos);
566 bool isOR = (trigExpr.find("OR") != std::string::npos);
567
568 if((!isdimuon && mulegs<2) || (isdimuon && sfmuons.size()==2) || (mulegs>=2 && isOR)){ //Case 1: the tool takes easy care of the single, standard-dimuon and OR-of-single chains
569 if (m_muonTriggerSFTool->getTriggerScaleFactor( sfmuons, trig_sf, trigExpr ) == CP::CorrectionCode::Ok) {
570 ATH_MSG_DEBUG( "MuonTrig ScaleFactor " << trig_sf );
571 }
572 else{
573 ATH_MSG_DEBUG( "MuonTrig FAILED SOMEHOW");
574 }
575 }
576 else if(mulegs!=2 && isOR){ //Case 2: not supported. Not efficiency defined for (at least) one leg. Sorry...
577 ATH_MSG_WARNING( "SF for " << trigExpr << " are only supported for two muon events!");
578 }
579 else{ //Case 3: let's go the hard way...
580 //Following https://twiki.cern.ch/twiki/bin/view/Atlas/TrigMuonEfficiency
581 std::string newtrigExpr = TString(trigExpr).Copy().ReplaceAll("HLT_2","").Data();
582
583 //redefine dimuon triggers here (2mu14 --> mu14_mu14)
584 if (isdimuon) { newtrigExpr += "_"+newtrigExpr; }
585 newtrigExpr = std::regex_replace(newtrigExpr, std::regex("HLT_"), "");
586
587 for (auto part : std::views::split(newtrigExpr, '_')) {
588 std::string mutrig(&*part.begin(), std::ranges::distance(part));
589 double dataFactor = 1.;
590 double mcFactor = 1.;
591
592 for (const xAOD::Muon* mu : sfmuons) {
593 // No need for additional trigger matching
594 dataFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, true));
595 mcFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, false));
596 }
597 if( (1-mcFactor) > 0. )
598 trig_sf *= (1-dataFactor)/(1-mcFactor);
599 }
600 }
601
602 return trig_sf;
603}
604
605
606double SUSYObjDef_xAOD::GetTotalMuonSF(const xAOD::MuonContainer& muons, const bool recoSF, const bool isoSF, const std::string& trigExpr, const bool bmhptSF) {
607 double sf(1.);
608
610 for (const xAOD::Muon* muon : muons) {
611 if( !acc_passOR(*muon) ) continue;
612 if (acc_signal(*muon)) {
613 sfmuons.push_back(muon);
614 if (recoSF || isoSF) { sf *= this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF); }
615 } else { // decorate baseline muons as well
616 if (recoSF || isoSF) { this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF, false); } //avoid OVR warnings in this case
617 }
618 }
619
620 sf *= GetTotalMuonTriggerSF(*sfmuons.asDataVector(), trigExpr);
621
622 return sf;
623}
624
625
626 double SUSYObjDef_xAOD::GetTotalMuonSFsys(const xAOD::MuonContainer& muons, const CP::SystematicSet& systConfig, const bool recoSF, const bool isoSF, const std::string& trigExpr, const bool bmhptSF) {
627 double sf(1.);
628 //Set the new systematic variation
629 StatusCode ret = m_muonEfficiencySFTool->applySystematicVariation(systConfig);
630 if ( ret != StatusCode::SUCCESS) {
631 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors for systematic var. " << systConfig.name() );
632 }
633
634 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(systConfig);
635 if ( ret != StatusCode::SUCCESS) {
636 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors for systematic var. " << systConfig.name() );
637 }
638
639 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(systConfig);
640 if ( ret != StatusCode::SUCCESS) {
641 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors for systematic var. " << systConfig.name() );
642 }
643
644 ret = m_muonIsolationSFTool->applySystematicVariation(systConfig);
645 if ( ret != StatusCode::SUCCESS) {
646 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors for systematic var. " << systConfig.name() );
647 }
648
649 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(systConfig);
650 if ( ret != StatusCode::SUCCESS) {
651 ATH_MSG_ERROR("Cannot configure MuonHighPtIsolationScaleFactors for systematic var. " << systConfig.name() );
652 }
653
654 ret = m_muonTriggerSFTool->applySystematicVariation(systConfig);
655 if ( ret != StatusCode::SUCCESS) {
656 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors for systematic var. " << systConfig.name() );
657 }
658
659 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(systConfig);
660 if (ret != StatusCode::SUCCESS) {
661 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
662 }
663
664 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(systConfig);
665 if (ret != StatusCode::SUCCESS) {
666 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
667 }
668
669 sf = GetTotalMuonSF(muons, recoSF, isoSF, trigExpr, bmhptSF);
670
671 //Roll back to default
672 ret = m_muonEfficiencySFTool->applySystematicVariation(m_currentSyst);
673 if ( ret != StatusCode::SUCCESS) {
674 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors back to default.");
675 }
676
677 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(m_currentSyst);
678 if ( ret != StatusCode::SUCCESS) {
679 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors back to default.");
680 }
681
682 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(m_currentSyst);
683 if ( ret != StatusCode::SUCCESS) {
684 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors back to default.");
685 }
686
687 ret = m_muonIsolationSFTool->applySystematicVariation(m_currentSyst);
688 if ( ret != StatusCode::SUCCESS) {
689 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
690 }
691
692 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(m_currentSyst);
693 if ( ret != StatusCode::SUCCESS) {
694 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
695 }
696
697 ret = m_muonTriggerSFTool->applySystematicVariation(m_currentSyst);
698 if ( ret != StatusCode::SUCCESS) {
699 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors back to default.");
700 }
701
702 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(m_currentSyst);
703 if (ret != StatusCode::SUCCESS) {
704 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
705 }
706
707 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(m_currentSyst);
708 if (ret != StatusCode::SUCCESS) {
709 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
710 }
711
712 return sf;
713}
714
715}
#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()
@ 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.
DataVector adapter that acts like it holds const pointers.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
const DV * asDataVector() const
Return a pointer to this object, as a const DataVector.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
bool empty() const noexcept
Returns true if the collection is empty.
Helper class to provide constant type-safe access to aux data.
asg::AnaToolHandle< CP::IMuonSelectionTool > m_muonSelectionTool
asg::AnaToolHandle< ITrigGlobalEfficiencyCorrectionTool > m_trigGlobalEffCorrTool_multiLep
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoBaselineTool
asg::AnaToolHandle< CP::IMuonEfficiencyScaleFactors > m_muonEfficiencySFTool
bool IsBadMuon(const xAOD::Muon &input, const float qopcut) const override final
Definition Muons.cxx:409
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoHighPtTool
asg::AnaToolHandle< CP::IMuonEfficiencyScaleFactors > m_muonTTVAEfficiencySFTool
asg::AnaToolHandle< CP::IIsolationSelectionTool > m_isoTool
SG::WriteHandleKey< xAOD::MuonContainer > m_outMuonLocation
bool IsHighPtMuon(const xAOD::Muon &input) const override final
Definition Muons.cxx:390
asg::AnaToolHandle< CP::IMuonLRTOverlapRemovalTool > m_muonLRTORTool
StatusCode MergeMuons(const xAOD::MuonContainer &muons, const std::vector< bool > &writeMuon, xAOD::MuonContainer *outputCol) const override final
Definition Muons.cxx:56
asg::AnaToolHandle< CP::IMuonTriggerScaleFactors > m_muonTriggerSFTool
StatusCode prepareLRTMuons(const xAOD::MuonContainer *inMuons, xAOD::MuonContainer *copy) const override final
Definition Muons.cxx:74
std::string m_muBaselineIso_WP
const xAOD::MuonContainer * lrt_muons
CP::SystematicSet m_currentSyst
asg::AnaToolHandle< CP::IMuonEfficiencyScaleFactors > m_muonEfficiencyBMHighPtSFTool
std::string m_muIsoHighPt_WP
asg::AnaToolHandle< CP::IMuonCalibrationAndSmearingTool > m_muonCalibTool
double GetTotalMuonSFsys(const xAOD::MuonContainer &muons, const CP::SystematicSet &systConfig, const bool recoSF=true, const bool isoSF=true, const std::string &trigExpr="HLT_mu20_iloose_L1MU15_OR_HLT_mu50", const bool bmhptSF=true) override final
Definition Muons.cxx:626
double GetTotalMuonTriggerSF(const xAOD::MuonContainer &sfmuons, const std::string &trigExpr) override final
Definition Muons.cxx:551
bool IsSignalMuon(const xAOD::Muon &input, const float ptcut, const float d0sigcut, const float z0cut, const float etacut=DUMMYDEF) const override final
Definition Muons.cxx:348
StatusCode GetMuons(xAOD::MuonContainer *&copy, xAOD::ShallowAuxContainer *&copyaux, const bool recordSG=true, const std::string &muonkey="Muons", const std::string &lrtmuonkey="MuonsLRT", const xAOD::MuonContainer *containerToBeCopied=nullptr) override final
Definition Muons.cxx:101
bool IsCosmicMuon(const xAOD::Muon &input, const float z0cut, const float d0cut) const override final
Definition Muons.cxx:448
asg::AnaToolHandle< CP::IMuonSelectionTool > m_muonSelectionHighPtTool
asg::AnaToolHandle< CP::IMuonEfficiencyScaleFactors > m_muonHighPtIsolationSFTool
asg::AnaToolHandle< ITrigGlobalEfficiencyCorrectionTool > m_trigGlobalEffCorrTool_diLep
const xAOD::Vertex * GetPrimVtx() const override final
double GetTotalMuonSF(const xAOD::MuonContainer &muons, const bool recoSF=true, const bool isoSF=true, const std::string &trigExpr="HLT_mu20_iloose_L1MU15_OR_HLT_mu50", const bool bmhptSF=true) override final
Definition Muons.cxx:606
StatusCode FillMuon(xAOD::Muon &input, const float ptcut, const float etacut) override final
Definition Muons.cxx:212
asg::AnaToolHandle< CP::IMuonSelectionTool > m_muonSelectionToolBaseline
double GetMuonTriggerEfficiency(const xAOD::Muon &mu, const std::string &trigExpr, const bool isdata=false) override final
Definition Muons.cxx:537
float GetSignalMuonSF(const xAOD::Muon &mu, const bool recoSF=true, const bool isoSF=true, const bool doBadMuonHP=true, const bool warnOVR=true) override final
Definition Muons.cxx:484
asg::AnaToolHandle< CP::IMuonEfficiencyScaleFactors > m_muonIsolationSFTool
const xAOD::MuonContainer * prompt_muons
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.
virtual double pt() const override final
The transverse momentum ( ) of the particle.
bool contains(const std::string &s, const std::string &regx)
does a string contain the substring
Definition hcg.cxx:116
double error(const Amg::MatrixX &mat, int index)
return diagonal error of the matrix caller should ensure the matrix is symmetric and the index is in ...
SG::Decorator< T, ALLOC > Decorator
Helper class to provide type-safe access to aux data, specialized for JaggedVecElt.
Definition AuxElement.h:576
@ VIEW_ELEMENTS
this data object is a view, it does not own its elmts
static const SG::ConstAccessor< float > acc_d0sig("d0sig")
static const SG::Decorator< float > dec_DFCommonJetDr("DFCommonJetDr")
static const SG::ConstAccessor< char > acc_isolHighPt("isolHighPt")
static const SG::Decorator< float > dec_dRJet("dRJet")
static const SG::Decorator< char > dec_cosmic("cosmic")
static const SG::Decorator< double > dec_effscalefact("effscalefact")
static const SG::Decorator< char > dec_passSignalID("passSignalID")
static const SG::Decorator< char > dec_passedHighPtCuts("passedHighPtCuts")
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::ConstAccessor< char > acc_passedHighPtCuts("passedHighPtCuts")
static const SG::ConstAccessor< char > acc_passSignalID("passSignalID")
static const SG::ConstAccessor< char > acc_signal("signal")
static const SG::ConstAccessor< char > acc_baseline("baseline")
static const SG::ConstAccessor< float > acc_DFCommonJetDr("DFCommonJetDr")
static const SG::Decorator< float > dec_z0sinTheta("z0sinTheta")
static const double DUMMYDEF
static const SG::Decorator< char > dec_bad("bad")
static const SG::Decorator< char > dec_isLRT("isLRT")
static const SG::ConstAccessor< char > acc_passOR("passOR")
static const SG::ConstAccessor< char > acc_lrtFilter("passLRTFilter")
static const SG::ConstAccessor< char > acc_isol("isol")
static const SG::Decorator< char > dec_isol("isol")
static const SG::Decorator< char > dec_signal("signal")
static const SG::Decorator< float > dec_d0sig("d0sig")
static const SG::Decorator< char > dec_selected("selected")
double d0significance(const xAOD::TrackParticle *tp, double d0_uncert_beam_spot_2)
typename ShallowCopyResult< T >::type ShallowCopyResult_t
Return type of xAOD::shallowCopy.
Definition ShallowCopy.h:68
EventInfo_v1 EventInfo
Definition of the latest event info version.
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.
ShallowCopyResult_t< T > shallowCopy(const T &cont, const EventContext &ctx)
Create a shallow copy of an existing container.
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...
Muon_v1 Muon
Reference the current persistent version:
setBGCode setTAP setLVL2ErrorBits bool
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".
@ numberOfPixelHoles
number of pixel layers on track with absence of hits [unit8_t].
@ numberOfTRTHits
number of TRT hits [unit8_t].
@ numberOfBLayerHits
these are the hits in the first pixel layer, i.e.
@ numberOfSCTDeadSensors
number of dead SCT sensors crossed [unit8_t].
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].
@ numberOfTRTOutliers
number of TRT outliers [unit8_t].
@ numberOfPixelDeadSensors
number of dead pixel sensors crossed [unit8_t].
@ numberOfSCTHoles
number of SCT holes [unit8_t].