All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ClusteringValidation_module.cc
Go to the documentation of this file.
1 //////////////////////////////////////////////////////////////////////////////////////
2 // Class: ClusteringValidation
3 // Module type: analyser
4 // File: ClusteringValidation_module.cc
5 // Author: Mike Wallbank (m.wallbank@sheffied.ac.uk), May 2015
6 //
7 // A module to validate clustering algorithms.
8 // Compares the output of different clustering algorithms run over a pi0 sample.
9 //
10 // Usage: Specify the hit finder (HitsModuleLabel) and the clustering outputs
11 // to validate (ClusterModuleLabels) in the fhicl file.
12 // Module will make validation plots for all clusterings specified and also
13 // produce comparison plots. Number of clusterings to analyse can be one or more.
14 // Saves everything in the file validationHistograms.root.
15 //////////////////////////////////////////////////////////////////////////////////////
16 
17 #include "art/Framework/Core/EDAnalyzer.h"
18 #include "art/Framework/Core/ModuleMacros.h"
19 #include "art/Framework/Principal/Event.h"
20 #include "art/Framework/Principal/Handle.h"
21 #include "art/Framework/Services/Registry/ServiceHandle.h"
22 #include "canvas/Persistency/Common/FindManyP.h"
23 #include "canvas/Persistency/Common/Ptr.h"
24 #include "fhiclcpp/ParameterSet.h"
25 
26 // LArSoft includes
33 #include "nusimdata/SimulationBase/MCParticle.h"
34 
35 // ROOT & STL includes
36 #include "TCanvas.h"
37 #include "TEfficiency.h"
38 #include "TFile.h"
39 #include "TH1.h"
40 #include "TH2D.h"
41 #include "TLegend.h"
42 #include "TProfile.h"
43 #include "TStyle.h"
44 
45 #include <algorithm>
46 #include <fstream>
47 #include <iostream>
48 #include <map>
49 
52  class ClusterAnalyser;
53  class ClusterCounter;
54 }
55 
56 enum class ClusterID : int {};
57 enum class TrackID : int {};
58 typedef std::vector<ClusterID> ClusterIDs;
59 typedef std::vector<TrackID> TrackIDs;
60 
62 public:
63  explicit ClusterCounter(unsigned int& tpc, unsigned int& plane);
64 
68  void AssociateClusterAndTrack(ClusterID clusID, TrackID trackID);
69  double GetCompleteness(ClusterID id);
70  double GetCleanliness(ClusterID id);
71  double GetEfficiency(TrackID id);
77  std::vector<std::pair<TrackID, ClusterIDs>> GetPhotons();
79  bool IsNoise(ClusterID id);
80  bool IsNoise(TrackID id);
81  bool PassesCut();
82 
83 private:
84  unsigned int tpc, plane;
85 
86  std::map<TrackID, int> numHitsPreClustering;
87  std::map<ClusterID, int> numSignalHitsPostClustering;
88  std::map<ClusterID, int> numNoiseHitsPostClustering;
89  std::map<ClusterID, TrackID> clusterToTrackID;
90  std::map<TrackID, ClusterIDs> trackToClusterIDs;
91  std::map<TrackID, std::map<std::string, double>> particleProperties;
92  std::map<TrackID, simb::MCParticle> trueParticles;
93 
94  art::ServiceHandle<geo::Geometry const> geometry;
95  art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
96  art::ServiceHandle<cheat::ParticleInventoryService> pi_serv;
97 };
98 
100 {
101  tpc = t;
102  plane = p;
103 }
104 
105 void
107 {
108  ++numHitsPreClustering[trackID];
109 }
110 
111 void
113 {
114  ++numSignalHitsPostClustering[clusID];
115 }
116 
117 void
119 {
120  ++numNoiseHitsPostClustering[clusID];
121 }
122 
123 void
125 {
126  clusterToTrackID[clusID] = trackID;
127  trackToClusterIDs[trackID].push_back(clusID);
128 }
129 
130 double
132 {
133  return (double)numSignalHitsPostClustering[clusID] /
134  (double)numHitsPreClustering[clusterToTrackID[clusID]];
135 }
136 
137 double
139 {
140  return (double)numSignalHitsPostClustering[clusID] / (double)(GetNumberHitsInCluster(clusID));
141 }
142 
143 double
145 {
146  return 1 / (double)trackToClusterIDs.at(trackID).size();
147 }
148 
149 int
151 {
152  return numHitsPreClustering[trackID];
153 }
154 
155 int
157 {
158  return numSignalHitsPostClustering[clusID] + numNoiseHitsPostClustering[clusID];
159 }
160 
161 int
163 {
164  int nHits = 0;
165  for (auto& trackHits : numHitsPreClustering)
166  nHits += trackHits.second;
167  return nHits;
168 }
169 
172 {
173  ClusterIDs v;
174  for (std::map<ClusterID, TrackID>::iterator i = clusterToTrackID.begin();
175  i != clusterToTrackID.end();
176  i++)
177  v.push_back(i->first);
178  return v;
179 }
180 
181 TrackIDs
183 {
184  TrackIDs v;
185  for (std::map<TrackID, ClusterIDs>::iterator i = trackToClusterIDs.begin();
186  i != trackToClusterIDs.end();
187  i++)
188  v.push_back(i->first);
189  return v;
190 }
191 
192 std::vector<std::pair<TrackID, ClusterIDs>>
194 {
195  std::vector<std::pair<TrackID, ClusterIDs>> photonVector;
196  for (unsigned int track = 0; track < GetListOfTrackIDs().size(); ++track)
197  if (!IsNoise(GetListOfTrackIDs().at(track)) &&
198  pi_serv->TrackIdToParticle_P((int)GetListOfTrackIDs().at(track))->PdgCode() == 22)
199  photonVector.push_back(std::pair<TrackID, ClusterIDs>(
200  GetListOfTrackIDs().at(track), trackToClusterIDs.at(GetListOfTrackIDs().at(track))));
201  return photonVector;
202 }
203 
204 TrackID
206 {
207  return clusterToTrackID.at(id);
208 }
209 
210 bool
212 {
213  return IsNoise(clusterToTrackID.at(clusID));
214 }
215 
216 bool
218 {
219  return (int)trackID == 0 ? true : false;
220 }
221 
222 bool
224 {
225  if (GetPhotons().size() > 2 || GetPhotons().size() == 0) return false;
226  TrackIDs goodPhotons;
227  for (unsigned int photon = 0; photon < GetPhotons().size(); ++photon)
228  for (unsigned int cluster = 0; cluster < GetPhotons().at(photon).second.size(); ++cluster)
229  if (GetCompleteness(GetPhotons().at(photon).second.at(cluster)) > 0.5)
230  goodPhotons.push_back(GetPhotons().at(photon).first);
231  if ((GetPhotons().size() == 2 && goodPhotons.size() > 2) ||
232  (GetPhotons().size() == 1 && goodPhotons.size() > 1))
233  std::cout << "More than 2 with >50%?!" << std::endl;
234  bool pass = ((GetPhotons().size() == 2 && goodPhotons.size() == 2) ||
235  (GetPhotons().size() == 1 && goodPhotons.size() == 1));
236  return pass;
237 }
238 
239 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
241 public:
242  explicit ClusterAnalyser(std::string& label);
243 
244  void Analyse(detinfo::DetectorClocksData const& clockData,
245  std::vector<art::Ptr<recob::Hit>>& hits,
246  std::vector<art::Ptr<recob::Cluster>>& clusters,
247  const art::FindManyP<recob::Hit>& fmh,
248  int numHits);
249  TrackID FindTrackID(detinfo::DetectorClocksData const& clockData, art::Ptr<recob::Hit>& hit);
250  TrackID FindTrueTrack(detinfo::DetectorClocksData const& clockData,
251  std::vector<art::Ptr<recob::Hit>>& clusterHits);
252  double FindPhotonAngle();
253  double GetEndTrackDistance(TrackID id1, TrackID id2);
254  const simb::MCParticle* GetPi0();
255  TObjArray GetHistograms();
256  void MakeHistograms();
257  void WriteFile();
258 
259 private:
260  // Clustering properties
261  std::string fClusterLabel;
262 
263  // hists
264  TH1 *hCompleteness, *hCleanliness, *hComplCleanl;
265  TH1 *hPi0Angle, *hPi0Energy, *hPi0ConversionDistance, *hPi0ConversionSeparation, *hPi0AngleCut,
266  *hPi0EnergyCut, *hPi0ConversionDistanceCut, *hPi0ConversionSeparationCut;
267  TH2 *hNumHitsCompleteness, *hNumHitsEnergy;
268  TProfile *hCompletenessEnergy, *hCompletenessAngle, *hCompletenessConversionDistance,
269  *hCompletenessConversionSeparation;
270  TProfile *hCleanlinessEnergy, *hCleanlinessAngle, *hCleanlinessConversionDistance,
271  *hCleanlinessConversionSeparation;
272  TProfile *hComplCleanlEnergy, *hComplCleanlAngle, *hComplCleanlConversionDistance,
273  *hComplCleanlConversionSeparation;
274  TEfficiency *hEfficiencyAngle, *hEfficiencyEnergy, *hEfficiencyConversionDistance,
275  *hEfficiencyConversionSeparation;
276  TObjArray fHistArray;
277 
278  std::map<unsigned int, std::map<unsigned int, std::unique_ptr<ClusterCounter>>> clusterMap;
279  std::map<TrackID, const simb::MCParticle*> trueParticles;
280 
281  // Services
282  art::ServiceHandle<geo::Geometry const> geometry;
283  art::ServiceHandle<cheat::ParticleInventoryService const> pi_serv;
284  art::ServiceHandle<cheat::BackTrackerService const> bt_serv;
285 };
286 
288 {
289 
290  fClusterLabel = clusterLabel;
291 
292  // Make the histograms
293  hCompleteness = new TH1D("Completeness", ";Completeness;", 101, 0, 1.01);
294  hCompletenessEnergy =
295  new TProfile("CompletenessEnergy", ";True Energy (GeV);Completeness", 100, 0, 2);
296  hCompletenessAngle =
297  new TProfile("CompletenessAngle", ";True Angle (deg);Completeness;", 100, 0, 180);
298  hCompletenessConversionDistance = new TProfile(
299  "CompletenessConversionDistance", ";True Distance from Vertex (cm);Completeness", 100, 0, 200);
300  hCompletenessConversionSeparation = new TProfile("CompletenessConversionSeparation",
301  ";True Conversion Separation (cm);Completeness",
302  100,
303  0,
304  200);
305  hCleanliness = new TH1D("Cleanliness", ";Cleanliness;", 101, 0, 1.01);
306  hCleanlinessEnergy =
307  new TProfile("CleanlinessEnergy", ";True Energy (GeV);Cleanliness", 100, 0, 2);
308  hCleanlinessAngle =
309  new TProfile("CleanlinessAngle", ";True Angle (deg);Cleanliness;", 100, 0, 180);
310  hCleanlinessConversionDistance = new TProfile(
311  "CleanlinessConversionDistance", ";True Distance from Vertex (cm);Cleanliness", 100, 0, 200);
312  hCleanlinessConversionSeparation = new TProfile(
313  "CleanlinessConversionSeparation", ";True Conversion Separation (cm);Cleanliness", 100, 0, 200);
314  hComplCleanl = new TH1D("CompletenessCleanliness", ";Completeness * Cleanliness;", 101, 0, 1.01);
315  hComplCleanlEnergy = new TProfile(
316  "CompletenessCleanlinessEnergy", ";True Energy (GeV);Completeness * Cleanliness", 100, 0, 2);
317  hComplCleanlAngle = new TProfile(
318  "CompletenessCleanlinessAngle", ";True Angle (deg);Completeness * Cleanliness;", 100, 0, 180);
319  hComplCleanlConversionDistance =
320  new TProfile("CompletenessCleanlinessConversionDistance",
321  ";True Distance from Vertex (cm);Completeness * Cleanliness",
322  100,
323  0,
324  200);
325  hComplCleanlConversionSeparation =
326  new TProfile("CompletenessCleanlinessConversionSeparation",
327  ";True Conversion Separation (cm);Completeness * Cleanliness",
328  100,
329  0,
330  200);
331  hPi0Energy = new TH1D("Pi0EnergyCut", ";True Energy (GeV);", 25, 0, 2);
332  hPi0Energy->Sumw2();
333  hPi0Angle = new TH1D("Pi0AngleCut", ";True Angle (deg);", 25, 0, 180);
334  hPi0Angle->Sumw2();
335  hPi0ConversionDistance =
336  new TH1D("Pi0ConversionDistanceCut", ";True Distance from Vertex (cm);", 25, 0, 200);
337  hPi0ConversionDistance->Sumw2();
338  hPi0ConversionSeparation =
339  new TH1D("Pi0ConversionSeparationCut", ";True Separation from Vertex (cm);", 25, 0, 200);
340  hPi0ConversionSeparation->Sumw2();
341  hPi0EnergyCut = new TH1D("Pi0EnergyCut", ";True Energy (GeV);Efficiency", 25, 0, 2);
342  hPi0EnergyCut->Sumw2();
343  hPi0AngleCut = new TH1D("Pi0AngleCut", ";True Angle (deg);Efficiency", 25, 0, 180);
344  hPi0AngleCut->Sumw2();
345  hPi0ConversionDistanceCut =
346  new TH1D("Pi0ConversionDistanceCut", ";True Distance from Vertex (cm);Efficiency", 25, 0, 200);
347  hPi0ConversionDistanceCut->Sumw2();
348  hPi0ConversionSeparationCut = new TH1D(
349  "Pi0ConversionSeparationCut", ";True Separation from Vertex (cm);Efficiency", 25, 0, 200);
350  hPi0ConversionSeparationCut->Sumw2();
351  hNumHitsCompleteness =
352  new TH2D("NumHitsCompleteness", ";Completeness;Size of Cluster", 101, 0, 1.01, 100, 0, 100);
353  hNumHitsEnergy =
354  new TH2D("NumHitsEnergy", ";True Energy (GeV);Size of Cluster", 100, 0, 2, 100, 0, 100);
355 }
356 
357 void
359  std::vector<art::Ptr<recob::Hit>>& hits,
360  std::vector<art::Ptr<recob::Cluster>>& clusters,
361  const art::FindManyP<recob::Hit>& fmh,
362  int minHits)
363 {
364 
365  // Make a map of cluster counters in TPC/plane space
366  for (unsigned int tpc = 0; tpc < geometry->NTPC(0); ++tpc) {
367  for (unsigned int plane = 0; plane < geometry->Nplanes(tpc, 0); ++plane) {
368  clusterMap[tpc][plane] = (std::unique_ptr<ClusterCounter>)new ClusterCounter(tpc, plane);
369  }
370  }
371 
372  // Save preclustered hits
373  for (size_t hitIt = 0; hitIt < hits.size(); ++hitIt) {
374  art::Ptr<recob::Hit> hit = hits.at(hitIt);
375  TrackID trackID = FindTrackID(clockData, hit);
376  clusterMap[hit->WireID().TPC % 2][hit->WireID().Plane]->AddHitPreClustering(trackID);
377  }
378 
379  // Save true tracks
380  trueParticles.clear();
381  const sim::ParticleList& particles = pi_serv->ParticleList();
382  for (sim::ParticleList::const_iterator particleIt = particles.begin();
383  particleIt != particles.end();
384  ++particleIt) {
385  const simb::MCParticle* particle = particleIt->second;
386  trueParticles[(TrackID)particle->TrackId()] = particle;
387  }
388 
389  // Save the clustered hits
390  for (size_t clusIt = 0; clusIt < clusters.size(); ++clusIt) {
391 
392  // Get cluster information
393  unsigned int tpc = clusters.at(clusIt)->Plane().TPC % 2;
394  unsigned int plane = clusters.at(clusIt)->Plane().Plane;
395  ClusterID id = (ClusterID)clusters.at(clusIt)->ID();
396 
397  // Only analyse planes with enough hits in to fairly represent the clustering
398  if (clusterMap[tpc][plane]->GetNumberHitsInPlane() < minHits) continue;
399 
400  // Get the hits from the cluster
401  std::vector<art::Ptr<recob::Hit>> clusterHits = fmh.at(clusIt);
402 
403  if (clusterHits.size() < 10) continue;
404 
405  // Find which track this cluster belongs to
406  TrackID trueTrackID = FindTrueTrack(clockData, clusterHits);
407 
408  // Save the info for this cluster
409  clusterMap[tpc][plane]->AssociateClusterAndTrack(id, trueTrackID);
410  for (std::vector<art::Ptr<recob::Hit>>::iterator clusHitIt = clusterHits.begin();
411  clusHitIt != clusterHits.end();
412  ++clusHitIt) {
413  art::Ptr<recob::Hit> hit = *clusHitIt;
414  TrackID trackID = FindTrackID(clockData, hit);
415  if (trackID == trueTrackID)
416  clusterMap[tpc][plane]->AddSignalHitPostClustering(id);
417  else
418  clusterMap[tpc][plane]->AddNoiseHitPostClustering(id);
419  }
420  }
421 
422  this->MakeHistograms();
423 }
424 
425 TrackID
427  art::Ptr<recob::Hit>& hit)
428 {
429  double particleEnergy = 0;
430  TrackID likelyTrackID = (TrackID)0;
431  std::vector<sim::TrackIDE> trackIDs = bt_serv->HitToTrackIDEs(clockData, hit);
432  for (unsigned int idIt = 0; idIt < trackIDs.size(); ++idIt) {
433  if (trackIDs.at(idIt).energy > particleEnergy) {
434  particleEnergy = trackIDs.at(idIt).energy;
435  likelyTrackID = (TrackID)TMath::Abs(trackIDs.at(idIt).trackID);
436  }
437  }
438  return likelyTrackID;
439 }
440 
441 TrackID
443  std::vector<art::Ptr<recob::Hit>>& clusterHits)
444 {
445  std::map<TrackID, double> trackMap;
446  for (std::vector<art::Ptr<recob::Hit>>::iterator clusHitIt = clusterHits.begin();
447  clusHitIt != clusterHits.end();
448  ++clusHitIt) {
449  art::Ptr<recob::Hit> hit = *clusHitIt;
450  TrackID trackID = FindTrackID(clockData, hit);
451  trackMap[trackID] += hit->Integral();
452  }
453  //return std::max_element(trackMap.begin(), trackMap.end(), [](const std::pair<int,double>& p1, const std::pair<int,double>& p2) {return p1.second < p2.second;} )->first;
454  double highestCharge = 0;
455  TrackID clusterTrack = (TrackID)0;
456  for (std::map<TrackID, double>::iterator trackIt = trackMap.begin(); trackIt != trackMap.end();
457  ++trackIt)
458  if (trackIt->second > highestCharge) {
459  highestCharge = trackIt->second;
460  clusterTrack = trackIt->first;
461  }
462  return clusterTrack;
463 }
464 
465 double
467 {
468  const simb::MCParticle* pi0 = GetPi0();
469  if (pi0->NumberDaughters() != 2) return -999;
470  double angle = (trueParticles.at((TrackID)pi0->Daughter(0))
471  ->Momentum()
472  .Angle(trueParticles.at((TrackID)pi0->Daughter(1))->Momentum().Vect()) *
473  (180 / TMath::Pi()));
474  return angle;
475 }
476 
477 const simb::MCParticle*
479 {
480  const simb::MCParticle* pi0 = nullptr;
481  for (std::map<TrackID, const simb::MCParticle*>::iterator particleIt = trueParticles.begin();
482  particleIt != trueParticles.end();
483  ++particleIt)
484  if (particleIt->second->PdgCode() == 111) pi0 = particleIt->second;
485  return pi0;
486 }
487 
488 double
490 {
491  return TMath::Sqrt(
492  TMath::Power(
493  trueParticles.at(id1)->EndPosition().X() - trueParticles.at(id2)->EndPosition().X(), 2) +
494  TMath::Power(
495  trueParticles.at(id1)->EndPosition().Y() - trueParticles.at(id2)->EndPosition().Y(), 2) +
496  TMath::Power(
497  trueParticles.at(id1)->EndPosition().Z() - trueParticles.at(id2)->EndPosition().Z(), 2));
498 }
499 
500 TObjArray
502 {
503 
504  // Make efficiency histograms
505  hEfficiencyEnergy = new TEfficiency(*hPi0EnergyCut, *hPi0Energy);
506  hEfficiencyAngle = new TEfficiency(*hPi0AngleCut, *hPi0Angle);
507  hEfficiencyConversionDistance =
508  new TEfficiency(*hPi0ConversionDistanceCut, *hPi0ConversionDistance);
509  hEfficiencyConversionSeparation =
510  new TEfficiency(*hPi0ConversionSeparationCut, *hPi0ConversionSeparation);
511 
512  hEfficiencyEnergy->SetName("EfficiencyEnergy");
513  hEfficiencyAngle->SetName("EnergyAngle");
514  hEfficiencyConversionDistance->SetName("EfficiencyConversionDistance");
515  hEfficiencyConversionSeparation->SetName("EfficiencyConversionSeparation");
516 
517  // Add all the histograms to the object array
518  fHistArray.Add(hCompleteness);
519  fHistArray.Add(hCompletenessEnergy);
520  fHistArray.Add(hCompletenessAngle);
521  fHistArray.Add(hCompletenessConversionDistance);
522  fHistArray.Add(hCompletenessConversionSeparation);
523  fHistArray.Add(hCleanliness);
524  fHistArray.Add(hCleanlinessEnergy);
525  fHistArray.Add(hCleanlinessAngle);
526  fHistArray.Add(hCleanlinessConversionDistance);
527  fHistArray.Add(hCleanlinessConversionSeparation);
528  fHistArray.Add(hComplCleanl);
529  fHistArray.Add(hComplCleanlEnergy);
530  fHistArray.Add(hComplCleanlAngle);
531  fHistArray.Add(hComplCleanlConversionDistance);
532  fHistArray.Add(hComplCleanlConversionSeparation);
533  fHistArray.Add(hEfficiencyEnergy);
534  fHistArray.Add(hEfficiencyAngle);
535  fHistArray.Add(hEfficiencyConversionDistance);
536  fHistArray.Add(hEfficiencyConversionSeparation);
537  fHistArray.Add(hNumHitsCompleteness);
538  fHistArray.Add(hNumHitsEnergy);
539 
540  return fHistArray;
541 }
542 
543 void
545 {
546 
547  // Loop over the tpcs and planes in the geometry
548  for (unsigned int tpc = 0; tpc < geometry->NTPC(0); ++tpc) {
549  for (unsigned int plane = 0; plane < geometry->Nplanes(tpc, 0); ++plane) {
550 
551  ClusterIDs clusterIDs = clusterMap[tpc][plane]->GetListOfClusterIDs();
552 
553  // Fill histograms for the efficiency
554  if (clusterMap[tpc][plane]->GetPhotons().size() == 2) {
555  hPi0Angle->Fill(FindPhotonAngle());
556  hPi0Energy->Fill(GetPi0()->Momentum().E());
557  hPi0ConversionDistance->Fill(
558  std::min(GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(0).first,
559  (TrackID)GetPi0()->TrackId()),
560  GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(1).first,
561  (TrackID)GetPi0()->TrackId())));
562  hPi0ConversionSeparation->Fill(
563  GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(0).first,
564  clusterMap[tpc][plane]->GetPhotons().at(1).first));
565  if (clusterMap[tpc][plane]->PassesCut()) {
566  hPi0AngleCut->Fill(FindPhotonAngle());
567  hPi0EnergyCut->Fill(GetPi0()->Momentum().E());
568  hPi0ConversionDistanceCut->Fill(
569  std::min(GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(0).first,
570  (TrackID)GetPi0()->TrackId()),
571  GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(1).first,
572  (TrackID)GetPi0()->TrackId())));
573  hPi0ConversionSeparationCut->Fill(
574  GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(0).first,
575  clusterMap[tpc][plane]->GetPhotons().at(1).first));
576  }
577  else
578  std::cout << "TPC " << tpc << ", Plane " << plane << " fails the cut" << std::endl;
579  }
580 
581  // Look at all the clusters
582  for (unsigned int cluster = 0; cluster < clusterIDs.size(); ++cluster) {
583 
584  ClusterID clusID = clusterIDs.at(cluster);
585  double completeness = clusterMap[tpc][plane]->GetCompleteness(clusID);
586  double cleanliness = clusterMap[tpc][plane]->GetCleanliness(clusID);
587  int numClusterHits = clusterMap[tpc][plane]->GetNumberHitsInCluster(clusID);
588 
589  // Fill histograms for this cluster
590  hCompleteness->Fill(completeness, numClusterHits);
591  hCleanliness->Fill(cleanliness, numClusterHits);
592  hComplCleanl->Fill(completeness * cleanliness, numClusterHits);
593  hNumHitsCompleteness->Fill(completeness, numClusterHits);
594 
595  // Is this cluster doesn't correspond to a true particle continue
596  if (clusterMap[tpc][plane]->IsNoise(clusID)) continue;
597 
598  double pi0Energy = GetPi0()->Momentum().E();
599  double pi0DecayAngle = FindPhotonAngle();
600  double conversionDistance = GetEndTrackDistance(clusterMap[tpc][plane]->GetTrack(clusID),
601  (TrackID)GetPi0()->TrackId());
602 
603  hCompletenessEnergy->Fill(pi0Energy, completeness, numClusterHits);
604  hCompletenessAngle->Fill(pi0DecayAngle, completeness, numClusterHits);
605  hCompletenessConversionDistance->Fill(conversionDistance, completeness, numClusterHits);
606  hCleanlinessEnergy->Fill(pi0Energy, cleanliness, numClusterHits);
607  hCleanlinessAngle->Fill(pi0DecayAngle, cleanliness, numClusterHits);
608  hCleanlinessConversionDistance->Fill(conversionDistance, cleanliness, numClusterHits);
609  hComplCleanlEnergy->Fill(pi0Energy, cleanliness * completeness, numClusterHits);
610  hComplCleanlAngle->Fill(pi0DecayAngle, cleanliness * completeness, numClusterHits);
611  hComplCleanlConversionDistance->Fill(
612  conversionDistance, cleanliness * completeness, numClusterHits);
613  hNumHitsEnergy->Fill(pi0Energy, numClusterHits);
614 
615  // Continue if there are not two photons in the view
616  if (clusterMap[tpc][plane]->GetPhotons().size() != 2) continue;
617 
618  double conversionSeparation =
619  GetEndTrackDistance(clusterMap[tpc][plane]->GetPhotons().at(0).first,
620  clusterMap[tpc][plane]->GetPhotons().at(1).first);
621 
622  hCompletenessConversionSeparation->Fill(conversionSeparation, completeness, numClusterHits);
623  hCleanlinessConversionSeparation->Fill(conversionSeparation, cleanliness, numClusterHits);
624  }
625  }
626  }
627 }
628 
629 void
631 {
632 
633  // Average completeness/cleanliness
634  double avCompleteness = hCompleteness->GetMean();
635  double avCleanliness = hCleanliness->GetMean();
636 
637  // Write file
638  std::ofstream outFile("effpur");
639  outFile << avCompleteness << " " << avCleanliness;
640  outFile.close();
641 }
642 
643 // --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
644 class ClusteringValidation::ClusteringValidation : public art::EDAnalyzer {
645 public:
646  explicit ClusteringValidation(fhicl::ParameterSet const& p);
647 
648 private:
649  void analyze(art::Event const& evt);
650  void beginJob();
651  void endJob();
652 
653  // Clusterings to compare and the hits which the clustering was run over
654  std::vector<std::string> fClusterModuleLabels;
655  std::string fHitsModuleLabel;
656 
657  // Minimum hits needed to analyse a plane
659 
660  // Canvas on which to save histograms
661  TCanvas* fCanvas;
662 
663  // The cluster analysers
664  // -- one for each clustering type being compared
665  std::map<std::string, std::unique_ptr<ClusterAnalyser>> clusterAnalysis;
666 };
667 
669  : EDAnalyzer(pset)
670 {
671  fMinHitsInPlane = pset.get<int>("MinHitsInPlane");
672  fClusterModuleLabels = pset.get<std::vector<std::string>>("ClusterModuleLabels");
673  fHitsModuleLabel = pset.get<std::string>("HitsModuleLabel");
674 
675  fCanvas = new TCanvas("fCanvas", "", 800, 600);
676  gStyle->SetOptStat(0);
677 }
678 
679 void
681 {
682  // Get the hits from the event
683  art::Handle<std::vector<recob::Hit>> hitHandle;
684  std::vector<art::Ptr<recob::Hit>> hits;
685  if (evt.getByLabel(fHitsModuleLabel, hitHandle)) art::fill_ptr_vector(hits, hitHandle);
686 
687  // Get clustering information from event
688  // and give to the ClusterAnalyser to analyse
689  for (auto clustering : fClusterModuleLabels) {
690 
691  // Get the clusters from the event
692  art::Handle<std::vector<recob::Cluster>> clusterHandle;
693  std::vector<art::Ptr<recob::Cluster>> clusters;
694  if (evt.getByLabel(clustering, clusterHandle)) art::fill_ptr_vector(clusters, clusterHandle);
695 
696  // Find the associations (the hits) for the clusters
697  art::FindManyP<recob::Hit> fmh(clusterHandle, evt, clustering);
698 
699  // Analyse this particular clustering
700  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(evt);
701  clusterAnalysis.at(clustering)->Analyse(clockData, hits, clusters, fmh, fMinHitsInPlane);
702  }
703 }
704 
705 void
707 {
708 
709  // Construct the cluster analysers here
710  // -- one for each of the clustering types to compare
711  for (auto clustering : fClusterModuleLabels)
712  clusterAnalysis[clustering] = (std::unique_ptr<ClusterAnalyser>)new ClusterAnalyser(clustering);
713 }
714 
715 void
717 {
718 
719  // Make a map of all the histograms for each clustering
720  std::map<std::string, TObjArray> allHistograms;
721  for (auto clustering : fClusterModuleLabels)
722  allHistograms[clustering] = clusterAnalysis.at(clustering)->GetHistograms();
723 
724  // Write histograms to file
725  TFile* file = TFile::Open("validationHistograms.root", "RECREATE");
726  for (auto clustering : fClusterModuleLabels) {
727  file->cd();
728  file->mkdir(clustering.c_str());
729  file->cd(clustering.c_str());
730  for (int histIt = 0; histIt < allHistograms.begin()->second.GetEntriesFast(); ++histIt)
731  allHistograms.at(clustering).At(histIt)->Write();
732  }
733 
734  // Write images of overlaid histograms
735  for (int histIt = 0; histIt < allHistograms.begin()->second.GetEntriesFast(); ++histIt) {
736  fCanvas->cd();
737  fCanvas->Clear();
738  const char* name = allHistograms.begin()->second.At(histIt)->GetName();
739  TLegend* l = new TLegend(0.6, 0.8, 0.8, 0.9, name, "brNDC");
740  int clusterings = 1;
741  for (std::map<std::string, TObjArray>::iterator clusteringIt = allHistograms.begin();
742  clusteringIt != allHistograms.end();
743  ++clusteringIt, ++clusterings) {
744  TH1* h = (TH1*)allHistograms.at(clusteringIt->first).At(histIt);
745  h->SetLineColor(clusterings);
746  h->SetMarkerColor(clusterings);
747  if (clusterings == 1)
748  h->Draw();
749  else
750  h->Draw("same");
751  l->AddEntry(h, clusteringIt->first.c_str(), "lp");
752  }
753  l->Draw("same");
754  //fCanvas->SaveAs(name+TString(".png"));
755  file->cd();
756  fCanvas->Write(name);
757  }
758 
759  file->Close();
760  delete file;
761 
762  if (clusterAnalysis.find("blurredclusteringdc") != clusterAnalysis.end())
763  clusterAnalysis.at("blurredclusteringdc")->WriteFile();
764 }
765 
art::ServiceHandle< cheat::BackTrackerService const > bt_serv
process_name can override from command line with o or output photon
Definition: runPID.fcl:28
std::map< ClusterID, int > numNoiseHitsPostClustering
const geo::GeometryCore * geometry
process_name cluster
Definition: cheaterreco.fcl:51
art::ServiceHandle< cheat::BackTrackerService const > bt_serv
std::vector< TrackID > TrackIDs
* file
Definition: file_to_url.sh:69
Declaration of signal hit object.
art::ServiceHandle< geo::Geometry const > geometry
pdgs p
Definition: selectors.fcl:22
double GetEndTrackDistance(TrackID id1, TrackID id2)
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
process_name E
process_name use argoneut_mc_hitfinder track
std::map< TrackID, ClusterIDs > trackToClusterIDs
std::map< TrackID, std::map< std::string, double > > particleProperties
process_name hit
Definition: cheaterreco.fcl:51
TString outFile
ClusterCounter(unsigned int &tpc, unsigned int &plane)
std::map< ClusterID, int > numSignalHitsPostClustering
while getopts h
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
TrackID FindTrackID(detinfo::DetectorClocksData const &clockData, art::Ptr< recob::Hit > &hit)
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
std::vector< std::pair< TrackID, ClusterIDs > > GetPhotons()
art::ServiceHandle< cheat::ParticleInventoryService const > pi_serv
TrackID FindTrueTrack(detinfo::DetectorClocksData const &clockData, std::vector< art::Ptr< recob::Hit >> &clusterHits)
std::vector< ClusterID > ClusterIDs
Declaration of cluster object.
std::map< unsigned int, std::map< unsigned int, std::unique_ptr< ClusterCounter > > > clusterMap
unsigned int NTPC(unsigned int cstat=0) const
Returns the total number of TPCs in the specified cryostat.
std::map< TrackID, const simb::MCParticle * > trueParticles
Contains all timing reference information for the detector.
Var Sqrt(const Var &v)
Use to take sqrt of a var.
Definition: Var.cxx:172
std::map< TrackID, simb::MCParticle > trueParticles
void AssociateClusterAndTrack(ClusterID clusID, TrackID trackID)
then echo fcl name
finds tracks best matching by angle
TCEvent evt
Definition: DataStructs.cxx:8
void Analyse(detinfo::DetectorClocksData const &clockData, std::vector< art::Ptr< recob::Hit >> &hits, std::vector< art::Ptr< recob::Cluster >> &clusters, const art::FindManyP< recob::Hit > &fmh, int numHits)
std::map< ClusterID, TrackID > clusterToTrackID
art framework interface to geometry description
BEGIN_PROLOG could also be cout
std::map< std::string, std::unique_ptr< ClusterAnalyser > > clusterAnalysis
art::ServiceHandle< cheat::ParticleInventoryService > pi_serv
art::ServiceHandle< geo::Geometry const > geometry