ATLAS Offline Software
Loading...
Searching...
No Matches
EGInvariantMassTool.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 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#include <cmath>
14using std::abs;
15using std::sqrt;
16
17#include "TLorentzVector.h"
18
19namespace DerivationFramework {
20
23{
24 if (m_sgName.key().empty()) {
25 ATH_MSG_ERROR("No SG name provided for the output of EGInvariantMassTool!");
26 return StatusCode::FAILURE;
27 }
28 ATH_CHECK(m_sgName.initialize());
29
30 if (!m_container1Name.key().empty()) {
31 ATH_CHECK(m_container1Name.initialize());
32 }
33 if (!m_container2Name.key().empty()) {
34 ATH_CHECK(m_container2Name.initialize());
35 }
36 if (!m_pt1BranchName.key().empty()) {
37 ATH_CHECK(m_pt1BranchName.initialize());
38 }
39 if (!m_eta1BranchName.key().empty()) {
40 ATH_CHECK(m_eta1BranchName.initialize());
41 }
42 if (!m_phi1BranchName.key().empty()) {
43 ATH_CHECK(m_phi1BranchName.initialize());
44 }
45 if (!m_pt2BranchName.key().empty()) {
46 ATH_CHECK(m_pt2BranchName.initialize());
47 }
48 if (!m_eta2BranchName.key().empty()) {
49 ATH_CHECK(m_eta2BranchName.initialize());
50 }
51 if (!m_phi2BranchName.key().empty()) {
52 ATH_CHECK(m_phi2BranchName.initialize());
53 }
54
55 ATH_CHECK(initializeParser({ m_expression1, m_expression2 }));
56
57 return StatusCode::SUCCESS;
58}
59
60StatusCode
61EGInvariantMassTool::addBranches(const EventContext& ctx) const
62{
63
65
66 // create the vector which will hold the values invariant masses
67 auto masses = std::make_unique<std::vector<float>>();
68 // compute the invariant mass values
69 ATH_CHECK(getInvariantMasses(ctx, *masses));
70
71 ATH_CHECK(writeHandle.record(std::move(masses)));
72
73 return StatusCode::SUCCESS;
74}
75
76StatusCode
78 std::vector<float>& masses) const
79{
80 // Get optional payload
81 const std::vector<float>* pt1 = nullptr;
82 if (!m_pt1BranchName.key().empty()) {
84 pt1 = readHandle.ptr();
85 }
86 const std::vector<float>* pt2 = nullptr;
87 if (!m_pt2BranchName.key().empty()) {
89 pt2 = readHandle.ptr();
90 }
91
92 const std::vector<float>* eta1 = nullptr;
93 if (!m_eta1BranchName.key().empty()) {
95 eta1 = readHandle.ptr();
96 }
97 const std::vector<float>* eta2 = nullptr;
98 if (!m_eta2BranchName.key().empty()) {
100 eta2 = readHandle.ptr();
101 }
102
103 const std::vector<float>* phi1 = nullptr;
104 if (!m_phi1BranchName.key().empty()) {
106 phi1 = readHandle.ptr();
107 }
108 const std::vector<float>* phi2 = nullptr;
109 if (!m_phi2BranchName.key().empty()) {
111 phi2 = readHandle.ptr();
112 }
113 // Get the input particles
115 ctx };
117 ctx };
118 const xAOD::IParticleContainer* particles1 = inputParticles1.ptr();
119 const xAOD::IParticleContainer* particles2 = inputParticles2.ptr();
120
121 // get the positions of the elements which pass the requirement
122 std::vector<int> entries1 = m_parser[kParser1]->evaluateAsVector();
123 unsigned int nEntries1 = entries1.size();
124 std::vector<int> entries2 = m_parser[kParser2]->evaluateAsVector();
125 unsigned int nEntries2 = entries2.size();
126
127 // if there are no particles in one of the two lists to combine,
128 // just leave the function
129 if (nEntries1 == 0 || nEntries2 == 0) {
130 return StatusCode::SUCCESS;
131 }
132
133 // check the sizes are compatible
134 if (particles1->size() != nEntries1) {
135 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
136 return StatusCode::FAILURE;
137 }
138 if (particles2->size() != nEntries2) {
139 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
140 return StatusCode::FAILURE;
141 }
142 if ((pt1 && pt1->size() != nEntries1) ||
143 ((!m_doTransverseMass || (m_mindR > 0.0)) && eta1 &&
144 eta1->size() != nEntries1) ||
145 (phi1 && phi1->size() != nEntries1)) {
146 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
147 return StatusCode::FAILURE;
148 }
149 if ((pt2 && pt2->size() != nEntries2) ||
150 ((!m_doTransverseMass || (m_mindR > 0.0)) && eta2 &&
151 eta2->size() != nEntries2) ||
152 (phi2 && phi2->size() != nEntries2)) {
153 ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
154 return StatusCode::FAILURE;
155 }
156
157 // Double loop to get the pairs for which the mass should be calculated
158 unsigned int outerIt, innerIt;
159 std::vector<std::vector<int>> pairs;
160 for (outerIt = 0; outerIt < nEntries1; ++outerIt) {
161 for (innerIt = 0; innerIt < nEntries2; ++innerIt) {
162 std::vector<int> tmpPair;
163 if (entries1[outerIt] == 1 && entries2[innerIt] == 1) {
164 tmpPair.push_back(outerIt);
165 tmpPair.push_back(innerIt);
166 pairs.push_back(tmpPair);
167 }
168 }
169 }
170
171 // since IParticle interface does not provide charge() method
172 // we need to identify the particle type in case we want to check
173 // its charge (through a type cast)
176 if (m_checkCharge) {
177 type1 = ((*particles1)[0])->type();
178 type2 = ((*particles2)[0])->type();
179 if ((type1 != xAOD::Type::Electron && type1 != xAOD::Type::Muon) ||
180 (type2 != xAOD::Type::Electron && type2 != xAOD::Type::Muon)) {
182 "Cannot check charge for particles not of type electron or muon");
183 return StatusCode::FAILURE;
184 }
185 }
186
187 for (const auto& pair : pairs) {
188 unsigned int first = pair[0];
189 unsigned int second = pair[1];
190 float apt1 = pt1 ? (*pt1)[first] : ((*particles1)[first])->p4().Pt();
191 float apt2 = pt2 ? (*pt2)[second] : ((*particles2)[second])->p4().Pt();
192 float aeta1(-999.), aeta2(-999.);
193 if (!m_doTransverseMass || (m_mindR > 0.0)) {
194 aeta1 = eta1 ? (*eta1)[first] : ((*particles1)[first])->p4().Eta();
195 aeta2 = eta2 ? (*eta2)[second] : ((*particles2)[second])->p4().Eta();
196 }
197 float aphi1 = phi1 ? (*phi1)[first] : ((*particles1)[first])->p4().Phi();
198 float aphi2 = phi2 ? (*phi2)[second] : ((*particles2)[second])->p4().Phi();
199
200 if (m_mindR > 0.0) {
201 float deta = aeta1 - aeta2;
202 float dphi = abs(aphi1 - aphi2);
203 if (dphi > TMath::Pi()) {
204 dphi = TMath::TwoPi() - dphi;
205 }
206 if (sqrt(deta * deta + dphi * dphi) < m_mindR) {
207 continue;
208 }
209 }
210
211 if (m_checkCharge) {
212 float q1(0.), q2(0.);
213 if (type1 == xAOD::Type::Electron) {
214 q1 = ((xAOD::Electron*)((*particles1)[first]))->charge();
215 } else if (type1 == xAOD::Type::Muon) {
216 q1 = ((xAOD::Muon*)((*particles1)[first]))
217 ->primaryTrackParticle()
218 ->charge();
219 }
220 if (type2 == xAOD::Type::Electron) {
221 q2 = ((xAOD::Electron*)((*particles2)[second]))->charge();
222 } else if (type2 == xAOD::Type::Muon) {
223 q2 = ((xAOD::Muon*)((*particles2)[second]))
224 ->primaryTrackParticle()
225 ->charge();
226 }
227 if (q1 * q2 > 0.) {
228 continue;
229 }
230 }
231 TLorentzVector v1, v2, v;
232 if (m_doTransverseMass) {
233 v1.SetPtEtaPhiM(apt1, 0., aphi1, m_mass1Hypothesis);
234 v2.SetPtEtaPhiM(apt2, 0., aphi2, m_mass2Hypothesis);
235 } else {
236 v1.SetPtEtaPhiM(apt1, aeta1, aphi1, m_mass1Hypothesis);
237 v2.SetPtEtaPhiM(apt2, aeta2, aphi2, m_mass2Hypothesis);
238 }
239 float mass = (v1 + v2).M();
240 masses.push_back(mass);
241 }
242 return StatusCode::SUCCESS;
243}
244} // 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.