RecoEff_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: RecoEff
3 // Module Type: analyzer
4 // File: RecoEff_module.cc
5 // Author: D.Stefan and R.Sulej
6 // Modified by: Jake Calcutt
7 //
8 ////////////////////////////////////////////////////////////////////////
9 
17 #include "art_root_io/TFileService.h"
19 #include "fhiclcpp/types/Atom.h"
22 
23 #include "canvas/Persistency/Common/FindManyP.h"
24 #include "canvas/Persistency/Common/FindMany.h"
25 #include "canvas/Persistency/Common/FindOne.h"
26 #include "canvas/Persistency/Common/FindOneP.h"
27 
40 
41 #include "TH1.h"
42 #include "TH2.h"
43 #include "TEfficiency.h"
44 #include "TTree.h"
45 #include "TVector3.h"
46 
47 
48 /*#ifndef PARTTREE
49  #define PARTTREE
50 #endif
51 
52 #ifndef IDETREE
53  #define IDETREE
54 #endif
55 */
56 
57 namespace pdune
58 {
59  class RecoEff;
60 }
61 
63 public:
64 
66 
67  struct Config {
68  using Name = fhicl::Name;
70 
71  fhicl::Atom<art::InputTag> SimulationLabel { Name("SimulationLabel"), Comment("tag of simulation producer") };
72 
73  fhicl::Atom<art::InputTag> HitModuleLabel { Name("HitModuleLabel"), Comment("tag of hits producer") };
74 
75  fhicl::Atom<art::InputTag> TrackModuleLabel { Name("TrackModuleLabel"), Comment("tag of track producer") };
76 
77  fhicl::Atom<size_t> MinHitsPerPlane { Name("MinHitsPerPlane"), Comment("min hits per plane for a reconstructable MC particle") };
78 
79  fhicl::Sequence<std::string> Filters { Name("Filters"), Comment("on which particles the efficiency is calculated") };
80 
81  fhicl::Sequence<int> Pdg { Name("Pdg"), Comment("which PDG code, or 0 for all particles") };
82 
83  fhicl::Atom<size_t> EffHitMax { Name("EffHitMax"), Comment("max hits per MC particle in the track efficiency") };
84  fhicl::Atom<size_t> EffHitBins { Name("EffHitBins"), Comment("number of bins in the track efficiency") };
85 
86  fhicl::Atom<size_t> EffEMax { Name("EffEMax"), Comment("max hits per MC particle in the track efficiency") };
87  fhicl::Atom<size_t> EffEBins { Name("EffEBins"), Comment("number of bins in the track efficiency") };
88 
89  fhicl::Atom<size_t> EffDepMax { Name("EffDepMax"), Comment("max hits per MC particle in the track efficiency") };
90  fhicl::Atom<size_t> EffDepBins { Name("EffDepBins"), Comment("number of bins in the track efficiency") };
91 
92  fhicl::Atom<size_t> EffLengthMax { Name("EffLengthMax"), Comment("max hits per MC particle in the track efficiency") };
93  fhicl::Atom<size_t> EffLengthBins { Name("EffLengthBins"), Comment("number of bins in the track efficiency") };
94 
95  fhicl::Atom<size_t> EnableParticleTree { Name("EnableParticleTree"), Comment("Turn on saving Particle Tree") };
96  fhicl::Atom<size_t> EnableIDETree { Name("EnableIDETree"), Comment("Turn on saving IDE Tree") };
97 
98  };
100 
101  explicit RecoEff(Parameters const& config);
102 
103  RecoEff(RecoEff const &) = delete;
104  RecoEff(RecoEff &&) = delete;
105  RecoEff & operator = (RecoEff const &) = delete;
106  RecoEff & operator = (RecoEff &&) = delete;
107 
108  void analyze(art::Event const & evt) override;
109  void beginJob() override;
110  void endJob() override;
111 
112 private:
113  void ResetVars();
114  double GetLengthInTPC(detinfo::DetectorClocksData const& clockData,
115  simb::MCParticle part);
116  TVector3 GetPositionInTPC(detinfo::DetectorClocksData const& clockData,
117  simb::MCParticle part, int MCHit);
118  double GetdEdX(simb::MCTrajectory traj, size_t this_step);
119 
122 
125 
128 
131 
132  TTree *fEventTree;
133  TTree *fTrkTree;
134  //TTree *fHitTree; // unused
135 
136  TTree *fTrkIDETree;
138 
139  int fRun, fEvent;
142  short fMatched;
143 
144  float fEnGen, fEkGen;
145  float fT0;
146 
147  float fTrkPurityPerPlane[3], fTrkCompletnessPerPlane[3]; // fixed size, don't expect more than 3 planes, less is OK
148  float fTrkPurity, fTrkCompletness; // all planes together
149  int fTrkPid;
150  short fTrkSize;
151  short fTrkMatched;
152  double fTrkLength;
153  int fTrkID;
154  double fTrkEnergy;
155  double fTrkX[10000];
156  double fTrkY[10000];
157  double fTrkZ[10000];
158  double fT0Corr[10000];
159  int nT0s;
160 
161  std::vector<int> fTrkIDEs;
163  std::vector<double> fTrkContribs;
164 
165  double fTrueTrkE;
167  double fTrueTrkDep;
172  double fTrueTrkdEdX[10000];
173  double fTrueTrkStepE[10000];
174  double fTrueTrkX[10000];
175  double fTrueTrkY[10000];
176  double fTrueTrkZ[10000];
179 
180 
183  std::vector<int> fTrueTrkRecos;
185  std::vector<double> fTrueTrkContribs;
186 
187  double MCTruthT0, TickT0;
188  TH1D* fHitDx;
189  TH1D* fHitDy;
190  TH1D* fHitDz;
191  TH1D* fHitDist3D;
192 
197 
199 
200  std::vector< EFilterMode > fFilters;
201  std::vector< int > fPdg;
202 
208 
209 
211  int fPartPID;
212  int fPartID;
213  int fOrigin;
214  double fPartLength;
215  double fTotLength;
218 
220  double XDriftVelocity{};
221  double WindowSize{};
222 };
223 
225  fSimulationLabel(config().SimulationLabel()),
226  fHitModuleLabel(config().HitModuleLabel()),
228 
229 
230  fMinHitsPerPlane(config().MinHitsPerPlane()),
231  fPdg(config().Pdg()),
232  fEffHitMax(config().EffHitMax()),
233  fEffHitBins(config().EffHitBins()),
234 
235  fEffEMax(config().EffEMax()),
236  fEffEBins(config().EffEBins()),
237 
238  fEffDepMax(config().EffDepMax()),
239  fEffDepBins(config().EffDepBins()),
240 
241  fEffLengthMax(config().EffLengthMax()),
242  fEffLengthBins(config().EffLengthBins()),
243 
245  fEnableIDETree(config().EnableIDETree())
246 // fEnableParticleTree(config().EnableParticleTree),
247 // fEnableIDETree(config().EnableIDETree)
248 
249 {
250  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataForJob();
251  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService>()->DataForJob(clockData);
252  XDriftVelocity = detProp.DriftVelocity()*1e-3; //cm/ns
253  WindowSize = detProp.NumberTimeSamples() * clockData.TPCClock().TickPeriod() * 1e3;
254 
255  auto flt = config().Filters();
256  for (const auto & s : flt)
257  {
258  if (s == "cosmic") { fFilters.push_back(pdune::RecoEff::kCosmic); }
259  else if (s == "beam") { fFilters.push_back(pdune::RecoEff::kBeam); }
260  else if (s == "primary") { fFilters.push_back(pdune::RecoEff::kPrimary); }
261  else if (s == "second") { fFilters.push_back(pdune::RecoEff::kSecondary); }
262  else { std::cout << "unsupported filter name: " << s << std::endl; }
263  }
264 }
265 
267 {
269 
270  fDenominatorHist = tfs->make<TH1D>("Denominator", "all reconstructable particles", fEffHitBins, 0., fEffHitMax);
271  fNominatorHist = tfs->make<TH1D>("Nominator", "reconstructed and matched tracks", fEffHitBins, 0., fEffHitMax);
272 
273  fEnergyDenominatorHist = tfs->make<TH1D>("EnergyDenominator", "all reconstructable particles", fEffEBins, 0., fEffEMax);
274  fEnergyNominatorHist = tfs->make<TH1D>("EnergyNominator", "reconstructed and matched tracks", fEffEBins, 0., fEffEMax);
275 
276  fLengthDenominatorHist = tfs->make<TH1D>("LengthDenominator", "all reconstructable particles", fEffLengthBins, 0., fEffLengthMax);
277  fLengthNominatorHist = tfs->make<TH1D>("LengthNominator", "reconstructed and matched tracks", fEffLengthBins, 0., fEffLengthMax);
278 
279  fDepDenominatorHist = tfs->make<TH1D>("DepDenominator", "all reconstructable particles", fEffDepBins, 0., fEffDepMax);
280  fDepNominatorHist = tfs->make<TH1D>("DepNominator", "reconstructed and matched tracks", fEffDepBins, 0., fEffDepMax);
281 
282  fEventTree = tfs->make<TTree>("events", "summary tree");
283  fEventTree->Branch("fRun", &fRun, "fRun/I");
284  fEventTree->Branch("fEvent", &fEvent, "fEvent/I");
285  fEventTree->Branch("fEnGen", &fEnGen, "fEnGen/F");
286  fEventTree->Branch("fEkGen", &fEkGen, "fEkGen/F");
287  fEventTree->Branch("fT0", &fT0, "fT0/F");
288  fEventTree->Branch("fNRecoTracks", &fNRecoTracks, "fNRecoTracks/S");
289  fEventTree->Branch("fReconstructable", &fReconstructable, "fReconstructable/S");
290  fEventTree->Branch("fMatched", &fMatched, "fMatched/S");
291 
292  fTrkTree = tfs->make<TTree>("tracks", "track metrics");
293  fTrkTree->Branch("fTrkPurity", &fTrkPurity, "fTrkPurity/F");
294  fTrkTree->Branch("fTrkCompletness", &fTrkCompletness, "fTrkCompletness/F");
295  fTrkTree->Branch("fTrkPurityPerPlane", &fTrkPurityPerPlane, "fTrkPurityPerPlane[3]/F");
296  fTrkTree->Branch("fTrkCompletnessPerPlane", &fTrkCompletnessPerPlane, "fTrkCompletnessPerPlane[3]/F");
297  fTrkTree->Branch("fTrkPid", &fTrkPid, "fTrkPid/I");
298  fTrkTree->Branch("fTrkID", &fTrkID, "fTrkID/I");
299  fTrkTree->Branch("fTrkSize", &fTrkSize, "fTrkSize/S");
300  fTrkTree->Branch("fTrkMatched", &fTrkMatched, "fTrkMatched/S");
301  fTrkTree->Branch("fTrkLength", &fTrkLength, "fTrkLength/D");
302  fTrkTree->Branch("fTrkIDEs", &fTrkIDEs);
303  fTrkTree->Branch("fTrkContribs", &fTrkContribs);
304  fTrkTree->Branch("fTrkNIDEs", &fTrkNIDEs);
305  fTrkTree->Branch("fEvent", &fEvent);
306  fTrkTree->Branch("fTrkEnergy", &fTrkEnergy);
307  fTrkTree->Branch("fTrkX", &fTrkX, "fTrkX[10000]/D");
308  fTrkTree->Branch("fTrkY", &fTrkY, "fTrkY[10000]/D");
309  fTrkTree->Branch("fTrkZ", &fTrkZ, "fTrkZ[10000]/D");
310  fTrkTree->Branch("fT0Corr", &fT0Corr, "fT0Corr[10000]/D");
311  fTrkTree->Branch("nT0s", &nT0s);
312 
314  fParticleTree = tfs->make<TTree>("particles","Particles");
315 
316  fParticleTree->Branch("fPID",&fPartPID);
317  fParticleTree->Branch("fStatus",&fPartStatus);
318  fParticleTree->Branch("fID",&fPartID);
319  fParticleTree->Branch("fLength",&fPartLength);
320  fParticleTree->Branch("fTotLength",&fTotLength);
321  fParticleTree->Branch("fEvent",&fEvent);
322  fParticleTree->Branch("fOrigin",&fOrigin);
323  fParticleTree->Branch("fProcess",&fProcess);
324  fParticleTree->Branch("fEndProcess",&fEndProcess);
325  }
326 
327  if(fEnableIDETree){
328  fTrkIDETree = tfs->make<TTree>("trackIDEs","trackIDE metrics");
329 
330  fTrkIDETree->Branch("fTrkE", &fTrueTrkE, "fTrkE/D");
331  fTrkIDETree->Branch("fTrkLength", &fTrueTrkLength, "fTrkLength/D");
332  fTrkIDETree->Branch("fTrkDep", &fTrueTrkDep, "fTrkDep/D");
333  fTrkIDETree->Branch("fTrkPID", &fTrueTrkPID, "fTrkPID/I");
334  fTrkIDETree->Branch("fTrkID", &fTrueTrkID, "fTrkID/I");
335  fTrkIDETree->Branch("fTrkSize", &fTrueTrkSize, "fTrkSize/I");
336  fTrkIDETree->Branch("fTrkX", &fTrueTrkX, "fTrkX[10000]/D");
337  fTrkIDETree->Branch("fTrkY", &fTrueTrkY, "fTrkY[10000]/D");
338  fTrkIDETree->Branch("fTrkZ", &fTrueTrkZ, "fTrkZ[10000]/D");
339  fTrkIDETree->Branch("fT0Corr", &fT0Corr, "fT0Corr[10000]/D");
340  fTrkIDETree->Branch("fTrkdEdX", &fTrueTrkdEdX, "fTrkdEdX[10000]/D");
341  fTrkIDETree->Branch("fTrkStepE", &fTrueTrkStepE, "fTrkStepE[10000]/D");
342  fTrkIDETree->Branch("fTrkSteps", &track_step, "fTrkSteps/D");
343  fTrkIDETree->Branch("fEvent", &fEvent, "fEvent/I");
344  fTrkIDETree->Branch("fTrkOrigin",&fTrueTrkOrigin);
345  fTrkIDETree->Branch("fTrkRecoGuess", &fTrueTrkRecoGuess);
346  fTrkIDETree->Branch("fTrkEnergyGuess",&fTrueTrkEnergyGuess);
347  fTrkIDETree->Branch("fTrkRecos", &fTrueTrkRecos);
348  fTrkIDETree->Branch("fTrkNRecos", &fTrueTrkNRecos);
349  fTrkIDETree->Branch("fTrkContribs", &fTrueTrkContribs);
350  fTrkIDETree->Branch("fTrkCrossCPA", &fTrueTrkCrossCPA);
351  }
352 
353  fHitDist3D = tfs->make<TH1D>("HitD3D", "MC-reco 3D distance", 400, 0., 10.0);
354  fHitDx = tfs->make<TH1D>("HitDx", "MC-reco X distance", 400, 0., 10.0);
355  fHitDy = tfs->make<TH1D>("HitDy", "MC-reco Y distance", 400, 0., 10.0);
356  fHitDz = tfs->make<TH1D>("HitDz", "MC-reco Z distance", 400, 0., 10.0);
357 
358  //Need to correct for name in space point branch
359  if(fTrackModuleLabel == "pandoraTrack"){
360  fTempTrackModuleLabel = "pandora";
361  }
362  else{
364  }
365 }
366 
368 {
369  for (int i = 0; i < fDenominatorHist->GetNbinsX(); ++i)
370  {
371  double nom = fNominatorHist->GetBinContent(i);
372  double den = fDenominatorHist->GetBinContent(i);
373  std::cout << "nhits: " << i << " nom:" << nom << " den:" << den << std::endl;
374  if (nom > den) { fNominatorHist->SetBinContent(i, den); }
375  }
377  TEfficiency* fEfficiency = tfs->makeAndRegister<TEfficiency>("Efficiency", "tracking efficiency", *fNominatorHist, *fDenominatorHist);
378  TEfficiency* fEnergyEfficiency = tfs->makeAndRegister<TEfficiency>("EnergyEfficiency", "tracking efficiency", *fEnergyNominatorHist, *fEnergyDenominatorHist);
379  std::cout << "Efficiency created: " << fEfficiency->GetTitle() << " " << fEnergyEfficiency->GetTitle() << std::endl;
380  TEfficiency* fLengthEfficiency = tfs->makeAndRegister<TEfficiency>("LengthEfficiency", "tracking efficiency", *fLengthNominatorHist, *fLengthDenominatorHist);
381  std::cout << "Efficiency created: " << fEfficiency->GetTitle() << " " << fLengthEfficiency->GetTitle() << std::endl;
382  TEfficiency* fDepEfficiency = tfs->makeAndRegister<TEfficiency>("DepEfficiency", "tracking efficiency", *fDepNominatorHist, *fDepDenominatorHist);
383  std::cout << "Efficiency created: " << fEfficiency->GetTitle() << " " << fDepEfficiency->GetTitle() << std::endl;
384 
385 }
386 
388 {
389  ResetVars();
390 
391  fRun = evt.run();
392  fEvent = evt.id().event();
393 
396 
397  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(evt);
398  auto const detProp = art::ServiceHandle<detinfo::DetectorPropertiesService>()->DataFor(evt, clockData);
399 
401  //Particle List diagnostics
402  const sim::ParticleList& plist = pi_serv->ParticleList();
403  for ( sim::ParticleList::const_iterator ipar = plist.begin(); ipar!=plist.end(); ++ipar){
404 
405  simb::MCParticle * part = ipar->second;
406 
407  fPartPID = part->PdgCode();
408  if(fPartPID > 2212) {continue;}
409 
410  fPartStatus = part->StatusCode();
411  fPartID = part->TrackId();
412  fPartLength = GetLengthInTPC(clockData, *part);
413  fTotLength = part->Trajectory().TotalLength();
414  fProcess = part->Process();
415  fEndProcess = part->EndProcess();
416  fOrigin = pi_serv->ParticleToMCTruth_P(part)->Origin();
417 
418  fParticleTree->Fill();
419  }
420  }
421 
422  // we are going to look only for these MC truth particles, which contributed to hits
423  // and normalize efficiency to things which indeed generated activity and hits in TPC's:
424  // - need a vector of hits associated to these MC particles,
425  // - need the energy deposit corresponding to the particle part seen i these hits.
426  std::unordered_map<int, std::vector<recob::Hit> > mapTrackIDtoHits;
427  std::unordered_map<int, double> mapTrackIDtoHitsEnergyPerPlane[3];
428  std::unordered_map<int, double> mapTrackIDtoHitsEnergy;
429 
430  std::unordered_map<int, double> mapTrackIDtoLength;
431  const auto hitListHandle = evt.getValidHandle< std::vector<recob::Hit> >(fHitModuleLabel);
432  for (auto const & h : *hitListHandle)
433  {
434  std::unordered_map<int, double> particleID_E;
435 
436  for (auto const & id : bt_serv->HitToTrackIDEs(clockData,h)) // loop over std::vector< sim::TrackIDE > contributing to hit h
437  {
438 
439  // select only hadronic and muon track, skip EM activity (electron's pdg, negative track id)
440  if ((id.trackID > 0) && (abs((pi_serv->TrackIdToParticle_P(id.trackID))->PdgCode()) != 11))
441  {
442  particleID_E[id.trackID] += id.energy;
443  const simb::MCParticle * part = pi_serv->TrackIdToParticle_P(id.trackID);
444  mapTrackIDtoLength[id.trackID] = GetLengthInTPC(clockData, *part);
445  }
446  }
447 
448  int best_id = 0;
449  double max_e = 0;
450  for (auto const & contrib : particleID_E)
451  {
452  if (contrib.second > max_e) // find particle TrackID corresponding to max energy contribution
453  {
454  max_e = contrib.second;
455  best_id = contrib.first;
456  }
457  }
458 
459  if (max_e > 0)
460  {
461  mapTrackIDtoHits[best_id].push_back(h);
462  mapTrackIDtoHitsEnergyPerPlane[h.WireID().Plane][best_id] += max_e;
463  mapTrackIDtoHitsEnergy[best_id] += max_e;
464  }
465  }
466 
467  // ---------------------------------------------------------------------------------------
468 
469 
470  // now lets map particles to their associated hits, but with some filtering of things
471  // which have a minimal chance to be reconstructed: so at least some hits in two views
472  std::unordered_map<int, std::vector< recob::Hit >> mapTrackIDtoHits_filtered;
473  for (auto const & p : mapTrackIDtoHits)
474  {
475  bool skip = false;
476  auto origin = pi_serv->TrackIdToMCTruth_P(p.first)->Origin();
477  for (auto f : fFilters)
478  {
479  switch (f)
480  {
481  case pdune::RecoEff::kCosmic: if (origin != simb::kCosmicRay) { skip = true; } break;
482  case pdune::RecoEff::kBeam: if (origin != simb::kSingleParticle) { skip = true; } break;
483 
485  if (pi_serv->TrackIdToParticle_P(p.first)->Process() != "primary") { skip = true; }
486  break;
487 
489  {
490  int mId = pi_serv->TrackIdToParticle_P(p.first)->Mother();
491  const simb::MCParticle * mother = pi_serv->TrackIdToParticle_P(mId);
492  if ((mother == 0) || (mother->Process() != "primary")) { skip = true; }
493  break;
494  }
495 
496  default: break;
497  }
498  }
499  if (skip) { continue; } // skip if any condition failed
500 
501  if (!fPdg.empty())
502  {
503  skip = true;
504  for (int code : fPdg) { if (pi_serv->TrackIdToParticle_P(p.first)->PdgCode() == code) { skip = false; break; } }
505  if (skip) { continue; } // skip only if no PDG is matching
506  }
507 
508  std::unordered_map<geo::View_t, size_t> hit_count;
509  for (auto const & h : p.second) { hit_count[h.View()]++; }
510 
511  size_t nviews = 0;
512  for (auto const & n : hit_count) { if (n.second > fMinHitsPerPlane) { nviews++; } }
513  if (nviews >= 2)
514  {
515  // passed all conditions, move to filtered maps
516  mapTrackIDtoHits_filtered.emplace(p);
517  }
518  }
519  fReconstructable = mapTrackIDtoHits_filtered.size();
520 
521  std::cout << "------------ event: " << fEvent << " has reconstructable: " << fReconstructable << std::endl;
522  for (auto const &p : mapTrackIDtoHits_filtered)
523  {
524 
525  //Want to get the initial energy of the particle
526  int this_code = pi_serv->TrackIdToParticle_P(p.first)->PdgCode();
527  double this_energy = pi_serv->TrackIdToParticle_P(p.first)->E(0);
528  double this_length = mapTrackIDtoLength[p.first];
529 
530  std::cout << " : id " << p.first << " size " << p.second.size() << " en: " << mapTrackIDtoHitsEnergy[p.first] << " init en: " << this_energy << " PDG: " << this_code << " Length: " << this_length << std::endl;
531 
532  fDenominatorHist->Fill(p.second.size());
533  fEnergyDenominatorHist->Fill(this_energy);
534  fLengthDenominatorHist->Fill(this_length);
535  fDepDenominatorHist->Fill(mapTrackIDtoHitsEnergy[p.first]);
536  }
537  // ---------------------------------------------------------------------------------------
538 
539 
540  // match reconstructed tracks to MC particles
541  const auto trkHandle = evt.getValidHandle< std::vector<recob::Track> >(fTrackModuleLabel);
542  fNRecoTracks = trkHandle->size();
543 
544 
545  art::FindManyP< recob::Hit > hitsFromTracks(trkHandle, evt, fTrackModuleLabel);
546  art::FindManyP< recob::SpacePoint > spFromHits(hitListHandle, evt, fTempTrackModuleLabel);
547 // art::FindMany< anab::T0 > t0sFromTracks(trkHandle, evt, fTempTrackModuleLabel );
548 
549 
550  //Make map from G4Track (IDE) ID to track index
551  std::unordered_map<int, int> mapIDEtoRecoTrack;
552  std::unordered_map<int, double> mapIDEtoRecoEnergy;
553  std::unordered_map<int, std::vector< std::pair<int, double > > > mapIDEtoTrackContribs;
554 
555  for (size_t t = 0; t < trkHandle->size(); ++t) // loop over tracks
556  {
557  // *** here you should select if the reconstructed track is interesting, eg:
558  // - associated PFParticle has particlular PDG code
559  // - or just the recob::Track has interesting ParticleID
560 
561  std::unordered_map<int, double> trkID_E_perPlane[3]; // map filtered MC particles to their energy contributed to track t in each plane
562  std::unordered_map<int, double> trkID_E; // map filtered MC particles to their energy contributed to track t
563  double totE_anyMC_inPlane[3] = { 0, 0, 0 };
564  double totE_anyMC = 0;
565  const auto & hits = hitsFromTracks.at(t);
566  for (const auto & h : hits) // loop over hits assigned to track t
567  {
568  size_t plane = h->WireID().Plane;
569  for (auto const & ide : bt_serv->HitToTrackIDEs(clockData, h)) // loop over std::vector< sim::TrackIDE >, for a hit h
570  {
571  if (mapTrackIDtoHits_filtered.find(ide.trackID) != mapTrackIDtoHits_filtered.end())
572  {
573  trkID_E_perPlane[plane][ide.trackID] += ide.energy; // ...and sum energies contributed to this reco track
574  trkID_E[ide.trackID] += ide.energy; // by MC particles which we considered as reconstructable
575  }
576  totE_anyMC_inPlane[plane] += ide.energy;
577  totE_anyMC += ide.energy;
578  }
579  }
580 
581  // find MC particle which cotributed maximum energy to track t
582  int best_id = 0;
583  double max_e = 0;
584  std::array< double, 3 > e_inPlane = {{ 0, 0, 0 }};
585  for (auto const & entry : trkID_E)
586  {
587  mapIDEtoTrackContribs[entry.first].push_back(std::make_pair(t, entry.second));
588  fTrkIDEs.push_back(entry.first);
589  fTrkContribs.push_back(entry.second);
590  if (entry.second > max_e) // find track ID corresponding to max energy
591  {
592  max_e = entry.second;
593  best_id = entry.first;
594 
595  for (size_t i = 0; i < 3; ++i)
596  {
597  e_inPlane[i] = trkID_E_perPlane[i][entry.first];
598  }
599  }
600  }
601  //'Best guess'
602  if(max_e == 0){
603  mapIDEtoRecoTrack[best_id] = -1;
604  }
605  else{
606  mapIDEtoRecoTrack[best_id] = t;
607  }
608  mapIDEtoRecoEnergy[best_id] = max_e;
609 
610  // check if reco track is matching to MC particle:
611  if ((max_e > 0.5 * totE_anyMC) && // MC particle has more than 50% energy contribution to the track
612  (max_e > 0.5 * mapTrackIDtoHitsEnergy[best_id])) // track covers more than 50% of energy deposited by MC particle in hits
613  {
614  fNominatorHist->Fill(mapTrackIDtoHits_filtered[best_id].size());
615 
616  double this_length = mapTrackIDtoLength[best_id];
617 
618  //Get Energy of this track
619  std::cout << " id: " << best_id << " init energy: " << pi_serv->TrackIdToParticle_P(best_id)->E(0) << " Length: " << this_length << std::endl;
620  fEnergyNominatorHist->Fill(pi_serv->TrackIdToParticle_P(best_id)->E(0));
621  fLengthNominatorHist->Fill(this_length);
622  fDepNominatorHist->Fill(mapTrackIDtoHitsEnergy[best_id]);
623  fTrkMatched = 1; fMatched++;
624  }
625  else { fTrkMatched = 0; }
626 
627  fTrkPurity = max_e / totE_anyMC;
628  fTrkCompletness = max_e / mapTrackIDtoHitsEnergy[best_id];
629  for (size_t i = 0; i < 3; ++i)
630  {
631  if (totE_anyMC_inPlane[i] > 0) { fTrkPurityPerPlane[i] = e_inPlane[i] / totE_anyMC_inPlane[i]; }
632  else { fTrkPurityPerPlane[i] = 0; }
633 
634  if (mapTrackIDtoHitsEnergyPerPlane[i][best_id] > 0) { fTrkCompletnessPerPlane[i] = e_inPlane[i] / mapTrackIDtoHitsEnergyPerPlane[i][best_id]; }
635  else fTrkCompletnessPerPlane[i] = 0;
636  }
637 
638  fTrkPid = (*trkHandle)[t].ParticleId();
639  fTrkSize = hits.size();
640  fTrkLength = (*trkHandle)[t].Length();
641  fTrkID = t;
642  fTrkEnergy = totE_anyMC;
643 
644  //T0 stuff
645 // std::vector<const anab::T0*> T0s = t0sFromTracks.at(t);
646  std::vector<const anab::T0*> T0s;
647  nT0s = T0s.size();
648  std::cout << "Got " << nT0s << " T0s" <<std::endl;
649 
650  if(nT0s > 0){
651  std::cout << "T0s size: " << nT0s << std::endl;
652  MCTruthT0 = T0s[0]->Time();
653  }
654  else{
655  std::cout << "No T0s found" << std::endl;
656  MCTruthT0 = 0;
657  }
658  TickT0 = MCTruthT0 / sampling_rate(clockData);
659 
660 
661  int track_step = 0;
662  for(auto const & pos : (((*trkHandle)[t].Trajectory()).Trajectory()).Positions()){
663  if (track_step > 9999) break;
664 // fTrkX[track_step] = pos.X(); //need to correct t0
665  auto const this_wire = hits[hits.size() - (1 + track_step)]->WireID();
666  double t0Correction = detProp.ConvertTicksToX( TickT0, this_wire.Plane, this_wire.TPC, this_wire.Cryostat );
667  std::cout << "Correction: " << t0Correction << " " << sampling_rate(clockData) << std::endl;
668  fT0Corr[track_step] = t0Correction;
669  fTrkX[track_step] = (pos.X()/* - t0Correction*/);
670  fTrkY[track_step] = pos.Y();
671  fTrkZ[track_step] = pos.Z();
672  track_step++;
673  }
674 
675  fTrkNIDEs = fTrkIDEs.size();
676  fTrkTree->Fill();
677  for(int track_step = 0; track_step < 10000; ++track_step){
678  fTrkX[track_step] = 0;
679  fTrkY[track_step] = 0;
680  fTrkZ[track_step] = 0;
681  }
682 
683  fTrkIDEs.clear();
684  fTrkContribs.clear();
685 
686 
687  if (fTrkMatched == 1)
688  {
689  for (const auto & h : hits) // loop over hits assigned to matched track
690  {
691  const auto & sps = spFromHits.at(h.key());
692  if (sps.empty()) { continue; }
693  const auto & sp = *sps.front();
694 
695  std::vector< sim::IDE > ides = bt_serv->HitToAvgSimIDEs(clockData, *h);
696 
697  std::array< double, 3 > hitpos = {{0, 0, 0}};
698  double hitE = 0;
699  for (auto const & ide : ides)
700  {
701  if (ide.trackID == best_id)
702  {
703  hitpos[0] += ide.x * ide.energy;
704  hitpos[1] += ide.y * ide.energy;
705  hitpos[2] += ide.z * ide.energy;
706  hitE += ide.energy;
707  }
708  }
709  if (hitE > 0)
710  {
711  hitpos[0] /= hitE; hitpos[1] /= hitE; hitpos[2] /= hitE;
712  double dx = 0; // sp.XYZ()[0] - hitpos[0]; // --- need t0 correction
713  double dy = sp.XYZ()[1] - hitpos[1];
714  double dz = sp.XYZ()[2] - hitpos[2];
715  //fHitDx->Fill(dx); // --- need t0 correction
716  fHitDy->Fill(dy);
717  fHitDz->Fill(dz);
718  fHitDist3D->Fill(sqrt(dx*dx + dy*dy + dz*dz));
719  }
720  }
721  }
722  }
723 
724  if(fEnableIDETree){
725  std::cout << "IDE Tree"<< std::endl;
726  //Note: mapTrackIDtoHits -> filtered?
727  //Add in branch that includes the 'max_e' from above
728  //as well as 'best guess' reco track
729  //keep thinking about this
730  for (auto const & p : mapTrackIDtoHits_filtered)
731  {
732  fTrueTrkID = p.first;
733  fTrueTrkSize = p.second.size();
734  const simb::MCParticle * part = pi_serv->TrackIdToParticle_P(fTrueTrkID);
735  fTrueTrkE = part->E(0);
736  fTrueTrkLength = mapTrackIDtoLength[fTrueTrkID];
737  fTrueTrkDep = mapTrackIDtoHitsEnergy[fTrueTrkID];
738  fTrueTrkPID = part->PdgCode();
739 
741 
742  fTrueTrkRecoGuess = mapIDEtoRecoTrack[p.first];
743  fTrueTrkEnergyGuess = mapIDEtoRecoEnergy[p.first];
744 
745  std::vector<std::pair<int, double>> TrackContribs;
746  TrackContribs = mapIDEtoTrackContribs[p.first];
747  for (auto const & tc : TrackContribs){
748  fTrueTrkRecos.push_back(tc.first);
749  fTrueTrkContribs.push_back(tc.second);
750  }
751 
752  auto const traj = part->Trajectory();
753 
754  track_step = 0;
755  for(size_t step = 0; step < traj.size(); ++step){
756  //Don't know if I need this break, but just to be sure...
757  if (track_step > 9999) break;
758 
759  TVector3 pos = GetPositionInTPC(clockData, *part, step);
760 
761  if( (pos != TVector3(-1,-1,-1)) && (pos != TVector3(0,0,0))){
762  fTrueTrkX[track_step] = pos.X();
763  fTrueTrkY[track_step] = pos.Y();
764  fTrueTrkZ[track_step] = pos.Z();
765  fTrueTrkStepE[track_step] = part->E(step);
766  if(track_step > 0){
767  fTrueTrkdEdX[track_step] = GetdEdX(traj, step);
768  }
769  track_step++;
770  }
771  }
772 
773  if(fTrueTrkX[0] < 0 && fTrueTrkX[track_step - 1] > 0){
774  fTrueTrkCrossCPA = true;
775  }
776  else if(fTrueTrkX[0] > 0 && fTrueTrkX[track_step - 1] < 0){
777  fTrueTrkCrossCPA = true;
778  }
779  else{fTrueTrkCrossCPA = false;}
780 
781  fTrueTrkNRecos = fTrueTrkRecos.size();
782  fTrkIDETree->Fill();
783  for(size_t step = 0; step < 10000; ++step){
784  fTrueTrkX[step] = 0;
785  fTrueTrkY[step] = 0;
786  fTrueTrkZ[step] = 0;
787  fTrueTrkStepE[step] = 0;
788  fTrueTrkdEdX[step] = 0;
789  }
790  fTrueTrkRecos.clear();
791  fTrueTrkContribs.clear();
792  }
793  }
794 
796  {
797  std::cout << "WARNING: matched more reco tracks than selected MC particles: " << fMatched << " > " << fReconstructable << std::endl;
798  }
799 
800 
801  std::cout << "------------ reconstructed: " << fNRecoTracks << " and then matched to MC particles: " << fMatched
802  << " (reconstructable: " << fReconstructable << ")" << std::endl;
803  fEventTree->Fill();
804 }
805 
807 {
808  fRun = 0; fEvent = 0;
809 
810  fEnGen = 0; fEkGen = 0;
811  fT0 = 0;
812 
813  for (size_t i = 0; i < 3; ++i)
814  {
815  fTrkPurityPerPlane[i] = 0;
817  }
818 
819  fTrkPurity = 0; fTrkCompletness = 0;
820  fTrkPid = 0; fTrkSize = 0; fTrkMatched = 0;
821  fTrkLength = 0;
822  fMatched = 0;
823  fNRecoTracks = 0;
824  fReconstructable = 0;
825  fTrkID = 0;
826  fTrkIDEs.clear();
827  fTrkContribs.clear();
828 
829  if(fEnableIDETree){
830  fTrueTrkE = 0;
831  fTrueTrkID = 0;
832  fTrueTrkLength = 0;
833  fTrueTrkDep = 0;
834  fTrueTrkPID = 0;
835  fTrueTrkOrigin = -1;
836  for(size_t i = 0; i < 10000; ++i){
837  fTrueTrkX[i] = 0;
838  fTrueTrkY[i] = 0;
839  fTrueTrkZ[i] = 0;
840  }
841 
842  fTrueTrkRecoGuess = 0;
844  fTrueTrkRecos.clear();
845  fTrueTrkContribs.clear();
846  }
847 
848 
850  fPartStatus = 0;
851  fPartPID = 0;
852  fPartID = 0;
853  fPartLength = 0;
854  fTotLength = 0;
855  fOrigin = -1;
856  fProcess = "";
857  fEndProcess = "";
858  }
859 }
860 
862  const simb::MCParticle part) {
863 
864  unsigned int nTrajectoryPoints = part.NumberTrajectoryPoints();
865  std::vector<double> TPCLengthHits(nTrajectoryPoints,0);
866 
867  bool BeenInVolume = false;
868  int FirstHit = 0, LastHit = 0;
869  double TPCLength = 0;
870 
871  for(unsigned int MCHit=0; MCHit < nTrajectoryPoints; ++MCHit) {
872  const TLorentzVector& tmpPosition = part.Position(MCHit);
873  double const tmpPosArray[] = {tmpPosition[0], tmpPosition[1], tmpPosition[2]};
874 
875  if (MCHit!=0) TPCLengthHits[MCHit] = pow ( pow( (part.Vx(MCHit-1)-part.Vx(MCHit)),2)
876  + pow( (part.Vy(MCHit-1)-part.Vy(MCHit)),2)
877  + pow( (part.Vz(MCHit-1)-part.Vz(MCHit)),2)
878  , 0.5 );
879  // check if in TPC
880  geo::TPCID tpcid = geom->FindTPCAtPosition(tmpPosArray);
881  if(tpcid.isValid){
882  geo::CryostatGeo const & cryo = geom->Cryostat(tpcid.Cryostat);
883  geo::TPCGeo const & tpc = cryo.TPC(tpcid.TPC);
884  double XPlanePosition = tpc.PlaneLocation(0)[0];
885  double DriftTimeCorrection = fabs( tmpPosition[0] - XPlanePosition )/ XDriftVelocity;
886  double TimeAtPlane = part.T() + DriftTimeCorrection;
887  if( TimeAtPlane < trigger_offset(clockData) || TimeAtPlane > trigger_offset(clockData) + WindowSize){
888  continue;}
889  //Good hit in TPC
890  LastHit = MCHit;
891  if( !BeenInVolume ){
892  BeenInVolume = true;
893  FirstHit = MCHit;
894  }
895  }
896  }
897  for (int Hit = FirstHit+1; Hit <= LastHit; ++Hit ) {
898  TPCLength += TPCLengthHits[Hit];
899  }
900  return TPCLength;
901 }
902 
904  const simb::MCParticle part, int MCHit) {
905 
906  const TLorentzVector& tmpPosition = part.Position(MCHit);
907  double const tmpPosArray[] = {tmpPosition[0], tmpPosition[1], tmpPosition[2]};
908 
909  // check if in TPC
910  geo::TPCID tpcid = geom->FindTPCAtPosition(tmpPosArray);
911  if(tpcid.isValid){
912  geo::CryostatGeo const & cryo = geom->Cryostat(tpcid.Cryostat);
913  geo::TPCGeo const & tpc = cryo.TPC(tpcid.TPC);
914  double XPlanePosition = tpc.PlaneLocation(0)[0];
915  double DriftTimeCorrection = fabs( tmpPosition[0] - XPlanePosition )/ XDriftVelocity;
916  double TimeAtPlane = part.T() + DriftTimeCorrection;
917  if( TimeAtPlane < trigger_offset(clockData) || TimeAtPlane > trigger_offset(clockData) + WindowSize){
918  return TVector3(-1,-1,-1);}
919  }
920  else{
921  return TVector3(-1,-1,-1);
922  }
923 
924  TVector3 posInTPC(tmpPosArray);
925  return posInTPC;
926 }
927 
928 double pdune::RecoEff::GetdEdX(const simb::MCTrajectory traj, size_t this_step){
929  size_t prev_step = this_step - 1;
930  size_t next_step = this_step + 1;
931 
932  double dE_prev = fabs( traj.E(this_step) - traj.E(prev_step) );
933  double dE_next = fabs( traj.E(this_step) - traj.E(next_step) );
934 
935  double dX_prev = sqrt( pow( (traj.X(this_step) - traj.X(prev_step)), 2 )
936  + pow( (traj.X(this_step) - traj.X(prev_step)), 2 )
937  + pow( (traj.X(this_step) - traj.X(prev_step)), 2 ));
938 
939  double dX_next = sqrt( pow( (traj.X(this_step) - traj.X(next_step)), 2 )
940  + pow( (traj.X(this_step) - traj.X(next_step)), 2 )
941  + pow( (traj.X(this_step) - traj.X(next_step)), 2 ));
942  return (dE_prev + dE_next)/(dX_prev + dX_next);
943 }
944 
double E(const int i=0) const
Definition: MCParticle.h:233
std::string fProcess
unsigned int NumberTrajectoryPoints() const
Definition: MCParticle.h:218
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
double X(const size_type i) const
Definition: MCTrajectory.h:149
int PdgCode() const
Definition: MCParticle.h:212
double GetLengthInTPC(detinfo::DetectorClocksData const &clockData, simb::MCParticle part)
fhicl::Atom< size_t > EnableIDETree
QList< Entry > entry
fhicl::Atom< size_t > EffDepBins
Encapsulate the construction of a single cyostat.
fhicl::Atom< size_t > EffLengthMax
double E(const size_type i) const
Definition: MCTrajectory.h:156
std::vector< sim::TrackIDE > HitToTrackIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
fhicl::Comment Comment
art::ServiceHandle< geo::Geometry > geom
std::string string
Definition: nybbler.cc:12
const simb::MCTrajectory & Trajectory() const
Definition: MCParticle.h:253
const simb::MCParticle * TrackIdToParticle_P(int id) const
int Mother() const
Definition: MCParticle.h:213
TH1D * fLengthNominatorHist
simb::Origin_t Origin() const
Definition: MCTruth.h:74
constexpr T pow(T x)
Definition: pow.h:72
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
Geometry information for a single TPC.
Definition: TPCGeo.h:38
ChannelGroupService::Name Name
double fTrkX[10000]
double fTrkY[10000]
fhicl::Atom< art::InputTag > SimulationLabel
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
std::vector< int > fTrueTrkRecos
int StatusCode() const
Definition: MCParticle.h:211
fhicl::Atom< size_t > EffLengthBins
intermediate_table::const_iterator const_iterator
std::vector< int > fTrkIDEs
Geometry information for a single cryostat.
Definition: CryostatGeo.h:43
std::vector< EFilterMode > fFilters
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
std::string Process() const
Definition: MCParticle.h:215
Particle class.
fhicl::Atom< size_t > EffEBins
void endJob() override
const art::Ptr< simb::MCTruth > & ParticleToMCTruth_P(const simb::MCParticle *p) const
std::vector< double > fTrueTrkContribs
TH1D * fEnergyDenominatorHist
art framework interface to geometry description
TH1D * fDepNominatorHist
int TrackId() const
Definition: MCParticle.h:210
QCollection::Item first()
Definition: qglist.cpp:807
double fTrkZ[10000]
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
fhicl::Atom< art::InputTag > TrackModuleLabel
T abs(T value)
const double e
int PdgCode(Resonance_t res, int Q)
(resonance id, charge) -> PDG code
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
std::string EndProcess() const
Definition: MCParticle.h:216
art::InputTag fSimulationLabel
static Config * config
Definition: config.cpp:1054
const art::Ptr< simb::MCTruth > & TrackIdToMCTruth_P(int id) const
RecoEff(Parameters const &config)
std::void_t< T > n
single particles thrown at the detector
Definition: MCTruth.h:26
fhicl::Atom< size_t > MinHitsPerPlane
RecoEff & operator=(RecoEff const &)=delete
float fTrkCompletnessPerPlane[3]
fhicl::Sequence< std::string > Filters
std::vector< double > fTrkContribs
double T(const int i=0) const
Definition: MCParticle.h:224
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
fhicl::Atom< size_t > EffHitMax
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
fhicl::Atom< art::InputTag > HitModuleLabel
CodeOutputInterface * code
RunNumber_t run() const
Definition: DataViewImpl.cc:71
double fTrueTrkZ[10000]
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
double fT0Corr[10000]
std::string fEndProcess
double fTrueTrkEnergyGuess
art::InputTag fTempTrackModuleLabel
const sim::ParticleList & ParticleList() const
Encapsulate the geometry of a wire.
TVector3 GetPositionInTPC(detinfo::DetectorClocksData const &clockData, simb::MCParticle part, int MCHit)
void analyze(art::Event const &evt) override
double Vx(const int i=0) const
Definition: MCParticle.h:221
art::InputTag fHitModuleLabel
Declaration of signal hit object.
#define Comment
fhicl::Atom< size_t > EnableParticleTree
Encapsulate the construction of a single detector plane.
Contains all timing reference information for the detector.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Definition: CryostatGeo.cxx:93
double TotalLength() const
double fTrueTrkX[10000]
std::vector< sim::IDE > HitToAvgSimIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
art::InputTag fTrackModuleLabel
Provides recob::Track data product.
double Vz(const int i=0) const
Definition: MCParticle.h:223
int trigger_offset(DetectorClocksData const &data)
EventNumber_t event() const
Definition: EventID.h:116
double fTrueTrkY[10000]
float fTrkPurityPerPlane[3]
double fTrueTrkdEdX[10000]
fhicl::Sequence< int > Pdg
std::vector< int > fPdg
TCEvent evt
Definition: DataStructs.cxx:7
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
TH1D * fDepDenominatorHist
fhicl::Atom< size_t > EffEMax
TH1D * fLengthDenominatorHist
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
void beginJob() override
const double * PlaneLocation(unsigned int p) const
Definition: TPCGeo.cxx:382
static QCString * s
Definition: config.cpp:1042
EventID id() const
Definition: Event.cc:34
double Vy(const int i=0) const
Definition: MCParticle.h:222
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
Cosmic rays.
Definition: MCTruth.h:24
QTextStream & endl(QTextStream &s)
Encapsulate the construction of a single detector plane.
double fTrueTrkStepE[10000]
fhicl::Atom< size_t > EffDepMax
double GetdEdX(simb::MCTrajectory traj, size_t this_step)
fhicl::Atom< size_t > EffHitBins
TH1D * fEnergyNominatorHist