ATLAS Offline Software
EGInvariantMassTool.cxx
Go to the documentation of this file.
1 /*
2  Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
3 */
4 
6 // EGInvariantMassTool.cxx, (c) ATLAS Detector software
7 // Author: Giovanni Marchiori (giovanni.marchiori@cern.ch)
9 
11 #include "xAODEgamma/Electron.h"
12 #include "xAODMuon/Muon.h"
13 #include <cmath>
14 using std::abs;
15 using std::sqrt;
16 
17 #include "TLorentzVector.h"
18 
19 namespace DerivationFramework {
20 
22  const std::string& n,
23  const IInterface* p)
25  , m_expression1("true")
26  , m_expression2("true")
27  , m_mass1Hypothesis(0.0)
28  , m_mass2Hypothesis(0.0)
29  , m_mindR(0.0)
30  , m_checkCharge(true)
31  , m_doTransverseMass(false)
32 {
33  declareInterface<DerivationFramework::IAugmentationTool>(this);
34  declareProperty("Object1Requirements", m_expression1);
35  declareProperty("Object2Requirements", m_expression2);
36  declareProperty("Mass1Hypothesis", m_mass1Hypothesis);
37  declareProperty("Mass2Hypothesis", m_mass2Hypothesis);
38  declareProperty("CheckCharge", m_checkCharge);
39  declareProperty("MinDeltaR", m_mindR);
40  declareProperty("DoTransverseMass", m_doTransverseMass);
41 }
42 
45 {
46  if (m_sgName.key().empty()) {
47  ATH_MSG_ERROR("No SG name provided for the output of EGInvariantMassTool!");
48  return StatusCode::FAILURE;
49  }
51 
52  if (!m_container1Name.key().empty()) {
53  ATH_CHECK(m_container1Name.initialize());
54  }
55  if (!m_container2Name.key().empty()) {
56  ATH_CHECK(m_container2Name.initialize());
57  }
58  if (!m_pt1BranchName.key().empty()) {
60  }
61  if (!m_eta1BranchName.key().empty()) {
63  }
64  if (!m_phi1BranchName.key().empty()) {
66  }
67  if (!m_pt2BranchName.key().empty()) {
69  }
70  if (!m_eta2BranchName.key().empty()) {
72  }
73  if (!m_phi2BranchName.key().empty()) {
75  }
76 
78 
79  return StatusCode::SUCCESS;
80 }
81 
84 {
85 
86  const EventContext& ctx = Gaudi::Hive::currentContext();
87  SG::WriteHandle<std::vector<float>> writeHandle{ m_sgName, ctx };
88 
89  // create the vector which will hold the values invariant masses
90  auto masses = std::make_unique<std::vector<float>>();
91  // compute the invariant mass values
93 
94  ATH_CHECK(writeHandle.record(std::move(masses)));
95 
96  return StatusCode::SUCCESS;
97 }
98 
101  std::vector<float>& masses) const
102 {
103  // Get optional payload
104  const std::vector<float>* pt1 = nullptr;
105  if (!m_pt1BranchName.key().empty()) {
107  pt1 = readHandle.ptr();
108  }
109  const std::vector<float>* pt2 = nullptr;
110  if (!m_pt2BranchName.key().empty()) {
112  pt2 = readHandle.ptr();
113  }
114 
115  const std::vector<float>* eta1 = nullptr;
116  if (!m_eta1BranchName.key().empty()) {
118  eta1 = readHandle.ptr();
119  }
120  const std::vector<float>* eta2 = nullptr;
121  if (!m_eta2BranchName.key().empty()) {
123  eta2 = readHandle.ptr();
124  }
125 
126  const std::vector<float>* phi1 = nullptr;
127  if (!m_phi1BranchName.key().empty()) {
129  phi1 = readHandle.ptr();
130  }
131  const std::vector<float>* phi2 = nullptr;
132  if (!m_phi2BranchName.key().empty()) {
134  phi2 = readHandle.ptr();
135  }
136  // Get the input particles
138  ctx };
140  ctx };
141  const xAOD::IParticleContainer* particles1 = inputParticles1.ptr();
142  const xAOD::IParticleContainer* particles2 = inputParticles2.ptr();
143 
144  // get the positions of the elements which pass the requirement
145  std::vector<int> entries1 = m_parser[kParser1]->evaluateAsVector();
146  unsigned int nEntries1 = entries1.size();
147  std::vector<int> entries2 = m_parser[kParser2]->evaluateAsVector();
148  unsigned int nEntries2 = entries2.size();
149 
150  // if there are no particles in one of the two lists to combine,
151  // just leave the function
152  if (nEntries1 == 0 || nEntries2 == 0) {
153  return StatusCode::SUCCESS;
154  }
155 
156  // check the sizes are compatible
157  if (particles1->size() != nEntries1) {
158  ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
159  return StatusCode::FAILURE;
160  }
161  if (particles2->size() != nEntries2) {
162  ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
163  return StatusCode::FAILURE;
164  }
165  if ((pt1 && pt1->size() != nEntries1) ||
166  ((!m_doTransverseMass || (m_mindR > 0.0)) && eta1 &&
167  eta1->size() != nEntries1) ||
168  (phi1 && phi1->size() != nEntries1)) {
169  ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
170  return StatusCode::FAILURE;
171  }
172  if ((pt2 && pt2->size() != nEntries2) ||
173  ((!m_doTransverseMass || (m_mindR > 0.0)) && eta2 &&
174  eta2->size() != nEntries2) ||
175  (phi2 && phi2->size() != nEntries2)) {
176  ATH_MSG_ERROR("Branch sizes incompatible - returning zero");
177  return StatusCode::FAILURE;
178  }
179 
180  // Double loop to get the pairs for which the mass should be calculated
181  unsigned int outerIt, innerIt;
182  std::vector<std::vector<int>> pairs;
183  for (outerIt = 0; outerIt < nEntries1; ++outerIt) {
184  for (innerIt = 0; innerIt < nEntries2; ++innerIt) {
185  std::vector<int> tmpPair;
186  if (entries1[outerIt] == 1 && entries2[innerIt] == 1) {
187  tmpPair.push_back(outerIt);
188  tmpPair.push_back(innerIt);
189  pairs.push_back(tmpPair);
190  }
191  }
192  }
193 
194  // since IParticle interface does not provide charge() method
195  // we need to identify the particle type in case we want to check
196  // its charge (through a type cast)
197  xAOD::Type::ObjectType type1 = xAOD::Type::Other;
198  xAOD::Type::ObjectType type2 = xAOD::Type::Other;
199  if (m_checkCharge) {
200  type1 = ((*particles1)[0])->type();
201  type2 = ((*particles2)[0])->type();
202  if ((type1 != xAOD::Type::Electron && type1 != xAOD::Type::Muon) ||
203  (type2 != xAOD::Type::Electron && type2 != xAOD::Type::Muon)) {
205  "Cannot check charge for particles not of type electron or muon");
206  return StatusCode::FAILURE;
207  }
208  }
209 
210  for (const auto& pair : pairs) {
211  unsigned int first = pair[0];
212  unsigned int second = pair[1];
213  float apt1 = pt1 ? (*pt1)[first] : ((*particles1)[first])->p4().Pt();
214  float apt2 = pt2 ? (*pt2)[second] : ((*particles2)[second])->p4().Pt();
215  float aeta1(-999.), aeta2(-999.);
216  if (!m_doTransverseMass || (m_mindR > 0.0)) {
217  aeta1 = eta1 ? (*eta1)[first] : ((*particles1)[first])->p4().Eta();
218  aeta2 = eta2 ? (*eta2)[second] : ((*particles2)[second])->p4().Eta();
219  }
220  float aphi1 = phi1 ? (*phi1)[first] : ((*particles1)[first])->p4().Phi();
221  float aphi2 = phi2 ? (*phi2)[second] : ((*particles2)[second])->p4().Phi();
222 
223  if (m_mindR > 0.0) {
224  float deta = aeta1 - aeta2;
225  float dphi = abs(aphi1 - aphi2);
226  if (dphi > TMath::Pi()) {
227  dphi = TMath::TwoPi() - dphi;
228  }
229  if (sqrt(deta * deta + dphi * dphi) < m_mindR) {
230  continue;
231  }
232  }
233 
234  if (m_checkCharge) {
235  float q1(0.), q2(0.);
236  if (type1 == xAOD::Type::Electron) {
237  q1 = ((xAOD::Electron*)((*particles1)[first]))->charge();
238  } else if (type1 == xAOD::Type::Muon) {
239  q1 = ((xAOD::Muon*)((*particles1)[first]))
240  ->primaryTrackParticle()
241  ->charge();
242  }
243  if (type2 == xAOD::Type::Electron) {
244  q2 = ((xAOD::Electron*)((*particles2)[second]))->charge();
245  } else if (type2 == xAOD::Type::Muon) {
246  q2 = ((xAOD::Muon*)((*particles2)[second]))
247  ->primaryTrackParticle()
248  ->charge();
249  }
250  if (q1 * q2 > 0.) {
251  continue;
252  }
253  }
254  TLorentzVector v1, v2, v;
255  if (m_doTransverseMass) {
256  v1.SetPtEtaPhiM(apt1, 0., aphi1, m_mass1Hypothesis);
257  v2.SetPtEtaPhiM(apt2, 0., aphi2, m_mass2Hypothesis);
258  } else {
259  v1.SetPtEtaPhiM(apt1, aeta1, aphi1, m_mass1Hypothesis);
260  v2.SetPtEtaPhiM(apt2, aeta2, aphi2, m_mass2Hypothesis);
261  }
262  float mass = (v1 + v2).M();
263  masses.push_back(mass);
264  }
265  return StatusCode::SUCCESS;
266 }
267 } // end namespace DerivationFramework
python.SystemOfUnits.second
int second
Definition: SystemOfUnits.py:120
DerivationFramework::EGInvariantMassTool::m_phi1BranchName
SG::ReadHandleKey< std::vector< float > > m_phi1BranchName
Definition: EGInvariantMassTool.h:80
DerivationFramework::EGInvariantMassTool::m_mass1Hypothesis
float m_mass1Hypothesis
Definition: EGInvariantMassTool.h:108
xAOD::Electron
Electron_v1 Electron
Definition of the current "egamma version".
Definition: Event/xAOD/xAODEgamma/xAODEgamma/Electron.h:17
ParticleGun_SamplingFraction.eta2
eta2
Definition: ParticleGun_SamplingFraction.py:96
DerivationFramework::EGInvariantMassTool::m_container2Name
SG::ReadHandleKey< xAOD::IParticleContainer > m_container2Name
Definition: EGInvariantMassTool.h:59
DerivationFramework::EGInvariantMassTool::addBranches
virtual StatusCode addBranches() const override final
Pass the thinning service
Definition: EGInvariantMassTool.cxx:83
Base_Fragment.mass
mass
Definition: Sherpa_i/share/common/Base_Fragment.py:59
ObjectType
ObjectType
Definition: BaseObject.h:11
Muon.h
SG::ReadHandle
Definition: StoreGate/StoreGate/ReadHandle.h:70
AthCommonDataStore< AthCommonMsg< AlgTool > >::declareProperty
Gaudi::Details::PropertyBase & declareProperty(Gaudi::Property< T > &t)
Definition: AthCommonDataStore.h:145
ExpressionParserUserBase< AthAlgTool, NUM_PARSER >::m_parser
std::conditional< NUM_PARSER==1, std::unique_ptr< ExpressionParsing::ExpressionParser >, std::array< std::unique_ptr< ExpressionParsing::ExpressionParser >, NUM_PARSER > >::type m_parser
Definition: ExpressionParserUser.h:100
DerivationFramework::kParser2
@ kParser2
Definition: EGInvariantMassTool.h:28
DerivationFramework::EGInvariantMassTool::m_doTransverseMass
bool m_doTransverseMass
Definition: EGInvariantMassTool.h:111
xAOD::eta1
setEt setPhi setE277 setWeta2 eta1
Definition: TrigEMCluster_v1.cxx:41
read_hist_ntuple.t
t
Definition: read_hist_ntuple.py:5
SG::VarHandleKey::key
const std::string & key() const
Return the StoreGate ID for the referenced object.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:141
xAOD::Muon_v1
Class describing a Muon.
Definition: Muon_v1.h:38
DerivationFramework::EGInvariantMassTool::m_expression2
std::string m_expression2
Definition: EGInvariantMassTool.h:47
DerivationFramework::kParser1
@ kParser1
Definition: EGInvariantMassTool.h:27
python.CreateTierZeroArgdict.pairs
pairs
Definition: CreateTierZeroArgdict.py:201
DerivationFramework::EGInvariantMassTool::m_expression1
std::string m_expression1
Definition: EGInvariantMassTool.h:47
python.utils.AtlRunQueryDQUtils.p
p
Definition: AtlRunQueryDQUtils.py:210
DerivationFramework::EGInvariantMassTool::getInvariantMasses
StatusCode getInvariantMasses(const EventContext &ctx, std::vector< float > &) const
Definition: EGInvariantMassTool.cxx:100
ATH_MSG_ERROR
#define ATH_MSG_ERROR(x)
Definition: AthMsgStreamMacros.h:33
beamspotman.n
n
Definition: beamspotman.py:731
EL::StatusCode
::StatusCode StatusCode
StatusCode definition for legacy code.
Definition: PhysicsAnalysis/D3PDTools/EventLoop/EventLoop/StatusCode.h:22
DerivationFramework::EGInvariantMassTool::initialize
virtual StatusCode initialize() override final
Definition: EGInvariantMassTool.cxx:44
ATH_CHECK
#define ATH_CHECK
Definition: AthCheckMacros.h:40
DerivationFramework
THE reconstruction tool.
Definition: ParticleSortingAlg.h:24
SG::VarHandleKey::initialize
StatusCode initialize(bool used=true)
If this object is used as a property, then this should be called during the initialize phase.
Definition: AthToolSupport/AsgDataHandles/Root/VarHandleKey.cxx:103
DataVector
Derived DataVector<T>.
Definition: DataVector.h:794
EGInvariantMassTool.h
ExpressionParserUser< AthAlgTool, kNumEGInvariantMassToolParser >::initializeParser
StatusCode initializeParser(const ExpressionParsing::SelectionArg< NUM_PARSER > &selection_string)
DerivationFramework::EGInvariantMassTool::m_mindR
float m_mindR
Definition: EGInvariantMassTool.h:109
DerivationFramework::EGInvariantMassTool::m_mass2Hypothesis
float m_mass2Hypothesis
Definition: EGInvariantMassTool.h:108
DerivationFramework::EGInvariantMassTool::m_pt2BranchName
SG::ReadHandleKey< std::vector< float > > m_pt2BranchName
Definition: EGInvariantMassTool.h:87
ExpressionParserUser
Definition: ExpressionParserUser.h:107
DerivationFramework::EGInvariantMassTool::m_phi2BranchName
SG::ReadHandleKey< std::vector< float > > m_phi2BranchName
Definition: EGInvariantMassTool.h:101
DerivationFramework::kNumEGInvariantMassToolParser
@ kNumEGInvariantMassToolParser
Definition: EGInvariantMassTool.h:29
xAOD::Electron_v1
Definition: Electron_v1.h:34
Muon
struct TBPatternUnitContext Muon
DerivationFramework::EGInvariantMassTool::m_checkCharge
bool m_checkCharge
Definition: EGInvariantMassTool.h:110
ReadCellNoiseFromCoolCompare.v2
v2
Definition: ReadCellNoiseFromCoolCompare.py:364
python.PyAthena.v
v
Definition: PyAthena.py:154
SG::WriteHandle
Definition: StoreGate/StoreGate/WriteHandle.h:76
DerivationFramework::EGInvariantMassTool::m_pt1BranchName
SG::ReadHandleKey< std::vector< float > > m_pt1BranchName
Definition: EGInvariantMassTool.h:66
ATH_MSG_WARNING
#define ATH_MSG_WARNING(x)
Definition: AthMsgStreamMacros.h:32
python.CaloScaleNoiseConfig.type
type
Definition: CaloScaleNoiseConfig.py:78
DerivationFramework::EGInvariantMassTool::m_container1Name
SG::ReadHandleKey< xAOD::IParticleContainer > m_container1Name
Definition: EGInvariantMassTool.h:53
DeMoScan.first
bool first
Definition: DeMoScan.py:536
Electron.h
DerivationFramework::EGInvariantMassTool::m_eta1BranchName
SG::ReadHandleKey< std::vector< float > > m_eta1BranchName
Definition: EGInvariantMassTool.h:73
AthAlgTool
Definition: AthAlgTool.h:26
DerivationFramework::EGInvariantMassTool::m_eta2BranchName
SG::ReadHandleKey< std::vector< float > > m_eta2BranchName
Definition: EGInvariantMassTool.h:94
DataVector::size
size_type size() const noexcept
Returns the number of elements in the collection.
DerivationFramework::EGInvariantMassTool::m_sgName
SG::WriteHandleKey< std::vector< float > > m_sgName
Definition: EGInvariantMassTool.h:48
SUSY_SimplifiedModel_PreInclude.masses
dictionary masses
Definition: SUSY_SimplifiedModel_PreInclude.py:7
DerivationFramework::EGInvariantMassTool::EGInvariantMassTool
EGInvariantMassTool(const std::string &t, const std::string &n, const IInterface *p)
Definition: EGInvariantMassTool.cxx:21