All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
Dazzle_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: Dazzle
3 // Plugin Type: producer (art v3_05_01)
4 // File: Dazzle_module.cc
5 //
6 // Generated at Tue Jan 26 08:37:49 2021 by Edward Tyley using cetskelgen
7 // from cetlib version v3_10_00.
8 //
9 // Module that attempts to classify each tracks as either:
10 // - Muon (13)
11 // - Pion (211)
12 // - Proton (2212)
13 // - Other (0)
14 //
15 // If a track is not classified (becuase it is too short) it will be
16 // assigned a pdg of -5
17 ////////////////////////////////////////////////////////////////////////
18 
19 #include "art/Framework/Core/EDProducer.h"
20 #include "art/Framework/Core/ModuleMacros.h"
21 #include "art/Framework/Principal/DataViewImpl.h"
22 #include "art/Framework/Principal/Event.h"
23 #include "art/Framework/Principal/Handle.h"
24 #include "art/Framework/Principal/Run.h"
25 #include "art/Framework/Principal/SubRun.h"
26 #include "art_root_io/TFileService.h"
27 #include "canvas/Persistency/Common/FindManyP.h"
28 #include "canvas/Persistency/Common/Ptr.h"
29 #include "canvas/Persistency/Common/PtrVector.h"
30 #include "canvas/Utilities/InputTag.h"
31 #include "fhiclcpp/ParameterSet.h"
33 #include "messagefacility/MessageLogger/MessageLogger.h"
34 
47 
52 
53 // #include "sbncode/LArRecoProducer/LArReco/LGfitter.h"
54 
55 // Root Includes
56 #include "TCanvas.h"
57 #include "TF1.h"
58 #include "TGraph.h"
59 #include "TH1F.h"
60 #include "TMath.h"
61 #include "TTree.h"
62 
63 #include "TMVA/MethodCuts.h"
64 #include "TMVA/Reader.h"
65 #include "TMVA/Tools.h"
66 
67 #include <iostream>
68 #include <vector>
69 #include <numeric> // std::accumulate
70 
71 namespace sbn {
72 class Dazzle : public art::EDProducer {
73  public:
74  explicit Dazzle(fhicl::ParameterSet const& p);
75  // The compiler-generated destructor is fine for non-base
76  // classes without bare pointers or other resource use.
77 
78  // Plugins should not be copied or assigned.
79  Dazzle(Dazzle const&) = delete;
80  Dazzle(Dazzle&&) = delete;
81  Dazzle& operator=(Dazzle const&) = delete;
82  Dazzle& operator=(Dazzle&&) = delete;
83 
84  // Required functions.
85  void produce(art::Event& e) override;
86  void beginJob() override;
87 
88  private:
89  // Declare member data here.
90  art::ServiceHandle<art::TFileService> tfs;
91  art::ServiceHandle<cheat::ParticleInventoryService> particleInventory;
92 
94  const float fMinTrackLength;
95  const bool fMakeTree, fRunMVA;
96  const std::string fMethodName, fWeightFile;
97 
98  // FV defintion
99  const float fXMin, fXMax, fYMin, fYMax, fZMin, fZMax;
100 
101  // The metrics actually used in the MVA
102  float recoLen; // The length of the track [cm]
103  float chi2PIDMuon, chi2PIDProton; // Chi2 PID scores for different hyptheses
104  // The muon and pion scores are very correlated, instead take the relative difference
106  // The mean and max are very correlates, take the ration max/mean
107  float mcsScatterMean, mcsScatterMaxRatio; // Scattering angles used in MCS calculation [mrad]
108  float meanDCA; // Distance of closest approach to interpolated track [cm]
109  float stoppingChi2Ratio; // Ratio of exp/pol0 chi2 fits to end of track
110  // This variable takes too long to calculate reliably, so instead approximate using pol0 fit
111  // float lgcMPV; // Most Probable value of fitted Landau-Guassian [MeV/cm]
112  float chi2Pol0Fit; // Fitted pol0 to find the dE/dx of the track [MeV/cm]
113  float pDiff; // Relatve momentum agreement between range and MCS
114  //TODO: Root insists that we pass the reader floats, but these should really be ints
115  float numDaughters, maxDaughterHits; // Hierarchy of the track
116 
117  // MVA scores
119  int bestPDG;
120 
121  // Other metrics for filling in tree for analysis
122  TMVA::Reader* reader;
123  TTree* trackTree;
124 
126 
129  // float lgcAmp, lgcGaussWidth, lgcLandauWidth, lgcChi2;
134 
136 
137  void ClearTreeValues();
138  void FillPFPMetrics(const art::Ptr<recob::PFParticle>& pfp, const std::map<size_t, art::Ptr<recob::PFParticle>>& pfpMap,
139  const art::FindManyP<recob::Cluster>& fmCluster, const art::FindManyP<recob::Hit>& fmHit, const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta);
140  void FillTrueParticleMetrics(const detinfo::DetectorClocksData& clockData, const recob::Track& track, const std::vector<art::Ptr<recob::Hit>>& hits,
141  std::vector<art::Ptr<sim::SimChannel>>& simChannels);
142  void FillTrackMetrics(const recob::Track& track);
143  void FillMCSMetrics(const recob::MCSFitResult& mcs);
144  void FillChi2PIDMetrics(const anab::ParticleID& pid);
145  void FillRangePMetrics(const RangeP& range);
146  // void FillLGCMetrics(const LGCFit& lgc);
147  void FillClosestApproachMetrics(const ScatterClosestApproach& closestApproach);
148  void FillStoppingChi2Metrics(const StoppingChi2Fit& stoppingChi2);
149  MVAPID RunMVA();
150 
151  std::map<size_t, art::Ptr<recob::PFParticle>> GetPFPMap(std::vector<art::Ptr<recob::PFParticle>>& pfps) const;
152  unsigned int GetPFPHierarchyDepth(const art::Ptr<recob::PFParticle>& pfp, const std::map<size_t, art::Ptr<recob::PFParticle>>& pfpMap) const;
153  float GetPFPTrackScore(const art::Ptr<recob::PFParticle>& pfp, const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta) const;
154  bool InFV(const TVector3& pos) const;
155  std::string PdgString(const int pdg) const;
156 };
157 
158 Dazzle::Dazzle(fhicl::ParameterSet const& p)
159  : EDProducer { p }
160  , fSimChannelLabel(p.get<std::string>("SimChannelLabel"))
161  , fPFPLabel(p.get<std::string>("PFPLabel"))
162  , fTrackLabel(p.get<std::string>("TrackLabel"))
163  , fCaloLabel(p.get<std::string>("CaloLabel"))
164  , fMCSLabel(p.get<std::string>("MCSLabel"), std::string("muon"))
165  , fChi2Label(p.get<std::string>("Chi2Label"))
166  , fRangeLabel(p.get<std::string>("RangeLabel"), std::string("muon"))
167  // , fLGCLabel(p.get<std::string>("LGCLabel"))
168  , fClosestApproachLabel(p.get<std::string>("ClosestApproachLabel"))
169  , fStoppingChi2Label(p.get<std::string>("StoppingChi2Label"))
170  , fMinTrackLength(p.get<float>("MinTrackLength"))
171  , fMakeTree(p.get<bool>("MakeTree"))
172  , fRunMVA(p.get<bool>("RunMVA"))
173  , fMethodName(p.get<std::string>("MethodName", ""))
174  , fWeightFile(p.get<std::string>("WeightFile", ""))
175  , fXMin(p.get<float>("XMin"))
176  , fXMax(p.get<float>("XMax"))
177  , fYMin(p.get<float>("YMin"))
178  , fYMax(p.get<float>("YMax"))
179  , fZMin(p.get<float>("ZMin"))
180  , fZMax(p.get<float>("ZMax"))
181 // , lgFitter(p.get<float>("LGFitterNP", 100.f), p.get<float>("LGFitterSC", 8.f))
182 {
183  if (!fMakeTree && !fRunMVA)
184  throw cet::exception("Dazzle") << "Configured to do nothing";
185 
186  if (fRunMVA) {
187  if (fMethodName == "" || fWeightFile == "")
188  throw cet::exception("Dazzle") << "Trying to run MVA with inputs not set: MethodName: " << fMethodName << " and WeightFile: " << fWeightFile;
189 
190  cet::search_path searchPath("FW_SEARCH_PATH");
191  std::string fWeightFileFullPath;
192  if (!searchPath.find_file(fWeightFile, fWeightFileFullPath))
193  throw cet::exception("Dazzle") << "Unable to find weight file: " << fWeightFile << " in FW_SEARCH_PATH: " << searchPath.to_string();
194 
195  reader = new TMVA::Reader("V");
196 
197  reader->AddVariable("recoLen", &recoLen);
198 
199  reader->AddVariable("chi2PIDMuon", &chi2PIDMuon);
200  reader->AddVariable("chi2PIDProton", &chi2PIDProton);
201  reader->AddVariable("chi2PIDMuonPionDiff", &chi2PIDMuonPionDiff);
202 
203  reader->AddVariable("mcsScatterMean", &mcsScatterMean);
204  reader->AddVariable("mcsScatterMaxRatio", &mcsScatterMaxRatio);
205  reader->AddVariable("meanDCA", &meanDCA);
206 
207  reader->AddVariable("stoppingChi2Ratio", &stoppingChi2Ratio);
208  reader->AddVariable("chi2Pol0Fit", &chi2Pol0Fit);
209 
210  reader->AddVariable("pDiff", &pDiff);
211  reader->AddVariable("numDaughters", &numDaughters);
212  reader->AddVariable("maxDaughterHits", &maxDaughterHits);
213 
214  reader->BookMVA(fMethodName, fWeightFileFullPath);
215  }
216  // Call appropriate produces<>() functions here.
217  produces<std::vector<MVAPID>>();
218  produces<art::Assns<recob::Track, MVAPID>>();
219 }
220 
222 {
223  if (fMakeTree) {
224  trackTree = tfs->make<TTree>("trackTree", "Tree filled per Track with PID variables");
225 
226  // The metrics actually used in the MVA
227  trackTree->Branch("recoLen", &recoLen);
228  trackTree->Branch("chi2PIDMuon", &chi2PIDMuon);
229  trackTree->Branch("chi2PIDPion", &chi2PIDPion);
230  trackTree->Branch("chi2PIDProton", &chi2PIDProton);
231  trackTree->Branch("chi2PIDMuonPionDiff", &chi2PIDMuonPionDiff);
232  trackTree->Branch("mcsScatterMean", &mcsScatterMean);
233  trackTree->Branch("mcsScatterMaxRatio", &mcsScatterMaxRatio);
234  trackTree->Branch("meanDCA", &meanDCA);
235  trackTree->Branch("stoppingChi2Ratio", &stoppingChi2Ratio);
236  // trackTree->Branch("lgcMPV", &lgcMPV);
237  trackTree->Branch("pDiff", &pDiff);
238  trackTree->Branch("chi2Pol0Fit", &chi2Pol0Fit);
239  trackTree->Branch("numDaughters", &numDaughters);
240  trackTree->Branch("maxDaughterHits", &maxDaughterHits);
241 
242  if (fRunMVA) {
243  trackTree->Branch("muonScore", &muonScore);
244  trackTree->Branch("pionScore", &pionScore);
245  trackTree->Branch("protonScore", &protonScore);
246  trackTree->Branch("otherScore", &otherScore);
247  trackTree->Branch("bestScore", &bestScore);
248  trackTree->Branch("bestPDG", &bestPDG);
249  }
250 
251  trackTree->Branch("truePdg", &truePdg);
252  trackTree->Branch("trueP", &trueP);
253  trackTree->Branch("trueEndP", &trueEndP);
254  trackTree->Branch("trueThetaXZ", &trueThetaXZ);
255  trackTree->Branch("trueThetaYZ", &trueThetaYZ);
256  trackTree->Branch("trueType", &trueType);
257  trackTree->Branch("trueEndProcess", &trueEndProcess);
258  trackTree->Branch("energyComp", &energyComp);
259  trackTree->Branch("energyPurity", &energyPurity);
260 
261  trackTree->Branch("trueStopping", &trueStopping);
262 
263  trackTree->Branch("startX", &startX);
264  trackTree->Branch("startY", &startY);
265  trackTree->Branch("startZ", &startZ);
266 
267  trackTree->Branch("endX", &endX);
268  trackTree->Branch("endY", &endY);
269  trackTree->Branch("endZ", &endZ);
270 
271  trackTree->Branch("trueStartX", &trueStartX);
272  trackTree->Branch("trueStartY", &trueStartY);
273  trackTree->Branch("trueStartZ", &trueStartZ);
274 
275  trackTree->Branch("trueEndX", &trueEndX);
276  trackTree->Branch("trueEndY", &trueEndY);
277  trackTree->Branch("trueEndZ", &trueEndZ);
278 
279  trackTree->Branch("truePx", &truePx);
280  trackTree->Branch("truePy", &truePy);
281  trackTree->Branch("truePz", &truePz);
282 
283  trackTree->Branch("startDist", &startDist);
284  trackTree->Branch("endDist", &endDist);
285 
286  trackTree->Branch("numHits", &numHits);
287  trackTree->Branch("bestPlane", &bestPlane);
288  trackTree->Branch("bestPlaneHits", &bestPlaneHits);
289  trackTree->Branch("hierarchyDepth", &hierarchyDepth);
290  trackTree->Branch("trackScore", &trackScore);
291  trackTree->Branch("daughterTrackScore", &daughterTrackScore);
292 
293  trackTree->Branch("recoPrimary", &recoPrimary);
294  trackTree->Branch("recoContained", &recoContained);
295 
296  trackTree->Branch("chi2PIDKaon", &chi2PIDKaon);
297  trackTree->Branch("chi2PIDPDG", &chi2PIDPDG);
298  trackTree->Branch("chi2PIDPDGNoKaon", &chi2PIDPDGNoKaon);
299  trackTree->Branch("chi2PIDType", &chi2PIDType);
300  trackTree->Branch("chi2PIDTypeNoKaon", &chi2PIDTypeNoKaon);
301 
302  // trackTree->Branch("lgcAmp", &lgcAmp);
303  // trackTree->Branch("lgcGaussWidth", &lgcGaussWidth);
304  // trackTree->Branch("lgcLandauWidth", &lgcLandauWidth);
305  // trackTree->Branch("lgcChi2", &lgcChi2);
306 
307  trackTree->Branch("chi2ExpChi2", &chi2ExpChi2);
308 
309  trackTree->Branch("mcsMuonP", &mcsMuonP);
310  trackTree->Branch("mcsScatterMax", &mcsScatterMax);
311 
312  trackTree->Branch("rangeMuonP", &rangeMuonP);
313 
314  trackTree->Branch("stdDevDCA", &stdDevDCA);
315  trackTree->Branch("maxDCA", &maxDCA);
316  }
317 }
318 
319 void Dazzle::produce(art::Event& e)
320 {
321  auto const clockData(art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e));
322 
323  auto const pfpHandle(e.getValidHandle<std::vector<recob::PFParticle>>(fPFPLabel));
324  auto const clusterHandle(e.getValidHandle<std::vector<recob::Cluster>>(fPFPLabel));
325  auto const simChannelHandle(e.getValidHandle<std::vector<sim::SimChannel>>(fSimChannelLabel));
326  auto const trackHandle(e.getValidHandle<std::vector<recob::Track>>(fTrackLabel));
327 
328  std::vector<art::Ptr<recob::PFParticle>> pfps;
329  art::fill_ptr_vector(pfps, pfpHandle);
330 
331  std::vector<art::Ptr<sim::SimChannel>> simChannels;
332  art::fill_ptr_vector(simChannels, simChannelHandle);
333 
334  art::FindManyP<recob::Cluster> fmPFPCluster(pfpHandle, e, fPFPLabel);
335  art::FindManyP<larpandoraobj::PFParticleMetadata> fmPFPMeta(pfpHandle, e, fPFPLabel);
336  art::FindManyP<recob::Hit> fmClusterHit(clusterHandle, e, fPFPLabel);
337 
338  art::FindManyP<recob::Track> fmPFPTrack(pfpHandle, e, fTrackLabel);
339  art::FindManyP<recob::Hit> fmTrackHit(trackHandle, e, fTrackLabel);
340  art::FindManyP<anab::Calorimetry> fmTrackCalo(trackHandle, e, fCaloLabel);
341  art::FindManyP<recob::MCSFitResult> fmTrackMCS(trackHandle, e, fMCSLabel);
342  art::FindManyP<anab::ParticleID> fmTrackChi2(trackHandle, e, fChi2Label);
343 
344  // art::FindManyP<LGCFit> fmTrackLGC(trackHandle, e, fLGCLabel);
345  art::FindManyP<RangeP> fmTrackRange(trackHandle, e, fRangeLabel);
346  art::FindManyP<ScatterClosestApproach> fmTrackClosestApproach(trackHandle, e, fClosestApproachLabel);
347  art::FindManyP<StoppingChi2Fit> fmTrackStoppingChi2(trackHandle, e, fStoppingChi2Label);
348 
349  auto mvaPIDVec = std::make_unique<std::vector<MVAPID>>();
350  auto trackAssns = std::make_unique<art::Assns<recob::Track, MVAPID>>();
351 
352  const std::map<size_t, art::Ptr<recob::PFParticle>> pfpMap(this->GetPFPMap(pfps));
353 
354  for (auto const& pfp : pfps) {
355  this->ClearTreeValues();
356 
357  // Get the track for the PFP
358  std::vector<art::Ptr<recob::Track>> pfpTrackVec(fmPFPTrack.at(pfp.key()));
359 
360  // Skip showers and primaries
361  if (pfpTrackVec.empty())
362  continue;
363 
364  // There should be 1-1 PFP to tracks
365  if (pfpTrackVec.size() > 1)
366  throw cet::exception("Dazzle") << "Too many tracks: " << pfpTrackVec.size();
367 
368  art::Ptr<recob::Track>& pfpTrack(pfpTrackVec.front());
369 
370  if (pfpTrack->Length() < fMinTrackLength)
371  continue;
372 
373  this->FillTrackMetrics(*pfpTrack);
374 
375  // // TODO look at in terms of runtime
376  // if (!recoContained)
377  // continue;
378 
379  // We expect a calo for each plane
380  auto const caloVec(fmTrackCalo.at(pfpTrack.key()));
381  if (caloVec.size() != 3)
382  continue;
383 
384  // Fill only for the best plane, defined as the one with the most hits
385  // Prefer collection plane > 1st induction > 2nd induction
386  const unsigned int maxHits(std::max({ caloVec[0]->dEdx().size(), caloVec[1]->dEdx().size(), caloVec[2]->dEdx().size() }));
387  bestPlane = (caloVec[2]->dEdx().size() == maxHits) ? 2 : (caloVec[0]->dEdx().size() == maxHits) ? 0 : (caloVec[1]->dEdx().size() == maxHits) ? 1 : -1;
388  bestPlaneHits = maxHits;
389 
390  if (bestPlane < 0 || bestPlane > 3)
391  throw cet::exception("Dazzle") << "Best plane: " << bestPlane;
392 
393  this->FillPFPMetrics(pfp, pfpMap, fmPFPCluster, fmClusterHit, fmPFPMeta);
394 
395  // We should have a MCS fit result for muon, proton, pion and kaon hypotheses
396  // For now, just consider the muon
397  auto const mcsVec(fmTrackMCS.at(pfpTrack.key()));
398  if (mcsVec.size() == 1)
399  this->FillMCSMetrics(*mcsVec.front());
400 
401  // We should have a rangeP fit for muon and proton
402  // For now, just consider the muon
403  auto const rangeVec(fmTrackRange.at(pfpTrack.key()));
404  if (rangeVec.size() == 1)
405  this->FillRangePMetrics(*rangeVec.front());
406 
407  // We expect a chi2 for each plane
408  auto const chi2Vec(fmTrackChi2.at(pfpTrack.key()));
409  if (chi2Vec.size() == 3)
410  this->FillChi2PIDMetrics(*chi2Vec[bestPlane]);
411 
412  // auto const lgcVec(fmTrackLGC.at(pfpTrack.key()));
413  // if (lgcVec.size() == 1)
414  // this->FillLGCMetrics(*lgcVec.front());
415 
416  auto const closestApproachVec(fmTrackClosestApproach.at(pfpTrack.key()));
417  if (closestApproachVec.size() == 1)
418  this->FillClosestApproachMetrics(*closestApproachVec.front());
419 
420  auto const stoppingChi2Vec(fmTrackStoppingChi2.at(pfpTrack.key()));
421  if (stoppingChi2Vec.size() == 1)
422  this->FillStoppingChi2Metrics(*stoppingChi2Vec.front());
423 
424  if (fRunMVA) {
425  MVAPID mvaPID(this->RunMVA());
426  mvaPIDVec->push_back(mvaPID);
427  util::CreateAssn(*this, e, *mvaPIDVec, pfpTrack, *trackAssns);
428  }
429 
430  // Only fill the truth metrics if we are saving a TTree
431  if (fMakeTree) {
432  std::vector<art::Ptr<recob::Hit>> trackHitVec(fmTrackHit.at(pfpTrack.key()));
433  numHits = trackHitVec.size();
434  this->FillTrueParticleMetrics(clockData, *pfpTrack, trackHitVec, simChannels);
435  trackTree->Fill();
436  }
437  }
438  e.put(std::move(mvaPIDVec));
439  e.put(std::move(trackAssns));
440 }
441 
443 {
444  truePdg = -5;
445  chi2PIDPDG = -5;
446  chi2PIDPDGNoKaon = -5;
447  numHits = -5;
448  bestPlane = -5;
449  numDaughters = -5;
450  hierarchyDepth = -5;
451  trackScore = -5;
452  maxDaughterHits = -5;
453  daughterTrackScore = -5;
454 
455  trueStopping = -5;
456  recoContained = -5;
457  recoPrimary = -5;
458 
459  muonScore = -5.f;
460  pionScore = -5.f;
461  protonScore = -5.f;
462  otherScore = -5.f;
463  bestScore = -5.f;
464  bestPDG = -5;
465 
466  startX = -999.f;
467  startY = -999.f;
468  startZ = -999.f;
469  endX = -999.f;
470  endY = -999.f;
471  endZ = -999.f;
472  trueStartX = -999.f;
473  trueStartY = -999.f;
474  trueStartZ = -999.f;
475  trueEndX = -999.f;
476  trueEndY = -999.f;
477  trueEndZ = -999.f;
478  truePx = -999.f;
479  truePy = -999.f;
480  truePz = -999.f;
481  startDist = -999.f;
482  endDist = -999.f;
483 
484  trueP = -5.f;
485  trueEndP = -5.f;
486  trueThetaXZ = -5.f;
487  trueThetaYZ = -5.f;
488  energyPurity = -5.f;
489  energyComp = -5.f;
490  recoLen = -5.f;
491  mcsMuonP = -5.f;
492  rangeMuonP = -5.f;
493  pDiff = -5.f;
494  chi2PIDMuon = -5.f;
495  chi2PIDPion = -5.f;
496  chi2PIDKaon = -5.f;
497  chi2PIDProton = -5.f;
498  chi2PIDMuonPionDiff = -5.f;
499  // lgcMPV = -5.f;
500  // lgcAmp = -5.f;
501  // lgcGaussWidth = -5.f;
502  // lgcLandauWidth = -5.f;
503  // lgcChi2 = -5.f;
504  chi2Pol0Fit = -5.f;
505  chi2Pol0Chi2 = -5.f;
506  chi2ExpChi2 = -5.f;
507  stoppingChi2Ratio = -5.f;
508  mcsScatterMean = -5.f;
509  mcsScatterMax = -5.f;
510  mcsScatterMaxRatio = -5.f;
511  meanDCA = -5.f;
512  stdDevDCA = -5.f;
513  maxDCA = -5.f;
514 
515  trueType = "";
516  trueEndProcess = "";
517  chi2PIDType = "";
518  chi2PIDTypeNoKaon = "";
519 }
520 
521 void Dazzle::FillPFPMetrics(const art::Ptr<recob::PFParticle>& pfp, const std::map<size_t, art::Ptr<recob::PFParticle>>& pfpMap,
522  const art::FindManyP<recob::Cluster>& fmCluster, const art::FindManyP<recob::Hit>& fmHit, const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta)
523 {
524  auto const parentId(pfp->Parent());
525  auto const& parentIter(pfpMap.find(parentId));
526  if (parentIter != pfpMap.end())
527  recoPrimary = parentIter->second->IsPrimary();
528 
529  numDaughters = pfp->Daughters().size();
530  trackScore = this->GetPFPTrackScore(pfp, fmMeta);
531 
532  if (!numDaughters)
533  return;
534 
535  for (auto const daughterId : pfp->Daughters()) {
536  auto const& daughterIter(pfpMap.find(daughterId));
537  if (daughterIter == pfpMap.end())
538  continue;
539 
540  auto const& clusters(fmCluster.at(daughterIter->second.key()));
541  int daughterHits(0);
542  for (auto const& cluster : clusters) {
543  daughterHits += fmHit.at(cluster.key()).size();
544  }
545 
546  if (daughterHits > maxDaughterHits) {
547  maxDaughterHits = daughterHits;
548  daughterTrackScore = this->GetPFPTrackScore(daughterIter->second, fmMeta);
549  }
550  }
551 
552  if (!fMakeTree)
553  return;
554 
555  hierarchyDepth = this->GetPFPHierarchyDepth(pfp, pfpMap);
556 }
557 
558 void Dazzle::FillTrueParticleMetrics(const detinfo::DetectorClocksData& clockData, const recob::Track& track, const std::vector<art::Ptr<recob::Hit>>& hits, std::vector<art::Ptr<sim::SimChannel>>& simChannels)
559 {
560  art::ServiceHandle<cheat::BackTrackerService> bt_serv;
561  const int bestMatch(TruthMatchUtils::TrueParticleIDFromTotalTrueEnergy(clockData, hits, true));
562 
563  if (!TruthMatchUtils::Valid(bestMatch))
564  return;
565 
566  float totalHitEnergy(0.f), totalTrueHitEnergy(0.f);
567  for (auto const& hit : hits) {
568  const std::vector<sim::TrackIDE> trackIDEs(bt_serv->HitToTrackIDEs(clockData, hit));
569  totalHitEnergy = std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), totalHitEnergy,
570  [](float sum, auto const& ide) { return sum + ide.energy; });
571  totalTrueHitEnergy = std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), totalTrueHitEnergy,
572  [bestMatch](float sum, auto const& ide) { return (std::abs(ide.trackID) == bestMatch) ? sum + ide.energy : sum; });
573  }
574 
575  const std::vector<const sim::IDE*> trackIDEs(bt_serv->TrackIdToSimIDEs_Ps(bestMatch));
576  float totalTrueEnergy(std::accumulate(trackIDEs.cbegin(), trackIDEs.cend(), 0.f,
577  [](float sum, auto const& ide) { return sum + ide->energy; }));
578 
579  energyComp = totalTrueHitEnergy / totalTrueEnergy;
580  energyPurity = totalTrueHitEnergy / totalHitEnergy;
581 
582  const simb::MCParticle* const trueParticle(particleInventory->TrackIdToParticle_P(bestMatch));
583 
584  if (!trueParticle)
585  return;
586 
587  truePdg = trueParticle->PdgCode();
588  trueType = this->PdgString(truePdg);
589  trueEndProcess = trueParticle->EndProcess();
590 
591  trueStopping = (int)(trueEndProcess == "CoupledTransportation" || trueEndProcess == "FastScintillation" || trueEndProcess == "Decay" || trueEndProcess == "muMinusCaptureAtRest");
592 
593  trueP = trueParticle->P();
594  trueEndP = trueParticle->P(trueParticle->NumberTrajectoryPoints() - 2);
595 
596  const TVector3 trackStart(track.Start<TVector3>());
597  const TVector3 trackEnd(track.End<TVector3>());
598 
599  const TVector3 trueStart(trueParticle->Position().Vect());
600  const TVector3 trueEnd(trueParticle->EndPosition().Vect());
601 
602  trueStartX = trueStart.X();
603  trueStartY = trueStart.Y();
604  trueStartZ = trueStart.Z();
605 
606  trueEndX = trueEnd.X();
607  trueEndY = trueEnd.Y();
608  trueEndZ = trueEnd.Z();
609 
610  truePx = trueParticle->Px() / trueP;
611  truePy = trueParticle->Py() / trueP;
612  truePz = trueParticle->Pz() / trueP;
613 
614  trueThetaXZ = std::atan2(truePx, truePz);
615  trueThetaYZ = std::atan2(truePy, truePz);
616 
617  startDist = (trueStart - trackStart).Mag();
618  endDist = (trueEnd - trackEnd).Mag();
619 }
620 
622 {
623  recoLen = track.Length();
624 
625  const TVector3 start(track.Start<TVector3>());
626  const TVector3 end(track.End<TVector3>());
627  recoContained = this->InFV(start) && this->InFV(end);
628 
629  if (!fMakeTree)
630  return;
631 
632  startX = start.X();
633  startY = start.Y();
634  startZ = start.Z();
635 
636  endX = end.X();
637  endY = end.Y();
638  endZ = end.Z();
639 }
640 
641 bool Dazzle::InFV(const TVector3& pos) const
642 {
643  return (pos.X() > fXMin && pos.X() < fXMax && pos.Y() > fYMin && pos.Y() < fYMax && pos.Z() > fZMin && pos.Z() < fZMax);
644 }
645 
647 {
648  mcsMuonP = mcs.fwdMomentum();
649 
650  if (mcs.scatterAngles().empty())
651  return;
652 
653  unsigned int counter(0);
654  float maxScatter(0), meanScatter(0);
655  for (auto const& angle : mcs.scatterAngles()) {
656  if (angle < 0)
657  continue;
658  maxScatter = std::max(maxScatter, angle);
659  meanScatter += angle;
660  counter++;
661  }
662 
663  if (!counter)
664  return;
665 
666  mcsScatterMax = maxScatter;
667  mcsScatterMean = meanScatter / counter;
668  mcsScatterMaxRatio = maxScatter / meanScatter;
669 }
670 
672 {
673  rangeMuonP = range.range_p;
674 
675  pDiff = (rangeMuonP > 0 && mcsMuonP > 0) ? (mcsMuonP - rangeMuonP) / rangeMuonP : -5.f;
676 }
677 
678 // void Dazzle::FillLGCMetrics(const LGCFit& lgc)
679 // {
680 // lgcMPV = lgc.mMPV;
681 
682 // if (!fMakeTree)
683 // return;
684 
685 // lgcAmp = lgc.mAmplitude;
686 // lgcGaussWidth = lgc.mGaussWidth;
687 // lgcLandauWidth = lgc.mLandauWidth;
688 // lgcChi2 = lgc.mChi2 / lgc.mNDF;
689 // }
690 
692 {
693  meanDCA = closestApproach.mean;
694 
695  if (!fMakeTree)
696  return;
697 
698  stdDevDCA = closestApproach.stdDev;
699  maxDCA = closestApproach.max;
700 }
701 
703 {
704  chi2Pol0Chi2 = stoppingChi2.pol0Chi2;
705  chi2ExpChi2 = stoppingChi2.expChi2;
706 
707  stoppingChi2Ratio = (chi2Pol0Chi2 > 0.f && chi2ExpChi2 > 0.f) ? chi2Pol0Chi2 / chi2ExpChi2 : -5.f;
708 
709  if (!fMakeTree)
710  return;
711 
712  chi2Pol0Fit = stoppingChi2.pol0Fit;
713 }
714 
716 {
717  const std::vector<float> mvaScores(reader->EvaluateMulticlass(fMethodName));
718 
719  MVAPID pidResults;
720 
721  pidResults.AddScore(13, mvaScores.at(0));
722  pidResults.AddScore(211, mvaScores.at(1));
723  pidResults.AddScore(2212, mvaScores.at(2));
724  pidResults.AddScore(0, mvaScores.at(3));
725 
726  if (!fMakeTree)
727  return pidResults;
728 
729  muonScore = mvaScores.at(0);
730  pionScore = mvaScores.at(1);
731  protonScore = mvaScores.at(2);
732  otherScore = mvaScores.at(3);
733 
734  bestScore = pidResults.BestScore();
735  bestPDG = pidResults.BestPDG();
736 
737  return pidResults;
738 }
739 
741 {
742  // Assign dummy values.
743 
744  chi2PIDMuon = 0.;
745  chi2PIDPion = 0.;
746  chi2PIDKaon = 0.;
747  chi2PIDProton = 0.;
748  double chi2PIDBest = 0.;
749  chi2PIDPDG = 0;
750 
751  // Loop over algorithm scores and extract the ones we want.
752  // Also extract the preferred pdg.
753 
754  std::vector<anab::sParticleIDAlgScores> AlgScoresVec = pid.ParticleIDAlgScores();
755  for (size_t i_algscore=0; i_algscore<AlgScoresVec.size(); i_algscore++){
756  anab::sParticleIDAlgScores AlgScore = AlgScoresVec.at(i_algscore);
757  if (AlgScore.fAlgName == "Chi2"){
758  if (TMath::Abs(AlgScore.fAssumedPdg) == 13) { // chi2mu
759  chi2PIDMuon = AlgScore.fValue;
760  if(AlgScore.fValue < chi2PIDBest || chi2PIDBest == 0.) {
761  chi2PIDBest = AlgScore.fValue;
762  chi2PIDPDG = 13;
763  }
764  }
765  else if (TMath::Abs(AlgScore.fAssumedPdg) == 211) { // chi2pi
766  chi2PIDPion = AlgScore.fValue;
767  if(AlgScore.fValue < chi2PIDBest || chi2PIDBest == 0.) {
768  chi2PIDBest = AlgScore.fValue;
769  chi2PIDPDG = 211;
770  }
771  }
772  else if (TMath::Abs(AlgScore.fAssumedPdg) == 321) { // chi2ka
773  chi2PIDKaon = AlgScore.fValue;
774  if(AlgScore.fValue < chi2PIDBest || chi2PIDBest == 0.) {
775  chi2PIDBest = AlgScore.fValue;
776  chi2PIDPDG = 321;
777  }
778  }
779  else if (TMath::Abs(AlgScore.fAssumedPdg) == 2212) { // chi2pr
780  chi2PIDProton = AlgScore.fValue;
781  if(AlgScore.fValue < chi2PIDBest || chi2PIDBest == 0.) {
782  chi2PIDBest = AlgScore.fValue;
783  chi2PIDPDG = 2212;
784  }
785  }
786  }
787  }
789 
790  if (!fMakeTree)
791  return;
792 
794 
795  if (chi2PIDPDG != 321) {
798  } else {
799  if (chi2PIDMuon < chi2PIDProton && chi2PIDMuon < chi2PIDPion) {
800  chi2PIDPDGNoKaon = 13;
801  } else if (chi2PIDPion < chi2PIDProton) {
802  chi2PIDPDGNoKaon = 211;
803  } else {
804  chi2PIDPDGNoKaon = 2212;
805  }
807  }
808 }
809 
810 std::map<size_t, art::Ptr<recob::PFParticle>> Dazzle::GetPFPMap(std::vector<art::Ptr<recob::PFParticle>>& pfps) const
811 {
812  std::map<size_t, art::Ptr<recob::PFParticle>> pfpMap;
813  for (auto const& pfp : pfps) {
814  pfpMap[pfp->Self()] = pfp;
815  }
816  return pfpMap;
817 }
818 
819 unsigned int Dazzle::GetPFPHierarchyDepth(const art::Ptr<recob::PFParticle>& pfp, const std::map<size_t, art::Ptr<recob::PFParticle>>& pfpMap) const
820 {
821  if (pfp->Daughters().empty()) {
822  return 1;
823  }
824  unsigned int maxDepth(0);
825  for (auto const daughter : pfp->Daughters()) {
826  maxDepth = std::max(maxDepth, this->GetPFPHierarchyDepth(pfpMap.at(daughter), pfpMap));
827  }
828  return maxDepth + 1;
829 }
830 
831 float Dazzle::GetPFPTrackScore(const art::Ptr<recob::PFParticle>& pfp, const art::FindManyP<larpandoraobj::PFParticleMetadata>& fmMeta) const
832 {
833  auto const pfpMetaVec(fmMeta.at(pfp.key()));
834  if (pfpMetaVec.size() != 1)
835  return -5.f;
836  const larpandoraobj::PFParticleMetadata::PropertiesMap propertiesMap(pfpMetaVec.front()->GetPropertiesMap());
837  auto const& pfpTrackScoreIter = propertiesMap.find("TrackScore");
838  return pfpTrackScoreIter == propertiesMap.end() ? -5.f : pfpTrackScoreIter->second;
839 }
840 
841 std::string Dazzle::PdgString(const int pdg) const
842 {
843  switch (std::abs(pdg)) {
844  case 13:
845  return "Mu";
846  case 211:
847  return "Pion";
848  case 321:
849  return "Kaon";
850  case 2212:
851  return "Proton";
852  default:
853  return "Other";
854  }
855 }
856 }
857 
858 DEFINE_ART_MODULE(sbn::Dazzle)
const float fYMin
float daughterTrackScore
std::string chi2PIDType
float stoppingChi2Ratio
var pdg
Definition: selectors.fcl:14
const std::string fWeightFile
TTree * trackTree
process_name cluster
Definition: cheaterreco.fcl:51
std::string trueType
art::InputTag fMCSLabel
art::InputTag fCaloLabel
Declaration of signal hit object.
pdgs p
Definition: selectors.fcl:22
void FillPFPMetrics(const art::Ptr< recob::PFParticle > &pfp, const std::map< size_t, art::Ptr< recob::PFParticle >> &pfpMap, const art::FindManyP< recob::Cluster > &fmCluster, const art::FindManyP< recob::Hit > &fmHit, const art::FindManyP< larpandoraobj::PFParticleMetadata > &fmMeta)
TMVA::Reader * reader
void FillStoppingChi2Metrics(const StoppingChi2Fit &stoppingChi2)
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
const std::string fMethodName
const std::vector< float > & scatterAngles() const
vector of angles between the segments used in the fit
Definition: MCSFitResult.h:50
std::map< std::string, float > PropertiesMap
float maxDaughterHits
process_name use argoneut_mc_hitfinder track
Dazzle & operator=(Dazzle const &)=delete
float energyPurity
art::InputTag fRangeLabel
process_name hit
Definition: cheaterreco.fcl:51
float fValue
Result of Particle ID algorithm/test.
Definition: ParticleID.h:28
const bool fRunMVA
void FillTrueParticleMetrics(const detinfo::DetectorClocksData &clockData, const recob::Track &track, const std::vector< art::Ptr< recob::Hit >> &hits, std::vector< art::Ptr< sim::SimChannel >> &simChannels)
std::string fAlgName
&lt; determined particle ID
Definition: ParticleID.h:23
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
T abs(T value)
void FillChi2PIDMetrics(const anab::ParticleID &pid)
auto counter(T begin, T end)
Returns an object to iterate values from begin to end in a range-for loop.
Definition: counter.h:285
const std::vector< anab::sParticleIDAlgScores > & ParticleIDAlgScores() const
Definition: ParticleID.h:65
double Length(size_t p=0) const
Access to various track properties.
art::InputTag fPFPLabel
const bool fMakeTree
Utilities for matching a recob::Hit or vector of recob::Hit to the ID of the most significantly contr...
Point_t const & Start() const
Access to track position at different points.
unsigned int GetPFPHierarchyDepth(const art::Ptr< recob::PFParticle > &pfp, const std::map< size_t, art::Ptr< recob::PFParticle >> &pfpMap) const
float chi2PIDMuonPionDiff
void ClearTreeValues()
float mcsScatterMaxRatio
void FillTrackMetrics(const recob::Track &track)
const float fZMin
std::string chi2PIDTypeNoKaon
void FillMCSMetrics(const recob::MCSFitResult &mcs)
Dazzle(fhicl::ParameterSet const &p)
std::string trueEndProcess
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
std::string PdgString(const int pdg) const
const float fYMax
float chi2PIDProton
MVAPID RunMVA()
art::InputTag fClosestApproachLabel
float GetPFPTrackScore(const art::Ptr< recob::PFParticle > &pfp, const art::FindManyP< larpandoraobj::PFParticleMetadata > &fmMeta) const
Declaration of cluster object.
const float fZMax
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
Provides recob::Track data product.
void FillRangePMetrics(const RangeP &range)
bool Valid(const G4ID g4ID) noexcept
Test whether a G4ID returned by the TruthMatchUtils functions is valid.
const float fXMax
Class storing the result of the Maximum Likelihood fit of Multiple Coulomb Scattering angles between ...
Definition: MCSFitResult.h:19
float range_p
Definition: RangeP.h:7
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.
float chi2Pol0Chi2
Contains all timing reference information for the detector.
G4ID TrueParticleIDFromTotalTrueEnergy(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit >> &pHits, const bool rollupUnsavedIDs)
The G4 ID of the true particle which deposits the most energy in a vector of recob::Hit.
do i e
Point_t const & End() const
bool InFV(const TVector3 &pos) const
finds tracks best matching by angle
art::InputTag fChi2Label
void produce(art::Event &e) override
float fwdMomentum() const
momentum value from fit assuming a forward track direction
Definition: MCSFitResult.h:29
float numDaughters
void beginJob() override
art::ServiceHandle< art::TFileService > tfs
float mcsScatterMax
std::map< size_t, art::Ptr< recob::PFParticle > > GetPFPMap(std::vector< art::Ptr< recob::PFParticle >> &pfps) const
art::InputTag fSimChannelLabel
const float fXMin
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
art::ServiceHandle< cheat::ParticleInventoryService > particleInventory
int fAssumedPdg
PDG of particle hypothesis assumed by algorithm, if applicable. Set to 0 by default.
Definition: ParticleID.h:27
const float fMinTrackLength
art::InputTag fStoppingChi2Label
art::InputTag fTrackLabel
float mcsScatterMean
void FillClosestApproachMetrics(const ScatterClosestApproach &closestApproach)