All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
MCTruthTestAna_module.cc
Go to the documentation of this file.
1 /////////////////////////////////////////////////////////////////////////////
2 /// Class: MCTruthTestAna
3 /// Module Type: analyzer
4 /// File: MCTruthTestAna_module.cc
5 ///
6 /// Author: Tracy Usher
7 /// E-mail address: usher@slac.stanford.edu
8 ///
9 /// This is a test module which will compare the output of the parallel
10 /// "backtracker" based on Hit <--> MCParticle assocations to the output
11 /// of the actual BackTracker.
12 ///
13 /// It assumes that the event contains both the simchannel information
14 /// needed by the BackTracker and the Hit <--> MCParticle associations
15 /// needed by the alternate backtracker.
16 ///
17 ///
18 /////////////////////////////////////////////////////////////////////////////
19 
20 // Framework includes
21 #include "art/Framework/Core/EDAnalyzer.h"
22 #include "art/Framework/Principal/Event.h"
23 #include "art/Framework/Principal/Handle.h"
24 #include "art/Framework/Services/Registry/ServiceHandle.h"
25 #include "art_root_io/TFileService.h"
26 #include "art/Framework/Core/ModuleMacros.h"
27 #include "art/Utilities/make_tool.h"
28 #include "messagefacility/MessageLogger/MessageLogger.h"
29 #include "fhiclcpp/ParameterSet.h"
30 #include "cetlib_except/exception.h"
31 #include "canvas/Persistency/Common/FindManyP.h"
32 #include "canvas/Persistency/Common/PtrVector.h"
33 
34 // LArSoft includes
36 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
45 
46 #include "cetlib/cpu_timer.h"
50 
51 // The stuff we really need
55 
56 // ROOT includes. Note: To look up the properties of the ROOT classes,
57 // use the ROOT web site; e.g.,
58 // <http://root.cern.ch/root/html532/ClassIndex.html>
59 #include "TH1.h"
60 #include "TH2.h"
61 #include "TProfile.h"
62 
63 // C++ Includes
64 #include <map>
65 #include <vector>
66 #include <tuple>
67 #include <algorithm>
68 #include <iostream>
69 #include <string>
70 #include <cmath>
71 
72 #include <iostream>
73 #include <fstream>
74 
75 //-----------------------------------------------------------------------
76 //-----------------------------------------------------------------------
77 // class definition
78 
79 class MCTruthTestAna : public art::EDAnalyzer
80 {
81 public:
82 
83  // Standard constructor and destructor for an ART module.
84  explicit MCTruthTestAna(fhicl::ParameterSet const& pset);
85  virtual ~MCTruthTestAna();
86 
87  // This method is called once, at the start of the job. In this
88  // example, it will define the histograms and n-tuples we'll write.
89  void beginJob();
90  void endJob();
91 
92  // This method is called once, at the start of each run. It's a
93  // good place to read databases or files that may have
94  // run-dependent information.
95  void beginRun(const art::Run& run);
96 
97  // This method reads in any parameters from the .fcl files. This
98  // method is called 'reconfigure' because it might be called in the
99  // middle of a job; e.g., if the user changes parameter values in an
100  // interactive event display.
101  void reconfigure(fhicl::ParameterSet const& pset);
102 
103  // The analysis routine, called once per event.
104  void analyze (const art::Event& evt);
105 
106 private:
107 
108  // Where the data comes from
109  art::InputTag fHitProducerLabel;
110  art::InputTag fTrackProducerLabel;
111 
112  // For keeping track of the replacement backtracker
113  std::unique_ptr<truth::IMCTruthMatching> fMCTruthMatching;
114 
115  // Some histograms to keep a check on things
116  TH1D* fNumIDEHist;
127 
128  // Other variables that will be shared between different methods.
129  const geo::GeometryCore* fGeometry; // pointer to Geometry service
130 }; // class MCTruthTestAna
131 
132 
133 //-----------------------------------------------------------------------
134 //-----------------------------------------------------------------------
135 // class implementation
136 
137 //-----------------------------------------------------------------------
138 // Constructor
139 MCTruthTestAna::MCTruthTestAna(fhicl::ParameterSet const& parameterSet)
140  : EDAnalyzer(parameterSet)
141 
142 {
143  fGeometry = lar::providerFrom<geo::Geometry>();
144 
145  // Read in the parameters from the .fcl file.
146  this->reconfigure(parameterSet);
147 }
148 
149 //-----------------------------------------------------------------------
150 // Destructor
152 
153 //-----------------------------------------------------------------------
155 {
156  // Access ART's TFileService, which will handle creating and writing
157  // histograms and n-tuples for us.
158  art::ServiceHandle<art::TFileService> tfs;
159 
160  // The arguments to 'make<whatever>' are the same as those passed
161  // to the 'whatever' constructor, provided 'whatever' is a ROOT
162  // class that TFileService recognizes.
163 
164  // Define the histograms. Putting semi-colons around the title
165  // causes it to be displayed as the x-axis label if the histogram
166  // is drawn.
167  fNumIDEHist = tfs->make<TH1D>("NumIDEs", ";# ides", 20, 0., 20.);
168  fDeltaIDEHist = tfs->make<TH1D>("DeltaIDE", ";delta", 20, -10., 10.);
169  fNegEnergyHist = tfs->make<TH1D>("NegEnergy", ";energy", 500, 0., 10.);
170  fNegNElecHist = tfs->make<TH1D>("NegNumElec", ";# electrons", 200, 0., 100.);
171  fIDEMisMatchHist = tfs->make<TH1D>("IDEMisMatch", ";# mismatches", 20, 10., 10.);
172  fBTEfficiencyHist = tfs->make<TH1D>("BTEfficiency", ";efficiency", 102, 0., 1.02);
173  fAssocEfficiencyHist = tfs->make<TH1D>("AssocEffic", ";efficiency", 102, 0., 1.02);
174  fEfficiencyCompHist = tfs->make<TH2D>("Efficiency", ";BackTrack;Associations", 52, 0., 1.04, 52, 0., 1.04);
175  fBTPurityHist = tfs->make<TH1D>("BTPurity", ";Purity", 102, 0., 1.02);
176  fAssocPurityHist = tfs->make<TH1D>("AssocPurity", ";Purity", 102, 0., 1.02);
177  fPurityCompHist = tfs->make<TH2D>("Purity", ";BackTrack;Associations", 52, 0., 1.04, 52, 0., 1.04);
178 
179 }
180 
181 //-----------------------------------------------------------------------
182 void MCTruthTestAna::beginRun(const art::Run& /*run*/) {}
183 
184 //-----------------------------------------------------------------------
185 void MCTruthTestAna::reconfigure(fhicl::ParameterSet const& pset)
186 {
187  // Read parameters from the .fcl file. The names in the arguments
188  // to p.get<TYPE> must match names in the .fcl file.
189  fHitProducerLabel = pset.get<art::InputTag>("HitModuleLabel");
190  fTrackProducerLabel = pset.get<art::InputTag>("TrackProducerLabel");
191 
192  // Get the tool for MC Truth matching
193  fMCTruthMatching = art::make_tool<truth::IMCTruthMatching>(pset.get<fhicl::ParameterSet>("MCTruthMatching"));
194 
195  return;
196 }
197 
198 //-----------------------------------------------------------------------
199 void MCTruthTestAna::analyze(const art::Event& event)
200 {
201  // Recover the backtracker
202  art::ServiceHandle<cheat::BackTrackerService> backTracker;
203  art::ServiceHandle<cheat::ParticleInventoryService> partInventory;
204 
205  // "Rebuild" the maps used by the parallel backtracker
206  fMCTruthMatching->Rebuild(event);
207 
208  // Begin the comparisons by simply checking that the number of MCParticles agree between the two
209  const sim::ParticleList& particleList = fMCTruthMatching->ParticleList();
210  const sim::ParticleList& btPartList = partInventory->ParticleList();
211 
212  if (particleList.size() != btPartList.size())
213  {
214  mf::LogInfo("MCTruthTestAna") << "*** ParticleList size mismatch, BackTracker says: " << btPartList.size() << ", alternate says: " << particleList.size() << std::endl;
215  }
216 
217  // Flush with the success of passing that test, let's recover the hits and then loop through them
218  // and do hit-by-hit comparisons...
219  art::Handle<std::vector<recob::Hit> > hitHandle;
220  event.getByLabel(fHitProducerLabel, hitHandle);
221 
222  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event);
223  if (hitHandle.isValid())
224  {
225  int nTotalMisMatches(0);
226  int nNegTrackIDs(0);
227 
228  for(const auto& hit : *hitHandle)
229  {
230  int nIDEMisMatches(0);
231 
232  // Check the claimed parentage of the current hit
233  std::vector<sim::TrackIDE> trackIDEVec = fMCTruthMatching->HitToTrackID(clockData, hit);
234  std::vector<sim::TrackIDE> btTrkIDEVec = backTracker->HitToTrackIDEs(clockData, hit);
235 
236  int deltaIDs = int(btTrkIDEVec.size()) - int(trackIDEVec.size());
237 
238  fNumIDEHist->Fill(trackIDEVec.size(),1.);
239  fDeltaIDEHist->Fill(deltaIDs, 1.);
240 
241  // It can be that the BackTracker is returning IDE's with negative Track ID's and these don't
242  // appear in the associations, so bypass them here...
243  if (deltaIDs != 0)
244  {
245  int numNeg = std::count_if(btTrkIDEVec.begin(),btTrkIDEVec.end(),[](const auto& trackIDE){return trackIDE.trackID < 0;});
246 
247  deltaIDs -= numNeg;
248 
249  std::sort(btTrkIDEVec.begin(),btTrkIDEVec.end(),[](const auto& left, const auto& right){return left.trackID > right.trackID;});
250 
251  while(btTrkIDEVec.back().trackID < 0)
252  {
253  fNegEnergyHist->Fill(std::min(9.98,double(btTrkIDEVec.back().energy)), 1.);
254  fNegNElecHist->Fill(std::min(99.9,double(btTrkIDEVec.back().numElectrons)), 1.);
255 
256  btTrkIDEVec.pop_back();
257  nNegTrackIDs++;
258  }
259  }
260 
261  // Currently assume BackTracker is "correct" so loop over its output and look for match
262  for(const auto& btTrkID : btTrkIDEVec)
263  {
264  std::vector<sim::TrackIDE>::const_iterator trackIDItr = std::find_if(trackIDEVec.begin(),trackIDEVec.end(),[btTrkID](const auto& id){return btTrkID.trackID == id.trackID && btTrkID.energy == id.energy && btTrkID.numElectrons == id.numElectrons;});
265 
266  if (trackIDItr == trackIDEVec.end()) nIDEMisMatches++;
267  }
268 
269  fIDEMisMatchHist->Fill(nIDEMisMatches, 1.);
270  nTotalMisMatches += nIDEMisMatches;
271  }
272 
273  mf::LogInfo("MCTruthTestAna") << "==> Found " << nTotalMisMatches << " between BackTracker and Associations, BT reported " << nNegTrackIDs << " negative track ids \n";
274  }
275 
276  // We're on a roll now!
277  // So let's see if we can recover information about tracks
278  art::Handle<std::vector<recob::Track>> trackHandle;
279  event.getByLabel(fTrackProducerLabel, trackHandle);
280 
281  if (trackHandle.isValid())
282  {
283  // We are going to want a vector of art pointers to hits, so build here
284  std::vector<art::Ptr<recob::Hit>> hitPtrVector;
285 
286  art::fill_ptr_vector(hitPtrVector, hitHandle);
287 
288  // Recover the associations between tracks and hits
289  art::FindManyP<recob::Hit> hitTrackAssns(trackHandle, event, fTrackProducerLabel);
290 
291  int nBadEffMatches(0);
292  int nBadPurMatches(0);
293 
294  for(size_t trackIdx = 0; trackIdx < trackHandle->size(); trackIdx++)
295  {
296  art::Ptr<recob::Track> track(trackHandle,trackIdx);
297 
298  std::vector<art::Ptr<recob::Hit>> trackHitVec = hitTrackAssns.at(track.key());
299 
300  std::set<int> trackIDSet = fMCTruthMatching->GetSetOfTrackIDs(clockData, trackHitVec);
301  std::set<int> btTrkIDSet = backTracker->GetSetOfTrackIds(clockData, trackHitVec);
302 
303  // Check for case were we might have negative track IDs from the BackTracker
304  if (btTrkIDSet.size() > trackIDSet.size())
305  {
306  // Note that the container here is a std::set which will be ordered smallest to largest.
307  // In this case we want to remove elements from the front until they are positive
308  for(std::set<int>::iterator btTrkIDSetItr = btTrkIDSet.begin(); btTrkIDSetItr != btTrkIDSet.end();)
309  {
310  if (!(*btTrkIDSetItr < 0)) break;
311 
312  btTrkIDSetItr = btTrkIDSet.erase(btTrkIDSetItr);
313  }
314  }
315 
316  if (btTrkIDSet.size() != trackIDSet.size())
317  mf::LogDebug("MCTruthTestAna") << "Mismatch in associated track ids, backtracker: " << btTrkIDSet.size() << ", associations: " << trackIDSet.size() << ", track id: " << track.key() << "\n";
318 
319  // Ok, turn the "set" of track ID's into a vector of track ID's
320  std::vector<int> btTrkIDVec;
321 
322  for(auto& trackID : btTrkIDSet) btTrkIDVec.emplace_back(trackID);
323 
324  // And then use this to recover the vectors of hits associated to each MC track
325  std::vector<std::vector<art::Ptr<recob::Hit>>> trkHitVecVec;
326 
327  for(const auto& tkID : btTrkIDVec)
328  {
329  std::vector<art::Ptr<recob::Hit>> hitVec = backTracker->TrackIdToHits_Ps(clockData, tkID, hitPtrVector);
330  trkHitVecVec.push_back(hitVec);
331  }
332  // Apply majority logic - we declare the MCParticle with the most hits to be the "winner"
333  std::vector<std::vector<art::Ptr<recob::Hit>>>::iterator bestTrkHitVecItr = std::max_element(trkHitVecVec.begin(),trkHitVecVec.end(),[](const auto& a, const auto& b){return a.size() < b.size();});
334 
335  if (bestTrkHitVecItr == trkHitVecVec.end())
336  {
337  // I have been watching way too much Star Trek (the original!)
338  mf::LogDebug("MCTruthTestAna") << ">>>>>>> ERROR! >>>>>>> ERROR! >>>>>> MUST PURIFY! >>>>>> ERROR!" << "\n";
339  continue;
340  }
341 
342  int indexToBestMC = std::distance(trkHitVecVec.begin(),bestTrkHitVecItr);
343  int bestMCTrackID = btTrkIDVec.at(indexToBestMC);
344 
345  std::vector<art::Ptr<recob::Hit>>& bestMCTrackHitVec = *bestTrkHitVecItr;
346 
347  std::set<int> mcTrackIdxSet = {bestMCTrackID};
348 
349  double btTrkEffic = backTracker->HitCollectionEfficiency(clockData, mcTrackIdxSet, trackHitVec, bestMCTrackHitVec, geo::k3D);
350  double trackEffic = fMCTruthMatching->HitCollectionEfficiency(clockData, mcTrackIdxSet, trackHitVec, bestMCTrackHitVec, geo::k3D);
351 
352  if (btTrkEffic != trackEffic)
353  {
354  mf::LogDebug("MCTruthTestAna") << "Efficiency mismatch, track ID: " << bestMCTrackID << ", track: " << track.key() << ", # hits: " << trackHitVec.size() << ", # MC hits: " << bestMCTrackHitVec.size() << ", btTrkEff: " << btTrkEffic << ", trackEff: " << trackEffic << "\n|";
355  nBadEffMatches++;
356  }
357 
358  fBTEfficiencyHist->Fill(std::min(1.01,btTrkEffic), 1.);
359  fAssocEfficiencyHist->Fill(std::min(1.01,trackEffic), 1.);
360  fEfficiencyCompHist->Fill(std::min(1.01,btTrkEffic), std::min(1.01,trackEffic), 1.);
361 
362  double btTrkPurity = backTracker->HitCollectionPurity(clockData, mcTrackIdxSet, trackHitVec);
363  double trackPurity = fMCTruthMatching->HitCollectionPurity(clockData, mcTrackIdxSet, trackHitVec);
364 
365  if (btTrkPurity != trackPurity)
366  {
367  mf::LogDebug("MCTruthTestAna") << "Purity mismatch, track ID: " << bestMCTrackID << ", track: " << track.key() << ", # hits: " << trackHitVec.size() << ", # MC hits: " << bestMCTrackHitVec.size() << ", btTrkPurity: " << btTrkPurity << ", trackPurity: " << trackPurity << "\n|";
368  nBadPurMatches++;
369  }
370 
371  fBTPurityHist->Fill(std::min(1.01,btTrkPurity), 1.);
372  fAssocPurityHist->Fill(std::min(1.01,trackPurity), 1.);
373  fPurityCompHist->Fill(std::min(1.01,btTrkPurity),std::min(1.01,trackPurity), 1.);
374  }
375 
376  mf::LogDebug("MCTruthTestAna") << "Event with " << trackHandle->size() << " reconstructed tracks, found " << nBadEffMatches << " efficiency mismatches, " << nBadPurMatches << " purity mismatchs \n";
377  }
378 
379  return;
380 }
381 
383 {
384  // Make a call to normalize histograms if so desired
385 
386  return;
387 }
388 
389 // This macro has to be defined for this module to be invoked from a
390 // .fcl file; see MCTruthTestAna.fcl for more information.
391 DEFINE_ART_MODULE(MCTruthTestAna)
Utilities related to art service access.
Declaration of signal hit object.
walls no right
Definition: selectors.fcl:105
const geo::GeometryCore * fGeometry
This provides an interface which defines truth matching functions made available to downstream analys...
void analyze(const art::Event &evt)
MCTruthTestAna(fhicl::ParameterSet const &pset)
process_name use argoneut_mc_hitfinder track
process_name hit
Definition: cheaterreco.fcl:51
3-dimensional objects, potentially hits, clusters, prongs, etc.
Definition: geo_types.h:135
process_name gaushit a
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
art::InputTag fTrackProducerLabel
walls no left
Definition: selectors.fcl:105
Description of geometry of one entire detector.
void reconfigure(fhicl::ParameterSet const &pset)
Declaration of cluster object.
Definition of data types for geometry description.
Provides recob::Track data product.
void beginRun(const art::Run &run)
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
art::InputTag fHitProducerLabel
art framework interface to geometry description
std::unique_ptr< truth::IMCTruthMatching > fMCTruthMatching