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
64
65 const EventContext& ctx = Gaudi::Hive::currentContext();
66
68 ATH_CHECK(muonContainer.isValid());
69
71 ATH_CHECK(evtInfo.isValid());
72
74 ATH_CHECK(JPsiMuonContainer.record(std::make_unique<xAOD::MuonContainer>(), std::make_unique<xAOD::MuonAuxContainer>()));
75
77 ATH_CHECK(JPsiVertexContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
78
80 ATH_CHECK(JPsiTrackParticleContainer.record(std::make_unique<xAOD::TrackParticleContainer>(), std::make_unique<xAOD::TrackParticleAuxContainer>()));
81
82 // 1) Run J/Psi finder
83 auto jpsiVtxs = std::make_unique<xAOD::VertexContainer>();
84 auto jpsiAux = std::make_unique<xAOD::VertexAuxContainer>();
85 jpsiVtxs->setStore(jpsiAux.get());
86 ATH_CHECK(m_JPsiFinderTool->performSearch(ctx, *jpsiVtxs));
87
88 if (jpsiVtxs->empty()) {
89 ATH_MSG_DEBUG("No J/Psi candidates found");
90 return StatusCode::SUCCESS;
91 } else {
92 ATH_MSG_DEBUG("Found " << jpsiVtxs->size() << " J/Psi candidates");
93 }
94
95 for (const xAOD::Vertex* vtx : *jpsiVtxs) {
96 const auto& links = vtx->trackParticleLinks();
97 if (links.size() == 2) {
98 const xAOD::TrackParticle* tp1 = links[0].isValid() ? *links[0] : nullptr;
99 const xAOD::TrackParticle* tp2 = links[1].isValid() ? *links[1] : nullptr;
100 const xAOD::Muon* mu1 = tp1 ? findMuonFromTrack(tp1, muonContainer.cptr()) : nullptr;
101 const xAOD::Muon* mu2 = tp2 ? findMuonFromTrack(tp2, muonContainer.cptr()) : nullptr;
102
103 if (!mu1 && !mu2) {
104 ATH_MSG_WARNING("No muons found for J/Psi vertex with index " << vtx->index());
105 continue;
106 } else if (!mu1 || !mu2) {
107 ATH_MSG_WARNING("Only one muon found for J/Psi vertex with index " << vtx->index());
108 } else {
109 ATH_MSG_DEBUG("Found J/Psi vertex with index " << vtx->index() << " and muons: " << mu1->index() << ", " << mu2->index());
110 }
111
112 if (mu1) JPsiMuonContainer->push_back(new xAOD::Muon(*mu1));
113 if (mu2) JPsiMuonContainer->push_back(new xAOD::Muon(*mu2));
114 }
115
116 // vertices right out of JPsiFinder have vxTrackAtVertex decorators that can't be saved to container
117 // thus we make a fresh copy to avoid this issue
118 xAOD::Vertex* newVtx = new xAOD::Vertex();
119 JPsiVertexContainer->push_back(newVtx); // add the vertex to the container first
120
121 // Set properties of the new vertex
122 newVtx->setPosition(vtx->position());
123 newVtx->setCovariance(vtx->covariance());
124 newVtx->setFitQuality(vtx->chiSquared(), vtx->numberDoF());
125 newVtx->setVertexType(vtx->vertexType());
126
127 // copy track particle links
128 for (const auto& link : vtx->trackParticleLinks()) {
129 if (!link.isValid()) continue;
130 const xAOD::TrackParticle* oldTrack = *link;
132 newTrack->makePrivateStore(*oldTrack);
133 JPsiTrackParticleContainer->push_back(newTrack);
134 ElementLink<xAOD::TrackParticleContainer> newLink(*JPsiTrackParticleContainer, newTrack->index());
135 newVtx->addTrackAtVertex(newLink, 1.0); // weight is set to 1.0 for simplicity
136 }
137
138 // add identical decos to musa for comparison
139 constexpr double muonMass = 105.658; // Muon mass in MeV
140 TLorentzVector sumP4_muon, sumP4_electron, sumP4_selected;
141 std::vector<const xAOD::TrackParticle*> vtxTracks;
142
143 int vtxCharge = 0;
144
145 for (const auto& link : newVtx->trackParticleLinks()) {
146 const xAOD::TrackParticle* track = link.isValid() ? *link : nullptr;
147 if (!track) continue;
148
149 double pt = track->pt();
150 double eta = track->eta();
151 double phi = track->phi();
152
153 TLorentzVector p4_muon, p4_electron;
154 p4_muon.SetPtEtaPhiM(pt, eta, phi, muonMass);
155 p4_electron.SetPtEtaPhiM(pt, eta, phi, VKalVrtAthena::PhysConsts::mass_electron);
156
157 sumP4_muon += p4_muon;
158 sumP4_electron += p4_electron;
159 sumP4_selected += p4_muon; // assuming selected tracks are muons...
160
161 vtxCharge += track->charge();
162 vtxTracks.push_back(track);
163 }
164
165 //calculate opening angle between two tracks
166 float vtxDeltaR = 0;
167 if (vtxTracks.size() == 2) {
168 float dEta = vtxTracks[0]->eta() - vtxTracks[1]->eta();
169 float dPhi = std::abs(vtxTracks[0]->phi() - vtxTracks[1]->phi());
170 if (dPhi > M_PI) dPhi = 2 * M_PI - dPhi;
171 vtxDeltaR = std::sqrt(dEta * dEta + dPhi * dPhi);
172 }
173
174 vtx_pxAcc(*newVtx) = sumP4_muon.Px();
175 vtx_pyAcc(*newVtx) = sumP4_muon.Py();
176 vtx_pzAcc(*newVtx) = sumP4_muon.Pz();
177 vtx_massAcc(*newVtx) = sumP4_muon.M();
178 vtx_chargeAcc(*newVtx) = vtxCharge;
179 minOpAngAcc(*newVtx) = vtxDeltaR;
180 chi2_coreAcc(*newVtx) = vtx->chiSquared();
181 ndof_coreAcc(*newVtx) = vtx->numberDoF();
182 chi2_assocAcc(*newVtx) = vtx->chiSquared();
183 ndof_assocAcc(*newVtx) = vtx->numberDoF();
184 massAcc(*newVtx) = sumP4_muon.M();
185 mass_eAcc(*newVtx) = sumP4_electron.M();
186 mass_selectedTracksAcc(*newVtx) = sumP4_selected.M();
187 num_trksAcc(*newVtx) = links.size();
188 num_selectedTracksAcc(*newVtx) = links.size(); // Assuming all tracks are selected
189 num_associatedTracksAcc(*newVtx) = links.size(); // Assuming all tracks are associated
190 dCloseVrtAcc(*newVtx) = 0; // not implemented but assigned for comparison to MuSA
191 }
192
193 return StatusCode::SUCCESS;
194}
195
197 for (const xAOD::Muon* mu : *muons) {
198 if (mu->trackParticle(xAOD::Muon::CombinedTrackParticle) == tp) return mu;
199 if (mu->trackParticle(xAOD::Muon::InnerDetectorTrackParticle) == tp) return mu;
200 }
201 return nullptr;
202}
203
204} // 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 with parameters:
SG::WriteHandleKey< xAOD::TrackParticleContainer > m_JPsiTrackParticleContainer
SG::ReadHandleKey< xAOD::MuonContainer > m_muonContainer
virtual StatusCode initialize() override
virtual StatusCode execute() 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
void makePrivateStore()
Create a new (empty) private store for this object.
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
size_t index() const
Return the index of this element within its container.
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".