ATLAS Offline Software
Loading...
Searching...
No Matches
L0MuonSmearingAlg.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#include "L0MuonSmearingAlg.h"
6
8
9#include "TruthTrackSmearer.h"
10
11#include "TH1.h"
12
13#include <cstdint>
14#include <cmath>
15
16namespace L0Muon {
17
18L0MuonSmearingAlg::L0MuonSmearingAlg(const std::string& name, ISvcLocator* pSvcLocator)
19: AthReentrantAlgorithm(name, pSvcLocator) {}
20
21
23
24
26 ATH_MSG_INFO("Initializing " << name() << "...");
27
29 ATH_CHECK(m_outputMuonRoIKey.initialize());
30
31 ATH_CHECK(m_rndmSvc.retrieve());
32
33 ATH_MSG_INFO("########## L0MuonSmearingAlg Configurations are ########## ");
34 ATH_MSG_INFO("------- InputTruthParticleKey: " << m_inputTruthParticleKey.key());
35 ATH_MSG_INFO("------- OutputMuonRoIKey: "<< m_outputMuonRoIKey.key());
36 ATH_MSG_INFO("########## L0MuonSmearingAlg Configurations: That's it. ########## ");
37
38 // configure the Smearer
39 ATHRNG::RNGWrapper* rngWrapper = m_rndmSvc->getEngine(this);
40 m_mySmearer = std::make_unique<TruthTrackSmearer>(rngWrapper);
41
42 if (!m_monTool.empty()) ATH_CHECK(m_monTool.retrieve());
43 return StatusCode::SUCCESS;
44}
45
46
48 ATH_MSG_INFO ("Finalizing " << name() << "...");
49 return StatusCode::SUCCESS;
50}
51
52
53StatusCode L0MuonSmearingAlg::execute(const EventContext& ctx) const {
54 ATH_MSG_DEBUG ("Executing " << name() << "...");
55
57 const xAOD::TruthParticleContainer* inputTruth = inputTruth_handle.cptr();
58 if (not inputTruth) {
59 ATH_MSG_FATAL("Unable to retrieve input truth particle of " << m_inputTruthParticleKey.key());
60 return StatusCode::FAILURE;
61 }
62
64 ATH_CHECK(outputRoI_handle.record(std::make_unique<xAOD::MuonRoIContainer>(), std::make_unique<xAOD::MuonRoIAuxContainer>()));
65 auto outputRoIs = outputRoI_handle.ptr();
66
67 int n_input_tracks=0;
68 int n_output_tracks=0;
69 ATH_MSG_DEBUG("Found " << inputTruth->size() << " input truth particles of " << m_inputTruthParticleKey.key());
70
71 for (const auto* part : *inputTruth) {
72 // only muon is used
73 if (part->pdgId() != 13 && part->pdgId() != -13) continue;
74 // Minimum pT cut for 2 GeV
75 if (part->pt() < 2000.) continue; // MeV
76 // only undecayed physical particle
77 if (part->status() != 1) continue;
78 // eta within 3.0
79 if (std::abs(part->eta()) > 3.0) continue;
80
81 ATH_MSG_DEBUG("New Truth Muon: phi=" << part->phi()
82 << " eta=" << part->eta()
83 << " pT=" << part->pt() / 1000.
84 << "(GeV) q/pT=" << part->charge() * 1000. / part->pt()
85 << "(1/GeV) PDGID=" << part->pdgId()
86 << " status=" << part->status());
87 n_input_tracks++;
88
89 if (!m_monTool.empty()) {
90 auto track_input_eta = Monitored::Scalar<float>("track_input_eta", part->eta());
91 auto track_input_pt = Monitored::Scalar<float>("track_input_pt", part->pt() / 1000.);
92 auto track_input_phi = Monitored::Scalar<float>("track_input_phi", part->phi());
93 auto track_input_curv = Monitored::Scalar<float>("track_input_curv", part->charge() * 1000. / part->pt());
94 auto monitorIt = Monitored::Group(m_monTool, track_input_eta, track_input_pt, track_input_phi, track_input_curv);
95 }
96
97 float qoverPt = part->charge() / part->pt(); // in MeV
98 L0MuonTrack otrack;
99 if (m_mySmearer->emulateL0MuonTrack(qoverPt, part->eta(), part->phi(), otrack) == false) { // smearing here
100 ATH_MSG_DEBUG("Killed by the efficiency: q/pt=" << qoverPt * 1000. << " (1/GeV)");
101 continue; // false means the truth muon is killed by the emulated efficiency
102 }
103
104 n_output_tracks++;
105
106 ATH_MSG_DEBUG("L0Muon Track: phi=" << otrack.phi()
107 << " eta=" << otrack.eta()
108 << " pT=" << 1. / std::abs(otrack.invpt() * 1000.)
109 << "(GeV) q/pT=" << 1000. * otrack.invpt() << "(1/GeV)");
110
111 if (!m_monTool.empty()) {
112 auto track_output_eta = Monitored::Scalar<float>("track_output_eta", otrack.eta());
113 auto track_output_pt = Monitored::Scalar<float>("track_output_pt", 1./ std::abs(otrack.invpt() * 1000.));
114 auto track_output_phi = Monitored::Scalar<float>("track_output_phi", otrack.phi());
115 auto track_output_curv = Monitored::Scalar<float>("track_output_curv", otrack.invpt() * 1000.);
116 auto monitorIt = Monitored::Group(m_monTool, track_output_eta, track_output_pt, track_output_phi, track_output_curv);
117 }
118
119 // RoI creation
120 outputRoIs->push_back(std::make_unique<xAOD::MuonRoI>());
121
122 // To fill RoI contents, below converts from floating to bit-wise values.
123 static constexpr float PHI_ROISIZE = TMath::TwoPi() / static_cast<float>(xAOD::MuonRoI::PHI_MASK); // phi divided by 9 bits
124 static constexpr float ETA_ROISIZE = 5.4 / static_cast<float>(xAOD::MuonRoI::ETA_MASK); // eta divided by 14 bits
125 static constexpr float PT_ROISIZE = 127.5 / static_cast<float>(xAOD::MuonRoI::PT_MASK); // 0.5 GeV width for 0-128 GeV (8 bits)
126
127 uint32_t phiword = uint32_t((otrack.phi()+TMath::Pi()) / PHI_ROISIZE); // phi defined from 0 to 2pi in MuonRoI, instead of -pi to pi
128 uint32_t etaword = uint32_t((otrack.eta() + 2.7) / ETA_ROISIZE); // -2.7 to 2.7 in MuonRoI.
129 uint32_t ptword = static_cast<uint32_t>(1. / std::abs(otrack.invpt() * 1000.) / PT_ROISIZE);
130 if (ptword > 0xff) ptword = 0xff;
131
132 // to still input eta and phi for initialize, not calculated from RoIword
133 float roi_eta = etaword * ETA_ROISIZE - 2.7;
134 float roi_phi = phiword * PHI_ROISIZE - TMath::Pi();
135
136 // construct roiWord (23th bit is charge information.)
137 uint32_t roiword = (ptword<<24) | ((otrack.invpt() > 0)<<23) | (phiword<<14) | etaword;
138
139 uint32_t extraword = (static_cast<uint32_t>(0x1)<<31) | (((ptword>>1) + 0x2) & 0xf); // for the time being...
140
141 std::string emu_thr_name = "L0_MUx";
142 float thrvalue = static_cast<float>(((ptword>>1) + 0x2) & 0xf);
143 outputRoIs->back()->initialize(roiword, roi_eta, roi_phi, emu_thr_name, thrvalue, extraword);
144 if (outputRoIs->back()->pt() == 0.){
145 ATH_MSG_WARNING("L0MuonRoI: pT = 0");
146 continue;
147 }
148 ATH_MSG_DEBUG("L0MuonRoI: phi = " << roi_phi << " (0x" << std::hex << phiword << std::dec << "), "
149 << "eta = " << roi_eta << " (0x" << std::hex << etaword << std::dec << "), "
150 << "pT = " << outputRoIs->back()->pt() << " (GeV) (0x" << std::hex << ptword << std::dec << "), "
151 << "q/pT= " << ((otrack.invpt() > 0) ? 1. : -1.) / outputRoIs->back()->pt());
152
153 if (!m_monTool.empty()) {
154 auto roi_output_eta = Monitored::Scalar<float>("roi_output_eta", outputRoIs->back()->eta());
155 auto roi_output_phi = Monitored::Scalar<float>("roi_output_phi", outputRoIs->back()->phi());
156 auto roi_output_pt = Monitored::Scalar<float>("roi_output_pt", outputRoIs->back()->pt());
157 auto roi_output_curv = Monitored::Scalar<float>("roi_output_curv", (outputRoIs->back()->getCharge() > 0 ? 1. : -1.)/outputRoIs->back()->pt());
158
159 auto delta_eta = Monitored::Scalar<float>("delta_eta", outputRoIs->back()->eta() - part->eta());
160 auto delta_phi = Monitored::Scalar<float>("delta_phi", TVector2::Phi_mpi_pi(outputRoIs->back()->phi() - (part->phi())));
161 auto pt0 = part->pt();
162 if (pt0 == 0.) pt0 = 1e-9; //set minimum value to avoid div-by-zero
163 //units of outputRoIs->back()->pt() ?? something looks wrong here, division takes precedence over subtraction
164 auto delta_pt = Monitored::Scalar<float>("delta_pt", (outputRoIs->back()->pt() - pt0/1000.) / (pt0/1000.));
165 //
166 auto delta_curv = Monitored::Scalar<float>("delta_curv", ((outputRoIs->back()->getCharge() == 1 ? 1. : -1.)/outputRoIs->back()->pt() - (part->charge()*1000./pt0)) / (part->charge()*1000./pt0));
167
168 auto monitorIt = Monitored::Group(m_monTool, roi_output_eta, roi_output_pt, roi_output_phi, roi_output_curv,
169 delta_eta, delta_phi, delta_pt, delta_curv);
170 }
171 }
172
173 ATH_MSG_DEBUG ("Result: Number of input truth muons= " << n_input_tracks << " , smeared tracks= "<< n_output_tracks);
174
175 return StatusCode::SUCCESS;
176}
177
178
179} // end of namespace
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_FATAL(x)
#define ATH_MSG_INFO(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
A wrapper class for event-slot-local random engines.
Definition RNGWrapper.h:56
An algorithm that can be simultaneously executed in multiple threads.
size_type size() const noexcept
Returns the number of elements in the collection.
SG::WriteHandleKey< xAOD::MuonRoIContainer > m_outputMuonRoIKey
std::unique_ptr< TruthTrackSmearer > m_mySmearer
ToolHandle< GenericMonitoringTool > m_monTool
virtual StatusCode execute(const EventContext &ctx) const override
virtual StatusCode initialize() override
ServiceHandle< IAthRNGSvc > m_rndmSvc
Random number generator engine.
SG::ReadHandleKey< xAOD::TruthParticleContainer > m_inputTruthParticleKey
virtual StatusCode finalize() override
L0MuonSmearingAlg(const std::string &name, ISvcLocator *pSvcLocator)
float phi() const
Definition L0MuonTrack.h:20
double invpt() const
Definition L0MuonTrack.h:18
float eta() const
Definition L0MuonTrack.h:19
Group of local monitoring quantities and retain correlation when filling histograms
Declare a monitored scalar variable.
const_pointer_type cptr()
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
static constexpr uint32_t ETA_MASK
constants to decode RoI word for Run 4+
Definition MuonRoI_v1.h:147
static constexpr uint32_t PT_MASK
Definition MuonRoI_v1.h:149
static constexpr uint32_t PHI_MASK
Definition MuonRoI_v1.h:148
TruthParticleContainer_v1 TruthParticleContainer
Declare the latest version of the truth particle container.