Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HFTrackEfficiency.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file HFTrackEfficiency.cc
1 #include "HFTrackEfficiency.h"
2 
3 //____________________________________________________________________________..
5  : SubsysReco(name)
6  , m_triggerOnDecay(false)
7  , m_input_track_map_node_name("SvtxTrackMap")
8  , m_output_track_map_node_name("HFSelected")
9  , m_write_track_map(false)
10  , m_outfile_name("outputHFTrackEff.root")
11  , m_outfile(nullptr)
12  , m_tree(nullptr)
13  , m_write_nTuple(false)
14  , m_truthRecoMatchPercent(5.)
15  , m_nDaughters(2)
16 {
17 }
18 
19 //____________________________________________________________________________..
21 
22 //____________________________________________________________________________..
24 {
26 
28  {
29  PHNodeIterator nodeIter(topNode);
30 
31  PHCompositeNode *dstNode = dynamic_cast<PHCompositeNode *>(nodeIter.findFirst("PHCompositeNode", "DST"));
32  if (!dstNode)
33  {
34  dstNode = new PHCompositeNode("DST");
35  topNode->addNode(dstNode);
36  std::cout << "DST node added" << std::endl;
37  }
38 
39  outputNodeName = m_output_track_map_node_name + "_SvtxTrackMap";
41  PHIODataNode<PHObject> *outputTrackNode = new PHIODataNode<PHObject>(m_output_trackMap, outputNodeName.c_str(), "PHObject");
42  dstNode->addNode(outputTrackNode);
43  std::cout << outputNodeName << " node added" << std::endl;
44  }
45 
47 }
48 
49 //____________________________________________________________________________..
51 {
52  PHNodeIterator nodeIter(topNode);
53  PHCompositeNode *dstNode = static_cast<PHCompositeNode *>(nodeIter.findFirst("PHCompositeNode", "DST"));
54  assert(dstNode);
55 
56  std::string df_node_name = m_df_module_name + "_DecayMap";
57  m_decayMap = findNode::getClass<DecayFinderContainer_v1>(topNode, df_node_name.c_str());
58  if (!m_decayMap)
59  {
60  std::cout << __FILE__ << ": Missing node " << df_node_name << std::endl;
62  }
63 
64  m_input_trackMap = findNode::getClass<SvtxTrackMap>(topNode, m_input_track_map_node_name.c_str());
65  if (!m_input_trackMap)
66  {
67  std::cout << __FILE__ << ": Missing node " << m_input_track_map_node_name << std::endl;
69  }
70 
71  m_geneventmap = findNode::getClass<PHHepMCGenEventMap>(topNode, "PHHepMCGenEventMap");
72  if (!m_geneventmap)
73  {
74  std::cout << __FILE__ << ": Missing node PHHepMCGenEventMap" << std::endl;
75  }
76 
77  m_truthInfo = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
78  if (!m_truthInfo)
79  {
80  if (Verbosity() >= VERBOSITY_MORE)
81  {
82  std::cout << __FILE__ << ": Missing node G4TruthInfo" << std::endl;
83  }
84  }
85 
86  m_dst_truth_reco_map = findNode::getClass<PHG4ParticleSvtxMap_v1>(topNode, "PHG4ParticleSvtxMap");
88  {
89  if (Verbosity() >= VERBOSITY_MORE)
90  {
91  std::cout << __FILE__ << ": PHG4ParticleSvtxMap found, truth matching will be more accurate" << std::endl;
92  }
93  }
94  else
95  {
96  if (Verbosity() >= VERBOSITY_MORE)
97  {
98  std::cout << __FILE__ << ": PHG4ParticleSvtxMap not found, reverting to true matching by momentum relations. Truth matching will be less accurate" << std::endl;
99  }
100  }
101 
102  if (m_decay_descriptor.empty() && !m_decayMap->empty())
103  {
105  getNDaughters();
106  }
107 
108  bool reconstructableDecay = false;
109  for (auto &iter : *m_decayMap)
110  {
111  Decay decay = iter.second;
113 
114  m_all_tracks_reconstructed = findTracks(topNode, decay);
116  {
118  reconstructableDecay = true;
119  }
120 
121  if (m_write_nTuple)
122  {
123  if (m_counter_allDecays == 1)
124  {
126  }
127  m_tree->Fill();
128  resetBranches();
129  }
130  }
131 
132  if (m_triggerOnDecay && !reconstructableDecay)
133  {
134  if (Verbosity() >= VERBOSITY_MORE)
135  {
136  std::cout << "No decays were reconstructable in this event, skipping" << std::endl;
137  }
139  }
140  else
141  {
143  }
144 }
145 
147 {
148  PrintEff();
149 
151  {
152  m_outfile->Write();
153  m_outfile->Close();
154  delete m_outfile;
155  }
156 
158 }
159 
161 {
162  int trackableParticles[] = {11, 13, 211, 321, 2212};
163  bool recoTrackFound = false;
164  std::set<SvtxTrack *> selectedTracks;
165 
166  CLHEP::HepLorentzVector motherRecoLV;
167  CLHEP::HepLorentzVector daughterSumTrueLV;
168  CLHEP::HepLorentzVector *motherTrueLV = new CLHEP::HepLorentzVector();
169  CLHEP::HepLorentzVector *daughterTrueLV = new CLHEP::HepLorentzVector();
170 
171  HepMC::GenEvent *theEvent = nullptr;
172  if (m_geneventmap)
173  {
174  m_genevt = m_geneventmap->get(decay[0].first.first);
175  assert(m_genevt);
176 
177  theEvent = m_genevt->getEvent();
178  HepMC::GenParticle *mother = theEvent->barcode_to_particle(decay[0].first.second);
179  assert(mother);
180  if (Verbosity() >= VERBOSITY_MORE)
181  {
182  mother->print();
183  }
184 
185  m_true_mother_pT = mother->momentum().perp();
186  m_true_mother_p = std::sqrt(std::pow(mother->momentum().px(), 2) + std::pow(mother->momentum().py(), 2) + std::pow(mother->momentum().pz(), 2)); // Must have an old HepMC build, no mag function
187  m_true_mother_eta = mother->momentum().eta();
188 
189  HepMC::GenVertex *thisVtx = mother->production_vertex();
190  m_primary_vtx_x = thisVtx->point3d().x();
191  m_primary_vtx_y = thisVtx->point3d().y();
192  m_primary_vtx_z = thisVtx->point3d().z();
193  }
194 
195  for (unsigned int i = 1; i < decay.size(); ++i)
196  {
197  m_dst_track = nullptr;
198  int truth_ID = -1;
199  if (std::find(std::begin(trackableParticles), std::end(trackableParticles),
200  std::abs(decay[i].second)) != std::end(trackableParticles))
201  {
202  if (theEvent && decay[i].first.second > -1)
203  {
204  HepMC::GenParticle *daughterHepMC = theEvent->barcode_to_particle(decay[i].first.second);
205  if (Verbosity() >= VERBOSITY_MORE)
206  {
207  daughterHepMC->print();
208  }
209 
210  daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterHepMC->momentum().px(), daughterHepMC->momentum().py(), daughterHepMC->momentum().pz()), getParticleMass(decay[i].second));
211  daughterSumTrueLV += *daughterTrueLV;
212 
213  m_true_track_PID[i - 1] = daughterHepMC->pdg_id();
214 
215  // Now get the decay vertex position
216  HepMC::GenVertex *thisVtx = daughterHepMC->production_vertex();
217  m_secondary_vtx_x = thisVtx->point3d().x();
218  m_secondary_vtx_y = thisVtx->point3d().y();
219  m_secondary_vtx_z = thisVtx->point3d().z();
220 
221  // We need the G4 ID, not the HepMC ID to use the truth/reco map
223  {
225 
226  for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter)
227  {
228  PHG4Particle *daughterG4 = iter->second;
229 
230  if (abs(daughterG4->get_px() - daughterTrueLV->x()) <= 5e-3 &&
231  abs(daughterG4->get_py() - daughterTrueLV->y()) <= 5e-3 &&
232  abs(daughterG4->get_pz() - daughterTrueLV->z()) <= 5e-3 && daughterG4->get_pid() == decay[i].second)
233  {
234  truth_ID = daughterG4->get_track_id();
235  break;
236  }
237  }
238  }
239  }
240  else
241  {
243 
244  for (PHG4TruthInfoContainer::ConstIterator iter = range.first; iter != range.second; ++iter)
245  {
246  PHG4Particle *daughterG4 = iter->second;
247 
248  PHG4Particle *motherG4 = nullptr;
249  if (daughterG4->get_parent_id() != 0)
250  {
251  motherG4 = m_truthInfo->GetParticle(daughterG4->get_parent_id());
252  }
253  else
254  {
255  continue;
256  }
257 
258  if (motherG4->get_pid() == decay[0].second && motherG4->get_barcode() == decay[0].first.second && daughterG4->get_pid() == decay[i].second && daughterG4->get_barcode() == decay[i].first.second)
259  {
260  if (Verbosity() >= VERBOSITY_MORE)
261  {
262  daughterG4->identify();
263  }
264 
265  CLHEP::Hep3Vector *mother3Vector = new CLHEP::Hep3Vector(motherG4->get_px(), motherG4->get_py(), motherG4->get_pz());
266  motherTrueLV->setVectM((*mother3Vector), getParticleMass(decay[0].second));
267  m_true_mother_pT = motherTrueLV->perp();
268  m_true_mother_p = mother3Vector->mag();
269  m_true_mother_eta = motherTrueLV->pseudoRapidity();
270 
271  PHG4VtxPoint *thisVtx = m_truthInfo->GetVtx(motherG4->get_vtx_id());
272  m_primary_vtx_x = thisVtx->get_x();
273  m_primary_vtx_y = thisVtx->get_y();
274  m_primary_vtx_z = thisVtx->get_z();
275 
276  daughterTrueLV->setVectM(CLHEP::Hep3Vector(daughterG4->get_px(), daughterG4->get_py(), daughterG4->get_pz()), getParticleMass(decay[i].second));
277  daughterSumTrueLV += *daughterTrueLV;
278 
279  // Now get the decay vertex position
280  thisVtx = m_truthInfo->GetVtx(daughterG4->get_vtx_id());
281  m_secondary_vtx_x = thisVtx->get_x();
282  m_secondary_vtx_y = thisVtx->get_y();
283  m_secondary_vtx_z = thisVtx->get_z();
284 
285  m_true_track_PID[i - 1] = daughterG4->get_pid();
286  truth_ID = daughterG4->get_track_id();
287 
288  delete mother3Vector;
289  }
290  }
291  }
292 
293  m_true_track_pT[i - 1] = (float) daughterTrueLV->perp();
294  m_true_track_eta[i - 1] = (float) daughterTrueLV->pseudoRapidity();
297 
298  if (m_dst_truth_reco_map && truth_ID >= 0)
299  {
300  std::map<float, std::set<unsigned int>> reco_set = m_dst_truth_reco_map->get(truth_ID);
301  if (reco_set.size() == 0)
302  {
303  continue;
304  }
305  const auto &best_weight = reco_set.rbegin();
306  if (best_weight->second.size() == 0)
307  {
308  continue;
309  }
310  unsigned int best_reco_id = *best_weight->second.rbegin();
311  m_dst_track = m_input_trackMap->get(best_reco_id);
312  if (m_dst_track)
313  {
314  m_used_truth_reco_map[i - 1] = true;
315  recoTrackFound = true;
316  }
317  }
318  else
319  {
320  for (auto &iter : *m_input_trackMap)
321  {
322  m_dst_track = iter.second;
323  float delta_px = (m_dst_track->get_px() - daughterTrueLV->px()) / daughterTrueLV->px();
324  float delta_py = (m_dst_track->get_py() - daughterTrueLV->py()) / daughterTrueLV->py();
325  float delta_pz = (m_dst_track->get_pz() - daughterTrueLV->pz()) / daughterTrueLV->pz();
326 
327  if (std::abs(delta_px) <= m_truthRecoMatchPercent && std::abs(delta_py) <= m_truthRecoMatchPercent && std::abs(delta_pz) <= m_truthRecoMatchPercent)
328  {
329  recoTrackFound = true;
330  break;
331  }
332  }
333  }
334 
335  if (recoTrackFound)
336  {
337  selectedTracks.insert(m_dst_track);
338  if (Verbosity() >= VERBOSITY_MORE)
339  {
341  }
342  m_reco_track_exists[i - 1] = true;
347  {
349  }
350  else
351  {
352  m_reco_track_silicon_seeds[i - 1] = 0;
353  }
354  m_reco_track_tpc_seeds[i - 1] = static_cast<int>(m_dst_track->get_tpc_seed()->size_cluster_keys());
357 
358  CLHEP::HepLorentzVector *daughterRecoLV = new CLHEP::HepLorentzVector();
359  daughterRecoLV->setVectM(CLHEP::Hep3Vector(m_dst_track->get_px(), m_dst_track->get_py(), m_dst_track->get_pz()), getParticleMass(m_true_track_PID[i - 1]));
360 
361  motherRecoLV += *daughterRecoLV;
362  delete daughterRecoLV;
363  }
364 
365  recoTrackFound = false;
366  }
367  }
368 
369  m_true_mother_mass = daughterSumTrueLV.m();
370  bool foundDecay = true;
371  if (selectedTracks.size() == m_nDaughters)
372  {
373  m_reco_mother_mass = motherRecoLV.m();
374  if (m_write_track_map)
375  {
376  m_output_trackMap = findNode::getClass<SvtxTrackMap>(topNode, outputNodeName.c_str());
377  for (auto &track : selectedTracks)
378  {
379  m_output_trackMap->insertWithKey(track, track->get_id());
380  }
381  }
382  }
383  else
384  {
385  foundDecay = false;
386  }
387 
388  selectedTracks.clear();
389 
390  delete motherTrueLV;
391  delete daughterTrueLV;
392 
393  return foundDecay;
394 }
395 
397 {
398  m_outfile = new TFile(m_outfile_name.c_str(), "RECREATE");
399  m_tree = new TTree("HFTrackEfficiency", "HFTrackEfficiency");
400  m_tree->OptimizeBaskets();
401  m_tree->SetAutoSave(-5e6); // Save the output file every 5MB
402 
403  m_tree->Branch("all_tracks_reconstructed", &m_all_tracks_reconstructed, "all_tracks_reconstructed/O");
404  m_tree->Branch("true_mother_mass", &m_true_mother_mass, "true_mother_mass/F");
405  m_tree->Branch("reco_mother_mass", &m_reco_mother_mass, "reco_mother_mass/F");
406  m_tree->Branch("true_mother_pT", &m_true_mother_pT, "true_mother_pT/F");
407  m_tree->Branch("true_mother_p", &m_true_mother_p, "true_mother_p/F");
408  m_tree->Branch("true_mother_eta", &m_true_mother_eta, "true_mother_eta/F");
409  m_tree->Branch("min_true_track_pT", &m_min_true_track_pT, "min_true_track_pT/F");
410  m_tree->Branch("min_reco_track_pT", &m_min_reco_track_pT, "min_reco_track_pT/F");
411  m_tree->Branch("max_true_track_pT", &m_max_true_track_pT, "max_true_track_pT/F");
412  m_tree->Branch("max_reco_track_pT", &m_max_reco_track_pT, "max_reco_track_pT/F");
413 
414  for (unsigned int iTrack = 0; iTrack < m_nDaughters; ++iTrack)
415  {
416  std::string daughter_number = "track_" + std::to_string(iTrack + 1);
417  m_tree->Branch("reco_" + TString(daughter_number) + "_exists", &m_reco_track_exists[iTrack], "reco_" + TString(daughter_number) + "_exists/O");
418  m_tree->Branch("reco_" + TString(daughter_number) + "_used_truth_reco_map", &m_used_truth_reco_map[iTrack], "reco_" + TString(daughter_number) + "_used_truth_reco_map/O");
419  m_tree->Branch("true_" + TString(daughter_number) + "_pT", &m_true_track_pT[iTrack], "true_" + TString(daughter_number) + "_pT/F");
420  m_tree->Branch("reco_" + TString(daughter_number) + "_pT", &m_reco_track_pT[iTrack], "reco_" + TString(daughter_number) + "_pT/F");
421  m_tree->Branch("true_" + TString(daughter_number) + "_eta", &m_true_track_eta[iTrack], "true_" + TString(daughter_number) + "_eta/F");
422  m_tree->Branch("reco_" + TString(daughter_number) + "_eta", &m_reco_track_eta[iTrack], "reco_" + TString(daughter_number) + "_eta/F");
423  m_tree->Branch("true_" + TString(daughter_number) + "_PID", &m_true_track_PID[iTrack], "true_" + TString(daughter_number) + "_PID/F");
424  m_tree->Branch("reco_" + TString(daughter_number) + "_chi2nDoF", &m_reco_track_chi2nDoF[iTrack], "reco_" + TString(daughter_number) + "_chi2nDoF/F");
425  m_tree->Branch("reco_" + TString(daughter_number) + "_silicon_seeds", &m_reco_track_silicon_seeds[iTrack], "reco_" + TString(daughter_number) + "_silicon_seeds/I");
426  m_tree->Branch("reco_" + TString(daughter_number) + "_tpc_seeds", &m_reco_track_tpc_seeds[iTrack], "reco_" + TString(daughter_number) + "_tpc_seeds/I");
427  }
428 
429  m_tree->Branch("true_primary_vertex_x", &m_primary_vtx_x, "true_primary_vertex_x/F");
430  m_tree->Branch("true_primary_vertex_y", &m_primary_vtx_y, "true_primary_vertex_y/F");
431  m_tree->Branch("true_primary_vertex_z", &m_primary_vtx_z, "true_primary_vertex_z/F");
432  m_tree->Branch("true_secondary_vertex_x", &m_secondary_vtx_x, "true_secondary_vertex_x/F");
433  m_tree->Branch("true_secondary_vertex_y", &m_secondary_vtx_y, "true_secondary_vertex_y/F");
434  m_tree->Branch("true_secondary_vertex_z", &m_secondary_vtx_z, "true_secondary_vertex_z/F");
435 }
436 
438 {
440  m_true_mother_mass = std::numeric_limits<float>::quiet_NaN();
441  m_reco_mother_mass = std::numeric_limits<float>::quiet_NaN();
442  m_true_mother_pT = std::numeric_limits<float>::quiet_NaN();
443  m_true_mother_p = std::numeric_limits<float>::quiet_NaN();
444  m_true_mother_eta = std::numeric_limits<float>::quiet_NaN();
445  m_min_true_track_pT = std::numeric_limits<float>::max();
446  m_min_reco_track_pT = std::numeric_limits<float>::max();
447  m_max_true_track_pT = -1 * std::numeric_limits<float>::max();
448  m_max_reco_track_pT = -1 * std::numeric_limits<float>::max();
449  for (unsigned int iTrack = 0; iTrack < m_nDaughters; ++iTrack)
450  {
451  m_reco_track_exists[iTrack] = false;
452  m_used_truth_reco_map[iTrack] = false;
453  m_true_track_pT[iTrack] = std::numeric_limits<float>::quiet_NaN();
454  m_reco_track_pT[iTrack] = std::numeric_limits<float>::quiet_NaN();
455  m_true_track_eta[iTrack] = std::numeric_limits<float>::quiet_NaN();
456  m_reco_track_eta[iTrack] = std::numeric_limits<float>::quiet_NaN();
457  m_true_track_PID[iTrack] = std::numeric_limits<float>::quiet_NaN();
458  m_reco_track_chi2nDoF[iTrack] = std::numeric_limits<float>::quiet_NaN();
459  m_reco_track_silicon_seeds[iTrack] = 0;
460  m_reco_track_tpc_seeds[iTrack] = 0;
461  }
462 
463  m_primary_vtx_x = std::numeric_limits<float>::quiet_NaN();
464  m_primary_vtx_y = std::numeric_limits<float>::quiet_NaN();
465  m_primary_vtx_z = std::numeric_limits<float>::quiet_NaN();
466  m_secondary_vtx_x = std::numeric_limits<float>::quiet_NaN();
467  m_secondary_vtx_y = std::numeric_limits<float>::quiet_NaN();
468  m_secondary_vtx_z = std::numeric_limits<float>::quiet_NaN();
469 }
470 
472 {
473  Decay decay = m_decayMap->begin()->second;
474  m_decay_descriptor = getParticleName(decay[0].second);
475  m_decay_descriptor += " ->";
476  for (unsigned int i = 1; i < decay.size(); ++i)
477  {
478  m_decay_descriptor += " ";
479  m_decay_descriptor += getParticleName(decay[i].second);
480  }
481 }
482 
484 {
485  int trackableParticles[] = {11, 13, 211, 321, 2212};
486  m_nDaughters = 0;
487  Decay decay = m_decayMap->begin()->second;
488  for (unsigned int i = 1; i < decay.size(); ++i)
489  {
490  if (std::find(std::begin(trackableParticles), std::end(trackableParticles),
491  std::abs(decay[i].second)) != std::end(trackableParticles))
492  {
493  ++m_nDaughters;
494  }
495  }
496 }
497 
499 {
500  return TDatabasePDG::Instance()->GetParticle(PDGID)->GetName();
501 }
502 
504 {
505  return TDatabasePDG::Instance()->GetParticle(PDGID)->Mass();
506 }
507 
508 //____________________________________________________________________________..
510 {
511  std::cout << "\n--------------- Heavy Flavor Tracking Efficiency ---------------" << std::endl;
512  std::cout << "Tracking Efficiency for " << m_decay_descriptor << std::endl;
513  std::cout << "Number of decays fully in acceptance: " << m_counter_allDecays << std::endl;
514  std::cout << "Number of decays with all tracks reconstructed: " << m_counter_acceptedDecays << std::endl;
515  std::cout << "Efficiency: " << std::setw(4) << (float) m_counter_acceptedDecays * 100 / float(m_counter_allDecays) << "%" << std::endl;
516  std::cout << "----------------------------------------------------------------\n"
517  << std::endl;
518 }