CosmicEfficiency_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: CosmicEfficiency
3 // Plugin Type: analyzer (art v2_07_03)
4 // File: CosmicEfficiency_module.cc
5 //
6 // Generated at Mon Sep 4 06:55:33 2017 by Leigh Whitehead using cetskelgen
7 // from cetlib version v3_00_01.
8 ////////////////////////////////////////////////////////////////////////
9 
16 #include "art_root_io/TFileService.h"
18 #include "canvas/Persistency/Common/FindManyP.h"
19 #include "fhiclcpp/ParameterSet.h"
21 
30 
31 #include "TH1F.h"
32 
33 namespace cosmic {
34  class CosmicEfficiency;
35 }
36 
37 
39 public:
40 
41  // Just make an enum for plotting in a histogram to avoid
42  // histograms of the pdg code. These definitions are
43  // valid for particle and antiparticle
44  // Note the enum starts at one since this is the bin
45  // number for the histograms
47  {
48  kNotSet = 0,
49  kElectron = 1,
50  kMuon = 2,
51  kPion = 3,
52  kProton = 4,
53  kKaon = 5,
54  kOther = 6
55  };
56 
57  explicit CosmicEfficiency(fhicl::ParameterSet const & p);
58  // The compiler-generated destructor is fine for non-base
59  // classes without bare pointers or other resource use.
60 
61  // Plugins should not be copied or assigned.
62  CosmicEfficiency(CosmicEfficiency const &) = delete;
64  CosmicEfficiency & operator = (CosmicEfficiency const &) = delete;
66 
67  virtual void beginJob() override;
68  virtual void endJob() override;
69 
70  // Required functions.
71  void analyze(art::Event const & e) override;
72 
73 private:
74 
76  const std::vector< art::Ptr<recob::Hit> > & hits) const;
77 
78  const particleType ConvertPDGCode(int pdg) const;
79 
81 
82  // fcl parameters
84  bool fVerbose;
85 
86  // Useful counters
87  unsigned int fTrueCosmicMuon;
88  unsigned int fTaggedCosmicMuon;
89  unsigned int fTrueOther;
90  unsigned int fTaggedOther;
91  // Also tag just anything from cosmic or beam origin
92  unsigned int fTrueCosmicOrigin;
93  unsigned int fTaggedCosmicOrigin;
94  unsigned int fTrueOtherOrigin;
95  unsigned int fTaggedOtherOrigin;
96 
97  // Histograms
100  TH1F *hCosmicEff;
101  TH1F *hCosmicPur;
102  TH1F *hTaggedPDG;
103  TH1F *hTrkLenAll;
104  TH1F *hTrkLenTag;
105  TH1F *hTrkLenEff;
106  TH1F *hTagType;
107 };
108 
109 
111  :
112  EDAnalyzer(p),
113  fTrackerTag(p.get<art::InputTag>("TrackerTag")),
114  fVerbose(p.get<bool>("Verbose")),
116  fTrueOther(0), fTaggedOther(0),
119 {
120 
121 }
122 
124 {
125 
126  // Get a file service so we can make some histograms to write out
128 
129  hCosmicMuonEff = tfs->make<TH1F>("hCosmicMuonEff",";Efficiency",50,0,1.0001);
130  hCosmicMuonPur = tfs->make<TH1F>("hCosmicMuonPur",";Purity",50,0,1.0001);
131  hCosmicEff = tfs->make<TH1F>("hCosmicEff",";Efficiency",50,0,1.0001);
132  hCosmicPur = tfs->make<TH1F>("hCosmicPur",";Purity",50,0,1.0001);
133  hTaggedPDG = tfs->make<TH1F>("hTaggedParticleType","",6,0.5,6.5);
134  hTrkLenAll = tfs->make<TH1F>("hTrkLenAll","",10,0,600);
135  hTrkLenTag = tfs->make<TH1F>("hTrkLenTag","",10,0,600);
136  hTrkLenEff = tfs->make<TH1F>("hTrkLenEff","",10,0,600);
137  hTagType = tfs->make<TH1F>("hTagType","",12,0,12);
138 
139  // Let's give the particle type plot useful labels
140  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kElectron,"Electron");
141  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kMuon,"Muon");
142  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kPion,"Pion");
143  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kProton,"Proton");
144  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kKaon,"Kaon");
145  hTaggedPDG->GetXaxis()->SetBinLabel(cosmic::CosmicEfficiency::kOther,"Other");
146 
147  // Tag type labels would be nice too.
148  hTagType->GetXaxis()->SetBinLabel(1,"YY");
149  hTagType->GetXaxis()->SetBinLabel(2,"YZ");
150  hTagType->GetXaxis()->SetBinLabel(3,"ZZ");
151  hTagType->GetXaxis()->SetBinLabel(4,"XX");
152  hTagType->GetXaxis()->SetBinLabel(5,"XY");
153  hTagType->GetXaxis()->SetBinLabel(6,"XZ");
154  hTagType->GetXaxis()->SetBinLabel(7,"Y");
155  hTagType->GetXaxis()->SetBinLabel(8,"Z");
156  hTagType->GetXaxis()->SetBinLabel(9,"X");
157  hTagType->GetXaxis()->SetBinLabel(10,"Outside Drift (Part)");
158  hTagType->GetXaxis()->SetBinLabel(11,"Outside Drift (Full)");
159  hTagType->GetXaxis()->SetBinLabel(12,"Beam Incompatible");
160 
161 }
162 
164 {
165 
166  // We must have MC for this module to make sense
167  if(evt.isRealData()) return;
168 
169  // Get the reconstructed tracks
170  auto recoTracks = evt.getValidHandle<std::vector<recob::Track> >(fTrackerTag);
171 
172  // We need the association between the tracks and the hits
173  const art::FindManyP<recob::Hit> findTrackHits(recoTracks, evt, fTrackerTag);
174 
175  // Also want the association between tracks and anab::CosmicTag objects
176  const art::FindManyP<anab::CosmicTag> findCosmicTags(recoTracks,evt,fTrackerTag);
177 
178  // Finally, get the backtracker
180 
181  // Since we will make plots of efficiency per event, we need local versions of the class variables
182  unsigned int local_TrueCosmicMuon = 0;
183  unsigned int local_TaggedCosmicMuon = 0;
184  unsigned int local_TrueOther = 0;
185  unsigned int local_TaggedOther = 0;
186  unsigned int local_TrueCosmicOrigin = 0;
187  unsigned int local_TaggedCosmicOrigin = 0;
188  unsigned int local_TrueOtherOrigin = 0;
189  unsigned int local_TaggedOtherOrigin = 0;
190 
191  // Fill a vector with the true tracks matched
192  std::vector<int> matchedTruths;
193 
194  // Loop over the tracks
195  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
196  for(unsigned int t = 0; t < recoTracks->size(); ++t){
197 
198  // Get the hits
199  auto const& trackHits = findTrackHits.at(t);
200 
201  // Get the best match MC Particle for this track
202  const simb::MCParticle* trueMatch = GetTruthParticle(clockData, trackHits);
203 
204  if(trueMatch == 0x0) continue;
205 
206  bool alreadyMatched = false;
207  if(std::find(matchedTruths.begin(),matchedTruths.end(),trueMatch->TrackId())==matchedTruths.end()){
208  matchedTruths.push_back(trueMatch->TrackId());
209  }
210  else{
211  alreadyMatched = true;
212  }
213 
214  // We need to use the backtracker to find if this true particle is cosmic or not
215  bool isCosmic = false;
216  bool isCosmicMuon = false;
217  const art::Ptr<simb::MCTruth> mc = pi_serv->TrackIdToMCTruth_P(trueMatch->TrackId());
218 
219  // Check if we have a cosmic muon (or anti-muon) and set the true counting variables
220  if(mc->Origin() == simb::kCosmicRay){
221  if(fabs(trueMatch->PdgCode()) == 13){
222  ++local_TrueCosmicMuon;
223  isCosmicMuon = true;
224  hTrkLenAll->Fill(((*recoTracks)[t].Vertex()-(*recoTracks)[t].End()).R());
225  }
226  else{
227  ++local_TrueOther;
228  }
229  ++local_TrueCosmicOrigin;
230  isCosmic = true;
231  }
232  else{
233  // Definitely not cosmic!
234  ++local_TrueOther;
235  ++local_TrueOtherOrigin;
236  }
237 
238  // Now look for a cosmic tag object
239  auto const& trackCosmicTag = findCosmicTags.at(t);
240 
241  // I'm not sure GEANT keeps the names of the particle processes properly. Let's
242  // get the MCParticle straight from the MCTruth and see what happens.
243  std::string correctProcess = "";
244  for(int tp = 0; tp < mc->NParticles(); ++tp){
245 
246  if(mc->GetParticle(tp).Position().X() == trueMatch->Position().X()){
247  if(mc->GetParticle(tp).Position().Y() == trueMatch->Position().Y()){
248  if(mc->GetParticle(tp).Position().Z() == trueMatch->Position().Z()){
249  correctProcess = mc->GetParticle(tp).Process();
250  break;
251  }
252  }
253  }
254  }
255 
256  // Did we find a cosmic tag for this track?
257  if(trackCosmicTag.size() == 0){
258  // If we don't have a tag, let's see if we can find out why.
259  if(isCosmicMuon && fVerbose){
260  std::cout << "We've found a cosmic muon but we don't have a tag for it" << std::endl;
261  //std::cout << "Reco vertex = "; (*recoTracks)[t].Vertex().Print();
262  //std::cout << "True vertex = "; trueMatch->Position().Vect().Print();
263  //std::cout << "Reco end = "; (*recoTracks)[t].End().Print();
264  //std::cout << "True end = "; trueMatch->EndPosition().Vect().Print();
265  std::cout << " - Track length = " << ((*recoTracks)[t].Vertex()-(*recoTracks)[t].End()).R() << std::endl;
266  if((*recoTracks)[t].Vertex().Y() < (*recoTracks)[t].End().Y()){
267  std::cout << " - Track reconstructed with the vertex lower than the end point" << std::endl;
268  }
269  if((*recoTracks)[t].Vertex().Y() < 550 && (*recoTracks)[t].End().Y() < 550){
270  std::cout << " - This track was reconstructed away from the top of the detector... no way to tag it. " << std::endl;
271  }
272  if(alreadyMatched){
273  std::cout << " - This true particle " << trueMatch->TrackId() << "was already matched" << std::endl;
274  }
275  }
276  continue;
277  }
278  else{
279  // Specific cosmic muon counters
280  if(isCosmicMuon){
281  ++local_TaggedCosmicMuon;
282  hTrkLenTag->Fill(((*recoTracks)[t].Vertex()-(*recoTracks)[t].End()).R());
283  }
284  else{
285  ++local_TaggedOther;
286  }
287  // Origin counters
288  if(isCosmic){
289  ++local_TaggedCosmicOrigin;
290  }
291  else{
292  ++local_TaggedOtherOrigin;
293  if(fVerbose){
294  if(correctProcess == "primary"){
295  std::cout << " - Oops! Tagged a good beam particle (" << trueMatch->PdgCode() << ") as a cosmic (" << ConvertCosmicType(trackCosmicTag[0]->CosmicType()) << ")" << std::endl;
296  }
297  else if(correctProcess == "primaryBackground"){
298  std::cout << " - Oops! Tagged a background beam particle (" << trueMatch->PdgCode() << ") as a cosmic (" << ConvertCosmicType(trackCosmicTag[0]->CosmicType()) << ")" << std::endl;
299  }
300  else{
301  std::cout << " - Oops! Tagged a non-primary beam particle (" << trueMatch->PdgCode() << ") as a cosmic (" << ConvertCosmicType(trackCosmicTag[0]->CosmicType()) << ")" << std::endl;
302  }
303  (*recoTracks)[t].Vertex<TVector3>().Print();
304  (*recoTracks)[t].End<TVector3>().Print();
305  trueMatch->Position().Vect().Print();
306  trueMatch->EndPosition().Vect().Print();
307  }
308  }
309  // Fill the tagged particle hisrogram
310  hTaggedPDG->Fill(ConvertPDGCode(trueMatch->PdgCode()));
311  // Type of tag histogram
312  hTagType->Fill(ConvertCosmicType(trackCosmicTag[0]->CosmicType()));
313  }
314 
315  } // End loop over reconstructed tracks
316 
317  // Fill the plots
318  if(local_TrueCosmicMuon > 0){
319  hCosmicMuonEff->Fill(local_TaggedCosmicMuon/static_cast<float>(local_TrueCosmicMuon));
320  }
321  if(local_TaggedCosmicMuon+local_TaggedOther > 0){
322  hCosmicMuonPur->Fill(local_TaggedCosmicMuon/static_cast<float>(local_TaggedCosmicMuon + local_TaggedOther));
323  }
324  if(local_TrueCosmicOrigin > 0){
325  hCosmicEff->Fill(local_TaggedCosmicOrigin/static_cast<float>(local_TrueCosmicOrigin));
326  }
327  if(local_TaggedCosmicOrigin+local_TaggedOtherOrigin > 0){
328  hCosmicPur->Fill(local_TaggedCosmicOrigin/static_cast<float>(local_TaggedCosmicOrigin + local_TaggedOtherOrigin));
329  }
330 
331  // Make sure to increment the main member counters
332  fTrueCosmicMuon += local_TrueCosmicMuon;
333  fTaggedCosmicMuon += local_TaggedCosmicMuon;
334  fTrueOther += local_TrueOther;
335  fTaggedOther += local_TaggedOther;
336 
337  fTrueCosmicOrigin += local_TrueCosmicOrigin;
338  fTaggedCosmicOrigin += local_TaggedCosmicOrigin;
339  fTrueOtherOrigin += local_TrueOtherOrigin;
340  fTaggedOtherOrigin += local_TaggedOtherOrigin;
341 }
342 
344 {
346  std::cout << " == Cosmic Efficiency Summary == " << std::endl;
347  std::cout << " - Looking for cosmic muons: " << std::endl;
348  std::cout << " Tagged " << fTaggedCosmicMuon << " of " << fTrueCosmicMuon << " :: " << 100.*fTaggedCosmicMuon/static_cast<float>(fTrueCosmicMuon) << "% efficiency" << std::endl;
349  std::cout << " Total tags = " << fTaggedCosmicMuon + fTaggedOther << " :: "
350  << 100.*fTaggedCosmicMuon/static_cast<float>(fTaggedCosmicMuon + fTaggedOther) << "% purity" << std::endl;
351  std::cout << " - Looking for just cosmic origin: " << std::endl;
352  std::cout << " Tagged " << fTaggedCosmicOrigin << " of " << fTrueCosmicOrigin << " :: " << 100.*fTaggedCosmicOrigin/static_cast<float>(fTrueCosmicOrigin) << "% efficiency" << std::endl;
353  std::cout << " Total tags = " << fTaggedCosmicOrigin + fTaggedOtherOrigin << " :: "
354  << 100.*fTaggedCosmicOrigin/static_cast<float>(fTaggedCosmicOrigin + fTaggedOtherOrigin) << "% purity" << std::endl;
355  }
356  for(int b = 1; b <= hTrkLenAll->GetNbinsX(); ++b){
357  if(hTrkLenAll->GetBinContent(b) != 0){
358  float all = hTrkLenAll->GetBinContent(b);
359  float tag = hTrkLenTag->GetBinContent(b);
360  float eff = tag / all;
361  // Use binomial error... not perfect, but hopefully ok.
362  float err = sqrt((eff*(1-eff))/all);
363  hTrkLenEff->SetBinContent(b,eff);
364  hTrkLenEff->SetBinError(b,err);
365  }
366  }
367 }
368 
369 // Function to find the best matched true particle to a reconstructed particle
371  const std::vector< art::Ptr<recob::Hit> > & hits) const
372 {
373  const simb::MCParticle* mcParticle = 0;
374 
377  std::unordered_map<int, double> trkIDE;
378  for (auto const & h : hits)
379  {
380  for (auto const & ide : bt_serv->HitToTrackIDEs(clockData, h)) // loop over std::vector<sim::TrackIDE>
381  {
382  trkIDE[ide.trackID] += ide.energy; // sum energy contribution by each track ID
383  }
384  }
385 
386  int best_id = 0;
387  double tot_e = 0, max_e = 0;
388  for (auto const & contrib : trkIDE)
389  {
390  tot_e += contrib.second; // sum total energy in these hits
391  if (contrib.second > max_e) // find track ID corresponding to max energy
392  {
393  max_e = contrib.second;
394  best_id = contrib.first;
395  }
396  }
397 
398  if ((max_e > 0) && (tot_e > 0)) // ok, found something reasonable
399  {
400  if (best_id < 0) // NOTE: negative ID means this is EM activity
401  { // caused by track with the same but positive ID
402 // best_id = -best_id; // --> we'll find mother MCParticle of these hits
403  return mcParticle;
404  }
405  mcParticle = pi_serv->TrackIdToParticle_P(best_id); // MCParticle corresponding to track ID
406  }
407 
408  return mcParticle;
409 }
410 
411 // Function to convert the PDG code into the scheme we want to use for our histogram
413 {
415 
416  switch(pdg)
417  {
418  case -11:
419  case 11:
421  break;
422  case -13:
423  case 13:
425  break;
426  case 211:
427  case -211:
429  break;
430  case 2212:
431  case -2212:
433  break;
434  case 321:
435  case -321:
437  break;
438  default:
440  }
441 
442  return particle;
443 }
444 
445 // Function to convert the cosmic tag enum into a value for the histogram
447 {
448  int val = -1;
449 
450  switch(tag){
451  case anab::CosmicTagID_t::kGeometry_YY : val = 0; break;
452  case anab::CosmicTagID_t::kGeometry_YZ : val = 1; break;
453  case anab::CosmicTagID_t::kGeometry_ZZ : val = 2; break;
454  case anab::CosmicTagID_t::kGeometry_XX : val = 3; break;
455  case anab::CosmicTagID_t::kGeometry_XY : val = 4; break;
456  case anab::CosmicTagID_t::kGeometry_XZ : val = 5; break;
457  case anab::CosmicTagID_t::kGeometry_Y : val = 6; break;
458  case anab::CosmicTagID_t::kGeometry_Z : val = 7; break;
459  case anab::CosmicTagID_t::kGeometry_X : val = 8; break;
460  case anab::CosmicTagID_t::kOutsideDrift_Partial : val = 9; break;
461  case anab::CosmicTagID_t::kOutsideDrift_Complete : val = 10; break;
462  case anab::CosmicTagID_t::kFlash_BeamIncompatible : val = 11; break;
463  default: val = -1;
464  }
465  return val;
466 }
467 
CosmicEfficiency & operator=(CosmicEfficiency const &)=delete
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
int PdgCode() const
Definition: MCParticle.h:212
const TLorentzVector & EndPosition() const
Definition: MCParticle.h:225
std::vector< sim::TrackIDE > HitToTrackIDEs(detinfo::DetectorClocksData const &clockData, recob::Hit const &hit) const
std::string string
Definition: nybbler.cc:12
const simb::MCParticle * TrackIdToParticle_P(int id) const
enum anab::cosmic_tag_id CosmicTagID_t
simb::Origin_t Origin() const
Definition: MCTruth.h:74
struct vector vector
const particleType ConvertPDGCode(int pdg) const
int NParticles() const
Definition: MCTruth.h:75
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
std::string Process() const
Definition: MCParticle.h:215
Particle class.
int TrackId() const
Definition: MCParticle.h:210
virtual void beginJob() override
bool isRealData() const
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
const art::Ptr< simb::MCTruth > & TrackIdToMCTruth_P(int id) const
int ConvertCosmicType(anab::CosmicTagID_t tag) const
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
void err(const char *fmt,...)
Definition: message.cpp:226
const simb::MCParticle & GetParticle(int i) const
Definition: MCTruth.h:76
Declaration of signal hit object.
static QInternalList< QTextCodec > * all
Definition: qtextcodec.cpp:63
Contains all timing reference information for the detector.
void End(void)
Definition: gXSecComp.cxx:210
virtual void endJob() override
Provides recob::Track data product.
void analyze(art::Event const &e) override
static bool * b
Definition: config.cpp:1043
boost::graph_traits< ModuleGraph >::vertex_descriptor Vertex
Definition: ModuleGraph.h:25
TCEvent evt
Definition: DataStructs.cxx:7
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
const simb::MCParticle * GetTruthParticle(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits) const
int bool
Definition: qglobal.h:345
CosmicEfficiency(fhicl::ParameterSet const &p)
Cosmic rays.
Definition: MCTruth.h:24
QTextStream & endl(QTextStream &s)