ATLAS Offline Software
Loading...
Searching...
No Matches
MuSAVtxJPsiValidationAlg.cxx
Go to the documentation of this file.
1/*
2Copyright (C) 2025 CERN for the benefit of the ATLAS collaboration
3*/
4
5// this algorithm produces a J/Psi candidate muons container to be passed to the MuSAVtxFitter
6// to be used in "tag and probe" style studies on the MuSA performance
10#include "xAODMuon/Muon.h"
13#include "xAODTracking/Vertex.h"
15#include "AthLinks/ElementLink.h"
18#include "VrtSecInclusive/Constants.h"
20
21namespace {
22 // Accessors for vertex properties
23 const SG::AuxElement::Accessor<float> vtx_pxAcc("vtx_px");
24 const SG::AuxElement::Accessor<float> vtx_pyAcc("vtx_py");
25 const SG::AuxElement::Accessor<float> vtx_pzAcc("vtx_pz");
26 const SG::AuxElement::Accessor<float> vtx_massAcc("vtx_mass");
27 const SG::AuxElement::Accessor<float> vtx_chargeAcc("vtx_charge");
28 const SG::AuxElement::Accessor<float> minOpAngAcc("minOpAng");
29 const SG::AuxElement::Accessor<float> chi2_coreAcc("chi2_core");
30 const SG::AuxElement::Accessor<float> ndof_coreAcc("ndof_core");
31 const SG::AuxElement::Accessor<float> chi2_assocAcc("chi2_assoc");
32 const SG::AuxElement::Accessor<float> ndof_assocAcc("ndof_assoc");
33 const SG::AuxElement::Accessor<float> massAcc("mass");
34 const SG::AuxElement::Accessor<float> mass_eAcc("mass_e");
35 const SG::AuxElement::Accessor<float> mass_selectedTracksAcc("mass_selectedTracks");
36 const SG::AuxElement::Accessor<int> num_trksAcc("num_trks");
37 const SG::AuxElement::Accessor<int> num_selectedTracksAcc("num_selectedTracks");
38 const SG::AuxElement::Accessor<int> num_associatedTracksAcc("num_associatedTracks");
39 const SG::AuxElement::Accessor<float> dCloseVrtAcc("dCloseVrt");
40}
41
42namespace Rec {
43
44MuSAVtxJPsiValidationAlg::MuSAVtxJPsiValidationAlg(const std::string& name, ISvcLocator* p)
45 : AthAlgorithm(name,p)
46{}
47
49 ATH_CHECK(m_muonContainer.initialize());
50 ATH_CHECK(m_eventInfo.initialize());
51 ATH_CHECK(m_JPsiMuonContainer.initialize());
52 ATH_CHECK(m_JPsiVertexContainer.initialize());
54
55 ATH_CHECK(m_JPsiFinderTool.retrieve());
56 ATH_MSG_DEBUG("Retrieved J/Psi finder tool: " << m_JPsiFinderTool);
57
58 ATH_MSG_DEBUG("Initialization successful");
59
60 return StatusCode::SUCCESS;
61}
62
63StatusCode MuSAVtxJPsiValidationAlg::execute(const EventContext& ctx) {
64
65
67 ATH_CHECK(muonContainer.isValid());
68
70 ATH_CHECK(evtInfo.isValid());
71
73 ATH_CHECK(JPsiMuonContainer.record(std::make_unique<xAOD::MuonContainer>(), std::make_unique<xAOD::MuonAuxContainer>()));
74
76 ATH_CHECK(JPsiVertexContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
77
79 ATH_CHECK(JPsiTrackParticleContainer.record(std::make_unique<xAOD::TrackParticleContainer>(), std::make_unique<xAOD::TrackParticleAuxContainer>()));
80
81 // 1) Run J/Psi finder
82 auto jpsiVtxs = std::make_unique<xAOD::VertexContainer>();
83 auto jpsiAux = std::make_unique<xAOD::VertexAuxContainer>();
84 jpsiVtxs->setStore(jpsiAux.get());
85 ATH_CHECK(m_JPsiFinderTool->performSearch(ctx, *jpsiVtxs));
86
87 if (jpsiVtxs->empty()) {
88 ATH_MSG_DEBUG("No J/Psi candidates found");
89 return StatusCode::SUCCESS;
90 } else {
91 ATH_MSG_DEBUG("Found " << jpsiVtxs->size() << " J/Psi candidates");
92 }
93
94 for (const xAOD::Vertex* vtx : *jpsiVtxs) {
95 const auto& links = vtx->trackParticleLinks();
96 if (links.size() == 2) {
97 const xAOD::TrackParticle* tp1 = links[0].isValid() ? *links[0] : nullptr;
98 const xAOD::TrackParticle* tp2 = links[1].isValid() ? *links[1] : nullptr;
99 const xAOD::Muon* mu1 = tp1 ? findMuonFromTrack(tp1, muonContainer.cptr()) : nullptr;
100 const xAOD::Muon* mu2 = tp2 ? findMuonFromTrack(tp2, muonContainer.cptr()) : nullptr;
101
102 if (!mu1 && !mu2) {
103 ATH_MSG_WARNING("No muons found for J/Psi vertex with index " << vtx->index());
104 continue;
105 } else if (!mu1 || !mu2) {
106 ATH_MSG_WARNING("Only one muon found for J/Psi vertex with index " << vtx->index());
107 } else {
108 ATH_MSG_DEBUG("Found J/Psi vertex with index " << vtx->index() << " and muons: " << mu1->index() << ", " << mu2->index());
109 }
110
111 if (mu1) JPsiMuonContainer->push_back(new xAOD::Muon(*mu1));
112 if (mu2) JPsiMuonContainer->push_back(new xAOD::Muon(*mu2));
113 }
114
115 // vertices right out of JPsiFinder have vxTrackAtVertex decorators that can't be saved to container
116 // thus we make a fresh copy to avoid this issue
117 xAOD::Vertex* newVtx = new xAOD::Vertex();
118 JPsiVertexContainer->push_back(newVtx); // add the vertex to the container first
119
120 // Set properties of the new vertex
121 newVtx->setPosition(vtx->position());
122 newVtx->setCovariance(vtx->covariance());
123 newVtx->setFitQuality(vtx->chiSquared(), vtx->numberDoF());
124 newVtx->setVertexType(vtx->vertexType());
125
126 // copy track particle links
127 for (const auto& link : vtx->trackParticleLinks()) {
128 if (!link.isValid()) continue;
129 const xAOD::TrackParticle* oldTrack = *link;
131 newTrack->makePrivateStore(*oldTrack);
132 JPsiTrackParticleContainer->push_back(newTrack);
133 ElementLink<xAOD::TrackParticleContainer> newLink(*JPsiTrackParticleContainer, newTrack->index());
134 newVtx->addTrackAtVertex(newLink, 1.0); // weight is set to 1.0 for simplicity
135 }
136
137 // add identical decos to musa for comparison
138 constexpr double muonMass = 105.658; // Muon mass in MeV
139 TLorentzVector sumP4_muon, sumP4_electron, sumP4_selected;
140 std::vector<const xAOD::TrackParticle*> vtxTracks;
141
142 int vtxCharge = 0;
143
144 for (const auto& link : newVtx->trackParticleLinks()) {
145 const xAOD::TrackParticle* track = link.isValid() ? *link : nullptr;
146 if (!track) continue;
147
148 double pt = track->pt();
149 double eta = track->eta();
150 double phi = track->phi();
151
152 TLorentzVector p4_muon, p4_electron;
153 p4_muon.SetPtEtaPhiM(pt, eta, phi, muonMass);
154 p4_electron.SetPtEtaPhiM(pt, eta, phi, VKalVrtAthena::PhysConsts::mass_electron);
155
156 sumP4_muon += p4_muon;
157 sumP4_electron += p4_electron;
158 sumP4_selected += p4_muon; // assuming selected tracks are muons...
159
160 vtxCharge += track->charge();
161 vtxTracks.push_back(track);
162 }
163
164 //calculate opening angle between two tracks
165 float vtxDeltaR = 0;
166 if (vtxTracks.size() == 2) {
167 float dEta = vtxTracks[0]->eta() - vtxTracks[1]->eta();
168 float dPhi = std::abs(vtxTracks[0]->phi() - vtxTracks[1]->phi());
169 if (dPhi > M_PI) dPhi = 2 * M_PI - dPhi;
170 vtxDeltaR = std::sqrt(dEta * dEta + dPhi * dPhi);
171 }
172
173 vtx_pxAcc(*newVtx) = sumP4_muon.Px();
174 vtx_pyAcc(*newVtx) = sumP4_muon.Py();
175 vtx_pzAcc(*newVtx) = sumP4_muon.Pz();
176 vtx_massAcc(*newVtx) = sumP4_muon.M();
177 vtx_chargeAcc(*newVtx) = vtxCharge;
178 minOpAngAcc(*newVtx) = vtxDeltaR;
179 chi2_coreAcc(*newVtx) = vtx->chiSquared();
180 ndof_coreAcc(*newVtx) = vtx->numberDoF();
181 chi2_assocAcc(*newVtx) = vtx->chiSquared();
182 ndof_assocAcc(*newVtx) = vtx->numberDoF();
183 massAcc(*newVtx) = sumP4_muon.M();
184 mass_eAcc(*newVtx) = sumP4_electron.M();
185 mass_selectedTracksAcc(*newVtx) = sumP4_selected.M();
186 num_trksAcc(*newVtx) = links.size();
187 num_selectedTracksAcc(*newVtx) = links.size(); // Assuming all tracks are selected
188 num_associatedTracksAcc(*newVtx) = links.size(); // Assuming all tracks are associated
189 dCloseVrtAcc(*newVtx) = 0; // not implemented but assigned for comparison to MuSA
190 }
191
192 return StatusCode::SUCCESS;
193}
194
196 for (const xAOD::Muon* mu : *muons) {
197 if (mu->trackParticle(xAOD::Muon::CombinedTrackParticle) == tp) return mu;
198 if (mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) == tp) return mu;
199 }
200 return nullptr;
201}
202
203} // namespace Rec
#define M_PI
Scalar eta() const
pseudorapidity method
Scalar phi() const
phi method
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
xAOD::MuonContainer * muonContainer
AthAlgorithm(const std::string &name, ISvcLocator *pSvcLocator)
Constructor.
virtual StatusCode execute(const EventContext &ctx) override
Execute method.
SG::WriteHandleKey< xAOD::TrackParticleContainer > m_JPsiTrackParticleContainer
SG::ReadHandleKey< xAOD::MuonContainer > m_muonContainer
virtual StatusCode initialize() override
SG::WriteHandleKey< xAOD::VertexContainer > m_JPsiVertexContainer
const xAOD::Muon * findMuonFromTrack(const xAOD::TrackParticle *tp, const xAOD::MuonContainer *muons)
ToolHandle< Analysis::JpsiFinder > m_JPsiFinderTool
SG::WriteHandleKey< xAOD::MuonContainer > m_JPsiMuonContainer
MuSAVtxJPsiValidationAlg(const std::string &name, ISvcLocator *pSvcLocator)
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
virtual bool isValid() override final
Can the handle be successfully dereferenced?
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
void addTrackAtVertex(const ElementLink< TrackParticleContainer > &tr, float weight=1.0)
Add a new track to the vertex.
const TrackParticleLinks_t & trackParticleLinks() const
Get all the particles associated with the vertex.
void setVertexType(VxType::VertexType vType)
Set the type of the vertex.
void setCovariance(const std::vector< float > &value)
Sets the covariance matrix as a simple vector of values.
void setPosition(const Amg::Vector3D &position)
Sets the 3-position.
void setFitQuality(float chiSquared, float numberDoF)
Set the 'Fit Quality' information.
Gaudi Tools.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
Vertex_v1 Vertex
Define the latest version of the vertex class.
Muon_v1 Muon
Reference the current persistent version:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".