Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
KshortReconstruction.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file KshortReconstruction.cc
1 #include "KshortReconstruction.h"
2 
4 
7 #include <phool/getClass.h>
8 
10 
11 #include <utility>
12 
13 #include <TLorentzVector.h>
14 
15 #include <TFile.h>
16 #include <TH1D.h>
17 #include <TNtuple.h>
18 
20 {
21  // Loop over tracks and check for close DCA match with all other tracks
22  for (auto tr1_it = m_svtxTrackMap->begin(); tr1_it != m_svtxTrackMap->end(); ++tr1_it)
23  {
24  auto id1 = tr1_it->first;
25  auto tr1 = tr1_it->second;
26  if (tr1->get_quality() > _qual_cut)
27  {
28  continue;
29  }
30 
31  // calculate number silicon tracks
32  double this_dca_cut = track_dca_cut;
33  TrackSeed* siliconseed = tr1->get_silicon_seed();
34  if (!siliconseed)
35  {
36  this_dca_cut *= 5;
37  if (Verbosity() > 2)
38  {
39  std::cout << "silicon seed not found" << std::endl;
40  }
41  if (_require_mvtx)
42  {
43  continue;
44  }
45  }
46  Acts::Vector3 pos1(tr1->get_x(), tr1->get_y(), tr1->get_z());
47  Acts::Vector3 mom1(tr1->get_px(), tr1->get_py(), tr1->get_pz());
48  Acts::Vector3 dcaVals1 = calculateDca(tr1, mom1, pos1);
49  // first dca cuts
50  if (dcaVals1(0) < this_dca_cut or dcaVals1(1) < this_dca_cut)
51  {
52  continue;
53  }
54 
55  // look for close DCA matches with all other such tracks
56  for (auto tr2_it = std::next(tr1_it); tr2_it != m_svtxTrackMap->end(); ++tr2_it)
57  {
58  auto id2 = tr2_it->first;
59  auto tr2 = tr2_it->second;
60  if (tr2->get_quality() > _qual_cut)
61  {
62  continue;
63  }
64 
65  // calculate number silicon tracks
66  TrackSeed* siliconseed2 = tr2->get_silicon_seed();
67  double this_dca_cut2 = track_dca_cut;
68  if (!siliconseed2)
69  {
70  this_dca_cut2 *= 5;
71  if (Verbosity() > 2)
72  {
73  std::cout << "silicon seed not found" << std::endl;
74  }
75  if (_require_mvtx)
76  {
77  continue;
78  }
79  }
80 
81  // dca xy and dca z cut here compare to track dca cut
82  Acts::Vector3 pos2(tr2->get_x(), tr2->get_y(), tr2->get_z());
83  Acts::Vector3 mom2(tr2->get_px(), tr2->get_py(), tr2->get_pz());
84  Acts::Vector3 dcaVals2 = calculateDca(tr2, mom2, pos2);
85 
86  if (dcaVals2(0) < this_dca_cut2 or dcaVals2(1) < this_dca_cut2)
87  {
88  continue;
89  }
90 
91  // find DCA of these two tracks
92  if (Verbosity() > 3)
93  {
94  std::cout << "Check DCA for tracks " << id1 << " and " << id2 << std::endl;
95  }
96 
97  if (tr1->get_charge() == tr2->get_charge())
98  {
99  continue;
100  }
101 
102  // declare these variables to pass into findPCAtwoTracks and fillHistogram by reference
103  double pair_dca;
104  Acts::Vector3 pca_rel1;
105  Acts::Vector3 pca_rel2;
106  double invariantMass;
107  double invariantPt;
108  float rapidity;
109  float pseudorapidity;
110 
111  // Initial calculation of point of closest approach between the two tracks
112  // This presently assumes straight line tracks to get a rough answer
113  // Should update to use circles instead?
114  findPcaTwoTracks(pos1, pos2, mom1, mom2, pca_rel1, pca_rel2, pair_dca);
115 
116  // tracks with small relative pca are k short candidates
117  if (abs(pair_dca) < pair_dca_cut)
118  {
119  // Pair pca and dca were calculated with nominal track parameters and are approximate
120  // Project tracks to this rough pca
121  Eigen::Vector3d projected_pos1;
122  Eigen::Vector3d projected_mom1;
123  Eigen::Vector3d projected_pos2;
124  Eigen::Vector3d projected_mom2;
125 
126  bool ret1 = projectTrackToPoint(tr1, pca_rel1, projected_pos1, projected_mom1);
127  bool ret2 = projectTrackToPoint(tr2, pca_rel2, projected_pos2, projected_mom2);
128 
129  if (!ret1 or !ret2)
130  {
131  continue;
132  }
133 
134  // recalculate pca starting with projected position and momentum
135  double pair_dca_proj;
136  Acts::Vector3 pca_rel1_proj;
137  Acts::Vector3 pca_rel2_proj;
138  findPcaTwoTracks(projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj);
139 
140  //if(pair_dca_proj > pair_dca_cut) continue;
141 
142  // invariant mass is calculated in this method
143  fillHistogram(projected_mom1, projected_mom2, recomass, invariantMass, invariantPt, rapidity, pseudorapidity);
144  fillNtp(tr1, tr2, dcaVals1, dcaVals2, pca_rel1, pca_rel2, pair_dca, invariantMass, invariantPt, rapidity, pseudorapidity, projected_pos1, projected_pos2, projected_mom1, projected_mom2, pca_rel1_proj, pca_rel2_proj, pair_dca_proj);
145 
146  if (Verbosity() > 2)
147  {
148  std::cout << " Accepted Track Pair" << std::endl;
149  std::cout << " invariant mass: " << invariantMass << std::endl;
150  std::cout << " track1 dca_cut: " << this_dca_cut << " track2 dca_cut: " << this_dca_cut2 << std::endl;
151  std::cout << " dca3dxy1,dca3dz1,phi1: " << dcaVals1 << std::endl;
152  std::cout << " dca3dxy2,dca3dz2,phi2: " << dcaVals2 << std::endl;
153  std::cout << "Initial: pca_rel1: " << pca_rel1 << " pca_rel2: " << pca_rel2 << std::endl;
154  std::cout << " Initial: mom1: " << mom1 << " mom2: " << mom2 << std::endl;
155  std::cout << "Proj_pca_rel: proj_pos1: " << projected_pos1 << " proj_pos2: " << projected_pos2 << " proj_mom1: " << projected_mom1 << " proj_mom2: " << projected_mom2 << std::endl;
156  std::cout << " Relative PCA = " << abs(pair_dca) << " pca_cut = " << pair_dca_cut << std::endl;
157  std::cout << " charge 1: " << tr1->get_charge() << " charge2: " << tr2->get_charge() << std::endl;
158  std::cout << "found viable projection" << std::endl;
159  std::cout << "Final: pca_rel1_proj: " << pca_rel1_proj << " pca_rel2_proj: " << pca_rel2_proj << " mom1: " << projected_mom1 << " mom2: " << projected_mom2 << std::endl << std::endl;
160  }
161  }
162  }
163  }
164  return 0;
165 }
166 
167 void KshortReconstruction::fillNtp(SvtxTrack* track1, SvtxTrack* track2, Acts::Vector3 dcavals1, Acts::Vector3 dcavals2, Acts::Vector3 pca_rel1, Acts::Vector3 pca_rel2, double pair_dca, double invariantMass, double invariantPt, float rapidity, float pseudorapidity, Eigen::Vector3d projected_pos1, Eigen::Vector3d projected_pos2, Eigen::Vector3d projected_mom1, Eigen::Vector3d projected_mom2, Acts::Vector3 pca_rel1_proj, Acts::Vector3 pca_rel2_proj, double pair_dca_proj)
168 {
169  double px1 = track1->get_px();
170  double py1 = track1->get_py();
171  double pz1 = track1->get_pz();
172  auto tpcSeed1 = track1->get_tpc_seed();
173  size_t tpcClusters1 = tpcSeed1->size_cluster_keys();
174  double eta1 = asinh(pz1 / sqrt(pow(px1, 2) + pow(py1, 2)));
175 
176  double px2 = track2->get_px();
177  double py2 = track2->get_py();
178  double pz2 = track2->get_pz();
179  auto tpcSeed2 = track2->get_tpc_seed();
180  size_t tpcClusters2 = tpcSeed2->size_cluster_keys();
181  double eta2 = asinh(pz2 / sqrt(pow(px2, 2) + pow(py2, 2)));
182 
183  auto vtxid = track1->get_vertex_id();
184  auto svtxVertex = m_vertexMap->get(vtxid);
185 
186  Acts::Vector3 vertex(svtxVertex->get_x(), svtxVertex->get_y(), svtxVertex->get_z()); // primary vertex
187 
188  Acts::Vector3 pathLength = (pca_rel1 + pca_rel2) * 0.5 - vertex;
189  Acts::Vector3 pathLength_proj = (pca_rel1_proj + pca_rel2_proj) * 0.5 - vertex;
190 
191  float mag_pathLength = sqrt(pow(pathLength(0), 2) + pow(pathLength(1), 2) + pow(pathLength(2), 2));
192  float mag_pathLength_proj = sqrt(pow(pathLength_proj(0), 2) + pow(pathLength_proj(1), 2) + pow(pathLength_proj(2), 2));
193 
194  Acts::Vector3 projected_momentum = projected_mom1 + projected_mom2;
195  float cos_theta_reco = pathLength_proj.dot(projected_momentum) / (projected_momentum.norm() * pathLength_proj.norm());
196 
197  if (!svtxVertex)
198  {
199  return;
200  }
201 
202  float reco_info[] = {track1->get_x(), track1->get_y(), track1->get_z(), track1->get_px(), track1->get_py(), track1->get_pz(), (float) dcavals1(0), (float) dcavals1(1), (float) dcavals1(2), (float) pca_rel1(0), (float) pca_rel1(1), (float) pca_rel1(2), (float) eta1, (float) track1->get_charge(), (float) tpcClusters1, track2->get_x(), track2->get_y(), track2->get_z(), track2->get_px(), track2->get_py(), track2->get_pz(), (float) dcavals2(0), (float) dcavals2(1), (float) dcavals2(2), (float) pca_rel2(0), (float) pca_rel2(1), (float) pca_rel2(2), (float) eta2, (float) track2->get_charge(), (float) tpcClusters2, svtxVertex->get_x(), svtxVertex->get_y(), svtxVertex->get_z(), (float) pair_dca, (float) invariantMass, (float) invariantPt, (float) pathLength(0), (float) pathLength(1), (float) pathLength(2), mag_pathLength, rapidity, pseudorapidity, (float) projected_pos1(0), (float) projected_pos1(1), (float) projected_pos1(2), (float) projected_pos2(0), (float) projected_pos2(1), (float) projected_pos2(2), (float) projected_mom1(0), (float) projected_mom1(1), (float) projected_mom1(2), (float) projected_mom2(0), (float) projected_mom2(1), (float) projected_mom2(2), (float) pca_rel1_proj(0), (float) pca_rel1_proj(1), (float) pca_rel1_proj(2), (float) pca_rel2_proj(0), (float) pca_rel2_proj(1), (float) pca_rel2_proj(2), (float) pair_dca_proj, (float) pathLength_proj(0), (float) pathLength_proj(1), (float) pathLength_proj(2), mag_pathLength_proj, track1->get_quality(), track2->get_quality(), cos_theta_reco};
203 
204  ntp_reco_info->Fill(reco_info);
205 }
206 
207 void KshortReconstruction::fillHistogram(Eigen::Vector3d mom1, Eigen::Vector3d mom2, TH1D* massreco, double& invariantMass, double& invariantPt, float& rapidity, float& pseudorapidity)
208 {
209  double E1 = sqrt(pow(mom1(0), 2) + pow(mom1(1), 2) + pow(mom1(2), 2) + pow(decaymass, 2));
210  double E2 = sqrt(pow(mom2(0), 2) + pow(mom2(1), 2) + pow(mom2(2), 2) + pow(decaymass, 2));
211 
212  TLorentzVector v1(mom1(0), mom1(1), mom1(2), E1);
213  TLorentzVector v2(mom2(0), mom2(1), mom2(2), E2);
214 
215  TLorentzVector tsum;
216  tsum = v1 + v2;
217 
218  rapidity = tsum.Rapidity();
219  pseudorapidity = tsum.Eta();
220  invariantMass = tsum.M();
221  invariantPt = tsum.Pt();
222 
223  if (Verbosity() > 2)
224  {
225  std::cout << "px1: " << mom1(0) << " py1: " << mom1(1) << " pz1: " << mom1(2) << " E1: " << E1 << std::endl;
226  std::cout << "px2: " << mom2(0) << " py2: " << mom2(1) << " pz2: " << mom2(2) << " E2: " << E2 << std::endl;
227  std::cout << "tsum: " << tsum(0) << " " << tsum(1) << " " << tsum(2) << " " << tsum(3) << std::endl;
228  std::cout << "invariant mass: " << invariantMass << " invariant Pt: " << invariantPt << std::endl;
229  }
230 
231  if (invariantPt > invariant_pt_cut)
232  {
233  massreco->Fill(invariantMass);
234  }
235 }
236 
237 bool KshortReconstruction::projectTrackToPoint(SvtxTrack* track, Eigen::Vector3d PCA, Eigen::Vector3d& pos, Eigen::Vector3d& mom)
238 {
239  bool ret = true;
240 
242  ActsPropagator actsPropagator(_tGeometry);
243  auto perigee = actsPropagator.makeVertexSurface(PCA); // PCA is in cm here
244  auto params = actsPropagator.makeTrackParams(track, m_vertexMap);
245  if(!params.ok())
246  {
247  return false;
248  }
249  auto result = actsPropagator.propagateTrack(params.value(), perigee);
250 
251  if (result.ok())
252  {
253  auto projectionPos = result.value().second.position(_tGeometry->geometry().getGeoContext());
254  const auto momentum = result.value().second.momentum();
255  pos(0) = projectionPos.x() / Acts::UnitConstants::cm;
256  pos(1) = projectionPos.y() / Acts::UnitConstants::cm;
257  pos(2) = projectionPos.z() / Acts::UnitConstants::cm;
258 
259  if(Verbosity() > 2)
260  {
261  std::cout << " Input PCA " << PCA << " projection out " << pos << std::endl;
262  }
263 
264  mom(0) = momentum.x();
265  mom(1) = momentum.y();
266  mom(2) = momentum.z();
267  }
268  else
269  {
270  std::cout << " Failed projection of track with: " << std::endl;
271  std::cout << " x,y,z = " << track->get_x() << " " << track->get_y() << " " << track->get_z() << std::endl;
272  std::cout << " px,py,pz = " << track->get_px() << " " << track->get_py() << " " << track->get_pz() << std::endl;
273  std::cout << " to point (x,y,z) = " << PCA(0) / Acts::UnitConstants::cm << " " << PCA(1) / Acts::UnitConstants::cm << " " << PCA(2) / Acts::UnitConstants::cm << std::endl;
274  ret = false;
275  }
276 
277  return ret;
278 }
279 
280 bool KshortReconstruction::projectTrackToCylinder(SvtxTrack* track, double Radius, Eigen::Vector3d& pos, Eigen::Vector3d& mom)
281 {
282  // Make a cylinder surface at the radius and project the track to that
283  bool ret = true;
284  const double eta = 2.0;
285  const double theta = 2. * atan(exp(-eta));
286  const double halfZ = Radius / tan(theta) * Acts::UnitConstants::cm;
287  Radius *= Acts::UnitConstants::cm;
288 
290  auto transform = Acts::Transform3::Identity();
291 
292  std::shared_ptr<Acts::CylinderSurface> cylSurf =
293  Acts::Surface::makeShared<Acts::CylinderSurface>(transform,
294  Radius,
295  halfZ);
296  ActsPropagator actsPropagator(_tGeometry);
297  auto params = actsPropagator.makeTrackParams(track, m_vertexMap);
298  if(!params.ok())
299  {
300  return false;
301  }
302 
303  auto result = actsPropagator.propagateTrack(params.value(), cylSurf);
304  if (result.ok())
305  {
306  auto projectionPos = result.value().second.position(_tGeometry->geometry().getGeoContext());
307  const auto momentum = result.value().second.momentum();
308  pos(0) = projectionPos.x() / Acts::UnitConstants::cm;
309  pos(1) = projectionPos.y() / Acts::UnitConstants::cm;
310  pos(2) = projectionPos.z() / Acts::UnitConstants::cm;
311 
312  mom(0) = momentum.x();
313  mom(1) = momentum.y();
314  mom(2) = momentum.z();
315  }
316  else
317  {
318  ret = false;
319  }
320 
321  return ret;
322 }
323 
325 {
326  auto vertexId = track->get_vertex_id();
327  const SvtxVertex* svtxVertex = m_vertexMap->get(vertexId);
328  Acts::Vector3 vertex = Acts::Vector3::Zero();
329  if (svtxVertex)
330  {
331  vertex(0) = svtxVertex->get_x() * Acts::UnitConstants::cm;
332  vertex(1) = svtxVertex->get_y() * Acts::UnitConstants::cm;
333  vertex(2) = svtxVertex->get_z() * Acts::UnitConstants::cm;
334  }
335 
336  return vertex;
337 }
338 
340 {
341  TLorentzVector v1;
342  TLorentzVector v2;
343 
344  double px1 = mom1(0);
345  double py1 = mom1(1);
346  double pz1 = mom1(2);
347  double px2 = mom2(0);
348  double py2 = mom2(1);
349  double pz2 = mom2(2);
350 
351  Float_t E1 = sqrt(pow(px1, 2) + pow(py1, 2) + pow(pz1, 2) + pow(decaymass, 2));
352  Float_t E2 = sqrt(pow(px2, 2) + pow(py2, 2) + pow(pz2, 2) + pow(decaymass, 2));
353 
354  v1.SetPxPyPzE(px1, py1, pz1, E1);
355  v2.SetPxPyPzE(px2, py2, pz2, E2);
356 
357  // calculate lorentz vector
358  const Eigen::Vector3d& a1 = std::move(pos1);
359  const Eigen::Vector3d& a2 = std::move(pos2);
360 
361  Eigen::Vector3d b1(v1.Px(), v1.Py(), v1.Pz());
362  Eigen::Vector3d b2(v2.Px(), v2.Py(), v2.Pz());
363 
364  // The shortest distance between two skew lines described by
365  // a1 + c * b1
366  // a2 + d * b2
367  // where a1, a2, are vectors representing points on the lines, b1, b2 are direction vectors, and c and d are scalars
368  // dca = (b1 x b2) .(a2-a1) / |b1 x b2|
369 
370  // bcrossb/mag_bcrossb is a unit vector perpendicular to both direction vectors b1 and b2
371  auto bcrossb = b1.cross(b2);
372  auto mag_bcrossb = bcrossb.norm();
373  // a2-a1 is the vector joining any arbitrary points on the two lines
374  auto aminusa = a2 - a1;
375 
376  // The DCA of these two lines is the projection of a2-a1 along the direction of the perpendicular to both
377  // remember that a2-a1 is longer than (or equal to) the dca by definition
378  dca = 999;
379  if (mag_bcrossb != 0)
380  {
381  dca = bcrossb.dot(aminusa) / mag_bcrossb;
382  }
383  else
384  {
385  return; // same track, skip combination
386  }
387 
388  // get the points at which the normal to the lines intersect the lines, where the lines are perpendicular
389  double X = b1.dot(b2) - b1.dot(b1) * b2.dot(b2) / b2.dot(b1);
390  double Y = (a2.dot(b2) - a1.dot(b2)) - (a2.dot(b1) - a1.dot(b1)) * b2.dot(b2) / b2.dot(b1);
391  double c = Y / X;
392 
393  double F = b1.dot(b1) / b2.dot(b1);
394  double G = -(a2.dot(b1) - a1.dot(b1)) / b2.dot(b1);
395  double d = c * F + G;
396 
397  // then the points of closest approach are:
398  pca1 = a1 + c * b1;
399  pca2 = a2 + d * b2;
400 
401  return;
402 }
403 
405  : SubsysReco(name)
406 {
407 }
408 
410 {
411  // For the purposes of this module, we set default values of zero to cause this track to be rejected if the dca calc fails
412  Acts::Vector3 outVals(0, 0, 0);
413  auto vtxid = track->get_vertex_id();
414  if (!m_vertexMap)
415  {
416  std::cout << "Could not find m_vertexmap " << std::endl;
417  return outVals;
418  }
419  auto svtxVertex = m_vertexMap->get(vtxid);
420  if (!svtxVertex)
421  {
422  std::cout << "Could not find vtxid in m_vertexMap " << vtxid << std::endl;
423  return outVals;
424  }
425  Acts::Vector3 vertex(svtxVertex->get_x(), svtxVertex->get_y(), svtxVertex->get_z());
426  position -= vertex;
427  Acts::Vector3 r = momentum.cross(Acts::Vector3(0., 0., 1.));
428  float phi = atan2(r(1), r(0));
429 
431  rot(0, 0) = cos(phi);
432  rot(0, 1) = -sin(phi);
433  rot(0, 2) = 0;
434  rot(1, 0) = sin(phi);
435  rot(1, 1) = cos(phi);
436  rot(1, 2) = 0;
437  rot(2, 0) = 0;
438  rot(2, 1) = 0;
439  rot(2, 2) = 1;
440 
441  Acts::Vector3 pos_R = rot * position;
442  double dca3dxy = pos_R(0);
443  double dca3dz = pos_R(2);
444 
445  outVals(0) = abs(dca3dxy);
446  outVals(1) = abs(dca3dz);
447  outVals(2) = phi;
448 
449  if (Verbosity() > 4)
450  {
451  std::cout << " pre-position: " << position << std::endl;
452  std::cout << " vertex: " << vertex << std::endl;
453  std::cout << " vertex subtracted-position: " << position << std::endl;
454  }
455 
456  return outVals;
457 }
458 
460 {
461  const char* cfilepath = filepath.c_str();
462  fout = new TFile(cfilepath, "recreate");
463  ntp_reco_info = new TNtuple("ntp_reco_info", "decay_pairs", "x1:y1:z1:px1:py1:pz1:dca3dxy1:dca3dz1:phi1:pca_rel1_x:pca_rel1_y:pca_rel1_z:eta1:charge1:tpcClusters_1:x2:y2:z2:px2:py2:pz2:dca3dxy2:dca3dz2:phi2:pca_rel2_x:pca_rel2_y:pca_rel2_z:eta2:charge2:tpcClusters_2:vertex_x:vertex_y:vertex_z:pair_dca:invariant_mass:invariant_pt:pathlength_x:pathlength_y:pathlength_z:pathlength:rapidity:pseudorapidity:projected_pos1_x:projected_pos1_y:projected_pos1_z:projected_pos2_x:projected_pos2_y:projected_pos2_z:projected_mom1_x:projected_mom1_y:projected_mom1_z:projected_mom2_x:projected_mom2_y:projected_mom2_z:projected_pca_rel1_x:projected_pca_rel1_y:projected_pca_rel1_z:projected_pca_rel2_x:projected_pca_rel2_y:projected_pca_rel2_z:projected_pair_dca:projected_pathlength_x:projected_pathlength_y:projected_pathlength_z:projected_pathlength:quality1:quality2:cosThetaReco");
464 
465  getNodes(topNode);
466 
467  char name[500];
468  sprintf(name, "recomass");
469  recomass = new TH1D(name, name, 1000, 0.0, 1); // root histogram arguments: name,title,bins,minvalx,maxvalx
470 
471  return 0;
472 }
473 
475 {
476  fout->cd();
477  ntp_reco_info->Write();
478  recomass->Write();
479  fout->Close();
480 
481  return 0;
482 }
483 
485 {
486  m_svtxTrackMap = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
487  if (!m_svtxTrackMap)
488  {
489  std::cout << PHWHERE << "No SvtxTrackMap on node tree, exiting." << std::endl;
491  }
492 
493  m_vertexMap = findNode::getClass<SvtxVertexMap>(topNode, "SvtxVertexMap");
494  if (!m_vertexMap)
495  {
496  std::cout << PHWHERE << "No vertexMap on node tree, exiting." << std::endl;
498  }
499 
500  _tGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
501  if (!_tGeometry)
502  {
503  std::cout << PHWHERE << "Error, can't find acts tracking geometry" << std::endl;
505  }
506 
508 }