ATLAS Offline Software
Loading...
Searching...
No Matches
JpsiXPlus2V0.cxx
Go to the documentation of this file.
1/*
2 Copyright (C) 2002-2025 CERN for the benefit of the ATLAS collaboration
3 Contact: Xin Chen <xin.chen@cern.ch>
4*/
5#include "JpsiXPlus2V0.h"
12#include "BPhysPVCascadeTools.h"
16#include "HepPDT/ParticleDataTable.hh"
17#include "VxVertex/RecVertex.h"
20#include <algorithm>
21#include <functional>
22
23namespace DerivationFramework {
24 typedef ElementLink<xAOD::VertexContainer> VertexLink;
25 typedef std::vector<VertexLink> VertexLinkVector;
26
27 using Analysis::JpsiUpsilonCommon;
28
29 JpsiXPlus2V0::JpsiXPlus2V0(const std::string& type, const std::string& name, const IInterface* parent) : base_class(type,name,parent),
30 m_vertexJXContainerKey("InputJXVertices"),
32 m_cascadeOutputKeys({"JpsiXPlus2V0_SubVtx1", "JpsiXPlus2V0_SubVtx2", "JpsiXPlus2V0_SubVtx3", "JpsiXPlus2V0_MainVtx"}),
33 m_v0VtxOutputKey(""),
34 m_TrkParticleCollection("InDetTrackParticles"),
35 m_VxPrimaryCandidateName("PrimaryVertices"),
36 m_pvContainerName("PrimaryVertices"),
37 m_refPVContainerName("RefittedPrimaryVertices"),
38 m_eventInfo_key("EventInfo"),
39 m_RelinkContainers({"InDetTrackParticles","InDetLargeD0TrackParticles"}),
40 m_useImprovedMass(false),
41 m_jxMassLower(0.0),
42 m_jxMassUpper(30000.0),
43 m_jpsiMassLower(0.0),
44 m_jpsiMassUpper(20000.0),
45 m_diTrackMassLower(-1.0),
46 m_diTrackMassUpper(-1.0),
47 m_V01Hypothesis("Ks"),
48 m_V02Hypothesis("Lambda"),
49 m_LambdaMassLower(0.0),
50 m_LambdaMassUpper(10000.0),
51 m_KsMassLower(0.0),
52 m_KsMassUpper(10000.0),
53 m_lxyV01_cut(-999.0),
54 m_lxyV02_cut(-999.0),
55 m_minMass_gamma(-1.0),
56 m_chi2cut_gamma(-1.0),
57 m_JXV02MassLower(0.0),
58 m_JXV02MassUpper(30000.0),
59 m_MassLower(0.0),
60 m_MassUpper(31000.0),
61 m_jxDaug_num(4),
62 m_jxDaug1MassHypo(-1),
63 m_jxDaug2MassHypo(-1),
64 m_jxDaug3MassHypo(-1),
65 m_jxDaug4MassHypo(-1),
66 m_massJX(-1),
67 m_massJpsi(-1),
68 m_massX(-1),
69 m_massLd(-1),
70 m_massKs(-1),
71 m_massJXV02(-1),
72 m_massMainV(-1),
73 m_constrJX(false),
74 m_constrJpsi(false),
75 m_constrX(false),
76 m_constrV01(false),
77 m_constrV02(false),
78 m_constrJXV02(false),
79 m_constrMainV(false),
80 m_cascadeFitWithPV(0),
81 m_firstDecayAtPV(false),
82 m_JXSubVtx(false),
83 m_JXV02SubVtx(false),
84 m_chi2cut_JX(-1.0),
85 m_chi2cut_V0(-1.0),
86 m_chi2cut(-1.0),
87 m_useTRT(false),
88 m_ptTRT(450),
89 m_d0_cut(2),
90 m_maxJXCandidates(0),
91 m_maxV0Candidates(0),
92 m_maxMainVCandidates(0),
93 m_iVertexFitter("Trk::TrkVKalVrtFitter"),
94 m_iV0Fitter("Trk::V0VertexFitter"),
95 m_iGammaFitter("Trk::TrkVKalVrtFitter"),
96 m_pvRefitter("Analysis::PrimaryVertexRefitter", this),
97 m_V0Tools("Trk::V0Tools"),
98 m_trackToVertexTool("Reco::TrackToVertex"),
99 m_v0TrkSelector("InDet::TrackSelectorTool"),
100 m_CascadeTools("DerivationFramework::CascadeTools"),
101 m_vertexEstimator("InDet::VertexPointEstimator"),
102 m_extrapolator("Trk::Extrapolator/AtlasExtrapolator")
103 {
104 declareProperty("JXVertices", m_vertexJXContainerKey);
105 declareProperty("V0Vertices", m_vertexV0ContainerKey);
106 declareProperty("JXVtxHypoNames", m_vertexJXHypoNames);
107 declareProperty("CascadeVertexCollections", m_cascadeOutputKeys); // size is 3 or 4 only
108 declareProperty("OutoutV0VtxCollection", m_v0VtxOutputKey);
109 declareProperty("TrackParticleCollection", m_TrkParticleCollection);
110 declareProperty("VxPrimaryCandidateName", m_VxPrimaryCandidateName);
111 declareProperty("PVContainerName", m_pvContainerName);
112 declareProperty("RefPVContainerName", m_refPVContainerName);
113 declareProperty("EventInfoKey", m_eventInfo_key);
114 declareProperty("RelinkTracks", m_RelinkContainers);
115 declareProperty("UseImprovedMass", m_useImprovedMass);
116 declareProperty("JXMassLowerCut", m_jxMassLower); // only effective when m_jxDaug_num>2
117 declareProperty("JXMassUpperCut", m_jxMassUpper); // only effective when m_jxDaug_num>2
118 declareProperty("JpsiMassLowerCut", m_jpsiMassLower);
119 declareProperty("JpsiMassUpperCut", m_jpsiMassUpper);
120 declareProperty("DiTrackMassLower", m_diTrackMassLower); // only effective when m_jxDaug_num=4
121 declareProperty("DiTrackMassUpper", m_diTrackMassUpper); // only effective when m_jxDaug_num=4
122 declareProperty("V01Hypothesis", m_V01Hypothesis); // "Ks", "Lambda" or "Lambda/Ks"
123 declareProperty("V02Hypothesis", m_V02Hypothesis); // "Ks", "Lambda" or "Lambda/Ks"
124 declareProperty("LxyV01Cut", m_lxyV01_cut);
125 declareProperty("LxyV02Cut", m_lxyV02_cut);
126 declareProperty("LambdaMassLowerCut", m_LambdaMassLower);
127 declareProperty("LambdaMassUpperCut", m_LambdaMassUpper);
128 declareProperty("KsMassLowerCut", m_KsMassLower);
129 declareProperty("KsMassUpperCut", m_KsMassUpper);
130 declareProperty("MassCutGamma", m_minMass_gamma);
131 declareProperty("Chi2CutGamma", m_chi2cut_gamma);
132 declareProperty("JXV02MassLowerCut", m_JXV02MassLower); // only effective when m_JXSubVtx=true & m_JXV02SubVtx=true
133 declareProperty("JXV02MassUpperCut", m_JXV02MassUpper); // only effective when m_JXSubVtx=true & m_JXV02SubVtx=true
134 declareProperty("MassLowerCut", m_MassLower);
135 declareProperty("MassUpperCut", m_MassUpper);
136 declareProperty("HypothesisName", m_hypoName = "TQ");
137 declareProperty("NumberOfJXDaughters", m_jxDaug_num); // 2, or 3, or 4 only
138 declareProperty("JXDaug1MassHypo", m_jxDaug1MassHypo);
139 declareProperty("JXDaug2MassHypo", m_jxDaug2MassHypo);
140 declareProperty("JXDaug3MassHypo", m_jxDaug3MassHypo);
141 declareProperty("JXDaug4MassHypo", m_jxDaug4MassHypo);
142 declareProperty("JXMass", m_massJX); // only effective when m_jxDaug_num>2
143 declareProperty("JpsiMass", m_massJpsi);
144 declareProperty("XMass", m_massX); // only effective when m_jxDaug_num=4
145 declareProperty("LambdaMass", m_massLd);
146 declareProperty("KsMass", m_massKs);
147 declareProperty("JXV02VtxMass", m_massJXV02); // mass of JX + 2nd V0
148 declareProperty("MainVtxMass", m_massMainV);
149 declareProperty("ApplyJXMassConstraint", m_constrJX); // only effective when m_jxDaug_num>2
150 declareProperty("ApplyJpsiMassConstraint", m_constrJpsi);
151 declareProperty("ApplyXMassConstraint", m_constrX); // only effective when m_jxDaug_num=4
152 declareProperty("ApplyV01MassConstraint", m_constrV01); // first V0
153 declareProperty("ApplyV02MassConstraint", m_constrV02); // second V0
154 declareProperty("ApplyJXV02MassConstraint", m_constrJXV02); // constrain JX + 2nd V0
155 declareProperty("ApplyMainVMassConstraint", m_constrMainV);
156 declareProperty("DoCascadeFitWithPV", m_cascadeFitWithPV);
157 declareProperty("FirstDecayAtPV", m_firstDecayAtPV);
158 declareProperty("HasJXSubVertex", m_JXSubVtx);
159 declareProperty("HasJXV02SubVertex", m_JXV02SubVtx); // only effective when m_JXSubVtx=true
160 declareProperty("Chi2CutJX", m_chi2cut_JX);
161 declareProperty("Chi2CutV0", m_chi2cut_V0);
162 declareProperty("Chi2Cut", m_chi2cut);
163 declareProperty("UseTRT", m_useTRT);
164 declareProperty("PtTRT", m_ptTRT);
165 declareProperty("Trackd0Cut", m_d0_cut);
166 declareProperty("MaxJXCandidates", m_maxJXCandidates);
167 declareProperty("MaxV0Candidates", m_maxV0Candidates);
168 declareProperty("MaxMainVCandidates", m_maxMainVCandidates);
169 declareProperty("RefitPV", m_refitPV = true);
170 declareProperty("MaxnPV", m_PV_max = 1000);
171 declareProperty("MinNTracksInPV", m_PV_minNTracks = 0);
172 declareProperty("DoVertexType", m_DoVertexType = 7);
173 declareProperty("TrkVertexFitterTool", m_iVertexFitter);
174 declareProperty("V0VertexFitterTool", m_iV0Fitter);
175 declareProperty("GammaFitterTool", m_iGammaFitter);
176 declareProperty("PVRefitter", m_pvRefitter);
177 declareProperty("V0Tools", m_V0Tools);
178 declareProperty("TrackToVertexTool", m_trackToVertexTool);
179 declareProperty("V0TrackSelectorTool", m_v0TrkSelector);
180 declareProperty("CascadeTools", m_CascadeTools);
181 declareProperty("VertexPointEstimator", m_vertexEstimator);
182 declareProperty("Extrapolator", m_extrapolator);
183 }
184
186 if((m_V01Hypothesis != "Ks" && m_V01Hypothesis != "Lambda" && m_V01Hypothesis != "Lambda/Ks" && m_V01Hypothesis != "Ks/Lambda") ||
187 (m_V02Hypothesis != "Ks" && m_V02Hypothesis != "Lambda" && m_V02Hypothesis != "Lambda/Ks" && m_V02Hypothesis != "Ks/Lambda")) {
188 ATH_MSG_FATAL("Incorrect V0 container hypothesis - not recognized");
189 return StatusCode::FAILURE;
190 }
191
193 ATH_MSG_FATAL("Incorrect number of JX daughters");
194 return StatusCode::FAILURE;
195 }
196
197 if(m_vertexV0ContainerKey.key()=="" && m_v0VtxOutputKey.key()=="") {
198 ATH_MSG_FATAL("Input and output V0 container names can not be both empty");
199 return StatusCode::FAILURE;
200 }
201
202 // retrieving vertex Fitter
203 ATH_CHECK( m_iVertexFitter.retrieve() );
204
205 // retrieving V0 vertex Fitter
206 ATH_CHECK( m_iV0Fitter.retrieve() );
207
208 // retrieving photon conversion vertex Fitter
209 ATH_CHECK( m_iGammaFitter.retrieve() );
210
211 // retrieving primary vertex refitter
212 ATH_CHECK( m_pvRefitter.retrieve() );
213
214 // retrieving the V0 tool
215 ATH_CHECK( m_V0Tools.retrieve() );
216
217 // retrieving the TrackToVertex extrapolator tool
218 ATH_CHECK( m_trackToVertexTool.retrieve() );
219
220 // retrieving the V0 track selector tool
221 ATH_CHECK( m_v0TrkSelector.retrieve() );
222
223 // retrieving the Cascade tools
224 ATH_CHECK( m_CascadeTools.retrieve() );
225
226 // retrieving the vertex point estimator
227 ATH_CHECK( m_vertexEstimator.retrieve() );
228
229 // retrieving the extrapolator
230 ATH_CHECK( m_extrapolator.retrieve() );
231
232 ATH_CHECK( m_vertexJXContainerKey.initialize() );
234 ATH_CHECK( m_VxPrimaryCandidateName.initialize() );
235 ATH_CHECK( m_TrkParticleCollection.initialize() );
236 ATH_CHECK( m_pvContainerName.initialize() );
237 ATH_CHECK( m_refPVContainerName.initialize() );
238 ATH_CHECK( m_cascadeOutputKeys.initialize() );
239 ATH_CHECK( m_eventInfo_key.initialize() );
240 ATH_CHECK( m_RelinkContainers.initialize() );
242
243 ATH_CHECK( m_partPropSvc.retrieve() );
244 auto pdt = m_partPropSvc->PDT();
245
246 // https://gitlab.cern.ch/atlas/athena/-/blob/main/Generators/TruthUtils/TruthUtils/AtlasPID.h
257
258 m_massesV0_ppi.push_back(m_mass_proton);
259 m_massesV0_ppi.push_back(m_mass_pion);
260 m_massesV0_pip.push_back(m_mass_pion);
261 m_massesV0_pip.push_back(m_mass_proton);
262 m_massesV0_pipi.push_back(m_mass_pion);
263 m_massesV0_pipi.push_back(m_mass_pion);
264
265 // retrieve particle masses
269 if(m_constrV01 || m_constrV02) {
272 }
275
280
281 return StatusCode::SUCCESS;
282 }
283
284 StatusCode JpsiXPlus2V0::performSearch(std::vector<Trk::VxCascadeInfo*>& cascadeinfoContainer, const std::vector<std::pair<const xAOD::Vertex*,V0Enum> >& selectedV0Candidates, const EventContext& ctx) const {
285 ATH_MSG_DEBUG( "JpsiXPlus2V0::performSearch" );
286 if(selectedV0Candidates.size()==0) return StatusCode::SUCCESS;
287
288 // Get all track containers when m_RelinkContainers is not empty
289 std::vector<const xAOD::TrackParticleContainer*> trackCols;
292 ATH_CHECK( handle.isValid() );
293 trackCols.push_back(handle.cptr());
294 }
295
296 // Get default PV container
298 ATH_CHECK( defaultPVContainer.isValid() );
299
300 // Get PV container
302 ATH_CHECK( pvContainer.isValid() );
303
304 // Get Jpsi+X container
306 ATH_CHECK( jxContainer.isValid() );
307
308 std::vector<double> massesJX{m_jxDaug1MassHypo, m_jxDaug2MassHypo};
309 if(m_jxDaug_num>=3) massesJX.push_back(m_jxDaug3MassHypo);
310 if(m_jxDaug_num==4) massesJX.push_back(m_jxDaug4MassHypo);
311
312 // Select the JX candidates before calling cascade fit
313 std::vector<const xAOD::Vertex*> selectedJXCandidates;
314 for(auto vxcItr=jxContainer.ptr()->begin(); vxcItr!=jxContainer.ptr()->end(); ++vxcItr) {
315 // Check the passed flag first
316 const xAOD::Vertex* vtx = *vxcItr;
317 bool passed = false;
318 for(const std::string& name : m_vertexJXHypoNames) {
319 SG::AuxElement::Accessor<Char_t> flagAcc("passed_"+name);
320 if(flagAcc.isAvailable(*vtx) && flagAcc(*vtx)) {
321 passed = true;
322 }
323 }
324 if(m_vertexJXHypoNames.size() && !passed) continue;
325
326 // Add loose cut on Jpsi mass from e.g. JX -> Jpsi pi+ pi-
327 TLorentzVector p4_mu1, p4_mu2;
328 p4_mu1.SetPtEtaPhiM(vtx->trackParticle(0)->pt(),vtx->trackParticle(0)->eta(),vtx->trackParticle(0)->phi(), m_jxDaug1MassHypo);
329 p4_mu2.SetPtEtaPhiM(vtx->trackParticle(1)->pt(),vtx->trackParticle(1)->eta(),vtx->trackParticle(1)->phi(), m_jxDaug2MassHypo);
330 double mass_jpsi = (p4_mu1 + p4_mu2).M();
331 if (mass_jpsi < m_jpsiMassLower || mass_jpsi > m_jpsiMassUpper) continue;
332
333 TLorentzVector p4_trk1, p4_trk2;
334 if(m_jxDaug_num>=3) p4_trk1.SetPtEtaPhiM(vtx->trackParticle(2)->pt(),vtx->trackParticle(2)->eta(),vtx->trackParticle(2)->phi(), m_jxDaug3MassHypo);
335 if(m_jxDaug_num==4) p4_trk2.SetPtEtaPhiM(vtx->trackParticle(3)->pt(),vtx->trackParticle(3)->eta(),vtx->trackParticle(3)->phi(), m_jxDaug4MassHypo);
336
337 if(m_jxDaug_num==3) {
338 double mass_jx = (p4_mu1 + p4_mu2 + p4_trk1).M();
339 if(m_useImprovedMass && m_massJpsi>0) mass_jx += - (p4_mu1 + p4_mu2).M() + m_massJpsi;
340 if(mass_jx < m_jxMassLower || mass_jx > m_jxMassUpper) continue;
341 }
342 else if(m_jxDaug_num==4) {
343 double mass_jx = (p4_mu1 + p4_mu2 + p4_trk1 + p4_trk2).M();
344 if(m_useImprovedMass && m_massJpsi>0) mass_jx += - (p4_mu1 + p4_mu2).M() + m_massJpsi;
345 if(mass_jx < m_jxMassLower || mass_jx > m_jxMassUpper) continue;
346
348 double mass_diTrk = (p4_trk1 + p4_trk2).M();
349 if(mass_diTrk < m_diTrackMassLower || mass_diTrk > m_diTrackMassUpper) continue;
350 }
351 }
352
353 double chi2DOF = vtx->chiSquared()/vtx->numberDoF();
354 if(m_chi2cut_JX>0 && chi2DOF>m_chi2cut_JX) continue;
355
356 selectedJXCandidates.push_back(vtx);
357 }
358 if(selectedJXCandidates.size()==0) return StatusCode::SUCCESS;
359
360 std::sort( selectedJXCandidates.begin(), selectedJXCandidates.end(), [](const xAOD::Vertex* a, const xAOD::Vertex* b) { return a->chiSquared()/a->numberDoF() < b->chiSquared()/b->numberDoF(); } );
361 if(m_maxJXCandidates>0 && selectedJXCandidates.size()>m_maxJXCandidates) {
362 selectedJXCandidates.erase(selectedJXCandidates.begin()+m_maxJXCandidates, selectedJXCandidates.end());
363 }
364
365 // Select JX+V0+V0 candidates
366 std::vector<const xAOD::TrackParticle*> tracksJX; tracksJX.reserve(m_jxDaug_num);
367 std::vector<const xAOD::TrackParticle*> tracksV01; tracksV01.reserve(2);
368 for(auto jxItr=selectedJXCandidates.cbegin(); jxItr!=selectedJXCandidates.cend(); ++jxItr) {
369 tracksJX.clear();
370 for(size_t i=0; i<(*jxItr)->nTrackParticles(); i++) tracksJX.push_back((*jxItr)->trackParticle(i));
371 for(auto V0Itr1=selectedV0Candidates.cbegin(); V0Itr1!=selectedV0Candidates.cend(); ++V0Itr1) {
372 if(std::find(tracksJX.cbegin(), tracksJX.cend(), V0Itr1->first->trackParticle(0)) != tracksJX.cend()) continue;
373 if(std::find(tracksJX.cbegin(), tracksJX.cend(), V0Itr1->first->trackParticle(1)) != tracksJX.cend()) continue;
374 tracksV01.clear();
375 for(size_t j=0; j<V0Itr1->first->nTrackParticles(); j++) tracksV01.push_back(V0Itr1->first->trackParticle(j));
376 for(auto V0Itr2=V0Itr1+1; V0Itr2!=selectedV0Candidates.cend(); ++V0Itr2) {
377 if(std::find(tracksJX.cbegin(), tracksJX.cend(), V0Itr2->first->trackParticle(0)) != tracksJX.cend()) continue;
378 if(std::find(tracksJX.cbegin(), tracksJX.cend(), V0Itr2->first->trackParticle(1)) != tracksJX.cend()) continue;
379 if(std::find(tracksV01.cbegin(), tracksV01.cend(), V0Itr2->first->trackParticle(0)) != tracksV01.cend()) continue;
380 if(std::find(tracksV01.cbegin(), tracksV01.cend(), V0Itr2->first->trackParticle(1)) != tracksV01.cend()) continue;
381
382 int numberOfVertices = 0;
383 if((m_V01Hypothesis=="Lambda/Ks" || m_V01Hypothesis=="Ks/Lambda") && (m_V02Hypothesis=="Lambda/Ks" || m_V02Hypothesis=="Ks/Lambda")) {
384 numberOfVertices = m_JXSubVtx && m_JXV02SubVtx ? 2 : 1;
385 }
386 else if((m_V01Hypothesis == "Ks" || m_V01Hypothesis == "Lambda") && (m_V02Hypothesis=="Lambda/Ks" || m_V02Hypothesis=="Ks/Lambda")) {
387 if((m_V01Hypothesis == "Ks" && V0Itr1->second==KS) ||
388 (m_V01Hypothesis == "Lambda" && (V0Itr1->second==LAMBDA || V0Itr1->second==LAMBDABAR))) numberOfVertices = 1;
389 if((m_V01Hypothesis == "Ks" && V0Itr2->second==KS) ||
390 (m_V01Hypothesis == "Lambda" && (V0Itr2->second==LAMBDA || V0Itr2->second==LAMBDABAR))) {
391 if(numberOfVertices == 1) numberOfVertices = m_JXSubVtx && m_JXV02SubVtx ? 2 : 1;
392 else numberOfVertices = -1;
393 }
394 }
395 else if((m_V02Hypothesis == "Ks" || m_V02Hypothesis == "Lambda") && (m_V01Hypothesis=="Lambda/Ks" || m_V01Hypothesis=="Ks/Lambda")) {
396 if((m_V02Hypothesis == "Ks" && V0Itr2->second==KS) ||
397 (m_V02Hypothesis == "Lambda" && (V0Itr2->second==LAMBDA || V0Itr2->second==LAMBDABAR))) numberOfVertices = 1;
398 if((m_V02Hypothesis == "Ks" && V0Itr1->second==KS) ||
399 (m_V02Hypothesis == "Lambda" && (V0Itr1->second==LAMBDA || V0Itr1->second==LAMBDABAR))) {
400 if(numberOfVertices == 1) numberOfVertices = m_JXSubVtx && m_JXV02SubVtx ? 2 : 1;
401 else numberOfVertices = -1;
402 }
403 }
404 else if(m_V01Hypothesis == "Ks" && m_V02Hypothesis == "Lambda") {
405 if(V0Itr1->second==KS && (V0Itr2->second==LAMBDA || V0Itr2->second==LAMBDABAR)) numberOfVertices = 1;
406 else if(V0Itr2->second==KS && (V0Itr1->second==LAMBDA || V0Itr1->second==LAMBDABAR)) numberOfVertices = -1;
407 }
408 else if(m_V01Hypothesis == "Lambda" && m_V02Hypothesis == "Ks") {
409 if((V0Itr1->second==LAMBDA || V0Itr1->second==LAMBDABAR) && V0Itr2->second==KS) numberOfVertices = 1;
410 else if((V0Itr2->second==LAMBDA || V0Itr2->second==LAMBDABAR) && V0Itr1->second==KS) numberOfVertices = -1;
411 }
412 else if(m_V01Hypothesis == "Ks" && m_V02Hypothesis == "Ks") {
413 if(V0Itr1->second==KS && V0Itr2->second==KS) numberOfVertices = m_JXSubVtx && m_JXV02SubVtx ? 2 : 1;
414 }
415 else if(m_V01Hypothesis == "Lambda" && m_V02Hypothesis == "Lambda") {
416 if((V0Itr1->second==LAMBDA || V0Itr1->second==LAMBDABAR) && (V0Itr2->second==LAMBDA || V0Itr2->second==LAMBDABAR)) numberOfVertices = m_JXSubVtx && m_JXV02SubVtx ? 2 : 1;
417 }
418
419 if(numberOfVertices==2) {
420 Trk::VxCascadeInfo* result1 = fitMainVtx(*jxItr, massesJX, V0Itr1->first, V0Itr1->second, V0Itr2->first, V0Itr2->second, trackCols, defaultPVContainer.cptr(), pvContainer.cptr());
421 if(result1) cascadeinfoContainer.push_back(result1);
422 Trk::VxCascadeInfo* result2 = fitMainVtx(*jxItr, massesJX, V0Itr2->first, V0Itr2->second, V0Itr1->first, V0Itr1->second, trackCols, defaultPVContainer.cptr(), pvContainer.cptr());
423 if(result2) cascadeinfoContainer.push_back(result2);
424 }
425 else if(numberOfVertices==1) {
426 Trk::VxCascadeInfo* result = fitMainVtx(*jxItr, massesJX, V0Itr1->first, V0Itr1->second, V0Itr2->first, V0Itr2->second, trackCols, defaultPVContainer.cptr(), pvContainer.cptr());
427 if(result) cascadeinfoContainer.push_back(result);
428 }
429 else if(numberOfVertices==-1) {
430 Trk::VxCascadeInfo* result = fitMainVtx(*jxItr, massesJX, V0Itr2->first, V0Itr2->second, V0Itr1->first, V0Itr1->second, trackCols, defaultPVContainer.cptr(), pvContainer.cptr());
431 if(result) cascadeinfoContainer.push_back(result);
432 }
433 }
434 }
435 }
436
437 return StatusCode::SUCCESS;
438 }
439
440 StatusCode JpsiXPlus2V0::addBranches(const EventContext& ctx) const {
441 size_t topoN = 4;
442 if(!m_JXSubVtx) topoN--;
443
444 if(m_cascadeOutputKeys.size() != topoN) {
445 ATH_MSG_FATAL("Incorrect number of output cascade vertices");
446 return StatusCode::FAILURE;
447 }
448
449 std::array<SG::WriteHandle<xAOD::VertexContainer>, 4> VtxWriteHandles; int ikey(0);
451 VtxWriteHandles[ikey] = SG::WriteHandle<xAOD::VertexContainer>(key, ctx);
452 ATH_CHECK( VtxWriteHandles[ikey].record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
453 ikey++;
454 }
455
456 //----------------------------------------------------
457 // retrieve primary vertices
458 //----------------------------------------------------
459 const xAOD::Vertex* primaryVertex(nullptr);
461 ATH_CHECK( defaultPVContainer.isValid() );
462 if (defaultPVContainer.cptr()->size()==0) {
463 ATH_MSG_WARNING("You have no primary vertices: " << defaultPVContainer.cptr()->size());
464 return StatusCode::RECOVERABLE;
465 }
466 else primaryVertex = (*defaultPVContainer.cptr())[0];
467
468 //----------------------------------------------------
469 // Record refitted primary vertices
470 //----------------------------------------------------
472 if(m_refitPV) {
474 ATH_CHECK( refPvContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
475 }
476
477 // Get TrackParticle container (standard + LRT)
479 ATH_CHECK( trackContainer.isValid() );
480
481 // Get all track containers when m_RelinkContainers is not empty
482 std::vector<const xAOD::TrackParticleContainer*> trackCols;
485 ATH_CHECK( handle.isValid() );
486 trackCols.push_back(handle.cptr());
487 }
488
489 // output V0 vertices
491 if(m_vertexV0ContainerKey.key()=="" && m_v0VtxOutputKey.key()!="") {
493 ATH_CHECK( V0OutputContainer.record(std::make_unique<xAOD::VertexContainer>(), std::make_unique<xAOD::VertexAuxContainer>()) );
494 }
495
496 // Get the input containers
497 // Note: If the event does not contain a JX candidate, it is skipped and the V0 container will not be constructed if not previously available in StoreGate
499 ATH_CHECK( jxContainer.isValid() );
500 if(jxContainer->size()==0) return StatusCode::SUCCESS;
501
502 // Select the displaced tracks
503 std::vector<const xAOD::TrackParticle*> tracksDisplaced;
504 if(m_v0VtxOutputKey.key()!="") {
505 for(const xAOD::TrackParticle* TP : *trackContainer.cptr()) {
506 // V0 track selection (https://gitlab.cern.ch/atlas/athena/-/blob/main/InnerDetector/InDetRecTools/InDetTrackSelectorTool/src/InDetConversionTrackSelectorTool.cxx)
507 if(m_v0TrkSelector->decision(*TP, primaryVertex)) {
508 uint8_t temp(0);
509 uint8_t nclus(0);
510 if(TP->summaryValue(temp, xAOD::numberOfPixelHits)) nclus += temp;
511 if(TP->summaryValue(temp, xAOD::numberOfSCTHits) ) nclus += temp;
512 if(!m_useTRT && nclus == 0) continue;
513
514 bool trk_cut = false;
515 if(nclus != 0) trk_cut = true;
516 if(nclus == 0 && TP->pt()>=m_ptTRT) trk_cut = true;
517 if(!trk_cut) continue;
518
519 // track is used if std::abs(d0/sig_d0) > d0_cut for PV
520 if(!d0Pass(TP,primaryVertex)) continue;
521
522 tracksDisplaced.push_back(TP);
523 }
524 }
525 }
526
527 SG::AuxElement::Accessor<std::string> mAcc_type("Type_V0Vtx");
528 SG::AuxElement::Accessor<int> mAcc_gfit("gamma_fit");
529 SG::AuxElement::Accessor<float> mAcc_gmass("gamma_mass");
530 SG::AuxElement::Accessor<float> mAcc_gchisq("gamma_chisq");
531 SG::AuxElement::Accessor<int> mAcc_gndof("gamma_ndof");
532
533 std::vector<std::pair<const xAOD::Vertex*,V0Enum> > selectedV0Candidates;
534
536 if(m_vertexV0ContainerKey.key() != "") {
538 ATH_CHECK( V0Container.isValid() );
539
540 for(const xAOD::Vertex* vtx : *V0Container.cptr()) {
541 std::string type_V0Vtx;
542 if(mAcc_type.isAvailable(*vtx)) type_V0Vtx = mAcc_type(*vtx);
543
544 V0Enum opt(UNKNOWN); double massV0(0);
545 if(type_V0Vtx == "Lambda") {
546 opt = LAMBDA;
547 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_ppi);
548 if(massV0<m_LambdaMassLower || massV0>m_LambdaMassUpper) continue;
549 }
550 else if(type_V0Vtx == "Lambdabar") {
551 opt = LAMBDABAR;
552 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_pip);
553 if(massV0<m_LambdaMassLower || massV0>m_LambdaMassUpper) continue;
554 }
555 else if(type_V0Vtx == "Ks") {
556 opt = KS;
557 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_pipi);
558 if(massV0<m_KsMassLower || massV0>m_KsMassUpper) continue;
559 }
560
561 if(opt==UNKNOWN) continue;
563 if((opt==LAMBDA || opt==LAMBDABAR) && m_V01Hypothesis == "Ks") continue;
564 if(opt==KS && m_V01Hypothesis == "Lambda") continue;
565 }
566
567 int gamma_fit = mAcc_gfit.isAvailable(*vtx) ? mAcc_gfit(*vtx) : 0;
568 double gamma_mass = mAcc_gmass.isAvailable(*vtx) ? mAcc_gmass(*vtx) : -1;
569 double gamma_chisq = mAcc_gchisq.isAvailable(*vtx) ? mAcc_gchisq(*vtx) : 999999;
570 double gamma_ndof = mAcc_gndof.isAvailable(*vtx) ? mAcc_gndof(*vtx) : 0;
571 if(gamma_fit==1 && gamma_mass<m_minMass_gamma && gamma_chisq/gamma_ndof<m_chi2cut_gamma) continue;
572
573 selectedV0Candidates.push_back(std::pair<const xAOD::Vertex*,V0Enum>{vtx,opt});
574 }
575 }
576 else {
577 // fit V0 vertices
578 fitV0Container(V0OutputContainer.ptr(), tracksDisplaced, trackCols);
579
580 for(const xAOD::Vertex* vtx : *V0OutputContainer.cptr()) {
581 std::string type_V0Vtx;
582 if(mAcc_type.isAvailable(*vtx)) type_V0Vtx = mAcc_type(*vtx);
583
584 V0Enum opt(UNKNOWN); double massV0(0);
585 if(type_V0Vtx == "Lambda") {
586 opt = LAMBDA;
587 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_ppi);
588 if(massV0<m_LambdaMassLower || massV0>m_LambdaMassUpper) continue;
589 }
590 else if(type_V0Vtx == "Lambdabar") {
591 opt = LAMBDABAR;
592 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_pip);
593 if(massV0<m_LambdaMassLower || massV0>m_LambdaMassUpper) continue;
594 }
595 else if(type_V0Vtx == "Ks") {
596 opt = KS;
597 massV0 = m_V0Tools->invariantMass(vtx, m_massesV0_pipi);
598 if(massV0<m_KsMassLower || massV0>m_KsMassUpper) continue;
599 }
600
601 if(opt==UNKNOWN) continue;
603 if((opt==LAMBDA || opt==LAMBDABAR) && m_V01Hypothesis == "Ks") continue;
604 if(opt==KS && m_V01Hypothesis == "Lambda") continue;
605 }
606
607 int gamma_fit = mAcc_gfit.isAvailable(*vtx) ? mAcc_gfit(*vtx) : 0;
608 double gamma_mass = mAcc_gmass.isAvailable(*vtx) ? mAcc_gmass(*vtx) : -1;
609 double gamma_chisq = mAcc_gchisq.isAvailable(*vtx) ? mAcc_gchisq(*vtx) : 999999;
610 double gamma_ndof = mAcc_gndof.isAvailable(*vtx) ? mAcc_gndof(*vtx) : 0;
611 if(gamma_fit==1 && gamma_mass<m_minMass_gamma && gamma_chisq/gamma_ndof<m_chi2cut_gamma) continue;
612
613 selectedV0Candidates.push_back(std::pair<const xAOD::Vertex*,V0Enum>{vtx,opt});
614 }
615 }
616
617 // sort and chop the V0 candidates
618 std::sort( selectedV0Candidates.begin(), selectedV0Candidates.end(), [](std::pair<const xAOD::Vertex*,V0Enum>& a, std::pair<const xAOD::Vertex*,V0Enum>& b) { return a.first->chiSquared()/a.first->numberDoF() < b.first->chiSquared()/b.first->numberDoF(); } );
619 if(m_maxV0Candidates>0 && selectedV0Candidates.size()>m_maxV0Candidates) {
620 selectedV0Candidates.erase(selectedV0Candidates.begin()+m_maxV0Candidates, selectedV0Candidates.end());
621 }
622 if(selectedV0Candidates.size()==0) return StatusCode::SUCCESS;
623
624 std::vector<Trk::VxCascadeInfo*> cascadeinfoContainer;
625 ATH_CHECK( performSearch(cascadeinfoContainer, selectedV0Candidates, ctx) );
626
627 // sort and chop the main candidates
628 std::sort( cascadeinfoContainer.begin(), cascadeinfoContainer.end(), [](Trk::VxCascadeInfo* a, Trk::VxCascadeInfo* b) { return a->fitChi2()/a->nDoF() < b->fitChi2()/b->nDoF(); } );
629 if(m_maxMainVCandidates>0 && cascadeinfoContainer.size()>m_maxMainVCandidates) {
630 for(auto it=cascadeinfoContainer.begin()+m_maxMainVCandidates; it!=cascadeinfoContainer.end(); it++) delete *it;
631 cascadeinfoContainer.erase(cascadeinfoContainer.begin()+m_maxMainVCandidates, cascadeinfoContainer.end());
632 }
633
635 ATH_CHECK( evt.isValid() );
636 BPhysPVCascadeTools helper(&(*m_CascadeTools), evt.cptr());
637 helper.SetMinNTracksInPV(m_PV_minNTracks);
638
639 // Decorators for the main vertex: chi2, ndf, pt and pt error, plus the V0 vertex variables
640 SG::AuxElement::Decorator<VertexLinkVector> CascadeLinksDecor("CascadeVertexLinks");
641 SG::AuxElement::Decorator<float> chi2_decor("ChiSquared");
642 SG::AuxElement::Decorator<int> ndof_decor("nDoF");
644 SG::AuxElement::Decorator<float> PtErr_decor("PtErr");
645
646 SG::AuxElement::Decorator<float> lxy_SV1_decor("lxy_SV1");
647 SG::AuxElement::Decorator<float> lxyErr_SV1_decor("lxyErr_SV1");
648 SG::AuxElement::Decorator<float> a0xy_SV1_decor("a0xy_SV1");
649 SG::AuxElement::Decorator<float> a0xyErr_SV1_decor("a0xyErr_SV1");
650 SG::AuxElement::Decorator<float> a0z_SV1_decor("a0z_SV1");
651 SG::AuxElement::Decorator<float> a0zErr_SV1_decor("a0zErr_SV1");
652
653 SG::AuxElement::Decorator<float> lxy_SV2_decor("lxy_SV2");
654 SG::AuxElement::Decorator<float> lxyErr_SV2_decor("lxyErr_SV2");
655 SG::AuxElement::Decorator<float> a0xy_SV2_decor("a0xy_SV2");
656 SG::AuxElement::Decorator<float> a0xyErr_SV2_decor("a0xyErr_SV2");
657 SG::AuxElement::Decorator<float> a0z_SV2_decor("a0z_SV2");
658 SG::AuxElement::Decorator<float> a0zErr_SV2_decor("a0zErr_SV2");
659
660 SG::AuxElement::Decorator<float> lxy_SV3_decor("lxy_SV3");
661 SG::AuxElement::Decorator<float> lxyErr_SV3_decor("lxyErr_SV3");
662 SG::AuxElement::Decorator<float> a0xy_SV3_decor("a0xy_SV3");
663 SG::AuxElement::Decorator<float> a0xyErr_SV3_decor("a0xyErr_SV3");
664 SG::AuxElement::Decorator<float> a0z_SV3_decor("a0z_SV3");
665 SG::AuxElement::Decorator<float> a0zErr_SV3_decor("a0zErr_SV3");
666
667 SG::AuxElement::Decorator<float> chi2_V3_decor("ChiSquared_V3");
668 SG::AuxElement::Decorator<int> ndof_V3_decor("nDoF_V3");
669
670 for(auto cascade_info : cascadeinfoContainer) {
671 if(cascade_info==nullptr) {
672 ATH_MSG_ERROR("CascadeInfo is null");
673 continue;
674 }
675
676 const std::vector<xAOD::Vertex*> &cascadeVertices = cascade_info->vertices();
677 if(cascadeVertices.size() != topoN) ATH_MSG_ERROR("Incorrect number of vertices");
678 for(size_t i=0; i<topoN; i++) {
679 if(cascadeVertices[i]==nullptr) ATH_MSG_ERROR("Error null vertex");
680 }
681
682 cascade_info->setSVOwnership(false); // Prevent Container from deleting vertices
683 const auto mainVertex = cascadeVertices[topoN-1]; // this is the mother vertex
684 const std::vector< std::vector<TLorentzVector> > &moms = cascade_info->getParticleMoms();
685
686 // Identify the input JX
687 int ijx = m_JXSubVtx ? topoN-2 : topoN-1;
688 const xAOD::Vertex* jxVtx(nullptr);
689 if(m_jxDaug_num==4) jxVtx = FindVertex<4>(jxContainer.ptr(), cascadeVertices[ijx]);
690 else if(m_jxDaug_num==3) jxVtx = FindVertex<3>(jxContainer.ptr(), cascadeVertices[ijx]);
691 else jxVtx = FindVertex<2>(jxContainer.ptr(), cascadeVertices[ijx]);
692
693 xAOD::BPhysHypoHelper vtx(m_hypoName, mainVertex);
694
695 // Get refitted track momenta from all vertices, charged tracks only
696 BPhysPVCascadeTools::SetVectorInfo(vtx, cascade_info);
697 vtx.setPass(true);
698
699 //
700 // Decorate main vertex
701 //
702 // mass, mass error
703 // https://gitlab.cern.ch/atlas/athena/-/blob/main/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/VxCascadeInfo.h
704 BPHYS_CHECK( vtx.setMass(m_CascadeTools->invariantMass(moms[topoN-1])) );
705 BPHYS_CHECK( vtx.setMassErr(m_CascadeTools->invariantMassError(moms[topoN-1],cascade_info->getCovariance()[topoN-1])) );
706 // pt and pT error (the default pt of mainVertex is != the pt of the full cascade fit!)
707 Pt_decor(*mainVertex) = m_CascadeTools->pT(moms[topoN-1]);
708 PtErr_decor(*mainVertex) = m_CascadeTools->pTError(moms[topoN-1],cascade_info->getCovariance()[topoN-1]);
709 // chi2 and ndof (the default chi2 of mainVertex is != the chi2 of the full cascade fit!)
710 chi2_decor(*mainVertex) = cascade_info->fitChi2();
711 ndof_decor(*mainVertex) = cascade_info->nDoF();
712
713 // decorate the cascade vertices
714 lxy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxy(moms[0],cascadeVertices[0],mainVertex);
715 lxyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->lxyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
716 a0z_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0z(moms[0],cascadeVertices[0],mainVertex);
717 a0zErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0zError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
718 a0xy_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xy(moms[0],cascadeVertices[0],mainVertex);
719 a0xyErr_SV1_decor(*cascadeVertices[0]) = m_CascadeTools->a0xyError(moms[0],cascade_info->getCovariance()[0],cascadeVertices[0],mainVertex);
720
722 lxy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxy(moms[1],cascadeVertices[1],cascadeVertices[2]);
723 lxyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],cascadeVertices[2]);
724 a0z_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0z(moms[1],cascadeVertices[1],cascadeVertices[2]);
725 a0zErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0zError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],cascadeVertices[2]);
726 a0xy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xy(moms[1],cascadeVertices[1],cascadeVertices[2]);
727 a0xyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],cascadeVertices[2]);
728 }
729 else {
730 lxy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxy(moms[1],cascadeVertices[1],mainVertex);
731 lxyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->lxyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
732 a0z_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0z(moms[1],cascadeVertices[1],mainVertex);
733 a0zErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0zError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
734 a0xy_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xy(moms[1],cascadeVertices[1],mainVertex);
735 a0xyErr_SV2_decor(*cascadeVertices[1]) = m_CascadeTools->a0xyError(moms[1],cascade_info->getCovariance()[1],cascadeVertices[1],mainVertex);
736 }
737
738 if(m_JXSubVtx) {
739 lxy_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->lxy(moms[2],cascadeVertices[2],mainVertex);
740 lxyErr_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->lxyError(moms[2],cascade_info->getCovariance()[2],cascadeVertices[2],mainVertex);
741 a0z_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->a0z(moms[2],cascadeVertices[2],mainVertex);
742 a0zErr_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->a0zError(moms[2],cascade_info->getCovariance()[2],cascadeVertices[2],mainVertex);
743 a0xy_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->a0xy(moms[2],cascadeVertices[2],mainVertex);
744 a0xyErr_SV3_decor(*cascadeVertices[2]) = m_CascadeTools->a0xyError(moms[2],cascade_info->getCovariance()[2],cascadeVertices[2],mainVertex);
745 }
746
747 chi2_V3_decor(*cascadeVertices[2]) = m_V0Tools->chisq(jxVtx);
748 ndof_V3_decor(*cascadeVertices[2]) = m_V0Tools->ndof(jxVtx);
749
750 if(m_cascadeFitWithPV==0) {
751 ATH_CHECK(helper.FillCandwithRefittedVertices(m_refitPV, defaultPVContainer.cptr(), m_refitPV ? refPvContainer.ptr() : 0, &(*m_pvRefitter), m_PV_max, m_DoVertexType, cascade_info, topoN-1, m_massMainV, vtx));
752 }
753
754 for(size_t i=0; i<topoN; i++) {
755 VtxWriteHandles[i].ptr()->push_back(cascadeVertices[i]);
756 }
757
758 // Set links to cascade vertices
759 VertexLinkVector cascadeVertexLinks;
760 VertexLink vertexLink1;
761 vertexLink1.setElement(cascadeVertices[0]);
762 vertexLink1.setStorableObject(*VtxWriteHandles[0].ptr());
763 if( vertexLink1.isValid() ) cascadeVertexLinks.push_back( vertexLink1 );
764 VertexLink vertexLink2;
765 vertexLink2.setElement(cascadeVertices[1]);
766 vertexLink2.setStorableObject(*VtxWriteHandles[1].ptr());
767 if( vertexLink2.isValid() ) cascadeVertexLinks.push_back( vertexLink2 );
768 if(topoN==4) {
769 VertexLink vertexLink3;
770 vertexLink3.setElement(cascadeVertices[2]);
771 vertexLink3.setStorableObject(*VtxWriteHandles[2].ptr());
772 if( vertexLink3.isValid() ) cascadeVertexLinks.push_back( vertexLink3 );
773 }
774 CascadeLinksDecor(*mainVertex) = cascadeVertexLinks;
775 } // loop over cascadeinfoContainer
776
777 // Deleting cascadeinfo since this won't be stored.
778 for (auto cascade_info : cascadeinfoContainer) {
779 if(cascade_info) delete cascade_info;
780 }
781
782 return StatusCode::SUCCESS;
783 }
784
785 bool JpsiXPlus2V0::d0Pass(const xAOD::TrackParticle* track, const xAOD::Vertex* PV) const {
786 bool pass = false;
787 const EventContext& ctx = Gaudi::Hive::currentContext();
788 std::unique_ptr<Trk::Perigee> per = m_trackToVertexTool->perigeeAtVertex(ctx, *track, PV->position());
789 if(!per) return pass;
790 double d0 = per->parameters()[Trk::d0];
791 double sig_d0 = sqrt((*per->covariance())(0,0));
792 if(std::abs(d0/sig_d0) > m_d0_cut) pass = true;
793 return pass;
794 }
795
796 Trk::VxCascadeInfo* JpsiXPlus2V0::fitMainVtx(const xAOD::Vertex* JXvtx, std::vector<double>& massesJX, const xAOD::Vertex* V01vtx, const V0Enum V01, const xAOD::Vertex* V02vtx, const V0Enum V02, const std::vector<const xAOD::TrackParticleContainer*>& trackCols, const xAOD::VertexContainer* defaultPVContainer, const xAOD::VertexContainer* pvContainer) const {
797 Trk::VxCascadeInfo* result(nullptr);
798
799 std::vector<const xAOD::TrackParticle*> tracksJX;
800 for(size_t i=0; i<JXvtx->nTrackParticles(); i++) tracksJX.push_back(JXvtx->trackParticle(i));
801 if (tracksJX.size() != massesJX.size()) {
802 ATH_MSG_ERROR("Problems with JX input: number of tracks or track mass inputs is not correct!");
803 return result;
804 }
805 std::vector<const xAOD::TrackParticle*> tracksV01;
806 for(size_t j=0; j<V01vtx->nTrackParticles(); j++) tracksV01.push_back(V01vtx->trackParticle(j));
807 std::vector<const xAOD::TrackParticle*> tracksV02;
808 for(size_t j=0; j<V02vtx->nTrackParticles(); j++) tracksV02.push_back(V02vtx->trackParticle(j));
809
810 std::vector<const xAOD::TrackParticle*> tracksJpsi{tracksJX[0], tracksJX[1]};
811 std::vector<const xAOD::TrackParticle*> tracksX;
812 if(m_jxDaug_num>=3) tracksX.push_back(tracksJX[2]);
813 if(m_jxDaug_num==4) tracksX.push_back(tracksJX[3]);
814
815 std::vector<double> massesV01;
816 if(V01==LAMBDA) massesV01 = m_massesV0_ppi;
817 else if(V01==LAMBDABAR) massesV01 = m_massesV0_pip;
818 else if(V01==KS) massesV01 = m_massesV0_pipi;
819 std::vector<double> massesV02;
820 if(V02==LAMBDA) massesV02 = m_massesV0_ppi;
821 else if(V02==LAMBDABAR) massesV02 = m_massesV0_pip;
822 else if(V02==KS) massesV02 = m_massesV0_pipi;
823
824 TLorentzVector p4_moth, p4_JX, p4_v01, p4_v02, tmp;
825 for(size_t it=0; it<JXvtx->nTrackParticles(); it++) {
826 tmp.SetPtEtaPhiM(JXvtx->trackParticle(it)->pt(), JXvtx->trackParticle(it)->eta(), JXvtx->trackParticle(it)->phi(), massesJX[it]);
827 p4_moth += tmp; p4_JX += tmp;
828 }
829 xAOD::BPhysHelper V01_helper(V01vtx);
830 for(int it=0; it<V01_helper.nRefTrks(); it++) {
831 p4_moth += V01_helper.refTrk(it,massesV01[it]);
832 p4_v01 += V01_helper.refTrk(it,massesV01[it]);
833 }
834 xAOD::BPhysHelper V02_helper(V02vtx);
835 for(int it=0; it<V02_helper.nRefTrks(); it++) {
836 p4_moth += V02_helper.refTrk(it,massesV02[it]);
837 p4_v02 += V02_helper.refTrk(it,massesV02[it]);
838 }
839 double main_mass = p4_moth.M();
841 if(m_jxDaug_num==2 && m_massJpsi>0) main_mass += - p4_JX.M() + m_massJpsi;
842 else if(m_jxDaug_num>=3 && m_massJX>0) main_mass += - p4_JX.M() + m_massJX;
843 if((V01==LAMBDA || V01==LAMBDABAR) && m_massLd>0) main_mass += - p4_v01.M() + m_massLd;
844 else if(V01==KS && m_massKs>0) main_mass += - p4_v01.M() + m_massKs;
845 if((V02==LAMBDA || V02==LAMBDABAR) && m_massLd>0) main_mass += - p4_v02.M() + m_massLd;
846 else if(V02==KS && m_massKs>0) main_mass += - p4_v02.M() + m_massKs;
847 }
848 if (main_mass < m_MassLower || main_mass > m_MassUpper) return result;
849
851 double JXV02_mass = (p4_JX+p4_v02).M();
853 if(m_jxDaug_num==2 && m_massJpsi>0) JXV02_mass += - p4_JX.M() + m_massJpsi;
854 else if(m_jxDaug_num>=3 && m_massJX>0) JXV02_mass += - p4_JX.M() + m_massJX;
855 if((V02==LAMBDA || V02==LAMBDABAR) && m_massLd>0) JXV02_mass += - p4_v02.M() + m_massLd;
856 else if(V02==KS && m_massKs>0) JXV02_mass += - p4_v02.M() + m_massKs;
857 }
858 if (JXV02_mass < m_JXV02MassLower || JXV02_mass > m_JXV02MassUpper) return result;
859 }
860
866 xAOD::BPhysHelper JX_helper(JXvtx);
867 const xAOD::Vertex* origPv_xAOD = (m_cascadeFitWithPV>=1 && m_cascadeFitWithPV<=4) ? JX_helper.origPv(pvtype) : nullptr;
868 const xAOD::Vertex* pv_xAOD = (m_cascadeFitWithPV>=1 && m_cascadeFitWithPV<=4) ? JX_helper.pv(pvtype) : nullptr;
869 std::unique_ptr<Trk::RecVertex> pv_AOD;
870 if(pv_xAOD) pv_AOD = std::make_unique<Trk::RecVertex>(pv_xAOD->position(),pv_xAOD->covariancePosition(),pv_xAOD->numberDoF(),pv_xAOD->chiSquared());
871
872 SG::AuxElement::Decorator<float> chi2_V1_decor("ChiSquared_V1");
873 SG::AuxElement::Decorator<int> ndof_V1_decor("nDoF_V1");
874 SG::AuxElement::Decorator<std::string> type_V1_decor("Type_V1");
875 SG::AuxElement::Decorator<float> chi2_V2_decor("ChiSquared_V2");
876 SG::AuxElement::Decorator<int> ndof_V2_decor("nDoF_V2");
877 SG::AuxElement::Decorator<std::string> type_V2_decor("Type_V2");
878
879 SG::AuxElement::Accessor<int> mAcc_gfit("gamma_fit");
880 SG::AuxElement::Accessor<float> mAcc_gmass("gamma_mass");
881 SG::AuxElement::Accessor<float> mAcc_gmasserr("gamma_massError");
882 SG::AuxElement::Accessor<float> mAcc_gchisq("gamma_chisq");
883 SG::AuxElement::Accessor<int> mAcc_gndof("gamma_ndof");
884 SG::AuxElement::Accessor<float> mAcc_gprob("gamma_probability");
885
886 SG::AuxElement::Decorator<int> mDec_gfit("gamma_fit");
887 SG::AuxElement::Decorator<float> mDec_gmass("gamma_mass");
888 SG::AuxElement::Decorator<float> mDec_gmasserr("gamma_massError");
889 SG::AuxElement::Decorator<float> mDec_gchisq("gamma_chisq");
890 SG::AuxElement::Decorator<int> mDec_gndof("gamma_ndof");
891 SG::AuxElement::Decorator<float> mDec_gprob("gamma_probability");
892 SG::AuxElement::Decorator< std::vector<float> > trk_pxDeco("TrackPx_V0nc");
893 SG::AuxElement::Decorator< std::vector<float> > trk_pyDeco("TrackPy_V0nc");
894 SG::AuxElement::Decorator< std::vector<float> > trk_pzDeco("TrackPz_V0nc");
895
896 std::vector<float> trk_px;
897 std::vector<float> trk_py;
898 std::vector<float> trk_pz;
899
900 // Apply the user's settings to the fitter
901 std::unique_ptr<Trk::IVKalState> state = m_iVertexFitter->makeState();
902 // Robustness: http://cdsweb.cern.ch/record/685551
903 int robustness = 0;
904 m_iVertexFitter->setRobustness(robustness, *state);
905 // Build up the topology
906 // Vertex list
907 std::vector<Trk::VertexID> vrtList;
908 // https://gitlab.cern.ch/atlas/athena/-/blob/main/Tracking/TrkVertexFitter/TrkVKalVrtFitter/TrkVKalVrtFitter/IVertexCascadeFitter.h
909 // V01 vertex
910 Trk::VertexID vID1;
911 if (m_constrV01) {
912 vID1 = m_iVertexFitter->startVertex(tracksV01,massesV01,*state,V01==KS?m_massKs:m_massLd);
913 } else {
914 vID1 = m_iVertexFitter->startVertex(tracksV01,massesV01,*state);
915 }
916 vrtList.push_back(vID1);
917 // V02 vertex
918 Trk::VertexID vID2;
919 if (m_constrV02) {
920 vID2 = m_iVertexFitter->nextVertex(tracksV02,massesV02,*state,V02==KS?m_massKs:m_massLd);
921 } else {
922 vID2 = m_iVertexFitter->nextVertex(tracksV02,massesV02,*state);
923 }
924 vrtList.push_back(vID2);
925 Trk::VertexID vID3;
926 if(m_JXSubVtx) {
927 if(m_JXV02SubVtx) { // for e.g. Lambda_b -> Jpsi + Lambda
928 // JX+V02 vertex
929 std::vector<Trk::VertexID> vrtList1{vID1};
930 std::vector<Trk::VertexID> vrtList2{vID2};
931 if (m_constrJXV02) {
932 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,vrtList2,*state,m_massJXV02);
933 } else {
934 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,vrtList2,*state);
935 }
936 vrtList1.push_back(vID3);
937 if (m_constrJX && m_jxDaug_num>2) {
938 std::vector<Trk::VertexID> cnstV; cnstV.clear();
939 if ( !m_iVertexFitter->addMassConstraint(vID3,tracksJX,cnstV,*state,m_massJX).isSuccess() ) {
940 ATH_MSG_WARNING("addMassConstraint for JX failed");
941 }
942 }
943 // Mother vertex including JX and two V0's
944 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
945 std::vector<double> tp_masses; tp_masses.clear();
946 if(m_constrMainV) {
947 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList1,*state,m_massMainV);
948 } else {
949 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList1,*state);
950 }
951 }
952 else { // no JXV02SubVtx
953 // JX vertex
954 if (m_constrJX && m_jxDaug_num>2) {
955 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,*state,m_massJX);
956 } else {
957 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,*state);
958 }
959 vrtList.push_back(vID3);
960 // Mother vertex including JX and two V0's
961 std::vector<const xAOD::TrackParticle*> tp; tp.clear();
962 std::vector<double> tp_masses; tp_masses.clear();
963 if(m_constrMainV) {
964 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList,*state,m_massMainV);
965 } else {
966 m_iVertexFitter->nextVertex(tp,tp_masses,vrtList,*state);
967 }
968 }
969 }
970 else { // m_JXSubVtx=false
971 // Mother vertex including JX and two V0's
972 if(m_constrMainV) {
973 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,vrtList,*state,m_massMainV);
974 } else {
975 vID3 = m_iVertexFitter->nextVertex(tracksJX,massesJX,vrtList,*state);
976 }
977 if (m_constrJX && m_jxDaug_num>2) {
978 std::vector<Trk::VertexID> cnstV; cnstV.clear();
979 if ( !m_iVertexFitter->addMassConstraint(vID3,tracksJX,cnstV,*state,m_massJX).isSuccess() ) {
980 ATH_MSG_WARNING("addMassConstraint for JX failed");
981 }
982 }
983 }
984
985 if (m_constrJpsi) {
986 std::vector<Trk::VertexID> cnstV; cnstV.clear();
987 if ( !m_iVertexFitter->addMassConstraint(vID3,tracksJpsi,cnstV,*state,m_massJpsi).isSuccess() ) {
988 ATH_MSG_WARNING("addMassConstraint for Jpsi failed");
989 }
990 }
991 if (m_constrX && m_jxDaug_num==4 && m_massX>0) {
992 std::vector<Trk::VertexID> cnstV; cnstV.clear();
993 if ( !m_iVertexFitter->addMassConstraint(vID3,tracksX,cnstV,*state,m_massX).isSuccess() ) {
994 ATH_MSG_WARNING("addMassConstraint for X failed");
995 }
996 }
997 // Do the work
998 std::unique_ptr<Trk::VxCascadeInfo> fit_result = std::unique_ptr<Trk::VxCascadeInfo>( m_iVertexFitter->fitCascade(*state, pv_AOD.get(), pv_AOD.get() && m_firstDecayAtPV ? true : false) );
999
1000 if (fit_result != nullptr) {
1001 for(auto v : fit_result->vertices()) {
1002 if(v->nTrackParticles()==0) {
1003 std::vector<ElementLink<xAOD::TrackParticleContainer> > nullLinkVector;
1004 v->setTrackParticleLinks(nullLinkVector);
1005 }
1006 }
1007 // reset links to original tracks
1008 BPhysPVCascadeTools::PrepareVertexLinks(fit_result.get(), trackCols);
1009
1010 // necessary to prevent memory leak
1011 fit_result->setSVOwnership(true);
1012
1013 // Chi2/DOF cut
1014 double chi2DOF = fit_result->fitChi2()/fit_result->nDoF();
1015 bool chi2CutPassed = (m_chi2cut <= 0.0 || chi2DOF < m_chi2cut);
1016
1017 const std::vector<std::vector<TLorentzVector> > &moms = fit_result->getParticleMoms();
1018 const std::vector<xAOD::Vertex*> &cascadeVertices = fit_result->vertices();
1019 size_t iMoth = cascadeVertices.size()-1;
1020 double lxy_SV1 = m_CascadeTools->lxy(moms[0],cascadeVertices[0],cascadeVertices[iMoth]);
1021 double lxy_SV2 = (m_JXSubVtx && m_JXV02SubVtx) ? m_CascadeTools->lxy(moms[1],cascadeVertices[1],cascadeVertices[2]) : m_CascadeTools->lxy(moms[1],cascadeVertices[1],cascadeVertices[iMoth]);
1022 if(chi2CutPassed && lxy_SV1>m_lxyV01_cut && lxy_SV2>m_lxyV02_cut) {
1023 chi2_V1_decor(*cascadeVertices[0]) = V01vtx->chiSquared();
1024 ndof_V1_decor(*cascadeVertices[0]) = V01vtx->numberDoF();
1025 if(V01==LAMBDA) type_V1_decor(*cascadeVertices[0]) = "Lambda";
1026 else if(V01==LAMBDABAR) type_V1_decor(*cascadeVertices[0]) = "Lambdabar";
1027 else if(V01==KS) type_V1_decor(*cascadeVertices[0]) = "Ks";
1028 mDec_gfit(*cascadeVertices[0]) = mAcc_gfit.isAvailable(*V01vtx) ? mAcc_gfit(*V01vtx) : 0;
1029 mDec_gmass(*cascadeVertices[0]) = mAcc_gmass.isAvailable(*V01vtx) ? mAcc_gmass(*V01vtx) : -1;
1030 mDec_gmasserr(*cascadeVertices[0]) = mAcc_gmasserr.isAvailable(*V01vtx) ? mAcc_gmasserr(*V01vtx) : -1;
1031 mDec_gchisq(*cascadeVertices[0]) = mAcc_gchisq.isAvailable(*V01vtx) ? mAcc_gchisq(*V01vtx) : 999999;
1032 mDec_gndof(*cascadeVertices[0]) = mAcc_gndof.isAvailable(*V01vtx) ? mAcc_gndof(*V01vtx) : 0;
1033 mDec_gprob(*cascadeVertices[0]) = mAcc_gprob.isAvailable(*V01vtx) ? mAcc_gprob(*V01vtx) : -1;
1034 trk_px.clear(); trk_py.clear(); trk_pz.clear();
1035 for(int it=0; it<V01_helper.nRefTrks(); it++) {
1036 trk_px.push_back( V01_helper.refTrk(it).Px() );
1037 trk_py.push_back( V01_helper.refTrk(it).Py() );
1038 trk_pz.push_back( V01_helper.refTrk(it).Pz() );
1039 }
1040 trk_pxDeco(*cascadeVertices[0]) = trk_px;
1041 trk_pyDeco(*cascadeVertices[0]) = trk_py;
1042 trk_pzDeco(*cascadeVertices[0]) = trk_pz;
1043
1044 chi2_V2_decor(*cascadeVertices[1]) = V02vtx->chiSquared();
1045 ndof_V2_decor(*cascadeVertices[1]) = V02vtx->numberDoF();
1046 if(V02==LAMBDA) type_V2_decor(*cascadeVertices[1]) = "Lambda";
1047 else if(V02==LAMBDABAR) type_V2_decor(*cascadeVertices[1]) = "Lambdabar";
1048 else if(V02==KS) type_V2_decor(*cascadeVertices[1]) = "Ks";
1049 mDec_gfit(*cascadeVertices[1]) = mAcc_gfit.isAvailable(*V02vtx) ? mAcc_gfit(*V02vtx) : 0;
1050 mDec_gmass(*cascadeVertices[1]) = mAcc_gmass.isAvailable(*V02vtx) ? mAcc_gmass(*V02vtx) : -1;
1051 mDec_gmasserr(*cascadeVertices[1]) = mAcc_gmasserr.isAvailable(*V02vtx) ? mAcc_gmasserr(*V02vtx) : -1;
1052 mDec_gchisq(*cascadeVertices[1]) = mAcc_gchisq.isAvailable(*V02vtx) ? mAcc_gchisq(*V02vtx) : 999999;
1053 mDec_gndof(*cascadeVertices[1]) = mAcc_gndof.isAvailable(*V02vtx) ? mAcc_gndof(*V02vtx) : 0;
1054 mDec_gprob(*cascadeVertices[1]) = mAcc_gprob.isAvailable(*V02vtx) ? mAcc_gprob(*V02vtx) : -1;
1055 trk_px.clear(); trk_py.clear(); trk_pz.clear();
1056 for(int it=0; it<V02_helper.nRefTrks(); it++) {
1057 trk_px.push_back( V02_helper.refTrk(it).Px() );
1058 trk_py.push_back( V02_helper.refTrk(it).Py() );
1059 trk_pz.push_back( V02_helper.refTrk(it).Pz() );
1060 }
1061 trk_pxDeco(*cascadeVertices[1]) = trk_px;
1062 trk_pyDeco(*cascadeVertices[1]) = trk_py;
1063 trk_pzDeco(*cascadeVertices[1]) = trk_pz;
1064
1065 result = fit_result.release();
1066 }
1067 }
1068
1069 if(pv_xAOD && result && result->getParticleMoms().size()>0) {
1070 size_t index = result->getParticleMoms().size() - 1;
1071 const std::vector<TLorentzVector> &mom = result->getParticleMoms()[index];
1072 const Amg::MatrixX &cov = result->getCovariance()[index];
1073 const xAOD::Vertex* mainVertex = result->vertices()[index];
1074 xAOD::BPhysHypoHelper vtx(m_hypoName, mainVertex);
1075 bool isInDefaultPVCont = false;
1076 for(const xAOD::Vertex* pvVtx : *defaultPVContainer) {
1077 if(pv_xAOD == pvVtx) { isInDefaultPVCont = true; break; }
1078 }
1079 if(isInDefaultPVCont) vtx.setPv( pv_xAOD, defaultPVContainer, pvtype );
1080 else vtx.setPv( pv_xAOD, pvContainer, pvtype );
1081 if(origPv_xAOD) vtx.setOrigPv( origPv_xAOD, defaultPVContainer, pvtype );
1082 vtx.setLxy ( m_CascadeTools->lxy (mom, vtx.vtx(), pv_xAOD), pvtype );
1083 vtx.setLxyErr ( m_CascadeTools->lxyError (mom, cov, vtx.vtx(), pv_xAOD), pvtype );
1084 vtx.setA0 ( m_CascadeTools->a0 (mom, vtx.vtx(), pv_xAOD), pvtype );
1085 vtx.setA0Err ( m_CascadeTools->a0Error (mom, cov, vtx.vtx(), pv_xAOD), pvtype );
1086 vtx.setA0xy ( m_CascadeTools->a0xy (mom, vtx.vtx(), pv_xAOD), pvtype );
1087 vtx.setA0xyErr( m_CascadeTools->a0xyError(mom, cov, vtx.vtx(), pv_xAOD), pvtype );
1088 vtx.setZ0 ( m_CascadeTools->a0z (mom, vtx.vtx(), pv_xAOD), pvtype );
1089 vtx.setZ0Err ( m_CascadeTools->a0zError (mom, cov, vtx.vtx(), pv_xAOD), pvtype );
1090 vtx.setRefitPVStatus( 0, pvtype );
1091 // Proper decay times
1092 vtx.setTau( m_CascadeTools->tau(mom, vtx.vtx(), pv_xAOD), pvtype, xAOD::BPhysHypoHelper::TAU_INV_MASS );
1093 vtx.setTauErr( m_CascadeTools->tauError(mom, cov, vtx.vtx(), pv_xAOD), pvtype, xAOD::BPhysHypoHelper::TAU_INV_MASS );
1094 vtx.setTau( m_CascadeTools->tau(mom, vtx.vtx(), pv_xAOD, m_massMainV), pvtype, xAOD::BPhysHypoHelper::TAU_CONST_MASS );
1095 vtx.setTauErr( m_CascadeTools->tauError(mom, cov, vtx.vtx(), pv_xAOD, m_massMainV), pvtype, xAOD::BPhysHypoHelper::TAU_CONST_MASS );
1096 }
1097
1098 return result;
1099 }
1100
1101 void JpsiXPlus2V0::fitV0Container(xAOD::VertexContainer* V0ContainerNew, const std::vector<const xAOD::TrackParticle*>& selectedTracks, const std::vector<const xAOD::TrackParticleContainer*>& trackCols) const {
1102 const EventContext& ctx = Gaudi::Hive::currentContext();
1103
1104 SG::AuxElement::Decorator<std::string> mDec_type("Type_V0Vtx");
1105 SG::AuxElement::Decorator<int> mDec_gfit("gamma_fit");
1106 SG::AuxElement::Decorator<float> mDec_gmass("gamma_mass");
1107 SG::AuxElement::Decorator<float> mDec_gmasserr("gamma_massError");
1108 SG::AuxElement::Decorator<float> mDec_gchisq("gamma_chisq");
1109 SG::AuxElement::Decorator<int> mDec_gndof("gamma_ndof");
1110 SG::AuxElement::Decorator<float> mDec_gprob("gamma_probability");
1111
1112 std::vector<const xAOD::TrackParticle*> posTracks;
1113 std::vector<const xAOD::TrackParticle*> negTracks;
1114 for(const xAOD::TrackParticle* TP : selectedTracks) {
1115 if(TP->charge()>0) posTracks.push_back(TP);
1116 else negTracks.push_back(TP);
1117 }
1118
1119 for(const xAOD::TrackParticle* TP1 : posTracks) {
1120 const Trk::Perigee& aPerigee1 = TP1->perigeeParameters();
1121 for(const xAOD::TrackParticle* TP2 : negTracks) {
1122 const Trk::Perigee& aPerigee2 = TP2->perigeeParameters();
1123 int sflag(0), errorcode(0);
1124 Amg::Vector3D startingPoint = m_vertexEstimator->getCirclesIntersectionPoint(&aPerigee1,&aPerigee2,sflag,errorcode);
1125 if (errorcode != 0) {startingPoint(0) = 0.0; startingPoint(1) = 0.0; startingPoint(2) = 0.0;}
1126
1127 if (errorcode == 0 || errorcode == 5 || errorcode == 6 || errorcode == 8) {
1128 Trk::PerigeeSurface perigeeSurface(startingPoint);
1129 const Trk::TrackParameters* extrapolatedPerigee1 = m_extrapolator->extrapolate(ctx,TP1->perigeeParameters(), perigeeSurface).release();
1130 const Trk::TrackParameters* extrapolatedPerigee2 = m_extrapolator->extrapolate(ctx,TP2->perigeeParameters(), perigeeSurface).release();
1131 std::vector<std::unique_ptr<const Trk::TrackParameters> > cleanup;
1132 if(!extrapolatedPerigee1) extrapolatedPerigee1 = &TP1->perigeeParameters();
1133 else cleanup.push_back(std::unique_ptr<const Trk::TrackParameters>(extrapolatedPerigee1));
1134 if(!extrapolatedPerigee2) extrapolatedPerigee2 = &TP2->perigeeParameters();
1135 else cleanup.push_back(std::unique_ptr<const Trk::TrackParameters>(extrapolatedPerigee2));
1136 if(extrapolatedPerigee1 && extrapolatedPerigee2) {
1137 bool pass = false;
1138 TLorentzVector v1; TLorentzVector v2;
1139 if(!pass) {
1140 v1.SetXYZM(extrapolatedPerigee1->momentum().x(),extrapolatedPerigee1->momentum().y(),extrapolatedPerigee1->momentum().z(),m_mass_proton);
1141 v2.SetXYZM(extrapolatedPerigee2->momentum().x(),extrapolatedPerigee2->momentum().y(),extrapolatedPerigee2->momentum().z(),m_mass_pion);
1142 if((v1+v2).M()>1030.0 && (v1+v2).M()<1200.0) pass = true;
1143 }
1144 if(!pass) {
1145 v1.SetXYZM(extrapolatedPerigee1->momentum().x(),extrapolatedPerigee1->momentum().y(),extrapolatedPerigee1->momentum().z(),m_mass_pion);
1146 v2.SetXYZM(extrapolatedPerigee2->momentum().x(),extrapolatedPerigee2->momentum().y(),extrapolatedPerigee2->momentum().z(),m_mass_proton);
1147 if((v1+v2).M()>1030.0 && (v1+v2).M()<1200.0) pass = true;
1148 }
1149 if(!pass) {
1150 v1.SetXYZM(extrapolatedPerigee1->momentum().x(),extrapolatedPerigee1->momentum().y(),extrapolatedPerigee1->momentum().z(),m_mass_pion);
1151 v2.SetXYZM(extrapolatedPerigee2->momentum().x(),extrapolatedPerigee2->momentum().y(),extrapolatedPerigee2->momentum().z(),m_mass_pion);
1152 if((v1+v2).M()>430.0 && (v1+v2).M()<565.0) pass = true;
1153 }
1154 if(pass) {
1155 std::vector<const xAOD::TrackParticle*> tracksV0;
1156 tracksV0.push_back(TP1); tracksV0.push_back(TP2);
1157 std::unique_ptr<xAOD::Vertex> V0vtx = std::unique_ptr<xAOD::Vertex>( m_iV0Fitter->fit(tracksV0, startingPoint) );
1158 if(V0vtx && V0vtx->chiSquared()>=0) {
1159 double chi2DOF = V0vtx->chiSquared()/V0vtx->numberDoF();
1160 if(chi2DOF>m_chi2cut_V0) continue;
1161
1162 double massSig_V0_Lambda1 = std::abs(m_V0Tools->invariantMass(V0vtx.get(), m_massesV0_ppi)-m_mass_Lambda)/m_V0Tools->invariantMassError(V0vtx.get(), m_massesV0_ppi);
1163 double massSig_V0_Lambda2 = std::abs(m_V0Tools->invariantMass(V0vtx.get(), m_massesV0_pip)-m_mass_Lambda)/m_V0Tools->invariantMassError(V0vtx.get(), m_massesV0_pip);
1164 double massSig_V0_Ks = std::abs(m_V0Tools->invariantMass(V0vtx.get(), m_massesV0_pipi)-m_mass_Ks)/m_V0Tools->invariantMassError(V0vtx.get(), m_massesV0_pipi);
1165 if(massSig_V0_Lambda1<=massSig_V0_Lambda2 && massSig_V0_Lambda1<=massSig_V0_Ks) {
1166 mDec_type(*V0vtx.get()) = "Lambda";
1167 }
1168 else if(massSig_V0_Lambda2<=massSig_V0_Lambda1 && massSig_V0_Lambda2<=massSig_V0_Ks) {
1169 mDec_type(*V0vtx.get()) = "Lambdabar";
1170 }
1171 else if(massSig_V0_Ks<=massSig_V0_Lambda1 && massSig_V0_Ks<=massSig_V0_Lambda2) {
1172 mDec_type(*V0vtx.get()) = "Ks";
1173 }
1174
1175 int gamma_fit = 0; int gamma_ndof = 0; double gamma_chisq = 999999.;
1176 double gamma_prob = -1., gamma_mass = -1., gamma_massErr = -1.;
1177 std::unique_ptr<xAOD::Vertex> gammaVtx = std::unique_ptr<xAOD::Vertex>( m_iGammaFitter->fit(tracksV0, m_V0Tools->vtx(V0vtx.get())) );
1178 if (gammaVtx) {
1179 gamma_fit = 1;
1180 gamma_mass = m_V0Tools->invariantMass(gammaVtx.get(),m_mass_e,m_mass_e);
1181 gamma_massErr = m_V0Tools->invariantMassError(gammaVtx.get(),m_mass_e,m_mass_e);
1182 gamma_chisq = m_V0Tools->chisq(gammaVtx.get());
1183 gamma_ndof = m_V0Tools->ndof(gammaVtx.get());
1184 gamma_prob = m_V0Tools->vertexProbability(gammaVtx.get());
1185 }
1186 mDec_gfit(*V0vtx.get()) = gamma_fit;
1187 mDec_gmass(*V0vtx.get()) = gamma_mass;
1188 mDec_gmasserr(*V0vtx.get()) = gamma_massErr;
1189 mDec_gchisq(*V0vtx.get()) = gamma_chisq;
1190 mDec_gndof(*V0vtx.get()) = gamma_ndof;
1191 mDec_gprob(*V0vtx.get()) = gamma_prob;
1192
1193 xAOD::BPhysHelper V0_helper(V0vtx.get());
1194 V0_helper.setRefTrks(); // AOD only method
1195
1196 if(not trackCols.empty()){
1197 try {
1198 JpsiUpsilonCommon::RelinkVertexTracks(trackCols, V0vtx.get());
1199 } catch (std::runtime_error const& e) {
1200 ATH_MSG_ERROR(e.what());
1201 return;
1202 }
1203 }
1204
1205 V0ContainerNew->push_back(std::move(V0vtx));
1206 }
1207 }
1208 }
1209 }
1210 }
1211 }
1212 }
1213
1214 template<size_t NTracks>
1216 for (const xAOD::Vertex* v1 : *cont) {
1217 assert(v1->nTrackParticles() == NTracks);
1218 std::array<const xAOD::TrackParticle*, NTracks> a1;
1219 std::array<const xAOD::TrackParticle*, NTracks> a2;
1220 for(size_t i=0; i<NTracks; i++){
1221 a1[i] = v1->trackParticle(i);
1222 a2[i] = v->trackParticle(i);
1223 }
1224 std::sort(a1.begin(), a1.end());
1225 std::sort(a2.begin(), a2.end());
1226 if(a1 == a2) return v1;
1227 }
1228 return nullptr;
1229 }
1230}
#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
value_type push_back(value_type pElem)
Add an element to the end of the collection.
static void PrepareVertexLinks(Trk::VxCascadeInfo *result, const xAOD::TrackParticleContainer *importedTrackCollection)
static double getParticleMass(const HepPDT::ParticleDataTable *pdt, int pdg)
static void SetVectorInfo(xAOD::BPhysHelper &, const Trk::VxCascadeInfo *)
static void RelinkVertexTracks(const std::vector< const xAOD::TrackParticleContainer * > &trkcols, xAOD::Vertex *vtx)
SG::ReadHandleKey< xAOD::VertexContainer > m_pvContainerName
std::vector< std::string > m_vertexJXHypoNames
ToolHandle< DerivationFramework::CascadeTools > m_CascadeTools
JpsiXPlus2V0(const std::string &type, const std::string &name, const IInterface *parent)
ServiceHandle< IPartPropSvc > m_partPropSvc
std::vector< double > m_massesV0_pip
virtual StatusCode addBranches(const EventContext &ctx) const override
ToolHandle< Reco::ITrackToVertex > m_trackToVertexTool
ToolHandle< Trk::ITrackSelectorTool > m_v0TrkSelector
std::vector< double > m_massesV0_ppi
SG::ReadHandleKey< xAOD::VertexContainer > m_VxPrimaryCandidateName
ToolHandle< Trk::IExtrapolator > m_extrapolator
ToolHandle< Trk::TrkVKalVrtFitter > m_iVertexFitter
ToolHandle< Analysis::PrimaryVertexRefitter > m_pvRefitter
ToolHandle< Trk::V0Tools > m_V0Tools
SG::ReadHandleKey< xAOD::EventInfo > m_eventInfo_key
ToolHandle< InDet::VertexPointEstimator > m_vertexEstimator
std::vector< double > m_massesV0_pipi
ToolHandle< Trk::IVertexFitter > m_iGammaFitter
bool d0Pass(const xAOD::TrackParticle *track, const xAOD::Vertex *PV) const
SG::WriteHandleKey< xAOD::VertexContainer > m_refPVContainerName
SG::WriteHandleKeyArray< xAOD::VertexContainer > m_cascadeOutputKeys
virtual StatusCode initialize() override
ToolHandle< Trk::TrkV0VertexFitter > m_iV0Fitter
const xAOD::Vertex * FindVertex(const xAOD::VertexContainer *cont, const xAOD::Vertex *v) const
Trk::VxCascadeInfo * fitMainVtx(const xAOD::Vertex *JXvtx, std::vector< double > &massesJX, const xAOD::Vertex *V01vtx, const V0Enum V01, const xAOD::Vertex *V02vtx, const V0Enum V02, const std::vector< const xAOD::TrackParticleContainer * > &trackCols, const xAOD::VertexContainer *defaultPVContainer, const xAOD::VertexContainer *pvContainer) const
SG::WriteHandleKey< xAOD::VertexContainer > m_v0VtxOutputKey
void fitV0Container(xAOD::VertexContainer *V0ContainerNew, const std::vector< const xAOD::TrackParticle * > &selectedTracks, const std::vector< const xAOD::TrackParticleContainer * > &trackCols) const
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexJXContainerKey
SG::ReadHandleKey< xAOD::TrackParticleContainer > m_TrkParticleCollection
SG::ReadHandleKeyArray< xAOD::TrackParticleContainer > m_RelinkContainers
StatusCode performSearch(std::vector< Trk::VxCascadeInfo * > &cascadeinfoContainer, const std::vector< std::pair< const xAOD::Vertex *, V0Enum > > &selectedV0Candidates, const EventContext &ctx) const
SG::ReadHandleKey< xAOD::VertexContainer > m_vertexV0ContainerKey
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.
Property holding a SG store/key/clid from which a ReadHandle is made.
const_pointer_type ptr()
Dereference the pointer.
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.
const_pointer_type cptr() const
Dereference the pointer.
StatusCode record(std::unique_ptr< T > data)
Record a const object to the store.
pointer_type ptr()
Dereference the pointer.
const Amg::Vector3D & momentum() const
Access method for the momentum.
Class describing the Line to which the Perigee refers to.
float setZ0(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
longitudinal impact parameter
const xAOD::Vertex * origPv(const pv_type vertexType=BPhysHelper::PV_MIN_A0)
original PV
bool setLxyErr(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
its error
bool setLxy(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the transverse decay distance and its error measured between the refitted primary vertex of type ...
float setZ0Err(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
longitudinal impact parameter error
const xAOD::Vertex * vtx() const
Getter method for the cached xAOD::Vertex.
float setA0(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the 3D and transverse impact parameters and their error.
bool setPv(const xAOD::Vertex *pv, const xAOD::VertexContainer *vertexContainer, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the refitted collision vertex of type pv_type.
const xAOD::Vertex * pv(const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Get the refitted collision vertex of type pv_type.
TVector3 refTrk(const size_t index)
Returns i-th refitted track 3-momentum.
pv_type
: Enum type of the PV
bool setRefTrks(std::vector< float > px, std::vector< float > py, std::vector< float > pz)
Sets refitted track momenta.
float setA0Err(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
3D impact parameter error
bool setRefitPVStatus(int code, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the exitCode of the refitter for vertex of type pv_type.
float setA0xyErr(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
transverse impact parameter error
int nRefTrks()
Returns number of stored refitted track momenta.
float setA0xy(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
transverse impact parameter
bool setOrigPv(const xAOD::Vertex *pv, const xAOD::VertexContainer *vertexContainer, const pv_type vertexType=BPhysHelper::PV_MIN_A0)
Set the original collision vertex of type pv_type.
bool setMass(const float val)
Set given invariant mass and its error.
bool setPass(bool passVal)
get the pass flag for this hypothesis
bool setTau(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0, const tau_type tauType=BPhysHypoHelper::TAU_CONST_MASS)
: Set the proper decay time and error.
bool setMassErr(const float val)
invariant mass error
bool setTauErr(const float val, const pv_type vertexType=BPhysHelper::PV_MIN_A0, const tau_type tauType=BPhysHypoHelper::TAU_CONST_MASS)
proper decay time 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.
float numberDoF() const
Returns the number of degrees of freedom of the vertex fit as float.
float chiSquared() const
Returns the of the vertex fit as float.
const Amg::Vector3D & position() const
Returns the 3-pos.
Eigen::Matrix< double, Eigen::Dynamic, Eigen::Dynamic > MatrixX
Dynamic Matrix - dynamic allocation.
Eigen::Matrix< double, 3, 1 > Vector3D
THE reconstruction tool.
ElementLink< xAOD::VertexContainer > VertexLink
std::vector< VertexLink > VertexLinkVector
static const int PSI2S
static const int MUON
static const int BCPLUS
static const int ELECTRON
static const int K0S
static const int LAMBDAB0
static const int PIPLUS
static const int JPSI
static const int LAMBDA0
static const int PROTON
ParametersT< TrackParametersDim, Charged, PerigeeSurface > Perigee
@ d0
Definition ParamDefs.h:63
ParametersBase< TrackParametersDim, Charged > TrackParameters
Definition index.py:1
void sort(typename DataModel_detail::iterator< DVL > beg, typename DataModel_detail::iterator< DVL > end)
Specialization of sort for DataVector/List.
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.
@ numberOfSCTHits
number of hits in SCT [unit8_t].
@ numberOfPixelHits
these are the pixel hits, including the b-layer [unit8_t].