Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
KFParticle_Tools.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file KFParticle_Tools.cc
1 /*
2  * This file is part of KFParticle package
3  * Copyright ( C ) 2007-2019 FIAS Frankfurt Institute for Advanced Studies
4  * 2007-2019 Goethe University of Frankfurt
5  * 2007-2019 Ivan Kisel <I.Kisel@compeng.uni-frankfurt.de>
6  * 2007-2019 Maksym Zyzak
7  *
8  * KFParticle is free software: you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * ( at your option ) any later version.
12  *
13  * KFParticle is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 /*****************/
23 /* Cameron Dean */
24 /* LANL 2020 */
25 /* cdean@bnl.gov */
26 /*****************/
27 
28 #include "KFParticle_Tools.h"
29 
32 
37 
38 #include <phool/getClass.h>
39 
40 // KFParticle stuff
41 #include <KFParticle.h>
42 #include <KFVertex.h>
43 
44 #include <Rtypes.h>
45 #include <TDatabasePDG.h>
46 #include <TMatrixD.h>
47 #include <TMatrixDfwd.h> // for TMatrixD
48 #include <TMatrixT.h> // for TMatrixT, operator*
49 
50 #include <Eigen/Dense>
51 
52 #include <algorithm> // for max, remove, minmax_el...
53 #include <cmath> // for sqrt, pow, M_PI
54 #include <cstdlib> // for abs, NULL
55 #include <iostream> // for operator<<, basic_ostream
56 #include <iterator> // for end
57 #include <map> // for _Rb_tree_iterator, map
58 #include <memory> // for allocator_traits<>::va...
59 
62  : m_has_intermediates(false)
63  , m_min_mass(0)
64  , m_max_mass(0)
65  , m_min_decayTime(-1 * FLT_MAX)
66  , m_max_decayTime(FLT_MAX)
67  , m_min_decayLength(-1 * FLT_MAX)
68  , m_max_decayLength(FLT_MAX)
69  , m_track_pt(0.2)
70  , m_track_ptchi2(FLT_MAX)
71  , m_track_ip(-1.)
72  , m_track_ipchi2(0.)
73  , m_track_chi2ndof(4.)
74  , m_nMVTXHits(3)
75  , m_nTPCHits(20)
76  , m_comb_DCA(0.05)
77  , m_vertex_chi2ndof(15.)
78  , m_fdchi2(0.)
79  , m_dira_min(0.90)
80  , m_dira_max(1.01)
81  , m_mother_pt(0.)
82  , m_mother_ipchi2(FLT_MAX)
83  , m_get_charge_conjugate(true)
84  , m_extrapolateTracksToSV(true)
85  , m_vtx_map_node_name("SvtxVertexMap")
86  , m_trk_map_node_name("SvtxTrackMap")
87  , m_dst_vertexmap()
88  , m_dst_trackmap()
89  , m_dst_vertex()
90  , m_dst_track()
91 {
92 }
93 
95 {
96  float f_vertexParameters[6] = {m_dst_vertex->get_x(),
98  m_dst_vertex->get_z(), 0, 0, 0};
99 
100  float f_vertexCovariance[21];
101  unsigned int iterate = 0;
102  for (unsigned int i = 0; i < 3; ++i)
103  {
104  for (unsigned int j = 0; j <= i; ++j)
105  {
106  f_vertexCovariance[iterate] = m_dst_vertex->get_error(i, j);
107  ++iterate;
108  }
109  }
110 
111  KFParticle kfp_vertex;
112  kfp_vertex.Create(f_vertexParameters, f_vertexCovariance, 0, -1);
113  kfp_vertex.NDF() = m_dst_vertex->get_ndof();
114  kfp_vertex.Chi2() = m_dst_vertex->get_chisq();
115 
116  return kfp_vertex;
117 }
118 
119 std::vector<KFParticle> KFParticle_Tools::makeAllPrimaryVertices(PHCompositeNode *topNode, const std::string &vertexMapName)
120 {
121  std::string vtxMN;
122  if (vertexMapName.empty())
123  {
124  vtxMN = m_vtx_map_node_name;
125  }
126  else
127  {
128  vtxMN = vertexMapName;
129  }
130 
131  std::vector<KFParticle> primaryVertices;
132  m_dst_vertexmap = findNode::getClass<SvtxVertexMap>(topNode, vtxMN);
133  auto globalvertexmap = findNode::getClass<GlobalVertexMap>(topNode, "GlobalVertexMap");
134  if (!globalvertexmap)
135  {
136  std::cout << "Can't continue in KFParticle_Tools::makeAllPrimaryVertices" << std::endl;
137  }
138 
139  unsigned int vertexID = 0;
140 
141  for (GlobalVertexMap::ConstIter iter = globalvertexmap->begin(); iter != globalvertexmap->end(); ++iter)
142  {
143  GlobalVertex *gvertex = iter->second;
144  auto svtxiter = gvertex->find_vertexes(GlobalVertex::SVTX);
145  // check that it contains a track vertex
146  if (svtxiter == gvertex->end_vertexes())
147  {
148  continue;
149  }
150 
151  auto svtxvertexvector = svtxiter->second;
152 
153  for (auto &vertex : svtxvertexvector)
154  {
155  m_dst_vertex = m_dst_vertexmap->find(vertex->get_id())->second;
156 
157  primaryVertices.push_back(makeVertex(topNode));
158  primaryVertices[vertexID].SetId(gvertex->get_id());
159  ++vertexID;
160  }
161  }
162 
163  return primaryVertices;
164 }
165 
167 {
168  KFParticle kfp_particle;
169 
170  float f_trackParameters[6] = {m_dst_track->get_x(),
171  m_dst_track->get_y(),
172  m_dst_track->get_z(),
173  m_dst_track->get_px(),
174  m_dst_track->get_py(),
175  m_dst_track->get_pz()};
176 
177  float f_trackCovariance[21];
178  unsigned int iterate = 0;
179  for (unsigned int i = 0; i < 6; ++i)
180  {
181  for (unsigned int j = 0; j <= i; ++j)
182  {
183  f_trackCovariance[iterate] = m_dst_track->get_error(i, j);
184  ++iterate;
185  }
186  }
187 
188  kfp_particle.Create(f_trackParameters, f_trackCovariance, (Int_t) m_dst_track->get_charge(), -1);
189  kfp_particle.NDF() = m_dst_track->get_ndf();
190  kfp_particle.Chi2() = m_dst_track->get_chisq();
191  kfp_particle.SetId(m_dst_track->get_id());
192 
193  return kfp_particle;
194 }
195 
197 {
198  std::vector<KFParticle> daughterParticles;
199  m_dst_trackmap = findNode::getClass<SvtxTrackMap>(topNode, m_trk_map_node_name.c_str());
200  unsigned int trackID = 0;
201 
202  for (auto &iter : *m_dst_trackmap)
203  {
204  m_dst_track = iter.second;
205 
206  // First check if we have the required number of MVTX and TPC hits
207  TrackSeed *tpcseed = m_dst_track->get_tpc_seed();
208  TrackSeed *silseed = m_dst_track->get_silicon_seed();
209  int MVTX_hits = 0;
210  int TPC_hits = 0;
211 
212  if (silseed)
213  {
214  for (auto cluster_iter = silseed->begin_cluster_keys();
215  cluster_iter != silseed->end_cluster_keys(); ++cluster_iter)
216  {
217  const auto &cluster_key = *cluster_iter;
218  const auto trackerID = TrkrDefs::getTrkrId(cluster_key);
219 
220  if (trackerID == TrkrDefs::mvtxId)
221  {
222  ++MVTX_hits;
223  }
224  }
225  if (MVTX_hits < m_nMVTXHits)
226  {
227  continue;
228  }
229  }
230  if (tpcseed)
231  {
232  for (auto cluster_iter = tpcseed->begin_cluster_keys(); cluster_iter != tpcseed->end_cluster_keys(); ++cluster_iter)
233  {
234  const auto &cluster_key = *cluster_iter;
235  const auto trackerID = TrkrDefs::getTrkrId(cluster_key);
236 
237  if (trackerID == TrkrDefs::tpcId)
238  {
239  ++TPC_hits;
240  }
241  }
242  if (TPC_hits < m_nTPCHits)
243  {
244  continue;
245  }
246  }
247 
248  daughterParticles.push_back(makeParticle(topNode));
249  daughterParticles[trackID].SetId(iter.first);
250  ++trackID;
251  }
252 
253  return daughterParticles;
254 }
255 
257 {
258  std::string vtxMN;
259  if (vertexMapName.empty())
260  {
261  vtxMN = m_vtx_map_node_name;
262  }
263  else
264  {
265  vtxMN = vertexMapName;
266  }
267 
268  SvtxVertex *associatedVertex = nullptr;
269  m_dst_vertexmap = findNode::getClass<SvtxVertexMap>(topNode, vtxMN);
270  auto globalvertexmap = findNode::getClass<GlobalVertexMap>(topNode, "GlobalVertexMap");
271  GlobalVertex *associatedgvertex = globalvertexmap->find(vertex.Id())->second;
272  auto svtxvtx_id = associatedgvertex->find_vtxids(GlobalVertex::SVTX)->second;
273  associatedVertex = m_dst_vertexmap->find(svtxvtx_id)->second;
274 
275  return associatedVertex->size_tracks();
276 }
277 
278 /*const*/ bool KFParticle_Tools::isGoodTrack(const KFParticle &particle, const std::vector<KFParticle> &primaryVertices)
279 {
280  bool goodTrack = false;
281 
282  float min_ip = 0;
283  float min_ipchi2 = 0;
284 
285  float pt = particle.GetPt();
286  float pterr = particle.GetErrPt();
287  float ptchi2 = pow(pterr / pt, 2);
288  float trackchi2ndof = particle.GetChi2() / particle.GetNDF();
289  calcMinIP(particle, primaryVertices, min_ip, min_ipchi2);
290 
291  if (pt >= m_track_pt && ptchi2 <= m_track_ptchi2 && min_ip >= m_track_ip && min_ipchi2 >= m_track_ipchi2 && trackchi2ndof <= m_track_chi2ndof)
292  {
293  goodTrack = true;
294  }
295  /*
296  std::cout << "Track pT = " << pt << ", min. track pT = " << m_track_pt << std::endl;
297  std::cout << "Track pTchi2 = " << ptchi2 << ", min. track pTchi2 = " << m_track_ptchi2 << std::endl;
298  std::cout << "Track IP = " << min_ip << ", min. track IP = " << m_track_ip << std::endl;
299  std::cout << "Track IPchi2 = " << min_ipchi2 << ", min. track IPchi2 = " << m_track_ipchi2 << std::endl;
300  std::cout << "Track chi2/nDoF = " << trackchi2ndof << ", max. track chi2/nDoF = " << m_track_chi2ndof << std::endl;
301  std::string track_designation = goodTrack ? "good" : "bad";
302  std::cout << "Track designated as " << track_designation << std::endl;
303  */
304  return goodTrack;
305 }
306 
307 int KFParticle_Tools::calcMinIP(const KFParticle &track, const std::vector<KFParticle> &PVs,
308  float &minimumIP, float &minimumIPchi2)
309 {
310  std::vector<float> ip, ipchi2;
311 
312  for (const auto &PV : PVs)
313  {
314  ip.push_back(track.GetDistanceFromVertex(PV));
315  float thisIPchi2 = track.GetDeviationFromVertex(PV);
316  if (thisIPchi2 < 0)
317  {
318  thisIPchi2 = 0;
319  }
320  ipchi2.push_back(thisIPchi2); //Τhere are times where the IPchi2 calc fails
321  }
322 
323  auto minmax_ip = minmax_element(ip.begin(), ip.end()); // Order the IP from small to large
324  minimumIP = *minmax_ip.first;
325  auto minmax_ipchi2 = minmax_element(ipchi2.begin(), ipchi2.end()); // Order the IP chi2 from small to large
326  minimumIPchi2 = *minmax_ipchi2.first;
327 
328  return 0;
329 }
330 
331 std::vector<int> KFParticle_Tools::findAllGoodTracks(std::vector<KFParticle> daughterParticles, const std::vector<KFParticle> &primaryVertices)
332 {
333  std::vector<int> goodTrackIndex;
334 
335  for (unsigned int i_parts = 0; i_parts < daughterParticles.size(); ++i_parts)
336  {
337  if (isGoodTrack(daughterParticles[i_parts], primaryVertices))
338  {
339  goodTrackIndex.push_back(i_parts);
340  }
341  }
342 
343  removeDuplicates(goodTrackIndex);
344 
345  return goodTrackIndex;
346 }
347 
348 std::vector<std::vector<int>> KFParticle_Tools::findTwoProngs(std::vector<KFParticle> daughterParticles, std::vector<int> goodTrackIndex, int nTracks)
349 {
350  std::vector<std::vector<int>> goodTracksThatMeet;
351 
352  for (std::vector<int>::iterator i_it = goodTrackIndex.begin(); i_it != goodTrackIndex.end(); ++i_it)
353  {
354  for (std::vector<int>::iterator j_it = goodTrackIndex.begin(); j_it != goodTrackIndex.end(); ++j_it)
355  {
356  if (i_it < j_it)
357  {
358  if (daughterParticles[*i_it].GetDistanceFromParticle(daughterParticles[*j_it]) <= m_comb_DCA)
359  {
360  KFVertex twoParticleVertex;
361  twoParticleVertex += daughterParticles[*i_it];
362  twoParticleVertex += daughterParticles[*j_it];
363  float vertexchi2ndof = twoParticleVertex.GetChi2() / twoParticleVertex.GetNDF();
364  std::vector<int> combination = {*i_it, *j_it};
365 
366  if (nTracks == 2 && vertexchi2ndof > m_vertex_chi2ndof)
367  {
368  continue;
369  }
370  else
371  {
372  goodTracksThatMeet.push_back(combination);
373  }
374  }
375  }
376  }
377  }
378 
379  return goodTracksThatMeet;
380 }
381 
382 std::vector<std::vector<int>> KFParticle_Tools::findNProngs(std::vector<KFParticle> daughterParticles,
383  const std::vector<int> &goodTrackIndex,
384  std::vector<std::vector<int>> goodTracksThatMeet,
385  int nRequiredTracks, unsigned int nProngs)
386 {
387  unsigned int nGoodProngs = goodTracksThatMeet.size();
388 
389  for (auto &i_it : goodTrackIndex)
390  {
391  for (unsigned int i_prongs = 0; i_prongs < nGoodProngs; ++i_prongs)
392  {
393  bool trackNotUsedAlready = true;
394  for (unsigned int i_trackCheck = 0; i_trackCheck < nProngs - 1; ++i_trackCheck)
395  {
396  if (i_it == goodTracksThatMeet[i_prongs][i_trackCheck])
397  {
398  trackNotUsedAlready = false;
399  }
400  }
401  if (trackNotUsedAlready)
402  {
403  bool dcaMet = true;
404  for (unsigned int i = 0; i < nProngs - 1; ++i)
405  {
406  if (daughterParticles[i_it].GetDistanceFromParticle(daughterParticles[goodTracksThatMeet[i_prongs][i]]) > m_comb_DCA)
407  {
408  dcaMet = false;
409  }
410  }
411 
412  if (dcaMet)
413  {
414  KFVertex particleVertex;
415  particleVertex += daughterParticles[i_it];
416  std::vector<int> combination;
417  combination.push_back(i_it);
418  for (unsigned int i = 0; i < nProngs - 1; ++i)
419  {
420  particleVertex += daughterParticles[goodTracksThatMeet[i_prongs][i]];
421  combination.push_back(goodTracksThatMeet[i_prongs][i]);
422  }
423  float vertexchi2ndof = particleVertex.GetChi2() / particleVertex.GetNDF();
424 
425  if ((unsigned int) nRequiredTracks == nProngs && vertexchi2ndof > m_vertex_chi2ndof)
426  {
427  continue;
428  }
429  else
430  {
431  goodTracksThatMeet.push_back(combination);
432  }
433  }
434  }
435  }
436  }
437 
438  goodTracksThatMeet.erase(goodTracksThatMeet.begin(), goodTracksThatMeet.begin() + nGoodProngs);
439  for (auto &i : goodTracksThatMeet)
440  {
441  sort(i.begin(), i.end());
442  }
443  removeDuplicates(goodTracksThatMeet);
444 
445  return goodTracksThatMeet;
446 }
447 
448 std::vector<std::vector<int>> KFParticle_Tools::appendTracksToIntermediates(KFParticle intermediateResonances[], std::vector<KFParticle> daughterParticles, const std::vector<int> &goodTrackIndex, int num_remaining_tracks)
449 {
450  std::vector<std::vector<int>> goodTracksThatMeet, goodTracksThatMeetIntermediates; //, vectorOfGoodTracks;
451  if (num_remaining_tracks == 1)
452  {
453  for (auto &i_it : goodTrackIndex)
454  {
455  std::vector<KFParticle> v_intermediateResonances(intermediateResonances, intermediateResonances + m_num_intermediate_states);
456  std::vector<std::vector<int>> dummyTrackList;
457  std::vector<int> dummyTrackID; // I already have the track ids stored in goodTracksThatMeet[i]
458  v_intermediateResonances.insert(end(v_intermediateResonances), daughterParticles[i_it]);
459  for (unsigned int k = 0; k < v_intermediateResonances.size(); ++k)
460  {
461  dummyTrackID.push_back(k);
462  }
463  dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size());
464  if (v_intermediateResonances.size() > 2)
465  {
466  for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p)
467  {
468  dummyTrackList = findNProngs(v_intermediateResonances,
469  dummyTrackID, dummyTrackList,
470  (int) v_intermediateResonances.size(), (int) p);
471  }
472  }
473 
474  if (dummyTrackList.size() != 0)
475  {
476  std::vector<int> goodTrack{i_it};
477  goodTracksThatMeetIntermediates.push_back(goodTrack);
478  }
479  }
480  }
481  else
482  {
483  goodTracksThatMeet = findTwoProngs(daughterParticles, goodTrackIndex, num_remaining_tracks);
484 
485  for (int p = 3; p <= num_remaining_tracks; ++p)
486  {
487  goodTracksThatMeet = findNProngs(daughterParticles, goodTrackIndex, goodTracksThatMeet, num_remaining_tracks, p);
488  }
489 
490  for (auto &i : goodTracksThatMeet)
491  {
492  std::vector<KFParticle> v_intermediateResonances(intermediateResonances, intermediateResonances + m_num_intermediate_states);
493  std::vector<std::vector<int>> dummyTrackList;
494  std::vector<int> dummyTrackID; // I already have the track ids stored in goodTracksThatMeet[i]
495  for (int j : i)
496  {
497  v_intermediateResonances.push_back(daughterParticles[i[j]]);
498  }
499  for (unsigned int k = 0; k < v_intermediateResonances.size(); ++k)
500  {
501  dummyTrackID.push_back(k);
502  }
503  dummyTrackList = findTwoProngs(v_intermediateResonances, dummyTrackID, (int) v_intermediateResonances.size());
504  for (unsigned int p = 3; p <= v_intermediateResonances.size(); ++p)
505  {
506  dummyTrackList = findNProngs(v_intermediateResonances, dummyTrackID, dummyTrackList, (int) v_intermediateResonances.size(), (int) p);
507  }
508 
509  if (dummyTrackList.size() != 0)
510  {
511  goodTracksThatMeetIntermediates.push_back(i);
512  }
513  }
514  }
515 
516  return goodTracksThatMeetIntermediates;
517 }
518 
520 {
521  TMatrixD flightVector(3, 1);
522  TMatrixD momVector(3, 1);
523  flightVector(0, 0) = particle.GetX() - vertex.GetX();
524  flightVector(1, 0) = particle.GetY() - vertex.GetY();
525  flightVector(2, 0) = particle.GetZ() - vertex.GetZ();
526 
527  momVector(0, 0) = particle.GetPx();
528  momVector(1, 0) = particle.GetPy();
529  momVector(2, 0) = particle.GetPz();
530 
531  TMatrixD momDotFD(1, 1); // Calculate momentum dot flight distance
532  momDotFD = TMatrixD(momVector, TMatrixD::kTransposeMult, flightVector);
533  float f_momDotFD = momDotFD(0, 0);
534 
535  TMatrixD sizeOfMom(1, 1); // Calculates the size of the momentum vector
536  sizeOfMom = TMatrixD(momVector, TMatrixD::kTransposeMult, momVector);
537  float f_sizeOfMom = sqrt(sizeOfMom(0, 0));
538 
539  TMatrixD sizeOfFD(1, 1); // Calculates the size of the flight distance vector
540  sizeOfFD = TMatrixD(flightVector, TMatrixD::kTransposeMult, flightVector);
541  float f_sizeOfFD = sqrt(sizeOfFD(0, 0));
542 
543  return f_momDotFD / (f_sizeOfMom * f_sizeOfFD);
544 }
545 
547 {
548  TMatrixD flightVector(3, 1);
549  TMatrixD flightDistanceCovariance(3, 3);
550 
551  const KFParticle &kfp_vertex(vertex);
552 
553  flightVector(0, 0) = particle.GetX() - kfp_vertex.GetX();
554  flightVector(1, 0) = particle.GetY() - kfp_vertex.GetY();
555  flightVector(2, 0) = particle.GetZ() - kfp_vertex.GetZ();
556 
557  for (int i = 0; i < 3; i++)
558  {
559  for (int j = 0; j < 3; j++)
560  {
561  flightDistanceCovariance(i, j) = particle.GetCovariance(i, j) + kfp_vertex.GetCovariance(i, j);
562  }
563  }
564 
565  TMatrixD anInverseMatrix(3, 3);
566  anInverseMatrix = flightDistanceCovariance.Invert();
567  TMatrixD m_chi2Value(1, 1);
568  m_chi2Value = TMatrixD(flightVector, TMatrixD::kTransposeMult, anInverseMatrix * flightVector);
569  return m_chi2Value(0, 0);
570 }
571 
572 std::tuple<KFParticle, bool> KFParticle_Tools::buildMother(KFParticle vDaughters[], std::string daughterOrder[],
573  bool isIntermediate, int intermediateNumber, int nTracks,
574  bool constrainMass, float required_vertexID)
575 {
576  KFParticle mother;
577  KFParticle inputTracks[nTracks];
578 
579  mother.SetConstructMethod(2);
580 
581  bool daughterMassCheck = true;
582  float unique_vertexID = 0;
583 
584  // Figure out if the decay has reco. tracks mixed with resonances
585  int num_tracks_used_by_intermediates = 0;
586  for (int i = 0; i < m_num_intermediate_states; ++i)
587  {
588  num_tracks_used_by_intermediates += m_num_tracks_from_intermediate[i];
589  }
590  int num_remaining_tracks = m_num_tracks - num_tracks_used_by_intermediates;
591 
592  for (int i = 0; i < nTracks; ++i)
593  {
594  float daughterMass = 0;
595  daughterMass = constrainMass ? getParticleMass(daughterOrder[i].c_str()) : vDaughters[i].GetMass();
596  if ((num_remaining_tracks > 0 && i >= m_num_intermediate_states) || isIntermediate)
597  {
598  daughterMass = getParticleMass(daughterOrder[i].c_str());
599  }
600  inputTracks[i].Create(vDaughters[i].Parameters(),
601  vDaughters[i].CovarianceMatrix(),
602  (Int_t) vDaughters[i].GetQ(),
603  daughterMass);
604  mother.AddDaughter(inputTracks[i]);
605  unique_vertexID += vDaughters[i].GetQ() * getParticleMass(daughterOrder[i].c_str());
606  }
607 
608  if (isIntermediate)
609  {
610  mother.SetPDG(getParticleID(m_intermediate_name[intermediateNumber].c_str()));
611  }
612  if (!isIntermediate && !m_mother_name_Tools.empty())
613  {
615  }
616 
617  bool chargeCheck;
619  {
620  chargeCheck = std::abs(unique_vertexID) == std::abs(required_vertexID) ? true : false;
621  }
622  else
623  {
624  chargeCheck = unique_vertexID == required_vertexID ? true : false;
625  }
626 
627  for (int j = 0; j < nTracks; ++j)
628  {
630  {
631  inputTracks[j].SetProductionVertex(mother);
632  }
634  {
635  if (inputTracks[j].GetMass() == 0)
636  {
637  daughterMassCheck = false;
638  }
639  }
640  }
641 
642  float calculated_mass, calculated_mass_err;
643  mother.GetMass(calculated_mass, calculated_mass_err);
644  float calculated_pt = mother.GetPt();
645 
646  float min_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].first : m_min_mass;
647  float max_mass = isIntermediate ? m_intermediate_mass_range[intermediateNumber].second : m_max_mass;
648  float min_pt = isIntermediate ? m_intermediate_min_pt[intermediateNumber] : m_mother_pt;
649 
650  float max_vertex_volume = isIntermediate ? m_intermediate_vertex_volume[intermediateNumber] : m_mother_vertex_volume;
651 
652  bool goodCandidate = false;
653  if (calculated_mass >= min_mass && calculated_mass <= max_mass &&
654  calculated_pt >= min_pt && daughterMassCheck && chargeCheck && calculateEllipsoidVolume(mother) <= max_vertex_volume)
655  {
656  goodCandidate = true;
657  }
658 
659  // Check the requirements of an intermediate states against this mother and re-do goodCandidate
660  if (goodCandidate && m_has_intermediates && !isIntermediate) // The decay has intermediate states and we are now looking at the mother
661  {
662  for (int k = 0; k < m_num_intermediate_states; ++k)
663  {
664  float intermediate_DIRA = eventDIRA(vDaughters[k], mother);
665  float intermediate_FDchi2 = flightDistanceChi2(vDaughters[k], mother);
666  if (intermediate_DIRA < m_intermediate_min_dira[k] ||
667  intermediate_FDchi2 < m_intermediate_min_fdchi2[k])
668  {
669  goodCandidate = false;
670  }
671  }
672  }
673 
674  return std::make_tuple(mother, goodCandidate);
675 }
676 
678 {
679  KFParticle particleCopy = particle;
680  particleCopy.SetProductionVertex(vertex);
681  particleCopy.TransportToDecayVertex();
682 
683  float calculated_decayTime;
684  float calculated_decayTimeErr;
685  float calculated_decayLength;
686  float calculated_decayLengthErr;
687 
688  particleCopy.GetLifeTime(calculated_decayTime, calculated_decayTimeErr);
689  particleCopy.GetDecayLength(calculated_decayLength, calculated_decayLengthErr);
690 
691  float calculated_fdchi2 = flightDistanceChi2(particle, vertex);
692  float calculated_dira = eventDIRA(particle, vertex);
693  float calculated_ipchi2 = particle.GetDeviationFromVertex(vertex);
694 
695  goodCandidate = false;
696 
697  const float speed = 2.99792458e-2;
698  calculated_decayTime /= speed;
699 
700  if (calculated_fdchi2 >= m_fdchi2 && calculated_ipchi2 <= m_mother_ipchi2 && isInRange(m_dira_min, calculated_dira, m_dira_max) && isInRange(m_min_decayTime, calculated_decayTime, m_max_decayTime) && isInRange(m_min_decayLength, calculated_decayLength, m_max_decayLength))
701  {
702  goodCandidate = true;
703  }
704 }
705 
706 std::tuple<KFParticle, bool> KFParticle_Tools::getCombination(KFParticle vDaughters[], std::string daughterOrder[], KFParticle vertex, bool constrain_to_vertex, bool isIntermediate, int intermediateNumber, int nTracks, bool constrainMass, float required_vertexID)
707 {
708  KFParticle candidate;
709  bool isGoodCandidate;
710 
711  std::tie(candidate, isGoodCandidate) = buildMother(vDaughters, daughterOrder, isIntermediate, intermediateNumber, nTracks, constrainMass, required_vertexID);
712 
713  if (constrain_to_vertex && isGoodCandidate && !isIntermediate)
714  {
715  constrainToVertex(candidate, isGoodCandidate, vertex);
716  }
717 
718  return std::make_tuple(candidate, isGoodCandidate);
719 }
720 
721 std::vector<std::vector<std::string>> KFParticle_Tools::findUniqueDaughterCombinations(int start, int end)
722 {
723  std::vector<int> vect_permutations;
724  std::vector<std::vector<std::string>> uniqueCombinations;
725  std::map<int, std::string> daughterMap;
726  for (int i = start; i < end; i++)
727  {
728  daughterMap.insert(std::pair<int, std::string>(i, m_daughter_name[i]));
729  vect_permutations.push_back(i);
730  }
731  int *permutations = &vect_permutations[0];
732 
733  do
734  {
735  std::vector<std::string> combination;
736  combination.reserve((end - start));
737  for (int i = 0; i < (end - start); i++)
738  {
739  combination.push_back(daughterMap.find(permutations[i])->second);
740  }
741  uniqueCombinations.push_back(combination);
742  } while (std::next_permutation(permutations, permutations + vect_permutations.size()));
743 
744  removeDuplicates(uniqueCombinations);
745 
746  return uniqueCombinations;
747 }
748 
749 double KFParticle_Tools::calculateEllipsoidRadius(int posOrNeg, double sigma_ii, double sigma_jj, double sigma_ij)
750 { // Note - Only works for a 2D ellipsoid OR rotated nD ellipsoid to avoid projections
751  if (std::abs(posOrNeg) != 1)
752  {
753  std::cout << "You have set posOrNeg to " << posOrNeg << ". This value must be +/- 1! Skipping" << std::endl;
754  return 0;
755  }
756 
757  double r_ij = sqrt((sigma_ii + sigma_jj) / 2 + posOrNeg * (sqrt(pow((sigma_ii - sigma_jj) / 2, 2) + pow(sigma_ij, 2))));
758 
759  return r_ij;
760 }
761 
763 {
764  TMatrixD cov_matrix(3, 3);
765 
766  for (int i = 0; i < 3; ++i)
767  {
768  for (int j = 0; j < 3; ++j)
769  {
770  cov_matrix(i, j) = particle.GetCovariance(i, j);
771  }
772  }
773 
774  float volume;
775  if (cov_matrix(0, 0) * cov_matrix(1, 1) * cov_matrix(2, 2) == 0)
776  {
777  volume = 0;
778  }
779  else
780  {
781  volume = (4. / 3.) * M_PI * sqrt((std::abs(cov_matrix.Determinant()))); // The covariance matrix is error-squared
782  }
783 
784  return volume;
785 }
786 
787 float KFParticle_Tools::calculateJT(const KFParticle &mother, const KFParticle &daughter)
788 {
789  Eigen::Vector3f motherP = Eigen::Vector3f(mother.GetPx(), mother.GetPy(), mother.GetPz());
790  Eigen::Vector3f daughterP = Eigen::Vector3f(daughter.GetPx(), daughter.GetPy(), daughter.GetPz());
791 
792  Eigen::Vector3f motherP_X_daughterP = motherP.cross(daughterP);
793 
794  float jT = (motherP_X_daughterP.norm()) / motherP.norm();
795 
796  return jT;
797 }
798 
799 bool KFParticle_Tools::isInRange(float min, float value, float max)
800 {
801  return min <= value && value <= max;
802 }
803 
804 void KFParticle_Tools::removeDuplicates(std::vector<double> &v)
805 {
806  auto end = v.end();
807  for (auto it = v.begin(); it != end; ++it)
808  {
809  end = remove(it + 1, end, *it);
810  }
811  v.erase(end, v.end());
812 }
813 
814 void KFParticle_Tools::removeDuplicates(std::vector<int> &v)
815 {
816  auto end = v.end();
817  for (auto it = v.begin(); it != end; ++it)
818  {
819  end = remove(it + 1, end, *it);
820  }
821  v.erase(end, v.end());
822 }
823 
824 void KFParticle_Tools::removeDuplicates(std::vector<std::vector<int>> &v)
825 {
826  auto end = v.end();
827  for (auto it = v.begin(); it != end; ++it)
828  {
829  end = remove(it + 1, end, *it);
830  }
831  v.erase(end, v.end());
832 }
833 
834 void KFParticle_Tools::removeDuplicates(std::vector<std::vector<std::string>> &v)
835 {
836  auto end = v.end();
837  for (auto it = v.begin(); it != end; ++it)
838  {
839  end = remove(it + 1, end, *it);
840  }
841  v.erase(end, v.end());
842 }
843 
845 {
846  bool particleFound = true;
847  if (!TDatabasePDG::Instance()->GetParticle(particle.c_str()))
848  {
849  std::cout << "The particle, " << particle << " is not recognized" << std::endl;
850  std::cout << "Check TDatabasePDG for a list of available particles" << std::endl;
851  particleFound = false;
852  }
853 
854  return particleFound;
855 }
856 
858 {
859  return TDatabasePDG::Instance()->GetParticle(particle.c_str())->PdgCode();
860 }
861 
863 {
864  return TDatabasePDG::Instance()->GetParticle(particle.c_str())->Mass();
865 }
866 
867 float KFParticle_Tools::getParticleMass(const int PDGID)
868 {
869  return TDatabasePDG::Instance()->GetParticle(PDGID)->Mass();
870 }
871 
873 {
874  std::cout << "Track ID: " << particle.Id() << std::endl;
875  std::cout << "PDG ID: " << particle.GetPDG() << ", charge: " << (int) particle.GetQ() << ", mass: " << particle.GetMass() << " GeV" << std::endl;
876  std::cout << "(px,py,pz) = (" << particle.GetPx() << " +/- " << std::sqrt(particle.GetCovariance(3, 3)) << ", ";
877  std::cout << particle.GetPy() << " +/- " << std::sqrt(particle.GetCovariance(4, 4)) << ", ";
878  std::cout << particle.GetPz() << " +/- " << std::sqrt(particle.GetCovariance(5, 5)) << ") GeV" << std::endl;
879  std::cout << "(x,y,z) = (" << particle.GetX() << " +/- " << std::sqrt(particle.GetCovariance(0, 0)) << ", ";
880  std::cout << particle.GetY() << " +/- " << std::sqrt(particle.GetCovariance(1, 1)) << ", ";
881  std::cout << particle.GetZ() << " +/- " << std::sqrt(particle.GetCovariance(2, 2)) << ") cm\n"
882  << std::endl;
883 }