ATLAS Offline Software
Loading...
Searching...
No Matches
JpsiPlusPsiCascade.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2026 CERN for the benefit of the ATLAS collaboration
3 Contact: Xin Chen <xin.chen@cern.ch>
4*/
11#include "BPhysPVCascadeTools.h"
16#include <algorithm>
17
18namespace DerivationFramework {
19 typedef ElementLink<xAOD::VertexContainer> VertexLink;
20 typedef std::vector<VertexLink> VertexLinkVector;
21
23 // retrieving vertex Fitter
24 ATH_CHECK( m_iVertexFitter.retrieve() );
25
26 // retrieve PV refitter
27 ATH_CHECK( m_pvRefitter.retrieve() );
28
29 // retrieving the V0 tools
30 ATH_CHECK( m_V0Tools.retrieve() );
31
32 // retrieving the Cascade tools
33 ATH_CHECK( m_CascadeTools.retrieve() );
34
35 ATH_CHECK( m_vertexContainerKey.initialize() );
36 ATH_CHECK( m_vertexPsiContainerKey.initialize() );
37 ATH_CHECK( m_VxPrimaryCandidateName.initialize() );
38 ATH_CHECK( m_trackContainerName.initialize() );
39 ATH_CHECK( m_refPVContainerName.initialize() );
40 ATH_CHECK( m_cascadeOutputsKeys.initialize() );
41 ATH_CHECK( m_eventInfo_key.initialize() );
42
43 auto gendata = std::make_shared<GenData>();
44 if(m_mass_jpsi < 0.) m_mass_jpsi = gendata->particleMass(MC::JPSI).value();
45 if(m_mass_jpsi2 < 0.) m_mass_jpsi2 = gendata->particleMass(MC::JPSI).value();
46 if(m_mass_psi < 0.) m_mass_psi = gendata->particleMass(MC::PSI2S).value();
47 if(m_vtx1Daug1MassHypo < 0.) m_vtx1Daug1MassHypo = gendata->particleMass(MC::MUON).value();
48 if(m_vtx1Daug2MassHypo < 0.) m_vtx1Daug2MassHypo = gendata->particleMass(MC::MUON).value();
49 if(m_vtx1Daug3MassHypo < 0.) m_vtx1Daug3MassHypo = gendata->particleMass(MC::PIPLUS).value();
50 if(m_vtx1Daug4MassHypo < 0.) m_vtx1Daug4MassHypo = gendata->particleMass(MC::PIPLUS).value();
51 if(m_vtx2Daug1MassHypo < 0.) m_vtx2Daug1MassHypo = gendata->particleMass(MC::MUON).value();
52 if(m_vtx2Daug2MassHypo < 0.) m_vtx2Daug2MassHypo = gendata->particleMass(MC::MUON).value();
53
54 return StatusCode::SUCCESS;
55 }
56
57 StatusCode JpsiPlusPsiCascade::addBranches(const EventContext& ctx) const {
58 if (m_vtx1Daug_num != 3 && m_vtx1Daug_num != 4) {
59 ATH_MSG_FATAL("Incorrect number of Psi daughters (should be 3 or 4)");
60 return StatusCode::FAILURE;
61 }
62
63 constexpr int topoN = 3;
64 if(m_cascadeOutputsKeys.size() != topoN) {
65 ATH_MSG_FATAL("Incorrect number of VtxContainers");
66 return StatusCode::FAILURE;
67 }
68 std::array<SG::WriteHandle<xAOD::VertexContainer>, topoN> VtxWriteHandles; int ikey(0);
70 VtxWriteHandles[ikey] = SG::WriteHandle<xAOD::VertexContainer>(key, ctx);
71 ATH_CHECK( VtxWriteHandles[ikey].record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
72 ikey++;
73 }
74
75 //----------------------------------------------------
76 // retrieve primary vertices
77 //----------------------------------------------------
79 ATH_CHECK( pvContainer.isValid() );
80 if (pvContainer.cptr()->size()==0) {
81 ATH_MSG_WARNING("You have no primary vertices: " << pvContainer.cptr()->size());
82 return StatusCode::RECOVERABLE;
83 }
84
85 //----------------------------------------------------
86 // Record refitted primary vertices
87 //----------------------------------------------------
89 if(m_refitPV) {
91 ATH_CHECK( refPvContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
92 }
93
94 std::vector<Trk::VxCascadeInfo*> cascadeinfoContainer;
95 std::vector<Trk::VxCascadeInfo*> cascadeinfoContainer_noConstr;
96 ATH_CHECK(performSearch(&cascadeinfoContainer,&cascadeinfoContainer_noConstr,ctx));
97
99 ATH_CHECK( evt.isValid() );
100 BPhysPVCascadeTools helper(&(*m_CascadeTools), evt.cptr());
101 helper.SetMinNTracksInPV(m_PV_minNTracks);
102
103 // Decorators for the vertices
104 SG::AuxElement::Decorator<VertexLinkVector> CascadeLinksDecor("CascadeVertexLinks");
105 SG::AuxElement::Decorator<VertexLinkVector> PsiLinksDecor("PsiVertexLinks");
106 SG::AuxElement::Decorator<VertexLinkVector> JpsiLinksDecor("JpsiVertexLinks");
107 SG::AuxElement::Decorator<float> chi2_decor("ChiSquared");
108 SG::AuxElement::Decorator<int> ndof_decor("nDoF");
109 SG::AuxElement::Decorator<float> chi2_nc_decor("ChiSquared_nc");
110 SG::AuxElement::Decorator<int> ndof_nc_decor("nDoF_nc");
111 SG::AuxElement::Decorator<float> Pt_decor("Pt");
112 SG::AuxElement::Decorator<float> PtErr_decor("PtErr");
113 SG::AuxElement::Decorator<float> chi2_SV1_decor("ChiSquared_SV1");
114 SG::AuxElement::Decorator<float> chi2_nc_SV1_decor("ChiSquared_nc_SV1");
115 SG::AuxElement::Decorator<float> chi2_V1_decor("ChiSquared_V1");
116 SG::AuxElement::Decorator<int> ndof_V1_decor("nDoF_V1");
117 SG::AuxElement::Decorator<float> lxy_SV1_decor("lxy_SV1");
118 SG::AuxElement::Decorator<float> lxyErr_SV1_decor("lxyErr_SV1");
119 SG::AuxElement::Decorator<float> a0xy_SV1_decor("a0xy_SV1");
120 SG::AuxElement::Decorator<float> a0xyErr_SV1_decor("a0xyErr_SV1");
121 SG::AuxElement::Decorator<float> a0z_SV1_decor("a0z_SV1");
122 SG::AuxElement::Decorator<float> a0zErr_SV1_decor("a0zErr_SV1");
123 SG::AuxElement::Decorator<float> chi2_SV2_decor("ChiSquared_SV2");
124 SG::AuxElement::Decorator<float> chi2_nc_SV2_decor("ChiSquared_nc_SV2");
125 SG::AuxElement::Decorator<float> chi2_V2_decor("ChiSquared_V2");
126 SG::AuxElement::Decorator<int> ndof_V2_decor("nDoF_V2");
127 SG::AuxElement::Decorator<float> lxy_SV2_decor("lxy_SV2");
128 SG::AuxElement::Decorator<float> lxyErr_SV2_decor("lxyErr_SV2");
129 SG::AuxElement::Decorator<float> a0xy_SV2_decor("a0xy_SV2");
130 SG::AuxElement::Decorator<float> a0xyErr_SV2_decor("a0xyErr_SV2");
131 SG::AuxElement::Decorator<float> a0z_SV2_decor("a0z_SV2");
132 SG::AuxElement::Decorator<float> a0zErr_SV2_decor("a0zErr_SV2");
133
134 // Get the containers and identify the input Jpsi and Psi
136 ATH_CHECK( psiContainer.isValid() );
138 ATH_CHECK( jpsiContainer.isValid() );
139
140 for(size_t ic=0; ic<cascadeinfoContainer.size(); ic++) {
141 Trk::VxCascadeInfo* cascade_info = cascadeinfoContainer[ic];
142 if(cascade_info==nullptr) {
143 ATH_MSG_ERROR("CascadeInfo is null");
144 continue;
145 }
146
147 Trk::VxCascadeInfo* cascade_info_noConstr = cascadeinfoContainer_noConstr[ic];
148
149 const std::vector<xAOD::Vertex*> &cascadeVertices = cascade_info->vertices();
150 if(cascadeVertices.size() != topoN) ATH_MSG_ERROR("Incorrect number of vertices");
151 if(cascadeVertices[0]==nullptr || cascadeVertices[1]==nullptr || cascadeVertices[2]==nullptr) ATH_MSG_ERROR("Error null vertex");
152 // Keep vertices
153 for(int i=0; i<topoN; i++) VtxWriteHandles[i].ptr()->push_back(cascadeVertices[i]);
154
155 cascade_info->setSVOwnership(false); // Prevent Container from deleting vertices
156 const auto mainVertex = cascadeVertices[2]; // this is the mother vertex
157 const std::vector< std::vector<TLorentzVector> > &moms = cascade_info->getParticleMoms();
158
159 // Set links to cascade vertices
160 std::vector<VertexLink> precedingVertexLinks;
161 VertexLink vertexLink1;
162 vertexLink1.setElement(cascadeVertices[0]);
163 vertexLink1.setStorableObject(*VtxWriteHandles[0].ptr());
164 if( vertexLink1.isValid() ) precedingVertexLinks.push_back( vertexLink1 );
165 VertexLink vertexLink2;
166 vertexLink2.setElement(cascadeVertices[1]);
167 vertexLink2.setStorableObject(*VtxWriteHandles[1].ptr());
168 if( vertexLink2.isValid() ) precedingVertexLinks.push_back( vertexLink2 );
169 CascadeLinksDecor(*mainVertex) = precedingVertexLinks;
170
171 // Identify the input Jpsi
172 const xAOD::Vertex* jpsiVertex = BPhysPVCascadeTools::FindVertex<2>(jpsiContainer.cptr(), cascadeVertices[1]);
173 // Identify the input Psi
174 const xAOD::Vertex* psiVertex(0);
175 if(m_vtx1Daug_num==4) psiVertex = BPhysPVCascadeTools::FindVertex<4>(psiContainer.cptr(), cascadeVertices[0]);
176 else psiVertex = BPhysPVCascadeTools::FindVertex<3>(psiContainer.cptr(), cascadeVertices[0]);
177
178 // Set links to input vertices
179 std::vector<const xAOD::Vertex*> jpsiVerticestoLink;
180 if(jpsiVertex) jpsiVerticestoLink.push_back(jpsiVertex);
181 else ATH_MSG_WARNING("Could not find linking Jpsi");
182 if(!BPhysPVCascadeTools::LinkVertices(JpsiLinksDecor, jpsiVerticestoLink, jpsiContainer.cptr(), mainVertex)) ATH_MSG_ERROR("Error decorating with Jpsi vertex");
183
184 std::vector<const xAOD::Vertex*> psiVerticestoLink;
185 if(psiVertex) psiVerticestoLink.push_back(psiVertex);
186 else ATH_MSG_WARNING("Could not find linking Psi");
187 if(!BPhysPVCascadeTools::LinkVertices(PsiLinksDecor, psiVerticestoLink, psiContainer.cptr(), mainVertex)) ATH_MSG_ERROR("Error decorating with Psi vertex");
188
189 xAOD::BPhysHypoHelper vtx(m_hypoName, mainVertex);
190
191 // Get refitted track momenta from all vertices, charged tracks only
192 BPhysPVCascadeTools::SetVectorInfo(vtx, cascade_info);
193 vtx.setPass(true);
194
195 //
196 // Decorate main vertex
197 //
198 // mass, mass error
199 // https://gitlab.cern.ch/atlas/athena/-/blob/21.2/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/VxCascadeInfo.h
200 BPHYS_CHECK( vtx.setMass(m_CascadeTools->invariantMass(moms[2])) );
201 BPHYS_CHECK( vtx.setMassErr(m_CascadeTools->invariantMassError(moms[2],cascade_info->getCovariance()[2])) );
202 // pt and pT error (the default pt of mainVertex is != the pt of the full cascade fit!)
203 Pt_decor(*mainVertex) = m_CascadeTools->pT(moms[2]);
204 PtErr_decor(*mainVertex) = m_CascadeTools->pTError(moms[2],cascade_info->getCovariance()[2]);
205 // chi2 and ndof (the default chi2 of mainVertex is != the chi2 of the full cascade fit!)
206 chi2_decor(*mainVertex) = cascade_info->fitChi2();
207 ndof_decor(*mainVertex) = cascade_info->nDoF();
208 chi2_nc_decor(*mainVertex) = cascade_info_noConstr ? cascade_info_noConstr->fitChi2() : -999999.;
209 ndof_nc_decor(*mainVertex) = cascade_info_noConstr ? cascade_info_noConstr->nDoF() : -1;
210
211 // decorate the Psi vertex
212 chi2_SV1_decor(*cascadeVertices[0]) = m_V0Tools->chisq(cascadeVertices[0]);
213 chi2_nc_SV1_decor(*cascadeVertices[0]) = cascade_info_noConstr ? m_V0Tools->chisq(cascade_info_noConstr->vertices()[0]) : -999999.;
214 chi2_V1_decor(*cascadeVertices[0]) = m_V0Tools->chisq(psiVertex);
215 ndof_V1_decor(*cascadeVertices[0]) = m_V0Tools->ndof(psiVertex);
216 lxy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxy(moms[0],cascadeVertices[0],mainVertex);
217 lxyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
218 a0z_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0z(moms[0],cascadeVertices[0],mainVertex);
219 a0zErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0zError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
220 a0xy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xy(moms[0],cascadeVertices[0],mainVertex);
221 a0xyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
222
223 // decorate the Jpsi vertex
224 chi2_SV2_decor(*cascadeVertices[1]) = m_V0Tools->chisq(cascadeVertices[1]);
225 chi2_nc_SV2_decor(*cascadeVertices[1]) = cascade_info_noConstr ? m_V0Tools->chisq(cascade_info_noConstr->vertices()[1]) : -999999.;
226 chi2_V2_decor(*cascadeVertices[1]) = m_V0Tools->chisq(jpsiVertex);
227 ndof_V2_decor(*cascadeVertices[1]) = m_V0Tools->ndof(jpsiVertex);
228 lxy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxy(moms[1],cascadeVertices[1],mainVertex);
229 lxyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
230 a0z_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0z(moms[1],cascadeVertices[1],mainVertex);
231 a0zErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0zError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
232 a0xy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xy(moms[1],cascadeVertices[1],mainVertex);
233 a0xyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
234
235 double Mass_Moth = m_CascadeTools->invariantMass(moms[2]); //size=2
236 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));
237 } // loop over cascadeinfoContainer
238
239 // Deleting cascadeinfo since this won't be stored.
240 // Vertices have been kept in m_cascadeOutputs and should be owned by their container
241 for (auto cascade_info : cascadeinfoContainer) delete cascade_info;
242 for (auto cascade_info_noConstr : cascadeinfoContainer_noConstr) delete cascade_info_noConstr;
243
244 return StatusCode::SUCCESS;
245 }
246
247 JpsiPlusPsiCascade::JpsiPlusPsiCascade(const std::string& type, const std::string& name, const IInterface* parent) : base_class(type,name,parent),
250 m_cascadeOutputsKeys({"JpsiPlusPsiCascadeVtx1", "JpsiPlusPsiCascadeVtx2", "JpsiPlusPsiCascadeVtx3"}),
251 m_VxPrimaryCandidateName("PrimaryVertices"),
252 m_trackContainerName("InDetTrackParticles"),
253 m_eventInfo_key("EventInfo"),
254 m_jpsiMassLower(0.0),
255 m_jpsiMassUpper(20000.0),
256 m_diTrackMassLower(-1.0),
257 m_diTrackMassUpper(-1.0),
258 m_psiMassLower(0.0),
259 m_psiMassUpper(25000.0),
260 m_jpsi2MassLower(0.0),
261 m_jpsi2MassUpper(20000.0),
262 m_MassLower(0.0),
263 m_MassUpper(31000.0),
264 m_vtx1Daug_num(4),
265 m_vtx1Daug1MassHypo(-1),
266 m_vtx1Daug2MassHypo(-1),
267 m_vtx1Daug3MassHypo(-1),
268 m_vtx1Daug4MassHypo(-1),
269 m_vtx2Daug1MassHypo(-1),
270 m_vtx2Daug2MassHypo(-1),
271 m_mass_jpsi(-1),
272 m_mass_diTrk(-1),
273 m_mass_psi(-1),
274 m_mass_jpsi2(-1),
275 m_constrPsi(false),
276 m_constrJpsi(false),
277 m_constrDiTrk(false),
278 m_constrJpsi2(false),
279 m_chi2cut_Psi(-1.0),
280 m_chi2cut_Jpsi(-1.0),
281 m_chi2cut(-1.0),
282 m_maxCandidates(0),
283 m_iVertexFitter("Trk::TrkVKalVrtFitter"),
284 m_pvRefitter("Analysis::PrimaryVertexRefitter"),
285 m_V0Tools("Trk::V0Tools"),
286 m_CascadeTools("DerivationFramework::CascadeTools")
287 {
288 declareProperty("JpsiVertices", m_vertexContainerKey);
289 declareProperty("PsiVertices", m_vertexPsiContainerKey);
290 declareProperty("JpsiVtxHypoNames", m_vertexJpsiHypoNames);
291 declareProperty("PsiVtxHypoNames", m_vertexPsiHypoNames);
292 declareProperty("VxPrimaryCandidateName", m_VxPrimaryCandidateName);
293 declareProperty("TrackContainerName", m_trackContainerName);
294 declareProperty("RefPVContainerName", m_refPVContainerName = "RefittedPrimaryVertices");
295 declareProperty("JpsiMassLowerCut", m_jpsiMassLower);
296 declareProperty("JpsiMassUpperCut", m_jpsiMassUpper);
297 declareProperty("DiTrackMassLower", m_diTrackMassLower); // only effective when m_vtx1Daug_num=4
298 declareProperty("DiTrackMassUpper", m_diTrackMassUpper); // only effective when m_vtx1Daug_num=4
299 declareProperty("PsiMassLowerCut", m_psiMassLower);
300 declareProperty("PsiMassUpperCut", m_psiMassUpper);
301 declareProperty("Jpsi2MassLowerCut", m_jpsi2MassLower);
302 declareProperty("Jpsi2MassUpperCut", m_jpsi2MassUpper);
303 declareProperty("MassLowerCut", m_MassLower);
304 declareProperty("MassUpperCut", m_MassUpper);
305 declareProperty("HypothesisName", m_hypoName = "TQ");
306 declareProperty("NumberOfPsiDaughters", m_vtx1Daug_num); // 3 or 4 only
307 declareProperty("Vtx1Daug1MassHypo", m_vtx1Daug1MassHypo);
308 declareProperty("Vtx1Daug2MassHypo", m_vtx1Daug2MassHypo);
309 declareProperty("Vtx1Daug3MassHypo", m_vtx1Daug3MassHypo);
310 declareProperty("Vtx1Daug4MassHypo", m_vtx1Daug4MassHypo);
311 declareProperty("Vtx2Daug1MassHypo", m_vtx2Daug1MassHypo);
312 declareProperty("Vtx2Daug2MassHypo", m_vtx2Daug2MassHypo);
313 declareProperty("JpsiMass", m_mass_jpsi);
314 declareProperty("DiTrackMass", m_mass_diTrk);
315 declareProperty("PsiMass", m_mass_psi);
316 declareProperty("Jpsi2Mass", m_mass_jpsi2);
317 declareProperty("ApplyJpsiMassConstraint", m_constrJpsi);
318 declareProperty("ApplyDiTrackMassConstraint", m_constrDiTrk); // only effective when m_vtx1Daug_num=4
319 declareProperty("ApplyPsiMassConstraint", m_constrPsi);
320 declareProperty("ApplyJpsi2MassConstraint", m_constrJpsi2);
321 declareProperty("Chi2CutPsi", m_chi2cut_Psi);
322 declareProperty("Chi2CutJpsi", m_chi2cut_Jpsi);
323 declareProperty("Chi2Cut", m_chi2cut);
324 declareProperty("MaxCandidates", m_maxCandidates);
325 declareProperty("RefitPV", m_refitPV = true);
326 declareProperty("MaxnPV", m_PV_max = 1000);
327 declareProperty("MinNTracksInPV", m_PV_minNTracks = 0);
328 declareProperty("DoVertexType", m_DoVertexType = 7);
329 declareProperty("TrkVertexFitterTool", m_iVertexFitter);
330 declareProperty("PVRefitter", m_pvRefitter);
331 declareProperty("V0Tools", m_V0Tools);
332 declareProperty("CascadeTools", m_CascadeTools);
333 declareProperty("CascadeVertexCollections", m_cascadeOutputsKeys);
334 }
335
336 StatusCode JpsiPlusPsiCascade::performSearch(std::vector<Trk::VxCascadeInfo*> *cascadeinfoContainer, std::vector<Trk::VxCascadeInfo*> *cascadeinfoContainer_noConstr, const EventContext& ctx) const {
337 ATH_MSG_DEBUG( "JpsiPlusPsiCascade::performSearch" );
338 assert(cascadeinfoContainer!=nullptr && cascadeinfoContainer_noConstr!=nullptr);
339
340 // Get TrackParticle container (for setting links to the original tracks)
342 ATH_CHECK( trackContainer.isValid() );
343
344 std::vector<const xAOD::TrackParticle*> tracksJpsi;
345 std::vector<const xAOD::TrackParticle*> tracksDiTrk;
346 std::vector<const xAOD::TrackParticle*> tracksPsi;
347 std::vector<const xAOD::TrackParticle*> tracksJpsi2;
348 std::vector<double> massesPsi;
349 massesPsi.push_back(m_vtx1Daug1MassHypo);
350 massesPsi.push_back(m_vtx1Daug2MassHypo);
351 massesPsi.push_back(m_vtx1Daug3MassHypo);
352 if(m_vtx1Daug_num==4) massesPsi.push_back(m_vtx1Daug4MassHypo);
353 std::array<double,2> massesJpsi2{m_vtx2Daug1MassHypo, m_vtx2Daug2MassHypo};
354
355 // Get Psi container
357 ATH_CHECK( psiContainer.isValid() );
358
359 // Get Jpsi container
361 ATH_CHECK( jpsiContainer.isValid() );
362
363 // Select the J/psi candidates before calling cascade fit
364 std::vector<const xAOD::Vertex*> selectedJpsiCandidates;
365 for(auto vxcItr=jpsiContainer.cptr()->cbegin(); vxcItr!=jpsiContainer.cptr()->cend(); ++vxcItr) {
366 // Check the passed flag first
367 const xAOD::Vertex* vtx = *vxcItr;
368 bool passed = false;
369 for(size_t i=0; i<m_vertexJpsiHypoNames.size(); i++) {
370 SG::AuxElement::Accessor<Char_t> flagAcc("passed_"+m_vertexJpsiHypoNames[i]);
371 if(flagAcc.isAvailable(*vtx) && flagAcc(*vtx)) {
372 passed |= 1;
373 }
374 }
375 if(m_vertexJpsiHypoNames.size() && !passed) continue;
376
377 // Check Jpsi candidate invariant mass and skip if need be
378 double mass_jpsi2 = m_V0Tools->invariantMass(*vxcItr, massesJpsi2);
379 if (mass_jpsi2 < m_jpsi2MassLower || mass_jpsi2 > m_jpsi2MassUpper) continue;
380
381 double chi2DOF = (*vxcItr)->chiSquared()/(*vxcItr)->numberDoF();
382 if(m_chi2cut_Jpsi>0 && chi2DOF>m_chi2cut_Jpsi) continue;
383
384 selectedJpsiCandidates.push_back(*vxcItr);
385 }
386 if(selectedJpsiCandidates.size()==0) return StatusCode::SUCCESS;
387
388 // Select the Psi candidates before calling cascade fit
389 std::vector<const xAOD::Vertex*> selectedPsiCandidates;
390 for(auto vxcItr=psiContainer.cptr()->cbegin(); vxcItr!=psiContainer.cptr()->cend(); ++vxcItr) {
391 // Check the passed flag first
392 const xAOD::Vertex* vtx = *vxcItr;
393 bool passed = false;
394 for(size_t i=0; i<m_vertexPsiHypoNames.size(); i++) {
395 SG::AuxElement::Accessor<Char_t> flagAcc("passed_"+m_vertexPsiHypoNames[i]);
396 if(flagAcc.isAvailable(*vtx) && flagAcc(*vtx)) {
397 passed |= 1;
398 }
399 }
400 if(m_vertexPsiHypoNames.size() && !passed) continue;
401
402 // Check Psi candidate invariant mass and skip if need be
403 double mass_psi = m_V0Tools->invariantMass(*vxcItr,massesPsi);
404 if(mass_psi < m_psiMassLower || mass_psi > m_psiMassUpper) continue;
405
406 // Add loose cut on Jpsi mass from Psi -> Jpsi pi+ pi-, or on phi mass from Ds+ -> phi pi+
407 TLorentzVector p4_mu1, p4_mu2;
408 p4_mu1.SetPtEtaPhiM( (*vxcItr)->trackParticle(0)->pt(),
409 (*vxcItr)->trackParticle(0)->eta(),
410 (*vxcItr)->trackParticle(0)->phi(), m_vtx1Daug1MassHypo);
411 p4_mu2.SetPtEtaPhiM( (*vxcItr)->trackParticle(1)->pt(),
412 (*vxcItr)->trackParticle(1)->eta(),
413 (*vxcItr)->trackParticle(1)->phi(), m_vtx1Daug2MassHypo);
414 double mass_jpsi = (p4_mu1 + p4_mu2).M();
415 if (mass_jpsi < m_jpsiMassLower || mass_jpsi > m_jpsiMassUpper) continue;
416
418 TLorentzVector p4_trk1, p4_trk2;
419 p4_trk1.SetPtEtaPhiM( (*vxcItr)->trackParticle(2)->pt(),
420 (*vxcItr)->trackParticle(2)->eta(),
421 (*vxcItr)->trackParticle(2)->phi(), m_vtx1Daug3MassHypo);
422 p4_trk2.SetPtEtaPhiM( (*vxcItr)->trackParticle(3)->pt(),
423 (*vxcItr)->trackParticle(3)->eta(),
424 (*vxcItr)->trackParticle(3)->phi(), m_vtx1Daug4MassHypo);
425 double mass_diTrk = (p4_trk1 + p4_trk2).M();
426 if (mass_diTrk < m_diTrackMassLower || mass_diTrk > m_diTrackMassUpper) continue;
427 }
428
429 double chi2DOF = (*vxcItr)->chiSquared()/(*vxcItr)->numberDoF();
430 if(m_chi2cut_Psi>0 && chi2DOF>m_chi2cut_Psi) continue;
431
432 selectedPsiCandidates.push_back(*vxcItr);
433 }
434 if(selectedPsiCandidates.size()==0) return StatusCode::SUCCESS;
435
436 std::vector<std::pair<const xAOD::Vertex*, const xAOD::Vertex*> > candidatePairs;
437 for(auto jpsiItr=selectedJpsiCandidates.cbegin(); jpsiItr!=selectedJpsiCandidates.cend(); ++jpsiItr) {
438 tracksJpsi2.clear();
439 for(size_t i=0; i<(*jpsiItr)->nTrackParticles(); i++) tracksJpsi2.push_back((*jpsiItr)->trackParticle(i));
440 for(auto psiItr=selectedPsiCandidates.cbegin(); psiItr!=selectedPsiCandidates.cend(); ++psiItr) {
441 bool skip = false;
442 for(size_t j=0; j<(*psiItr)->nTrackParticles(); j++) {
443 if(std::find(tracksJpsi2.cbegin(), tracksJpsi2.cend(), (*psiItr)->trackParticle(j)) != tracksJpsi2.cend()) { skip = true; break; }
444 }
445 if(skip) continue;
446 candidatePairs.push_back(std::pair<const xAOD::Vertex*, const xAOD::Vertex*>(*jpsiItr,*psiItr));
447 }
448 }
449
450 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(); } );
451 if(m_maxCandidates>0 && candidatePairs.size()>m_maxCandidates) {
452 candidatePairs.erase(candidatePairs.begin()+m_maxCandidates, candidatePairs.end());
453 }
454
455 for(size_t ic=0; ic<candidatePairs.size(); ic++) {
456 const xAOD::Vertex* jpsiVertex = candidatePairs[ic].first;
457 const xAOD::Vertex* psiVertex = candidatePairs[ic].second;
458
459 tracksJpsi2.clear();
460 for(size_t it=0; it<jpsiVertex->nTrackParticles(); it++) tracksJpsi2.push_back(jpsiVertex->trackParticle(it));
461 if (tracksJpsi2.size() != 2 || massesJpsi2.size() != 2) {
462 ATH_MSG_ERROR("Problems with Jpsi input: number of tracks or track mass inputs is not 2!");
463 }
464 tracksPsi.clear();
465 for(size_t it=0; it<psiVertex->nTrackParticles(); it++) tracksPsi.push_back(psiVertex->trackParticle(it));
466 if (tracksPsi.size() != massesPsi.size()) {
467 ATH_MSG_ERROR("Problems with Psi input: number of tracks or track mass inputs is not correct!");
468 }
469
470 tracksJpsi.clear();
471 tracksJpsi.push_back(psiVertex->trackParticle(0));
472 tracksJpsi.push_back(psiVertex->trackParticle(1));
473 tracksDiTrk.clear();
474 if(m_vtx1Daug_num==4) {
475 tracksDiTrk.push_back(psiVertex->trackParticle(2));
476 tracksDiTrk.push_back(psiVertex->trackParticle(3));
477 }
478
479 TLorentzVector p4_moth;
480 TLorentzVector tmp;
481 for(size_t it=0; it<jpsiVertex->nTrackParticles(); it++) {
482 tmp.SetPtEtaPhiM(jpsiVertex->trackParticle(it)->pt(),jpsiVertex->trackParticle(it)->eta(),jpsiVertex->trackParticle(it)->phi(),massesJpsi2[it]);
483 p4_moth += tmp;
484 }
485 for(size_t it=0; it<psiVertex->nTrackParticles(); it++) {
486 tmp.SetPtEtaPhiM(psiVertex->trackParticle(it)->pt(),psiVertex->trackParticle(it)->eta(),psiVertex->trackParticle(it)->phi(),massesPsi[it]);
487 p4_moth += tmp;
488 }
489 if (p4_moth.M() < m_MassLower || p4_moth.M() > m_MassUpper) continue;
490
491 // Apply the user's settings to the fitter
492 std::unique_ptr<Trk::IVKalState> state = m_iVertexFitter->makeState(ctx);
493 // Robustness: http://cdsweb.cern.ch/record/685551
494 int robustness = 0;
495 m_iVertexFitter->setRobustness(robustness, *state);
496 // Build up the topology
497 // Vertex list
498 std::vector<Trk::VertexID> vrtList;
499 // Psi vertex
500 Trk::VertexID vID1;
501 // https://gitlab.cern.ch/atlas/athena/-/blob/21.2/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/IVertexCascadeFitter.h
502 if (m_constrPsi) {
503 vID1 = m_iVertexFitter->startVertex(tracksPsi,massesPsi,*state,m_mass_psi);
504 } else {
505 vID1 = m_iVertexFitter->startVertex(tracksPsi,massesPsi,*state);
506 }
507 vrtList.push_back(vID1);
508 // Jpsi vertex
509 Trk::VertexID vID2;
510 if (m_constrJpsi2) {
511 vID2 = m_iVertexFitter->nextVertex(tracksJpsi2,massesJpsi2,*state,m_mass_jpsi2);
512 } else {
513 vID2 = m_iVertexFitter->nextVertex(tracksJpsi2,massesJpsi2,*state);
514 }
515 vrtList.push_back(vID2);
516 // Mother vertex including Jpsi and Psi
517 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
518 std::vector<double> tp_masses; tp_masses.clear();
519 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList,*state);
520 if (m_constrJpsi) {
521 std::vector<Trk::VertexID> cnstV; cnstV.clear();
522 if ( !m_iVertexFitter->addMassConstraint(vID1,tracksJpsi,cnstV,*state,m_mass_jpsi).isSuccess() ) {
523 ATH_MSG_WARNING("addMassConstraint for Jpsi failed");
524 }
525 }
527 std::vector<Trk::VertexID> cnstV; cnstV.clear();
528 if ( !m_iVertexFitter->addMassConstraint(vID1,tracksDiTrk,cnstV,*state,m_mass_diTrk).isSuccess() ) {
529 ATH_MSG_WARNING("addMassConstraint for DiTrk failed");
530 }
531 }
532 // Do the work
533 std::unique_ptr<Trk::VxCascadeInfo> result(m_iVertexFitter->fitCascade(*state));
534
535 bool pass = false;
536 if (result != nullptr) {
537 for(auto v : result->vertices()) {
538 if(v->nTrackParticles()==0) {
539 std::vector<ElementLink<xAOD::TrackParticleContainer> > nullLinkVector;
540 v->setTrackParticleLinks(nullLinkVector);
541 }
542 }
543 // reset links to original tracks
544 BPhysPVCascadeTools::PrepareVertexLinks(result.get(), trackContainer.cptr());
545
546 // necessary to prevent memory leak
547 result->setSVOwnership(true);
548
549 // Chi2/DOF cut
550 double chi2DOF = result->fitChi2()/result->nDoF();
551 bool chi2CutPassed = (m_chi2cut <= 0.0 || chi2DOF < m_chi2cut);
552
553 if(chi2CutPassed) {
554 cascadeinfoContainer->push_back(result.release());
555 pass = true;
556 }
557 }
558
559 // do cascade fit again without any mass constraints
560 if(pass) {
562 std::unique_ptr<Trk::IVKalState> state (m_iVertexFitter->makeState(ctx));
563 m_iVertexFitter->setRobustness(robustness, *state);
564 std::vector<Trk::VertexID> vrtList_nc;
565 // Psi vertex
566 Trk::VertexID vID1_nc = m_iVertexFitter->startVertex(tracksPsi,massesPsi,*state);
567 vrtList_nc.push_back(vID1_nc);
568 Trk::VertexID vID2_nc = m_iVertexFitter->nextVertex(tracksJpsi2,massesJpsi2,*state);
569 vrtList_nc.push_back(vID2_nc);
570 // Mother vertex including Jpsi and Psi
571 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
572 std::vector<double> tp_masses; tp_masses.clear();
573 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList_nc,*state);
574 // Do the work
575 std::unique_ptr<Trk::VxCascadeInfo> result_nc(m_iVertexFitter->fitCascade(*state));
576
577 if (result_nc != nullptr) {
578 for(auto v : result_nc->vertices()) {
579 if(v->nTrackParticles()==0) {
580 std::vector<ElementLink<xAOD::TrackParticleContainer> > nullLinkVector;
581 v->setTrackParticleLinks(nullLinkVector);
582 }
583 }
584 // reset links to original tracks
585 BPhysPVCascadeTools::PrepareVertexLinks(result_nc.get(), trackContainer.cptr());
586
587 // necessary to prevent memory leak
588 result_nc->setSVOwnership(true);
589 cascadeinfoContainer_noConstr->push_back(result_nc.release());
590 }
591 else cascadeinfoContainer_noConstr->push_back(0);
592 }
593 else cascadeinfoContainer_noConstr->push_back(0);
594 }
595 } //Iterate over candidatePairs
596
597 return StatusCode::SUCCESS;
598 }
599}
#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 const xAOD::Vertex * FindVertex(const xAOD::VertexContainer *c, const xAOD::Vertex *v)
static void SetVectorInfo(xAOD::BPhysHelper &, const Trk::VxCascadeInfo *)
SG::WriteHandleKeyArray< xAOD::VertexContainer > m_cascadeOutputsKeys
SG::WriteHandleKey< xAOD::VertexContainer > m_refPVContainerName
virtual StatusCode initialize() override
PublicToolHandle< DerivationFramework::CascadeTools > m_CascadeTools
StatusCode performSearch(std::vector< Trk::VxCascadeInfo * > *cascadeinfoContainer, std::vector< Trk::VxCascadeInfo * > *cascadeinfoContainer_noConstr, const EventContext &ctx) const
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexPsiContainerKey
std::vector< std::string > m_vertexJpsiHypoNames
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_trackContainerName
PublicToolHandle< Analysis::PrimaryVertexRefitter > m_pvRefitter
SG::ReadHandleKey< xAOD::VertexContainer > m_VxPrimaryCandidateName
Name of primary vertex container.
PublicToolHandle< Trk::V0Tools > m_V0Tools
JpsiPlusPsiCascade(const std::string &t, const std::string &n, const IInterface *p)
virtual StatusCode addBranches(const EventContext &ctx) const override
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexContainerKey
ToolHandle< Trk::TrkVKalVrtFitter > m_iVertexFitter
std::vector< std::string > m_vertexPsiHypoNames
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo_key
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.