ATLAS Offline Software
Loading...
Searching...
No Matches
PsiPlusPsiCascade.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2024 CERN for the benefit of the ATLAS collaboration
3 Contact: Xin Chen <xin.chen@cern.ch>
4*/
5#include "PsiPlusPsiCascade.h"
11#include "BPhysPVCascadeTools.h"
14#include "HepPDT/ParticleDataTable.hh"
16#include <algorithm>
17#include <functional>
18
19namespace DerivationFramework {
20 typedef ElementLink<xAOD::VertexContainer> VertexLink;
21 typedef std::vector<VertexLink> VertexLinkVector;
22
24 // retrieving vertex Fitter
25 ATH_CHECK( m_iVertexFitter.retrieve() );
26
27 // retrieve PV refitter
28 ATH_CHECK( m_pvRefitter.retrieve() );
29
30 // retrieving the V0 tools
31 ATH_CHECK( m_V0Tools.retrieve() );
32
33 // retrieving the Cascade tools
34 ATH_CHECK( m_CascadeTools.retrieve() );
35
36 ATH_CHECK( m_vertexPsi1ContainerKey.initialize() );
37 ATH_CHECK( m_vertexPsi2ContainerKey.initialize() );
38 ATH_CHECK( m_VxPrimaryCandidateName.initialize() );
39 ATH_CHECK( m_trackContainerName.initialize() );
40 ATH_CHECK( m_refPVContainerName.initialize() );
41 ATH_CHECK( m_cascadeOutputsKeys.initialize() );
42 ATH_CHECK( m_eventInfo_key.initialize() );
43
44 ATH_CHECK( m_partPropSvc.retrieve() );
45 auto pdt = m_partPropSvc->PDT();
46
47 // retrieve particle masses
48 // https://gitlab.cern.ch/atlas/athena/-/blob/main/Generators/TruthUtils/TruthUtils/AtlasPID.h
53
62
63 return StatusCode::SUCCESS;
64 }
65
66 StatusCode PsiPlusPsiCascade::addBranches(const EventContext& ctx) const {
67 if ((m_vtx1Daug_num != 3 && m_vtx1Daug_num != 4) || (m_vtx2Daug_num != 3 && m_vtx2Daug_num != 4)) {
68 ATH_MSG_FATAL("Incorrect number of Psi daughters (should be 3 or 4)");
69 return StatusCode::FAILURE;
70 }
71
72 constexpr int topoN = 3;
73 if(m_cascadeOutputsKeys.size() != topoN) {
74 ATH_MSG_FATAL("Incorrect number of VtxContainers");
75 return StatusCode::FAILURE;
76 }
77 std::array<SG::WriteHandle<xAOD::VertexContainer>, topoN> VtxWriteHandles; int ikey(0);
79 VtxWriteHandles[ikey] = SG::WriteHandle<xAOD::VertexContainer>(key, ctx);
80 ATH_CHECK( VtxWriteHandles[ikey].record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
81 ikey++;
82 }
83
84 //----------------------------------------------------
85 // retrieve primary vertices
86 //----------------------------------------------------
88 ATH_CHECK( pvContainer.isValid() );
89 if (pvContainer.cptr()->size()==0) {
90 ATH_MSG_WARNING("You have no primary vertices: " << pvContainer.cptr()->size());
91 return StatusCode::RECOVERABLE;
92 }
93
94 //----------------------------------------------------
95 // Record refitted primary vertices
96 //----------------------------------------------------
98 if(m_refitPV) {
100 ATH_CHECK( refPvContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
101 }
102
103 std::vector<Trk::VxCascadeInfo*> cascadeinfoContainer;
104 std::vector<Trk::VxCascadeInfo*> cascadeinfoContainer_noConstr;
105 ATH_CHECK(performSearch(&cascadeinfoContainer,&cascadeinfoContainer_noConstr,ctx));
106
108 ATH_CHECK( evt.isValid() );
109 BPhysPVCascadeTools helper(&(*m_CascadeTools), evt.cptr());
110 helper.SetMinNTracksInPV(m_PV_minNTracks);
111
112 // Decorators for the main vertex: chi2, ndf, pt and pt error, plus the V0 vertex variables
113 SG::AuxElement::Decorator<VertexLinkVector> CascadeLinksDecor("CascadeVertexLinks");
114 SG::AuxElement::Decorator<VertexLinkVector> Psi1LinksDecor("Psi1VertexLinks");
115 SG::AuxElement::Decorator<VertexLinkVector> Psi2LinksDecor("Psi2VertexLinks");
116 SG::AuxElement::Decorator<float> chi2_decor("ChiSquared");
117 SG::AuxElement::Decorator<int> ndof_decor("nDoF");
118 SG::AuxElement::Decorator<float> chi2_nc_decor("ChiSquared_nc");
119 SG::AuxElement::Decorator<int> ndof_nc_decor("nDoF_nc");
121 SG::AuxElement::Decorator<float> PtErr_decor("PtErr");
122 SG::AuxElement::Decorator<float> chi2_SV1_decor("ChiSquared_SV1");
123 SG::AuxElement::Decorator<float> chi2_nc_SV1_decor("ChiSquared_nc_SV1");
124 SG::AuxElement::Decorator<float> chi2_V1_decor("ChiSquared_V1");
125 SG::AuxElement::Decorator<int> ndof_V1_decor("nDoF_V1");
126 SG::AuxElement::Decorator<float> lxy_SV1_decor("lxy_SV1");
127 SG::AuxElement::Decorator<float> lxyErr_SV1_decor("lxyErr_SV1");
128 SG::AuxElement::Decorator<float> a0xy_SV1_decor("a0xy_SV1");
129 SG::AuxElement::Decorator<float> a0xyErr_SV1_decor("a0xyErr_SV1");
130 SG::AuxElement::Decorator<float> a0z_SV1_decor("a0z_SV1");
131 SG::AuxElement::Decorator<float> a0zErr_SV1_decor("a0zErr_SV1");
132 SG::AuxElement::Decorator<float> chi2_SV2_decor("ChiSquared_SV2");
133 SG::AuxElement::Decorator<float> chi2_nc_SV2_decor("ChiSquared_nc_SV2");
134 SG::AuxElement::Decorator<float> chi2_V2_decor("ChiSquared_V2");
135 SG::AuxElement::Decorator<int> ndof_V2_decor("nDoF_V2");
136 SG::AuxElement::Decorator<float> lxy_SV2_decor("lxy_SV2");
137 SG::AuxElement::Decorator<float> lxyErr_SV2_decor("lxyErr_SV2");
138 SG::AuxElement::Decorator<float> a0xy_SV2_decor("a0xy_SV2");
139 SG::AuxElement::Decorator<float> a0xyErr_SV2_decor("a0xyErr_SV2");
140 SG::AuxElement::Decorator<float> a0z_SV2_decor("a0z_SV2");
141 SG::AuxElement::Decorator<float> a0zErr_SV2_decor("a0zErr_SV2");
142
143 // Get the container and identify the input Psi's
145 ATH_CHECK( psi1Container.isValid() );
147 ATH_CHECK( psi2Container.isValid() );
148
149 for(size_t ic=0; ic<cascadeinfoContainer.size(); ic++) {
150 Trk::VxCascadeInfo* cascade_info = cascadeinfoContainer[ic];
151 if(cascade_info==nullptr) {
152 ATH_MSG_ERROR("CascadeInfo is null");
153 continue;
154 }
155
156 Trk::VxCascadeInfo* cascade_info_noConstr = cascadeinfoContainer_noConstr[ic];
157
158 const std::vector<xAOD::Vertex*> &cascadeVertices = cascade_info->vertices();
159 if(cascadeVertices.size() != topoN) ATH_MSG_ERROR("Incorrect number of vertices");
160 if(cascadeVertices[0]==nullptr || cascadeVertices[1]==nullptr || cascadeVertices[2]==nullptr) ATH_MSG_ERROR("Error null vertex");
161 // Keep vertices
162 for(int i=0; i<topoN; i++) VtxWriteHandles[i].ptr()->push_back(cascadeVertices[i]);
163
164 cascade_info->setSVOwnership(false); // Prevent Container from deleting vertices
165 const auto mainVertex = cascadeVertices[2]; // this is the mother vertex
166 const std::vector< std::vector<TLorentzVector> > &moms = cascade_info->getParticleMoms();
167
168 // Set links to cascade vertices
169 std::vector<VertexLink> precedingVertexLinks;
170 VertexLink vertexLink1;
171 vertexLink1.setElement(cascadeVertices[0]);
172 vertexLink1.setStorableObject(*VtxWriteHandles[0].ptr());
173 if( vertexLink1.isValid() ) precedingVertexLinks.push_back( vertexLink1 );
174 VertexLink vertexLink2;
175 vertexLink2.setElement(cascadeVertices[1]);
176 vertexLink2.setStorableObject(*VtxWriteHandles[1].ptr());
177 if( vertexLink2.isValid() ) precedingVertexLinks.push_back( vertexLink2 );
178 CascadeLinksDecor(*mainVertex) = precedingVertexLinks;
179
180 // Identify the input Psi2
181 const xAOD::Vertex* psi2Vertex(0);
182 if(m_vtx2Daug_num==4) psi2Vertex = BPhysPVCascadeTools::FindVertex<4>(psi2Container.cptr(), cascadeVertices[1]);
183 else psi2Vertex = BPhysPVCascadeTools::FindVertex<3>(psi2Container.cptr(), cascadeVertices[1]);
184 // Identify the input Psi1
185 const xAOD::Vertex* psi1Vertex(0);
186 if(m_vtx1Daug_num==4) psi1Vertex = BPhysPVCascadeTools::FindVertex<4>(psi1Container.cptr(), cascadeVertices[0]);
187 else psi1Vertex = BPhysPVCascadeTools::FindVertex<3>(psi1Container.cptr(), cascadeVertices[0]);
188
189 // Set links to input vertices
190 std::vector<const xAOD::Vertex*> psi2VerticestoLink;
191 if(psi2Vertex) psi2VerticestoLink.push_back(psi2Vertex);
192 else ATH_MSG_WARNING("Could not find linking Jpsi");
193 if(!BPhysPVCascadeTools::LinkVertices(Psi2LinksDecor, psi2VerticestoLink, psi2Container.cptr(), mainVertex)) ATH_MSG_ERROR("Error decorating with Psi2 vertex");
194
195 std::vector<const xAOD::Vertex*> psi1VerticestoLink;
196 if(psi1Vertex) psi1VerticestoLink.push_back(psi1Vertex);
197 else ATH_MSG_WARNING("Could not find linking Psi1");
198 if(!BPhysPVCascadeTools::LinkVertices(Psi1LinksDecor, psi1VerticestoLink, psi1Container.cptr(), mainVertex)) ATH_MSG_ERROR("Error decorating with Psi1 vertex");
199
200 xAOD::BPhysHypoHelper vtx(m_hypoName, mainVertex);
201
202 // Get refitted track momenta from all vertices, charged tracks only
203 BPhysPVCascadeTools::SetVectorInfo(vtx, cascade_info);
204 vtx.setPass(true);
205
206 //
207 // Decorate main vertex
208 //
209 // mass, mass error
210 // https://gitlab.cern.ch/atlas/athena/-/blob/21.2/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/VxCascadeInfo.h
211 BPHYS_CHECK( vtx.setMass(m_CascadeTools->invariantMass(moms[2])) );
212 BPHYS_CHECK( vtx.setMassErr(m_CascadeTools->invariantMassError(moms[2],cascade_info->getCovariance()[1])) );
213 // pt and pT error (the default pt of mainVertex is != the pt of the full cascade fit!)
214 Pt_decor(*mainVertex) = m_CascadeTools->pT(moms[2]);
215 PtErr_decor(*mainVertex) = m_CascadeTools->pTError(moms[2],cascade_info->getCovariance()[1]);
216 // chi2 and ndof (the default chi2 of mainVertex is != the chi2 of the full cascade fit!)
217 chi2_decor(*mainVertex) = cascade_info->fitChi2();
218 ndof_decor(*mainVertex) = cascade_info->nDoF();
219 chi2_nc_decor(*mainVertex) = cascade_info_noConstr ? cascade_info_noConstr->fitChi2() : -999999.;
220 ndof_nc_decor(*mainVertex) = cascade_info_noConstr ? cascade_info_noConstr->nDoF() : -1;
221
222 // decorate the Psi1 vertex
223 chi2_SV1_decor(*cascadeVertices[0]) = m_V0Tools->chisq(cascadeVertices[0]);
224 chi2_nc_SV1_decor(*cascadeVertices[0]) = cascade_info_noConstr ? m_V0Tools->chisq(cascade_info_noConstr->vertices()[0]) : -999999.;
225 chi2_V1_decor(*cascadeVertices[0]) = m_V0Tools->chisq(psi1Vertex);
226 ndof_V1_decor(*cascadeVertices[0]) = m_V0Tools->ndof(psi1Vertex);
227 lxy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxy(moms[0],cascadeVertices[0],mainVertex);
228 lxyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
229 a0z_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0z(moms[0],cascadeVertices[0],mainVertex);
230 a0zErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0zError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
231 a0xy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xy(moms[0],cascadeVertices[0],mainVertex);
232 a0xyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
233
234 // decorate the Psi2 vertex
235 chi2_SV2_decor(*cascadeVertices[1]) = m_V0Tools->chisq(cascadeVertices[1]);
236 chi2_nc_SV2_decor(*cascadeVertices[1]) = cascade_info_noConstr ? m_V0Tools->chisq(cascade_info_noConstr->vertices()[1]) : -999999.;
237 chi2_V2_decor(*cascadeVertices[1]) = m_V0Tools->chisq(psi2Vertex);
238 ndof_V2_decor(*cascadeVertices[1]) = m_V0Tools->ndof(psi2Vertex);
239 lxy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxy(moms[1],cascadeVertices[1],mainVertex);
240 lxyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
241 a0z_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0z(moms[1],cascadeVertices[1],mainVertex);
242 a0zErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0zError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
243 a0xy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xy(moms[1],cascadeVertices[1],mainVertex);
244 a0xyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
245
246 double Mass_Moth = m_CascadeTools->invariantMass(moms[2]); // size=2
247 ATH_CHECK(helper.FillCandwithRefittedVertices(m_refitPV, pvContainer.cptr(), m_refitPV ? refPvContainer.ptr() : 0, &(*m_pvRefitter), m_PV_max, m_DoVertexType, cascade_info, 2, Mass_Moth, vtx));
248 } // loop over cascadeinfoContainer
249
250 // Deleting cascadeinfo since this won't be stored.
251 // Vertices have been kept in m_cascadeOutputs and should be owned by their container
252 for (auto cascade_info : cascadeinfoContainer) delete cascade_info;
253 for (auto cascade_info_noConstr : cascadeinfoContainer_noConstr) delete cascade_info_noConstr;
254
255 return StatusCode::SUCCESS;
256 }
257
258 PsiPlusPsiCascade::PsiPlusPsiCascade(const std::string& type, const std::string& name, const IInterface* parent) : base_class(type,name,parent),
261 m_cascadeOutputsKeys({"PsiPlusPsiCascadeVtx1", "PsiPlusPsiCascadeVtx2", "PsiPlusPsiCascadeVtx3"}),
262 m_VxPrimaryCandidateName("PrimaryVertices"),
263 m_trackContainerName("InDetTrackParticles"),
264 m_eventInfo_key("EventInfo"),
265 m_jpsi1MassLower(0.0),
266 m_jpsi1MassUpper(20000.0),
267 m_jpsi2MassLower(0.0),
268 m_jpsi2MassUpper(20000.0),
269 m_diTrack1MassLower(-1.0),
270 m_diTrack1MassUpper(-1.0),
271 m_diTrack2MassLower(-1.0),
272 m_diTrack2MassUpper(-1.0),
273 m_psi1MassLower(0.0),
274 m_psi1MassUpper(25000.0),
275 m_psi2MassLower(0.0),
276 m_psi2MassUpper(25000.0),
277 m_MassLower(0.0),
278 m_MassUpper(31000.0),
279 m_vtx1Daug_num(4),
280 m_vtx1Daug1MassHypo(-1),
281 m_vtx1Daug2MassHypo(-1),
282 m_vtx1Daug3MassHypo(-1),
283 m_vtx1Daug4MassHypo(-1),
284 m_vtx2Daug_num(4),
285 m_vtx2Daug1MassHypo(-1),
286 m_vtx2Daug2MassHypo(-1),
287 m_vtx2Daug3MassHypo(-1),
288 m_vtx2Daug4MassHypo(-1),
289 m_massPsi1(-1),
290 m_massPsi2(-1),
291 m_massJpsi1(-1),
292 m_massJpsi2(-1),
293 m_massDiTrk1(-1),
294 m_massDiTrk2(-1),
295 m_constrPsi1(false),
296 m_constrPsi2(false),
297 m_constrJpsi1(false),
298 m_constrJpsi2(false),
299 m_constrDiTrk1(false),
300 m_constrDiTrk2(false),
301 m_chi2cut_Psi1(-1.0),
302 m_chi2cut_Psi2(-1.0),
303 m_chi2cut(-1.0),
304 m_removeDuplicatePairs(false),
305 m_maxCandidates(0),
306 m_iVertexFitter("Trk::TrkVKalVrtFitter"),
307 m_pvRefitter("Analysis::PrimaryVertexRefitter", this),
308 m_V0Tools("Trk::V0Tools"),
309 m_CascadeTools("DerivationFramework::CascadeTools")
310 {
311 declareProperty("Psi1Vertices", m_vertexPsi1ContainerKey);
312 declareProperty("Psi2Vertices", m_vertexPsi2ContainerKey);
313 declareProperty("Psi1VtxHypoNames", m_vertexPsi1HypoNames);
314 declareProperty("Psi2VtxHypoNames", m_vertexPsi2HypoNames);
315 declareProperty("VxPrimaryCandidateName", m_VxPrimaryCandidateName);
316 declareProperty("TrackContainerName", m_trackContainerName);
317 declareProperty("RefPVContainerName", m_refPVContainerName = "RefittedPrimaryVertices");
318 declareProperty("Jpsi1MassLowerCut", m_jpsi1MassLower);
319 declareProperty("Jpsi1MassUpperCut", m_jpsi1MassUpper);
320 declareProperty("Jpsi2MassLowerCut", m_jpsi2MassLower);
321 declareProperty("Jpsi2MassUpperCut", m_jpsi2MassUpper);
322 declareProperty("DiTrack1MassLower", m_diTrack1MassLower); // only effective when m_vtx1Daug_num=4
323 declareProperty("DiTrack1MassUpper", m_diTrack1MassUpper); // only effective when m_vtx1Daug_num=4
324 declareProperty("DiTrack2MassLower", m_diTrack2MassLower); // only effective when m_vtx2Daug_num=4
325 declareProperty("DiTrack2MassUpper", m_diTrack2MassUpper); // only effective when m_vtx2Daug_num=4
326 declareProperty("Psi1MassLowerCut", m_psi1MassLower);
327 declareProperty("Psi1MassUpperCut", m_psi1MassUpper);
328 declareProperty("Psi2MassLowerCut", m_psi2MassLower);
329 declareProperty("Psi2MassUpperCut", m_psi2MassUpper);
330 declareProperty("MassLowerCut", m_MassLower);
331 declareProperty("MassUpperCut", m_MassUpper);
332 declareProperty("HypothesisName", m_hypoName = "TQ");
333 declareProperty("NumberOfPsi1Daughters", m_vtx1Daug_num); // 3 or 4 only
334 declareProperty("Vtx1Daug1MassHypo", m_vtx1Daug1MassHypo);
335 declareProperty("Vtx1Daug2MassHypo", m_vtx1Daug2MassHypo);
336 declareProperty("Vtx1Daug3MassHypo", m_vtx1Daug3MassHypo);
337 declareProperty("Vtx1Daug4MassHypo", m_vtx1Daug4MassHypo);
338 declareProperty("NumberOfPsi2Daughters", m_vtx2Daug_num); // 3 or 4 only
339 declareProperty("Vtx2Daug1MassHypo", m_vtx2Daug1MassHypo);
340 declareProperty("Vtx2Daug2MassHypo", m_vtx2Daug2MassHypo);
341 declareProperty("Vtx2Daug3MassHypo", m_vtx2Daug3MassHypo);
342 declareProperty("Vtx2Daug4MassHypo", m_vtx2Daug4MassHypo);
343 declareProperty("Jpsi1Mass", m_massJpsi1);
344 declareProperty("Jpsi2Mass", m_massJpsi2);
345 declareProperty("DiTrack1Mass", m_massDiTrk1);
346 declareProperty("DiTrack2Mass", m_massDiTrk2);
347 declareProperty("Psi1Mass", m_massPsi1);
348 declareProperty("Psi2Mass", m_massPsi2);
349 declareProperty("ApplyPsi1MassConstraint", m_constrPsi1);
350 declareProperty("ApplyPsi2MassConstraint", m_constrPsi2);
351 declareProperty("ApplyJpsi1MassConstraint", m_constrJpsi1);
352 declareProperty("ApplyJpsi2MassConstraint", m_constrJpsi2);
353 declareProperty("ApplyDiTrk1MassConstraint",m_constrDiTrk1); // only effective when m_vtx1Daug_num=4
354 declareProperty("ApplyDiTrk2MassConstraint",m_constrDiTrk2); // only effective when m_vtx2Daug_num=4
355 declareProperty("Chi2CutPsi1", m_chi2cut_Psi1);
356 declareProperty("Chi2CutPsi2", m_chi2cut_Psi2);
357 declareProperty("Chi2Cut", m_chi2cut);
358 declareProperty("RemoveDuplicatePairs", m_removeDuplicatePairs); // only effective when m_vertexPsi1ContainerKey == m_vertexPsi2ContainerKey
359 declareProperty("MaxCandidates", m_maxCandidates);
360 declareProperty("RefitPV", m_refitPV = true);
361 declareProperty("MaxnPV", m_PV_max = 1000);
362 declareProperty("MinNTracksInPV", m_PV_minNTracks = 0);
363 declareProperty("DoVertexType", m_DoVertexType = 7);
364 declareProperty("TrkVertexFitterTool", m_iVertexFitter);
365 declareProperty("PVRefitter", m_pvRefitter);
366 declareProperty("V0Tools", m_V0Tools);
367 declareProperty("CascadeTools", m_CascadeTools);
368 declareProperty("CascadeVertexCollections", m_cascadeOutputsKeys);
369 }
370
371 StatusCode PsiPlusPsiCascade::performSearch(std::vector<Trk::VxCascadeInfo*> *cascadeinfoContainer, std::vector<Trk::VxCascadeInfo*> *cascadeinfoContainer_noConstr, const EventContext& ctx) const {
372 ATH_MSG_DEBUG( "PsiPlusPsiCascade::performSearch" );
373 assert(cascadeinfoContainer!=nullptr && cascadeinfoContainer_noConstr!=nullptr);
374
375 // Get TrackParticle container (for setting links to the original tracks)
377 ATH_CHECK( trackContainer.isValid() );
378
379 std::vector<const xAOD::TrackParticle*> tracksJpsi1;
380 std::vector<const xAOD::TrackParticle*> tracksJpsi2;
381 std::vector<const xAOD::TrackParticle*> tracksDiTrk1;
382 std::vector<const xAOD::TrackParticle*> tracksDiTrk2;
383 std::vector<const xAOD::TrackParticle*> tracksPsi1;
384 std::vector<const xAOD::TrackParticle*> tracksPsi2;
385 std::vector<double> massesPsi1;
386 massesPsi1.push_back(m_vtx1Daug1MassHypo);
387 massesPsi1.push_back(m_vtx1Daug2MassHypo);
388 massesPsi1.push_back(m_vtx1Daug3MassHypo);
389 if(m_vtx1Daug_num==4) massesPsi1.push_back(m_vtx1Daug4MassHypo);
390 std::vector<double> massesPsi2;
391 massesPsi2.push_back(m_vtx2Daug1MassHypo);
392 massesPsi2.push_back(m_vtx2Daug2MassHypo);
393 massesPsi2.push_back(m_vtx2Daug3MassHypo);
394 if(m_vtx2Daug_num==4) massesPsi2.push_back(m_vtx2Daug4MassHypo);
395
396 // Get Psi1 container
398 ATH_CHECK( psi1Container.isValid() );
399
400 // Get Psi2 container
402 ATH_CHECK( psi2Container.isValid() );
403
404 // Select the Psi2 candidates before calling cascade fit
405 std::vector<const xAOD::Vertex*> selectedPsi2Candidates;
406 for(auto vxcItr=psi2Container.cptr()->cbegin(); vxcItr!=psi2Container.cptr()->cend(); ++vxcItr) {
407 // Check the passed flag first
408 const xAOD::Vertex* vtx = *vxcItr;
409 bool passed = false;
410 for(size_t i=0; i<m_vertexPsi2HypoNames.size(); i++) {
412 if(flagAcc.isAvailable(*vtx) && flagAcc(*vtx)) {
413 passed |= 1;
414 }
415 }
416 if(m_vertexPsi2HypoNames.size() && !passed) continue;
417
418 // Check Psi2 candidate invariant mass and skip if need be
419 double mass_psi2 = m_V0Tools->invariantMass(*vxcItr, massesPsi2);
420 if (mass_psi2 < m_psi2MassLower || mass_psi2 > m_psi2MassUpper) continue;
421
422 // Add loose cut on Jpsi2 mass from Psi2 -> Jpsi2 pi+ pi-, or on phi mass from Ds+ -> phi pi+
423 TLorentzVector p4_mu1, p4_mu2;
424 p4_mu1.SetPtEtaPhiM( (*vxcItr)->trackParticle(0)->pt(),
425 (*vxcItr)->trackParticle(0)->eta(),
426 (*vxcItr)->trackParticle(0)->phi(), m_vtx2Daug1MassHypo);
427 p4_mu2.SetPtEtaPhiM( (*vxcItr)->trackParticle(1)->pt(),
428 (*vxcItr)->trackParticle(1)->eta(),
429 (*vxcItr)->trackParticle(1)->phi(), m_vtx2Daug2MassHypo);
430 double mass_jpsi2 = (p4_mu1 + p4_mu2).M();
431 if (mass_jpsi2 < m_jpsi2MassLower || mass_jpsi2 > m_jpsi2MassUpper) continue;
432
434 TLorentzVector p4_trk1, p4_trk2;
435 p4_trk1.SetPtEtaPhiM( (*vxcItr)->trackParticle(2)->pt(),
436 (*vxcItr)->trackParticle(2)->eta(),
437 (*vxcItr)->trackParticle(2)->phi(), m_vtx2Daug3MassHypo);
438 p4_trk2.SetPtEtaPhiM( (*vxcItr)->trackParticle(3)->pt(),
439 (*vxcItr)->trackParticle(3)->eta(),
440 (*vxcItr)->trackParticle(3)->phi(), m_vtx2Daug4MassHypo);
441 double mass_diTrk2 = (p4_trk1 + p4_trk2).M();
442 if (mass_diTrk2 < m_diTrack2MassLower || mass_diTrk2 > m_diTrack2MassUpper) continue;
443 }
444
445 double chi2DOF = (*vxcItr)->chiSquared()/(*vxcItr)->numberDoF();
446 if(m_chi2cut_Psi2>0 && chi2DOF>m_chi2cut_Psi2) continue;
447
448 selectedPsi2Candidates.push_back(*vxcItr);
449 }
450 if(selectedPsi2Candidates.size()==0) return StatusCode::SUCCESS;
451
452 // Select the Psi1 candidates before calling cascade fit
453 std::vector<const xAOD::Vertex*> selectedPsi1Candidates;
454 for(auto vxcItr=psi1Container.cptr()->cbegin(); vxcItr!=psi1Container.cptr()->cend(); ++vxcItr) {
455 // Check the passed flag first
456 const xAOD::Vertex* vtx = *vxcItr;
457 bool passed = false;
458 for(size_t i=0; i<m_vertexPsi1HypoNames.size(); i++) {
460 if(flagAcc.isAvailable(*vtx) && flagAcc(*vtx)) {
461 passed |= 1;
462 }
463 }
464 if(m_vertexPsi1HypoNames.size() && !passed) continue;
465
466 // Check Psi candidate invariant mass and skip if need be
467 double mass_psi1 = m_V0Tools->invariantMass(*vxcItr,massesPsi1);
468 if(mass_psi1 < m_psi1MassLower || mass_psi1 > m_psi1MassUpper) continue;
469
470 // Add loose cut on Jpsi1 mass from Psi1 -> Jpsi1 pi+ pi-, or on phi mass from Ds+ -> phi pi+
471 TLorentzVector p4_mu1, p4_mu2;
472 p4_mu1.SetPtEtaPhiM( (*vxcItr)->trackParticle(0)->pt(),
473 (*vxcItr)->trackParticle(0)->eta(),
474 (*vxcItr)->trackParticle(0)->phi(), m_vtx1Daug1MassHypo);
475 p4_mu2.SetPtEtaPhiM( (*vxcItr)->trackParticle(1)->pt(),
476 (*vxcItr)->trackParticle(1)->eta(),
477 (*vxcItr)->trackParticle(1)->phi(), m_vtx1Daug2MassHypo);
478 double mass_jpsi1 = (p4_mu1 + p4_mu2).M();
479 if (mass_jpsi1 < m_jpsi1MassLower || mass_jpsi1 > m_jpsi1MassUpper) continue;
480
482 TLorentzVector p4_trk1, p4_trk2;
483 p4_trk1.SetPtEtaPhiM( (*vxcItr)->trackParticle(2)->pt(),
484 (*vxcItr)->trackParticle(2)->eta(),
485 (*vxcItr)->trackParticle(2)->phi(), m_vtx1Daug3MassHypo);
486 p4_trk2.SetPtEtaPhiM( (*vxcItr)->trackParticle(3)->pt(),
487 (*vxcItr)->trackParticle(3)->eta(),
488 (*vxcItr)->trackParticle(3)->phi(), m_vtx1Daug4MassHypo);
489 double mass_diTrk1 = (p4_trk1 + p4_trk2).M();
490 if (mass_diTrk1 < m_diTrack1MassLower || mass_diTrk1 > m_diTrack1MassUpper) continue;
491 }
492
493 double chi2DOF = (*vxcItr)->chiSquared()/(*vxcItr)->numberDoF();
494 if(m_chi2cut_Psi1>0 && chi2DOF>m_chi2cut_Psi1) continue;
495
496 selectedPsi1Candidates.push_back(*vxcItr);
497 }
498 if(selectedPsi1Candidates.size()==0) return StatusCode::SUCCESS;
499
500 std::vector<std::pair<const xAOD::Vertex*, const xAOD::Vertex*> > candidatePairs;
501 for(auto psi1Itr=selectedPsi1Candidates.cbegin(); psi1Itr!=selectedPsi1Candidates.cend(); ++psi1Itr) {
502 tracksPsi1.clear();
503 for(size_t i=0; i<(*psi1Itr)->nTrackParticles(); i++) tracksPsi1.push_back((*psi1Itr)->trackParticle(i));
504 for(auto psi2Itr=selectedPsi2Candidates.cbegin(); psi2Itr!=selectedPsi2Candidates.cend(); ++psi2Itr) {
505 bool skip = false;
506 for(size_t j=0; j<(*psi2Itr)->nTrackParticles(); j++) {
507 if(std::find(tracksPsi1.cbegin(), tracksPsi1.cend(), (*psi2Itr)->trackParticle(j)) != tracksPsi1.cend()) { skip = true; break; }
508 }
509 if(skip) continue;
511 for(size_t ic=0; ic<candidatePairs.size(); ic++) {
512 const xAOD::Vertex* psi1Vertex = candidatePairs[ic].first;
513 const xAOD::Vertex* psi2Vertex = candidatePairs[ic].second;
514 if((psi1Vertex == *psi1Itr && psi2Vertex == *psi2Itr) || (psi1Vertex == *psi2Itr && psi2Vertex == *psi1Itr)) { skip = true; break; }
515 }
516 }
517 if(skip) continue;
518 candidatePairs.push_back(std::pair<const xAOD::Vertex*, const xAOD::Vertex*>(*psi1Itr,*psi2Itr));
519 }
520 }
521
522 std::sort( candidatePairs.begin(), candidatePairs.end(), [](std::pair<const xAOD::Vertex*, const xAOD::Vertex*> a, std::pair<const xAOD::Vertex*, const xAOD::Vertex*> b) { return a.first->chiSquared()/a.first->numberDoF()+a.second->chiSquared()/a.second->numberDoF() < b.first->chiSquared()/b.first->numberDoF()+b.second->chiSquared()/b.second->numberDoF(); } );
523 if(m_maxCandidates>0 && candidatePairs.size()>m_maxCandidates) {
524 candidatePairs.erase(candidatePairs.begin()+m_maxCandidates, candidatePairs.end());
525 }
526
527 for(size_t ic=0; ic<candidatePairs.size(); ic++) {
528 const xAOD::Vertex* psi1Vertex = candidatePairs[ic].first;
529 const xAOD::Vertex* psi2Vertex = candidatePairs[ic].second;
530
531 tracksPsi1.clear();
532 for(size_t it=0; it<psi1Vertex->nTrackParticles(); it++) tracksPsi1.push_back(psi1Vertex->trackParticle(it));
533 if (tracksPsi1.size() != massesPsi1.size()) {
534 ATH_MSG_ERROR("Problems with Psi1 input: number of tracks or track mass inputs is not correct!");
535 }
536 tracksPsi2.clear();
537 for(size_t it=0; it<psi2Vertex->nTrackParticles(); it++) tracksPsi2.push_back(psi2Vertex->trackParticle(it));
538 if (tracksPsi2.size() != massesPsi2.size()) {
539 ATH_MSG_ERROR("Problems with Psi2 input: number of tracks or track mass inputs is not correct!");
540 }
541
542 tracksJpsi1.clear();
543 tracksJpsi1.push_back(psi1Vertex->trackParticle(0));
544 tracksJpsi1.push_back(psi1Vertex->trackParticle(1));
545 tracksDiTrk1.clear();
546 if(m_vtx1Daug_num==4) {
547 tracksDiTrk1.push_back(psi1Vertex->trackParticle(2));
548 tracksDiTrk1.push_back(psi1Vertex->trackParticle(3));
549 }
550 tracksJpsi2.clear();
551 tracksJpsi2.push_back(psi2Vertex->trackParticle(0));
552 tracksJpsi2.push_back(psi2Vertex->trackParticle(1));
553 tracksDiTrk2.clear();
554 if(m_vtx2Daug_num==4) {
555 tracksDiTrk2.push_back(psi2Vertex->trackParticle(2));
556 tracksDiTrk2.push_back(psi2Vertex->trackParticle(3));
557 }
558
559 TLorentzVector p4_moth;
560 TLorentzVector tmp;
561 for(size_t it=0; it<psi1Vertex->nTrackParticles(); it++) {
562 tmp.SetPtEtaPhiM(psi1Vertex->trackParticle(it)->pt(),psi1Vertex->trackParticle(it)->eta(),psi1Vertex->trackParticle(it)->phi(),massesPsi1[it]);
563 p4_moth += tmp;
564 }
565 for(size_t it=0; it<psi2Vertex->nTrackParticles(); it++) {
566 tmp.SetPtEtaPhiM(psi2Vertex->trackParticle(it)->pt(),psi2Vertex->trackParticle(it)->eta(),psi2Vertex->trackParticle(it)->phi(),massesPsi2[it]);
567 p4_moth += tmp;
568 }
569 if (p4_moth.M() < m_MassLower || p4_moth.M() > m_MassUpper) continue;
570
571 // Apply the user's settings to the fitter
572 std::unique_ptr<Trk::IVKalState> state = m_iVertexFitter->makeState();
573 // Robustness: http://cdsweb.cern.ch/record/685551
574 int robustness = 0;
575 m_iVertexFitter->setRobustness(robustness, *state);
576 // Build up the topology
577 // Vertex list
578 std::vector<Trk::VertexID> vrtList;
579 // Psi1 vertex
580 Trk::VertexID vID1;
581 // https://gitlab.cern.ch/atlas/athena/-/blob/21.2/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/IVertexCascadeFitter.h
582 if (m_constrPsi1) {
583 vID1 = m_iVertexFitter->startVertex(tracksPsi1,massesPsi1,*state,m_massPsi1);
584 } else {
585 vID1 = m_iVertexFitter->startVertex(tracksPsi1,massesPsi1,*state);
586 }
587 vrtList.push_back(vID1);
588 // Psi2 vertex
589 Trk::VertexID vID2;
590 if (m_constrPsi2) {
591 vID2 = m_iVertexFitter->nextVertex(tracksPsi2,massesPsi2,*state,m_massPsi2);
592 } else {
593 vID2 = m_iVertexFitter->nextVertex(tracksPsi2,massesPsi2,*state);
594 }
595 vrtList.push_back(vID2);
596 // Mother vertex including Psi1 and Psi2
597 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
598 std::vector<double> tp_masses; tp_masses.clear();
599 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList,*state);
600 if (m_constrJpsi1) {
601 std::vector<Trk::VertexID> cnstV; cnstV.clear();
602 if ( !m_iVertexFitter->addMassConstraint(vID1,tracksJpsi1,cnstV,*state,m_massJpsi1).isSuccess() ) {
603 ATH_MSG_WARNING("addMassConstraint for Jpsi1 failed");
604 }
605 }
607 std::vector<Trk::VertexID> cnstV; cnstV.clear();
608 if ( !m_iVertexFitter->addMassConstraint(vID1,tracksDiTrk1,cnstV,*state,m_massDiTrk1).isSuccess() ) {
609 ATH_MSG_WARNING("addMassConstraint for DiTrk1 failed");
610 }
611 }
612 if (m_constrJpsi2) {
613 std::vector<Trk::VertexID> cnstV; cnstV.clear();
614 if ( !m_iVertexFitter->addMassConstraint(vID2,tracksJpsi2,cnstV,*state,m_massJpsi2).isSuccess() ) {
615 ATH_MSG_WARNING("addMassConstraint for Jpsi2 failed");
616 }
617 }
619 std::vector<Trk::VertexID> cnstV; cnstV.clear();
620 if ( !m_iVertexFitter->addMassConstraint(vID2,tracksDiTrk2,cnstV,*state,m_massDiTrk2).isSuccess() ) {
621 ATH_MSG_WARNING("addMassConstraint for DiTrk2 failed");
622 }
623 }
624 // Do the work
625 std::unique_ptr<Trk::VxCascadeInfo> result(m_iVertexFitter->fitCascade(*state));
626
627 bool pass = false;
628 if (result != nullptr) {
629 for(auto v : result->vertices()) {
630 if(v->nTrackParticles()==0) {
631 std::vector<ElementLink<xAOD::TrackParticleContainer> > nullLinkVector;
632 v->setTrackParticleLinks(nullLinkVector);
633 }
634 }
635 // reset links to original tracks
636 BPhysPVCascadeTools::PrepareVertexLinks(result.get(), trackContainer.cptr());
637
638 // necessary to prevent memory leak
639 result->setSVOwnership(true);
640
641 // Chi2/DOF cut
642 double chi2DOF = result->fitChi2()/result->nDoF();
643 bool chi2CutPassed = (m_chi2cut <= 0.0 || chi2DOF < m_chi2cut);
644
645 if(chi2CutPassed) {
646 cascadeinfoContainer->push_back(result.release());
647 pass = true;
648 }
649 }
650
651 // do cascade fit again without any mass constraints
652 if(pass) {
654 std::unique_ptr<Trk::IVKalState> state (m_iVertexFitter->makeState());
655 m_iVertexFitter->setRobustness(robustness, *state);
656 std::vector<Trk::VertexID> vrtList_nc;
657 // Psi1 vertex
658 Trk::VertexID vID1_nc = m_iVertexFitter->startVertex(tracksPsi1,massesPsi1,*state);
659 vrtList_nc.push_back(vID1_nc);
660 // Psi2 vertex
661 Trk::VertexID vID2_nc = m_iVertexFitter->nextVertex(tracksPsi2,massesPsi2,*state);
662 vrtList_nc.push_back(vID2_nc);
663 // Mother vertex including Psi1 and Psi2
664 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
665 std::vector<double> tp_masses; tp_masses.clear();
666 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList_nc,*state);
667 // Do the work
668 std::unique_ptr<Trk::VxCascadeInfo> result_nc(m_iVertexFitter->fitCascade(*state));
669
670 if (result_nc != nullptr) {
671 for(auto v : result_nc->vertices()) {
672 if(v->nTrackParticles()==0) {
673 std::vector<ElementLink<xAOD::TrackParticleContainer> > nullLinkVector;
674 v->setTrackParticleLinks(nullLinkVector);
675 }
676 }
677 // reset links to original tracks
678 BPhysPVCascadeTools::PrepareVertexLinks(result_nc.get(), trackContainer.cptr());
679
680 // necessary to prevent memory leak
681 result_nc->setSVOwnership(true);
682 cascadeinfoContainer_noConstr->push_back(result_nc.release());
683 }
684 else cascadeinfoContainer_noConstr->push_back(0);
685 }
686 else cascadeinfoContainer_noConstr->push_back(0);
687 }
688 } //Iterate over candidatePairs
689
690 return StatusCode::SUCCESS;
691 }
692}
#define ATH_CHECK
Evaluate an expression and check for errors.
#define ATH_MSG_ERROR(x)
#define ATH_MSG_FATAL(x)
#define ATH_MSG_WARNING(x)
#define ATH_MSG_DEBUG(x)
#define BPHYS_CHECK(EXP)
Useful CHECK macro.
: B-physics xAOD helpers.
ATLAS-specific HepMC functions.
bool passed(DecisionID id, const DecisionIDContainer &)
checks if required decision ID is in the set of IDs in the container
static Double_t a
static bool LinkVertices(SG::AuxElement::Decorator< VertexLinkVector > &decor, const std::vector< const xAOD::Vertex * > &vertices, const xAOD::VertexContainer *vertexContainer, const xAOD::Vertex *vert)
static void PrepareVertexLinks(Trk::VxCascadeInfo *result, const xAOD::TrackParticleContainer *importedTrackCollection)
static double getParticleMass(const HepPDT::ParticleDataTable *pdt, int pdg)
static const xAOD::Vertex * FindVertex(const xAOD::VertexContainer *c, const xAOD::Vertex *v)
static void SetVectorInfo(xAOD::BPhysHelper &, const Trk::VxCascadeInfo *)
ToolHandle< Analysis::PrimaryVertexRefitter > m_pvRefitter
SG::WriteHandleKeyArray< xAOD::VertexContainer > m_cascadeOutputsKeys
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexPsi1ContainerKey
virtual StatusCode initialize() override
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo_key
ToolHandle< Trk::TrkVKalVrtFitter > m_iVertexFitter
ServiceHandle< IPartPropSvc > m_partPropSvc
ToolHandle< DerivationFramework::CascadeTools > m_CascadeTools
std::vector< std::string > m_vertexPsi1HypoNames
virtual StatusCode addBranches(const EventContext &ctx) const override
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexPsi2ContainerKey
std::vector< std::string > m_vertexPsi2HypoNames
StatusCode performSearch(std::vector< Trk::VxCascadeInfo * > *cascadeinfoContainer, std::vector< Trk::VxCascadeInfo * > *cascadeinfoContainer_noConstr, const EventContext &ctx) const
SG::ReadHandleKey< xAOD::VertexContainer > m_VxPrimaryCandidateName
Name of primary vertex container.
PsiPlusPsiCascade(const std::string &type, const std::string &name, const IInterface *parent)
SG::WriteHandleKey< xAOD::VertexContainer > m_refPVContainerName
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackContainerName
SG::Decorator< T, ALLOC > Decorator
Definition AuxElement.h:575
SG::Accessor< T, ALLOC > Accessor
Definition AuxElement.h:572
bool isAvailable(const ELT &e) const
Test to see if this variable exists in the store.
virtual bool isValid() override final
Can the handle be successfully dereferenced?
const_pointer_type cptr()
Dereference the pointer.
Property holding a SG store/key/clid from which a WriteHandle is made.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
double fitChi2() const
const std::vector< Amg::MatrixX > & getCovariance() const
const std::vector< std::vector< TLorentzVector > > & getParticleMoms() const
const std::vector< xAOD::Vertex * > & vertices() const
void setSVOwnership(bool Ownership)
bool setMass(const float val)
Set given invariant mass and its error.
bool setPass(bool passVal)
get the pass flag for this hypothesis
bool setMassErr(const float val)
invariant mass error
virtual double phi() const override final
The azimuthal angle ( ) of the particle (has range to .)
virtual double pt() const override final
The transverse momentum ( ) of the particle.
virtual double eta() const override final
The pseudorapidity ( ) of the particle.
size_t nTrackParticles() const
Get the number of tracks associated with this vertex.
const TrackParticle * trackParticle(size_t i) const
Get the pointer to a given track that was used in vertex reco.
THE reconstruction tool.
ElementLink< xAOD::VertexContainer > VertexLink
std::vector< VertexLink > VertexLinkVector
static const int PSI2S
static const int MUON
static const int PIPLUS
static const int JPSI
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
Vertex_v1 Vertex
Define the latest version of the vertex class.