All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TimeTrackTreeStorage_module.cc
Go to the documentation of this file.
1 /**
2  * @file TimeTrackTreeStorage_module.cc
3  * @authors Jacob Zettlemoyer (FNAL, jzettle@fnal.gov),
4  * Animesh Chatterjee (U. Pittsburgh, anc238@pitt.edu),
5  * Gianluca Petrillo (SLAC, petrillo@slac.stanford.edu)
6  * @date Tue Sep 21 10:33:10 2021
7  *
8  * Borrowed heavily from Gray Putnam's existing TrackCaloSkimmer
9  */
10 
11 // ICARUS libraries
18 
19 // LArSoft libraries
20 // #include "lardata/DetectorInfoServices/DetectorClocksService.h"
22 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
33 // #include "lardataobj/RecoBase/SpacePoint.h"
35 // #include "lardataobj/RecoBase/PFParticleMetadata.h"
36 #include "lardataobj/RawData/OpDetWaveform.h" // raw::Channel_t
38 #include "lardataobj/RawData/TriggerData.h" // raw::Trigger
39 
40 // framework libraries
41 #include "art_root_io/TFileService.h"
42 #include "art/Framework/Core/EDAnalyzer.h"
43 #include "art/Framework/Core/ModuleMacros.h"
44 #include "art/Framework/Principal/Event.h"
45 #include "art/Framework/Principal/Handle.h"
46 #include "art/Framework/Principal/Run.h"
47 #include "canvas/Persistency/Common/FindOneP.h"
48 #include "canvas/Persistency/Common/FindManyP.h"
49 #include "canvas/Persistency/Common/Assns.h"
50 #include "canvas/Persistency/Common/Ptr.h"
51 #include "canvas/Utilities/InputTag.h"
52 #include "fhiclcpp/types/TableAs.h"
53 #include "fhiclcpp/types/Sequence.h"
54 #include "fhiclcpp/types/Atom.h"
55 #include "fhiclcpp/types/OptionalAtom.h"
56 #include "messagefacility/MessageLogger/MessageLogger.h"
57 
58 // ROOT libraries
59 #include "TTree.h"
60 
61 // C/C++ libraries
62 #include <vector>
63 #include <string>
64 #include <utility> // std::move(), std::pair
65 #include <cmath>
66 
67 
68 namespace {
69 
70  // ---------------------------------------------------------------------------
71  /// Returns the sequence of `track` valid points (as geometry points).
72  std::vector<geo::Point_t> extractTrajectory
73  (recob::Track const& track, bool reverse = false)
74  {
75  std::vector<geo::Point_t> trackPath;
76  std::size_t index = track.FirstValidPoint();
77  while (index != recob::TrackTrajectory::InvalidIndex) {
78  trackPath.push_back(track.LocationAtPoint(index));
79  if (++index >= track.NPoints()) break;
80  index = track.NextValidPoint(index);
81  }
82  if (reverse) std::reverse(trackPath.begin(), trackPath.end());
83  return trackPath;
84  } // extractTrajectory()
85 
86 } // local namespace
87 
88 
89 // -----------------------------------------------------------------------------
90 namespace sbn { class TimeTrackTreeStorage; }
91 /**
92  * @brief Fills a ROOT tree with track-based triggering information.
93  *
94  *
95  * Track selection criteria
96  * =========================
97  *
98  * This module does not perform almost any selection: it processes all the
99  * reconstructed particle flow objects (PFO) (typically from Pandora) selected
100  * by the module in `T0selProducer`, which may perform the desired selection.
101  * For every PFO which is associated to a track (`recob::Track`), that
102  * associated track and the associated time (`anab::T0`) are saved in a tree
103  * entry.
104  *
105  *
106  * Optical detector information
107  * -----------------------------
108  *
109  * Currently, _all_ reconstructed flashes in the cryostat are saved together
110  * with _each_ tree entry, i.e. to each selected track. There is no attempt to
111  * match a single flash to a track.
112  *
113  *
114  *
115  * Trigger information
116  * ====================
117  *
118  * There are two distinct groups of information about triggers in the tree.
119  * The first one is the hardware trigger, that is the trigger that was actually
120  * used to decide to record the event. That is the same information for all
121  * tracks within the same event (and the same in both cryostats, too).
122  * The other group of information is from trigger logic simulation on the
123  * collected data (optical detector waveforms): there may be multiple branches
124  * in this group, one for each simulated trigger logic, and each tree entry,
125  * corresponding to a selected track, may have its own value for each trigger
126  * logic response.
127  *
128  *
129  * Simulated trigger information
130  * ------------------------------
131  *
132  * A branch is added for each configured trigger logic.
133  * This module actually ignores the details of the logic yielding the results:
134  * a trigger result is a group of data products under the same tag.
135  * For example, a tag `M1` (presumably, a very loose trigger logic requiring
136  * just one PMT pair above threshold anywhere in the detector, with no hint of
137  * which that threshold is) will produce a branch with name `"M1"` including
138  * information from the `M1` data products (so far, only a collection of
139  * `raw::Trigger` is read).
140  * It is assumed that there is one trigger result for each selected track
141  * (as found in the data product from `T0selProducer` configuration parameter).
142  * Note that a trigger object is expected to be present _regardless whether
143  * the trigger fired or not_. It is assumed that the trigger fired if at least
144  * one of the `raw::Trigger::TriggerBits()` is set, not fired otherwise.
145  *
146  * Each branch mirrors a data record, `TriggerInfo_t`, reporting the response
147  * for one simulated trigger logic.
148  * The structure and interpretation of the trigger response branch is described
149  * in ROOT TTree code by the string in
150  * `TriggerInfo_t::TriggerResponseBranchStructure`, and its meaning is:
151  * * `fired` (boolean): whether this trigger has triggered at all during the
152  * considered trigger gate.
153  * * `time` (double): time of the trigger, taken directly from
154  * `raw::Trigger::TriggerTime()`; it is expected to be measurent in
155  * microseconds and relative to the nominal time reference of the event,
156  * which for data is the hardware trigger time and for simulation is the
157  * "hardware" beam gate time (however that is defined).
158  * * `gate` (double): start time of the gate where the trigger logic was
159  * simulated. It is in the same time scale as the trigger time, and
160  * directly taken from `raw::Trigger::BeamGateTime()`.
161  *
162  *
163  */
164 class sbn::TimeTrackTreeStorage : public art::EDAnalyzer {
165 
166  using TriggerInputSpec_t
168 
169 public:
170 
171  /// Data record the trigger response branch is based on.
173 
174  struct Config {
175  using Name = fhicl::Name;
176  using Comment = fhicl::Comment;
177 
178  /// Information on a single trigger source for the tree.
180 
181  fhicl::Atom<std::string> Name {
182  fhicl::Name("Name"),
183  Comment("name of the trigger (e.g. `\"M5O3\"`)")
184  };
185  fhicl::Atom<art::InputTag> TriggerTag {
186  fhicl::Name("TriggerTag"),
187  Comment("tag of the input trigger info data product")
188  };
189 
190  }; // TriggerSpecConfig
192  = fhicl::TableAs<TriggerInputSpec_t, TriggerSpecConfig>;
193 
194 
195  fhicl::Atom<art::InputTag> PFPproducer {
196  Name("PFPproducer"),
197  Comment("tag of the input particle flow objects to process")
198  // mandatory
199  };
200 
201  fhicl::OptionalAtom<art::InputTag> T0Producer {
202  Name("T0Producer"),
203  Comment("tag of the input track time (t0) information [as PFPproducer]")
204  // default: as PFPproducer
205  };
206 
207  fhicl::OptionalAtom<art::InputTag> T0selProducer {
208  Name("T0selProducer"),
209  Comment
210  ("tag of the selected tracks (as a collection of art::Ptr) [as PFPproducer]")
211  // default: as PFPproducer
212  };
213 
214  fhicl::Atom<art::InputTag> TrackProducer {
215  Name("TrackProducer"),
216  Comment("tag of the association of particles to tracks")
217  // mandatory
218  };
219 
220  fhicl::Atom<art::InputTag> TrackFitterProducer {
221  Name("TrackFitterProducer"),
222  Comment("tag of the association of the tracks with the hits")
223  // mandatory
224  };
225 
226  fhicl::Atom<art::InputTag> CaloProducer {
227  Name("CaloProducer"),
228  Comment("tag of the association of the tracks with the calorimetry module")
229  //mandatory
230  };
231 
232 
233  fhicl::Atom<art::InputTag> BeamGateProducer {
234  Name("BeamGateProducer"),
235  Comment("tag of beam gate information")
236  // mandatory
237  };
238 
239  fhicl::Atom<art::InputTag> TriggerProducer {
240  Name("TriggerProducer"),
241  Comment("tag of hardware trigger information")
242  // mandatory
243  };
244 
245  fhicl::Atom<art::InputTag> FlashProducer {
246  Name("FlashProducer"),
247  Comment("tag of flash information")
248  //mandatory
249  };
250 
251  fhicl::Sequence<TriggerSpecConfigTable> EmulatedTriggers {
252  Name("EmulatedTriggers"),
253  Comment("the emulated triggers to include in the tree")
254  };
255 
256  fhicl::Atom<std::string> LogCategory {
257  Name("LogCategory"),
258  Comment("label for output messages of this module instance"),
259  "TimeTrackTreeStorage" // default
260  };
261 
262  fhicl::Atom<float> MODA {
263  Name("MODA"),
264  Comment("first recombination parameter for dE/dx calculations"),
265  0.930 //default
266  };
267 
268  fhicl::Atom<float> MODB {
269  Name("MODB"),
270  Comment("second recombination parameter for dE/dx calculations"),
271  0.212
272  };
273 
274  fhicl::Atom<float> Wion {
275  Name("Wion"),
276  Comment("work function for recombination"),
277  0.0000236016
278  };
279 
280  fhicl::Atom<float> Efield {
281  Name("Efield"),
282  Comment("Electric field in kV/cm"),
283  0.5
284  };
285 
286  fhicl::Atom<bool> ForceDowngoing {
287  Name("ForceDowngoing"),
288  Comment("force all tracks to be downgoing, flipping them when necessary"),
289  false
290  };
291 
292  }; // Config
293 
294  using Parameters = art::EDAnalyzer::Table<Config>;
295 
296  explicit TimeTrackTreeStorage(Parameters const& p);
297 
299  unsigned hkey,
300  const recob::Track &trk,
301  const recob::TrackHitMeta &thm,
302  const std::vector<art::Ptr<anab::Calorimetry>> &calo,
303  const geo::GeometryCore *geo);
304 
305  float dEdx_calc(float dQdx,
306  float A,
307  float B,
308  float Wion,
309  float E);
310 
311  void analyze(art::Event const& e) override;
312 
313  void endJob() override;
314 
315 private:
316 
317 
318  // --- BEGIN -- Configuration parameters -------------------------------------
319 
320  art::InputTag const fPFPproducer;
321  art::InputTag const fT0Producer;
322  art::InputTag const fT0selProducer;
323  art::InputTag const fTrackProducer;
324  art::InputTag const fTrackFitterProducer;
325  art::InputTag const fCaloProducer;
326  art::InputTag const fBeamGateProducer;
327  art::InputTag const fTriggerProducer;
328  art::InputTag const fFlashProducer;
329  std::string const fLogCategory;
330  float const fMODA;
331  float const fMODB;
332  float const fWion;
333  float const fEfield;
334  bool const fForceDowngoing; ///< Whether to force all tracks to be downgoing.
335 
336  // --- END ---- Configuration parameters -------------------------------------
337 
338  // --- BEGIN -- Tree buffers -------------------------------------------------
339 
340  unsigned int fEvent;
341  unsigned int fRun;
342  unsigned int fSubRun;
343 
344  sbn::selTrackInfo fTrackInfo; //change to one entry per track instead of per event
348  std::vector<sbn::selLightInfo> fFlashStore;
350  std::vector<sbn::selHitInfo> fHitStore;
351  // --- END ---- Tree buffers -------------------------------------------------
352 
353  // --- BEGIN -- Cached information -------------------------------------------
354 
355  /// PMT geometry objects, grouped by wall (drift) coordinate.
356  std::vector<std::pair<double, std::vector<raw::Channel_t>>> fPMTwalls;
357 
358  // --- BEGIN -- Cached information -------------------------------------------
359 
360 
361  TTree *fStoreTree = nullptr;
362 
363  unsigned int fTotalProcessed = 0;
364 
365 
366  // `convert()` needs to be a free function
368 
369 
370  // --- BEGIN -- Trigger response branches ------------------------------------
371 
372  /// Manages filling of trigger result branches.
374 
375  // --- END ---- Trigger response branches ------------------------------------
376 
377  /// Accesses detector geometry to return all PMT split by wall.
378  std::vector<std::pair<double, std::vector<raw::Channel_t>>>
379  computePMTwalls() const;
380 
381 }; // sbn::TimeTrackTreeStorage
382 
383 
384 // -----------------------------------------------------------------------------
385 namespace sbn {
386 
389  {
390  return {
391  config.Name() // name
392  , config.TriggerTag() // inputTag
393  };
394  } // convert(sbn::TriggerSpecConfig)
395 
396 } // namespace sbn
397 
398 
399 // -----------------------------------------------------------------------------
401  : EDAnalyzer{p}
402  // configuration
403  , fPFPproducer { p().PFPproducer() }
404  , fT0Producer { p().T0Producer().value_or(fPFPproducer) }
405  , fT0selProducer { p().T0selProducer().value_or(fPFPproducer) }
406  , fTrackProducer { p().TrackProducer() }
407  , fTrackFitterProducer { p().TrackFitterProducer() }
408  , fCaloProducer { p().CaloProducer() }
409  , fBeamGateProducer { p().BeamGateProducer() }
410  , fTriggerProducer { p().TriggerProducer() }
411  , fFlashProducer { p().FlashProducer() }
412  , fLogCategory { p().LogCategory() }
413  , fMODA { p().MODA() }
414  , fMODB { p().MODB() }
415  , fWion { p().Wion() }
416  , fEfield { p().Efield() }
417  , fForceDowngoing { p().ForceDowngoing() }
418  // algorithms
419  , fPMTwalls { computePMTwalls() }
420  , fStoreTree {
421  art::ServiceHandle<art::TFileService>()->make<TTree>
422  ("TimedTrackStorage", "Timed Track Tree")
423  }
424  , fTriggerResponses
425  { p().EmulatedTriggers(), consumesCollector(), *fStoreTree }
426 {
427 
428  //
429  // declaration of input
430  //
431 
432  // consumes<std::vector<recob::PFParticle>>(fPFPproducer); // not yet?
433  consumes<std::vector<art::Ptr<recob::PFParticle>>>(fT0selProducer);
434  consumes<sbn::ExtraTriggerInfo>(fTriggerProducer);
435  consumes<std::vector<sim::BeamGateInfo>>(fBeamGateProducer);
436  consumes<art::Assns<recob::PFParticle, recob::Track>>(fTrackProducer);
437  consumes<art::Assns<recob::PFParticle, anab::T0>>(fT0Producer);
438  consumes<art::Assns<recob::Hit, recob::Track, recob::TrackHitMeta>>(fTrackProducer);
439  consumes<recob::OpFlash>(fFlashProducer);
440 
441  //
442  // tree population
443  //
444  fStoreTree->Branch("run", &fRun);
445  fStoreTree->Branch("subrun", &fSubRun);
446  fStoreTree->Branch("event", &fEvent);
447  fStoreTree->Branch("beamInfo", &fBeamInfo);
448  fStoreTree->Branch("triggerInfo", &fTriggerInfo);
449  fStoreTree->Branch("selTracks", &fTrackInfo);
450  fStoreTree->Branch("selFlashes", &fFlashStore); //store all flashes in an event for all tracks
451  fStoreTree->Branch("selHits", &fHitStore);
452  //fStoreTree->Branch("selFlashes", &fFlashInfo);
453 
454 } // sbn::TimeTrackTreeStorage::TimeTrackTreeStorage()
455 
456 
457 void sbn::TimeTrackTreeStorage::analyze(art::Event const& e)
458 {
459  const geo::GeometryCore *geom = lar::providerFrom<geo::Geometry>();
460  // Implementation of required member function here.
461  fEvent = e.event();
462  fSubRun = e.subRun();
463  fRun = e.run();
464  fBeamInfo = {};
465 
466  std::vector<art::Ptr<recob::PFParticle>> const& pfparticles = e.getProduct<std::vector<art::Ptr<recob::PFParticle>>> (fT0selProducer);
467  if(pfparticles.empty()) {
468  mf::LogDebug(fLogCategory) << "No particles in '" << fT0selProducer.encode() << "'.";
469  return;
470  }
471 
472  std::vector<sim::BeamGateInfo> const& beamgate = e.getProduct<std::vector<sim::BeamGateInfo>> (fBeamGateProducer);
473  if(beamgate.empty())
474  mf::LogWarning(fLogCategory) << "No Beam Gate Information!";
475  else {
476  if(beamgate.size() > 1)
477  mf::LogWarning(fLogCategory) << "Event has multiple beam gate info labels! (maybe this changes later to be standard)";
478  sim::BeamGateInfo const& bg = beamgate[0];
479  fBeamInfo.beamGateSimStart = bg.Start();
480  fBeamInfo.beamGateDuration = bg.Width();
481  fBeamInfo.beamGateType = bg.BeamType();
482  }
483 
484  sbn::ExtraTriggerInfo const &triggerinfo = e.getProduct<sbn::ExtraTriggerInfo> (fTriggerProducer);
485  fTriggerInfo.beamType = value(triggerinfo.sourceType);
486  fTriggerInfo.triggerTime = triggerinfo.triggerTimestamp;
487  fTriggerInfo.beamGateTime = triggerinfo.beamGateTimestamp;
488  fTriggerInfo.triggerID = triggerinfo.triggerID;
489  fTriggerInfo.gateID = triggerinfo.gateID;
490 
491  //mf::LogTrace(fLogCategory) << "HERE!";
492  art::FindOneP<recob::Track> particleTracks(pfparticles,e,fTrackProducer);
493  art::FindOneP<anab::T0> t0Tracks(pfparticles,e,fT0Producer);
494  std::vector<recob::OpFlash> const &particleFlashes = e.getProduct<std::vector<recob::OpFlash>>(fFlashProducer);
495  //art::FindOneP<recob::SpacePoint> particleSPs(pfparticles, e, fT0selProducer);
496  //mf::LogTrace(fLogCategory) << "PFParticles size: " << pfparticles.size() << " art::FindOneP Tracks Size: " << particleTracks.size();
497  art::ValidHandle<std::vector<recob::Track>> allTracks = e.getValidHandle<std::vector<recob::Track>>(fTrackProducer);
498  art::FindManyP<recob::Hit,recob::TrackHitMeta> trkht(allTracks,e,fTrackProducer); //for track hits
499  art::FindManyP<anab::Calorimetry> calorim(allTracks, e, fCaloProducer);
500 
501  // get an extractor bound to this event
502  sbn::details::TriggerResponseManager::Extractors triggerResponseExtractors
503  = fTriggerResponses.extractorsFor(e);
504  unsigned int processed = 0;
505  for(unsigned int iPart = 0; iPart < pfparticles.size(); ++iPart)
506  {
507  art::Ptr<recob::Track> const& trackPtr = particleTracks.at(iPart);
508  if(trackPtr.isNull()) continue;
509 
510  fFlashInfo = {};
511  fFlashStore.clear();
512  fHitStore.clear();
513 
514  art::Ptr<anab::T0> const& t0Ptr = t0Tracks.at(iPart);
515  float const track_t0 = t0Ptr->Time();
516  if(!particleFlashes.empty())
517  {
518  //float min_flash_t0_diff = 999999.0;
519  for(unsigned int iFlash = 0; iFlash < particleFlashes.size(); ++iFlash)
520  {
521  fFlashInfo = {};
522  recob::OpFlash const flashPtr = particleFlashes.at(iFlash);
523  float const flash_pe = flashPtr.TotalPE();
524  float const flash_time = flashPtr.Time();
525  float const flash_x = flashPtr.XCenter();
526  float const flash_y = flashPtr.YCenter();
527  float const flash_z = flashPtr.ZCenter();
528  float flash_t0_diff = flash_time - track_t0/1e3;
529  //if(std::abs(flash_t0_diff) < min_flash_t0_diff)
530  //{
531  fFlashInfo.flash_id = iFlash;
532  fFlashInfo.sum_pe = flash_pe;
533  fFlashInfo.flash_time = flash_time;
534  fFlashInfo.flash_x = flash_x;
535  fFlashInfo.flash_y = flash_y;
536  fFlashInfo.flash_z = flash_z;
537  fFlashInfo.diff_flash_t0 = flash_t0_diff;
538  //min_flash_t0_diff = std::abs(flash_t0_diff);
539  fFlashStore.push_back(fFlashInfo);
540  //}
541  }
542  }
543  sbn::selTrackInfo trackInfo;
544  trackInfo.trackID = trackPtr->ID();
545  trackInfo.t0 = track_t0/1e3; //is this in nanoseconds? Will convert to seconds so I can understand better
546  //if(track_t0/1e3 < 10 && track_t0/1e3 > -10)
547  //mf::LogTrace(fLogCategory) << track_t0/1e3 << " Run is: " << fRun << " SubRun is: " << fSubRun << " Event is: " << fEvent << " Track ID is: " << trackPtr->ID();
548 
549  recob::tracking::Point_t startPoint = trackPtr->Start();
550  recob::tracking::Point_t endPoint = trackPtr->End();
551  recob::tracking::Vector_t startDir = trackPtr->StartDirection();
552  bool const flipTrack = fForceDowngoing && (startDir.Y() > 0.0);
553  if (flipTrack) {
554  std::swap(startPoint, endPoint);
555  startDir = -trackPtr->EndDirection();
556  }
557 
558  trackInfo.start_x = startPoint.X();
559  trackInfo.start_y = startPoint.Y();
560  trackInfo.start_z = startPoint.Z();
561  trackInfo.end_x = endPoint.X();
562  trackInfo.end_y = endPoint.Y();
563  trackInfo.end_z = endPoint.Z();
564  trackInfo.dir_x = startDir.X();
565  trackInfo.dir_y = startDir.Y();
566  trackInfo.dir_z = startDir.Z();
567  trackInfo.length = trackPtr->Length();
568 
569  std::vector<geo::Point_t> const trackPath
570  = extractTrajectory(*trackPtr, flipTrack);
572  = util::pathMiddlePoint(trackPath.begin(), std::prev(trackPath.end()));
573  trackInfo.middle_x = middlePoint.X();
574  trackInfo.middle_y = middlePoint.Y();
575  trackInfo.middle_z = middlePoint.Z();
576 
577  //
578  // determination of cathode crossing
579  //
580  // this determination should be independent of track direction;
581  icarus::CathodeDesc_t const cathode
582  = icarus::findTPCcathode(middlePoint, *geom);
583 
584  icarus::CathodeCrossing_t crossInfo
585  = icarus::detectCrossing(trackPath.begin(), trackPath.end(), cathode);
586 
587  if (crossInfo) {
588 
589  auto itBeforeCathode = trackPath.begin() + crossInfo.indexBefore;
590  auto itAfterCathode = trackPath.begin() + crossInfo.indexAfter;
591 
592  geo::Point_t middleBeforeCathode
593  = util::pathMiddlePoint(trackPath.begin(), itBeforeCathode);
594  geo::Point_t middleAfterCathode
595  = util::pathMiddlePoint(itAfterCathode, std::prev(trackPath.end()));
596 
597  // "before" is defined as "smaller x", so:
598  if (distance(middleAfterCathode, cathode) < 0.0) {
599  assert(distance(middleBeforeCathode, cathode) >= 0.0);
600  std::swap(crossInfo.indexBefore, crossInfo.indexAfter);
601  std::swap(itBeforeCathode, itAfterCathode);
602  std::swap(crossInfo.before, crossInfo.after);
603  std::swap(middleBeforeCathode, middleAfterCathode);
604  }
605 
606  trackInfo.beforecathode = crossInfo.before;
607  trackInfo.aftercathode = crossInfo.after;
608 
609  geo::Point_t const& atCathodePoint = crossInfo.crossingPoint;
610  trackInfo.atcathode_x = atCathodePoint.X();
611  trackInfo.atcathode_y = atCathodePoint.Y();
612  trackInfo.atcathode_z = atCathodePoint.Z();
613 
614  trackInfo.midbeforecathode_x = middleBeforeCathode.X();
615  trackInfo.midbeforecathode_y = middleBeforeCathode.Y();
616  trackInfo.midbeforecathode_z = middleBeforeCathode.Z();
617 
618  trackInfo.midaftercathode_x = middleAfterCathode.X();
619  trackInfo.midaftercathode_y = middleAfterCathode.Y();
620  trackInfo.midaftercathode_z = middleAfterCathode.Z();
621 
622  } // if crossing
623 
624  //Animesh added hit information - 2/8/2022
625 
626  unsigned int plane = 0; //hit plane number
627 
628  std::vector<art::Ptr<recob::Hit>> const& allHits = trkht.at(trackPtr.key());
629  std::vector<const recob::TrackHitMeta*> const& trkmetas = trkht.data(trackPtr.key());
630  std::vector<art::Ptr<anab::Calorimetry>> const& calorimetrycol = calorim.at(trackPtr.key());
631  std::vector<std::vector<unsigned int>> hits(plane);
632 
633  // art::FindManyP<recob::SpacePoint> fmspts(allHits, e, fT0selProducer);
634  // or art::FindManyP<recob::SpacePoint> fmspts(allHits, e, fSpacePointModuleLabel); // Not sure how to define it
635  for (size_t ih = 0; ih < allHits.size(); ++ih)
636  {
637  //hits[allHits[ih]->WireID().Plane].push_back(ih);
638  sbn::selHitInfo hinfo = makeHit(*allHits[ih], allHits[ih].key(), *trackPtr, *trkmetas[ih], calorimetrycol, geom);
639  if(hinfo.plane == 2)
640  fHitStore.push_back(hinfo);
641 
642  }
643  float totE = 0;
644  float totq_int = 0;
645  float totq_dqdx = 0;
646  for (size_t i = 0; i < fHitStore.size(); ++i)
647  {
648  if(fHitStore[i].dEdx > -1)
649  {
650  float E_hit = fHitStore[i].dEdx*fHitStore[i].pitch; //energy of hit, in MeV?
651  totE += E_hit;
652  }
653 
654  if(fHitStore[i].dqdx > -1)
655  {
656  float q_hit = fHitStore[i].integral;
657  totq_int += q_hit;
658  float q_hit_dqdx = fHitStore[i].dqdx*fHitStore[i].pitch;
659  totq_dqdx += q_hit_dqdx;
660  }
661  /*
662  if(fHitStore[i].pitch > 1 && fHitStore[i].dqdx < 100)
663  {
664  std::cout << "In strange peak! Event: " << fEvent << " Track ID: " << trackInfo.trackID << " Hit ID: " << i << " Total Number of hits: " << fHitStore.size() << std::endl;
665  }
666  */
667  }
668  trackInfo.energy = totE;
669  trackInfo.charge_int = totq_int;
670  trackInfo.charge_dqdx = totq_dqdx;
671  fTrackInfo = std::move(trackInfo);
672  /*
673  for(size_t trajp = 0; trajp < trackPtr->NumberTrajectoryPoints()-1; ++trajp)
674  {
675  TVector3 cur_point(trackPtr->TrajectoryPoint(traj_p).position.X(), trackPtr->TrajectoryPoint(traj_p).position.Y(), trackPtr->TrajectoryPoint(traj_p).position.Z());
676  TVector3 next_point(trackPtr->TrajectoryPoint(traj_p+1).position.X(), trackPtr->TrajectoryPoint(traj_p+1).position.Y(), trackPtr->TrajectoryPoint(traj_p+1).position.Z());
677  if(abs(cur_point.X()) < 170 && abs(next_point.X()) > 170)
678  //interpolate to get cathode crossing point
679 
680  }
681  */
682 
683  triggerResponseExtractors.fetch(iPart); // TODO no check performed; need to find a way
684 
685  ++processed;
686  ++fTotalProcessed;
687  fStoreTree->Fill();
688  } // for particle
689 
690  mf::LogInfo(fLogCategory) << "Particles Processed: " << processed;
691 
692 } // sbn::TimeTrackTreeStorage::analyze()
693 
694 
696  unsigned hkey,
697  const recob::Track &trk,
698  const recob::TrackHitMeta &thm,
699  const std::vector<art::Ptr<anab::Calorimetry>> &calo,
700  const geo::GeometryCore *geo)
701 {
702 
703  // TrackHitInfo to save
704  sbn::selHitInfo hinfo;
705 
706  // information from the hit object
707  hinfo.integral = hit.Integral();
708  hinfo.sumadc = hit.SummedADC();
709  hinfo.width = hit.RMS();
710  hinfo.pk_time = hit.PeakTime();
711  hinfo.mult = hit.Multiplicity();
712  hinfo.wire = hit.WireID().Wire;
713  hinfo.plane = hit.WireID().Plane;
714  hinfo.channel = geo->PlaneWireToChannel(hit.WireID());
715  hinfo.tpc = hit.WireID().TPC;
716  hinfo.end = hit.EndTick();
717  hinfo.start = hit.StartTick();
718  hinfo.id = (int)hkey;
719 
720  bool const badhit = (thm.Index() == std::numeric_limits<unsigned int>::max()) ||
721  (!trk.HasValidPoint(thm.Index()));
722 
723  //hinfo.ontraj = !badhit;
724  // Save trajectory information if we can
725  if(!badhit)
726  {
727  geo::Point_t const& loc = trk.LocationAtPoint(thm.Index());
728  hinfo.px = loc.X();
729  hinfo.py = loc.Y();
730  hinfo.pz = loc.Z();
731 
732  geo::Vector_t const& dir = trk.DirectionAtPoint(thm.Index());
733  hinfo.dirx = dir.X();
734  hinfo.diry = dir.Y();
735  hinfo.dirz = dir.Z();
736 
737  // And determine if the Hit is on a Calorimetry object
738  for (const art::Ptr<anab::Calorimetry> &c: calo) {
739  if (c->PlaneID().Plane != hinfo.plane) continue;
740 
741  // Found the plane! Now find the hit:
742  for (unsigned i_calo = 0; i_calo < c->dQdx().size(); i_calo++) {
743  // "TpIndices" match to the hit key
744  if (c->TpIndices()[i_calo] != hkey) continue;
745  // Fill the calo information associated with the hit
746  hinfo.oncalo = true;
747  hinfo.pitch = c->TrkPitchVec()[i_calo];
748  hinfo.dqdx = c->dQdx()[i_calo];
749  hinfo.dEdx = dEdx_calc(hinfo.dqdx, fMODA, fMODB, fWion, fEfield);
750  hinfo.rr = c->ResidualRange()[i_calo];
751  break;
752  } // for i_calo
753  break;
754  } // for c
755  }
756 
757  return hinfo;
758 }
759 
761  float A,
762  float B,
763  float Wion,
764  float E)
765 {
766  float LAr_density_gmL = 1.389875; //LAr density in g/cm^3
767  float alpha = A;
768  float beta = B/(LAr_density_gmL*E);
769  float dEdx = ((std::exp(dQdx*Wion*beta) - alpha)/beta)*3.278;
770 
771  return dEdx;
772 
773 }
774 
775 
776 // -----------------------------------------------------------------------------
778 
779  mf::LogInfo(fLogCategory) << "Processed " << fTotalProcessed << " tracks.";
780 
781 } // sbn::TimeTrackTreeStorage::endJob()
782 
783 
784 // -----------------------------------------------------------------------------
785 std::vector<std::pair<double, std::vector<raw::Channel_t>>>
787 
788  geo::GeometryCore const& geom { *lar::providerFrom<geo::Geometry>() };
789 
790  // run the algorithm to identify the PMT walls (as groups of geo::OpDetGeo)
791  std::vector<std::pair<double, std::vector<geo::OpDetGeo const*>>> opDetWalls
793 
794  // and weirdly, the only portable way to go from a OpDetGeo to its channel
795  // is to build a map (maybe because it's not guaranteed to be 1-to-1?)
796  std::map<geo::OpDetGeo const*, raw::Channel_t> opDetToChannel;
797  for (auto const channel: util::counter<raw::Channel_t>(geom.MaxOpChannel()))
798  opDetToChannel[&geom.OpDetGeoFromOpChannel(channel)] = channel;
799 
800  // rewrite the data structure replacing each detector with its readout channel
801  std::vector<std::pair<double, std::vector<raw::Channel_t>>> channelWalls;
802  for (auto const& [ coord, PMTs ]: opDetWalls) {
803  std::vector<raw::Channel_t> channels;
804  channels.reserve(PMTs.size());
805  for (geo::OpDetGeo const* PMT: PMTs)
806  channels.push_back(opDetToChannel.at(PMT));
807 
808  channelWalls.emplace_back(coord, std::move(channels));
809  } // for walls
810 
811  return channelWalls;
812 } // sbn::TimeTrackTreeStorage::computePMTwalls()
813 
814 
815 // -----------------------------------------------------------------------------
816 
817 DEFINE_ART_MODULE(sbn::TimeTrackTreeStorage)
std::vector< sbn::selLightInfo > fFlashStore
std::vector< sbn::selHitInfo > fHitStore
Information on a single trigger source for the tree.
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space.
Definition: geo_vectors.h:164
float middle_y
Half-way distance along the trajectory.
unsigned int gateID
Incremental counter of gates from any source opened from start of the run.
fhicl::Sequence< TriggerSpecConfigTable > EmulatedTriggers
Utilities related to art service access.
float atcathode_z
Cathode crossing point of trajectory.
#define PMT
Definition: NestAlg.cxx:19
Manages extraction of trigger results and filling of their branches.
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
geo::WireID WireID() const
Definition: Hit.h:233
void analyze(art::Event const &e) override
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:220
geo::Point_t crossingPoint
Trajectory crossing point.
Declaration of signal hit object.
sbn::details::TriggerResponseManager fTriggerResponses
Manages filling of trigger result branches.
Point_t const & LocationAtPoint(size_t i) const
pdgs p
Definition: selectors.fcl:22
bool HasValidPoint(size_t i) const
float LAr_density_gmL
Definition: dedx.py:10
Class to keep data related to recob::Hit associated with recob::Track.
CathodeDesc_t findTPCcathode(geo::Point_t const &point, geo::GeometryCore const &geom)
Returns cathode information for cryostat at the specified point.
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:224
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
double after
Length of the path &quot;after&quot; the cathode.
process_name E
process_name use argoneut_mc_hitfinder track
double Start() const
Definition: BeamGateInfo.h:30
Data related to recob::Hit associated with recob::Track.The purpose is to collect several variables t...
Definition: TrackHitMeta.h:43
process_name hit
Definition: cheaterreco.fcl:51
fhicl::Atom< art::InputTag > TrackFitterProducer
float atcathode_x
Cathode crossing point of trajectory.
fhicl::Atom< art::InputTag > TriggerProducer
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:226
friend TriggerInputSpec_t convert(Config::TriggerSpecConfig const &config)
Algorithms dealing with a trajectory and the cathode.
float dEdx_calc(float dQdx, float A, float B, float Wion, float E)
std::uint64_t beamGateTimestamp
Absolute timestamp of the opening of this beam gate [ns].
fDetProps &fDetProps fDetProps &fDetProps fLogCategory
double ZCenter() const
Definition: OpFlash.h:117
process_name can override from command line with o or output calo
Definition: pid.fcl:40
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Access the description of detector geometry.
float beforecathode
Track path length before cathode (lower x).
double Time() const
Definition: OpFlash.h:106
ROOT::Math::DisplacementVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Vector_t
Type for representation of momenta in 3D space. See recob::tracking::Coord_t for more details on the ...
Definition: TrackingTypes.h:29
Simple description for the cathode.
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
Additional information on trigger.
fhicl::TableAs< TriggerInputSpec_t, TriggerSpecConfig > TriggerSpecConfigTable
fhicl::OptionalAtom< art::InputTag > T0Producer
float midaftercathode_x
Midpoint of subpath after cathode.
float atcathode_y
Cathode crossing point of trajectory.
std::size_t indexBefore
Index of the point &quot;before&quot; cathode.
Helper managing the trigger response part of a TTree.
Algorihtm to group PMTs into piling towers.
BEGIN_PROLOG vertical distance to the surface Name
float middle_x
Half-way distance along the trajectory.
Test of util::counter and support utilities.
float midaftercathode_z
Midpoint of subpath after cathode.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Description of geometry of one entire detector.
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:216
float midbeforecathode_x
Midpoint of subpath before cathode.
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
Provides recob::Track data product.
std::vector< std::pair< double, std::vector< raw::Channel_t > > > computePMTwalls() const
Accesses detector geometry to return all PMT split by wall.
sbn::triggerSource sourceType
Type of this gate (sbn::triggerSource::NBits marks this object invalid).
tuple dir
Definition: dropbox.py:28
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:217
size_t FirstValidPoint() const
Encapsulate the geometry of an optical detector.
std::vector< std::pair< double, std::vector< raw::Channel_t > > > fPMTwalls
PMT geometry objects, grouped by wall (drift) coordinate.
float midbeforecathode_y
Midpoint of subpath before cathode.
raw::ChannelID_t PlaneWireToChannel(WireID const &wireid) const
Returns the ID of the TPC channel connected to the specified wire.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
float aftercathode
Track path length before cathode (higher x).
CathodeCrossing_t detectCrossing(Iter begin, Iter end, CathodeDesc_t const &cathode)
Returns the crossing point of a trajectory on the cathode.
float midaftercathode_y
Midpoint of subpath after cathode.
size_t NextValidPoint(size_t index) const
double before
Length of the path &quot;before&quot; the cathode.
static constexpr size_t InvalidIndex
Value returned on failed index queries.
std::vector< std::pair< double, PMTlist_t > > PMTwalls(geo::CryostatGeo const &cryo) const
Groups optical detectors under the specified cryostat into walls.
int Wion
Definition: dedx.py:125
Information about a single trigger logic (hardware or emulated).
float middle_z
Half-way distance along the trajectory.
double Width() const
Definition: BeamGateInfo.h:31
sbn::selHitInfo makeHit(const recob::Hit &hit, unsigned hkey, const recob::Track &trk, const recob::TrackHitMeta &thm, const std::vector< art::Ptr< anab::Calorimetry >> &calo, const geo::GeometryCore *geo)
do i e
fhicl::OptionalAtom< art::InputTag > T0selProducer
float SummedADC() const
The sum of calibrated ADC counts of the hit (0. by default)
Definition: Hit.h:223
unsigned int Index() const
Hit index along the track trajectory.
Definition: TrackHitMeta.h:55
Vector_t DirectionAtPoint(size_t i) const
float midbeforecathode_z
Midpoint of subpath before cathode.
auto pathMiddlePoint(FIter itFirst, LIter itLast, double relTarget=0.5)
Returns the geometric point in the middle of the specified path.
Data product holding additional trigger information.
temporary value
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
art::EDAnalyzer::Table< Config > Parameters
fhicl::Atom< art::InputTag > BeamGateProducer
double TotalPE() const
Definition: OpFlash.cxx:68
Fills a ROOT tree with track-based triggering information.
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
double XCenter() const
Returns the estimated center on x direction (.
Definition: OpFlash.h:113
std::uint64_t triggerTimestamp
Absolute timestamp of this trigger [ns].
float A
Definition: dedx.py:137
Algorithms dealing with a trajectory as a sequence of 3D points.
bool const fForceDowngoing
Whether to force all tracks to be downgoing.
unsigned int triggerID
The identifier of this trigger (usually matching the event number).
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
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< Coord_t >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space. See recob::tracking::Coord_t for more detai...
Definition: TrackingTypes.h:26
double YCenter() const
Definition: OpFlash.h:115
Configuration specifications for the emulation of a trigger logic.
Information about the cathode crossing of a path.
BeamType_t BeamType() const
Definition: BeamGateInfo.h:32
std::size_t indexAfter
Index of the point &quot;after&quot; cathode.
geo::Point_t middlePoint(BeginIter begin, EndIter end)
Returns the middle of the specified points.
TimeTrackTreeStorage::TriggerInputSpec_t convert(TimeTrackTreeStorage::Config::TriggerSpecConfig const &config)
art framework interface to geometry description
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
fDetProps &fDetProps fDetProps &fDetProps consumesCollector())
Algorithm clustering PMT according to their position.