ATLAS Offline Software
Loading...
Searching...
No Matches
Muons.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 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
183 std::pair<xAOD::MuonContainer*, xAOD::ShallowAuxContainer*> shallowcopy = xAOD::shallowCopyContainer(*muons);
184 copy = shallowcopy.first;
185 copyaux = shallowcopy.second;
186 bool setLinks = xAOD::setOriginalObjectLink(*muons, *copy);
187 if (!setLinks) {
188 ATH_MSG_WARNING("Failed to set original object links on " << muonkey);
189 }
190 } else { // use the user-supplied collection instead
191 ATH_MSG_DEBUG("Not retrieving muon collection, using existing one provided by user");
192 muons=copy; // this does nothing
193 }
194
195 for (const auto muon : *copy) {
200 }
201 if (recordSG) {
202 ATH_CHECK( evtStore()->record(copy, "STCalib" + muonkey + m_currentSyst.name()) );
203 ATH_CHECK( evtStore()->record(copyaux, "STCalib" + muonkey + m_currentSyst.name() + "Aux.") );
204 }
205 return StatusCode::SUCCESS;
206}
207
208StatusCode SUSYObjDef_xAOD::FillMuon(xAOD::Muon& input, float ptcut, float etacut) {
209
210 ATH_MSG_VERBOSE( "Starting FillMuon on mu with pt=" << input.pt() );
211
212 dec_baseline(input) = false;
213 dec_selected(input) = 0;
214 dec_signal(input) = false;
215 dec_isol(input) = false;
216 dec_isolHighPt(input) = false;
217 dec_passedHighPtCuts(input) = false;
218 dec_passSignalID(input) = false;
219
220 if (m_muEffCorrForce1D) {
221 dec_DFCommonJetDr(input) = -2.0;
222 } else if (!acc_DFCommonJetDr.isAvailable(input)) {
223 dec_dRJet(input) = -2.0;
224 }
225
226 // don't bother calibrating or computing WP
227 if ( input.pt() < 3e3 ) return StatusCode::SUCCESS;
228
229 ATH_MSG_VERBOSE( "MUON pt before calibration " << input.pt() );
230
231 ATH_MSG_VERBOSE( "MUON eta = " << input.eta() );
232 ATH_MSG_VERBOSE( "MUON type = " << input.muonType() );
233 ATH_MSG_VERBOSE( "MUON author = " << input.author() );
234
235 if (m_muonCalibTool->applyCorrection( input ) == CP::CorrectionCode::OutOfValidityRange){
236 ATH_MSG_VERBOSE("FillMuon: applyCorrection out of validity range");
237 }
238
239 ATH_MSG_VERBOSE( "MUON pt after calibration " << input.pt() );
240
241 const xAOD::EventInfo* evtInfo = nullptr;
242 ATH_CHECK( evtStore()->retrieve( evtInfo, "EventInfo" ) );
243 const xAOD::Vertex* pv = this->GetPrimVtx();
244 double primvertex_z = pv ? pv->z() : 0;
245 //const xAOD::TrackParticle* track = input.primaryTrackParticle();
247 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
248 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
249 if (!track) return StatusCode::SUCCESS; // don't treat SAF muons without CB track further
250 }
251 else {
252 track = input.primaryTrackParticle();
253 }
254
255 //impact parameters (after applyCorrection() so to have the primaryTrack links restored in old buggy samples)
256 if (track){
257 dec_z0sinTheta(input) = (track->z0() + track->vz() - primvertex_z) * TMath::Sin(input.p4().Theta());
258 } else {
259 ATH_MSG_WARNING("FillMuon: Muon of pT and eta " << input.pt() << " MeV " << input.eta() << " has no associated track");
260 }
261 //protect against exception thrown for null or negative d0sig
262 try {
263 if (track)
265 else
266 dec_d0sig(input) = -99.;
267 }
268 catch (...) {
269 float d0sigError = -99.;
270 ATH_MSG_WARNING("FillMuon : Exception caught from d0significance() calculation. Setting dummy decoration d0sig=" << d0sigError );
271 dec_d0sig(input) = d0sigError;
272 }
273
274 if (m_debug) {
275 // Summary variables in
276 // /cvmfs/atlas.cern.ch/repo/sw/ASG/AnalysisBase/2.0.3/xAODTracking/Root/TrackSummaryAccessors_v1.cxx
277
278 unsigned char nBLHits(0), nPixHits(0), nPixelDeadSensors(0), nPixHoles(0),
279 nSCTHits(0), nSCTDeadSensors(0), nSCTHoles(0), nTRTHits(0), nTRTOutliers(0);
280
281 if (track){
282 track->summaryValue( nBLHits, xAOD::numberOfBLayerHits);
283 track->summaryValue( nPixHits, xAOD::numberOfPixelHits);
284 track->summaryValue( nPixelDeadSensors, xAOD::numberOfPixelDeadSensors);
285 track->summaryValue( nPixHoles, xAOD::numberOfPixelHoles);
286
287 track->summaryValue( nSCTHits, xAOD::numberOfSCTHits);
288 track->summaryValue( nSCTDeadSensors, xAOD::numberOfSCTDeadSensors);
289 track->summaryValue( nSCTHoles, xAOD::numberOfSCTHoles);
290
291 track->summaryValue( nTRTHits, xAOD::numberOfTRTHits);
292 track->summaryValue( nTRTOutliers, xAOD::numberOfTRTOutliers);
293 }
294
295 ATH_MSG_INFO( "MUON pt: " << input.pt() );
296 ATH_MSG_INFO( "MUON eta: " << input.eta() );
297 ATH_MSG_INFO( "MUON phi: " << input.phi() );
298 ATH_MSG_INFO( "MUON comb: " << (input.muonType() == xAOD::Muon::Combined));
299 ATH_MSG_INFO( "MUON sTag: " << (input.muonType() == xAOD::Muon::SegmentTagged));
300 ATH_MSG_INFO( "MUON loose:" << (input.quality() == xAOD::Muon::Loose));
301 ATH_MSG_INFO( "MUON bHit: " << static_cast<int>( nBLHits ));
302 ATH_MSG_INFO( "MUON pHit: " << static_cast<int>( nPixHits ));
303 ATH_MSG_INFO( "MUON pDead:" << static_cast<int>( nPixelDeadSensors ));
304 ATH_MSG_INFO( "MUON pHole:" << static_cast<int>( nPixHoles ));
305 ATH_MSG_INFO( "MUON sHit: " << static_cast<int>( nSCTHits));
306 ATH_MSG_INFO( "MUON sDead:" << static_cast<int>( nSCTDeadSensors ));
307 ATH_MSG_INFO( "MUON sHole:" << static_cast<int>( nSCTHoles ));
308 ATH_MSG_INFO( "MUON tHit: " << static_cast<int>( nTRTHits ));
309 ATH_MSG_INFO( "MUON tOut: " << static_cast<int>( nTRTOutliers ));
310
311 const xAOD::TrackParticle* idtrack =
312 input.trackParticle( xAOD::Muon::InnerDetectorTrackParticle );
313
314 if ( !idtrack) {
315 ATH_MSG_VERBOSE( "No ID track!! " );
316 } else {
317 ATH_MSG_VERBOSE( "ID track pt: " << idtrack->pt());
318 }
319 }
320
321 if ( !m_force_noMuId && !m_muonSelectionToolBaseline->accept(input)) return StatusCode::SUCCESS;
322
323 if (input.pt() <= ptcut || std::abs(input.eta()) >= etacut) return StatusCode::SUCCESS;
324
325 if (m_mubaselinez0>0. && std::abs(acc_z0sinTheta(input))>m_mubaselinez0) return StatusCode::SUCCESS;
326 if (m_mubaselined0sig>0. && std::abs(acc_d0sig(input))>m_mubaselined0sig) return StatusCode::SUCCESS;
327
328 //--- Do baseline isolation check
329 if ( !( m_muBaselineIso_WP.empty() ) && !( m_isoBaselineTool->accept(input) ) ) return StatusCode::SUCCESS;
330
331 dec_baseline(input) = true;
332 dec_selected(input) = 2;
333
334 //disable if (!m_muIso_WP.empty() && m_muIso_WP.find("PLV")!=std::string::npos) ATH_CHECK( m_isoToolLowPtPLV->augmentPLV(input) );
335 if (!m_muIso_WP.empty()) dec_isol(input) = bool(m_isoTool->accept(input));
336 if (!m_muIsoHighPt_WP.empty()) dec_isolHighPt(input) = bool(m_isoHighPtTool->accept(input));
337 dec_passSignalID(input) = bool(m_muonSelectionTool->accept(input));
338
339 ATH_MSG_VERBOSE("FillMuon: passed baseline selection");
340 return StatusCode::SUCCESS;
341}
342
343
344bool SUSYObjDef_xAOD::IsSignalMuon(const xAOD::Muon & input, float ptcut, float d0sigcut, float z0cut, float etacut) const
345{
346 if (!acc_baseline(input)) return false;
347 if (!acc_passSignalID(input)) return false;
348
349 if (input.pt() <= ptcut || input.pt() == 0) return false; // pT cut (might be necessary for leading muon to pass trigger)
350 if ( etacut==DUMMYDEF ){
351 if(std::abs(input.eta()) > m_muEta ) return false;
352 }
353 else if ( std::abs(input.eta()) > etacut ) return false;
354
355 if (z0cut > 0.0 && std::abs(acc_z0sinTheta(input)) > z0cut) return false; // longitudinal IP cut
356 if (acc_d0sig(input) != 0) {
357 if (d0sigcut > 0.0 && std::abs(acc_d0sig(input)) > d0sigcut) return false; // transverse IP cut
358 }
359
360 if (m_doMuIsoSignal) {
361 if ( !( (acc_isol(input) && input.pt()<m_muIsoHighPtThresh) || (acc_isolHighPt(input) && input.pt()>m_muIsoHighPtThresh)) ) return false;
362 ATH_MSG_VERBOSE( "IsSignalMuon: passed isolation");
363 }
364
365 //set HighPtMuon decoration
366 IsHighPtMuon(input);
367
368 dec_signal(input) = true;
369
370 if (m_muId == 4) { //i.e. HighPt muons
371 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
372 << " signal? " << static_cast<int>(acc_signal(input))
373 << " isolation? " << static_cast<int>(acc_isol(input))
374 << " passedHighPtCuts? " << static_cast<int>(acc_passedHighPtCuts(input)));
375 } else {
376 ATH_MSG_VERBOSE( "IsSignalMuon: mu pt " << input.pt()
377 << " signal? " << static_cast<int>( acc_signal(input))
378 << " isolation? " << static_cast<int>( acc_isol(input)));
379 // Don't show HighPtFlag ... we didn't set it!
380 }
381
382 return acc_signal(input);
383}
384
385
387// See https://indico.cern.ch/event/371499/contribution/1/material/slides/0.pdf and
388// https://indico.cern.ch/event/397325/contribution/19/material/slides/0.pdf and
389// https://twiki.cern.ch/twiki/bin/view/Atlas/MuonSelectionTool
390{
391 if (input.pt() < 3e3){
392 ATH_MSG_DEBUG("No HighPt check supported for muons below 3GeV! False.");
393 dec_passedHighPtCuts(input) = false;
394 return false;
395 }
396
397 bool isHighPt=false;
398 isHighPt = bool(m_muonSelectionHighPtTool->accept(input));
399 dec_passedHighPtCuts(input) = isHighPt;
400
401 return isHighPt;
402}
403
404
405bool SUSYObjDef_xAOD::IsBadMuon(const xAOD::Muon& input, float qopcut) const
406{
407 const static SG::Decorator<char> dec_bad("bad");
408 dec_bad(input) = false;
409
410 const static SG::Decorator<char> dec_bad_highPt("bad_highPt");
411 dec_bad_highPt(input) = false;
412
414 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
415 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
416 if (!track) return false; // don't treat SAF muons without CB track further
417 }
418 else{
419 track = input.primaryTrackParticle();
420 if (!track){
421 ATH_MSG_WARNING("Non-SAF muon without a track; cannot test IsBadMuon criteria");
422 return false;
423 }
424 }
425
426 float Rerr = Amg::error(track->definingParametersCovMatrix(), 4) / std::abs(track->qOverP());
427 ATH_MSG_VERBOSE( "Track momentum error (%): " << Rerr * 100 );
428 bool isbad = Rerr > qopcut;
429 bool isbadHighPt = Rerr > qopcut;
430
431 //new recommendation from MCP
432 isbad |= m_muonSelectionTool->isBadMuon(input);
433
434 //new recommendation from MCP (at HighPT)
435 isbadHighPt |= m_muonSelectionHighPtTool->isBadMuon(input);
436
437 dec_bad(input) = isbad;
438 dec_bad_highPt(input) = isbadHighPt;
439
440 ATH_MSG_VERBOSE( "MUON isbad?: " << isbad );
441 return isbad;
442}
443
444bool SUSYObjDef_xAOD::IsCosmicMuon(const xAOD::Muon& input, float z0cut, float d0cut) const
445{
446 dec_cosmic(input) = false;
447
448 const xAOD::TrackParticle* track(nullptr);
449 if (input.muonType() == xAOD::Muon::SiliconAssociatedForwardMuon) {
450 track = input.trackParticle(xAOD::Muon::CombinedTrackParticle);
451 if (!track){
452 ATH_MSG_VERBOSE("WARNING: SAF muon without CB track found. Not possible to check cosmic muon criteria");
453 return false; // don't treat SAF muons without CB track further
454 }
455 }
456 else {
457 track = input.primaryTrackParticle();
458 if (!track){
459 ATH_MSG_WARNING("Non-SAF muon without primary track particle found. Not possible to check cosmic muon criteria");
460 return false;
461 }
462 }
463
464 double mu_d0 = track->d0();
465 const xAOD::Vertex* pv = this->GetPrimVtx();
466 double primvertex_z = pv ? pv->z() : 0;
467 double mu_z0_exPV = track->z0() + track->vz() - primvertex_z;
468
469 bool isCosmicMuon = (std::abs(mu_z0_exPV) >= z0cut || std::abs(mu_d0) >= d0cut);
470
471 if (isCosmicMuon) {
472 ATH_MSG_VERBOSE("COSMIC PV Z = " << primvertex_z << ", track z0 = " << mu_z0_exPV << ", track d0 = " << mu_d0);
473 }
474
475 dec_cosmic(input) = isCosmicMuon;
476 return isCosmicMuon;
477}
478
479
480 float SUSYObjDef_xAOD::GetSignalMuonSF(const xAOD::Muon& mu, const bool recoSF, const bool isoSF, const bool doBadMuonHP, const bool warnOVR)
481{
482 float sf(1.);
483
484 if (recoSF) {
485 float sf_reco(1.);
486 if (m_muonEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_reco ) == CP::CorrectionCode::OutOfValidityRange) {
487 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Reco getEfficiencyScaleFactor out of validity range");
488 }
489 ATH_MSG_VERBOSE( "MuonReco ScaleFactor " << sf_reco );
490 sf *= sf_reco;
491
492 float sf_ttva(1.);
493 if(m_doTTVAsf){
494 if (m_muonTTVAEfficiencySFTool->getEfficiencyScaleFactor( mu, sf_ttva ) == CP::CorrectionCode::OutOfValidityRange) {
495 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: TTVA getEfficiencyScaleFactor out of validity range");
496 }
497 ATH_MSG_VERBOSE( "MuonTTVA ScaleFactor " << sf_ttva );
498 sf *= sf_ttva;
499 }
500
501 float sf_badHighPt(1.);
502 if(m_muId == 4 && doBadMuonHP){
503 if (m_muonEfficiencyBMHighPtSFTool->getEfficiencyScaleFactor( mu, sf_badHighPt ) == CP::CorrectionCode::OutOfValidityRange) {
504 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: BadMuonHighPt getEfficiencyScaleFactor out of validity range");
505 }
506 ATH_MSG_VERBOSE( "MuonBadMuonHighPt ScaleFactor " << sf_badHighPt );
507 sf *= sf_badHighPt;
508 }
509 }
510
511
512 if (isoSF) {
513 float sf_iso(1.);
514 if (acc_isolHighPt(mu) && mu.pt()>m_muIsoHighPtThresh) {
515 if (m_muonHighPtIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
516 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: high-pt Iso getEfficiencyScaleFactor out of validity range");
517 }
518 } else if (acc_isol(mu) && mu.pt()<m_muIsoHighPtThresh) {
519 if (m_muonIsolationSFTool->getEfficiencyScaleFactor( mu, sf_iso ) == CP::CorrectionCode::OutOfValidityRange) {
520 if(warnOVR) ATH_MSG_WARNING(" GetSignalMuonSF: Iso getEfficiencyScaleFactor out of validity range");
521 }
522 }
523 ATH_MSG_VERBOSE( "MuonIso ScaleFactor " << sf_iso );
524 sf *= sf_iso;
525 }
526
527
528 dec_effscalefact(mu) = sf;
529 return sf;
530}
531
532
533double SUSYObjDef_xAOD::GetMuonTriggerEfficiency(const xAOD::Muon& mu, const std::string& trigExpr, const bool isdata) {
534
535 double eff(1.);
536
537 if (m_muonTriggerSFTool->getTriggerEfficiency(mu, eff, trigExpr, isdata) != CP::CorrectionCode::Ok) {
538 ATH_MSG_WARNING("Problem retrieving signal muon trigger efficiency for " << trigExpr );
539 }
540 else{
541 ATH_MSG_DEBUG("Got efficiency " << eff << " for " << trigExpr );
542 }
543 return eff;
544}
545
546
547double SUSYObjDef_xAOD::GetTotalMuonTriggerSF(const xAOD::MuonContainer& sfmuons, const std::string& trigExpr) {
548
549 if (trigExpr.empty() || sfmuons.empty()) return 1.;
550
551
552 double trig_sf = 1.;
553
554 int mulegs = 0;
555 const char *tmp = trigExpr.c_str();
556 while( (tmp = strstr(tmp, "mu")) ){
557 mulegs++;
558 tmp++;
559 }
560
561 bool isdimuon = (trigExpr.find("2mu") != std::string::npos);
562 bool isOR = (trigExpr.find("OR") != std::string::npos);
563
564 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
565 if (m_muonTriggerSFTool->getTriggerScaleFactor( sfmuons, trig_sf, trigExpr ) == CP::CorrectionCode::Ok) {
566 ATH_MSG_DEBUG( "MuonTrig ScaleFactor " << trig_sf );
567 }
568 else{
569 ATH_MSG_DEBUG( "MuonTrig FAILED SOMEHOW");
570 }
571 }
572 else if(mulegs!=2 && isOR){ //Case 2: not supported. Not efficiency defined for (at least) one leg. Sorry...
573 ATH_MSG_WARNING( "SF for " << trigExpr << " are only supported for two muon events!");
574 }
575 else{ //Case 3: let's go the hard way...
576 //Following https://twiki.cern.ch/twiki/bin/view/Atlas/TrigMuonEfficiency
577 std::string newtrigExpr = TString(trigExpr).Copy().ReplaceAll("HLT_2","").Data();
578
579 //redefine dimuon triggers here (2mu14 --> mu14_mu14)
580 if (isdimuon) { newtrigExpr += "_"+newtrigExpr; }
581 newtrigExpr = std::regex_replace(newtrigExpr, std::regex("HLT_"), "");
582
583 for (auto part : std::views::split(newtrigExpr, '_')) {
584 std::string mutrig(&*part.begin(), std::ranges::distance(part));
585 double dataFactor = 1.;
586 double mcFactor = 1.;
587
588 for (const xAOD::Muon* mu : sfmuons) {
589 // No need for additional trigger matching
590 dataFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, true));
591 mcFactor *= (1 - GetMuonTriggerEfficiency(*mu, "HLT_"+mutrig, false));
592 }
593 if( (1-mcFactor) > 0. )
594 trig_sf *= (1-dataFactor)/(1-mcFactor);
595 }
596 }
597
598 return trig_sf;
599}
600
601
602double SUSYObjDef_xAOD::GetTotalMuonSF(const xAOD::MuonContainer& muons, const bool recoSF, const bool isoSF, const std::string& trigExpr, const bool bmhptSF) {
603 double sf(1.);
604
606 for (const xAOD::Muon* muon : muons) {
607 if( !acc_passOR(*muon) ) continue;
608 if (acc_signal(*muon)) {
609 sfmuons.push_back(muon);
610 if (recoSF || isoSF) { sf *= this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF); }
611 } else { // decorate baseline muons as well
612 if (recoSF || isoSF) { this->GetSignalMuonSF(*muon, recoSF, isoSF, bmhptSF, false); } //avoid OVR warnings in this case
613 }
614 }
615
616 sf *= GetTotalMuonTriggerSF(*sfmuons.asDataVector(), trigExpr);
617
618 return sf;
619}
620
621
622 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) {
623 double sf(1.);
624 //Set the new systematic variation
625 StatusCode ret = m_muonEfficiencySFTool->applySystematicVariation(systConfig);
626 if ( ret != StatusCode::SUCCESS) {
627 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors for systematic var. " << systConfig.name() );
628 }
629
630 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(systConfig);
631 if ( ret != StatusCode::SUCCESS) {
632 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors for systematic var. " << systConfig.name() );
633 }
634
635 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(systConfig);
636 if ( ret != StatusCode::SUCCESS) {
637 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors for systematic var. " << systConfig.name() );
638 }
639
640 ret = m_muonIsolationSFTool->applySystematicVariation(systConfig);
641 if ( ret != StatusCode::SUCCESS) {
642 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors for systematic var. " << systConfig.name() );
643 }
644
645 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(systConfig);
646 if ( ret != StatusCode::SUCCESS) {
647 ATH_MSG_ERROR("Cannot configure MuonHighPtIsolationScaleFactors for systematic var. " << systConfig.name() );
648 }
649
650 ret = m_muonTriggerSFTool->applySystematicVariation(systConfig);
651 if ( ret != StatusCode::SUCCESS) {
652 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors for systematic var. " << systConfig.name() );
653 }
654
655 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(systConfig);
656 if (ret != StatusCode::SUCCESS) {
657 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
658 }
659
660 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(systConfig);
661 if (ret != StatusCode::SUCCESS) {
662 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) for systematic var. " << systConfig.name() );
663 }
664
665 sf = GetTotalMuonSF(muons, recoSF, isoSF, trigExpr, bmhptSF);
666
667 //Roll back to default
668 ret = m_muonEfficiencySFTool->applySystematicVariation(m_currentSyst);
669 if ( ret != StatusCode::SUCCESS) {
670 ATH_MSG_ERROR("Cannot configure MuonEfficiencyScaleFactors back to default.");
671 }
672
673 ret = m_muonEfficiencyBMHighPtSFTool->applySystematicVariation(m_currentSyst);
674 if ( ret != StatusCode::SUCCESS) {
675 ATH_MSG_ERROR("Cannot configure MuonBadMuonHighPtScaleFactors back to default.");
676 }
677
678 ret = m_muonTTVAEfficiencySFTool->applySystematicVariation(m_currentSyst);
679 if ( ret != StatusCode::SUCCESS) {
680 ATH_MSG_ERROR("Cannot configure MuonTTVAEfficiencyScaleFactors back to default.");
681 }
682
683 ret = m_muonIsolationSFTool->applySystematicVariation(m_currentSyst);
684 if ( ret != StatusCode::SUCCESS) {
685 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
686 }
687
688 ret = m_muonHighPtIsolationSFTool->applySystematicVariation(m_currentSyst);
689 if ( ret != StatusCode::SUCCESS) {
690 ATH_MSG_ERROR("Cannot configure MuonIsolationScaleFactors back to default.");
691 }
692
693 ret = m_muonTriggerSFTool->applySystematicVariation(m_currentSyst);
694 if ( ret != StatusCode::SUCCESS) {
695 ATH_MSG_ERROR("Cannot configure MuonTriggerScaleFactors back to default.");
696 }
697
698 ret = m_trigGlobalEffCorrTool_diLep->applySystematicVariation(m_currentSyst);
699 if (ret != StatusCode::SUCCESS) {
700 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
701 }
702
703 ret = m_trigGlobalEffCorrTool_multiLep->applySystematicVariation(m_currentSyst);
704 if (ret != StatusCode::SUCCESS) {
705 ATH_MSG_ERROR("Cannot configure TrigGlobalEfficiencyCorrectionTool (trigger) back to default.");
706 }
707
708 return sf;
709}
710
711}
#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.
Helper class to provide type-safe access to aux data.
Definition Decorator.h:59
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:405
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:386
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:622
double GetTotalMuonTriggerSF(const xAOD::MuonContainer &sfmuons, const std::string &trigExpr) override final
Definition Muons.cxx:547
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:344
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:444
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:602
StatusCode FillMuon(xAOD::Muon &input, const float ptcut, const float etacut) override final
Definition Muons.cxx:208
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:533
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:480
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:114
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 ...
@ 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::ConstAccessor< char > acc_isolHighPt("isolHighPt")
static const SG::Decorator< double > dec_effscalefact("effscalefact")
static const SG::Decorator< float > dec_DFCommonJetDr("DFCommonJetDr")
static const SG::Decorator< char > dec_bad("bad")
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_dRJet("dRJet")
static const SG::ConstAccessor< char > acc_passedHighPtCuts("passedHighPtCuts")
static const SG::ConstAccessor< char > acc_passSignalID("passSignalID")
static const SG::Decorator< char > dec_isLRT("isLRT")
static const SG::ConstAccessor< char > acc_signal("signal")
static const SG::Decorator< char > dec_cosmic("cosmic")
static const SG::ConstAccessor< char > acc_baseline("baseline")
static const SG::Decorator< char > dec_passedHighPtCuts("passedHighPtCuts")
static const SG::ConstAccessor< float > acc_DFCommonJetDr("DFCommonJetDr")
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_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< char > dec_selected("selected")
static const SG::Decorator< float > dec_z0sinTheta("z0sinTheta")
double d0significance(const xAOD::TrackParticle *tp, double d0_uncert_beam_spot_2)
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...
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].