Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TruthRecoTrackMatching.cc
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file TruthRecoTrackMatching.cc
2 #include "TrkrClusterIsMatcher.h"
3 #include "ClusKeyIter.h"
4 
7 
9 
16 
17 #include <trackbase/TpcDefs.h>
18 #include <trackbase/TrkrCluster.h>
20 #include <trackbase/TrkrDefs.h>
21 
24 
26 
27 #include <phool/PHCompositeNode.h>
28 #include <phool/PHDataNode.h> // for PHDataNode
29 #include <phool/PHIODataNode.h>
30 #include <phool/PHNode.h> // for PHNode
31 #include <phool/PHNodeIterator.h>
32 #include <phool/PHObject.h> // for PHObject
33 #include <phool/PHRandomSeed.h>
34 #include <phool/getClass.h>
35 #include <phool/phool.h> // for PHWHERE
36 
37 #include <TFile.h>
38 #include <TSystem.h>
39 #include <TTree.h>
40 
41 #include <algorithm>
42 
43 // To change:
44 // Make the definition of matching clusters to be if the truth cluster center is withing 1/2 of width of the reco track center
45 
47  TrkrClusterIsMatcher* _ismatcher
48  , const unsigned short _nmincluster_match
49  , const float _nmincluster_ratio
50  , const float _cutoff_dphi
51  , const float _same_dphi
52  , const float _cutoff_deta
53  , const float _same_deta
54  , const unsigned short _max_nreco_per_truth
55  , const unsigned short _max_ntruth_per_reco)
56  : m_ismatcher { _ismatcher }
57  , m_nmincluster_match{_nmincluster_match} // minimum number of clusters to match, default=4
58  , m_nmincluster_ratio{_nmincluster_ratio} // minimum ratio to match a track, default=0.
59  // -- Track Kinematic Cuts to match --
60  , m_cutoff_dphi{_cutoff_dphi} // maximum |dphi|=|phi_reco-phi_truth| to search for match
61  , m_same_dphi{_same_dphi} // all tracks in this |dphi| must be tested for matches
62  , m_cutoff_deta{_cutoff_deta} // same as m_cutoff_dphi for deta
63  , m_same_deta{_same_deta} // same as m_same_dphi for deta
64  // cluster matching widths ()
65  // number of truth tracks allowed matched per reco track, and v. versa
66  , m_max_nreco_per_truth{_max_nreco_per_truth}
67  , m_max_ntruth_per_reco{_max_ntruth_per_reco}
68 {
69  m_TCEval.ismatcher = m_ismatcher;
70  if (Verbosity() > 50)
71  {
72  std::cout << " Starting TruthRecoTrackMatching.cc " << std::endl;
73  }
74 }
75 
77 {
78  if (Verbosity() > 10)
79  {
80  topNode->print();
81  }
82  auto init_status = m_ismatcher->init(topNode);
83  if (init_status == Fun4AllReturnCodes::ABORTRUN)
84  {
85  return init_status;
86  }
87 
89  {
91  }
95 }
96 
98 {
99  if (topnode == nullptr)
100  {
102  }
103  if (Verbosity() > 1000)
104  {
105  topnode->print(); // perhaps not needed
106  }
107 
108  m_nmatched_index_true.clear();
109 
110  // -------------------------------------------------------------------------------
111  // Build recoData
112  // ------------------------------------------------------------------------------
113 
114  // recoData is a vector of tuples that acts like a table with four columns,
115  // with one entry each of n tracks:
116  // (0)::float (1)::float (2)::float (3)::short
117  // phi-0 eta-0 pT-0 index-0
118  // phi-1 eta-1 pT-1 index-1
119  // phi-2 eta-2 pT-2 index-2
120  // ... ... ... ...
121  // phi-n-2 eta-n-2 pT-n-2 index-n-2
122  // phi-n-1 eta-n-1 pT-n-1 index-n-1
123  // phi-n eta-n pT-n index-n
124  if (Verbosity() > 60)
125  {
126  std::cout << "reco tracks size: " << m_SvtxTrackMap->size() << std::endl;
127  }
128 
129  recoData.clear();
130 
131  for (auto& reco : *m_SvtxTrackMap)
132  {
133  auto index_reco = reco.first;
134  auto track = reco.second;
135  recoData.push_back({track->get_phi(), track->get_eta(), track->get_pt(), index_reco});
136  }
137  // sort the recoData table by phi
138  std::sort(recoData.begin(), recoData.end(), CompRECOtoPhi());
139 
140  // phi will be sorted by proximity in the table, so re-add the first entries to the
141  // end of the table so that they can be compared against the phi across the
142  // circular boundary condition. This makes the table potentially look like:
143  // (0)::float (1)::float (2)::float (3)::short
144  // phi-0 eta-0 pT-0 index-0
145  // phi-1 eta-1 pT-1 index-1
146  // phi-2 eta-2 pT-2 index-2
147  // ... ... ... ...
148  // phi-n-2 eta-n-2 pT-n-2 index-n-2
149  // phi-n-1 eta-n-1 pT-n-1 index-n-1
150  // phi-n eta-n pT-n index-n
151  // phi-0 eta-0 pT-0 index-0 // <- values wrapped from the lowest phi values
152  // phi-1 eta-1 pT-1 index-1 // <-
153  RECOvec wraps{};
154  auto wrap_from_start = std::upper_bound(recoData.begin(),
155  recoData.end(), (-M_PI + m_cutoff_dphi), CompRECOtoPhi());
156  for (auto iter = recoData.begin(); iter != wrap_from_start; ++iter)
157  {
158  auto entry = *iter; // make a new copy to wrap to the other side of recoData
159  std::get<RECOphi>(entry) = std::get<RECOphi>(entry) + 2 * M_PI; // put the new copy on the other end
160  wraps.push_back(entry);
161  }
162  for (auto E : wraps)
163  {
164  recoData.push_back(E);
165  }
166 
167  if (Verbosity() > 70)
168  {
169  std::cout << " ****************************************** " << std::endl;
170  std::cout << " This is the RECO map of tracks to match to " << std::endl;
171  std::cout << " ****************************************** " << std::endl;
172  for (auto& E : recoData)
173  {
174  std::cout << Form(" id:%2i (phi:eta:pt) (%5.2f:%5.2f:%5.2f)", std::get<RECOid>(E),
175  std::get<RECOphi>(E), std::get<RECOeta>(E), std::get<RECOpt>(E))
176  << std::endl;
177  }
178  std::cout << " ****end*listing*********************** " << std::endl;
179  }
180 
181  /******************************************************************************
182  * Loop through the truth tracks one at a time. Based on track phi, eta, and pT
183  * build two indices of truth-to-reco pairs:
184  * innerbox_pairs: pairs of truth-to-reco tracks within same_d{phi,eta}
185  * i.e. |phi_true-phi_reco|<same_dphi && |eta_true-eta_reco|<same_deta).
186  * These are the "innerboxes" (retangles in phi and eta space).
187  * All of these pairs will have to be checked for matching tracks, and the
188  * best fits will be removed first.
189  * outerbox_pairs: these are wider boxes (sized by cutoff_d{phi,eta})
190  * These are possible matches that are only checked for tracks remaining
191  * after the innerbox_pairs are checked and matches made.
192  ******************************************************************************/
193 
194  std::vector<std::pair<unsigned short, unsigned short>> outerbox_pairs{};
195  std::vector<std::pair<unsigned short, unsigned short>> innerbox_pairs{};
196 
197  if (topnode == nullptr)
198  {
200  }
201  if (Verbosity() > 70)
202  {
203  std::cout << "Number of truth tracks: " << m_TrkrTruthTrackContainer->getMap().size() << std::endl;
204  for (auto& _pair : m_TrkrTruthTrackContainer->getMap())
205  {
206  auto& track = _pair.second;
207  std::cout << Form(" id:%2i (phi:eta:pt) (%5.2f:%5.2f:%5.2f nclus: %i)", track->getTrackid(),
208  track->getPhi(), track->getPseudoRapidity(), track->getPt(),
209  (int) track->getClusters().size())
210  << std::endl;
211  }
212  std::cout << " ----end-listing-truth-tracks---------- " << std::endl;
213  }
214 
215  for (auto _pair : m_TrkrTruthTrackContainer->getMap())
216  {
217  auto id_true = _pair.first;
218  auto track = _pair.second;
219 
220  auto match_indices = find_box_matches(track->getPhi(),
221  track->getPseudoRapidity(), track->getPt());
222 
223  // keep track of all truth tracks (by track-id) which has been matched
224  for (auto& id_reco : match_indices.first)
225  {
226  innerbox_pairs.emplace_back(id_true, id_reco);
227  }
228  for (auto& id_reco : match_indices.second)
229  {
230  outerbox_pairs.emplace_back(id_true, id_reco);
231  }
232 
233  if (Verbosity() > 80)
234  {
235  std::cout << Form(" T(%i) find box(%5.2f:%5.2f:%5.2f)",
236  (int) track->getTrackid(), track->getPhi(),
237  track->getPseudoRapidity(), track->getPt());
238  for (auto& id_reco : match_indices.first)
239  {
240  std::cout << "->IB(" << id_reco << ")";
241  }
242  for (auto& id_reco : match_indices.second)
243  {
244  std::cout << "->OB(" << id_reco << ")";
245  }
246  std::cout << std::endl;
247  }
248  }
249 
250  if (Verbosity() > 100)
251  {
252  std::cout << "Innerbox pairs" << std::endl;
253  }
254  match_tracks_in_box(innerbox_pairs);
255  if (Verbosity() > 100)
256  {
257  std::cout << "Outerbox pairs" << std::endl;
258  }
259  match_tracks_in_box(outerbox_pairs);
260 
261  // fill the list of all truth track ids that are not matched
262  for (auto _pair : m_TrkrTruthTrackContainer->getMap())
263  {
264  auto id_true = _pair.first;
266  }
267 
268  if (Verbosity() > 50)
269  {
270  std::cout << " --START--print-all-stored-matches--" << std::endl;
271  std::cout << " --0-- Printing all matches stored (start)" << std::endl;
272  // re-print all the tracks with the matches with the fit values
273  for (auto match : m_EmbRecoMatchContainer->getMatches())
274  {
275  std::cout << Form(" Match id(%2i->%2i) nClusMatch-nClusTrue-nClusReco (%2i:%2i:%2i)",
276  match->idTruthTrack(), match->idRecoTrack(),
277  match->nClustersMatched(), match->nClustersTruth(), match->nClustersReco())
278  << std::endl;
279  }
280  std::cout << " --END--print-all-stored-matches----" << std::endl;
281  }
282 
283  if (m_write_diag)
284  {
285  fill_tree();
286  }
287 
289 }
290 
292 {
293  TFile* s_current = gDirectory->GetFile();
294  if (m_write_diag)
295  {
296  m_diag_file->cd();
297  /* G4Eval::write_StringToTFile( */
298  /* "trk_match_sel", */
299  /* Form(" Matching criteria:\n" */
300  /* " min. clusters to match: %i\n" */
301  /* " min. clust. match ratio: %4.2f" */
302  /* " dphi small window: %4.2f" */
303  /* " dphi large windows: %4.2f" */
304  /* " deta small window: %4.2f" */
305  /* " deta large window: %4.2f" */
306  /* " nmax phg4 matches per svtx: %i" */
307  /* " nmax svtx matches per phg4: %i", */
308  /* m_nmincluster_match, m_nmincluster_ratio, m_same_dphi, m_cutoff_dphi, m_same_deta, m_cutoff_deta, m_max_ntruth_per_reco, m_max_nreco_per_truth)); */
309  m_diag_tree->Write();
310  m_diag_file->Save();
311  m_diag_file->Close();
312  if (s_current != nullptr)
313  {
314  s_current->cd();
315  }
316  }
317 
319 }
320 
321 //--------------------------------------------------
322 // Internal functions
323 //--------------------------------------------------
324 
326 {
327  PHNodeIterator iter(topNode);
328  PHCompositeNode* dstNode = dynamic_cast<PHCompositeNode*>(iter.findFirst("PHCompositeNode", "DST"));
329  if (!dstNode)
330  {
331  std::cout << PHWHERE << "DST Node missing, doing nothing." << std::endl;
332  exit(1);
333  }
334 
335  // Initiailize the modules
336  m_PHG4TruthInfoContainer = findNode::getClass<PHG4TruthInfoContainer>(topNode, "G4TruthInfo");
338  {
339  std::cout << "Could not locate G4TruthInfo node when running "
340  << "\"TruthRecoTrackMatching\" module." << std::endl;
342  }
343 
344  m_SvtxTrackMap = findNode::getClass<SvtxTrackMap>(topNode, "SvtxTrackMap");
345  if (!m_SvtxTrackMap)
346  {
347  std::cout << "Could not locate SvtxTrackMap node when running "
348  << "\"TruthRecoTrackMatching\" module." << std::endl;
350  }
351 
352  m_TruthClusterContainer = findNode::getClass<TrkrClusterContainer>(topNode,
353  "TRKR_TRUTHCLUSTERCONTAINER");
355  {
356  std::cout << "Could not locate TRKR_TRUTHCLUSTERCONTAINER node when "
357  << "running \"TruthRecoTrackMatching\" module." << std::endl;
359  }
360 
361  m_RecoClusterContainer = findNode::getClass<TrkrClusterContainer>(topNode, "TRKR_CLUSTER");
363  {
364  std::cout << "Could not locate TRKR_CLUSTER node when running "
365  << "\"TruthRecoTrackMatching\" module." << std::endl;
367  }
368 
369  m_TrkrTruthTrackContainer = findNode::getClass<TrkrTruthTrackContainer>(topNode,
370  "TRKR_TRUTHTRACKCONTAINER");
372  {
373  std::cout << "Could not locate TRKR_TRUTHTRACKCONTAINER node when "
374  << "running \"TruthRecoTrackMatching\" module." << std::endl;
376  }
377 
379  findNode::getClass<PHG4TpcCylinderGeomContainer>(topNode, "CYLINDERCELLGEOM_SVTX");
381  {
382  std::cout << "Could not locate CYLINDERCELLGEOM_SVTX node when "
383  << "running \"TruthRecoTrackMatching\" module." << std::endl;
384  /* std::cout << PHWHERE << "ERROR: Can't find node CYLINDERCELLGEOM_SVTX" << std::endl; */
386  }
387 
388  // note that layers 0-6, and > 55, don't work
389  /* for (int layer=7; layer<55; ++layer) { */
390  /* PHG4TpcCylinderGeom *layergeom = m_PHG4TpcCylinderGeomContainer->GetLayerCellGeom(layer); */
391  /* if (layer==7) m_zstep = layergeom->get_zstep(); */
392  /* m_phistep[layer] = layergeom->get_phistep(); */
393  /* } */
394  m_EmbRecoMatchContainer = findNode::getClass<EmbRecoMatchContainer>(topNode,
395  "TRKR_EMBRECOMATCHCONTAINER");
397  {
398  PHNodeIterator dstiter(dstNode);
399 
400  auto DetNode = dynamic_cast<PHCompositeNode*>(dstiter.findFirst("PHCompositeNode", "TRKR"));
401  if (!DetNode)
402  {
403  DetNode = new PHCompositeNode("TRKR");
404  dstNode->addNode(DetNode);
405  }
406 
409  "TRKR_EMBRECOMATCHCONTAINER", "PHObject");
410  DetNode->addNode(newNode);
411  }
412 
413  m_ActsGeometry = findNode::getClass<ActsGeometry>(topNode, "ActsGeometry");
414 
416 }
417 
418 std::pair<std::vector<unsigned short>, std::vector<unsigned short>>
419 TruthRecoTrackMatching::find_box_matches(float truth_phi, float truth_eta, float truth_pt)
420 {
421  // sort through the recoData to find:
422  // inner_box : possible matches withing m_same_d{phi,eta,pt}
423  // outer_box : (assumed to be strictly larger than, and therefore contain, inner_box, in m_cutoff_d{phi, eta,pt}
424  // recoData is already sorted by eta, but as the boxes "zoom in" on acceptable matches, it gets
425  // sorted by eta and (if applicable) pT as well. `mix_pair` keeps track of the range of recoData that has
426  // been sorted so that it can be resorted to phi order.
427  RECO_pair_iter mix_pair{recoData.begin(), recoData.end()};
428 
429  mix_pair.first = std::lower_bound(mix_pair.first, mix_pair.second,
430  truth_phi - m_cutoff_dphi, CompRECOtoPhi());
431 
432  mix_pair.second = std::upper_bound(mix_pair.first, mix_pair.second,
433  truth_phi + m_cutoff_dphi, CompRECOtoPhi());
434 
435  if (mix_pair.first == mix_pair.second)
436  {
437  // there are no possible phi_matches; return nothing
438  return {{}, {}};
439  }
440 
441  // There are tracks within the outer_box phi range;
442  // now re-shuffle the phi outerbox range for eta and see if there
443  // are tracks in outer_box-eta range
444  std::sort(mix_pair.first, mix_pair.second, CompRECOtoEta());
445 
446  RECO_pair_iter outer_box = mix_pair;
447  outer_box.first = std::lower_bound(mix_pair.first, mix_pair.second,
448  truth_eta - m_cutoff_deta, CompRECOtoEta());
449 
450  outer_box.second = std::lower_bound(outer_box.first, outer_box.second,
451  truth_eta + m_cutoff_deta, CompRECOtoEta());
452 
453  if (outer_box.first == outer_box.second)
454  {
455  // there are no eta_matches in outerbox; resort mix_pair and return nothing
456  std::sort(mix_pair.first, mix_pair.second, CompRECOtoPhi());
457  return {{}, {}};
458  }
459 
460  // if pt is specified, restrict pt_box to the given range
461  RECO_pair_iter inner_box = outer_box;
462  const float _delta_outer_pt = delta_outer_pt(truth_pt);
463  const float _delta_inner_pt = delta_inner_pt(truth_pt);
464  if (_delta_outer_pt > 0)
465  {
466  std::sort(outer_box.first, outer_box.second, CompRECOtoPt());
467  outer_box.first = std::lower_bound(outer_box.first, outer_box.second, truth_pt - _delta_outer_pt, CompRECOtoPt());
468  outer_box.second = std::upper_bound(outer_box.first, outer_box.second, truth_pt + _delta_outer_pt, CompRECOtoPt());
469 
470  // if not outer_box, resort and return nothing
471  if (outer_box.first == outer_box.second)
472  {
473  // there are no eta_matches in outerbox; resort mix_pair and return nothing
474  std::sort(mix_pair.first, mix_pair.second, CompRECOtoPhi());
475  return {{}, {}};
476  }
477 
478  // now calculate the inner box -- this time sorting in reverse -- pT, then eta, then phi
479  inner_box = outer_box;
480  if (_delta_inner_pt > 0)
481  {
482  // start the inner pair -- the outerbox is already sorted by pT
483  inner_box.first = std::lower_bound(inner_box.first,
484  inner_box.second, truth_pt - _delta_inner_pt, CompRECOtoPt());
485  inner_box.second = std::upper_bound(inner_box.first,
486  inner_box.second, truth_pt + _delta_inner_pt, CompRECOtoPt());
487  }
488 
489  // go back to sorted by eta
490  std::sort(inner_box.first, inner_box.second, CompRECOtoEta());
491  }
492 
493  // At this point we know that we have outer_box matches
494  // Finish checking if there are any possible inner_box matches
495 
496  // check for inner_box eta matches
497  if (inner_box.first != inner_box.second)
498  {
499  inner_box.first = std::lower_bound(inner_box.first, inner_box.second,
500  truth_eta - m_same_deta, CompRECOtoEta());
501 
502  inner_box.second = std::lower_bound(inner_box.first, inner_box.second,
503  truth_eta + m_same_deta, CompRECOtoEta());
504  }
505 
506  // check for inner_box phi matches
507  if (inner_box.first != inner_box.second)
508  {
509  std::sort(inner_box.first, inner_box.second, CompRECOtoPhi());
510 
511  inner_box.first = std::lower_bound(inner_box.first, inner_box.second,
512  truth_phi - m_same_dphi, CompRECOtoPhi());
513 
514  inner_box.second = std::lower_bound(inner_box.first, inner_box.second,
515  truth_phi + m_same_dphi, CompRECOtoPhi());
516  }
517 
518  // At this point there are definitely outer_box matches, and
519  // possible inner_box matches.
520  // Return all these possible matches, evaluating all inner_box_matches
521  std::vector<unsigned short> inner_box_matches, outer_box_matches;
522 
523  // fill inner_box_matches
524  for (auto iter = inner_box.first; iter != inner_box.second; ++iter)
525  {
526  inner_box_matches.push_back(std::get<RECOid>(*iter));
527  }
528  // fill inner_box_matches
529  for (auto iter = outer_box.first; iter != inner_box.first; ++iter)
530  {
531  outer_box_matches.push_back(std::get<RECOid>(*iter));
532  }
533  for (auto iter = inner_box.second; iter != outer_box.second; ++iter)
534  {
535  outer_box_matches.push_back(std::get<RECOid>(*iter));
536  }
537 
538  // resort recoData back to phi order
539  std::sort(mix_pair.first, mix_pair.second, CompRECOtoPhi());
540 
541  // return the box matches
542  return std::make_pair(inner_box_matches, outer_box_matches);
543 }
544 
546  std::vector<std::pair<unsigned short, unsigned short>>& box_pairs // possible matches by proximity in eta, phi, pT
547 )
548 {
549  if (box_pairs.size() == 0)
550  {
551  return;
552  }
553 
554  std::sort(box_pairs.begin(), box_pairs.end()); // sorted by first index_true, then id_reco
555  std::vector<PossibleMatch> poss_matches;
556 
557  auto ipair = box_pairs.begin(); // save current examined pair for sorting/unsorting purposes
558  while (ipair != box_pairs.end())
559  {
560  auto id_true = ipair->first;
561 
562  // See if this track already has the maximum number of matches. If it does, then skip all pairs using this truth-track-index;
563  if (at_nmax_index_true(id_true))
564  {
565  while (ipair != box_pairs.end())
566  {
567  ++ipair;
568  if (ipair->first != id_true)
569  {
570  break;
571  }
572  }
573  continue;
574  }
575 
576  // make all possible reco matches matched for this track
577  /* std::map<TrkrDefs::hitsetkey,TrkrDefs::cluskey> truth_keys; */
579  // add the truth keys into the track counter
580  /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); */
581  /* for (auto& key : truth_track->getClusters()) { */
582  /* truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; */
583  /* } */
584  /* unsigned short nclus_true = truth_keys.size(); */
585 
586  while (ipair != box_pairs.end())
587  { // Loop over all possible matches only for this index_true
588  //(subsequent true tracks will be caught on following loops)
589  if (ipair->first != id_true)
590  {
591  break; // never true on first iteration
592  }
593  if (at_nmax_id_reco(ipair->second))
594  {
595  ++ipair;
596  continue;
597  } // make sure the reco-track isn't alread matched
598  // ok, make a possible match: compare the clusters in the truth track and the reco track
599  SvtxTrack* reco_track = m_SvtxTrackMap->get(ipair->second);
600  m_TCEval.addClusKeys(reco_track);
602 
603  /* unsigned short nclus_match = 0; // fill in the comparison loop */
604  /* unsigned short nclus_nomatch = 0; // number of reco and truth cluster
605  * // that share a hitsetkey, but still fair matching criteria */
606  /* unsigned short nclus_reco = 0; // count in the comparison loop */
607  // do the comparison of the tracks
608  /* for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { */
609  /* ++nclus_reco; */
610  /* auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); */
611  /* if (truth_keys.count(hitsetkey) != 0) { */
612  /* // reco and truth cluster are in same hitsetkey-indexed subsurface. */
613  /* // See if they match (++nclus_match) or not (++nclus_nomatch) */
614  /* if (m_cluster_comp(truth_keys[hitsetkey], reco_ckey).first) { */
615  /* ++nclus_match; */
616  /* } else { */
617  /* ++nclus_nomatch; */
618  /* } */
619  /* } */
620  /* } */
621  unsigned short nclus_match = m_TCEval.phg4_n_matched();
622  unsigned short nclus_true = m_TCEval.phg4_nclus();
623  unsigned short nclus_reco = m_TCEval.svtx_nclus();
624  unsigned short nclus_nomatch = (int) (m_TCEval.svtx_keys.size() - nclus_match);
625 
626  if (Verbosity() > 100)
627  {
628  auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true);
629  std::cout << Form(
630  "possmatch:(phi,eta,pT:id) true(%5.2f,%5.2f,%4.2f:%2i) reco(%5.2f,%5.2f,%4.2f:%2i) "
631  "nCl(match:true:reco:nomatch)(%2i-%2i-%2i-%2i)",
632  truth_track->getPhi(), truth_track->getPseudoRapidity(), truth_track->getPt(),
633  (int) truth_track->getTrackid(),
634  reco_track->get_phi(), reco_track->get_eta(), reco_track->get_pt(),
635  ipair->second,
636  (int) nclus_match, (int) nclus_true, (int) nclus_reco, (int) nclus_nomatch)
637  << std::endl;
638  }
639  if (nclus_match >= m_nmincluster_match && (static_cast<float>(nclus_match) / nclus_true >= m_nmincluster_ratio))
640  {
641  poss_matches.push_back(
642  {nclus_match, nclus_true, nclus_reco,
643  ipair->first, ipair->second});
644  }
645  ++ipair;
646  }
647  }
648 
649  // add all possible matches started for the largest PM_nmatch (the top)
650  // for groups of ties of PM_nmatch, sort by PM_ntrue (from smallest)
651  // for groups of ties (PM_nmatch, PM_ntrue), go by smallest PM_nreco
652  // for groups of ties (PM_nmatch, PM_ntrue, PM_nreco), do a detailed sum diff in the deltas
653  std::sort(poss_matches.begin(), poss_matches.end(), SortPossibleMatch());
654 
655  if (Verbosity() > 200)
656  {
657  std::cout << " All chosen possible matches (" << poss_matches.size() << ") track pairs (nClMatched-nClTrue-nClReco : idTrue-idReco)" << std::endl;
658  int i{0};
659  for (auto match : poss_matches)
660  {
661  /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTracks()[std::get<PM_idtrue>(match)]; */
662  /* auto index_trut = truth_track->getTrackid(); */
663  std::cout << Form(" pair(%2i): %2i-%2i-%2i-<%2i>-%2i ", i++, (int) std::get<PM_nmatch>(match), (int) std::get<PM_ntrue>(match), (int) std::get<PM_nreco>(match), (int) std::get<PM_idtrue>(match), (int) std::get<PM_idreco>(match)) << std::endl;
664  }
665  }
666 
667  /* std::set<int> matched_idreco, matched_idtrue; */
668  auto iter = poss_matches.begin();
669  while (iter != poss_matches.end())
670  {
671  if (skip_match(*iter))
672  {
673  ++iter;
674  continue;
675  }
676  std::vector<std::pair<float, int>> sigma_metric = {{0., 0}};
677  int n_sigma = 0;
678  auto iter_same = iter + 1; // iterator to look forward from first point and get detailed comparisons for all possibly matched tracks
679  while (
680  iter_same != poss_matches.end() && (*iter_same)[PM_nmatch] == (*iter)[PM_nmatch] && (*iter_same)[PM_ntrue] == (*iter)[PM_ntrue] && (*iter_same)[PM_nreco] == (*iter)[PM_nreco])
681  {
682  ++n_sigma;
683  if (n_sigma == 1)
684  {
685  sigma_metric[0].first = sigma_CompMatchClusters(*iter);
686  }
687  sigma_metric.emplace_back(sigma_CompMatchClusters(*iter_same), n_sigma);
688  ++iter_same;
689  }
690  std::sort(sigma_metric.begin(), sigma_metric.end());
691 
692  bool first = true;
693  for (auto& sigma : sigma_metric)
694  {
695  if (first)
696  {
697  first = false;
698  }
699  else if (skip_match(*(iter + sigma.second)))
700  {
701  continue;
702  }
703  auto match = *(iter + sigma.second);
704  auto id_true = match[PM_idtrue];
705  auto id_reco = match[PM_idreco];
706  auto save_match = new EmbRecoMatchv1(id_true, id_reco,
707  match[PM_ntrue], match[PM_nreco], match[PM_nmatch]);
708  m_EmbRecoMatchContainer->addMatch(save_match);
709 
710  if (m_nmatched_index_true.find(id_true) == m_nmatched_index_true.end())
711  {
712  m_nmatched_index_true[id_true] = 1;
713  }
714  else
715  {
716  m_nmatched_index_true[id_true] += 1;
717  }
718  }
719  iter += sigma_metric.size();
720  }
721 }
722 
723 // ----------------------------------------
724 // convenience function
725 // ----------------------------------------
726 inline float TruthRecoTrackMatching::abs_dphi(float phi0, float phi1)
727 {
728  float dphi = std::fabs(phi0 - phi1);
729  while (dphi > M_PI)
730  {
731  dphi = std::fabs(dphi - 2 * M_PI);
732  }
733  return dphi;
734 }
735 
737 {
738  auto id_true = match[PM_idtrue];
739  auto id_reco = match[PM_idreco];
740 
742  m_TCEval.addClusKeys(m_SvtxTrackMap->get(id_reco));
743 
745 
746  int n_matched = m_TCEval.phg4_n_matched();
747 
748  if (n_matched)
749  {
750  return std::numeric_limits<float>::max();
751  }
752  else
753  {
754  return m_TCEval.match_stat / n_matched;
755  }
756 }
757 /* auto truth_track = m_TrkrTruthTrackContainer->getTruthTrack(id_true); */
758 /* if (!truth_track) return std::numeric_limits<float>::max(); */
759 /* std::map<TrkrDefs::hitsetkey,TrkrDefs::cluskey> truth_keys; // truth cluster keys */
760 /* for (auto& key : truth_track->getClusters()) */
761 /* truth_keys[TrkrDefs::getHitSetKeyFromClusKey(key)] = key; */
762 
763 /* SvtxTrack* reco_track = m_SvtxTrackMap->get(id_reco); */
764 /* if (!reco_track) return std::numeric_limits<float>::max(); */
765 
766 /* auto tpcseed = reco_track->get_tpc_seed(); */
767 /* if (!tpcseed) return std::numeric_limits<float>::max(); */
768 
769 /* double n_matches = 0.; // get the mean match values */
770 /* double sum_diff = 0.; */
771 
772 /* for (auto reco_ckey : G4Eval::ClusKeyIter(reco_track)) { */
773 /* auto hitsetkey = TrkrDefs::getHitSetKeyFromClusKey(reco_ckey); */
774 /* if (truth_keys.count(hitsetkey) == 0) continue; */
775 /* auto comp_val = m_cluster_comp(truth_keys[hitsetkey], reco_ckey); */
776 
777 /* if (comp_val.first) { */
778 /* n_matches += 1.; */
779 /* sum_diff += comp_val.second; */
780 /* } */
781 /* } */
782 /* return sum_diff/n_matches; */
783 /* } */
784 
786 {
787  return at_nmax_id_reco(match[PM_idreco]) || at_nmax_index_true(match[PM_idreco]);
788 }
789 
790 // ----------------------------------------------
791 // functions for permissible matching pt
792 // Currently not used, therefore tracks of any pT
793 // will be compared against each other.
794 // If wanted, will have to be updated with
795 // same values in the future.
796 // ----------------------------------------------
798 {
799  return -1. + pt * 0.; // 10. + 0.01*pt;
800 }
802 {
803  return -1. + pt * 0.; // 10. + 0.01*pt;
804 }
805 
806 bool TruthRecoTrackMatching::at_nmax_index_true(unsigned short index_true)
807 {
808  if (m_nmatched_index_true.find(index_true) == m_nmatched_index_true.end())
809  {
810  return false;
811  }
812  return m_nmatched_index_true[index_true] >= m_max_nreco_per_truth;
813 }
814 
815 bool TruthRecoTrackMatching::at_nmax_id_reco(unsigned short id_reco)
816 {
817  if (m_nmatched_id_reco->find(id_reco) == m_nmatched_id_reco->end())
818  {
819  return false;
820  }
821  return (*m_nmatched_id_reco)[id_reco] >= m_max_ntruth_per_reco;
822 }
823 
825 {
826  m_write_diag = true;
827  TFile* s_current = gDirectory->GetFile();
828  m_diag_file = new TFile(file_name.c_str(), "recreate");
829  // write out the cuts on this set of data
830  m_diag_file->cd();
831  m_diag_tree = new TTree("T", "Tree of Reco and True Clusters");
832 
833  m_diag_tree->Branch("event", &m_event);
834 
835  m_diag_tree->Branch("trkid_reco_matched", &m_trkid_reco_matched);
836  m_diag_tree->Branch("itrk_reco_matched", &m_cnt_reco_matched);
837  m_diag_tree->Branch("i0_reco_matched", &m_i0_reco_matched);
838  m_diag_tree->Branch("i1_reco_matched", &m_i1_reco_matched);
839  m_diag_tree->Branch("layer_reco_matched", &m_layer_reco_matched);
840  m_diag_tree->Branch("x_reco_matched", &m_x_reco_matched);
841  m_diag_tree->Branch("y_reco_matched", &m_y_reco_matched);
842  m_diag_tree->Branch("z_reco_matched", &m_z_reco_matched);
843 
844  m_diag_tree->Branch("trkid_reco_notmatched", &m_trkid_reco_notmatched);
845  m_diag_tree->Branch("itrk_reco_notmatched", &m_cnt_reco_notmatched);
846  m_diag_tree->Branch("i0_reco_notmatched", &m_i0_reco_notmatched);
847  m_diag_tree->Branch("i1_reco_notmatched", &m_i1_reco_notmatched);
848  m_diag_tree->Branch("layer_reco_notmatched", &m_layer_reco_notmatched);
849  m_diag_tree->Branch("x_reco_notmatched", &m_x_reco_notmatched);
850  m_diag_tree->Branch("y_reco_notmatched", &m_y_reco_notmatched);
851  m_diag_tree->Branch("z_reco_notmatched", &m_z_reco_notmatched);
852 
853  m_diag_tree->Branch("trkid_true_matched", &m_trkid_true_matched);
854  m_diag_tree->Branch("itrk_true_matched", &m_cnt_true_matched);
855  m_diag_tree->Branch("i0_true_matched", &m_i0_true_matched);
856  m_diag_tree->Branch("i1_true_matched", &m_i1_true_matched);
857  m_diag_tree->Branch("layer_true_matched", &m_layer_true_matched);
858  m_diag_tree->Branch("x_true_matched", &m_x_true_matched);
859  m_diag_tree->Branch("y_true_matched", &m_y_true_matched);
860  m_diag_tree->Branch("z_true_matched", &m_z_true_matched);
861 
862  m_diag_tree->Branch("trkid_true_notmatched", &m_trkid_true_notmatched);
863  m_diag_tree->Branch("itrk_true_notmatched", &m_cnt_true_notmatched);
864  m_diag_tree->Branch("i0_true_notmatched", &m_i0_true_notmatched);
865  m_diag_tree->Branch("i1_true_notmatched", &m_i1_true_notmatched);
866  m_diag_tree->Branch("layer_true_notmatched", &m_layer_true_notmatched);
867  m_diag_tree->Branch("x_true_notmatched", &m_x_true_notmatched);
868  m_diag_tree->Branch("y_true_notmatched", &m_y_true_notmatched);
869  m_diag_tree->Branch("z_true_notmatched", &m_z_true_notmatched);
870 
871  if (s_current != nullptr)
872  {
873  s_current->cd();
874  }
875 }
876 
878 {
879  m_trkid_reco_matched.clear();
880  m_i0_reco_matched.clear();
881  m_i1_reco_matched.clear();
882  m_layer_reco_matched.clear();
883  m_x_reco_matched.clear();
884  m_y_reco_matched.clear();
885  m_z_reco_matched.clear();
886 
887  m_trkid_reco_notmatched.clear();
888  m_i0_reco_notmatched.clear();
889  m_i1_reco_notmatched.clear();
890  m_layer_reco_notmatched.clear();
891  m_x_reco_notmatched.clear();
892  m_y_reco_notmatched.clear();
893  m_z_reco_notmatched.clear();
894 
895  m_trkid_true_matched.clear();
896  m_i0_true_matched.clear();
897  m_i1_true_matched.clear();
898  m_layer_true_matched.clear();
899  m_x_true_matched.clear();
900  m_y_true_matched.clear();
901  m_z_true_matched.clear();
902 
903  m_trkid_true_notmatched.clear();
904  m_i0_true_notmatched.clear();
905  m_i1_true_notmatched.clear();
906  m_layer_true_notmatched.clear();
907  m_x_true_notmatched.clear();
908  m_y_true_notmatched.clear();
909  m_z_true_notmatched.clear();
910 }
911 
913 {
914  // fill clusters or un-matched truth tracks
915  int cnt = 0;
916  int itrk = 0;
917  for (auto& trkid : m_EmbRecoMatchContainer->ids_TruthUnmatched())
918  {
919  m_trkid_true_notmatched.push_back(trkid);
920  m_i0_true_notmatched.push_back(cnt);
921  auto track = m_TrkrTruthTrackContainer->getTruthTrack(trkid);
922  for (auto& ckey : track->getClusters())
923  {
924  auto cluster = m_TruthClusterContainer->findCluster(ckey);
925  m_cnt_true_notmatched.push_back(itrk);
926  Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(ckey, cluster);
928  m_x_true_notmatched.push_back(gloc[0]);
929  m_y_true_notmatched.push_back(gloc[1]);
930  m_z_true_notmatched.push_back(gloc[2]);
931  ++cnt;
932  }
933  m_i1_true_notmatched.push_back(cnt);
934  ++itrk;
935  }
936 
937  // fill clusters of matched truth tracks
938  cnt = 0;
939  itrk = 0;
940  for (auto& trkid : m_EmbRecoMatchContainer->ids_TruthMatched())
941  {
942  m_trkid_true_matched.push_back(trkid);
943  m_i0_true_matched.push_back(cnt);
944  auto track = m_TrkrTruthTrackContainer->getTruthTrack(trkid);
945  for (auto& ckey : track->getClusters())
946  {
947  auto cluster = m_TruthClusterContainer->findCluster(ckey);
948  m_cnt_true_matched.push_back(itrk);
949  Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(ckey, cluster);
950  m_layer_true_matched.push_back(TrkrDefs::getLayer(ckey));
951  m_x_true_matched.push_back(gloc[0]);
952  m_y_true_matched.push_back(gloc[1]);
953  m_z_true_matched.push_back(gloc[2]);
954  ++cnt;
955  }
956  m_i1_true_matched.push_back(cnt);
957  ++itrk;
958  }
959 
960  // fill clusters of matched reco tracks
961  std::set<unsigned int> set_reco_matched;
962  cnt = 0;
963  itrk = 0;
964  for (auto& trkid : m_EmbRecoMatchContainer->ids_RecoMatched())
965  {
966  set_reco_matched.insert(trkid);
967  m_trkid_reco_matched.push_back(trkid);
968  SvtxTrack* reco_track = m_SvtxTrackMap->get(trkid);
969  m_i0_reco_matched.push_back(cnt);
970 
971  for (auto reco_ckey : ClusKeyIter(reco_track))
972  {
973  auto cluster = m_RecoClusterContainer->findCluster(reco_ckey);
974  Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(reco_ckey, cluster);
975  m_layer_reco_matched.push_back(TrkrDefs::getLayer(reco_ckey));
976  m_cnt_reco_matched.push_back(itrk);
977  m_x_reco_matched.push_back(gloc[0]);
978  m_y_reco_matched.push_back(gloc[1]);
979  m_z_reco_matched.push_back(gloc[2]);
980  ++cnt;
981  }
982  m_i1_reco_matched.push_back(cnt);
983  ++itrk;
984  }
985 
986  // fill clusters of not matched reco tracks
987  cnt = 0;
988  itrk = 0;
989  for (auto& reco : *m_SvtxTrackMap)
990  {
991  auto trkid = reco.first;
992  if (set_reco_matched.count(trkid))
993  {
994  continue;
995  }
996  m_trkid_reco_notmatched.push_back(trkid);
997  SvtxTrack* reco_track = m_SvtxTrackMap->get(trkid);
998  m_i0_reco_notmatched.push_back(cnt);
999  for (auto reco_ckey : ClusKeyIter(reco_track))
1000  {
1001  auto cluster = m_RecoClusterContainer->findCluster(reco_ckey);
1002  Eigen::Vector3d gloc = m_ActsGeometry->getGlobalPosition(reco_ckey, cluster);
1003  m_layer_reco_notmatched.push_back(TrkrDefs::getLayer(reco_ckey));
1004  m_cnt_reco_notmatched.push_back(itrk);
1005  m_x_reco_notmatched.push_back(gloc[0]);
1006  m_y_reco_notmatched.push_back(gloc[1]);
1007  m_z_reco_notmatched.push_back(gloc[2]);
1008  ++cnt;
1009  }
1010  m_i1_reco_notmatched.push_back(cnt);
1011  ++itrk;
1012  }
1013  ++m_event;
1014  m_diag_tree->Fill();
1016  return;
1017 }