LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
MCTruthT0Matching_module.cc
Go to the documentation of this file.
1 
42 // Framework includes
47 #include "art_root_io/TFileService.h"
50 
52 #include "fhiclcpp/ParameterSet.h"
53 
54 #include <iostream>
55 #include <iterator>
56 #include <map>
57 #include <memory>
58 
59 // LArSoft
73 
74 // ROOT
75 #include "TTree.h"
76 
77 namespace t0 {
78  class MCTruthT0Matching;
79 }
80 
82 public:
83  explicit MCTruthT0Matching(fhicl::ParameterSet const& p);
84  // The destructor generated by the compiler is fine for classes
85  // without bare pointers or other resource use.
86 
87  // Plugins should not be copied or assigned.
88  MCTruthT0Matching(MCTruthT0Matching const&) = delete;
92 
93  // Required functions.
94  void produce(art::Event& e) override;
95 
96  // Selected optional functions.
97  void beginJob() override;
98 
99 private:
100  // Params got from fcl file
106 
109 
111 
112  // Variable in TFS branches
113  TTree* fTree;
114  int TrackID = 0;
115  int TrueTrackID = 0;
117  double TrueTrackT0 = 0;
118 
119  int ShowerID = 0;
120  int ShowerMatchID = 0;
122  double ShowerT0 = 0;
123 };
124 
126 {
127  // Call appropriate produces<>() functions here.
128  fTrackModuleLabel = (p.get<art::InputTag>("TrackModuleLabel"));
129  fShowerModuleLabel = (p.get<art::InputTag>("ShowerModuleLabel"));
130  fPFParticleModuleLabel = (p.get<art::InputTag>("PFParticleModuleLabel", "pandoraNu"));
131  fMakeT0Assns = (p.get<bool>("makeT0Assns", true));
132  fMakePFParticleAssns = (p.get<bool>("makePFParticleAssns", false));
133 
134  fMakeHitAssns = p.get<bool>("makeHitAssns", true);
135  if (fMakeHitAssns) fHitModuleLabel = p.get<art::InputTag>("HitModuleLabel");
136  fOverrideRealData = p.get<bool>("OverrideRealData", false);
137 
138  if (
139  fMakeT0Assns) { // T0 assns are deprecated - this allows one to use deprecated funcionality. Added 2017-08-15. Should not be kept around forever
140  std::cout << "WARNING - You are using deprecated functionality\n";
141  std::cout << "MCTruthT0Matching T0 assns will be removed soon\n";
142  std::cout << "set your fcl parameter makeT0Assns to false and use MCParticle direct "
143  "associations instead"
144  << std::endl;
145  produces<std::vector<anab::T0>>();
146  produces<art::Assns<recob::Track, anab::T0>>();
147  produces<art::Assns<recob::Shower, anab::T0>>();
148  if (fMakePFParticleAssns) {
149  produces<art::Assns<recob::PFParticle, anab::T0>>();
150  } // only do PFParticles if desired by the user
151  }
152 
153  produces<art::Assns<recob::Track, simb::MCParticle, anab::BackTrackerMatchingData>>();
154  produces<art::Assns<recob::Shower, simb::MCParticle, anab::BackTrackerMatchingData>>();
155  if (fMakePFParticleAssns) { // only do PFParticles if desired by the user
156  produces<art::Assns<recob::PFParticle, simb::MCParticle, anab::BackTrackerMatchingData>>();
157  }
158 
159  if (fMakeHitAssns)
160  produces<art::Assns<recob::Hit, simb::MCParticle, anab::BackTrackerHitMatchingData>>();
161 }
162 
164 {
165  // Implementation of optional member function here.
167  fTree = tfs->make<TTree>("MCTruthT0Matching", "MCTruthT0");
168  fTree->Branch("TrueTrackT0", &TrueTrackT0, "TrueTrackT0/D");
169  fTree->Branch("TrueTrackID", &TrueTrackID, "TrueTrackID/D");
170 }
171 
173 {
174  if (evt.isRealData() && !fOverrideRealData) return;
175 
176  // Access art services...
180  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
181 
182  //TrackList handle
183  art::Handle<std::vector<recob::Track>> trackListHandle;
184  std::vector<art::Ptr<recob::Track>> tracklist;
185  if (evt.getByLabel(fTrackModuleLabel, trackListHandle))
186  art::fill_ptr_vector(tracklist, trackListHandle);
187 
188  //ShowerList handle
189  art::Handle<std::vector<recob::Shower>> showerListHandle;
190  std::vector<art::Ptr<recob::Shower>> showerlist;
191  if (evt.getByLabel(fShowerModuleLabel, showerListHandle))
192  art::fill_ptr_vector(showerlist, showerListHandle);
193 
194  //PFParticleList handle
195  art::Handle<std::vector<recob::PFParticle>> pfparticleListHandle;
196  std::vector<art::Ptr<recob::PFParticle>> pfparticlelist;
197  if (evt.getByLabel(fPFParticleModuleLabel, pfparticleListHandle))
198  art::fill_ptr_vector(pfparticlelist, pfparticleListHandle);
199 
200  auto mcpartHandle = evt.getValidHandle<std::vector<simb::MCParticle>>("largeant");
201  // simb::MCParticle const *firstParticle = &mcpartHandle->front();
202  // Create anab::T0 objects and make association with recob::Track, recob::Shower, and recob::PFParticle objects
203  std::unique_ptr<std::vector<anab::T0>> T0col(new std::vector<anab::T0>);
204  // if (fMakeT0Assns){ // T0 assns are deprecated - this allows one to use deprecated funcionality. Added 2017-08-15. Should not be kept around forever
205  std::unique_ptr<art::Assns<recob::Track, anab::T0>> Trackassn(
207  std::unique_ptr<art::Assns<recob::Shower, anab::T0>> Showerassn(
209  std::unique_ptr<art::Assns<recob::PFParticle, anab::T0>> PFParticleassn(
211 
212  // Create associations directly between MCParticle and either recob::Track, recob::Shower, or recob::PFParticle
213  // These associations contain metadata summarising the quality of the match
214  std::unique_ptr<art::Assns<recob::Track, simb::MCParticle, anab::BackTrackerMatchingData>>
216  std::unique_ptr<art::Assns<recob::Shower, simb::MCParticle, anab::BackTrackerMatchingData>>
217  MCPartShowerassn(
219  std::unique_ptr<art::Assns<recob::PFParticle, simb::MCParticle, anab::BackTrackerMatchingData>>
220  MCPartPFParticleassn(
222  // Association block for the hits<-->MCParticles
223  std::unique_ptr<art::Assns<recob::Hit, simb::MCParticle, anab::BackTrackerHitMatchingData>>
225 
226  double maxe = -1;
227  double tote = 0;
228  // int trkid = -1;
229  int maxtrkid = -1;
230  double maxn = -1;
231  double totn = 0;
232  int maxntrkid = -1;
234 
235  std::unordered_map<int, int> trkid_lookup; //indexed by geant4trkid, delivers MC particle location
236 
237  //if we want to make per-hit assns
238  if (fMakeHitAssns) {
239 
241  evt.getByLabel(fHitModuleLabel, hitListHandle);
242 
243  if (hitListHandle.isValid()) {
244 
245  auto const& hitList(*hitListHandle);
246  auto const& mcpartList(*mcpartHandle);
247  for (size_t i_h = 0; i_h < hitList.size(); ++i_h) {
248  art::Ptr<recob::Hit> hitPtr(hitListHandle, i_h);
249  auto trkide_list = bt_serv->HitToTrackIDEs(clockData, hitPtr);
250  struct TrackIDEinfo {
251  float E;
252  float NumElectrons;
253  };
254  std::map<int, TrackIDEinfo> trkide_collector;
255  maxe = -1;
256  tote = 0;
257  maxtrkid = -1;
258  maxn = -1;
259  totn = 0;
260  maxntrkid = -1;
261  for (auto const& t : trkide_list) {
262  trkide_collector[t.trackID].E += t.energy;
263  tote += t.energy;
264  if (trkide_collector[t.trackID].E > maxe) {
265  maxe = trkide_collector[t.trackID].E;
266  maxtrkid = t.trackID;
267  }
268  trkide_collector[t.trackID].NumElectrons += t.numElectrons;
269  totn += t.numElectrons;
270  if (trkide_collector[t.trackID].NumElectrons > maxn) {
271  maxn = trkide_collector[t.trackID].NumElectrons;
272  maxntrkid = t.trackID;
273  }
274 
275  //if not found, find mc particle...
276  if (trkid_lookup.find(t.trackID) == trkid_lookup.end()) {
277  size_t i_p = 0;
278  while (i_p < mcpartList.size()) {
279  if (mcpartList[i_p].TrackId() == t.trackID) {
280  trkid_lookup[t.trackID] = (int)i_p;
281  break;
282  }
283  ++i_p;
284  }
285  if (i_p == mcpartList.size()) trkid_lookup[t.trackID] = -1;
286  }
287 
288  } //end loop on TrackIDs
289 
290  //now find the mcparticle and loop back through ...
291  for (auto const& t : trkide_collector) {
292  int mcpart_i = trkid_lookup[t.first];
293  if (mcpart_i == -1) continue; //no mcparticle here
294  art::Ptr<simb::MCParticle> mcpartPtr(mcpartHandle, mcpart_i);
295  bthmd.ideFraction = t.second.E / tote;
296  bthmd.isMaxIDE = (t.first == maxtrkid);
297  bthmd.ideNFraction = t.second.NumElectrons / totn;
298  bthmd.isMaxIDEN = (t.first == maxntrkid);
299  MCPartHitassn->addSingle(hitPtr, mcpartPtr, bthmd);
300  }
301 
302  } //end loop on hits
303 
304  } //end if handle valid
305 
306  } //end if make hit/mcpart assns
307 
308  if (trackListHandle.isValid()) {
309  //Access tracks and hits
310  art::FindManyP<recob::Hit> fmtht(trackListHandle, evt, fTrackModuleLabel);
311 
312  size_t NTracks = tracklist.size();
313 
314  // Now to access MCTruth for each track...
315  for (size_t iTrk = 0; iTrk < NTracks; ++iTrk) {
316  TrueTrackT0 = 0;
317  TrackID = 0;
318  TrueTrackID = 0;
320  std::vector<art::Ptr<recob::Hit>> allHits = fmtht.at(iTrk);
321 
322  std::map<int, double> trkide;
323  for (size_t h = 0; h < allHits.size(); ++h) {
324  art::Ptr<recob::Hit> hit = allHits[h];
325  std::vector<sim::IDE> ides;
326  std::vector<sim::TrackIDE> TrackIDs = bt_serv->HitToTrackIDEs(clockData, hit);
327 
328  for (size_t e = 0; e < TrackIDs.size(); ++e) {
329  trkide[TrackIDs[e].trackID] += TrackIDs[e].energy;
330  }
331  }
332  // Work out which IDE despoited the most charge in the hit if there was more than one.
333  maxe = -1;
334  tote = 0;
335  for (std::map<int, double>::iterator ii = trkide.begin(); ii != trkide.end(); ++ii) {
336  tote += ii->second;
337  if ((ii->second) > maxe) {
338  maxe = ii->second;
339  TrackID = ii->first;
340  }
341  }
342  btdata.cleanliness = maxe / tote;
343 
344  // Now have trackID, so get PdG code and T0 etc.
345  const simb::MCParticle* tmpParticle = pi_serv->TrackIdToParticle_P(TrackID);
346  if (!tmpParticle)
347  continue; // Retain this check that the BackTracker can find the right particle
348  // Now, loop through the MCParticle's myself to find the correct match
349  int mcpart_i(-1);
350  for (auto const& particle : *mcpartHandle) {
351  mcpart_i++;
352  if (TrackID == particle.TrackId()) { break; }
353  }
354  const simb::MCParticle particle = mcpartHandle.product()->at(mcpart_i);
355  TrueTrackT0 = particle.T();
356  TrueTrackID = particle.TrackId();
357  TrueTriggerType = 2; // Using MCTruth as trigger, so tigger type is 2.
358 
359  T0col->push_back(anab::T0(TrueTrackT0, TrueTriggerType, TrueTrackID, (*T0col).size()));
360  //auto diff = particle - firstParticle;
361  auto diff = mcpart_i; // check I have a sensible value for this counter
362  if (diff >= (int)mcpartHandle->size()) {
363  std::cout << "Error, the backtracker is doing weird things to your pointers!" << std::endl;
364  throw std::exception();
365  }
366 
367  art::Ptr<simb::MCParticle> mcpartPtr(mcpartHandle, mcpart_i);
368  MCPartTrackassn->addSingle(tracklist[iTrk], mcpartPtr, btdata);
369  if (fMakeT0Assns) { util::CreateAssn(evt, *T0col, tracklist[iTrk], *Trackassn); }
370  fTree->Fill();
371 
372  } // Loop over tracks
373  }
374 
375  if (showerListHandle.isValid()) {
376  art::FindManyP<recob::Hit> fmsht(showerListHandle, evt, fShowerModuleLabel);
377  // Now Loop over showers....
378  size_t NShowers = showerlist.size();
379  for (size_t Shower = 0; Shower < NShowers; ++Shower) {
380  ShowerMatchID = 0;
381  ShowerID = 0;
382  ShowerT0 = 0;
383  std::vector<art::Ptr<recob::Hit>> allHits = fmsht.at(Shower);
385 
386  std::map<int, double> showeride;
387  for (size_t h = 0; h < allHits.size(); ++h) {
388  art::Ptr<recob::Hit> hit = allHits[h];
389  std::vector<sim::IDE> ides;
390  std::vector<sim::TrackIDE> TrackIDs = bt_serv->HitToTrackIDEs(clockData, hit);
391 
392  for (size_t e = 0; e < TrackIDs.size(); ++e) {
393  showeride[TrackIDs[e].trackID] += TrackIDs[e].energy;
394  }
395  }
396  // Work out which IDE despoited the most charge in the hit if there was more than one.
397  maxe = -1;
398  tote = 0;
399  for (std::map<int, double>::iterator ii = showeride.begin(); ii != showeride.end(); ++ii) {
400  tote += ii->second;
401  if ((ii->second) > maxe) {
402  maxe = ii->second;
403  ShowerID = ii->first;
404  }
405  }
406  btdata.cleanliness = maxe / tote;
407 
408  // Now have MCParticle trackID corresponding to shower, so get PdG code and T0 etc.
409  const simb::MCParticle* tmpParticle = pi_serv->TrackIdToParticle_P(ShowerID);
410  if (!tmpParticle)
411  continue; // Retain this check that the BackTracker can find the right particle
412  // Now, loop through the MCParticle's myself to find the correct match
413  int mcpart_i(-1);
414  for (auto const& particle : *mcpartHandle) {
415  mcpart_i++;
416  if (ShowerID == particle.TrackId()) { break; }
417  }
418  const simb::MCParticle particle = mcpartHandle.product()->at(mcpart_i);
419  ShowerT0 = particle.T();
420  ShowerID = particle.TrackId();
421  ShowerTriggerType = 2; // Using MCTruth as trigger, so tigger type is 2.
422  T0col->push_back(anab::T0(ShowerT0, ShowerTriggerType, ShowerID, (*T0col).size()));
423 
424  auto diff = mcpart_i; // check I have a sensible value for this counter
425  if (diff >= (int)mcpartHandle->size()) {
426  std::cout << "Error, the backtracker is doing weird things to your pointers!" << std::endl;
427  throw std::exception();
428  }
429  art::Ptr<simb::MCParticle> mcpartPtr(mcpartHandle, mcpart_i);
430  if (fMakeT0Assns) { util::CreateAssn(evt, *T0col, showerlist[Shower], *Showerassn); }
431  MCPartShowerassn->addSingle(showerlist[Shower], mcpartPtr, btdata);
432 
433  } // Loop over showers
434  }
435 
436  if (pfparticleListHandle.isValid()) {
437  //Access pfparticles and hits
438  art::FindManyP<recob::Cluster> fmcp(pfparticleListHandle, evt, fPFParticleModuleLabel);
439 
440  size_t NPfparticles = pfparticlelist.size();
441 
442  // Now to access MCTruth for each pfparticle...
443  for (size_t iPfp = 0; iPfp < NPfparticles; ++iPfp) {
444  TrueTrackT0 = 0;
445  TrackID = 0;
446  TrueTrackID = 0;
448 
449  std::vector<art::Ptr<recob::Hit>> allHits;
450  //Get all hits through associated clusters
451  std::vector<art::Ptr<recob::Cluster>> allClusters = fmcp.at(iPfp);
452  art::FindManyP<recob::Hit> fmhcl(allClusters, evt, fPFParticleModuleLabel);
453  for (size_t iclu = 0; iclu < allClusters.size(); ++iclu) {
454  std::vector<art::Ptr<recob::Hit>> hits = fmhcl.at(iclu);
455  allHits.insert(allHits.end(), hits.begin(), hits.end());
456  }
457 
458  std::map<int, double> trkide;
459  for (size_t h = 0; h < allHits.size(); ++h) {
460  art::Ptr<recob::Hit> hit = allHits[h];
461  std::vector<sim::IDE> ides;
462  std::vector<sim::TrackIDE> TrackIDs = bt_serv->HitToTrackIDEs(clockData, hit);
463 
464  for (size_t e = 0; e < TrackIDs.size(); ++e) {
465  trkide[TrackIDs[e].trackID] += TrackIDs[e].energy;
466  }
467  }
468  // Work out which IDE despoited the most charge in the hit if there was more than one.
469  double maxe = -1;
470  double tote = 0;
471  for (std::map<int, double>::iterator ii = trkide.begin(); ii != trkide.end(); ++ii) {
472  tote += ii->second;
473  if ((ii->second) > maxe) {
474  maxe = ii->second;
475  TrackID = ii->first;
476  }
477  }
478  btdata.cleanliness = maxe / tote;
479 
480  // Now have trackID, so get PdG code and T0 etc.
481  const simb::MCParticle* tmpParticle = pi_serv->TrackIdToParticle_P(TrackID);
482  if (!tmpParticle)
483  continue; // Retain this check that the BackTracker can find the right particle
484  // Now, loop through the MCParticle's myself to find the correct match
485  int mcpart_i(-1);
486  for (auto const& particle : *mcpartHandle) {
487  mcpart_i++;
488  if (TrackID == particle.TrackId()) { break; }
489  }
490  const simb::MCParticle particle = mcpartHandle.product()->at(mcpart_i);
491  TrueTrackT0 = particle.T();
492  TrueTrackID = particle.TrackId();
493  TrueTriggerType = 2; // Using MCTruth as trigger, so tigger type is 2.
494  //std::cout << "Got particle, PDG = " << particle.PdgCode() << std::endl;
495 
496  //std::cout << "Filling T0col with " << TrueTrackT0 << " " << TrueTriggerType << " " << TrueTrackID << " " << (*T0col).size() << std::endl;
497 
498  T0col->push_back(anab::T0(TrueTrackT0, TrueTriggerType, TrueTrackID, (*T0col).size()));
499  //auto diff = particle - firstParticle;
500  auto diff = mcpart_i; // check I have a sensible value for this counter
501  if (diff >= (int)mcpartHandle->size()) {
502  std::cout << "Error, the backtracker is doing weird things to your pointers!" << std::endl;
503  throw std::exception();
504  }
505  // art::Ptr<simb::MCParticle> mcpartPtr(mcpartHandle, particle - firstParticle);
506  art::Ptr<simb::MCParticle> mcpartPtr(mcpartHandle, mcpart_i);
507  //std::cout << "made MCParticle Ptr" << std::endl;
508  // const std::vertex< std::pair<double, std::string> > cleanlinessCompleteness;
509  // const std::pair<double, double> tmp(0.5, 0.5);
510  // MCPartassn->addSingle(tracklist[iPfp], mcpartPtr, tmp);
511  if (fMakePFParticleAssns) {
512  if (fMakeT0Assns) { util::CreateAssn(evt, *T0col, pfparticlelist[iPfp], *PFParticleassn); }
513  MCPartPFParticleassn->addSingle(pfparticlelist[iPfp], mcpartPtr, btdata);
514  }
515  fTree->Fill();
516  } // Loop over tracks
517  }
518 
519  if (fMakeT0Assns) {
520  evt.put(std::move(T0col));
521  evt.put(std::move(Trackassn));
522  evt.put(std::move(Showerassn));
523  if (fMakePFParticleAssns) { evt.put(std::move(PFParticleassn)); }
524  }
525  evt.put(std::move(MCPartTrackassn));
526  evt.put(std::move(MCPartShowerassn));
527  if (fMakePFParticleAssns) { evt.put(std::move(MCPartPFParticleassn)); }
528  if (fMakeHitAssns) evt.put(std::move(MCPartHitassn));
529 } // Produce
530 
code to link reconstructed objects back to the MC truth information
intermediate_table::iterator iterator
std::vector< sim::TrackIDE > HitToTrackIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
MCTruthT0Matching & operator=(MCTruthT0Matching const &)=delete
std::vector< TrackID > TrackIDs
const simb::MCParticle * TrackIdToParticle_P(int id) const
Declaration of signal hit object.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
Definition: T0.h:16
bool isRealData() const
Definition: Event.cc:53
Particle class.
MCTruthT0Matching(fhicl::ParameterSet const &p)
int TrackId() const
Definition: MCParticle.h:211
void produce(art::Event &e) override
bool isValid() const noexcept
Definition: Handle.h:203
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
void hits()
Definition: readHits.C:15
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
Float_t E
Definition: plot.C:20
double T(const int i=0) const
Definition: MCParticle.h:225
Provides recob::Track data product.
Declaration of cluster object.
Detector simulation of raw signals on wires.
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Utility object to perform functions of association.
TCEvent evt
Definition: DataStructs.cxx:8
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:306
Float_t e
Definition: plot.C:35
art framework interface to geometry description
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33