ATLAS Offline Software
Loading...
Searching...
No Matches
EGInvariantMassTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3*/
4
6// EGInvariantMassTool.cxx
7// Author: Giovanni Marchiori (giovanni.marchiori@cern.ch)
9
11#include "xAODEgamma/Electron.h"
12#include "xAODMuon/Muon.h"
13
14#include "TLorentzVector.h"
15
16#include <cmath>
17#include <numbers>
18
19
20namespace DerivationFramework {
21
24{
25 if (m_sgName.key().empty()) {
26 ATH_MSG_ERROR("No SG name provided for the output of EGInvariantMassTool!");
27 return StatusCode::FAILURE;
28 }
29 ATH_CHECK(m_sgName.initialize());
30
31 if (!m_container1Name.key().empty()) {
32 ATH_CHECK(m_container1Name.initialize());
33 }
34 if (!m_container2Name.key().empty()) {
35 ATH_CHECK(m_container2Name.initialize());
36 }
37 if (!m_pt1BranchName.key().empty()) {
38 ATH_CHECK(m_pt1BranchName.initialize());
39 }
40 if (!m_eta1BranchName.key().empty()) {
41 ATH_CHECK(m_eta1BranchName.initialize());
42 }
43 if (!m_phi1BranchName.key().empty()) {
44 ATH_CHECK(m_phi1BranchName.initialize());
45 }
46 if (!m_pt2BranchName.key().empty()) {
47 ATH_CHECK(m_pt2BranchName.initialize());
48 }
49 if (!m_eta2BranchName.key().empty()) {
50 ATH_CHECK(m_eta2BranchName.initialize());
51 }
52 if (!m_phi2BranchName.key().empty()) {
53 ATH_CHECK(m_phi2BranchName.initialize());
54 }
55
56 ATH_CHECK(initializeParser({ m_expression1, m_expression2 }));
57
58 return StatusCode::SUCCESS;
59}
60
61StatusCode
62EGInvariantMassTool::addBranches(const EventContext& ctx) const
63{
64
66
67 // create the vector which will hold the values invariant masses
68 auto masses = std::make_unique<std::vector<float>>();
69 // compute the invariant mass values
70 ATH_CHECK(getInvariantMasses(ctx, *masses));
71
72 ATH_CHECK(writeHandle.record(std::move(masses)));
73
74 return StatusCode::SUCCESS;
75}
76
77StatusCode
79 std::vector<float>& masses) const
80{
81 // Get optional payload
82 const std::vector<float>* pt1 = nullptr;
83 if (!m_pt1BranchName.key().empty()) {
85 pt1 = readHandle.ptr();
86 }
87 const std::vector<float>* pt2 = nullptr;
88 if (!m_pt2BranchName.key().empty()) {
90 pt2 = readHandle.ptr();
91 }
92
93 const std::vector<float>* eta1 = nullptr;
94 if (!m_eta1BranchName.key().empty()) {
96 eta1 = readHandle.ptr();
97 }
98 const std::vector<float>* eta2 = nullptr;
99 if (!m_eta2BranchName.key().empty()) {
101 eta2 = readHandle.ptr();
102 }
103
104 const std::vector<float>* phi1 = nullptr;
105 if (!m_phi1BranchName.key().empty()) {
107 phi1 = readHandle.ptr();
108 }
109 const std::vector<float>* phi2 = nullptr;
110 if (!m_phi2BranchName.key().empty()) {
112 phi2 = readHandle.ptr();
113 }
114 // Get the input particles
116 ctx };
118 ctx };
119 const xAOD::IParticleContainer* particles1 = inputParticles1.ptr();
120 const xAOD::IParticleContainer* particles2 = inputParticles2.ptr();
121
122 // get the positions of the elements which pass the requirement
123 std::vector<int> entries1 = m_parser[kParser1]->evaluateAsVector();
124 unsigned int nEntries1 = entries1.size();
125 std::vector<int> entries2 = m_parser[kParser2]->evaluateAsVector();
126 unsigned int nEntries2 = entries2.size();
127
128 // if there are no particles in one of the two lists to combine,
129 // just leave the function
130 if (nEntries1 == 0 || nEntries2 == 0) {
131 return StatusCode::SUCCESS;
132 }
133
134 // check the sizes are compatible
135 if (particles1->size() != nEntries1) {
136 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
137 return StatusCode::FAILURE;
138 }
139 if (particles2->size() != nEntries2) {
140 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
141 return StatusCode::FAILURE;
142 }
143 if ((pt1 && pt1->size() != nEntries1) ||
144 ((!m_doTransverseMass || (m_mindR > 0.0)) && eta1 &&
145 eta1->size() != nEntries1) ||
146 (phi1 && phi1->size() != nEntries1)) {
147 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
148 return StatusCode::FAILURE;
149 }
150 if ((pt2 && pt2->size() != nEntries2) ||
151 ((!m_doTransverseMass || (m_mindR > 0.0)) && eta2 &&
152 eta2->size() != nEntries2) ||
153 (phi2 && phi2->size() != nEntries2)) {
154 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
155 return StatusCode::FAILURE;
156 }
157
158 // Double loop to get the pairs for which the mass should be calculated
159 unsigned int outerIt, innerIt;
160 std::vector<std::vector<int>> pairs;
161 for (outerIt = 0; outerIt < nEntries1; ++outerIt) {
162 for (innerIt = 0; innerIt < nEntries2; ++innerIt) {
163 std::vector<int> tmpPair;
164 if (entries1[outerIt] == 1 && entries2[innerIt] == 1) {
165 tmpPair.push_back(outerIt);
166 tmpPair.push_back(innerIt);
167 pairs.push_back(std::move(tmpPair));
168 }
169 }
170 }
171
172 // since IParticle interface does not provide charge() method
173 // we need to identify the particle type in case we want to check
174 // its charge (through a type cast)
177 if (m_checkCharge) {
178 type1 = ((*particles1)[0])->type();
179 type2 = ((*particles2)[0])->type();
180 if ((type1 != xAOD::Type::Electron && type1 != xAOD::Type::Muon) ||
181 (type2 != xAOD::Type::Electron && type2 != xAOD::Type::Muon)) {
183 "Cannot check charge for particles not of type electron or muon");
184 return StatusCode::FAILURE;
185 }
186 }
187
188 for (const auto& pair : pairs) {
189 unsigned int first = pair[0];
190 unsigned int second = pair[1];
191 float apt1 = pt1 ? (*pt1)[first] : ((*particles1)[first])->p4().Pt();
192 float apt2 = pt2 ? (*pt2)[second] : ((*particles2)[second])->p4().Pt();
193 float aeta1(-999.), aeta2(-999.);
194 if (!m_doTransverseMass || (m_mindR > 0.0)) {
195 aeta1 = eta1 ? (*eta1)[first] : ((*particles1)[first])->p4().Eta();
196 aeta2 = eta2 ? (*eta2)[second] : ((*particles2)[second])->p4().Eta();
197 }
198 float aphi1 = phi1 ? (*phi1)[first] : ((*particles1)[first])->p4().Phi();
199 float aphi2 = phi2 ? (*phi2)[second] : ((*particles2)[second])->p4().Phi();
200
201 if (m_mindR > 0.0) {
202 float deta = aeta1 - aeta2;
203 float dphi = std::abs(aphi1 - aphi2);
204 if (dphi > std::numbers::pi) {
205 dphi = (2*std::numbers::pi) - dphi;
206 }
207 if (std::sqrt(deta * deta + dphi * dphi) < m_mindR) {
208 continue;
209 }
210 }
211
212 if (m_checkCharge) {
213 float q1(0.), q2(0.);
214 if (type1 == xAOD::Type::Electron) {
215 q1 = ((xAOD::Electron*)((*particles1)[first]))->charge();
216 } else if (type1 == xAOD::Type::Muon) {
217 q1 = ((xAOD::Muon*)((*particles1)[first]))
218 ->trackParticle(xAOD::Muon::TrackParticleType::Primary)
219 ->charge();
220 }
221 if (type2 == xAOD::Type::Electron) {
222 q2 = ((xAOD::Electron*)((*particles2)[second]))->charge();
223 } else if (type2 == xAOD::Type::Muon) {
224 q2 = ((xAOD::Muon*)((*particles2)[second]))
225 ->trackParticle(xAOD::Muon::TrackParticleType::Primary)
226 ->charge();
227 }
228 if (q1 * q2 > 0.) {
229 continue;
230 }
231 }
232 TLorentzVector v1, v2, v;
233 if (m_doTransverseMass) {
234 v1.SetPtEtaPhiM(apt1, 0., aphi1, m_mass1Hypothesis);
235 v2.SetPtEtaPhiM(apt2, 0., aphi2, m_mass2Hypothesis);
236 } else {
237 v1.SetPtEtaPhiM(apt1, aeta1, aphi1, m_mass1Hypothesis);
238 v2.SetPtEtaPhiM(apt2, aeta2, aphi2, m_mass2Hypothesis);
239 }
240 float mass = (v1 + v2).M();
241 masses.push_back(mass);
242 }
243 return StatusCode::SUCCESS;
244}
245} // end namespace DerivationFramework
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x,...)
#define ATH_MSG_WARNING(x,...)
size_type size() const noexcept
Returns the number of elements in the collection.
SG::ReadHandleKey< std::vector< float > > m_eta1BranchName
SG::ReadHandleKey< std::vector< float > > m_pt1BranchName
SG::ReadHandleKey< xAOD::IParticleContainer > m_container1Name
SG::ReadHandleKey< xAOD::IParticleContainer > m_container2Name
SG::WriteHandleKey< std::vector< float > > m_sgName
SG::ReadHandleKey< std::vector< float > > m_phi1BranchName
StatusCode getInvariantMasses(const EventContext &ctx, std::vector< float > &) const
virtual StatusCode initialize() override final
SG::ReadHandleKey< std::vector< float > > m_eta2BranchName
Gaudi::Property< std::string > m_expression2
SG::ReadHandleKey< std::vector< float > > m_pt2BranchName
SG::ReadHandleKey< std::vector< float > > m_phi2BranchName
virtual StatusCode addBranches(const EventContext &ctx) const override final
Gaudi::Property< std::string > m_expression1
const_pointer_type ptr()
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
STL class.
THE reconstruction tool.
::StatusCode StatusCode
StatusCode definition for legacy code.
ObjectType
Type of objects that have a representation in the xAOD EDM.
Definition ObjectType.h:32
@ Other
An object not falling into any of the other categories.
Definition ObjectType.h:34
@ Muon
The object is a muon.
Definition ObjectType.h:48
@ Electron
The object is an electron.
Definition ObjectType.h:46
Muon_v1 Muon
Reference the current persistent version:
Electron_v1 Electron
Definition of the current "egamma version".
DataVector< IParticle > IParticleContainer
Simple convenience declaration of IParticleContainer.