UtilityExample_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: UtilityExample
3 // Plugin Type: analyzer (art v2_07_03)
4 // File: UtilityExample_module.cc
5 //
6 // Generated at Mon Sep 4 06:55:33 2017 by Leigh Whitehead using cetskelgen
7 // from cetlib version v3_00_01.
8 //
9 // This module is designed to show some usage examples of the analysis
10 // tools that I have been producing for protoDUNE. The aim has been to
11 // simplify the associations between the different objects to make
12 // some of the low-level art features more transparent
13 //
14 // The code is split into a few sections with each focusing on a different
15 // type of initial object
16 //
17 ////////////////////////////////////////////////////////////////////////
18 
25 #include "art_root_io/TFileService.h"
27 #include "canvas/Persistency/Common/FindManyP.h"
28 #include "fhiclcpp/ParameterSet.h"
30 
42 
47 
48 namespace protoana {
49  class UtilityExample;
50 }
51 
52 
54 public:
55 
56  explicit UtilityExample(fhicl::ParameterSet const & p);
57  // The compiler-generated destructor is fine for non-base
58  // classes without bare pointers or other resource use.
59 
60  // Plugins should not be copied or assigned.
61  UtilityExample(UtilityExample const &) = delete;
62  UtilityExample(UtilityExample &&) = delete;
63  UtilityExample & operator = (UtilityExample const &) = delete;
65 
66  virtual void beginJob() override;
67  virtual void endJob() override;
68 
69  // Required functions.
70  void analyze(art::Event const & e) override;
71 
72 private:
73 
74  // fcl parameters
80  bool fVerbose;
81 
82 };
83 
84 
86  :
87  EDAnalyzer(p),
88  fCalorimetryTag(p.get<std::string>("CalorimetryTag")),
89  fTrackerTag(p.get<std::string>("TrackerTag")),
90  fShowerTag(p.get<std::string>("ShowerTag")),
91  fPFParticleTag(p.get<std::string>("PFParticleTag")),
92  fGeneratorTag(p.get<std::string>("GeneratorTag")),
93  fVerbose(p.get<bool>("Verbose"))
94 {
95 
96 }
97 
99 {
100 
101 }
102 
104 {
105 
106  // We must have MC for this module to make sense
107  if(evt.isRealData()) return;
108 
109  // ------------------------- Pure Truth Information -------------------------
110  // One of the slightly annoying things about the protoDUNE simulation is that
111  // LArG4 loses the information about which one of the true particles is the
112  // one we triggered on - also called the Good Particle. This is the particle
113  // from the beam that we are trying to detect.
114 
115  // Get the truth utility to help us out
117 
118  // Get the generator MCTruth objects and find the GEANT track id of the good particle. The generator MCTruth
119  // object has the information about which particle is the good one. The GetGeantGoodParticle(...) function
120  // takes care of giving you back the Geant4 version of this particle
121 
122  // Firstly we need to get the list of MCTruth objects from the generator. The standard protoDUNE
123  // simulation has fGeneratorTag = "generator"
124  auto mcTruths = evt.getValidHandle<std::vector<simb::MCTruth>>(fGeneratorTag);
125  // mcTruths is basically a pointer to an std::vector of simb::MCTruth objects. There should only be one
126  // of these, so we pass the first element into the function to get the good particle
127  const simb::MCParticle* geantGoodParticle = truthUtil.GetGeantGoodParticle((*mcTruths)[0],evt);
128  if(geantGoodParticle != 0x0){
129  std::cout << "Found GEANT particle corresponding to the good particle with pdg = " << geantGoodParticle->PdgCode() << std::endl;
130  }
131 
132  // ------------------------- Reco Track Information -------------------------
133  // In this section of code we will look at reconstructed tracks. The main
134  // reconstruction we use is Pandora, and we will look at all of the tracks
135  // reconstructed by this algorithm.
136 
137  // Get the track utility
139  // A few variables to tell us a bit about our reconstructed tracks
140  unsigned int nTracksWithTruth = 0;
141  unsigned int nTracksWithT0 = 0;
142  unsigned int nTracksWithTag = 0;
143  unsigned int nTracksWithCalo = 0;
144  // Get the reconstructed tracks, by default from the "pandoraTrack" module
145  auto recoTracks = evt.getValidHandle<std::vector<recob::Track> >(fTrackerTag);
146  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(evt);
147 
148  // Loop over the reconstructed tracks
149  for(unsigned int t = 0; t < recoTracks->size(); ++t){
150 
151  // Take the t-th element for our current track
152  const recob::Track thisTrack = (*recoTracks)[t];
153  // We can then use the truth utility to give us the true track matching out reconstructed track
154  const simb::MCParticle *trueMatch = truthUtil.GetMCParticleFromRecoTrack(clockData, thisTrack,evt,fTrackerTag);
155  bool hasTruth = (trueMatch != 0x0);
156 
157  // Some of the tracks, primarily those that cross the cathode, will have a reconstructed T0.
158  // We can access these through the track utility
159  std::vector<anab::T0> trackT0 = trackUtil.GetRecoTrackT0(thisTrack,evt,fTrackerTag);
160  bool hasT0 = (trackT0.size() != 0);
161 
162  // Similarly, some tracks can have a cosmic tag (though not from the pandora reconstruction)
163  std::vector<anab::CosmicTag> trackCosmic = trackUtil.GetRecoTrackCosmicTag(thisTrack,evt,fTrackerTag);
164  bool hasTag = (trackCosmic.size() != 0);
165 
166  // All tracks have some calorimetry information that stores things such as dE/dx etc.
167  std::vector<anab::Calorimetry> trackCalo = trackUtil.GetRecoTrackCalorimetry(thisTrack,evt,fTrackerTag,fCalorimetryTag);
168  bool hasCalo = (trackCalo.size() != 0);
169 
170  // Note that the above three functions return std::vectors of objects, but they will all either have
171  // size 0 or 1.
172 
173  if(hasTruth) ++nTracksWithTruth;
174  if(hasT0) ++nTracksWithT0;
175  if(hasTag) ++nTracksWithTag;
176  if(hasCalo) ++nTracksWithCalo;
177  } // End loop over reconstructed tracks
178 
179  // Report back what we have managed to find out about the tracks
180  std::cout << "Found " << recoTracks->size() << " reconstructed tracks:" << std::endl;
181  std::cout << " - " << nTracksWithTruth << " successfully associated to the truth information " << std::endl;
182  std::cout << " - " << nTracksWithT0 << " have a reconstructed T0" << std::endl;
183  std::cout << " - " << nTracksWithTag << " have a cosmic tag" << std::endl;
184  std::cout << " - " << nTracksWithCalo << " have calorimetry info" << std::endl;
185 
186  // ------------------------- Reco Shower Information ------------------------
187  // There isn't a whole lot that we can do with shower objects. Here I just
188  // get the average number of hits from all of the showers.
189 
190  // Get the shower utility
192 
193  // Get the reconstructed showers, by default from the "pandoraShower" module
194  auto recoShowers = evt.getValidHandle<std::vector<recob::Shower> >(fShowerTag);
195 
196  float totalHits = 0.0;
197 
198  for(unsigned int s = 0; s < recoShowers->size(); ++s){
199  // Get the shower
200  const recob::Shower thisShower = (*recoShowers)[s];
201  // Get the number of hits
202  totalHits += showerUtil.GetNumberRecoShowerHits(thisShower,evt,fShowerTag);
203  }
204 
205  std::cout << "Found " << recoShowers->size() << " showers with an average of " << totalHits/(float)recoShowers->size() << " hits" << std::endl;
206 
207 
208  // ------------------------- PFParticle Information -------------------------
209  // PFParticles are "particle flow" output objects that represent an
210  // individual particle. These are the highest level objects and contain
211  // links to their daughter particles and are the recommended starting
212  // point to use the output from the pandora reconstruction
213 
214  // Get the PFParticle utility
216 
217  // Get all of the PFParticles, by default from the "pandora" product
218  auto recoParticles = evt.getValidHandle<std::vector<recob::PFParticle>>(fPFParticleTag);
219 
220  // Get some information about the particles
221  unsigned int nParticlesPrimary = 0;
222  unsigned int nParticlesWithT0 = 0;
223  unsigned int nParticlesWithTag = 0;
224  for(unsigned int p = 0; p < recoParticles->size(); ++p){
225  // Get the PFParticle
226  const recob::PFParticle thisParticle = (*recoParticles)[p];
227 
228  // Only consider primary particles here
229  if(!thisParticle.IsPrimary()) continue;
230 
231  ++nParticlesPrimary;
232 
233  // Does this particle have a T0?
234  if(pfpUtil.GetPFParticleT0(thisParticle,evt,fPFParticleTag).size() != 0) ++nParticlesWithT0;
235 
236  // Does this particle have a cosmic tag?
237  if(pfpUtil.GetPFParticleCosmicTag(thisParticle,evt,fPFParticleTag).size() != 0) ++nParticlesWithTag;
238 
239  }
240  // Print out a summary
241  std::cout << "Found " << nParticlesPrimary << " reconstructed primary particles:" << std::endl;
242  std::cout << " - Total number of particles = " << recoParticles->size() << std::endl;
243  std::cout << " - " << nParticlesWithT0 << " have a reconstructed T0" << std::endl;
244  std::cout << " - " << nParticlesWithTag << " have a cosmic tag" << std::endl;
245 
246  // Pandora divides up the detector into slices representing spacial and temporal regions
247  // of the event. We can use metadata from pandora to build a slice map if we want to.
248  // This consists of the slice number from pandora and a vector of primary PFParticles
249  // in that slice
250  std::map<unsigned int, std::vector<const recob::PFParticle*>> sliceMap;
251  // Get the slice map from the PFParticle utility
252  sliceMap = pfpUtil.GetPFParticleSliceMap(evt,fPFParticleTag);
253  unsigned int nMultiSlice = 0;
254  // Let's count the number of slices containing multiple primary PFParticles
255  std::cout << "Found " << sliceMap.size() << " slices with PFParticles" << std::endl;
256  for(auto slice : sliceMap){
257  if(slice.second.size() > 1) ++nMultiSlice;
258  }
259  std::cout << " - " << nMultiSlice << " have at least one primary PFParticle" << std::endl;
260 
261  // Pandora will also tag which slice contains the beam particle. The PFParticle utility
262  // lets us find out which one
263  unsigned short beamSlice = pfpUtil.GetBeamSlice(evt,fPFParticleTag);
264  std::cout << "- Beam slice = " << beamSlice << std::endl;
265  if(beamSlice != 9999){
266  // We have found the beam slice. Let's get the particles contained in the slice
267  std::vector<const recob::PFParticle*> beamSlicePrimaries = pfpUtil.GetPFParticlesFromBeamSlice(evt,fPFParticleTag);
268  std::cout << " - Found the beam slice! " << beamSlicePrimaries.size() << " beam particles in slice " << beamSlice << std::endl;
269  // Loop over the particles in the beam slice
270  for (const recob::PFParticle* prim : beamSlicePrimaries){
271  // Use the PFParticle utility to get the vertex of the PFParticle
272  // NB: this is the most upstream position for beam particles, and the highest point for cosmics
273  const TVector3 vtx = pfpUtil.GetPFParticleVertex(*prim,evt,fPFParticleTag,fTrackerTag);
274  std::cout << "Beam particle vertex: " << std::endl;
275  vtx.Print();
276  // If this is a track-like particle then we can get a secondary interaction point from the
277  // downstream end of the track.
278  if(pfpUtil.IsPFParticleTracklike(*prim,evt,fPFParticleTag,fTrackerTag)){
279  const TVector3 sec = pfpUtil.GetPFParticleSecondaryVertex(*prim,evt,fPFParticleTag,fTrackerTag);
280  std::cout << "Beam particle interaction vertex: " << std::endl;
281  sec.Print();
282  // The following(complicated) statement gets the recob::Track from the recob::PFParticle and then
283  // gets the number of recob::Hit objects associated to the recob::Track
284  std::cout << "PFParticle track has " << trackUtil.GetNumberRecoTrackHits(*(pfpUtil.GetPFParticleTrack(*prim,evt,fPFParticleTag,fTrackerTag)),evt,fTrackerTag) << " hits" << std::endl;
285  }
286  // Showers do not have a secondary vertex
287  else{
288  // The following(complicated) statement gets the recob::Shower from the recob::PFParticle and then
289  // gets the number of recob::Hit objects associated to the recob::Shower
290  std::cout << "PFParticle shower has " << showerUtil.GetNumberRecoShowerHits(*(pfpUtil.GetPFParticleShower(*prim,evt,fPFParticleTag,fShowerTag)),evt,fShowerTag) << " hits" << std::endl;
291  }
292  // We can also ask the PFParticle how many recob::Hit and recob::SpacePoint objects it contains
293  std::cout << "Beam particle has " << pfpUtil.GetNumberPFParticleHits(*prim,evt,fPFParticleTag) << " hits and "
294  << pfpUtil.GetNumberPFParticleSpacePoints(*prim,evt,fPFParticleTag) << " space points" << std::endl;
295  // Try to get the daughter tracks and showers
296  const std::vector<const recob::Track*> daughterTracks = pfpUtil.GetPFParticleDaughterTracks(*prim,evt,fPFParticleTag,fTrackerTag);
297  const std::vector<const recob::Shower*> daughterShowers = pfpUtil.GetPFParticleDaughterShowers(*prim,evt,fPFParticleTag,fShowerTag);
298  std::cout << "Beam particle has " << daughterTracks.size() << " daughter tracks and " << daughterShowers.size() << " daughter showers." << std::endl;
299  }
300 
301  // Look for unassociated hits in the beam slice
302  const std::vector<const recob::Hit*> unassocHits = pfpUtil.GetPFParticleSliceUnassociatedHits(*(beamSlicePrimaries[0]),evt,fPFParticleTag);
303  std::cout << "The besm slice has " << unassocHits.size() << " hits not associated to any PFParticle " << std::endl;
304  }
305 
306  // The first pass of pandora reconstruction identifies clear cosmic particles. We can get a vector of these from the PFParticle utility
307  std::cout << "There are " << pfpUtil.GetClearCosmicPFParticles(evt,fPFParticleTag).size() << " clear cosmic muons in this event" << std::endl;
308 
309 }
310 
312 {
313 
314 }
315 
unsigned int GetNumberRecoTrackHits(const recob::Track &track, art::Event const &evt, const std::string trackModule) const
Get the number of hits from a given reco track.
std::vector< anab::T0 > GetPFParticleT0(const recob::PFParticle &particle, art::Event const &evt, std::string particleLabel) const
Get the T0(s) from a given PFParticle.
const simb::MCParticle * GetGeantGoodParticle(const simb::MCTruth &genTruth, const art::Event &evt) const
UtilityExample(fhicl::ParameterSet const &p)
const recob::Shower * GetPFParticleShower(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string showerLabel) const
Get the shower associated to this particle. Returns a null pointer if not found.
std::string string
Definition: nybbler.cc:12
std::vector< anab::Calorimetry > GetRecoTrackCalorimetry(const recob::Track &track, art::Event const &evt, const std::string trackModule, const std::string caloModule) const
Get the Calorimetry(s) from a given reco track.
const std::vector< const recob::Hit * > GetPFParticleSliceUnassociatedHits(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel) const
For a given PFParticle find its slice and return all those hits not associated to any PFParticle...
const TVector3 GetPFParticleVertex(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string trackLabel) const
Function to find the interaction vertex of a primary PFParticle.
STL namespace.
uint size() const
Definition: qcstring.h:201
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
bool IsPFParticleTracklike(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string trackLabel) const
Is the particle track-like?
Particle class.
unsigned int GetNumberRecoShowerHits(const recob::Shower &shower, art::Event const &evt, const std::string showerModule) const
Get the number of hits from a given reco shower.
std::vector< anab::T0 > GetRecoTrackT0(const recob::Track &track, art::Event const &evt, std::string trackModule) const
Get the T0(s) from a given reco track.
virtual void beginJob() override
bool isRealData() const
const double e
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
UtilityExample & operator=(UtilityExample const &)=delete
unsigned short GetBeamSlice(art::Event const &evt, const std::string particleLabel) const
Try to get the slice tagged as beam. Returns 9999 if no beam slice was found.
std::vector< anab::CosmicTag > GetRecoTrackCosmicTag(const recob::Track &track, art::Event const &evt, std::string trackModule) const
Get the cosmic tag(s) from a given reco track.
const recob::Track * GetPFParticleTrack(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string trackLabel) const
Get the track associated to this particle. Returns a null pointer if not found.
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
const std::map< unsigned int, std::vector< const recob::PFParticle * > > GetPFParticleSliceMap(art::Event const &evt, const std::string particleLabel) const
Get a map of slice index to the primary PFParticles within it.
const simb::MCParticle * GetMCParticleFromRecoTrack(detinfo::DetectorClocksData const &clockData, const recob::Track &track, art::Event const &evt, std::string trackModule) const
bool IsPrimary() const
Returns whether the particle is the root of the flow.
Definition: PFParticle.h:86
const std::vector< const recob::PFParticle * > GetPFParticlesFromBeamSlice(art::Event const &evt, const std::string particleLabel) const
Return the pointers for the PFParticles in the beam slice. Returns an empty vector is no beam slice w...
unsigned int GetNumberPFParticleSpacePoints(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel) const
Get the number of space points.
Declaration of signal hit object.
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
const std::vector< const recob::PFParticle * > GetClearCosmicPFParticles(art::Event const &evt, const std::string particleLabel) const
Get all of the clear cosmic ray particles.
std::vector< anab::CosmicTag > GetPFParticleCosmicTag(const recob::PFParticle &particle, art::Event const &evt, std::string particleLabel) const
Get the cosmic tag(s) from a given PFParticle.
const std::vector< const recob::Shower * > GetPFParticleDaughterShowers(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string showerLabel) const
Get the daughter showers from the PFParticle.
virtual void endJob() override
Provides recob::Track data product.
const TVector3 GetPFParticleSecondaryVertex(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string trackLabel) const
Function to find the secondary interaction vertex of a primary PFParticle.
void analyze(art::Event const &e) override
TCEvent evt
Definition: DataStructs.cxx:7
auto const & get(AssnsNode< L, R, D > const &r)
Definition: AssnsNode.h:115
int bool
Definition: qglobal.h:345
const std::vector< const recob::Track * > GetPFParticleDaughterTracks(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel, const std::string trackLabel) const
Get the daughter tracks from the PFParticle.
static QCString * s
Definition: config.cpp:1042
unsigned int GetNumberPFParticleHits(const recob::PFParticle &particle, art::Event const &evt, const std::string particleLabel) const
Get the number of hits.
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a "fitted" track:
Definition: Track.h:49
QTextStream & endl(QTextStream &s)