All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
StoppingCosmicIdAna_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: StoppingCosmicIdAna
3 // Module Type: analyzer
4 // File: StoppingCosmicIdAnaAna_module.cc
5 //
6 // Tom Brooks (tbrooks@fnal.gov)
7 ////////////////////////////////////////////////////////////////////////
8 
9 // sbndcode includes
13 
14 // LArSoft includes
21 #include "nusimdata/SimulationBase/MCParticle.h"
22 #include "nusimdata/SimulationBase/MCTruth.h"
25 
26 // Framework includes
27 #include "art/Framework/Core/EDAnalyzer.h"
28 #include "art/Framework/Principal/Event.h"
29 #include "art/Framework/Principal/Handle.h"
30 #include "art_root_io/TFileService.h"
31 #include "canvas/Persistency/Common/FindManyP.h"
32 #include "fhiclcpp/ParameterSet.h"
33 #include "fhiclcpp/types/Table.h"
34 #include "fhiclcpp/types/Atom.h"
35 
36 #include "Pandora/PdgTable.h"
37 
38 // ROOT includes. Note: To look up the properties of the ROOT classes,
39 // use the ROOT web site; e.g.,
40 // <https://root.cern.ch/doc/master/annotated.html>
41 #include "TVector3.h"
42 #include "TH1.h"
43 
44 // C++ includes
45 #include <map>
46 #include <vector>
47 #include <string>
48 #include <algorithm>
49 
50 namespace sbnd {
51 
52  class StoppingCosmicIdAna : public art::EDAnalyzer {
53  public:
54 
55  // Describes configuration parameters of the module
56  struct Config {
57  using Name = fhicl::Name;
58  using Comment = fhicl::Comment;
59 
60  // One Atom for each parameter
61  fhicl::Atom<art::InputTag> SimModuleLabel {
62  Name("SimModuleLabel"),
63  Comment("tag of detector simulation data product")
64  };
65 
66  fhicl::Atom<art::InputTag> TpcTrackModuleLabel {
67  Name("TpcTrackModuleLabel"),
68  Comment("tag of TPC track producer data product")
69  };
70 
71  fhicl::Atom<art::InputTag> CaloModuleLabel {
72  Name("CaloModuleLabel"),
73  Comment("tag of calorimetry producer data product")
74  };
75 
76  fhicl::Atom<art::InputTag> PandoraLabel {
77  Name("PandoraLabel"),
78  Comment("tag of pandora data product")
79  };
80 
81  fhicl::Atom<bool> Verbose {
82  Name("Verbose"),
83  Comment("Print information about what's going on")
84  };
85 
86  fhicl::Table<StoppingParticleCosmicIdAlg::Config> SPTagAlg {
87  Name("SPTagAlg"),
88  };
89 
90  }; // Config
91 
92  using Parameters = art::EDAnalyzer::Table<Config>;
93 
94  // Constructor: configures module
95  explicit StoppingCosmicIdAna(Parameters const& config);
96 
97  // Called once, at start of the job
98  virtual void beginJob() override;
99 
100  // Called once per event
101  virtual void analyze(const art::Event& event) override;
102 
103  // Called once, at end of the job
104  virtual void endJob() override;
105 
106  typedef art::Handle< std::vector<recob::PFParticle> > PFParticleHandle;
107  typedef std::map< size_t, art::Ptr<recob::PFParticle> > PFParticleIdMap;
108 
109  private:
110 
111  void GetPFParticleIdMap(const PFParticleHandle &pfParticleHandle, PFParticleIdMap &pfParticleMap);
112 
113  // fcl file parameters
114  art::InputTag fSimModuleLabel; ///< name of detsim producer
115  art::InputTag fTpcTrackModuleLabel; ///< name of TPC track producer
116  art::InputTag fCaloModuleLabel; ///< name of calorimetry producer
117  art::InputTag fPandoraLabel;
118  bool fVerbose; ///< print information about what's going on
119 
122 
123  // histograms
124  // True time of neutrino particles to get beam window
125  std::vector<std::string> types {"NuMuTrack", "CrTrack", "DirtTrack", "NuTrack", "NuMuPfp", "CrPfp", "DirtPfp", "NuPfp"};
126  std::map<std::string, TH1D*> hRatioTotal;
127  std::map<std::string, TH1D*> hRatioTag;
128  std::map<std::string, TH1D*> hStopLength;
129  std::map<std::string, TH1D*> hNoStopLength;
130  std::map<std::string, TH1D*> hStopChiSq;
131  std::map<std::string, TH1D*> hNoStopChiSq;
132 
133  }; // class StoppingCosmicIdAna
134 
135 
136  // Constructor
138  : EDAnalyzer(config)
139  , fSimModuleLabel (config().SimModuleLabel())
140  , fTpcTrackModuleLabel (config().TpcTrackModuleLabel())
141  , fCaloModuleLabel (config().CaloModuleLabel())
142  , fPandoraLabel (config().PandoraLabel())
143  , fVerbose (config().Verbose())
144  , spTag (config().SPTagAlg())
145  {
146 
147 
148  } // StoppingCosmicIdAna()
149 
150 
152  {
153  // Access tfileservice to handle creating and writing histograms
154  art::ServiceHandle<art::TFileService> tfs;
155  for(auto type : types){
156  hRatioTotal[type] = tfs->make<TH1D>(Form("%sRatioTotal", type.c_str()), "", 20, 1, 3);
157  hRatioTag[type] = tfs->make<TH1D>(Form("%sRatioTag", type.c_str()), "", 20, 1, 3);
158  hStopLength[type] = tfs->make<TH1D>(Form("%sStopLength", type.c_str()), "", 50, 0, 500);
159  hNoStopLength[type] = tfs->make<TH1D>(Form("%sNoStopLength", type.c_str()), "", 50, 0, 500);
160  hStopChiSq[type] = tfs->make<TH1D>(Form("%sStopChiSq", type.c_str()), "", 50, 0, 5);
161  hNoStopChiSq[type] = tfs->make<TH1D>(Form("%sNoStopChiSq", type.c_str()), "", 50, 0, 5);
162  }
163 
164  // Initial output
165  if(fVerbose) std::cout<<"----------------- Stopping Particle Cosmic ID Ana Module -------------------"<<std::endl;
166 
167  }// StoppingCosmicIdAna::beginJob()
168 
169 
170  void StoppingCosmicIdAna::analyze(const art::Event& event)
171  {
172  art::ServiceHandle<cheat::ParticleInventoryService> pi_serv;
173 
174  // Fetch basic event info
175  if(fVerbose){
176  std::cout<<"============================================"<<std::endl
177  <<"Run = "<<event.run()<<", SubRun = "<<event.subRun()<<", Event = "<<event.id().event()<<std::endl
178  <<"============================================"<<std::endl;
179  }
180 
181  //----------------------------------------------------------------------------------------------------------
182  // GETTING PRODUCTS
183  //----------------------------------------------------------------------------------------------------------
184 
185  // Retrieve all the truth info in the events
186  auto particleHandle = event.getValidHandle<std::vector<simb::MCParticle>>(fSimModuleLabel);
187 
188  // Retrieve the TPC tracks
189  auto tpcTrackHandle = event.getValidHandle<std::vector<recob::Track>>(fTpcTrackModuleLabel);
190 
191  // Get track to hit associations
192  art::FindManyP<recob::Hit> findManyHits(tpcTrackHandle, event, fTpcTrackModuleLabel);
193  art::FindManyP<anab::Calorimetry> findManyCalo(tpcTrackHandle, event, fCaloModuleLabel);
194 
195  // Get PFParticles from pandora
196  PFParticleHandle pfParticleHandle;
197  event.getByLabel(fPandoraLabel, pfParticleHandle);
198  if( !pfParticleHandle.isValid() ){
199  if(fVerbose) std::cout<<"Failed to find the PFParticles."<<std::endl;
200  return;
201  }
202  PFParticleIdMap pfParticleMap;
203  this->GetPFParticleIdMap(pfParticleHandle, pfParticleMap);
204  // Get PFParticle to track associations
205  art::FindManyP< recob::Track > pfPartToTrackAssoc(pfParticleHandle, event, fTpcTrackModuleLabel);
206 
207  //----------------------------------------------------------------------------------------------------------
208  // TRUTH MATCHING
209  //----------------------------------------------------------------------------------------------------------
210 
211  std::map<int, simb::MCParticle> particles;
212  std::vector<int> nuParticleIds;
213  std::vector<int> lepParticleIds;
214  std::vector<int> dirtParticleIds;
215  std::vector<int> crParticleIds;
216  // Loop over the true particles
217  for (auto const& particle: (*particleHandle)){
218 
219  // Make map with ID
220  int partID = particle.TrackId();
221  particles[partID] = particle;
222 
223  // Get MCTruth
224  art::Ptr<simb::MCTruth> truth = pi_serv->TrackIdToMCTruth_P(partID);
225  int pdg = std::abs(particle.PdgCode());
226 
227  // If origin is a neutrino
228  if(truth->Origin() == simb::kBeamNeutrino){
229  geo::Point_t vtx;
230  vtx.SetX(truth->GetNeutrino().Nu().Vx()); vtx.SetY(truth->GetNeutrino().Nu().Vy()); vtx.SetZ(truth->GetNeutrino().Nu().Vz());
231  // If neutrino vertex is not inside the TPC then call it a dirt particle
232  if(!fTPCGeo.InFiducial(vtx, 0, 0)){
233  dirtParticleIds.push_back(partID);
234  }
235  // If it's a primary muon
236  else if(pdg==13 && particle.Mother()==0){
237  lepParticleIds.push_back(partID);
238  }
239  // Other nu particles
240  else{
241  nuParticleIds.push_back(partID);
242  }
243  }
244 
245  // If origin is a cosmic ray
246  else if(truth->Origin() == simb::kCosmicRay){
247  crParticleIds.push_back(partID);
248  }
249 
250  }
251 
252  //----------------------------------------------------------------------------------------------------------
253  // STOPPING CHI2 ANALYSIS
254  //----------------------------------------------------------------------------------------------------------
255 
256  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(event);
257 
258  for(auto const& tpcTrack : (*tpcTrackHandle)){
259 
260  // Match to the true particle
261  std::vector<art::Ptr<recob::Hit>> hits = findManyHits.at(tpcTrack.ID());
262  int trueId = RecoUtils::TrueParticleIDFromTotalRecoHits(clockData, hits, false);
263  std::string type = "none";
264  if(std::find(lepParticleIds.begin(), lepParticleIds.end(), trueId) != lepParticleIds.end()) type = "NuMuTrack";
265  if(std::find(nuParticleIds.begin(), nuParticleIds.end(), trueId) != nuParticleIds.end()) type = "NuTrack";
266  if(std::find(crParticleIds.begin(), crParticleIds.end(), trueId) != crParticleIds.end()) type = "CrTrack";
267  if(std::find(dirtParticleIds.begin(), dirtParticleIds.end(), trueId) != dirtParticleIds.end()) type = "DirtTrack";
268  if(type == "none") continue;
269 
270  std::vector<art::Ptr<anab::Calorimetry>> calos = findManyCalo.at(tpcTrack.ID());
271  if(calos.size()==0) continue;
272 
273  // Only focus on muon tracks or it'll be too hard
274  if(std::abs(particles[trueId].PdgCode()) != 13) continue;
275 
276  geo::Point_t trueEnd {particles[trueId].EndX(), particles[trueId].EndY(), particles[trueId].EndZ()};
277  bool stops = false;
278 
279  if(fTPCGeo.InFiducial(trueEnd, 0.)) stops = true;
280 
281  if(stops) hStopLength[type]->Fill(tpcTrack.Length());
282  else hNoStopLength[type]->Fill(tpcTrack.Length());
283 
284  TVector3 trueEndVec (particles[trueId].EndX(), particles[trueId].EndY(), particles[trueId].EndZ());
285  TVector3 start = tpcTrack.Vertex<TVector3>();
286  TVector3 end = tpcTrack.End<TVector3>();
287  geo::Point_t recoEnd = tpcTrack.End();
288  if((start-trueEndVec).Mag() < (end-trueEndVec).Mag()) recoEnd = tpcTrack.Vertex();
289 
290  double chi2 = spTag.StoppingChiSq(recoEnd, calos);
291  if(stops) hStopChiSq[type]->Fill(chi2);
292  else hNoStopChiSq[type]->Fill(chi2);
293 
294  double startChi2 = spTag.StoppingChiSq(tpcTrack.Vertex(), calos);
295  double endChi2 = spTag.StoppingChiSq(tpcTrack.End(), calos);
296 
297  int nbins = hRatioTotal.begin()->second->GetNbinsX();
298  for(int i = 0; i < nbins; i++){
299  double ratioCut = hRatioTotal.begin()->second->GetBinCenter(i);
300 
301  hRatioTotal[type]->Fill(ratioCut);
302 
303  // If closest hit is below limit and track matches any hits then fill efficiency
304  if((startChi2 > ratioCut && !fTPCGeo.InFiducial(tpcTrack.End(), 5.) && tpcTrack.End().Y() > 0)
305  || (endChi2 > ratioCut && !fTPCGeo.InFiducial(tpcTrack.Vertex(), 5.) && tpcTrack.Vertex().Y() > 0)){
306  hRatioTag[type]->Fill(ratioCut);
307  }
308 
309  }
310 
311  }
312 
313  //Loop over the pfparticle map
314  for (PFParticleIdMap::const_iterator it = pfParticleMap.begin(); it != pfParticleMap.end(); ++it){
315 
316  const art::Ptr<recob::PFParticle> pParticle(it->second);
317  // Only look for primary particles
318  if (!pParticle->IsPrimary()) continue;
319  // Check if this particle is identified as the neutrino
320  const int pdg(pParticle->PdgCode());
321  const bool isNeutrino(std::abs(pdg) == pandora::NU_E || std::abs(pdg) == pandora::NU_MU || std::abs(pdg) == pandora::NU_TAU);
322  //Find neutrino pfparticle
323  if(!isNeutrino) continue;
324 
325  std::string type = "none";
326  std::vector<recob::Track> nuTracks;
327 
328  // Loop over daughters of pfparticle
329  for (const size_t daughterId : pParticle->Daughters()){
330 
331  // Get tracks associated with daughter
332  art::Ptr<recob::PFParticle> pDaughter = pfParticleMap.at(daughterId);
333  const std::vector< art::Ptr<recob::Track> > associatedTracks(pfPartToTrackAssoc.at(pDaughter.key()));
334  if(associatedTracks.size() != 1) continue;
335 
336  // Get the first associated track
337  recob::Track tpcTrack = *associatedTracks.front();
338  nuTracks.push_back(tpcTrack);
339 
340  // Truth match muon tracks and pfps
341  std::vector<art::Ptr<recob::Hit>> hits = findManyHits.at(tpcTrack.ID());
342  int trueId = RecoUtils::TrueParticleIDFromTotalRecoHits(clockData, hits, false);
343  if(std::find(lepParticleIds.begin(), lepParticleIds.end(), trueId) != lepParticleIds.end()){
344  type = "NuMuPfp";
345  }
346  else if(std::find(nuParticleIds.begin(), nuParticleIds.end(), trueId) != nuParticleIds.end()){
347  if(type != "NuMuPfp") type = "NuPfp";
348  }
349  else if(std::find(dirtParticleIds.begin(), dirtParticleIds.end(), trueId) != dirtParticleIds.end()){
350  if(type != "NuMuPfp" && type != "NuPfp") type = "DirtPfp";
351  }
352  else if(std::find(crParticleIds.begin(), crParticleIds.end(), trueId) != crParticleIds.end()){
353  if(type != "NuMuPfp" && type != "NuPfp" && type != "DirtPfp") type = "CrPfp";
354  }
355  }
356 
357  if(nuTracks.size() == 0) continue;
358 
359  std::sort(nuTracks.begin(), nuTracks.end(), [](auto& left, auto& right){
360  return left.Length() > right.Length();});
361 
362  recob::Track tpcTrack = nuTracks[0];
363  std::vector<art::Ptr<recob::Hit>> hits = findManyHits.at(tpcTrack.ID());
364  int trueId = RecoUtils::TrueParticleIDFromTotalRecoHits(clockData, hits, false);
365 
366  std::vector<art::Ptr<anab::Calorimetry>> calos = findManyCalo.at(tpcTrack.ID());
367  if(calos.size()==0) continue;
368 
369  // Only focus on muon tracks or it'll be too hard
370  if(std::abs(particles[trueId].PdgCode()) != 13) continue;
371 
372  geo::Point_t trueEnd {particles[trueId].EndX(), particles[trueId].EndY(), particles[trueId].EndZ()};
373  bool stops = false;
374 
375  if(fTPCGeo.InFiducial(trueEnd, 0.)) stops = true;
376 
377  if(stops) hStopLength[type]->Fill(tpcTrack.Length());
378  else hNoStopLength[type]->Fill(tpcTrack.Length());
379 
380  TVector3 trueEndVec (particles[trueId].EndX(), particles[trueId].EndY(), particles[trueId].EndZ());
381  TVector3 start = tpcTrack.Vertex<TVector3>();
382  TVector3 end = tpcTrack.End<TVector3>();
383  geo::Point_t recoEnd = tpcTrack.End();
384  if((start-trueEndVec).Mag() < (end-trueEndVec).Mag()) recoEnd = tpcTrack.Vertex();
385 
386  double chi2 = spTag.StoppingChiSq(recoEnd, calos);
387  if(stops) hStopChiSq[type]->Fill(chi2);
388  else hNoStopChiSq[type]->Fill(chi2);
389 
390  double startChi2 = spTag.StoppingChiSq(tpcTrack.Vertex(), calos);
391  double endChi2 = spTag.StoppingChiSq(tpcTrack.End(), calos);
392 
393  int nbins = hRatioTotal.begin()->second->GetNbinsX();
394  for(int i = 0; i < nbins; i++){
395  double ratioCut = hRatioTotal.begin()->second->GetBinCenter(i);
396 
397  hRatioTotal[type]->Fill(ratioCut);
398 
399  // If closest hit is below limit and track matches any hits then fill efficiency
400  if((startChi2 > ratioCut && !fTPCGeo.InFiducial(tpcTrack.End(), 5.) && tpcTrack.End().Y() > 0)
401  || (endChi2 > ratioCut && !fTPCGeo.InFiducial(tpcTrack.Vertex(), 5.) && tpcTrack.Vertex().Y() > 0)){
402  hRatioTag[type]->Fill(ratioCut);
403  }
404 
405  }
406 
407  }
408 
409 
410  } // StoppingCosmicIdAna::analyze()
411 
412 
414 
415 
416  } // StoppingCosmicIdAna::endJob()
417 
418  void StoppingCosmicIdAna::GetPFParticleIdMap(const PFParticleHandle &pfParticleHandle, PFParticleIdMap &pfParticleMap){
419  for (unsigned int i = 0; i < pfParticleHandle->size(); ++i){
420  const art::Ptr<recob::PFParticle> pParticle(pfParticleHandle, i);
421  if (!pfParticleMap.insert(PFParticleIdMap::value_type(pParticle->Self(), pParticle)).second){
422  std::cout << " Unable to get PFParticle ID map, the input PFParticle collection has repeat IDs!" <<"\n";
423  }
424  }
425  }
426 
427  DEFINE_ART_MODULE(StoppingCosmicIdAna)
428 } // namespace sbnd
BEGIN_PROLOG Verbose
std::map< std::string, TH1D * > hNoStopLength
fhicl::Atom< art::InputTag > TpcTrackModuleLabel
std::map< std::string, TH1D * > hRatioTag
var pdg
Definition: selectors.fcl:14
fhicl::Atom< art::InputTag > SimModuleLabel
Declaration of signal hit object.
walls no right
Definition: selectors.fcl:105
std::map< std::string, TH1D * > hRatioTotal
StoppingCosmicIdAna(Parameters const &config)
double StoppingChiSq(geo::Point_t end, std::vector< art::Ptr< anab::Calorimetry >> calos)
std::map< size_t, art::Ptr< recob::PFParticle > > PFParticleIdMap
art::InputTag fSimModuleLabel
name of detsim producer
art::EDAnalyzer::Table< Config > Parameters
T abs(T value)
virtual void analyze(const art::Event &event) override
art::InputTag fTpcTrackModuleLabel
name of TPC track producer
void GetPFParticleIdMap(const PFParticleHandle &pfParticleHandle, PFParticleIdMap &pfParticleMap)
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
const Cut kCosmicRay
bool fVerbose
print information about what&#39;s going on
BEGIN_PROLOG vertical distance to the surface Name
walls no left
Definition: selectors.fcl:105
int TrueParticleIDFromTotalRecoHits(detinfo::DetectorClocksData const &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
std::vector< std::string > types
fhicl::Table< StoppingParticleCosmicIdAlg::Config > SPTagAlg
Definition of data types for geometry description.
fhicl::Atom< art::InputTag > PandoraLabel
Provides recob::Track data product.
art::Handle< std::vector< recob::PFParticle > > PFParticleHandle
StoppingParticleCosmicIdAlg spTag
std::map< std::string, TH1D * > hStopLength
stream1 can override from command line with o or output services user sbnd
art::ServiceHandle< art::TFileService > tfs
art::InputTag fCaloModuleLabel
name of calorimetry producer
std::map< std::string, TH1D * > hStopChiSq
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:184
BEGIN_PROLOG could also be cout
std::map< std::string, TH1D * > hNoStopChiSq
fhicl::Atom< art::InputTag > CaloModuleLabel
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
bool InFiducial(geo::Point_t point, double fiducial)