ATLAS Offline Software
Loading...
Searching...
No Matches
MuSAVtxFitter.cxx
Go to the documentation of this file.
1/*
2Copyright (C) 2024 CERN for the benefit of the ATLAS collaboration
3*/
4
5// Header include
11#include "VrtSecInclusive/Constants.h"
12
13namespace {
14 // accessors for vertex links
15 const SG::AuxElement::Accessor<std::vector<ElementLink<xAOD::TrackParticleContainer>>> acc_MSTPLinks("MuSAVtx_MSTPLinks");
16 const SG::AuxElement::Accessor<std::vector<ElementLink<xAOD::MuonContainer>>> acc_MuonLinks("MuSAVtx_MuonLinks");
17 const SG::AuxElement::Accessor<ElementLink<xAOD::MuonContainer>> acc_MuonLink("MuSATrk_MuonLink");
18 const SG::AuxElement::Accessor<ElementLink<xAOD::TrackParticleContainer>> acc_MSTPLink("MuSATrk_MSTPLink");
19 // accessors for vertex properties
20 const SG::AuxElement::Accessor<float> vtx_pxAcc("vtx_px");
21 const SG::AuxElement::Accessor<float> vtx_pyAcc("vtx_py");
22 const SG::AuxElement::Accessor<float> vtx_pzAcc("vtx_pz");
23 const SG::AuxElement::Accessor<float> vtx_massAcc("vtx_mass");
24 const SG::AuxElement::Accessor<float> vtx_chargeAcc("vtx_charge");
25 const SG::AuxElement::Accessor<float> minOpAngAcc("minOpAng");
26 const SG::AuxElement::Accessor<float> chi2_coreAcc("chi2_core");
27 const SG::AuxElement::Accessor<float> ndof_coreAcc("ndof_core");
28 const SG::AuxElement::Accessor<float> chi2_assocAcc("chi2_assoc");
29 const SG::AuxElement::Accessor<float> ndof_assocAcc("ndof_assoc");
30 const SG::AuxElement::Accessor<float> massAcc("mass");
31 const SG::AuxElement::Accessor<float> mass_eAcc("mass_e");
32 const SG::AuxElement::Accessor<float> mass_selectedTracksAcc("mass_selectedTracks");
33 const SG::AuxElement::Accessor<int> num_trksAcc("num_trks");
34 const SG::AuxElement::Accessor<int> num_selectedTracksAcc("num_selectedTracks");
35 const SG::AuxElement::Accessor<int> num_associatedTracksAcc("num_associatedTracks");
36 const SG::AuxElement::Accessor<float> dCloseVrtAcc("dCloseVrt");
37 // accessors for track parameters wrt vertex (coordinate transformation only)
38 const SG::AuxElement::Accessor<float> qOverP_wrtSVAcc("qOverP_wrtSV");
39 const SG::AuxElement::Accessor<float> theta_wrtSVAcc("theta_wrtSV");
40 const SG::AuxElement::Accessor<float> p_wrtSVAcc("p_wrtSV");
41 const SG::AuxElement::Accessor<float> pt_wrtSVAcc("pt_wrtSV");
42 const SG::AuxElement::Accessor<float> eta_wrtSVAcc("eta_wrtSV");
43 const SG::AuxElement::Accessor<float> phi_wrtSVAcc("phi_wrtSV");
44 const SG::AuxElement::Accessor<float> d0_wrtSVAcc("d0_wrtSV");
45 const SG::AuxElement::Accessor<float> z0_wrtSVAcc("z0_wrtSV");
46 const SG::AuxElement::Accessor<float> sqrd0Err_wrtSVAcc("sqrd0Err_wrtSV");
47 const SG::AuxElement::Accessor<float> sqrz0Err_wrtSVAcc("sqrz0Err_wrtSV");
48 const SG::AuxElement::Accessor<float> sqrQoPErr_wrtSVAcc("sqrQoPErr_wrtSV");
49 // accessors for refit track parameters from VKalVrt (proper refit accounting for magnetic field)
50 const SG::AuxElement::Accessor<float> phi_refitAcc("phi_refit");
51 const SG::AuxElement::Accessor<float> theta_refitAcc("theta_refit");
52 const SG::AuxElement::Accessor<float> qOverP_refitAcc("qOverP_refit");
53 const SG::AuxElement::Accessor<float> p_refitAcc("p_refit");
54 const SG::AuxElement::Accessor<float> pt_refitAcc("pt_refit");
55 const SG::AuxElement::Accessor<float> eta_refitAcc("eta_refit");
56}
57
58namespace Rec {
59
61
63{
64 ATH_CHECK( m_muonContainer.initialize() );
65 ATH_CHECK( m_MSTPContainer.initialize() );
66 ATH_CHECK( m_eventInfo.initialize() );
67 ATH_CHECK( m_MuSAVertices.initialize() );
68 ATH_CHECK( m_MuSAExtrapolatedTracks.initialize() );
69
70 ATH_CHECK( m_MuSAVtxFitterTool.retrieve() );
71 ATH_MSG_DEBUG("Retrieved tool " << m_MuSAVtxFitterTool);
72
73 ATH_CHECK( m_trackToVertexTool.retrieve() );
74 ATH_MSG_DEBUG("Retrieved tool " << m_trackToVertexTool);
75
76 ATH_MSG_DEBUG("Initialization successful");
77
78 return StatusCode::SUCCESS;
79
80}
81
82StatusCode MuSAVtxFitter::fillCollections(std::vector<MuSAVtxFitterTool::WrkVrt>& workVerticesContainer,
83 xAOD::VertexContainer* MuSAVtxContainer,
84 xAOD::TrackParticleContainer* MuSAExtrapolatedTracksContainer,
86 const xAOD::TrackParticleContainer& MSTPContainer,
87 const EventContext& ctx) const
88{
89 ATH_MSG_DEBUG("MuSAVtxFitter::fillCollections");
90 for (const auto& workVertex : workVerticesContainer) {
91
92 xAOD::Vertex* MuSAVertex = new xAOD::Vertex();
93 MuSAVtxContainer->emplace_back(MuSAVertex);
94
95 // Place the new extrapolated tracks in the new container (we need the index for bookkeeping)
96 for (size_t i = 0; i < workVertex.newExtrapolatedTracks.size(); i++) {
97
98 // copy transfers ownership of the shared_ptr in wrkvrt to container
99 xAOD::TrackParticle* containerTrack = MuSAExtrapolatedTracksContainer->push_back(new xAOD::TrackParticle());
100 *containerTrack=*workVertex.newExtrapolatedTracks[i];
101
102 // Link the new tracks to the vertex
103 ElementLink<xAOD::TrackParticleContainer> link_trk(*MuSAExtrapolatedTracksContainer, MuSAExtrapolatedTracksContainer->size() - 1);
104 MuSAVertex->addTrackAtVertex(link_trk, 1.0);
105
106 //Also link the extrapolated tracks and vertices to their original muons -- extrapolated tracks and their muons should have the same index in workVertex
107
108 bool muonLinkSuccess = false;
109 bool MSTPLinkSuccess = false;
110
113 muonLinkSuccess = link_muon.toContainedElement(muonContainer, workVertex.muonCandidates[i]);
114
115 const xAOD::Muon* muon = muonContainer[link_muon.index()];
116 const xAOD::TrackParticle* MSTP = muon->trackParticle(xAOD::Muon::MuonSpectrometerTrackParticle);
117 if (MSTP) {
118 MSTPLinkSuccess = link_MSTP.toContainedElement(MSTPContainer, MSTP);
119 }
120
121 // Check that links are valid
122 if (!MSTPLinkSuccess) {
123 ATH_MSG_WARNING("Failed to link MSTP!");
124 } else {
125 acc_MSTPLink(*containerTrack) = link_MSTP;
126 auto& mstpLinks = acc_MSTPLinks(*MuSAVertex);
127 mstpLinks.push_back(link_MSTP);
128 }
129
130 if (!muonLinkSuccess) {
131 ATH_MSG_WARNING("Failed to link muon!");
132 } else {
133 acc_MuonLink(*containerTrack) = link_muon;
134 auto& muonLinks = acc_MuonLinks(*MuSAVertex);
135 muonLinks.push_back(link_muon);
136 }
137 }
138
139 MuSAVertex->setPosition(workVertex.pos);
141 MuSAVertex->setFitQuality(workVertex.chi2, 1);
142 std::vector<float> fCov(workVertex.cov.cbegin(), workVertex.cov.cend());
143 MuSAVertex->setCovariance(fCov);
144
145 vtx_pxAcc(*MuSAVertex) = workVertex.mom.Px();
146 vtx_pyAcc(*MuSAVertex) = workVertex.mom.Py();
147 vtx_pzAcc(*MuSAVertex) = workVertex.mom.Pz();
148
149 vtx_massAcc(*MuSAVertex) = workVertex.mom.M();
150 vtx_chargeAcc(*MuSAVertex) = workVertex.charge;
151
152 minOpAngAcc(*MuSAVertex) = workVertex.minOpAng;
153
154 chi2_coreAcc(*MuSAVertex) = workVertex.chi2Core;
155 ndof_coreAcc(*MuSAVertex) = 1;
156 chi2_assocAcc(*MuSAVertex) = workVertex.chi2;
157 ndof_assocAcc(*MuSAVertex) = workVertex.ndof();
158
159 TLorentzVector sumP4_muon;
160 TLorentzVector sumP4_electron;
161 TLorentzVector sumP4_selected;
162
163 constexpr double muonMass = 105.658; // Muon mass in MeV
164
165 for (size_t i = 0; i < workVertex.newExtrapolatedTracks.size(); i++) {
166 const xAOD::TrackParticle* track = workVertex.newExtrapolatedTracks[i].get();
167 double pt_wrtSV = track->pt();
168 double eta_wrtSV = track->eta();
169 double phi_wrtSV = track->phi();
170
171 TLorentzVector p4wrtSV_muon;
172 TLorentzVector p4wrtSV_electron;
173
174 p4wrtSV_muon.SetPtEtaPhiM(pt_wrtSV, eta_wrtSV, phi_wrtSV, muonMass);
175 p4wrtSV_electron.SetPtEtaPhiM(pt_wrtSV, eta_wrtSV, phi_wrtSV, VKalVrtAthena::PhysConsts::mass_electron);
176
177 sumP4_muon += p4wrtSV_muon;
178 sumP4_electron += p4wrtSV_electron;
179 sumP4_selected += p4wrtSV_muon;
180
181 size_t trackIndex = MuSAVertex->trackParticleLinks()[i].index();
182 xAOD::TrackParticle* containerTrack = MuSAExtrapolatedTracksContainer->at(trackIndex);
183
184 std::unique_ptr<Trk::Perigee> sv_perigee = m_trackToVertexTool->perigeeAtVertex(ctx, *containerTrack, workVertex.pos);
185 if (!sv_perigee) {
186 ATH_MSG_WARNING("Failed in obtaining the SV perigee for track!");
187 continue;
188 }
189
190 double qOverP_wrtSV = sv_perigee->parameters()[Trk::qOverP];
191 double theta_wrtSV = sv_perigee->parameters()[Trk::theta];
192 double p_wrtSV = 1.0 / std::abs(qOverP_wrtSV);
193 pt_wrtSV = p_wrtSV * sin(theta_wrtSV);
194 eta_wrtSV = -log(tan(theta_wrtSV / 2.0));
195 phi_wrtSV = sv_perigee->parameters()[Trk::phi];
196 double d0_wrtSV = sv_perigee->parameters()[Trk::d0];
197 double z0_wrtSV = sv_perigee->parameters()[Trk::z0];
198 double sqrd0Err_wrtSV = (*sv_perigee->covariance())(Trk::d0, Trk::d0);
199 double sqrz0Err_wrtSV = (*sv_perigee->covariance())(Trk::z0, Trk::z0);
200 double sqrQoPErr_wrtSV = (*sv_perigee->covariance())(Trk::qOverP, Trk::qOverP);
201
202 qOverP_wrtSVAcc(*containerTrack) = qOverP_wrtSV;
203 theta_wrtSVAcc(*containerTrack) = theta_wrtSV;
204 p_wrtSVAcc(*containerTrack) = p_wrtSV;
205 pt_wrtSVAcc(*containerTrack) = pt_wrtSV;
206 eta_wrtSVAcc(*containerTrack) = eta_wrtSV;
207 phi_wrtSVAcc(*containerTrack) = phi_wrtSV;
208 d0_wrtSVAcc(*containerTrack) = d0_wrtSV;
209 z0_wrtSVAcc(*containerTrack) = z0_wrtSV;
210 sqrd0Err_wrtSVAcc(*containerTrack) = sqrd0Err_wrtSV;
211 sqrz0Err_wrtSVAcc(*containerTrack) = sqrz0Err_wrtSV;
212 sqrQoPErr_wrtSVAcc(*containerTrack) = sqrQoPErr_wrtSV;
213
214 // Save VKalVrt refit track parameters (proper refit accounting for magnetic field)
215 // trkAtVrt contains: [0]=phi, [1]=theta, [2]=1/p (with sign)
216 if (i < workVertex.trkAtVrt.size() && workVertex.trkAtVrt[i].size() >= 3) {
217 double phi_refit = workVertex.trkAtVrt[i][0];
218 double theta_refit = workVertex.trkAtVrt[i][1];
219 double qOverP_refit = workVertex.trkAtVrt[i][2];
220 double p_refit = 1.0 / std::abs(qOverP_refit);
221 double pt_refit = p_refit * std::sin(theta_refit);
222 double eta_refit = -std::log(std::tan(theta_refit / 2.0));
223
224 phi_refitAcc(*containerTrack) = phi_refit;
225 theta_refitAcc(*containerTrack) = theta_refit;
226 qOverP_refitAcc(*containerTrack) = qOverP_refit;
227 p_refitAcc(*containerTrack) = p_refit;
228 pt_refitAcc(*containerTrack) = pt_refit;
229 eta_refitAcc(*containerTrack) = eta_refit;
230 } else {
231 ATH_MSG_WARNING("trkAtVrt not available for track " << i << ", skipping refit parameters");
232 }
233 }
234
235 massAcc(*MuSAVertex) = sumP4_muon.M();
236 mass_eAcc(*MuSAVertex) = sumP4_electron.M();
237 mass_selectedTracksAcc(*MuSAVertex) = sumP4_selected.M();
238 num_trksAcc(*MuSAVertex) = workVertex.nTracksTotal();
239 num_selectedTracksAcc(*MuSAVertex) = workVertex.selectedTrackIndices.size();
240 num_associatedTracksAcc(*MuSAVertex) = workVertex.associatedTrackIndices.size();
241 dCloseVrtAcc(*MuSAVertex) = workVertex.closestWrkVrtValue;
242 }
243 return StatusCode::SUCCESS;
244}
245
246StatusCode MuSAVtxFitter::execute(const EventContext& ctx) const
247{
249 ATH_CHECK(muonContainer.isValid());
250
251 SG::ReadHandle MSTPContainer(m_MSTPContainer, ctx);
252 ATH_CHECK(MSTPContainer.isValid());
253
254 SG::ReadHandle eventInfo(m_eventInfo, ctx);
255 ATH_CHECK(eventInfo.isValid());
256
257 SG::WriteHandle MuSAVtxContainer(m_MuSAVertices, ctx);
258 ATH_CHECK(MuSAVtxContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()));
259
260 SG::WriteHandle MuSAExtrapolatedTracksContainer(m_MuSAExtrapolatedTracks, ctx);
261 ATH_CHECK(MuSAExtrapolatedTracksContainer.record(std::make_unique<xAOD::TrackParticleContainer>(), std::make_unique<xAOD::TrackParticleAuxContainer>()));
262
263 std::vector<MuSAVtxFitterTool::WrkVrt> workVerticesContainer;
264
265 // Perform primary MuSA vertex fit
266 ATH_CHECK(m_MuSAVtxFitterTool->doMuSAVtxFit(workVerticesContainer, *muonContainer, *eventInfo, ctx));
267
268 // If there's no MuSA vertices to begin with, stop here to avoid wasting CPU cycles
269 if (workVerticesContainer.empty()) {
270 ATH_MSG_DEBUG("No MuSA vertices found");
271 return StatusCode::SUCCESS;
272 }
273
274 // Perform user-configurable post-fit selections
275 ATH_CHECK(m_MuSAVtxFitterTool->doPostFitSelections(workVerticesContainer));
276
277 // If there's no MuSA vertices remaining, stop here to again avoid wasting CPU cycles
278 if (workVerticesContainer.empty()) {
279 ATH_MSG_DEBUG("No MuSA vertices found after post-fit selection!");
280 return StatusCode::SUCCESS;
281 }
282
283 // Perform "ambiguity resolution" to prevent re-used SA muons in events with more than one MuSA vtx
284 ATH_CHECK(m_MuSAVtxFitterTool->selectBestVertices(workVerticesContainer));
285
286 // Again avoiding wasting CPU cycles if no MuSA vertices remain
287 if (workVerticesContainer.empty()) {
288 ATH_MSG_DEBUG("No MuSA vertices found after best overlap selection!");
289 return StatusCode::SUCCESS;
290 } else {
291 ATH_MSG_DEBUG("Found " << workVerticesContainer.size() << " MuSA vertices");
292 }
293
294 ATH_CHECK(fillCollections(workVerticesContainer, MuSAVtxContainer.ptr(), MuSAExtrapolatedTracksContainer.ptr(), *muonContainer, *MSTPContainer, ctx));
295 ATH_MSG_DEBUG("Saved MuSA collections!");
296
297 return StatusCode::SUCCESS;
298}
299}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
Handle class for adding a decoration to an object.
xAOD::MuonContainer * muonContainer
value_type emplace_back(value_type pElem)
Add an element to the end of the collection.
const T * at(size_type n) const
Access an element, as an rvalue.
value_type push_back(value_type pElem)
Add an element to the end of the collection.
size_type size() const noexcept
Returns the number of elements in the collection.
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_MSTPContainer
virtual ~MuSAVtxFitter()
StatusCode fillCollections(std::vector< MuSAVtxFitterTool::WrkVrt > &workVerticesContainer, xAOD::VertexContainer *MuSAVtxContainer, xAOD::TrackParticleContainer *MuSAExtrapolatedTracksContainer, const xAOD::MuonContainer &muonContainer, const xAOD::TrackParticleContainer &MSTPContainer, const EventContext &ctx) const
SG::ReadHandleKey< xAOD::MuonContainer > m_muonContainer
SG::WriteHandleKey< xAOD::VertexContainer > m_MuSAVertices
virtual StatusCode execute(const EventContext &ctx) const override
SG::WriteHandleKey< xAOD::TrackParticleContainer > m_MuSAExtrapolatedTracks
ToolHandle< Reco::ITrackToVertex > m_trackToVertexTool
virtual StatusCode initialize() override
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo
ToolHandle< Rec::MuSAVtxFitterTool > m_MuSAVtxFitterTool
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.
pointer_type ptr()
Dereference the pointer.
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.
@ theta
Definition ParamDefs.h:66
@ qOverP
perigee
Definition ParamDefs.h:67
@ phi
Definition ParamDefs.h:75
@ d0
Definition ParamDefs.h:63
@ z0
Definition ParamDefs.h:64
@ SecVtx
Secondary vertex.
TrackParticle_v1 TrackParticle
Reference the current persistent version:
VertexContainer_v1 VertexContainer
Definition of the current "Vertex container version".
Vertex_v1 Vertex
Define the latest version of the vertex class.
TrackParticleContainer_v1 TrackParticleContainer
Definition of the current "TrackParticle container version".
Muon_v1 Muon
Reference the current persistent version:
MuonContainer_v1 MuonContainer
Definition of the current "Muon container version".