T0RecoSCE_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: T0RecoSCE
3 // Module Type: analyser
4 // File: T0RecoSCE_module.cc
5 //
6 // Joshua Thompson - joshualt@fnal.gov
7 // developed from work by Hannah Rogers - hannah.rogers@colostate.edu
8 // based on uboonecode modules by David Caratelli and Chris Barnes
9 ////////////////////////////////////////////////////////////////////////
10 
18 #include "fhiclcpp/ParameterSet.h"
20 #include "art_root_io/TFileService.h"
21 
22 // services etc...
26 
27 // data-products
42 
43 // ROOT
44 #include "TVector3.h"
45 #include <TTree.h>
46 
47 // C++
48 #include <memory>
49 #include <iostream>
50 #include <utility>
51 
52 class T0RecoSCE;
53 
54 class T0RecoSCE : public art::EDAnalyzer {
55 public:
56  explicit T0RecoSCE(fhicl::ParameterSet const & p);
57  // The destructor generated by the compiler is fine for classes
58  // without bare pointers or other resource use.
59 
60  // Plugins should not be copied or assigned.
61  T0RecoSCE(T0RecoSCE const &) = delete;
62  T0RecoSCE(T0RecoSCE &&) = delete;
63  T0RecoSCE & operator = (T0RecoSCE const &) = delete;
64  T0RecoSCE & operator = (T0RecoSCE &&) = delete;
65 
66  void beginJob() override;
67 
68  //Required functions.
69  void analyze(art::Event const & evt) override;
70 
71 private:
72  // Functions to be used throughout module
73 
74  void SortTrackPoints (const recob::Track& track, std::vector<TVector3>& sorted_trk);
75 
76  void SplitTrack (const recob::Track& track, std::vector<TVector3>& sorted_trk);
77 
78  size_t FlashMatch (const double reco_time, std::vector<double> op_times_v);
79 
80  // Declare member data here
81 
87 
89 
90  bool fUseMC;
91 
92  double fEdgeWidth; // [cm]
94 
95  bool fCathode;
96  bool fAnode;
97 
98  bool fAllFlash;
99 
100  double fMinPE;
102 
105 
107 
110 
111  bool fDebug;
112 
113  double fDriftVelocity; // [cm/us]
114  unsigned int fReadoutWindow;
115 
118 
119  double det_top;
120  double det_bottom;
121  double det_front;
122  double det_back;
123  double det_width; // [cm]
124 
125  std::vector<double> op_times;
126 
127  std::vector<size_t> flash_id_v;
129 
130  std::vector<size_t> op_id_v;
132 
133  TTree *track_tree;
134  // Track parameters
135  double rc_time;
136  double length;
138  double rc_ys, rc_ye;
139  double rc_zs, rc_ze;
140 
141  // Track parameters for cathode crossing anode piercing tracks
145 
146  // Flash parameters
158 
159  // Reco results
161 
162  // Track info
169 
170  // MC info
171  double mc_time;
177  double dt_mc_reco;
179 
180  // Tree for flash info
181  TTree *flash_tree;
183  double flash_time;
186  double flash_pe;
191 
192  // Tree for event info
193  TTree *ev_tree;
194  int run;
195  int event;
197  int ev_ctr;
198 
199  };
200 
202  :
203  EDAnalyzer(fcl) {
204 
205  fTrackProducer = fcl.get<std::string> ("TrackProducer" );
206  fHitProducer = fcl.get<std::string> ("HitProducer" );
207  fFlashProducer = fcl.get<std::string> ("FlashProducer" );
208  fTriggerProducer = fcl.get<std::string> ("TriggerProducer" );
209  fPFPProducer = fcl.get<std::string> ("PFPProducer" );
210 
211  fOpHitProducer = fcl.get<std::string> ("OpHitProducer" );
212 
213  fUseMC = fcl.get<bool> ("UseMC" );
214 
215  fEdgeWidth = fcl.get<double> ("EdgeWidth" );
216  fReadoutEdgeTicks = fcl.get<int> ("ReadoutEdgeTicks" );
217 
218  fMinPE = fcl.get<double> ("MinPE" );
219  fMinTrackLength = fcl.get<double> ("MinTrackLength" );
220 
221  fCathode = fcl.get<bool> ("CathodeCrossers" );
222  fAnode = fcl.get<bool> ("AnodePiercers" );
223 
224  fDebug = fcl.get<bool> ("Debug" );
225 
226  fAllFlash = fcl.get<bool> ("AllFlashToTrackTimeDiffs");
227 
228  fFlashScaleFactor = fcl.get<double> ("FlashScaleFactor" );
229  fFlashTPCOffset = fcl.get<double> ("FlashTPCOffset" );
230 
231  fUseOpHits = fcl.get<bool> ("UseOpHits" );
232  fFirstOpChannel = fcl.get<int> ("FirstOpChannel" );
233  fLastOpChannel = fcl.get<int> ("LastOpChannel" );
234 
235  fAnodeT0Check = fcl.get<bool> ("CheckAssignedAnodeT0" );
236  fAnodeT0Producer = fcl.get<std::string> ("AnodeT0Producer" );
237 
238 
239  // get boundaries based on detector bounds
240  auto const* geom = lar::providerFrom<geo::Geometry>();
241 
246 
247  for (geo::TPCID const& tID: geom->IterateTPCIDs()) {
248  geo::TPCGeo const& TPC = geom->TPC(tID);
249 
250  if(TPC.DriftDistance() < 25.0) continue;
251 
252  double origin[3] = {0.};
253  double center[3] = {0.};
254  TPC.LocalToWorld(origin, center);
255 
256  double tpc_top = center[1] + TPC.HalfHeight();
257  double tpc_bottom = center[1] - TPC.HalfHeight();
258  double tpc_front = center[2] - TPC.HalfLength();
259  double tpc_back = center[2] + TPC.HalfLength();
260 
261  if (tpc_top > det_top) det_top = tpc_top;
262  if (tpc_bottom < det_bottom) det_bottom = tpc_bottom;
263  if (tpc_front < det_front) det_front = tpc_front;
264  if (tpc_back > det_back) det_back = tpc_back;
265 
266  det_width = TPC.DriftDistance();
267  }
268 
269  // Use 'detp' to find 'efield' and 'temp'
270  auto const detp = art::ServiceHandle<detinfo::DetectorPropertiesService>()->DataForJob();
271  double efield = detp.Efield();
272  std::cout << "Nominal electric field is: " << efield*1000 << " V/cm" << std::endl;
273 
274  double temp = detp.Temperature();
275  std::cout << "LAr temperature is: " << temp << " K" << std::endl;
276 
277  // Determine the drift velocity from 'efield' and 'temp'
278  fDriftVelocity = detp.DriftVelocity(efield,temp);
279  std::cout << "Drift velocity is: " << fDriftVelocity << " cm/us" << std::endl;
280 
281  // Get Readout window length
282 
283  fReadoutWindow = detp.ReadOutWindowSize();
284  std::cout << "Readout window is: " << fReadoutWindow << " ticks" << std::endl;
285  }
286 
288 
290 
291  track_tree = tfs->make<TTree>("track_tree","SCE calibrations variables");
292  //Track parameters
293  track_tree->Branch("rc_time",&rc_time,"rc_time/D");
294  track_tree->Branch("length", &length, "length/D");
295  track_tree->Branch("rc_xs",&rc_xs,"rc_xs/D");
296  track_tree->Branch("rc_xs_corr",&rc_xs_corr,"rc_xs/D");
297  track_tree->Branch("rc_ys",&rc_ys,"rc_ys/D");
298  track_tree->Branch("rc_zs",&rc_zs,"rc_zs/D");
299  track_tree->Branch("rc_xe",&rc_xe,"rc_xe/D");
300  track_tree->Branch("rc_xe_corr",&rc_xe_corr,"rc_xe_corr/D");
301  track_tree->Branch("rc_ye",&rc_ye,"rc_ye/D");
302  track_tree->Branch("rc_ze",&rc_ze,"rc_ze/D");
303 
304  if(fCathode&&fAnode) {
305  track_tree->Branch("cathode_rc_time",&cathode_rc_time,"cathode_rc_time/D");
306  track_tree->Branch("anode_rc_time",&anode_rc_time,"anode_rc_time/D");
307  track_tree->Branch("dt_anode_cathode",&dt_anode_cathode,"dt_anode_cathode/D");
308  }
309 
310  // Information on whether track crosses anode or cathode
311  track_tree->Branch("TPC_entering_candidate",&TPC_entering_candidate,"TPC_entering_candidate/B");
312  track_tree->Branch("TPC_exiting_candidate",&TPC_exiting_candidate,"TPC_exiting_candidate/B");
313  track_tree->Branch("cathode_crossing_track",&cathode_crossing_track,"cathode_crossing_track/B");
314 
315  // Flash parameters
316  track_tree->Branch("matched_flash_time",&matched_flash_time,"matched_flash_time/D");
317  track_tree->Branch("matched_flash_time_width",&matched_flash_time_width,"matched_flash_time_width/D");
318  //track_tree->Branch("corrected_matched_flash_time",&corrected_matched_flash_time,"corrected_matched_flash_time/D");
319  track_tree->Branch("matched_flash_pe",&matched_flash_pe,"matched_flash_pe/D");
320  track_tree->Branch("matched_flash_centre_y",&matched_flash_centre_y,"matched_flash_centre_y/D");
321  track_tree->Branch("matched_flash_centre_z",&matched_flash_centre_z,"matched_flash_centre_z/D");
322  track_tree->Branch("matched_flash_max_pe_det_x",&matched_flash_max_pe_det_x,"matched_flash_max_pe_det_x/D");
323  track_tree->Branch("matched_flash_max_pe_det_y",&matched_flash_max_pe_det_y,"matched_flash_max_pe_det_y/D");
324  track_tree->Branch("matched_flash_max_pe_det_z",&matched_flash_max_pe_det_z,"matched_flash_max_pe_det_z/D");
325  track_tree->Branch("matched_flash_width_y",&matched_flash_width_y,"matched_flash_width_y/D");
326  track_tree->Branch("matched_flash_width_z",&matched_flash_width_z,"matched_flash_width_z/D");
327 
328  // Flash -> track time difference
329  track_tree->Branch("dt_flash_reco",&dt_flash_reco,"dt_flash_reco/D");
330 
331  // Branches for MC truth info
332  if(fUseMC) {
333  track_tree->Branch("mc_time",&mc_time,"mc_time/D");
334  track_tree->Branch("dt_mc_reco",&dt_mc_reco,"dt_mc_reco/D");
335 
336  track_tree->Branch("mc_particle_x_anode",&mc_particle_x_anode,"mc_particle_x_anode/D");
337  track_tree->Branch("mc_particle_y_anode",&mc_particle_y_anode,"mc_particle_y_anode/D");
338  track_tree->Branch("mc_particle_z_anode",&mc_particle_z_anode,"mc_particle_z_anode/D");
339  track_tree->Branch("true_anode_piercer",&true_anode_piercer,"true_anode_piercer/B");
340  }
341 
342  // Flash Tree
343  if (fAllFlash) {
344  flash_tree = tfs->make<TTree>("flash_tree","Flash properties and reco time differences");
345  flash_tree->Branch("flash_time",&flash_time,"flash_time/D");
346  flash_tree->Branch("flash_time_width",&flash_time_width,"flash_time_width/D");
347  flash_tree->Branch("corrected_flash_time",&corrected_flash_time,"corrected_flash_time/D");
348  flash_tree->Branch("flash_reco_time_diff",&flash_reco_time_diff,"flash_reco_time_diff/D");
349  flash_tree->Branch("flash_pe",&flash_pe,"flash_pe/D");
350  flash_tree->Branch("flash_centre_y",&flash_centre_y,"flash_centre_y/D");
351  flash_tree->Branch("flash_centre_z",&flash_centre_z,"flash_centre_z/D");
352  flash_tree->Branch("flash_width_y",&flash_width_y,"flash_width_y/D");
353  flash_tree->Branch("flash_width_z",&flash_width_z,"flash_width_z/D");
354  }
355 
356  // Event Tree
357  ev_tree = tfs->make<TTree>("ev_tree","Event information");
358  ev_tree->Branch("total_particle_ctr",&total_particle_ctr,"total_particle_ctr/I");
359  ev_tree->Branch("ev_ctr",&ev_ctr,"ev_ctr/I");
360  ev_tree->Branch("run",&run,"run/I");
361  ev_tree->Branch("event",&event,"event/I");
362  ev_ctr = 0;
363  total_particle_ctr = 0;
364 
365  }
366 
368 
369  event = evt.event();
370  run = evt.run();
371  int track_number = 0;
372  ev_ctr++;
373 
374  // Load detector clocks for later
375  auto const clockData = art::ServiceHandle<detinfo::DetectorClocksService>()->DataFor(evt);
376 
377  double TPC_trigger_offset = 0.0;
378 
379  std::vector<std::vector<TLorentzVector>> mcpart_list;
380 
381  std::cout << "Event number: " << ev_ctr << std::endl;
382  if(fDebug) std::cout << "Set event number: " << event << "\nTop: " << det_top
383  << "\nBottom: " << det_bottom << "\nFront: " << det_front << "\nBack: " << det_back
384  << "\nEdge width: " << fEdgeWidth << std::endl;
385 
386  op_times.clear();
387  flash_id_v.clear();
388  flash_h.clear();
389 
390  op_id_v.clear();
391  op_hit_h.clear();
392 
393  // load Flashes
394  if (fDebug) std::cout << "Loading flash from producer " << fFlashProducer << std::endl;
395 
396  if(fAnode||fAllFlash){
397  flash_h = evt.getHandle<std::vector<recob::OpFlash> >(fFlashProducer);
398 
399  // make sure flashes look good
400  if(!flash_h) {
401  std::cerr<<"\033[93m[ERROR]\033[00m ... could not locate Flash!"<<std::endl;
402  throw std::exception();
403  }
404  }
405 
406  if(fUseOpHits) op_hit_h = evt.getHandle<std::vector<recob::OpHit> >(fOpHitProducer);
407 
408 
409  double trigger_time = 0;
410 
411  if(!fUseMC){
412  auto trigger_h = evt.getHandle<std::vector<recob::OpFlash> >(fTriggerProducer);
413 
414  if( !trigger_h || trigger_h->empty()) {
415  if(fDebug) std::cout << "\tTrigger not found. Skipping." << std::endl;
416  return;
417  }
418 
419  if(fDebug) std::cout << "Loading trigger time from producer "
421 
422  trigger_time = trigger_h->at(0).Time();
423  }
424 
425  // load PFParticles
426 
427  auto reco_particles_h = evt.getValidHandle<std::vector<recob::PFParticle>>(fPFPProducer);
428 
429  if(!reco_particles_h.isValid()) {
430  std::cerr<<"\033[93m[ERROR]\033[00m ... could not locate PFParticles!"<<std::endl;
431  throw std::exception();
432  }
433 
434  // Utilities for PFParticles and tracks
438 
439  // load MCParticles
440 
441  auto mcpart_h = evt.getHandle<std::vector<simb::MCParticle> >("largeant");
442 
443  // if we should use MCParticle
444  if (fUseMC){
445  // make sure particles exist
446  if(!mcpart_h.isValid()) {
447  std::cerr<<"\033[93m[ERROR]\033[00m ... could not locate MCParticle!"<<std::endl;
448  throw std::exception();
449  }
450 
451  // ^ if use MCParticle
452  }
453 
454  // Get trigger to TPC Offset
455  TPC_trigger_offset = clockData.TriggerOffsetTPC();
456  if(fDebug) std::cout << "TPC time offset from trigger: "
457  << TPC_trigger_offset << " us" << std::endl;
458 
459  // Prepare a vector of optical flash times, if flash above some PE cut value
460 
461  if((fAnode||fAllFlash)&&!fUseOpHits) {
462  size_t flash_ctr = 0;
463  for (auto const& flash : *flash_h){
464  if (flash.TotalPE() > fMinPE){
465  double op_flash_time = flash.Time() - trigger_time;
466  if(fUseMC) op_flash_time = op_flash_time - TPC_trigger_offset;
467  op_times.push_back(op_flash_time);
468  flash_id_v.push_back(flash_ctr);
469  //if (fDebug) std::cout << "\t Flash: " << flash_ctr
470  //<< " has time : " << flash.Time() - trigger_time
471  //<< ", PE : " << flash.TotalPE() << std::endl;
472  }
473  flash_ctr++;
474  } // for all flashes
475 
476  if(!fAnode) {
477  auto const& output_flash = FlashMatch(0.0,op_times);
478  if (fDebug) std::cout << "Output all flashes - closest flash to trigger time is: "
479  << output_flash << std::endl; }
480 
481  if(fDebug) std::cout << "Selected a total of " << op_times.size() << " OpFlashes/OpHits" << std::endl;
482  }
483 
484  if(fUseOpHits) {
485  size_t op_ctr = 0;
486  for (auto const& op_hit : *op_hit_h){
487  int op_hit_channel = op_hit.OpChannel();
488  if(op_hit_channel>=fFirstOpChannel&&op_hit_channel<=fLastOpChannel) {
489  double op_hit_time = op_hit.PeakTime() - trigger_time;
490  //if(fUseMC) op_hit_time = op_hit_time - TPC_trigger_offset;
491  op_times.push_back(op_hit_time);
492  op_id_v.push_back(op_ctr);
493  //if(fDebug) std::cout << "OpHit channel: " << op_hit_channel << std::endl;
494  }
495  op_ctr++;
496  }
497  }
498 
499  // LOOP THROUGH RECONSTRUCTED PFPARTICLES
500 
501  size_t ev_particle_ctr = 0;
502 
503  for(unsigned int p = 0; p < reco_particles_h->size(); ++p){
504 
505  recob::PFParticle particle = (*reco_particles_h)[p];
506 
507  // Only consider primary particles
508  if(!particle.IsPrimary()) continue;
509 
510  ev_particle_ctr++;
512 
513  const recob::Track* track = pfpUtil.GetPFParticleTrack(particle,evt,fPFPProducer,fTrackProducer);
514  if(track == 0x0) {
515  if(fDebug) std::cout << "\tPFParticle " << ev_particle_ctr << " is not track like" << std::endl;
516  continue; }
517 
518  if (fDebug) std::cout << "\tLooping through reco PFParticle " << ev_particle_ctr << std::endl;
519 
520  const std::vector<const recob::Hit*>& hit_v = trackUtil.GetRecoTrackHits(*track,evt,fTrackProducer);
521 
525  dt_anode_cathode = -999.;
526 
527  length = 0.;
528  rc_xs = fReadoutWindow/10.;
529  rc_xe = -fReadoutWindow/10.;
530  rc_xs_corr = 399.;
531  rc_xe_corr = -399.;
532  rc_ys = -99.;
533  rc_ye = -99.;
534  rc_zs = -99.;
535  rc_ze = -99.;
536 
540  matched_flash_pe = 0.;
541  matched_flash_centre_y = -99.;
542  matched_flash_centre_z = -99.;
543  matched_flash_width_y = -99.;
544  matched_flash_width_z = -99.;
548 
549  dt_flash_reco = 999;
550 
552 
553  anode_piercing_candidate = false;
554  cathode_crossing_track = false;
555  sister_track = 0;
556 
557  // Get sorted points for the track object [assuming downwards going]
558  std::vector<TVector3> sorted_trk;
559  SortTrackPoints(*track,sorted_trk);
560 
561  TVector3 track_start = sorted_trk.at(0);
562  TVector3 track_end = sorted_trk.at(sorted_trk.size() - 1);
563 
564  if(fDebug) std::cout << "\t\tTrack goes from (" << track_start.X() << ", "
565  << track_start.Y() << ", " << track_start.Z() << ") --> (" <<
566  track_end.X() << ", " << track_end.Y() << ", " << track_end.Z() <<
567  ")" << std::endl;
568 
569  if(sqrt(pow(track_start.X() - track_end.X(),2.0)
570  + pow(track_start.Y() - track_end.Y(),2.0)
571  + pow(track_start.Z() - track_end.Z(),2.0)) < fMinTrackLength ) {
572  if(fDebug) std::cout << "\t\t\tParticle track too short. Skipping." << std::endl;
573  continue;
574  }
575 
576  // Determine if the track crosses the cathode
577  auto const* geom = lar::providerFrom<geo::Geometry>();
578  auto const* hit = hit_v.at(0);
579  const geo::WireID wireID = hit->WireID();
580  const auto TPCGeoObject = geom->TPC(wireID.TPC,wireID.Cryostat);
581  short int driftDir_start = TPCGeoObject.DetectDriftDirection();
582  short int driftDir_end = 0;
583 
584  for (size_t ii = 1; ii < hit_v.size(); ii++) {
585  const geo::WireID wireID2 = hit_v.at(ii)->WireID();
586  const auto TPCGeoObject2 = geom->TPC(wireID2.TPC,wireID2.Cryostat);
587  driftDir_end = TPCGeoObject2.DetectDriftDirection();
588 
589  if(driftDir_end + driftDir_start == 0){
590  cathode_crossing_track = true;
591  ii = hit_v.size();
592  }
593  }
594 
595  const simb::MCParticle* mc_particle = 0x0;
596  int last_mc_point = 0;
597 
598  // if we should use MC info -> continue w/ MC validation
599  if (fUseMC){
600 
601  mc_particle = truthUtil.GetMCParticleFromRecoTrack(clockData, *track,evt,fTrackProducer);
602 
603  if(mc_particle==0x0) {
604  if(fDebug) std::cout << "\t\t\tNo MC particle matched to PFParticle "
605  << ev_particle_ctr << std::endl;
606  continue;
607  }
608 
609  mc_particle_ts = mc_particle->T(0);
610 
611  last_mc_point = mc_particle->NumberTrajectoryPoints()-1;
612  mc_particle_te = mc_particle->T(last_mc_point)/1000;
613 
614  mc_time = clockData.G4ToElecTime(mc_particle_ts) + TPC_trigger_offset;
615 
616  if(fDebug&&fabs(mc_particle_te - mc_particle_ts)>1) std::cout <<
617  "\t\t\tMC Particle end time: " << mc_particle_te <<
618  " us is significantly different from start time: " << mc_time <<
619  " us" << std::endl;
620  }
621 
622  // -------------------------------------------------------------------------------
623  // CATHODE CROSSERS
624 
625  if(fCathode){
626 
628  //GET T0 FROM PFPARTICLE
629  auto t0_v = pfpUtil.GetPFParticleT0(particle,evt,fPFPProducer);
630  if(t0_v.size() == 0) continue;
631  auto t0 = t0_v.at(0);
632  cathode_rc_time = t0.Time()/1000;
633 
634  if (fDebug) std::cout << "\t\tTrack crossers cathode - PFParticle has t0: "
635  << cathode_rc_time << " against MC particle t0: " << mc_time << std::endl;
636 
638 
639  std::vector<TVector3> split_trk = sorted_trk;
640 
641  SplitTrack(*track,split_trk);
642  std::vector<TVector3> top_trk = {split_trk.at(0), split_trk.at(1)};
643  std::vector<TVector3> bottom_trk = {split_trk.at(2), split_trk.at(3)};
644 
645  if(fDebug) std::cout << "\t\tCathode-crossing point: ("
646  << top_trk.at(1).X() << ", " << top_trk.at(1).Y() << ", "
647  << top_trk.at(1).Z() << ") --> (" << bottom_trk.at(0).X()
648  << ", " << bottom_trk.at(0).Y() << ", " << bottom_trk.at(0).Z()
649  << ")" << std::endl;
650 
651  // Top Track
652  //if(fDebug) std::cout << "\tTop track" << std::endl;
653 
654  sister_track = track_number + 1;
655  TVector3 top_track_start = top_trk.at(0);
656  TVector3 top_track_end = top_trk.at(1);
657 
658  rc_xs = top_track_start.X();
659  rc_xs_corr = rc_xs;
660  rc_ys = top_track_start.Y();
661  rc_zs = top_track_start.Z();
662  rc_xe = top_track_end.X();
663  rc_xe_corr = rc_xe;
664  rc_ye = top_track_end.Y();
665  rc_ze = top_track_end.Z();
666 
667  length = sqrt(pow(rc_xs - rc_xe,2.0) + pow(rc_ys - rc_ye,2.0) +
668  pow(rc_zs - rc_ze,2.0));
669 
670  track_tree->Fill();
671  track_number++;
672 
673  // Bottom Track
674  //if(fDebug) std::cout << "\tBottom track" << std::endl;
675  sister_track = track_number - 1;
676 
677  TVector3 bottom_track_start = bottom_trk.at(0);
678  TVector3 bottom_track_end = bottom_trk.at(1);
679 
680  rc_xs = bottom_track_start.X();
681  rc_xs_corr = rc_xs;
682  rc_ys = bottom_track_start.Y();
683  rc_zs = bottom_track_start.Z();
684  rc_xe = bottom_track_end.X();
685  rc_xe_corr = rc_xe;
686  rc_ye = bottom_track_end.Y();
687  rc_ze = bottom_track_end.Z();
688 
689  length = sqrt(pow(rc_xs - rc_xe,2.0) + pow(rc_ys - rc_ye,2.0) +
690  pow(rc_zs - rc_ze,2.0));
691 
692  track_tree->Fill();
693  track_number++;
694  }
695 
696  else if(fDebug) std::cout << "\t\tTrack does not cross cathode."<< std::endl;
697  }
698 
699  // ------------------------------------------------------------------------------------
700  // ANODE PIERCERS
701  if(fAnode){
702  // if(fDebug) std::cout << "\t\tThis track starts in TPC " << wireID.TPC <<
703  //" which has a drift direction of " << driftDir_start << std::endl;
704 
705  // create root trees variables
706 
707  rc_xs = track_start.X();
708  rc_ys = track_start.Y();
709  rc_zs = track_start.Z();
710  rc_xe = track_end.X();
711  rc_ye = track_end.Y();
712  rc_ze = track_end.Z();
713  length = track->Length();
714 
715  double x_shift = 0;
717  x_shift = cathode_rc_time*driftDir_start*fDriftVelocity;
718  }
719 
720  // Determine if track hits edge of readout window
721  // NECESSARY TO REMOVE TRACKS THAT AREN'T FINISHED WHEN WINDOW CLOSES
722  // AS WELL AS TRACKS THAT WERE BEING COLLECTED BEFORE THE WINDOW OPENED
723 
724  readout_edge = false;
725  for (auto& hits : hit_v) {
726  auto hit_tick = hits->PeakTime();
727  double hit_time = clockData.TPCTick2TrigTime(hit_tick);
728  //if(fDebug) std::cout << "\t\tHit from track " << trk_ctr <<
729  //" at tick: " << hit_tick << ", in TPC "
730  //<< hits->WireID().TPC << ", plane " << hits->WireID().Plane
731  //<< " and wire " << hits->WireID().Wire << std::endl;
732  if(hit_tick < fReadoutEdgeTicks || hit_tick > (fReadoutWindow - fReadoutEdgeTicks)){
733  readout_edge = true;
734  if(fDebug) std::cout << "\tTrack hits edge of readout window. "
735  "Skipping." << std::endl;
736  continue;
737  }
738  // If track within window, get reco time from earliest hit time
739  if (hit_time < anode_rc_time) anode_rc_time = hit_time;
740  }
741 
742  if(readout_edge) continue;
743 
744  TPC_entering_candidate = false;
745  TPC_exiting_candidate = false;
746 
747  // Tracks which may enter TPC through an APA
748  if (rc_ys < (det_top - fEdgeWidth) && rc_zs > (det_front + fEdgeWidth)
749  && rc_zs < (det_back - fEdgeWidth)) {
750 
751  // reconstruct track T0 w.r.t. trigger time
752  if( ( rc_xs > rc_xe && driftDir_start>0 ) ||
753  ( rc_xs < rc_xe && driftDir_start<0 ) ) {
754  TPC_entering_candidate = true;
755  if(fDebug) std::cout << "\t\tTrack may enter TPC through "
756  "anode. Reco t0: " << anode_rc_time << " us" << std::endl;
757  }
758  }
759 
760  // Tracks which may exit TPC through an APA
762  && rc_ze < (det_back - fEdgeWidth)) {
763 
764  // reconstruct track T0 w.r.t. trigger time
765  if( ( rc_xe > rc_xs && driftDir_end>0 ) ||
766  ( rc_xe < rc_xs && driftDir_end<0 ) ) {
767  TPC_exiting_candidate = true;
768  if(fDebug) std::cout << "\t\tTrack may exit TPC through "
769  "anode. Reco t0:" << anode_rc_time << " us" << std::endl;
770  }
771  }
772 
773 
776 
778  if(fDebug) std::cout << "\t\tTrack does not pierce anode." << std::endl;
779  continue;
780  }
781 
783  if(fDebug) std::cout << "\t\tTrack neither enters nor exits"
784  " through non-anode TPC face. No useful end point for SCE"
785  " measurement." << std::endl;
786  continue;
787  }
788 
789  rc_xs_corr = rc_xs - x_shift + driftDir_start*anode_rc_time*fDriftVelocity;
790  rc_xe_corr = rc_xe + x_shift + driftDir_end*anode_rc_time*fDriftVelocity;
791 
792  // FLASH MATCHING
793  size_t op_match_result = FlashMatch(anode_rc_time,op_times);
794 
795  if(op_match_result==99999) {
796  if(fDebug) std::cout << "Unable to match flash to track." << std::endl;
797  continue;
798  }
799 
800  if(!fUseOpHits) {
801  const art::Ptr<recob::OpFlash> flash_ptr(flash_h, op_match_result);
802 
803  matched_flash_time = flash_ptr->Time() - trigger_time;
805  if(fUseMC) corrected_matched_flash_time = fFlashScaleFactor*matched_flash_time + fFlashTPCOffset - TPC_trigger_offset;
806  matched_flash_time_width = flash_ptr->TimeWidth();
807 
809 
810  matched_flash_pe = flash_ptr->TotalPE();
811  matched_flash_centre_y = flash_ptr->YCenter();
812  matched_flash_centre_z = flash_ptr->ZCenter();
813  matched_flash_width_y = flash_ptr->YWidth();
814  matched_flash_width_z = flash_ptr->ZWidth();
815 
816  unsigned int max_pe_channel = 9999;
817  double max_pe = 0;
818  unsigned int pd_ch;
819  for(pd_ch = 0; pd_ch <= geom->MaxOpChannel(); pd_ch++) {
820  double channel_i_pe = flash_ptr->PE(pd_ch);
821  if(channel_i_pe > max_pe) {
822  max_pe = channel_i_pe;
823  max_pe_channel = pd_ch;
824  }
825  }
826 
827  if(max_pe_channel==9999||max_pe==0) continue;
828 
829  if(max_pe_channel<9999) {
830 
832 
833  if(max_pe_channel>143) matched_flash_max_pe_det_x = det_width;
834 
835  /*double max_pe_det_v[3];
836  geom->OpDetGeoFromOpChannel(max_pe_channel).GetCenter(max_pe_det_v);
837 
838  matched_flash_max_pe_det_x = max_pe_det_v[0];
839  matched_flash_max_pe_det_y = max_pe_det_v[1];
840  matched_flash_max_pe_det_z = max_pe_det_v[2];
841  */
842 
843  if(fDebug) std::cout << "\t\tOpChannel " << max_pe_channel <<
844  " has maximum PE, and is located at: (" <<
845  matched_flash_max_pe_det_x << ", " <<
846  matched_flash_max_pe_det_y << ", " <<
848  }
849 
850  if(fDebug) std::cout << "\t\t Matched to flash w/ index " << op_match_result << " w/ PE "
851  << matched_flash_pe << ", corrected time " << corrected_matched_flash_time <<
852  " us vs corrected reco time " << anode_rc_time << " us" << std::endl;
853  }
854 
855  if(fUseOpHits) {
856  const art::Ptr<recob::OpHit> op_ptr(op_hit_h, op_match_result);
857 
859 
860  if(fUseMC) matched_flash_time = matched_flash_time - TPC_trigger_offset;
861 
862 
863  if(fDebug) std::cout << "\t\t Matched to op hit w/ index " << op_match_result <<
864  " w/ time " << matched_flash_time << " us vs corrected reco time "
865  << anode_rc_time << " us" << std::endl;
866 
868 
869  }
870 
871  dt_mc_reco = 999.;
872  true_anode_piercer = false;
873 
875  mc_particle_y_anode = -99;
876  mc_particle_z_anode = -99;
877 
878  // if we should use MC info -> continue w/ MC validation
879  if (fUseMC){
880 
881  for(int mc_hit_i=0; mc_hit_i<last_mc_point; mc_hit_i++) {
882 
883  double mc_particle_xi = mc_particle->Position(mc_hit_i).X();
884  double mc_particle_yi = mc_particle->Position(mc_hit_i).Y();
885  double mc_particle_zi = mc_particle->Position(mc_hit_i).Z();
886 
887  if(abs(mc_particle_xi) > (det_width - 1) &&
888  abs(mc_particle_xi) < (det_width + 1) &&
889  mc_particle_yi > det_bottom && mc_particle_yi < det_top &&
890  mc_particle_zi > det_front && mc_particle_zi < det_back)
891  true_anode_piercer = true;
892 
893  if(abs(abs(mc_particle_xi) - det_width) <
895  mc_particle_x_anode = mc_particle_xi;
896  mc_particle_y_anode = mc_particle_yi;
897  mc_particle_z_anode = mc_particle_zi;
898  }
899  }
900 
902  std::cout << "\t\tMC Particle matched to track has t0: "
903  << mc_time << " us against reconstructed t0: "
904  << anode_rc_time << " us and passes through anode at: ("
905  << mc_particle_x_anode << ", " << mc_particle_y_anode << ", "
906  << mc_particle_z_anode << ")" << std::endl;
907 
908  } // ^ if we should use MCParticles
909 
910  // For verifying anode piercer T0 assigned by producer module
911 
912  if(fAnodeT0Check) {
913  bool HasT0 = false;
914 
915  unsigned int pIndex = particle.Self();
916 
917  std::vector<anab::T0> t0_apt_v;
918 
919  const art::FindManyP<anab::T0> findParticleT0s(reco_particles_h,evt,fAnodeT0Producer);
920 
921  for(unsigned int p = 0; p < findParticleT0s.at(pIndex).size(); ++p){
922  t0_apt_v.push_back((*(findParticleT0s.at(pIndex)[p])));
923  }
924 
925  if(t0_apt_v.size() != 0) HasT0 = true;
926 
927  if(HasT0) {
928  auto t0_apt = t0_apt_v.at(0);
929 
930  std::cout << "PFParticle has T0: " << (t0_apt.Time()/1000) <<
931  " us against anode reco time: " << anode_rc_time <<
932  " us with dt_flash_reco " << dt_flash_reco << " us." << std::endl;
933  }
934  }
935 
937 
938  if (fUseMC) dt_mc_reco = mc_time - rc_time;
939 
940  if(anode_rc_time < fReadoutWindow && cathode_rc_time > -fReadoutWindow)
942 
943  track_tree->Fill();
944  track_number++;
945 
946  }
947 
948  }
949 
950  ev_tree->Fill();
951  }
952 
953 void T0RecoSCE::SortTrackPoints(const recob::Track& track, std::vector<TVector3>& sorted_trk)
954 {
955  sorted_trk.clear();
956 
957  TVector3 track_start, track_end;
958  double start_y = det_bottom - fEdgeWidth;
959  double end_y = det_top + fEdgeWidth;
960 
961  for (size_t ii = 0; ii < track.NumberTrajectoryPoints(); ii++){
962  auto const& trk_loc = track.LocationAtPoint(ii);
963 
964  if ((trk_loc.X() < -998.)||(trk_loc.Y() < -998.)||(trk_loc.Z() < -998)) continue;
965 
966  if (trk_loc.Y() < end_y){
967  end_y = trk_loc.Y();
968  track_end = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
969  }
970  if (trk_loc.Y() > start_y){
971  start_y = trk_loc.Y();
972  track_start = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
973  }
974  }
975 
976  sorted_trk.push_back(track_start);
977  sorted_trk.push_back(track_end);
978 }
979 
980 void T0RecoSCE::SplitTrack(const recob::Track& track, std::vector<TVector3>& split_trk)
981 {
982  split_trk.clear();
983 
984  TVector3 track_neg, track_neg_c, track_pos_c,track_pos;
985  double neg_x = 0.0;
986  double pos_x = 0.0;
987  double neg_c = -2.0*fEdgeWidth;
988  double pos_c = 2.0*fEdgeWidth;
989 
990  for (size_t ii = 0; ii < track.NumberTrajectoryPoints(); ii++){
991  auto const& trk_loc = track.LocationAtPoint(ii);
992 
993  if ((trk_loc.X() < -998.)||(trk_loc.Y() < -998.)||(trk_loc.Z() < -998)) continue;
994 
995  if (trk_loc.X() < neg_x){
996  neg_x = trk_loc.X();
997  track_neg = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
998  }
999  if (trk_loc.X() > pos_x){
1000  pos_x = trk_loc.X();
1001  track_pos = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
1002  }
1003  if ((trk_loc.X() < 0.0) && (trk_loc.X() > neg_c)){
1004  neg_c = trk_loc.X();
1005  track_neg_c = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
1006  }
1007  if ((trk_loc.X() > 0.0) && (trk_loc.X() < pos_c)){
1008  pos_c = trk_loc.X();
1009  track_pos_c = {trk_loc.X(), trk_loc.Y(), trk_loc.Z()};
1010  }
1011  }
1012 
1013  if( track_neg.Y() > track_pos.Y()){
1014  split_trk.push_back(track_neg);
1015  split_trk.push_back(track_neg_c);
1016  split_trk.push_back(track_pos_c);
1017  split_trk.push_back(track_pos);
1018  } else {
1019  split_trk.push_back(track_pos);
1020  split_trk.push_back(track_pos_c);
1021  split_trk.push_back(track_neg_c);
1022  split_trk.push_back(track_neg);
1023  }
1024 
1025 }
1026 
1027 size_t T0RecoSCE::FlashMatch(const double reco_time, std::vector<double> op_times_v)
1028 {
1029  // loop through all reco'd flash times and see if one matches
1030  // the time from the track/particle
1031  double dt_min = 9999999.;
1032  size_t matched_op_id = 99999;
1033 
1036 
1037  flash_pe = -9;
1038  flash_centre_y = -9;
1039  flash_centre_z = -9;
1040  flash_width_y = -9;
1041  flash_width_z = -9;
1042  flash_time_width = -9;
1043 
1044  for (size_t i=0; i < op_times_v.size(); i++){
1045  double op_time_i = op_times_v[i];
1046  double corrected_op_time_i = op_time_i*fFlashScaleFactor + fFlashTPCOffset;
1047  flash_reco_time_diff = corrected_op_time_i - reco_time;
1048  if (fabs(flash_reco_time_diff) < dt_min){
1049  dt_min = fabs(flash_reco_time_diff);
1050  if(!fUseOpHits) matched_op_id = flash_id_v[i];
1051  if(fUseOpHits) matched_op_id = op_id_v[i];
1052  }
1053 
1054  if (fAllFlash) {
1055  const art::Ptr<recob::OpFlash> flash_i_ptr(flash_h, flash_id_v[i]);
1056  flash_time = op_time_i;
1057  corrected_flash_time = corrected_op_time_i;
1058  flash_pe = flash_i_ptr->TotalPE();
1059  flash_centre_y = flash_i_ptr->YCenter();
1060  flash_centre_z = flash_i_ptr->ZCenter();
1061  flash_width_y = flash_i_ptr->YWidth();
1062  flash_width_z = flash_i_ptr->ZWidth();
1063  flash_time_width = flash_i_ptr->TimeWidth();
1064  flash_tree->Fill();
1065  }
1066  }
1067  return matched_op_id;
1068  }
1069 
code to link reconstructed objects back to the MC truth information
double matched_flash_max_pe_det_y
unsigned int NumberTrajectoryPoints() const
Definition: MCParticle.h:218
const TLorentzVector & Position(const int i=0) const
Definition: MCParticle.h:219
EventNumber_t event() const
Definition: DataViewImpl.cc:85
bool TPC_entering_candidate
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.
double matched_flash_width_y
double mc_particle_ts
size_t Self() const
Returns the index of this particle.
Definition: PFParticle.h:92
double TimeWidth() const
Definition: OpFlash.h:107
double matched_flash_max_pe_det_x
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
std::vector< size_t > op_id_v
std::string string
Definition: nybbler.cc:12
double matched_flash_max_pe_det_z
art::Handle< std::vector< recob::OpHit > > op_hit_h
double corrected_flash_time
double mc_particle_z_anode
Point_t const & LocationAtPoint(size_t i) const
Definition: Track.h:126
constexpr T pow(T x)
Definition: pow.h:72
double mc_particle_te
Geometry information for a single TPC.
Definition: TPCGeo.h:38
double anode_rc_time
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:102
unsigned int fReadoutWindow
void SortTrackPoints(const recob::Track &track, std::vector< TVector3 > &sorted_trk)
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
double PeakTime() const
Definition: OpHit.h:64
double matched_flash_time_width
double flash_centre_y
std::string fAnodeT0Producer
std::string fPFPProducer
double PE(unsigned int i) const
Definition: OpFlash.h:110
double flash_width_y
double HalfLength() const
Length is associated with z coordinate [cm].
Definition: TPCGeo.h:117
EDAnalyzer(fhicl::ParameterSet const &pset)
Definition: EDAnalyzer.h:25
Particle class.
bool cathode_crossing_track
std::vector< size_t > flash_id_v
std::vector< double > op_times
double flash_time_width
double cathode_rc_time
art framework interface to geometry description
double flash_centre_z
std::string fTriggerProducer
double ZCenter() const
Definition: OpFlash.h:117
double fDriftVelocity
timescale_traits< TriggerTimeCategory >::time_point_t trigger_time
A point in time on the trigger time scale.
double dt_flash_reco
T abs(T value)
void analyze(art::Event const &evt) override
double Time() const
Definition: OpFlash.h:106
double Length(size_t p=0) const
Access to various track properties.
Definition: Track.h:167
double fEdgeWidth
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:67
double flash_reco_time_diff
TTree * flash_tree
T get(std::string const &key) const
Definition: ParameterSet.h:271
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.
double flash_width_z
bool true_anode_piercer
double T(const int i=0) const
Definition: MCParticle.h:224
std::string fHitProducer
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
double mc_particle_x_anode
p
Definition: test.py:223
T0RecoSCE & operator=(T0RecoSCE const &)=delete
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
RunNumber_t run() const
Definition: DataViewImpl.cc:71
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
Class def header for mctrack data container.
bool anode_piercing_candidate
bool TPC_exiting_candidate
double matched_flash_centre_y
double corrected_matched_flash_time
std::string fFlashProducer
Detector simulation of raw signals on wires.
double fMinTrackLength
double fFlashScaleFactor
double mc_particle_y_anode
double HalfHeight() const
Height is associated with y coordinate [cm].
Definition: TPCGeo.h:111
TTree * track_tree
double dt_anode_cathode
double YWidth() const
Definition: OpFlash.h:116
const std::vector< const recob::Hit * > GetRecoTrackHits(const recob::Track &track, art::Event const &evt, const std::string trackModule) const
Get the hits from a given reco track.
Declaration of signal hit object.
double DriftDistance() const
Definition: TPCGeo.h:155
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
art::Handle< std::vector< recob::OpFlash > > flash_h
void beginJob() override
void clear()
Definition: Handle.h:236
std::string fTrackProducer
T0RecoSCE(fhicl::ParameterSet const &p)
def center(depos, point)
Definition: depos.py:117
std::string fOpHitProducer
Provides recob::Track data product.
size_t FlashMatch(const double reco_time, std::vector< double > op_times_v)
double matched_flash_width_z
constexpr WireID()=default
Default constructor: an invalid TPC ID.
double fFlashTPCOffset
double TotalPE() const
Definition: OpFlash.cxx:68
TCEvent evt
Definition: DataStructs.cxx:7
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
double matched_flash_time
double YCenter() const
Definition: OpFlash.h:115
double matched_flash_centre_z
double matched_flash_pe
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
Definition: TPCGeo.h:563
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
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
void SplitTrack(const recob::Track &track, std::vector< TVector3 > &sorted_trk)
QTextStream & endl(QTextStream &s)
double ZWidth() const
Definition: OpFlash.h:118
Event finding and building.