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.trackParticle(xAOD::Muon::TrackParticleType::Primary);
251 if (input.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
252 track = input.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
253 if (!track) return StatusCode::SUCCESS; // don't treat SAF muons without CB track further
254 }
255 else {
256 track = input.trackParticle(xAOD::Muon::TrackParticleType::Primary);
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 type: " << input.muonType());
303 ATH_MSG_INFO( "MUON quality:" << input.quality());
304 ATH_MSG_INFO( "MUON bHit: " << static_cast<int>( nBLHits ));
305 ATH_MSG_INFO( "MUON pHit: " << static_cast<int>( nPixHits ));
306 ATH_MSG_INFO( "MUON pDead:" << static_cast<int>( nPixelDeadSensors ));
307 ATH_MSG_INFO( "MUON pHole:" << static_cast<int>( nPixHoles ));
308 ATH_MSG_INFO( "MUON sHit: " << static_cast<int>( nSCTHits));
309 ATH_MSG_INFO( "MUON sDead:" << static_cast<int>( nSCTDeadSensors ));
310 ATH_MSG_INFO( "MUON sHole:" << static_cast<int>( nSCTHoles ));
311 ATH_MSG_INFO( "MUON tHit: " << static_cast<int>( nTRTHits ));
312 ATH_MSG_INFO( "MUON tOut: " << static_cast<int>( nTRTOutliers ));
313
314 const xAOD::TrackParticle* idtrack =
315 input.trackParticle( xAOD::Muon::TrackParticleType::InnerDetectorTrackParticle );
316
317 if ( !idtrack) {
318 ATH_MSG_VERBOSE( "No ID track!! " );
319 } else {
320 ATH_MSG_VERBOSE( "ID track pt: " << idtrack->pt());
321 }
322 }
323
324 if ( !m_force_noMuId && !m_muonSelectionToolBaseline->accept(input)) return StatusCode::SUCCESS;
325
326 if (input.pt() <= ptcut || std::abs(input.eta()) >= etacut) return StatusCode::SUCCESS;
327
328 if (m_mubaselinez0>0. && std::abs(acc_z0sinTheta(input))>m_mubaselinez0) return StatusCode::SUCCESS;
329 if (m_mubaselined0sig>0. && std::abs(acc_d0sig(input))>m_mubaselined0sig) return StatusCode::SUCCESS;
330
331 //--- Do baseline isolation check
332 if ( !( m_muBaselineIso_WP.empty() ) && !( m_isoBaselineTool->accept(input) ) ) return StatusCode::SUCCESS;
333
334 dec_baseline(input) = true;
335 dec_selected(input) = 2;
336
337 //disable if (!m_muIso_WP.empty() && m_muIso_WP.find("PLV")!=std::string::npos) ATH_CHECK( m_isoToolLowPtPLV->augmentPLV(input) );
338 if (!m_muIso_WP.empty()) dec_isol(input) = bool(m_isoTool->accept(input));
339 if (!m_muIsoHighPt_WP.empty()) dec_isolHighPt(input) = bool(m_isoHighPtTool->accept(input));
340 dec_passSignalID(input) = bool(m_muonSelectionTool->accept(input));
341
342 ATH_MSG_VERBOSE("FillMuon: passed baseline selection");
343 return StatusCode::SUCCESS;
344}
345
346
347bool SUSYObjDef_xAOD::IsSignalMuon(const xAOD::Muon & input, float ptcut, float d0sigcut, float z0cut, float etacut) const
348{
349 if (!acc_baseline(input)) return false;
350 if (!acc_passSignalID(input)) return false;
351
352 if (input.pt() <= ptcut || input.pt() == 0) return false; // pT cut (might be necessary for leading muon to pass trigger)
353 if ( etacut==DUMMYDEF ){
354 if(std::abs(input.eta()) > m_muEta ) return false;
355 }
356 else if ( std::abs(input.eta()) > etacut ) return false;
357
358 if (z0cut > 0.0 && std::abs(acc_z0sinTheta(input)) > z0cut) return false; // longitudinal IP cut
359 if (acc_d0sig(input) != 0) {
360 if (d0sigcut > 0.0 && std::abs(acc_d0sig(input)) > d0sigcut) return false; // transverse IP cut
361 }
362
363 if (m_doMuIsoSignal) {
364 if ( !( (acc_isol(input) && input.pt()<m_muIsoHighPtThresh) || (acc_isolHighPt(input) && input.pt()>m_muIsoHighPtThresh)) ) return false;
365 ATH_MSG_VERBOSE( "IsSignalMuon: passed isolation");
366 }
367
368 //set HighPtMuon decoration
369 IsHighPtMuon(input);
370
371 dec_signal(input) = true;
372
373 if (m_muId == 4) { //i.e. HighPt muons
374 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
375 << " signal? " << static_cast<int>(acc_signal(input))
376 << " isolation? " << static_cast<int>(acc_isol(input))
377 << " passedHighPtCuts? " << static_cast<int>(acc_passedHighPtCuts(input)));
378 } else {
379 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
380 << " signal? " << static_cast<int>( acc_signal(input))
381 << " isolation? " << static_cast<int>( acc_isol(input)));
382 // Don't show HighPtFlag ... we didn't set it!
383 }
384
385 return acc_signal(input);
386}
387
388
390// See https://indico.cern.ch/event/371499/contribution/1/material/slides/0.pdf and
391// https://indico.cern.ch/event/397325/contribution/19/material/slides/0.pdf and
392// https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionTool
393{
394 if (input.pt() < 3e3){
395 ATH_MSG_DEBUG("No HighPt check supported for muons below 3GeV! False.");
396 dec_passedHighPtCuts(input) = false;
397 return false;
398 }
399
400 bool isHighPt=false;
401 isHighPt = bool(m_muonSelectionHighPtTool->accept(input));
402 dec_passedHighPtCuts(input) = isHighPt;
403
404 return isHighPt;
405}
406
407
408bool SUSYObjDef_xAOD::IsBadMuon(const xAOD::Muon& input, float qopcut) const
409{
410 const static SG::Decorator<char> dec_bad("bad");
411 dec_bad(input) = false;
412
413 const static SG::Decorator<char> dec_bad_highPt("bad_highPt");
414 dec_bad_highPt(input) = false;
415
416 const xAOD::TrackParticle* track{nullptr};
417 if (input.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
418 track = input.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
419 if (!track) return false; // don't treat SAF muons without CB track further
420 }
421 else{
422 track = input.trackParticle(xAOD::Muon::TrackParticleType::Primary);
423 if (!track){
424 ATH_MSG_WARNING("Non-SAF muon without a track; cannot test IsBadMuon criteria");
425 return false;
426 }
427 }
428
429 float Rerr = Amg::error(track->definingParametersCovMatrix(), 4) / std::abs(track->qOverP());
430 ATH_MSG_VERBOSE( "Track momentum error (%): " << Rerr * 100 );
431 bool isbad = Rerr > qopcut;
432 bool isbadHighPt = Rerr > qopcut;
433
434 //new recommendation from MCP
435 isbad |= m_muonSelectionTool->isBadMuon(input);
436
437 //new recommendation from MCP (at HighPT)
438 isbadHighPt |= m_muonSelectionHighPtTool->isBadMuon(input);
439
440 dec_bad(input) = isbad;
441 dec_bad_highPt(input) = isbadHighPt;
442
443 ATH_MSG_VERBOSE( "MUON isbad?: " << isbad );
444 return isbad;
445}
446
447bool SUSYObjDef_xAOD::IsCosmicMuon(const xAOD::Muon& input, float z0cut, float d0cut) const
448{
449 dec_cosmic(input) = false;
450
451 const xAOD::TrackParticle* track(nullptr);
452 if (input.muonType() == xAOD::Muon::MuonType::SiliconAssociatedForwardMuon) {
453 track = input.trackParticle(xAOD::Muon::TrackParticleType::CombinedTrackParticle);
454 if (!track){
455 ATH_MSG_VERBOSE("WARNING: SAF muon without CB track found. Not possible to check cosmic muon criteria");
456 return false; // don't treat SAF muons without CB track further
457 }
458 }
459 else {
460 track = input.trackParticle(xAOD::Muon::TrackParticleType::Primary);
461 if (!track){
462 ATH_MSG_WARNING("Non-SAF muon without primary track particle found. Not possible to check cosmic muon criteria");
463 return false;
464 }
465 }
466
467 double mu_d0 = track->d0();
468 const xAOD::Vertex* pv = this->GetPrimVtx();
469 double primvertex_z = pv ? pv->z() : 0;
470 double mu_z0_exPV = track->z0() + track->vz() - primvertex_z;
471
472 bool isCosmicMuon = (std::abs(mu_z0_exPV) >= z0cut || std::abs(mu_d0) >= d0cut);
473
474 if (isCosmicMuon) {
475 ATH_MSG_VERBOSE("COSMIC PV Z = " << primvertex_z << ", track z0 = " << mu_z0_exPV << ", track d0 = " << mu_d0);
476 }
477
478 dec_cosmic(input) = isCosmicMuon;
479 return isCosmicMuon;
480}
481
482
483 float SUSYObjDef_xAOD::GetSignalMuonSF(const xAOD::Muon& mu, const bool recoSF, const bool isoSF, const bool doBadMuonHP, const bool warnOVR)
484{
485 float sf(1.);
486
487 if (recoSF) {
488 float sf_reco(1.);
489 if (m_muonEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_reco ) == CP::CorrectionCode::OutOfValidityRange) {
490 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Reco getEfficiencyScaleFactor out of validity range");
491 }
492 ATH_MSG_VERBOSE( "MuonReco ScaleFactor " << sf_reco );
493 sf *= sf_reco;
494
495 float sf_ttva(1.);
496 if(m_doTTVAsf){
497 if (m_muonTTVAEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_ttva ) == CP::CorrectionCode::OutOfValidityRange) {
498 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: TTVA getEfficiencyScaleFactor out of validity range");
499 }
500 ATH_MSG_VERBOSE( "MuonTTVA ScaleFactor " << sf_ttva );
501 sf *= sf_ttva;
502 }
503
504 float sf_badHighPt(1.);
505 if(m_muId == 4 && doBadMuonHP){
506 if (m_muonEfficiencyBMHighPtSFTool->getEfficiencyScaleFactor( mu, sf_badHighPt ) == CP::CorrectionCode::OutOfValidityRange) {
507 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: BadMuonHighPt getEfficiencyScaleFactor out of validity range");
508 }
509 ATH_MSG_VERBOSE( "MuonBadMuonHighPt ScaleFactor " << sf_badHighPt );
510 sf *= sf_badHighPt;
511 }
512 }
513
514
515 if (isoSF) {
516 float sf_iso(1.);
517 if (acc_isolHighPt(mu) && mu.pt()>m_muIsoHighPtThresh) {
518 if (m_muonHighPtIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
519 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: high-pt Iso getEfficiencyScaleFactor out of validity range");
520 }
521 } else if (acc_isol(mu) && mu.pt()<m_muIsoHighPtThresh) {
522 if (m_muonIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
523 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Iso getEfficiencyScaleFactor out of validity range");
524 }
525 }
526 ATH_MSG_VERBOSE( "MuonIso ScaleFactor " << sf_iso );
527 sf *= sf_iso;
528 }
529
530
531 dec_effscalefact(mu) = sf;
532 return sf;
533}
534
535
536double SUSYObjDef_xAOD::GetMuonTriggerEfficiency(const xAOD::Muon& mu, const std::string& trigExpr, const bool isdata) {
537
538 double eff(1.);
539
540 if (m_muonTriggerSFTool->getTriggerEfficiency(mu, eff, trigExpr, isdata) != CP::CorrectionCode::Ok) {
541 ATH_MSG_WARNING("Problem retrieving signal muon trigger efficiency for " << trigExpr );
542 }
543 else{
544 ATH_MSG_DEBUG("Got efficiency " << eff << " for " << trigExpr );
545 }
546 return eff;
547}
548
549
550double SUSYObjDef_xAOD::GetTotalMuonTriggerSF(const xAOD::MuonContainer& sfmuons, const std::string& trigExpr) {
551
552 if (trigExpr.empty() || sfmuons.empty()) return 1.;
553
554
555 double trig_sf = 1.;
556
557 int mulegs = 0;
558 const char *tmp = trigExpr.c_str();
559 while( (tmp = strstr(tmp, "mu")) ){
560 mulegs++;
561 tmp++;
562 }
563
564 bool isdimuon = (trigExpr.find("2mu") != std::string::npos);
565 bool isOR = (trigExpr.find("OR") != std::string::npos);
566
567 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
568 if (m_muonTriggerSFTool->getTriggerScaleFactor( sfmuons, trig_sf, trigExpr ) == CP::CorrectionCode::Ok) {
569 ATH_MSG_DEBUG( "MuonTrig ScaleFactor " << trig_sf );
570 }
571 else{
572 ATH_MSG_DEBUG( "MuonTrig FAILED SOMEHOW");
573 }
574 }
575 else if(mulegs!=2 && isOR){ //Case 2: not supported. Not efficiency defined for (at least) one leg. Sorry...
576 ATH_MSG_WARNING( "SF for " << trigExpr << " are only supported for two muon events!");
577 }
578 else{ //Case 3: let's go the hard way...
579 //Following https://twiki.cern.ch/twiki/bin/view/Atlas/TrigMuonEfficiency
580 std::string newtrigExpr = TString(trigExpr).Copy().ReplaceAll("HLT_2","").Data();
581
582 //redefine dimuon triggers here (2mu14 --> mu14_mu14)
583 if (isdimuon) { newtrigExpr += "_"+newtrigExpr; }
584 newtrigExpr = std::regex_replace(newtrigExpr, std::regex("HLT_"), "");
585
586 for (auto part : std::views::split(newtrigExpr, '_')) {
587 std::string mutrig(&*part.begin(), std::ranges::distance(part));
588 double dataFactor = 1.;
589 double mcFactor = 1.;
590
591 for (const xAOD::Muon* mu : sfmuons) {
592 // No need for additional trigger matching
593 dataFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, true));
594 mcFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, false));
595 }
596 if( (1-mcFactor) > 0. )
597 trig_sf *= (1-dataFactor)/(1-mcFactor);
598 }
599 }
600
601 return trig_sf;
602}
603
604
605double SUSYObjDef_xAOD::GetTotalMuonSF(const xAOD::MuonContainer& muons, const bool recoSF, const bool isoSF, const std::string& trigExpr, const bool bmhptSF) {
606 double sf(1.);
607
609 for (const xAOD::Muon* muon : muons) {
610 if( !acc_passOR(*muon) ) continue;
611 if (acc_signal(*muon)) {
612 sfmuons.push_back(muon);
613 if (recoSF || isoSF) { sf *= this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF); }
614 } else { // decorate baseline muons as well
615 if (recoSF || isoSF) { this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF, false); } //avoid OVR warnings in this case
616 }
617 }
618
619 sf *= GetTotalMuonTriggerSF(*sfmuons.asDataVector(), trigExpr);
620
621 return sf;
622}
623
624
625 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) {
626 double sf(1.);
627 //Set the new systematic variation
628 StatusCode ret = m_muonEfficiencySFTool->applySystematicVariation(systConfig);
629 if ( ret != StatusCode::SUCCESS) {
630 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors for systematic var. " << systConfig.name() );
631 }
632
633 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(systConfig);
634 if ( ret != StatusCode::SUCCESS) {
635 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors for systematic var. " << systConfig.name() );
636 }
637
638 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(systConfig);
639 if ( ret != StatusCode::SUCCESS) {
640 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors for systematic var. " << systConfig.name() );
641 }
642
643 ret = m_muonIsolationSFTool->applySystematicVariation(systConfig);
644 if ( ret != StatusCode::SUCCESS) {
645 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors for systematic var. " << systConfig.name() );
646 }
647
648 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(systConfig);
649 if ( ret != StatusCode::SUCCESS) {
650 ATH_MSG_ERROR("Cannot configure MuonHighPtIsolationScaleFactors for systematic var. " << systConfig.name() );
651 }
652
653 ret = m_muonTriggerSFTool->applySystematicVariation(systConfig);
654 if ( ret != StatusCode::SUCCESS) {
655 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors for systematic var. " << systConfig.name() );
656 }
657
658 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(systConfig);
659 if (ret != StatusCode::SUCCESS) {
660 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
661 }
662
663 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(systConfig);
664 if (ret != StatusCode::SUCCESS) {
665 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
666 }
667
668 sf = GetTotalMuonSF(muons, recoSF, isoSF, trigExpr, bmhptSF);
669
670 //Roll back to default
671 ret = m_muonEfficiencySFTool->applySystematicVariation(m_currentSyst);
672 if ( ret != StatusCode::SUCCESS) {
673 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors back to default.");
674 }
675
676 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(m_currentSyst);
677 if ( ret != StatusCode::SUCCESS) {
678 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors back to default.");
679 }
680
681 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(m_currentSyst);
682 if ( ret != StatusCode::SUCCESS) {
683 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors back to default.");
684 }
685
686 ret = m_muonIsolationSFTool->applySystematicVariation(m_currentSyst);
687 if ( ret != StatusCode::SUCCESS) {
688 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
689 }
690
691 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(m_currentSyst);
692 if ( ret != StatusCode::SUCCESS) {
693 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
694 }
695
696 ret = m_muonTriggerSFTool->applySystematicVariation(m_currentSyst);
697 if ( ret != StatusCode::SUCCESS) {
698 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors back to default.");
699 }
700
701 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(m_currentSyst);
702 if (ret != StatusCode::SUCCESS) {
703 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
704 }
705
706 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(m_currentSyst);
707 if (ret != StatusCode::SUCCESS) {
708 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
709 }
710
711 return sf;
712}
713
714}
#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:408
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:389
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:625
double GetTotalMuonTriggerSF(const xAOD::MuonContainer &sfmuons, const std::string &trigExpr) override final
Definition Muons.cxx:550
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:347
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:447
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:605
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:536
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:483
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].