All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
icarusalg/icarusalg/gallery/galleryAnalysis/C++/MCAssociations.cpp
Go to the documentation of this file.
1 /**
2  * @file MCAssociations.cpp
3  * @brief Does something with the tracks (implementation file).
4  * @author Tracy Usher (usher@slac.stanford.edu
5  * @date October 24, 2017
6  * @see MCAssociations.h
7  *
8  */
9 
10 #include "MCAssociations.h"
11 
12 // LArSoft libraries
13 #include "nusimdata/SimulationBase/MCTruth.h"
16 
17 // canvas libraries
18 #include "canvas/Persistency/Common/FindMany.h"
19 
20 // ROOT libraries
21 #include "TVector3.h"
22 
23 // C/C++ standard libraries
24 #include <algorithm> // std::count_if()
25 
26 
27 MCAssociations::MCAssociations(fhicl::ParameterSet const& config)
28  : fHitProducerLabel(config.get<art::InputTag>("HitProducerLabel", "")),
29  fMCTruthProducerLabel(config.get<art::InputTag>("MCTruthProducerLabel", "")),
30  fAssnsProducerLabel(config.get<art::InputTag>("MCTrackAssnsProducerLabel","")),
31  fTrackProducerLabel(config.get<art::InputTag>("TrackProducerLabel","")),
32  fLocalDirName(config.get<std::string>("LocalDirName", ""))
33  {}
34 
36  const detinfo::DetectorPropertiesData& detectorProperties,
37  TDirectory* outDir)
38 {
40  fDetectorProperties = std::make_unique<detinfo::DetectorPropertiesData const>(detectorProperties);
41  fDir = outDir->mkdir(fLocalDirName.c_str());
42 }
43 
45 {
46  if (fDir)
47  {
48  fNTracks = std::make_unique<TH1F>("NTrueTracks", "Number of tracks;number of tracks;events", 100, 0., 200.);
49  fNTracks->SetDirectory(fDir);
50  fNHitsPerTrack = std::make_unique<TH1F>("NHitsPerTrack", "Number Hits/Track", 250, 0., 250.);
51  fNHitsPerTrack->SetDirectory(fDir);
52  fTrackLength = std::make_unique<TH1F>("TrackLength", "Length; track length(cm)", 200, 0., 200.);
53  fTrackLength->SetDirectory(fDir);
54  fTrackLenVsHits = std::make_unique<TH2F>("TrackLenVsHits", "Length;Hits", 200, 0., 200., 250, 0., 250.);
55 
56  fNHitsPerPrimary = std::make_unique<TH1F>("NHitsPerPrimary", "Number Hits/Primary;log(# hits)", 15, 0.5, 3.5);
57  fNHitsPerPrimary->SetDirectory(fDir);
58  fPrimaryLength = std::make_unique<TH1F>("PrimaryLength", "Length of Primary;length(cm)", 50, 0., 350.);
59  fPrimaryLength->SetDirectory(fDir);
60  fPrimaryLenVsHits = std::make_unique<TH2F>("PrimaryLenVsHits", "Length;Hits", 50, 0., 350., 250, 0., 2500.);
61  fPrimaryLenVsHits->SetDirectory(fDir);
62 
63  fNHitsPerReco = std::make_unique<TH1F>("PrimaryRecoNHits", "Number Hits/Track;log(# hits)", 15, 0.5, 3.5);
64  fNHitsPerReco->SetDirectory(fDir);
65  fDeltaNHits = std::make_unique<TH1F>("DeltaNHits", "Delta Number Hits", 100, -200., 200.);
66  fDeltaNHits->SetDirectory(fDir);
67  fPrimaryRecoLength = std::make_unique<TH1F>("PrimaryRecLength", "Length of Reco; length(cm)", 50, 0., 350.);
68  fPrimaryRecoLength->SetDirectory(fDir);
69  fDeltaTrackLen = std::make_unique<TH1F>("DeltaTrackLen", "Delta Track Length", 100, -100., 100.);
70  fDeltaTrackLen->SetDirectory(fDir);
71 
72  fPrimaryEfficiency = std::make_unique<TH1F>("PrimaryEfficiency", "Efficiency", 101, 0., 1.01);
73  fPrimaryEfficiency->SetDirectory(fDir);
74  fPrimaryCompleteness = std::make_unique<TH1F>("PrimaryCompleteness", "Completeness", 101, 0., 1.01);
75  fPrimaryCompleteness->SetDirectory(fDir);
76  fPrimaryPurity = std::make_unique<TH1F>("PrimaryPurity", "Purity", 101, 0., 1.01);
77  fPrimaryPurity->SetDirectory(fDir);
78 
79  fPrimaryEffVsMom = std::make_unique<TProfile>("PrimaryEffVsMom", "Efficiency vs Momentum;Momentum(GeV/c);Efficiency", 25, 0.1, 1.10, 0., 1.1);
80  fPrimaryEffVsMom->SetDirectory(fDir);
81  fPrimaryCompVsMom = std::make_unique<TProfile>("PrimaryCompVsMom", "Completeness vs Momentum;Momentum(GeV/c);Completeness", 25, 0.1, 1.10, 0., 1.1);
82  fPrimaryCompVsMom->SetDirectory(fDir);
83  fPrimaryPurityVsMom = std::make_unique<TProfile>("PrimaryPurVsMom", "Purity vs Momentum;Momentum(GeV/c);Purity", 25, 0.1, 1.10, 0., 1.1);
84  fPrimaryPurityVsMom->SetDirectory(fDir);
85 
86  fPrimaryEffVsLen = std::make_unique<TProfile>("PrimaryEffVsLen", "Efficiency vs Length; length; Efficiency", 30, 0., 300., 0., 1.1);
87  fPrimaryEffVsLen->SetDirectory(fDir);
88  fPrimaryCompVsLen = std::make_unique<TProfile>("PrimaryCompVsLen", "Completeness vs Length; length; Completeness", 30, 0., 300., 0., 1.1);
89  fPrimaryCompVsLen->SetDirectory(fDir);
90  fPrimaryPurityVsLen = std::make_unique<TProfile>("PrimaryPurVsLen", "Purity vs Length; length; Purity", 30, 0., 300., 0., 1.1);
91  fPrimaryPurityVsLen->SetDirectory(fDir);
92 
93  fPrimaryEffVsHits = std::make_unique<TProfile>("PrimaryEffVsHits", "Efficiency vs # Hits", 50, 0., 2000., 0., 1.1);
94  fPrimaryEffVsHits->SetDirectory(fDir);
95  fPrimaryCompVsHits = std::make_unique<TProfile>("PrimaryCompVsHits", "Completeness vs # Hits", 50, 0., 2000., 0., 1.1);
96  fPrimaryCompVsHits->SetDirectory(fDir);
97  fPrimaryPurityVsHits = std::make_unique<TProfile>("PrimaryPurityVsHits", "Purity vs # Hits", 50, 0., 2000., 0., 1.1);
98  fPrimaryPurityVsHits->SetDirectory(fDir);
99 
100  fPrimaryEffVsLogHits = std::make_unique<TProfile>("PrimaryEffVsLogHits", "Efficiency vs log(# Hits);log(# Hits);Efficiency", 15, 0.5, 3.5, 0., 1.1);
101  fPrimaryEffVsLogHits->SetDirectory(fDir);
102  fPrimaryCompVsLogHits = std::make_unique<TProfile>("PrimaryCompVsLogHits", "Completeness vs log(# Hits);log(# Hits);Completeness)", 15, 0.5, 3.5, 0., 1.1);
103  fPrimaryCompVsLogHits->SetDirectory(fDir);
104  fPrimaryPurityVsLogHits = std::make_unique<TProfile>("PrimaryPurityVsLogHits", "Purity vs log(# Hits);log(# Hits);Purity)", 15, 0.5, 3.5, 0., 1.1);
105  fPrimaryPurityVsLogHits->SetDirectory(fDir);
106  }
107  else
108  {
109  fNTracks.reset();
110  fNHitsPerTrack.reset();
111  fNHitsPerPrimary.reset();
112  }
113 
114  return;
115 } // MCAssociations::prepare()
116 
117 void MCAssociations::doTrackHitMCAssociations(gallery::Event& event)
118 {
119  // First step is to recover the MCTruth object vector...
120  const auto& mcParticleHandle = event.getValidHandle<std::vector<simb::MCParticle>>(fMCTruthProducerLabel);
121 
122  // Now see how many reco hits might be associated to this particle
123  art::FindMany<recob::Hit, anab::BackTrackerHitMatchingData> hitsPerMCParticle(mcParticleHandle, event, fAssnsProducerLabel);
124 
125  // Make maps, we really like to make maps
126  using HitToPartVecMap = std::map<const recob::Hit*,std::set<const simb::MCParticle*>>;
127  using PartToHitVecMap = std::map<const simb::MCParticle*, std::set<const recob::Hit*>>;
128 
129  HitToPartVecMap hitToPartVecMap;
130  PartToHitVecMap partToHitVecMap;
131 
132  // Loop through the particles
133  for(size_t mcIdx = 0; mcIdx < mcParticleHandle->size(); mcIdx++)
134  {
135  try
136  {
137  const simb::MCParticle& mcParticle = mcParticleHandle->at(mcIdx);
138 
139  std::vector<const recob::Hit*> hitsVec = hitsPerMCParticle.at(mcIdx);
140 
141  for(const auto& hit : hitsVec)
142  {
143  hitToPartVecMap[hit].insert(&mcParticle);
144  partToHitVecMap[&mcParticle].insert(hit);
145  }
146  }
147  catch(...) {break;}
148  }
149 
150  // In this section try looking at tracking. Eventually we want to move this out of here...
151  // First step is to recover the MCTruth object vector...
152  const auto& trackHandle = event.getValidHandle<std::vector<recob::Track>>(fTrackProducerLabel);
153 
154  // Now see how many reco hits might be associated to this particle
155  art::FindMany<recob::Hit> hitsPerTrack(trackHandle, event, fTrackProducerLabel);
156 
157  // Define a mapping between tracks and associated MCParticles
158  using TrackToParticleSetMap = std::map<const recob::Track*, std::set<const simb::MCParticle*>>;
159  using ParticleToTrackSetMap = std::map<const simb::MCParticle*, std::set<const recob::Track*>>;
160  using ParticleToHitSetMap = std::map<const simb::MCParticle*, std::set<const recob::Hit*>>;
161  using TrackToPartHitSetMap = std::map<const recob::Track*, ParticleToHitSetMap>;
162  using TrackToHitsVecMap = std::map<const recob::Track*, std::vector<const recob::Hit*>>;
163 
164  TrackToParticleSetMap trackToParticleSetMap;
165  ParticleToTrackSetMap particleToTrackSetMap;
166 
167  TrackToPartHitSetMap trackToPartHitSetMap;
168  TrackToHitsVecMap trackToHitsVecMap;
169 
170  // Loop through the tracks and associate via the hits to MCParticles
171  for(size_t trkIdx = 0; trkIdx < trackHandle->size(); trkIdx++)
172  {
173  const recob::Track& track = trackHandle->at(trkIdx);
174 
175  std::vector<const recob::Hit*> hitsVec = hitsPerTrack.at(trkIdx);
176 
177  trackToHitsVecMap[&track] = hitsVec;
178 
179  ParticleToHitSetMap& particleToHitSetMap = trackToPartHitSetMap[&track];
180 
181  for(const auto& hit : hitsVec)
182  {
183  HitToPartVecMap::iterator partItr = hitToPartVecMap.find(hit);
184 
185  if (partItr != hitToPartVecMap.end())
186  {
187  for(const auto& particle : partItr->second)
188  {
189  particleToHitSetMap[particle].insert(hit);
190  trackToParticleSetMap[&track].insert(particle);
191  particleToTrackSetMap[particle].insert(&track);
192  }
193  }
194  }
195  }
196 
197  // *****************************************************************************************
198  // The bits below here should eventually be moved into their own analyzer algorithm
199  // but we are in a hurry now so do it all here...
200  // Ok, at this point we should be able to relate MCParticles to tracks and hits
201  // Let's start by just looking at the primary particle
202  const simb::MCParticle& primaryParticle = mcParticleHandle->at(0);
203 
204  ParticleToTrackSetMap::iterator partTrackItr = particleToTrackSetMap.find(&primaryParticle);
205 
206  // Define the parameters we want...
207  int numPrimaryHitsTotal = partToHitVecMap[&primaryParticle].size();
208 
209  // If there are NO reconstructed hits associated to this particle then we don't count
210  // But this should really be a check on fiducial volume I think...
211  if (numPrimaryHitsTotal > 0)
212  {
213  const recob::Track* bestTrack(0);
214  float efficiency(0.);
215  float completeness(0.);
216  float purity(0.);
217  size_t numTrackHits(0);
218 
219  // Here we find the best matched track to the MCParticle.
220  // Nothing exciting, most hits wins sort of thing...
221  if (partTrackItr != particleToTrackSetMap.end())
222  {
223  // Recover the longest track...
224  for(const auto& track : partTrackItr->second)
225  {
226  if (trackToPartHitSetMap[track][partTrackItr->first].size() > numTrackHits)
227  {
228  bestTrack = track;
229  numTrackHits = trackToPartHitSetMap[track][partTrackItr->first].size();
230  }
231  }
232 
233  if (bestTrack)
234  {
235  int numPrimaryHitsMatch = numTrackHits;
236  int numTrackHitsTotal = trackToHitsVecMap[bestTrack].size();
237 
238  completeness = float(numPrimaryHitsMatch) / float(numPrimaryHitsTotal);
239  purity = float(numPrimaryHitsMatch) / float(numTrackHitsTotal);
240 
241  if (completeness > 0.2) efficiency = 1.;
242  }
243  }
244 
245  // Calculate the length of this mc particle inside the fiducial volume.
246  TVector3 mcstart;
247  TVector3 mcend;
248  TVector3 mcstartmom;
249  TVector3 mcendmom;
250 
251  double xOffset(0.);
252 
253  double mcTrackLen = length(primaryParticle, xOffset, mcstart, mcend, mcstartmom, mcendmom);
254  double trackLen = 0.;
255 
256  if (bestTrack) trackLen = length(bestTrack);
257 
258  fNTracks->Fill(partToHitVecMap.size(), 1.);
259  fNHitsPerPrimary->Fill(std::log10(double(partToHitVecMap[&primaryParticle].size())), 1.);
260  fPrimaryLength->Fill(mcTrackLen, 1.);
261  fPrimaryLenVsHits->Fill(mcTrackLen, partToHitVecMap[&primaryParticle].size(), 1.);
262 
263  fPrimaryRecoLength->Fill(trackLen, 1.);
264  fDeltaTrackLen->Fill(trackLen-mcTrackLen, 1.);
265 
266  fNHitsPerReco->Fill(std::log10(numTrackHits), 1.);
267  fDeltaNHits->Fill(numTrackHits - int(partToHitVecMap[&primaryParticle].size()), 1.);
268 
269  // Loop through the particles again to histogram some secondary info...
270  for(size_t mcIdx = 0; mcIdx < mcParticleHandle->size(); mcIdx++)
271  {
272  try
273  {
274  const simb::MCParticle& mcParticle = mcParticleHandle->at(mcIdx);
275 
276  if (!partToHitVecMap[&mcParticle].empty())
277  {
278  // Calculate the length of this mc particle inside the fiducial volume.
279  double secTrackLen = length(mcParticle, xOffset, mcstart, mcend, mcstartmom, mcendmom);
280 
281  fNHitsPerTrack->Fill(partToHitVecMap[&mcParticle].size(), 1.);
282  fTrackLength->Fill(secTrackLen, 1.);
283  fTrackLenVsHits->Fill(secTrackLen, partToHitVecMap[&mcParticle].size(), 1.);
284  }
285  }
286  catch(...) {break;}
287  }
288 
289  // Final sets of plots
290  fPrimaryEfficiency->Fill(efficiency, 1.);
291  fPrimaryCompleteness->Fill(completeness, 1.);
292  fPrimaryPurity->Fill(purity, 1.);
293 
294  fPrimaryEffVsHits->Fill(numPrimaryHitsTotal, efficiency, 1.);
295  fPrimaryCompVsHits->Fill(numPrimaryHitsTotal, completeness, 1.);
296  fPrimaryPurityVsHits->Fill(numPrimaryHitsTotal, purity, 1.);
297 
298  double partMom = primaryParticle.P();
299  fPrimaryEffVsMom->Fill(partMom, efficiency, 1.);
300  fPrimaryCompVsMom->Fill(partMom, completeness, 1.);
301  fPrimaryPurityVsMom->Fill(partMom, purity, 1.);
302 
303  fPrimaryEffVsLen->Fill(mcTrackLen, efficiency, 1.);
304  fPrimaryCompVsLen->Fill(mcTrackLen, completeness, 1.);
305  fPrimaryPurityVsLen->Fill(mcTrackLen, purity, 1.);
306 
307  double logNumHits = std::log10(numPrimaryHitsTotal);
308  fPrimaryEffVsLogHits->Fill(logNumHits, efficiency, 1.);
309  fPrimaryCompVsLogHits->Fill(logNumHits, completeness, 1.);
310  fPrimaryPurityVsLogHits->Fill(logNumHits, purity, 1.);
311  }
312 
313  return;
314 } // MCAssociations::processTracks()
315 
317 {
318  if (fNTracks)
319  {
320  fDir->cd();
321  fNTracks->Write();
322  fNHitsPerTrack->Write();
323  fTrackLength->Write();
324  fTrackLenVsHits->Write();
325  fNHitsPerPrimary->Write();
326  fPrimaryLength->Write();
327  fPrimaryLenVsHits->Write();
328  fPrimaryEfficiency->Write();
329  fPrimaryCompleteness->Write();
330  fPrimaryPurity->Write();
331  fPrimaryEffVsHits->Write();
332  fPrimaryCompVsHits->Write();
333  fPrimaryPurityVsHits->Write();
334  fPrimaryEffVsMom->Write();
335  fPrimaryCompVsMom->Write();
336  fPrimaryPurityVsMom->Write();
337  fPrimaryEffVsLen->Write();
338  fPrimaryCompVsLen->Write();
339  fPrimaryPurityVsLen->Write();
340  fPrimaryEffVsLogHits->Write();
341  fPrimaryCompVsLogHits->Write();
342  fPrimaryPurityVsLogHits->Write();
343  fPrimaryRecoLength->Write();
344  fDeltaTrackLen->Write();
345  fNHitsPerReco->Write();
346  fDeltaNHits->Write();
347  }
348 } // MCAssociations::finish()
349 
350 // Length of reconstructed track.
351 //----------------------------------------------------------------------------
353 {
354  return track->Length();
355 }
356 
357 // Length of MC particle.
358 //----------------------------------------------------------------------------
359 double MCAssociations::length(const simb::MCParticle& part, double dx,
360  TVector3& start, TVector3& end, TVector3& startmom, TVector3& endmom,
361  unsigned int tpc, unsigned int cstat) const
362 {
363  // Need the readout window size...
364  // double readOutWindowSize = fDetectorProperties->ReadOutWindowSize();
365 
366  double result = 0.;
367  TVector3 disp;
368  int n = part.NumberTrajectoryPoints();
369  bool first = true;
370 
371  // The following for debugging purposes
372  int findTrackID(-1);
373 
374  if (part.TrackId() == findTrackID) std::cout << ">>> length, mcpart: " << part << std::endl;
375 
376  // Loop over the complete collection of trajectory points
377  for(int i = 0; i < n; ++i)
378  {
379  TVector3 posInTPC(0.,0.,0.);
380  TVector3 posVec = part.Position(i).Vect();
381  double pos[] = {posVec.X(),posVec.Y(),posVec.Z()};
382 
383  // Try identifying the TPC we are in
384  unsigned int tpc(0);
385  unsigned int cstat(0);
386 
387  // Need to make sure this position is in an active region of the TPC
388  // If the particle is not in the cryostat then we skip
389  try
390  {
391  const geo::TPCGeo& tpcGeo = fGeometry->PositionToTPC(pos, tpc, cstat);
392 
393  TVector3 activePos = posVec - tpcGeo.GetActiveVolumeCenter();
394 
395  if (part.TrackId() == findTrackID)
396  std::cout << " --> traj point: " << i << ", pos: " << posVec.X() << "/" << posVec.Y() << "/" << posVec.Z() << ", active pos: " << activePos.X() << "/" << activePos.Y() << "/" << activePos.Z() << std::endl;
397 
398  if (std::fabs(activePos.X()) > tpcGeo.ActiveHalfWidth() || std::fabs(activePos.Y()) > tpcGeo.ActiveHalfHeight() || std::fabs(activePos.Z()) > 0.5 * tpcGeo.ActiveLength()) continue;
399 
400  posInTPC = TVector3(activePos.X() + tpcGeo.ActiveHalfWidth(), activePos.Y(), activePos.Z());
401  } catch(...) {continue;}
402 
403  // Make fiducial cuts.
404  // There are two sets here:
405  // 1) We check the original x,y,z position of the trajectory points and require they be
406  // within the confines of the physical TPC
407  // 2) We then check the timing of the presumed hit and make sure it lies within the
408  // readout window for this simulation
409  pos[0] += dx;
410  double ticks = fDetectorProperties->ConvertXToTicks(posInTPC.X(), 0, tpc, cstat);
411 
412  if (part.TrackId() == findTrackID)
413  std::cout << " ==> tpc: " << tpc << ", cstat: " << cstat << ", ticks: " << ticks << std::endl;
414 
415  // Currently it appears that the detector properties are not getting initialized properly and the returned
416  // number of ticks is garbage so we need to skip this for now. Will be important when we get CR's
417 // if(ticks >= 0. && ticks < readOutWindowSize)
418  {
419  if(first)
420  {
421  start = pos;
422  startmom = part.Momentum(i).Vect();
423  }
424  else
425  {
426  disp -= pos;
427  result += disp.Mag();
428  }
429  first = false;
430  disp = pos;
431  end = pos;
432  endmom = part.Momentum(i).Vect();
433  }
434 
435  if (part.TrackId() == findTrackID)
436  {
437  try
438  {
439  std::cout << ">>> Track #" << findTrackID << ", pos: " << posVec.X() << ", " << posVec.Y() << ", " << posVec.Z() << ", ticks: " << ticks << ", nearest Y wire: ";
440  geo::WireID wireID = fGeometry->NearestWireID(pos, 2);
441  std::cout << wireID << std::endl;
442  }
443  catch(...) {}
444  }
445  }
446 
447  return result;
448 }
double std(const std::vector< short > &wf, const double ped_mean, size_t start, size_t nsample)
Definition: UtilFunc.cxx:42
Point GetActiveVolumeCenter() const
Returns the center of the TPC active volume in world coordinates [cm].
Definition: TPCGeo.h:288
const geo::GeometryCore * geometry
double ActiveHalfHeight() const
Half height (associated with y coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:99
Declaration of signal hit object.
Geometry information for a single TPC.
Definition: TPCGeo.h:38
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
process_name use argoneut_mc_hitfinder track
process_name hit
Definition: cheaterreco.fcl:51
tick ticks
Alias for common language habits.
Definition: electronics.h:78
geo::TPCGeo const & PositionToTPC(geo::Point_t const &point) const
Returns the TPC at specified location.
double Length(size_t p=0) const
Access to various track properties.
double ActiveHalfWidth() const
Half width (associated with x coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:95
std::unique_ptr< detinfo::DetectorPropertiesData const > fDetectorProperties
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
Description of geometry of one entire detector.
double ActiveLength() const
Length (associated with z coordinate) of active TPC volume [cm].
Definition: TPCGeo.h:103
geo::WireID NearestWireID(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the ID of wire closest to position in the specified TPC.
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
BEGIN_PROLOG could also be cout
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
void setup(const geo::GeometryCore &, const detinfo::DetectorPropertiesData &, TDirectory *)