ProtoFlash_module.cc
Go to the documentation of this file.
1 // ProtoFlash_module
2 // Module that tries to associate T0s from reconstructed tracks and light flashes
3 // leigh.howard.whitehead@cern.ch
4 //
5 
6 #ifndef ProtoFlash_H
7 #define ProtoFlash_H 1
8 
9 // ROOT includes
10 #include "TH1D.h"
11 #include "TH2.h"
12 #include "TTree.h"
13 
14 // C++ includes
15 #include <map>
16 #include <vector>
17 #include <iostream>
18 
19 // LArSoft includes
26 #include "dune/OpticalDetector/OpFlashSort.h"
30 
31 // ART includes.
34 #include "fhiclcpp/ParameterSet.h"
39 #include "art_root_io/TFileService.h"
40 #include "art_root_io/TFileDirectory.h"
43 #include "canvas/Persistency/Common/FindManyP.h"
44 
45 namespace protoana {
46 
47  class ProtoFlash : public art::EDAnalyzer{
48  public:
49 
50  // Standard constructor and destructor for an ART module.
52  virtual ~ProtoFlash();
53 
54  // This method is called once, at the start of the job. In this
55  // example, it will define the histogram we'll write.
56  void beginJob();
57 
58  // The analyzer routine, called once per event.
59  void analyze (const art::Event&);
60 
61  // Extract true particle times and add them to a map
62  void ExtractTrueTimes(const std::string &moduleName, std::map<int,double> &timeMap, const art::Event &evt);
63 
64  private:
65 
66  // The stuff below is the part you'll most likely have to change to
67  // go from this custom example to your own task.
68 
69  // The parameters we'll read from the .fcl file.
70  std::string fOpFlashModuleLabel; // Input tag for OpFlash collection
71  std::string fOpHitModuleLabel; // Input tag for OpHit collection
72  std::string fSignalLabel; // Input tag for the signal generator label
73  std::string fCosmicLabel; // Input tag for the cosmic generator label
74  std::string fGeantLabel; // Input tag for GEANT
75  std::string fParticleLabel; // Input tag for particle reconstruction
76 
78  TH1D *hFlashPurity;
83  TH1D *hFlashTimes;
84  TH1D *hHitTimes;
85  TH1D *hNFlash;
87  };
88 
89 }
90 
91 #endif // FlashMatchAna_H
92 
93 namespace protoana {
94 
95  //-----------------------------------------------------------------------
96  // Constructor
98  : EDAnalyzer(pset)
99  {
100 
101  // Indicate that the Input Module comes from .fcl
102  fOpFlashModuleLabel = pset.get<std::string>("OpFlashModuleLabel");
103  fOpHitModuleLabel = pset.get<std::string>("OpHitModuleLabel");
104  fSignalLabel = pset.get<std::string>("SignalLabel");
105  fCosmicLabel = pset.get<std::string>("CosmicLabel");
106  fGeantLabel = pset.get<std::string>("GeantLabel");
107  fParticleLabel = pset.get<std::string>("ParticleLabel");
108 
110 
111  // Make a few plots
112  hFlashToTrueTime = tfs->make<TH1D>("hFlashToTrueTime","",50,-5,5);
113  hFlashPurity = tfs->make<TH1D>("hFlashPurity","",50,0.499,1.001);
114  hFlashToRecoTime = tfs->make<TH1D>("hFlashToRecoTime","",50,-5,5);
115  hFlashToRecoWide = tfs->make<TH1D>("hFlashToRecoWide","",100,-10,10);
116  hFlashToRecoWider = tfs->make<TH1D>("hFlashToRecoWider","",100,-50,50);
117  hNFlash = tfs->make<TH1D>("hNFlash","",50,0,400);
118  hNHitPerFlash = tfs->make<TH1D>("hNHitPerFlash","",50,0,100);
119  hFlashTimes = tfs->make<TH1D>("hFlashTimes","",100,-4000,4000);
120  hHitTimes = tfs->make<TH1D>("hHitTimes","",100,-4000,4000);
121  hPurityTimeDiff = tfs->make<TH2D>("hPurityTimeDiff","",25,-5,5,25,0.499,1.001);
122  }
123 
124  //-----------------------------------------------------------------------
125  // Destructor
127  {}
128 
129  //-----------------------------------------------------------------------
131  {}
132 
133  //-----------------------------------------------------------------------
135  {
136 
137  // Make sure we can use this on data and MC
138  bool isMC = !(evt.isRealData());
139 // isMC = false;
140 
141  // Get flashes from event
142  std::vector<art::Ptr<recob::OpFlash> > flashlist;
143  auto FlashHandle = evt.getHandle< std::vector< recob::OpFlash > >(fOpFlashModuleLabel);
144  if (FlashHandle) {
145  art::fill_ptr_vector(flashlist, FlashHandle);
146  std::sort(flashlist.begin(), flashlist.end(), recob::OpFlashPtrSortByPE);
147  }
148 
149  // Get assosciations between flashes and hits
150  art::FindManyP< recob::OpHit > Assns(FlashHandle, evt, fOpFlashModuleLabel);
151 
152  // We want to store a map of track time to track id
153  // This will later allow us to check how much of a flash comes from the best matched time
154  std::map<int,double> trueTimeID;
155  if(isMC){
156  // Check for generator inputs - particle gun or protoDUNE beam
157  if(fSignalLabel!=""){
158  ExtractTrueTimes(fSignalLabel,trueTimeID,evt);
159  }
160 
161  // Check for cosmic generator inputs
162  if(fCosmicLabel!=""){
163  ExtractTrueTimes(fCosmicLabel,trueTimeID,evt);
164  }
165  }
166 
167  //////////////////////////////////////
168  // Access all the Flash Information //
169  //////////////////////////////////////
170 
171  hNFlash->Fill(FlashHandle->size());
172 
173  // Use the clocks service to make sure to account for the offset between true times and the electronics clocks
174  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(evt);
175 
176  // Store a map of flash times
177  std::map<int,double> flashMap;
178 
179  // For every OpFlash in the vector
180  for(unsigned int i = 0; i < FlashHandle->size(); ++i)
181  {
182 
183  // Get OpFlash and associated hits
184  art::Ptr< recob::OpFlash > TheFlashPtr(FlashHandle, i);
185  recob::OpFlash TheFlash = *TheFlashPtr;
186  art::FindManyP< recob::OpHit > Assns(FlashHandle, evt, fOpFlashModuleLabel);
187  std::vector< art::Ptr<recob::OpHit> > matchedHits = Assns.at(i);
188 
189  // Account for the time offset in the TPC
190  flashMap.insert(std::make_pair(i,TheFlash.Time() - clockData.TriggerOffsetTPC()));
191 
192  hNHitPerFlash->Fill(matchedHits.size());
193  hFlashTimes->Fill(TheFlash.Time());
194 
195  for(auto const h : matchedHits){
196  hHitTimes->Fill(h->PeakTime());
197  }
198 
199  // Truth level code
200  if(isMC){
202 
203  // Get the best match in time, then check how much of the light comes from
204  // the best matched particle
205  int bestMatch = 0;
206  double bestPurity = 0;
207  double minTimeDiff = 1e20;
208 
209  // Iterate over the map
210  for(auto &m : trueTimeID){
211 
212  double dist = fabs(m.second - TheFlash.Time());
213  if(dist < minTimeDiff){
214  // Does this track give us purity > 0.5?
215  std::set<int> trackIDs;
216  trackIDs.emplace(m.first);
217  double purity = pbt->OpHitCollectionPurity(trackIDs,matchedHits);
218  if(purity < 0.5) continue;
219 
220  // If purity is good enough, this is a success
221  minTimeDiff = dist;
222  bestMatch = m.first;
223  bestPurity = purity;
224  }
225  }
226  if(minTimeDiff > 1000){
227  // std::cout << "No sensible true match to flash " << i << std::endl;
228  }
229 
230  if(bestPurity >= 0.5) std::cout << "Best true time matched particle " << bestMatch << " has delta T = " << minTimeDiff << " and gives a purity " << bestPurity << std::endl;
231 
232  hFlashToTrueTime->Fill(trueTimeID[bestMatch] - TheFlash.Time());
233  hPurityTimeDiff->Fill(trueTimeID[bestMatch] - TheFlash.Time(),bestPurity);
234  hFlashPurity->Fill(bestPurity);
235  }
236  } // End loop over flashes
237 
238  // Get reconstruction information from particles with a measured T0
239  // Try finding some particles
241  = evt.getValidHandle<std::vector<recob::PFParticle> >(fParticleLabel);
242 
244 
245  for (size_t p = 0; p != particleHandle->size(); ++p){
246 
247  const auto thisParticle = (*particleHandle)[p];
248 
249  // Only consider primaries so we don't include deltas etc
250  if(!(thisParticle.IsPrimary())) continue;
251 
252  // Did this particle have an associated T0?
253  std::vector<anab::T0> t0s = pfpUtil.GetPFParticleT0(thisParticle,evt,fParticleLabel);
254  if(t0s.size() == 0) continue;
255 
256  // Pandora gives us times in ns
257  double recoT0 = t0s[0].Time() / 1000.;
258 
259  int bestRecoMatch = 0;
260  double minRecoTimeDiff = 1e20;
261 
262  // Now loop over the flashes
263  for(auto &m : flashMap){
264  double dist = fabs(recoT0 - m.second);
265  if(dist < minRecoTimeDiff){
266  minRecoTimeDiff = dist;
267  bestRecoMatch = m.first;
268  }
269  }
270 
271  std::cout << "Particle " << p << " has a TPC T0 = " << recoT0 << std::endl;
272 
273  if(minRecoTimeDiff > 100){
274  std::cout << "No sensible reco match to flash " << p << std::endl;
275  }
276  std::cout << "Best matched flash " << bestRecoMatch << " has delta T = " << minRecoTimeDiff << std::endl;
277 
278  hFlashToRecoTime->Fill(recoT0 - flashMap[bestRecoMatch]);
279  hFlashToRecoWide->Fill(recoT0 - flashMap[bestRecoMatch]);
280  hFlashToRecoWider->Fill(recoT0 - flashMap[bestRecoMatch]);
281  }
282 
283  }
284 
285  void ProtoFlash::ExtractTrueTimes(const std::string &moduleName, std::map<int,double> &timeMap, const art::Event &evt){
286 
287 
288  auto MCTruthsHandle = evt.getValidHandle<std::vector<simb::MCTruth> >(moduleName);
289  art::Ptr<simb::MCTruth> thisMCTruth(MCTruthsHandle, 0);
290  if (thisMCTruth->NParticles() == 0) {
291  mf::LogError("FlashMatchAna") << "No Cosmic MCTruth Particles";
292  }
293  else std::cout << "MCTruth from " << moduleName << " has " << thisMCTruth->NParticles() << " particles " << std::endl;
294 
295  // Get all the track ids associated with the cosmic events.
296  art::FindManyP<simb::MCParticle> geantAssns(MCTruthsHandle,evt,fGeantLabel);
297 
298  for ( size_t i = 0; i < geantAssns.size(); i++) {
299  auto parts = geantAssns.at(i);
300  int counter = 0;
301  for (auto part = parts.begin(); part != parts.end(); part++) {
302  ++counter;
303  timeMap.insert(std::make_pair((*part)->TrackId(),(*part)->T()/1000.));
304  }
305  std::cout << "Found " << counter << " GEANT particles associated to " << moduleName << " MCTruth " << i << std::endl;
306  }
307 
308  }
309 
310 } // namespace protoana
311 
312 namespace protoana {
314 }
std::string fOpFlashModuleLabel
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
std::string string
Definition: nybbler.cc:12
void ExtractTrueTimes(const std::string &moduleName, std::map< int, double > &timeMap, const art::Event &evt)
MaybeLogger_< ELseverityLevel::ELsev_error, false > LogError
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
const double OpHitCollectionPurity(std::set< int > const &tkIds, std::vector< art::Ptr< recob::OpHit > > const &opHits_Ps)
bool isRealData() const
double Time() const
Definition: OpFlash.h:106
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
T get(std::string const &key) const
Definition: ParameterSet.h:271
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
p
Definition: test.py:223
struct recob::OpFlashPtrSortByPE_t OpFlashPtrSortByPE
constexpr double dist(const TReal *x, const TReal *y, const unsigned int dimension)
void analyze(const art::Event &)
TCEvent evt
Definition: DataStructs.cxx:7
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:297
ProtoFlash(const fhicl::ParameterSet &)
QTextStream & endl(QTextStream &s)