All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
TrackCaloSkimmer_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: TrackCaloSkimmer
3 // Plugin Type: analyzer (art v3_06_03)
4 // File: TrackCaloSkimmer_module.cc
5 //
6 // Generated at Mon May 17 09:46:34 2021 by Gray Putnam using cetskelgen
7 // from cetlib version v3_11_01.
8 //
9 // Module for creating a skim of track calorimetry reconstruction for use
10 // with calibrations in ICARUS.
11 ////////////////////////////////////////////////////////////////////////
12 
13 #include "TrackCaloSkimmer.h"
14 
15 #include "art/Utilities/make_tool.h"
16 
17 // Useful functions
20 
21 // Global functions / data for fitting
22 const size_t MAX_N_FIT_DATA = 30;
23 
24 static int N_FIT_DATA = -1;
25 static double FIT_RR[MAX_N_FIT_DATA];
26 static double FIT_DQDX[MAX_N_FIT_DATA];
27 
28 void ConstResiduals(int &npar, double *g, double &result, double *par, int flag) {
29  double ret = 0;
30 
31  double C = *par;
32 
33  for (int i = 0; i < N_FIT_DATA; i++) {
34  double diff = FIT_DQDX[i] - C;
35  ret += diff*diff;
36  }
37 
38  result = sqrt(ret);
39 }
40 
41 void ExpResiduals(int &npar, double *g, double &result, double *par, int flag) {
42  double ret = 0;
43 
44  double A = par[0];
45  double R = par[1];
46 
47  for (int i = 0; i < N_FIT_DATA; i++) {
48  double diff = FIT_DQDX[i] - A*exp(-FIT_RR[i]/R);
49  ret += diff*diff;
50  }
51 
52  result = sqrt(ret);
53 }
54 
56  delete fTrack;
57 }
58 
59 sbn::TrackCaloSkimmer::TrackCaloSkimmer(fhicl::ParameterSet const& p)
60  : EDAnalyzer{p},
61  fFitExp(2),
62  fFitConst(1)
63 {
64  // Grab config
65  fPFPproducer = p.get< art::InputTag > ("PFPproducer","pandoraGausCryo0");
66  fT0producers = p.get< std::vector<art::InputTag> > ("T0producers", {"pandoraGausCryo0"} );
67  fCALOproducer = p.get< art::InputTag > ("CALOproducer");
68  fTRKproducer = p.get< art::InputTag > ("TRKproducer" );
69  fTRKHMproducer= p.get< art::InputTag > ("TRKHMproducer", "");
70  fHITproducer = p.get< art::InputTag > ("HITproducer" );
71  fG4producer = p.get< std::string > ("G4producer" );
72  fSimChannelproducer = p.get< std::string > ("SimChannelproducer" );
73  fRequireT0 = p.get<bool>("RequireT0", false);
74  fDoTailFit = p.get<bool>("DoTailFit", true);
75  fVerbose = p.get<bool>("Verbose", false);
76  fSilenceMissingDataProducts = p.get<bool>("SilenceMissingDataProducts", false);
77  fHitRawDigitsTickCollectWidth = p.get<double>("HitRawDigitsTickCollectWidth", 50.);
78  fHitRawDigitsWireCollectWidth = p.get<int>("HitRawDigitsWireCollectWidth", 5);
79  fTailFitResidualRange = p.get<double>("TailFitResidualRange", 5.);
80  if (fTailFitResidualRange > 10.) {
81  std::cout << "sbn::TrackCaloSkimmer: Bad tail fit residual range config :(" << fTailFitResidualRange << "). Fits will not be meaningful.\n";
82  }
83  fFillTrackEndHits = p.get<bool>("FillTrackEndHits", true);
84  fTrackEndHitWireBox = p.get<float>("TrackEndHitWireBox", 60); // 20 cm
85  fTrackEndHitTimeBox = p.get<float>("TrackEndHitTimeBox", 300); // about 20cm
86 
87  fRawDigitproducers = p.get<std::vector<art::InputTag>>("RawDigitproducers", {});
88 
89  std::vector<fhicl::ParameterSet> selection_tool_configs(p.get<std::vector<fhicl::ParameterSet>>("SelectionTools"), {});
90  for (const fhicl::ParameterSet &p: selection_tool_configs) {
91  fSelectionTools.push_back(art::make_tool<sbn::ITCSSelectionTool>(p));
92  }
93 
94  // Setup meta info
95  fMeta.iproc = -1;
96  fMeta.ifile = -1;
97  const char *process_str = std::getenv("PROCESS");
98  if (process_str) {
99  try {
100  fMeta.iproc = std::stoi(process_str);
101  }
102  catch (...) {}
103  }
104 
105  // Output stuff
106  fTrack = new sbn::TrackInfo();
107 
108  art::ServiceHandle<art::TFileService> tfs;
109  fTree = tfs->make<TTree>("TrackCaloSkim", "Calo Tree");
110  fTree->Branch("trk", &fTrack);
111 }
112 
113 void sbn::TrackCaloSkimmer::analyze(art::Event const& e)
114 {
115  unsigned evt = e.event();
116  unsigned sub = e.subRun();
117  unsigned run = e.run();
118  if (fVerbose) {
119  std::cout << "[TrackCaloSkimmer::analyzeEvent] Run: " << run << ", SubRun: " << sub << ", Event: "<< evt << ", Is Data: " << e.isRealData() << std::endl;
120  }
121 
122  fMeta.evt = evt;
123  fMeta.subrun = sub;
124  fMeta.run = run;
125  fMeta.time = e.time().value();
126 
127  // Services
128  const geo::GeometryCore *geometry = lar::providerFrom<geo::Geometry>();
129  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataFor(e);
130  auto const dprop =
131  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataFor(e, clock_data);
132 
133  // Identify which detector: can only detect either sbnd or icarus
134 
135  std::string gdml = geometry->GDMLFile();
136  gdml = basename(gdml.c_str());
137 
138  for(unsigned int i = 0; i <gdml.size(); ++i) gdml[i] = std::tolower(gdml[i]);
139 
140  EDet det = kNOTDEFINED;
141 
142  const bool hasSBND = ((gdml.find("sbnd") != std::string::npos) ||
143  (geometry->DetectorName().find("sbnd") != std::string::npos));
144 
145  const bool hasICARUS = ((gdml.find("icarus") != std::string::npos) ||
146  (geometry->DetectorName().find("icarus") != std::string::npos));
147 
148  if(hasSBND == hasICARUS) {
149  std::cout << "TrackCaloSkimmer: Unable to automatically determine either SBND or ICARUS!" << std::endl;
150  abort();
151  }
152 
153  if(hasSBND) det = kSBND;
154  if(hasICARUS) det = kICARUS;
155 
156  // Setup the volumes
157  std::vector<std::vector<geo::BoxBoundedGeo>> TPCVols;
158  std::vector<geo::BoxBoundedGeo> AVs;
159 
160  // First the TPC
161  for (auto const &cryo: geometry->IterateCryostats()) {
162  geo::GeometryCore::TPC_iterator iTPC = geometry->begin_TPC(cryo.ID()),
163  tend = geometry->end_TPC(cryo.ID());
164  std::vector<geo::BoxBoundedGeo> this_tpc_volumes;
165  while (iTPC != tend) {
166  geo::TPCGeo const& TPC = *iTPC;
167  this_tpc_volumes.push_back(TPC.ActiveBoundingBox());
168  iTPC++;
169  }
170  TPCVols.push_back(std::move(this_tpc_volumes));
171  }
172 
173  for (const std::vector<geo::BoxBoundedGeo> &tpcs: TPCVols) {
174  double XMin = std::min_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MinX() < rhs.MinX(); })->MinX();
175  double YMin = std::min_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MinY() < rhs.MinY(); })->MinY();
176  double ZMin = std::min_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MinZ() < rhs.MinZ(); })->MinZ();
177 
178  double XMax = std::max_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MaxX() < rhs.MaxX(); })->MaxX();
179  double YMax = std::max_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MaxY() < rhs.MaxY(); })->MaxY();
180  double ZMax = std::max_element(tpcs.begin(), tpcs.end(), [](auto &lhs, auto &rhs) { return lhs.MaxZ() < rhs.MaxZ(); })->MaxZ();
181 
182  AVs.emplace_back(XMin, XMax, YMin, YMax, ZMin, ZMax);
183  }
184 
185  // Truth information
186  std::vector<art::Ptr<simb::MCParticle>> mcparticles;
187  if (fG4producer.size()) {
188  art::ValidHandle<std::vector<simb::MCParticle>> mcparticle_handle = e.getValidHandle<std::vector<simb::MCParticle>>(fG4producer);
189  art::fill_ptr_vector(mcparticles, mcparticle_handle);
190  }
191 
192  std::vector<art::Ptr<sim::SimChannel>> simchannels;
193  if (fSimChannelproducer.size()) {
194  art::ValidHandle<std::vector<sim::SimChannel>> simchannel_handle = e.getValidHandle<std::vector<sim::SimChannel>>(fSimChannelproducer);
195  art::fill_ptr_vector(simchannels, simchannel_handle);
196  }
197 
198  // Reconstructed Information
199  std::vector<art::Ptr<recob::PFParticle>> PFParticleList;
200  try {
201  art::ValidHandle<std::vector<recob::PFParticle>> pfparticles = e.getValidHandle<std::vector<recob::PFParticle>>(fPFPproducer);
202  art::fill_ptr_vector(PFParticleList, pfparticles);
203  }
204  catch(...) {
205  std::cout << "PFP's with tag: " << fPFPproducer << " not present.\n";
206  // Real data may have missing products -- just ignore the event
207  if (fSilenceMissingDataProducts) return;
208  else throw;
209  }
210 
211  // PFP-associated data
212  std::vector<art::FindManyP<anab::T0>> fmT0;
213  for (unsigned i_label = 0; i_label < fT0producers.size(); i_label++) {
214  fmT0.emplace_back(PFParticleList, e, fT0producers[i_label]);
215  }
216  art::FindManyP<recob::SpacePoint> PFParticleSPs(PFParticleList, e, fPFPproducer);
217 
218  // Now we don't need to guard access to further data. If this is an empty event it should be caught by PFP's or Hit's
219  art::ValidHandle<std::vector<recob::Track>> tracks = e.getValidHandle<std::vector<recob::Track>>(fTRKproducer);
220 
221  // Track - associated data
222  art::FindManyP<recob::Track> fmTracks(PFParticleList, e, fTRKproducer);
223 
224  art::InputTag thm_label = fTRKHMproducer.empty() ? fTRKproducer : fTRKHMproducer;
225  art::FindManyP<recob::Hit, recob::TrackHitMeta> fmtrkHits(tracks, e, thm_label);
226  art::FindManyP<anab::Calorimetry> fmCalo(tracks, e, fCALOproducer);
227 
228  // Collect raw digits for saving hits
229  std::vector<art::Ptr<raw::RawDigit>> rawdigitlist;
230  for (const art::InputTag &t: fRawDigitproducers) {
231  art::ValidHandle<std::vector<raw::RawDigit>> thisdigits = e.getValidHandle<std::vector<raw::RawDigit>>(t);
232  art::fill_ptr_vector(rawdigitlist, thisdigits);
233  }
234 
235  // The raw digit list is not sorted, so make it into a map on the WireID
236  std::map<geo::WireID, art::Ptr<raw::RawDigit>> rawdigits;
237  for (const art::Ptr<raw::RawDigit> &d: rawdigitlist) {
238 
239  std::vector<geo::WireID> wids;
240  // Handle bad channel ID
241  try {
242  wids = geometry->ChannelToWire(d->Channel());
243  }
244  catch(...) {
245  continue;
246  }
247 
248  // Ignore channel with no mapped wire
249  if (wids.size() == 0) continue;
250 
251  // Ignore wires that are already mapped
252  if (rawdigits.count(wids[0])) continue;
253 
254  rawdigits[wids[0]] = d;
255  }
256 
257  // Collect all hits
258  art::ValidHandle<std::vector<recob::Hit>> allhit_handle = e.getValidHandle<std::vector<recob::Hit>>(fHITproducer);
259  std::vector<art::Ptr<recob::Hit>> allHits;
260  art::fill_ptr_vector(allHits, allhit_handle);
261 
262  // And lookup the SP's
263  art::FindManyP<recob::SpacePoint> allHitSPs(allHits, e, fPFPproducer);
264 
265  // Prep truth-to-reco-matching info
266  //
267  // Use helper functions from CAFMaker/FillTrue
268  std::map<int, std::vector<std::pair<geo::WireID, const sim::IDE*>>> id_to_ide_map;
269  std::map<int, std::vector<art::Ptr<recob::Hit>>> id_to_truehit_map;
270  const cheat::BackTrackerService *bt = NULL;
271 
272  if (simchannels.size()) {
273  art::ServiceHandle<cheat::BackTrackerService> bt_serv;
274  id_to_ide_map = caf::PrepSimChannels(simchannels, *geometry);
275  id_to_truehit_map = caf::PrepTrueHits(allHits, clock_data, *bt_serv.get());
276  bt = bt_serv.get();
277  }
278 
279  // service data
280 
281  // Build global track info
282  std::vector<GlobalTrackInfo> track_infos;
283  for (const recob::Track &t: *tracks) {
284  track_infos.push_back({
285  t.Start(), t.End(), t.StartDirection(), t.EndDirection(), t.ID()
286  });
287  }
288 
289  for (art::Ptr<recob::PFParticle> p_pfp: PFParticleList) {
290  const recob::PFParticle &pfp = *p_pfp;
291 
292  const std::vector<art::Ptr<recob::Track>> thisTrack = fmTracks.at(p_pfp.key());
293  if (thisTrack.size() != 1)
294  continue;
295 
296  art::Ptr<recob::Track> trkPtr = thisTrack.at(0);
297 
298  std::vector<art::Ptr<anab::Calorimetry>> emptyCaloVector;
299  const std::vector<art::Ptr<anab::Calorimetry>> &calo = fmCalo.isValid() ? fmCalo.at(trkPtr.key()) : emptyCaloVector;
300 
301  std::vector<art::Ptr<recob::Hit>> emptyHitVector;
302  const std::vector<art::Ptr<recob::Hit>> &trkHits = fmtrkHits.isValid() ? fmtrkHits.at(trkPtr.key()) : emptyHitVector;
303 
304  art::FindManyP<recob::SpacePoint> fmtrkHitSPs(trkHits, e, fPFPproducer);
305 
306  std::vector<const recob::TrackHitMeta*> emptyTHMVector;
307  const std::vector<const recob::TrackHitMeta*> &trkHitMetas = fmtrkHits.isValid() ? fmtrkHits.data(trkPtr.key()) : emptyTHMVector;
308 
309  art::Ptr<recob::SpacePoint> nullSP;
310  std::vector<art::Ptr<recob::SpacePoint>> trkHitSPs;
311  if (fmtrkHitSPs.isValid()) {
312  for (unsigned i_hit = 0; i_hit < trkHits.size(); i_hit++) {
313  const std::vector<art::Ptr<recob::SpacePoint>> &h_sp = fmtrkHitSPs.at(i_hit);
314  if (h_sp.size()) {
315  trkHitSPs.push_back(h_sp.at(0));
316  }
317  else {
318  trkHitSPs.push_back(nullSP);
319  }
320  }
321  }
322 
323  int whicht0 = -1;
324  float t0 = std::numeric_limits<float>::signaling_NaN();
325  for (unsigned i_t0 = 0; i_t0 < fmT0.size(); i_t0++) {
326  if (fmT0[i_t0].isValid() && fmT0[i_t0].at(p_pfp.key()).size()) {
327  t0 = fmT0[i_t0].at(p_pfp.key()).at(0)->Time();
328  whicht0 = i_t0;
329 
330  if (fVerbose) std::cout << "Track: " << trkPtr->ID() << " Has T0 (" << fT0producers[i_t0] << ")\n";
331 
332  break;
333  }
334  }
335 
336  if (fRequireT0 && whicht0 < 0) {
337  continue;
338  }
339 
340  if (fVerbose) std::cout << "Processing new track! ID: " << trkPtr->ID() << " time: " << t0 << std::endl;
341 
342  // Reset the track object
343  *fTrack = sbn::TrackInfo();
344 
345  // Reset other persistent info
346  fSnippetCount.clear();
347  fWiresToSave.clear();
348 
349  // Fill the track!
350  FillTrack(*trkPtr, pfp, t0, trkHits, trkHitMetas, trkHitSPs, calo, rawdigits, track_infos, geometry, clock_data, bt, det);
351  fTrack->whicht0 = whicht0;
352 
353  FillTrackDaughterRays(*trkPtr, pfp, PFParticleList, PFParticleSPs);
354 
355  if (fFillTrackEndHits) FillTrackEndHits(geometry, dprop, *trkPtr, allHits, allHitSPs);
356 
357  // Fill the truth information if configured
358  if (simchannels.size()) FillTrackTruth(clock_data, trkHits, mcparticles, AVs, TPCVols, id_to_ide_map, id_to_truehit_map, dprop, geometry);
359 
360  // Save?
361  bool select = false;
362  if (!fSelectionTools.size()) select = true;
363 
364  // Take the OR of each selection tool
365  int i_select = 0;
366  for (const std::unique_ptr<sbn::ITCSSelectionTool> &t: fSelectionTools) {
367  if (t->DoSelect(*fTrack)) {
368  select = true;
369  fTrack->selected = i_select;
370  fTrack->nprescale = t->GetPrescale();
371  break;
372  }
373  i_select ++;
374  }
375 
376  // Save!
377  if (select) {
378  if (fVerbose) std::cout << "Track Selected! By tool: " << i_select << std::endl;
379  fTree->Fill();
380  }
381  }
382 }
383 
384 // helpers
385 
386 // Returns the minimum hit time for hits in either TPC E (TPCE==true)
387 // or TPC W (TPCE==false)
388 float HitMinTime(const std::vector<sbn::TrackHitInfo> &hits,
389  bool TPCE,
390  sbn::EDet det) {
391  double min = -1;
392  bool hit_is_TPCE = -1;
393 
394  for (const sbn::TrackHitInfo &h: hits) {
395 
396  // In ICARUS, TPC E is 0, 1 and TPC W is 2, 3
397  if(det == sbn::kICARUS) hit_is_TPCE = h.h.tpc <= 1;
398 
399  // In SBND, TPC 0 and 1
400  if(det == sbn::kSBND) hit_is_TPCE = h.h.tpc <= 0;
401 
402  if (h.oncalo && hit_is_TPCE == TPCE) {
403  if (min < 0. || h.h.time < min) min = h.h.time;
404  }
405  }
406 
407  return min;
408 }
409 
410 // Returns the maximum hit time for hits in either TPC E (TPCE==true)
411 // or TPC W (TPCE==false)
412 float HitMaxTime(const std::vector<sbn::TrackHitInfo> &hits,
413  bool TPCE,
414  sbn::EDet det) {
415  double max = -1;
416  bool hit_is_TPCE = -1;
417 
418  for (const sbn::TrackHitInfo &h: hits) {
419 
420  // In ICARUS, TPC E is 0, 1 and TPC W is 2, 3
421  if(det == sbn::kICARUS) hit_is_TPCE = h.h.tpc <= 1;
422 
423  // In SBND, TPC 0 and 1
424  if(det == sbn::kSBND) hit_is_TPCE = h.h.tpc <= 0;
425 
426  if (h.oncalo && hit_is_TPCE == TPCE) {
427  if (max < 0. || h.h.time > max) max = h.h.time;
428  }
429  }
430 
431  return max;
432 }
433 
434 sbn::Vector3D ConvertTVector(const TVector3 &tv) {
435  sbn::Vector3D v;
436  v.x = tv.X();
437  v.y = tv.Y();
438  v.z = tv.Z();
439 
440  return v;
441 }
442 
443 // Turn a particle position to a space-charge induced position
445  auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
446  art::ServiceHandle<geo::Geometry const> geom;
447 
448  geo::Point_t ret = loc;
449 
450  // Returned X is the drift -- multiply by the drift direction to undo this
451  int corr = geom->TPC(tpc.TPC).DriftDir()[0];
452 
453  if (sce && sce->EnableSimSpatialSCE()) {
454  geo::Vector_t offset = sce->GetPosOffsets(ret);
455 
456  ret.SetX(ret.X() + corr * offset.X());
457  ret.SetY(ret.Y() + offset.Y());
458  ret.SetZ(ret.Z() + offset.Z());
459  }
460 
461  return ret;
462 }
463 
464 // Turn a space-charge induced position to a trajectory Position
466  auto const* sce = lar::providerFrom<spacecharge::SpaceChargeService>();
467 
468  geo::Point_t ret = loc;
469 
470  if (sce && sce->EnableSimSpatialSCE()) {
471  geo::Vector_t offset = sce->GetCalPosOffsets(ret, tpc.TPC);
472 
473  ret.SetX(ret.X() + offset.X());
474  ret.SetY(ret.Y() + offset.Y());
475  ret.SetZ(ret.Z() + offset.Z());
476  }
477 
478  return ret;
479 
480 }
481 
482 // Collect MCParticle information
483 sbn::TrueParticle TrueParticleInfo(const simb::MCParticle &particle,
484  const std::vector<geo::BoxBoundedGeo> &active_volumes,
485  const std::vector<std::vector<geo::BoxBoundedGeo>> &tpc_volumes,
486  const std::map<int, std::vector<std::pair<geo::WireID, const sim::IDE *>>> &id_to_ide_map,
487  const std::map<int, std::vector<art::Ptr<recob::Hit>>> &id_to_truehit_map,
488  const detinfo::DetectorPropertiesData &dprop,
489  const geo::GeometryCore *geo) {
490 
491  std::vector<std::pair<geo::WireID, const sim::IDE *>> empty;
492  const std::vector<std::pair<geo::WireID, const sim::IDE *>> &particle_ides = id_to_ide_map.count(particle.TrackId()) ? id_to_ide_map.at(particle.TrackId()) : empty;
493 
494  std::vector<art::Ptr<recob::Hit>> emptyHits;
495  const std::vector<art::Ptr<recob::Hit>> &particle_hits = id_to_truehit_map.count(particle.TrackId()) ? id_to_truehit_map.at(particle.TrackId()) : emptyHits;
496 
497  sbn::TrueParticle trueparticle;
498 
499  trueparticle.length = 0.;
500  trueparticle.crosses_tpc = false;
501  trueparticle.wallin = (int)caf::kWallNone;
502  trueparticle.wallout = (int)caf::kWallNone;
503  trueparticle.plane0VisE = 0.;
504  trueparticle.plane1VisE = 0.;
505  trueparticle.plane2VisE = 0.;
506  trueparticle.plane0nhit = 0;
507  trueparticle.plane1nhit = 0;
508  trueparticle.plane2nhit = 0;
509  for (auto const &ide_pair: particle_ides) {
510  const geo::WireID &w = ide_pair.first;
511  const sim::IDE *ide = ide_pair.second;
512 
513  if (w.Plane == 0) {
514  trueparticle.plane0VisE += ide->energy / 1000. /* MeV -> GeV*/;
515  }
516  else if (w.Plane == 1) {
517  trueparticle.plane1VisE += ide->energy / 1000. /* MeV -> GeV*/;
518  }
519  else if (w.Plane == 2) {
520  trueparticle.plane2VisE += ide->energy / 1000. /* MeV -> GeV*/;
521  }
522  }
523 
524  for (const art::Ptr<recob::Hit> h: particle_hits) {
525  const geo::WireID &w = h->WireID();
526 
527  if (w.Plane == 0) {
528  trueparticle.plane0nhit ++;
529  }
530  else if (w.Plane == 1) {
531  trueparticle.plane1nhit ++;
532  }
533  else if (w.Plane == 2) {
534  trueparticle.plane2nhit ++;
535  }
536 
537  }
538 
539  // if no trajectory points, then assume outside AV
540  trueparticle.cont_tpc = particle.NumberTrajectoryPoints() > 0;
541  trueparticle.contained = particle.NumberTrajectoryPoints() > 0;
542 
543  // Get the entry and exit points
544  int entry_point = -1;
545 
546  int cryostat_index = -1;
547  int tpc_index = -1;
548 
549  for (unsigned j = 0; j < particle.NumberTrajectoryPoints(); j++) {
550  for (unsigned i = 0; i < active_volumes.size(); i++) {
551  if (active_volumes.at(i).ContainsPosition(particle.Position(j).Vect())) {
552  entry_point = j;
553  cryostat_index = i;
554  break;
555  }
556  }
557  if (entry_point != -1) break;
558  }
559 
560  // get the wall
561  if (entry_point > 0) {
562  trueparticle.wallin = (int)caf::GetWallCross(active_volumes.at(cryostat_index), particle.Position(entry_point).Vect(), particle.Position(entry_point-1).Vect());
563  }
564 
565  int exit_point = -1;
566 
567  // now setup the cryostat the particle is in
568  std::vector<geo::BoxBoundedGeo> volumes;
569  if (entry_point >= 0) {
570  volumes = tpc_volumes.at(cryostat_index);
571  for (unsigned i = 0; i < volumes.size(); i++) {
572  if (volumes[i].ContainsPosition(particle.Position(entry_point).Vect())) {
573  tpc_index = i;
574  trueparticle.cont_tpc = entry_point == 0;
575  break;
576  }
577  }
578  trueparticle.contained = entry_point == 0;
579  }
580  // if we couldn't find the initial point, set not contained
581  else {
582  trueparticle.contained = false;
583  }
584 
585  if (tpc_index < 0) {
586  trueparticle.cont_tpc = false;
587  }
588 
589  // Get the length and determine if any point leaves the active volume
590  // Use every trajectory point if possible
591  if (entry_point >= 0) {
592  // particle trajectory
593  const simb::MCTrajectory &trajectory = particle.Trajectory();
594  TVector3 pos = trajectory.Position(entry_point).Vect();
595  for (unsigned i = entry_point+1; i < particle.NumberTrajectoryPoints(); i++) {
596  TVector3 this_point = trajectory.Position(i).Vect();
597  // get the exit point
598  // update if particle is contained
599  // check if particle has crossed TPC
600  if (!trueparticle.crosses_tpc) {
601  for (unsigned j = 0; j < volumes.size(); j++) {
602  if (volumes[j].ContainsPosition(this_point) && tpc_index >= 0 && j != ((unsigned)tpc_index)) {
603  trueparticle.crosses_tpc = true;
604  break;
605  }
606  }
607  }
608  // check if particle has left tpc
609  if (trueparticle.cont_tpc) {
610  trueparticle.cont_tpc = volumes[tpc_index].ContainsPosition(this_point);
611  }
612 
613  if (trueparticle.contained) {
614  trueparticle.contained = active_volumes.at(cryostat_index).ContainsPosition(this_point);
615  }
616 
617  trueparticle.length += (this_point - pos).Mag();
618 
619  if (!active_volumes.at(cryostat_index).ContainsPosition(this_point) && active_volumes.at(cryostat_index).ContainsPosition(pos)) {
620  exit_point = i-1;
621  }
622 
623  pos = trajectory.Position(i).Vect();
624  }
625  }
626  if (exit_point < 0 && entry_point >= 0) {
627  exit_point = particle.NumberTrajectoryPoints() - 1;
628  }
629  if (exit_point >= 0 && ((unsigned)exit_point) < particle.NumberTrajectoryPoints() - 1) {
630  trueparticle.wallout = (int)caf::GetWallCross(active_volumes.at(cryostat_index), particle.Position(exit_point).Vect(), particle.Position(exit_point+1).Vect());
631  }
632 
633  // other truth information
634  trueparticle.pdg = particle.PdgCode();
635 
636  trueparticle.gen = ConvertTVector(particle.NumberTrajectoryPoints() ? particle.Position().Vect() : TVector3(-9999, -9999, -9999));
637  trueparticle.genT = particle.NumberTrajectoryPoints() ? particle.Position().T() / 1000. /* ns -> us*/: -9999;
638  trueparticle.genp = ConvertTVector(particle.NumberTrajectoryPoints() ? particle.Momentum().Vect(): TVector3(-9999, -9999, -9999));
639  trueparticle.genE = particle.NumberTrajectoryPoints() ? particle.Momentum().E(): -9999;
640 
641  trueparticle.start = ConvertTVector((entry_point >= 0) ? particle.Position(entry_point).Vect(): TVector3(-9999, -9999, -9999));
642  trueparticle.startT = (entry_point >= 0) ? particle.Position(entry_point).T() / 1000. /* ns-> us*/: -9999;
643  trueparticle.end = ConvertTVector((exit_point >= 0) ? particle.Position(exit_point).Vect(): TVector3(-9999, -9999, -9999));
644  trueparticle.endT = (exit_point >= 0) ? particle.Position(exit_point).T() / 1000. /* ns -> us */ : -9999;
645 
646  trueparticle.startp = ConvertTVector((entry_point >= 0) ? particle.Momentum(entry_point).Vect() : TVector3(-9999, -9999, -9999));
647  trueparticle.startE = (entry_point >= 0) ? particle.Momentum(entry_point).E() : -9999.;
648  trueparticle.endp = ConvertTVector((exit_point >= 0) ? particle.Momentum(exit_point).Vect() : TVector3(-9999, -9999, -9999));
649  trueparticle.endE = (exit_point >= 0) ? particle.Momentum(exit_point).E() : -9999.;
650 
651  trueparticle.start_process = (int)caf::GetG4ProcessID(particle.Process());
652  trueparticle.end_process = (int)caf::GetG4ProcessID(particle.EndProcess());
653 
654  trueparticle.G4ID = particle.TrackId();
655  trueparticle.parent = particle.Mother();
656 
657  // Organize deposition info into per-wire true "Hits" -- key is the Channel Number
658  std::map<unsigned, sbn::TrueHit> truehits;
659 
660  for (auto const &ide_pair: particle_ides) {
661  const geo::WireID &w = ide_pair.first;
662  unsigned c = geo->PlaneWireToChannel(w);
663  const sim::IDE *ide = ide_pair.second;
664 
665  // Set stuff
666  truehits[c].cryo = w.Cryostat;
667  truehits[c].tpc = w.TPC;
668  truehits[c].plane = w.Plane;
669  truehits[c].wire = w.Wire;
670  truehits[c].channel = c;
671 
672  // Average stuff using charge-weighting
673  float old_elec = truehits[c].nelec;
674  float new_elec = old_elec + ide->numElectrons;
675  truehits[c].p.x = (truehits[c].p.x*old_elec + ide->x*ide->numElectrons) / new_elec;
676  truehits[c].p.y = (truehits[c].p.y*old_elec + ide->y*ide->numElectrons) / new_elec;
677  truehits[c].p.z = (truehits[c].p.z*old_elec + ide->z*ide->numElectrons) / new_elec;
678 
679  // Also get the position with space charge un-done
680  geo::Point_t ide_p(ide->x, ide->y, ide->z);
681  geo::Point_t ide_p_scecorr = WireToTrajectoryPosition(ide_p, w);
682 
683  truehits[c].p_scecorr.x = (truehits[c].p_scecorr.x*old_elec + ide_p_scecorr.x()*ide->numElectrons) / new_elec;
684  truehits[c].p_scecorr.y = (truehits[c].p_scecorr.y*old_elec + ide_p_scecorr.y()*ide->numElectrons) / new_elec;
685  truehits[c].p_scecorr.z = (truehits[c].p_scecorr.z*old_elec + ide_p_scecorr.z()*ide->numElectrons) / new_elec;
686 
687  // Sum stuff
688  truehits[c].nelec += ide->numElectrons;
689  truehits[c].e += ide->energy;
690  truehits[c].ndep += 1;
691  }
692 
693  // Compute widths
694  for (auto const &ide_pair: particle_ides) {
695  const geo::WireID &w = ide_pair.first;
696  unsigned c = geo->PlaneWireToChannel(w);
697  const sim::IDE *ide = ide_pair.second;
698 
699  geo::Point_t ide_p(ide->x, ide->y, ide->z);
700  geo::Point_t ide_p_scecorr = WireToTrajectoryPosition(ide_p, w);
701 
702  // Average stuff using charge-weighting
703  float this_elec = ide->numElectrons;
704 
705  truehits[c].p_width.x += (ide_p.x() - truehits[c].p.x) * (ide_p.x() - truehits[c].p.x) * this_elec / truehits[c].nelec;
706  truehits[c].p_width.y += (ide_p.y() - truehits[c].p.y) * (ide_p.y() - truehits[c].p.y) * this_elec / truehits[c].nelec;
707  truehits[c].p_width.z += (ide_p.z() - truehits[c].p.z) * (ide_p.z() - truehits[c].p.z) * this_elec / truehits[c].nelec;
708 
709  truehits[c].p_scecorr_width.x += (ide_p_scecorr.x() - truehits[c].p_scecorr.x) * (ide_p_scecorr.x() - truehits[c].p_scecorr.x) * this_elec / truehits[c].nelec;
710  truehits[c].p_scecorr_width.y += (ide_p_scecorr.y() - truehits[c].p_scecorr.y) * (ide_p_scecorr.y() - truehits[c].p_scecorr.y) * this_elec / truehits[c].nelec;
711  truehits[c].p_scecorr_width.z += (ide_p_scecorr.z() - truehits[c].p_scecorr.z) * (ide_p_scecorr.z() - truehits[c].p_scecorr.z) * this_elec / truehits[c].nelec;
712  }
713 
714  // Convert to vector
715  std::vector<sbn::TrueHit> truehits_v;
716  for (auto const &p: truehits) {
717  truehits_v.push_back(p.second);
718  }
719 
720  // Compute the time of each hit
721  for (sbn::TrueHit &h: truehits_v) {
722  h.time = dprop.ConvertXToTicks(h.p.x, h.plane, h.tpc, h.cryo);
723 
724  double xdrift = abs(h.p.x - geo->TPC(h.tpc, h.cryo).PlaneLocation(0)[0]);
725  h.tdrift = xdrift / dprop.DriftVelocity();
726  }
727 
728  // Compute the pitch of each hit and order it in the trajectory
729  for (sbn::TrueHit &h: truehits_v) {
730  // Use the SCE-undone hit since this matches to the Trajectory
731  TVector3 h_p(h.p_scecorr.x, h.p_scecorr.y, h.p_scecorr.z);
732 
733  TVector3 direction;
734  float closest_dist = -1.;
735  int traj_index = -1;
736  for (unsigned i_traj = 0; i_traj < particle.NumberTrajectoryPoints(); i_traj++) {
737  if (closest_dist < 0. || (particle.Position(i_traj).Vect() - h_p).Mag() < closest_dist) {
738  direction = particle.Momentum(i_traj).Vect().Unit();
739  closest_dist = (particle.Position(i_traj).Vect() - h_p).Mag();
740  traj_index = i_traj;
741  }
742  }
743 
744  // If we got a direction, get the pitch
745  if (closest_dist >= 0. && direction.Mag() > 1e-4) {
746  geo::PlaneID plane(h.cryo, h.tpc, h.plane);
747  float angletovert = geo->WireAngleToVertical(geo->View(plane), plane) - 0.5*::util::pi<>();
748  float cosgamma = abs(cos(angletovert) * direction.Z() + sin(angletovert) * direction.Y());
749  float pitch = geo->WirePitch(plane) / cosgamma;
750  h.pitch = pitch;
751  }
752  else {
753  h.pitch = -1.;
754  }
755  // And the pitch induced by SCE
756  if (closest_dist >= 0. && direction.Mag() > 1e-4) {
757  geo::PlaneID plane(h.cryo, h.tpc, h.plane);
758  float angletovert = geo->WireAngleToVertical(geo->View(plane), plane) - 0.5*::util::pi<>();
759 
760  TVector3 loc_mdx_v = h_p - direction * (geo->WirePitch(geo->View(plane) / 2.));
761  TVector3 loc_pdx_v = h_p + direction * (geo->WirePitch(geo->View(plane) / 2.));
762 
763  // Convert types for helper functions
764  geo::Point_t loc_mdx(loc_mdx_v.X(), loc_mdx_v.Y(), loc_mdx_v.Z());
765  geo::Point_t loc_pdx(loc_pdx_v.X(), loc_pdx_v.Y(), loc_pdx_v.Z());
766  geo::Point_t h_p_point(h_p.X(), h_p.Y(), h_p.Z());
767 
768  loc_mdx = TrajectoryToWirePosition(loc_mdx, plane);
769  loc_pdx = TrajectoryToWirePosition(loc_pdx, plane);
770 
771  // Direction at wires
772  geo::Vector_t dir = (loc_pdx - loc_mdx) / (loc_mdx - loc_pdx).r();
773 
774  // Pitch at wires
775  double cosgamma = std::abs(std::sin(angletovert)*dir.Y() + std::cos(angletovert)*dir.Z());
776  double pitch;
777  if (cosgamma) {
778  pitch = geo->WirePitch(geo->View(plane))/cosgamma;
779  }
780  else {
781  pitch = 0.;
782  }
783 
784  // Now bring that back to the particle trajectory
785  geo::Point_t loc_w = TrajectoryToWirePosition(h_p_point, plane);
786 
787  geo::Point_t locw_pdx_traj = WireToTrajectoryPosition(loc_w + pitch*dir, plane);
788  geo::Point_t loc = WireToTrajectoryPosition(loc_w, plane);
789 
790  h.pitch_sce = (locw_pdx_traj - loc).R();
791  }
792  else {
793  h.pitch_sce = -1.;
794  }
795 
796  // And the trajectory location
797  h.itraj = traj_index;
798 
799  // And the residual range of the hit
800  h.rr = 0.;
801  if (traj_index >= 0) {
802  for (int i_traj = traj_index+1; i_traj < (int)particle.NumberTrajectoryPoints(); i_traj++) {
803  h.rr += (particle.Position(i_traj).Vect() - particle.Position(i_traj-1).Vect()).Mag();
804  }
805 
806  // Also account for the distance from the Hit point to the matched trajectory point
807  double hit_distance_along_particle = (h_p - particle.Position(traj_index).Vect()).Dot(particle.Momentum(traj_index).Vect().Unit());
808  h.rr += -hit_distance_along_particle;
809 
810  }
811  }
812 
813  // Order the hits by their location along the trajectory, start to end
814  std::sort(truehits_v.begin(), truehits_v.end(),
815  [](auto const &lhs, auto const &rhs) {
816  return lhs.itraj < rhs.itraj;
817  });
818 
819  // Save depositions into the True Particle
820  for (sbn::TrueHit &h: truehits_v) {
821  if (h.plane == 0) {
822  trueparticle.truehits0.push_back(h);
823  }
824  else if (h.plane == 1) {
825  trueparticle.truehits1.push_back(h);
826  }
827  else if (h.plane == 2) {
828  trueparticle.truehits2.push_back(h);
829  }
830  }
831 
832  return trueparticle;
833 }
834 
836  const detinfo::DetectorPropertiesData &dprop,
837  const recob::Track &track,
838  const std::vector<art::Ptr<recob::Hit>> &allHits,
839  const art::FindManyP<recob::SpacePoint> &allHitSPs) {
840 
841  (void) dprop; // TODO: use??
842 
843  geo::TPCID tpc_end = geometry->FindTPCAtPosition(track.End());
844  if (!tpc_end) return;
845 
846  geo::PlaneID plane_end(tpc_end, 2 /* collection */);
847 
848  float end_w = geometry->WireCoordinate(track.End(), plane_end);
849 
850  float end_t = -1000.;
851  float closest_wire_dist = -1.;
852  // Get the hit closest to the end to get the end time
853  for (const TrackHitInfo &h: fTrack->hits2) {
854  if (h.oncalo && (closest_wire_dist < 0. || abs(h.h.wire - end_w) < closest_wire_dist)) {
855  closest_wire_dist = abs(h.h.wire - end_w);
856  end_t = h.h.time;
857  }
858  }
859 
860  for (const art::Ptr<recob::Hit> &hit: allHits) {
861  geo::PlaneID h_p = hit->WireID();
862  if (h_p != plane_end) continue;
863 
864  // Inside the box?
865  float h_w = (float)hit->WireID().Wire;
866  float h_t = hit->PeakTime();
867 
868  if (abs(h_w - end_w) < fTrackEndHitWireBox &&
869  abs(h_t - end_t) < fTrackEndHitTimeBox) {
870 
871  // HitInfo to save
872  sbn::HitInfo hinfo;
873 
874  // information from the hit object
875  hinfo.integral = hit->Integral();
876  hinfo.sumadc = hit->SummedADC();
877  hinfo.width = hit->RMS();
878  hinfo.time = hit->PeakTime();
879  hinfo.mult = hit->Multiplicity();
880  hinfo.wire = hit->WireID().Wire;
881  hinfo.plane = hit->WireID().Plane;
882  hinfo.tpc = hit->WireID().TPC;
883  hinfo.end = hit->EndTick();
884  hinfo.start = hit->StartTick();
885  hinfo.id = hit.key();
886 
887  const std::vector<art::Ptr<recob::SpacePoint>> &h_sp = allHitSPs.at(hit.key());
888  if (h_sp.size()) {
889  const recob::SpacePoint &sp = *h_sp[0];
890  hinfo.sp.x = sp.position().x();
891  hinfo.sp.y = sp.position().y();
892  hinfo.sp.z = sp.position().z();
893 
894  hinfo.hasSP = true;
895  }
896  else {
897  hinfo.hasSP = false;
898  }
899 
900  fTrack->endhits.push_back(hinfo);
901 
902  }
903  }
904 
905 }
906 
908  const std::vector<art::Ptr<recob::Hit>> &trkHits,
909  const std::vector<art::Ptr<simb::MCParticle>> &mcparticles,
910  const std::vector<geo::BoxBoundedGeo> &active_volumes,
911  const std::vector<std::vector<geo::BoxBoundedGeo>> &tpc_volumes,
912  const std::map<int, std::vector<std::pair<geo::WireID, const sim::IDE*>>> id_to_ide_map,
913  const std::map<int, std::vector<art::Ptr<recob::Hit>>> id_to_truehit_map,
914  const detinfo::DetectorPropertiesData &dprop,
915  const geo::GeometryCore *geo) {
916 
917  // Lookup the true-particle match -- use utils in CAF
918  std::vector<std::pair<int, float>> matches = CAFRecoUtils::AllTrueParticleIDEnergyMatches(clock_data, trkHits, true);
919  float total_energy = CAFRecoUtils::TotalHitEnergy(clock_data, trkHits);
920 
921  fTrack->truth.depE = total_energy / 1000. /* MeV -> GeV */;
922 
923  // sort highest energy match to lowest
924  std::sort(matches.begin(), matches.end(),
925  [](const auto &a, const auto &b) {
926  return a.second > b.second;
927  }
928  );
929 
930  // Save the best match
931  if (matches.size()) {
932  std::pair<int, float> bestmatch = matches[0];
933 
934  fTrack->truth.pur = bestmatch.second / total_energy;
935 
936  for (const art::Ptr<simb::MCParticle> &p_mcp: mcparticles) {
937  if (p_mcp->TrackId() == bestmatch.first) {
938  if (fVerbose) std::cout << "Matched! Track ID: " << p_mcp->TrackId() << " pdg: " << p_mcp->PdgCode() << " process: " << p_mcp->EndProcess() << std::endl;
939  fTrack->truth.p = TrueParticleInfo(*p_mcp, active_volumes, tpc_volumes, id_to_ide_map, id_to_truehit_map, dprop, geo);
940  fTrack->truth.eff = fTrack->truth.depE / (fTrack->truth.p.plane0VisE + fTrack->truth.p.plane1VisE + fTrack->truth.p.plane2VisE);
941 
942  // Lookup any Michel
943  for (const art::Ptr<simb::MCParticle> &d_mcp: mcparticles) {
944  if (d_mcp->Mother() == p_mcp->TrackId() && // correct parent
945  (d_mcp->Process() == "Decay" || d_mcp->Process() == "muMinusCaptureAtRest") && // correct process
946  abs(d_mcp->PdgCode()) == 11) { // correct PDG code
947 
948  fTrack->truth.michel = TrueParticleInfo(*d_mcp, active_volumes, tpc_volumes, id_to_ide_map, id_to_truehit_map, dprop, geo);
949  break;
950  }
951  }
952 
953  break;
954  }
955  }
956  }
957 }
958 
959 
961  const recob::PFParticle &pfp,
962  const std::vector<art::Ptr<recob::PFParticle>> &PFParticleList,
963  const art::FindManyP<recob::SpacePoint> &PFParticleSPs) {
964 
965  for (unsigned d: pfp.Daughters()) {
966  const recob::PFParticle &d_pfp = *PFParticleList[d];
967 
968  fTrack->daughter_pdg.push_back(d_pfp.PdgCode());
969 
970  unsigned nsp = 0;
971  float min_distance = -1.;
972  for (const art::Ptr<recob::SpacePoint> &sp: PFParticleSPs.at(d)) {
973  if (min_distance < 0. || (sp->position() - trk.End()).r() < min_distance) {
974  min_distance = (sp->position() - trk.End()).r();
975  }
976  nsp++;
977  }
978 
979  fTrack->daughter_sp_toend_dist.push_back(min_distance);
980  fTrack->daughter_nsp.push_back(nsp);
981  }
982 
983 }
984 
986  const recob::PFParticle &pfp, float t0,
987  const std::vector<art::Ptr<recob::Hit>> &hits,
988  const std::vector<const recob::TrackHitMeta*> &thms,
989  const std::vector<art::Ptr<recob::SpacePoint>> &sps,
990  const std::vector<art::Ptr<anab::Calorimetry>> &calo,
991  const std::map<geo::WireID, art::Ptr<raw::RawDigit>> &rawdigits,
992  const std::vector<GlobalTrackInfo> &tracks,
993  const geo::GeometryCore *geo,
994  const detinfo::DetectorClocksData &clock_data,
995  const cheat::BackTrackerService *bt_serv,
996  const sbn::EDet det) {
997 
998  // Fill top level stuff
999  fTrack->meta = fMeta;
1000  fTrack->t0 = t0;
1001  fTrack->id = track.ID();
1002  fTrack->clear_cosmic_muon = pfp.Parent() == recob::PFParticle::kPFParticlePrimary;
1003 
1004  fTrack->length = track.Length();
1005  fTrack->start.x = track.Start().X();
1006  fTrack->start.y = track.Start().Y();
1007  fTrack->start.z = track.Start().Z();
1008  fTrack->end.x = track.End().X();
1009  fTrack->end.y = track.End().Y();
1010  fTrack->end.z = track.End().Z();
1011  fTrack->dir.x = track.StartDirection().X();
1012  fTrack->dir.y = track.StartDirection().Y();
1013  fTrack->dir.z = track.StartDirection().Z();
1014 
1015  if (hits.size() > 0) {
1016  fTrack->cryostat = hits[0]->WireID().Cryostat;
1017  }
1018 
1019  // Fill each hit
1020  for (unsigned i_hit = 0; i_hit < hits.size(); i_hit++) {
1021  sbn::TrackHitInfo hinfo = MakeHit(*hits[i_hit], hits[i_hit].key(), *thms[i_hit], track, sps[i_hit], calo, geo, clock_data, bt_serv);
1022  if (hinfo.h.plane == 0) {
1023  fTrack->hits0.push_back(hinfo);
1024  }
1025  else if (hinfo.h.plane == 1) {
1026  fTrack->hits1.push_back(hinfo);
1027  }
1028  else if (hinfo.h.plane == 2) {
1029  fTrack->hits2.push_back(hinfo);
1030  }
1031  }
1032 
1033  // Hit summary info
1034  fTrack->hit_min_time_p0_tpcE = HitMinTime(fTrack->hits0, true, det);
1035  fTrack->hit_max_time_p0_tpcE = HitMaxTime(fTrack->hits0, true, det);
1036  fTrack->hit_min_time_p0_tpcW = HitMinTime(fTrack->hits0, false, det);
1037  fTrack->hit_max_time_p0_tpcW = HitMaxTime(fTrack->hits0, false, det);
1038  fTrack->hit_min_time_p1_tpcE = HitMinTime(fTrack->hits1, true, det);
1039  fTrack->hit_max_time_p1_tpcE = HitMaxTime(fTrack->hits1, true, det);
1040  fTrack->hit_min_time_p1_tpcW = HitMinTime(fTrack->hits1, false, det);
1041  fTrack->hit_max_time_p1_tpcW = HitMaxTime(fTrack->hits1, false, det);
1042  fTrack->hit_min_time_p2_tpcE = HitMinTime(fTrack->hits2, true, det);
1043  fTrack->hit_max_time_p2_tpcE = HitMaxTime(fTrack->hits2, true, det);
1044  fTrack->hit_min_time_p2_tpcW = HitMinTime(fTrack->hits2, false, det);
1045  fTrack->hit_max_time_p2_tpcW = HitMaxTime(fTrack->hits2, false, det);
1046 
1047  // Save information on a fit to the end of the track
1048  if (fDoTailFit) DoTailFit();
1049 
1050  // Save the Wire ADC values we need to
1051  for (auto const &w_pair: fWiresToSave) {
1052  geo::WireID wire = w_pair.first;
1053 
1054  if (rawdigits.count(wire)) {
1055  const raw::RawDigit &thisdigit = *rawdigits.at(wire);
1056  int min_tick = std::max(0, w_pair.second.first);
1057  int max_tick = std::min((int)thisdigit.NADC(), w_pair.second.second);
1058 
1059  // collect the adcs
1060  std::vector<short> adcs;
1061  for (int t = min_tick; t < max_tick; t++) {
1062  adcs.push_back(thisdigit.ADC(t));
1063  }
1064 
1065  WireInfo winfo;
1066  winfo.wire = wire.Wire;
1067  winfo.plane = wire.Plane;
1068  winfo.tpc = wire.TPC;
1069  winfo.channel = geo->PlaneWireToChannel(wire);
1070  winfo.tdc0 = min_tick;
1071  winfo.adcs = adcs;
1072 
1073  if (winfo.plane == 0) {
1074  fTrack->wires0.push_back(winfo);
1075  }
1076  else if (winfo.plane == 1) {
1077  fTrack->wires1.push_back(winfo);
1078  }
1079  else if (winfo.plane == 2) {
1080  fTrack->wires2.push_back(winfo);
1081  }
1082  }
1083  }
1084  // Sort the ADC values by wire
1085  std::sort(fTrack->wires0.begin(), fTrack->wires0.end(), [](auto const &lhs, auto const &rhs) {return lhs.wire < rhs.wire;});
1086  std::sort(fTrack->wires1.begin(), fTrack->wires1.end(), [](auto const &lhs, auto const &rhs) {return lhs.wire < rhs.wire;});
1087  std::sort(fTrack->wires2.begin(), fTrack->wires2.end(), [](auto const &lhs, auto const &rhs) {return lhs.wire < rhs.wire;});
1088 
1089  // get information on nearby tracks
1090  for (const GlobalTrackInfo &othr: tracks) {
1091  if (othr.ID == track.ID()) continue;
1092 
1093  if ((track.End() - othr.start).r() < 50. || (track.End() - othr.end).r() < 50.) {
1094  fTrack->tracks_near_end_dist.push_back(std::min((track.End() - othr.start).r(), (track.End() - othr.end).r()));
1095  fTrack->tracks_near_end_costh.push_back(
1096  (track.End() - othr.start).r() < (track.End() - othr.end).r() ?
1097  track.EndDirection().Dot(othr.dir) : track.EndDirection().Dot(othr.enddir));
1098  }
1099  }
1100 
1101  for (const GlobalTrackInfo &othr: tracks) {
1102  if (othr.ID == track.ID()) continue;
1103 
1104  if ((track.Start() - othr.start).r() < 50. || (track.Start() - othr.end).r() < 50.) {
1105  fTrack->tracks_near_start_dist.push_back(std::min((track.Start() - othr.start).r(), (track.Start() - othr.end).r()));
1106  fTrack->tracks_near_start_costh.push_back(
1107  (track.Start() - othr.start).r() < (track.Start() - othr.end).r() ?
1108  track.StartDirection().Dot(othr.dir) : track.StartDirection().Dot(othr.enddir));
1109  }
1110  }
1111 
1112 }
1113 
1115  // Try fitting the constant and exponentials to the tail of dQ/dx v. RR on the collection plane
1116  std::vector<double> fit_rr;
1117  std::vector<double> fit_dqdx;
1118 
1119  for (const TrackHitInfo &h: fTrack->hits2) {
1120  if (h.oncalo && h.rr > 0. && h.rr < fTailFitResidualRange) {
1121  fit_rr.push_back(h.rr);
1122  fit_dqdx.push_back(h.dqdx);
1123  }
1124  }
1125 
1126  // TODO: should we throw an exception here??
1127  //
1128  // If there is too much data to fit in the array, throw exception
1129  if (fit_rr.size() > MAX_N_FIT_DATA) {
1130  throw cet::exception("sbn::TrackCaloSkimmer::DoTailFit: More fitting points required ("
1131  + std::to_string(fit_rr.size()) + ") than available in fit array (" + std::to_string(MAX_N_FIT_DATA) + ").\n");
1132  }
1133 
1134  // Copy the fit data to the global array
1135  for (unsigned i = 0; i < fit_rr.size() && i < MAX_N_FIT_DATA; i++) {
1136  FIT_RR[i] = fit_rr[i];
1137  FIT_DQDX[i] = fit_dqdx[i];
1138  }
1139  N_FIT_DATA = std::min(fit_rr.size(), MAX_N_FIT_DATA);
1140 
1141  fTrack->n_fit_point = N_FIT_DATA;
1142  if (fTrack->n_fit_point > 2) { // need more points than params
1143  // Fit the Exponential
1144  fFitExp.SetFCN(ExpResiduals);
1145  fFitExp.SetParameter(0, "A", *std::max_element(fit_dqdx.begin(), fit_dqdx.end()), 200, 0, 5000);
1146  fFitExp.SetParameter(1, "R", 10., 0.5, 0, 1000);
1147  fFitExp.ExecuteCommand("MIGRAD", 0, 0);
1148 
1149  double A = fFitExp.GetParameter(0);
1150  double R = fFitExp.GetParameter(1);
1151 
1152  int nparam;
1153  double param[2] {A, R};
1154  double residuals = -1;
1155  ExpResiduals(nparam, NULL, residuals, param, 0);
1156 
1157  fTrack->exp_fit_A = A;
1158  fTrack->exp_fit_R = R;
1159  fTrack->exp_fit_residuals = residuals;
1160 
1161  // Fit the Constant
1162  fFitConst.SetFCN(ConstResiduals);
1163  fFitConst.SetParameter(0, "C", std::accumulate(fit_dqdx.begin(), fit_dqdx.end(), 0.), 200, 0, 5000);
1164  fFitConst.ExecuteCommand("MIGRAD", 0, 0);
1165 
1166  double C = fFitConst.GetParameter(0);
1167 
1168  double cresiduals = -1;
1169  ConstResiduals(nparam, NULL, cresiduals, &C, 0);
1170 
1171  fTrack->const_fit_C = C;
1172  fTrack->const_fit_residuals = cresiduals;
1173  }
1174 }
1175 
1176 
1178  unsigned hkey,
1179  const recob::TrackHitMeta &thm,
1180  const recob::Track &trk,
1181  const art::Ptr<recob::SpacePoint> &sp,
1182  const std::vector<art::Ptr<anab::Calorimetry>> &calo,
1183  const geo::GeometryCore *geo,
1184  const detinfo::DetectorClocksData &dclock,
1185  const cheat::BackTrackerService *bt_serv) {
1186 
1187  // TrackHitInfo to save
1188  sbn::TrackHitInfo hinfo;
1189 
1190  // information from the hit object
1191  hinfo.h.integral = hit.Integral();
1192  hinfo.h.sumadc = hit.SummedADC();
1193  hinfo.h.width = hit.RMS();
1194  hinfo.h.time = hit.PeakTime();
1195  hinfo.h.mult = hit.Multiplicity();
1196  hinfo.h.wire = hit.WireID().Wire;
1197  hinfo.h.plane = hit.WireID().Plane;
1198  hinfo.h.channel = geo->PlaneWireToChannel(hit.WireID());
1199  hinfo.h.tpc = hit.WireID().TPC;
1200  hinfo.h.end = hit.EndTick();
1201  hinfo.h.start = hit.StartTick();
1202  hinfo.h.id = (int)hkey;
1203 
1204  // Do back-tracking on each hit
1205  if (bt_serv) {
1206  // The default BackTracking function goes from (peak - width, peak + width).
1207  //
1208  // This time range does not match well hits with a non-Gaussian shape where
1209  // the Gaussian-fit-width does not replicate the width of the pulse.
1210  //
1211  // Instead, we use the Hit (start, end) time range. This is also more relevant
1212  // for (e.g.) the SummedADC charge extraction method.
1213  //
1214  // Don't use this:
1215  // std::vector<sim::TrackIDE> ides = bt_serv->HitToTrackIDEs(dclock, hit);
1216  //
1217  // Use this:
1218  std::vector<sim::TrackIDE> ides = bt_serv->ChannelToTrackIDEs(dclock, hit.Channel(), hit.StartTick(), hit.EndTick());
1219 
1220  hinfo.h.truth.e = 0.;
1221  hinfo.h.truth.nelec = 0.;
1222 
1223  for (const sim::TrackIDE &ide: ides) {
1224  hinfo.h.truth.e += ide.energy;
1225  hinfo.h.truth.nelec += ide.numElectrons;
1226  }
1227  }
1228  else {
1229  hinfo.h.truth.e = -1.;
1230  hinfo.h.truth.nelec = -1.;
1231  }
1232 
1233  // look up the snippet
1234  sbn::TrackCaloSkimmer::Snippet snippet {hit.WireID(), hit.StartTick(), hit.EndTick()};
1235  if (!fSnippetCount.count(snippet)) {
1236  fSnippetCount[snippet] = 0;
1237  hinfo.i_snippet = 0;
1238  }
1239  else {
1240  fSnippetCount[snippet] ++;
1241  hinfo.i_snippet = fSnippetCount[snippet];
1242  }
1243 
1244  // Which wires to save
1245  int min_tick = (int)std::floor(hit.PeakTime() - fHitRawDigitsTickCollectWidth);
1246  int max_tick = (int)std::ceil(hit.PeakTime() + fHitRawDigitsTickCollectWidth);
1247  for (int wire = hinfo.h.wire - fHitRawDigitsWireCollectWidth; wire <= hinfo.h.wire + fHitRawDigitsWireCollectWidth; wire++) {
1248  geo::WireID w(hit.WireID(), wire);
1249 
1250  if (fWiresToSave.count(w)) {
1251  fWiresToSave.at(w).first = std::min(fWiresToSave.at(w).first, min_tick);
1252  fWiresToSave.at(w).second = std::max(fWiresToSave.at(w).second, max_tick);
1253  }
1254  else {
1255  fWiresToSave[w] = {min_tick, max_tick};
1256  }
1257  }
1258 
1259  // Information from the TrackHitMeta
1260  bool badhit = (thm.Index() == std::numeric_limits<unsigned int>::max()) ||
1261  (!trk.HasValidPoint(thm.Index()));
1262 
1263  hinfo.ontraj = !badhit;
1264 
1265  // Save trajectory information if we can
1266  if (!badhit) {
1267  geo::Point_t loc = trk.LocationAtPoint(thm.Index());
1268  hinfo.tp.x = loc.X();
1269  hinfo.tp.y = loc.Y();
1270  hinfo.tp.z = loc.Z();
1271 
1272  geo::Vector_t dir = trk.DirectionAtPoint(thm.Index());
1273  hinfo.dir.x = dir.X();
1274  hinfo.dir.y = dir.Y();
1275  hinfo.dir.z = dir.Z();
1276 
1277  // And determine if the Hit is on a Calorimetry object
1278  for (const art::Ptr<anab::Calorimetry> &c: calo) {
1279  if (c->PlaneID().Plane != hinfo.h.plane) continue;
1280 
1281  // Found the plane! Now find the hit:
1282  for (unsigned i_calo = 0; i_calo < c->dQdx().size(); i_calo++) {
1283  if (c->TpIndices()[i_calo] == hkey) { // "TpIndices" match to the hit key
1284  // Fill the calo information associated with the hit
1285  hinfo.oncalo = true;
1286  hinfo.pitch = c->TrkPitchVec()[i_calo];
1287  hinfo.dqdx = c->dQdx()[i_calo];
1288  hinfo.rr = c->ResidualRange()[i_calo];
1289  break;
1290  }
1291  }
1292  break;
1293  }
1294  }
1295 
1296  // Save SpacePoint information
1297  if (sp) {
1298  hinfo.h.sp.x = sp->position().x();
1299  hinfo.h.sp.y = sp->position().y();
1300  hinfo.h.sp.z = sp->position().z();
1301 
1302  hinfo.h.hasSP = true;
1303  }
1304  else {
1305  hinfo.h.hasSP = false;
1306  }
1307 
1308  return hinfo;
1309 }
1310 
1311 DEFINE_ART_MODULE(sbn::TrackCaloSkimmer)
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
void analyze(art::Event const &e) override
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
std::map< int, std::vector< std::pair< geo::WireID, const sim::IDE * > > > PrepSimChannels(const std::vector< art::Ptr< sim::SimChannel >> &simchannels, const geo::GeometryCore &geo)
Definition: FillTrue.cxx:685
const std::vector< size_t > & Daughters() const
Returns the collection of daughter particles.
Definition: PFParticle.h:114
int end_process
End G4 process of the particle. Values defined as enum in StandardRecord.
float z
z position of ionization [cm]
Definition: SimChannel.h:121
BEGIN_PROLOG TPC Trig offset(g4 rise time) ProjectToHeight
Definition: CORSIKAGen.fcl:7
unsigned int event
Definition: DataStructs.h:634
sbn::Vector3D ConvertTVector(const TVector3 &tv)
Collection of charge vs time digitized from a single readout channel.
Definition: RawDigit.h:69
int wallout
Wall of cryostat particle exits (wNone if stopping in detector)
ClusterModuleLabel join with tracks
static double FIT_RR[MAX_N_FIT_DATA]
short ADC(int i) const
ADC vector element number i; no decompression is applied.
Definition: RawDigit.h:208
const geo::GeometryCore * geometry
uint16_t plane
Plane number.
Vector3D endp
Momentum at last point in the active TPC volume [GeV/c].
Vector3D sp
Space-Point Position of hit [cm].
uint16_t tpc
TPC number of hit.
static constexpr size_t kPFParticlePrimary
Define index to signify primary particle.
Definition: PFParticle.h:61
Vector3D genp
Momentum at generation point [GeV/c].
then echo unknown compiler flag
HitInfo h
Hit information by itself.
geo::WireID WireID() const
Definition: Hit.h:233
float RMS() const
RMS of the hit shape, in tick units.
Definition: Hit.h:220
Vector3D gen
Generation position [cm].
int id
ID of hit.
Point_t const & LocationAtPoint(size_t i) const
void ConstResiduals(int &npar, double *g, double &result, double *par, int flag)
pdgs p
Definition: selectors.fcl:22
void FillTrackEndHits(const geo::GeometryCore *geometry, const detinfo::DetectorPropertiesData &dprop, const recob::Track &track, const std::vector< art::Ptr< recob::Hit >> &allHits, const art::FindManyP< recob::SpacePoint > &allHitSPs)
float HitMinTime(const std::vector< sbn::TrackHitInfo > &hits, bool TPCE, sbn::EDet det)
uint16_t channel
Channel number of hit.
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
Geometry information for a single TPC.
Definition: TPCGeo.h:38
geo::Point_t position() const
Returns the position of the point in world coordinates [cm].
Definition: SpacePoint.h:80
bool HasValidPoint(size_t i) const
geo::BoxBoundedGeo const & ActiveBoundingBox() const
Returns the box of the active volume of this TPC.
Definition: TPCGeo.h:320
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
int PdgCode() const
Return the type of particle as a PDG ID.
Definition: PFParticle.h:83
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:224
int16_t tdc0
TDC tick of the first ADC value.
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
process_name use argoneut_mc_hitfinder track
uint16_t plane
Plane number of hit.
void FillTrackDaughterRays(const recob::Track &trk, const recob::PFParticle &pfp, const std::vector< art::Ptr< recob::PFParticle >> &PFParticleList, const art::FindManyP< recob::SpacePoint > &PFParticleSPs)
float integral
Integral of gaussian fit to ADC values in hit [ADC].
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
float pitch
Pitch of track across wire the hit is on [cm].
void ExpResiduals(int &npar, double *g, double &result, double *par, int flag)
std::vector< TrueHit > truehits0
List of True &quot;hits&quot; of this particle on Plane 0.
BEGIN_PROLOG g
short int Multiplicity() const
How many hits could this one be shared with.
Definition: Hit.h:226
float x
x position of ionization [cm]
Definition: SimChannel.h:119
unsigned plane1nhit
Number of hits on plane 1 (2nd Ind.)
int wallin
Wall of cryostat particle enters (wNone if starting in detector)
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
BEGIN_PROLOG TPC
std::vector< TrueHit > truehits2
List of True &quot;hits&quot; of this particle on Plane 2.
uint16_t mult
Multiplicity of hit.
Vector3D dir
Direction of track at hit location.
void FillTrackTruth(const detinfo::DetectorClocksData &clock_data, const std::vector< art::Ptr< recob::Hit >> &trkHits, const std::vector< art::Ptr< simb::MCParticle >> &mcparticles, const std::vector< geo::BoxBoundedGeo > &active_volumes, const std::vector< std::vector< geo::BoxBoundedGeo >> &tpc_volumes, const std::map< int, std::vector< std::pair< geo::WireID, const sim::IDE * >>> id_to_ide_map, const std::map< int, std::vector< art::Ptr< recob::Hit >>> id_to_truehit_map, const detinfo::DetectorPropertiesData &dprop, const geo::GeometryCore *geo)
uint16_t wire
Wire number of hit.
TPC_iterator begin_TPC() const
Returns an iterator pointing to the first TPC in the detector.
float genE
Energy at generation pt [GeV].
int16_t start
Start tick of hit [ticks].
float dqdx
Initial computed dq/dx of hit [ADC/cm].
process_name gaushit a
while getopts h
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
sbn::TrueParticle TrueParticleInfo(const simb::MCParticle &particle, const std::vector< geo::BoxBoundedGeo > &active_volumes, const std::vector< std::vector< geo::BoxBoundedGeo >> &tpc_volumes, const std::map< int, std::vector< std::pair< geo::WireID, const sim::IDE * >>> &id_to_ide_map, const std::map< int, std::vector< art::Ptr< recob::Hit >>> &id_to_truehit_map, const detinfo::DetectorPropertiesData &dprop, const geo::GeometryCore *geo)
process_name can override from command line with o or output calo
Definition: pid.fcl:40
std::string GDMLFile() const
Returns the full directory path to the GDML file source.
std::vector< std::pair< int, float > > AllTrueParticleIDEnergyMatches(const detinfo::DetectorClocksData &clockData, const std::vector< art::Ptr< recob::Hit > > &hits, bool rollup_unsaved_ids=1)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
const size_t MAX_N_FIT_DATA
T abs(T value)
TrackHitInfo MakeHit(const recob::Hit &hit, unsigned hkey, const recob::TrackHitMeta &thm, const recob::Track &trk, const art::Ptr< recob::SpacePoint > &sp, const std::vector< art::Ptr< anab::Calorimetry >> &calo, const geo::GeometryCore *geo, const detinfo::DetectorClocksData &dclock, const cheat::BackTrackerService *bt_serv)
geo::Point_t WireToTrajectoryPosition(const geo::Point_t &loc, const geo::TPCID &tpc)
unsigned plane0nhit
Number of hits on plane 0 (1st Ind.)
float plane2VisE
Sum of energy deposited on plane 2 (Col.) [GeV].
Vector_t StartDirection() const
Access to track direction at different points.
double Length(size_t p=0) const
Access to various track properties.
static double FIT_DQDX[MAX_N_FIT_DATA]
TrackCaloSkimmer(fhicl::ParameterSet const &p)
void FillTrack(const recob::Track &track, const recob::PFParticle &pfp, float t0, const std::vector< art::Ptr< recob::Hit >> &hits, const std::vector< const recob::TrackHitMeta * > &thms, const std::vector< art::Ptr< recob::SpacePoint >> &sps, const std::vector< art::Ptr< anab::Calorimetry >> &calo, const std::map< geo::WireID, art::Ptr< raw::RawDigit >> &rawdigits, const std::vector< GlobalTrackInfo > &tracks, const geo::GeometryCore *geo, const detinfo::DetectorClocksData &clock_data, const cheat::BackTrackerService *bt_serv, const sbn::EDet det)
uint16_t channel
Channel number.
std::string DetectorName() const
Returns a string with the name of the detector, as configured.
Point_t const & Start() const
Access to track position at different points.
Vector3D tp
Track Trajectory position of hit [cm].
caf::g4_process_ GetG4ProcessID(const std::string &name)
Definition: FillTrue.cxx:1094
Ionization at a point of the TPC sensitive volume.
Definition: SimChannel.h:86
size_t Parent() const
Definition: PFParticle.h:96
bool contained
Whether the particle is contained in a single active volume.
float endT
End time last point in the active [mus – t=0 is spill time].
Vector3D start
Start position in the active TPC volume [cm].
bool crosses_tpc
Whether the particle crosses a TPC boundary.
bool cont_tpc
Whether the particle is contained in a single TPC.
float energy
energy deposited by ionization by this track ID and time [MeV]
Definition: SimChannel.h:118
std::vector< TrueHit > truehits1
List of True &quot;hits&quot; of this particle on Plane 1.
size_t NADC() const
Number of elements in the compressed ADC sample vector.
Definition: RawDigit.h:207
double ConvertXToTicks(double X, int p, int t, int c) const
static int N_FIT_DATA
geo::Point_t TrajectoryToWirePosition(const geo::Point_t &loc, const geo::TPCID &tpc)
float time
Peak time of hit [ticks].
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
j template void())
Definition: json.hpp:3108
Description of geometry of one entire detector.
float sumadc
&quot;SummedADC&quot; – sum of ADC values under gaussian fit [ADC]
raw::TDCtick_t StartTick() const
Initial tdc tick for hit.
Definition: Hit.h:216
View_t View(geo::PlaneID const &pid) const
Returns the view (wire orientation) on the channels of specified TPC plane.
float plane1VisE
Sum of energy deposited on plane 1 (2nd Ind.) [GeV].
float rr
Residual range of hit along track [cm].
float endE
Energy at last pt in active TPC volume [GeV].
Vector3D end
End position in the active TPC volume [cm].
float startT
Start time of first TPC point [mus – t=0 is spill time].
tuple dir
Definition: dropbox.py:28
float y
y position of ionization [cm]
Definition: SimChannel.h:120
raw::TDCtick_t EndTick() const
Final tdc tick for hit.
Definition: Hit.h:217
IteratorBox< cryostat_iterator,&GeometryCore::begin_cryostat,&GeometryCore::end_cryostat > IterateCryostats() const
Enables ranged-for loops on all cryostats of the detector.
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 HitMaxTime(const std::vector< sbn::TrackHitInfo > &hits, bool TPCE, sbn::EDet det)
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
void FillTrackTruth(const std::vector< art::Ptr< recob::Hit >> &hits, const std::map< int, caf::HitsEnergy > &id_hits_map, const std::vector< caf::SRTrueParticle > &particles, const detinfo::DetectorClocksData &clockData, caf::SRTrack &srtrack, bool allowEmpty)
Definition: FillTrue.cxx:118
Contains all timing reference information for the detector.
float length
Trajectory length in active TPC volume the particle first enters [cm].
std::string to_string(WindowPattern const &pattern)
std::map< int, std::vector< art::Ptr< recob::Hit > > > PrepTrueHits(const std::vector< art::Ptr< recob::Hit >> &allHits, const detinfo::DetectorClocksData &clockData, const cheat::BackTrackerService &backtracker)
Definition: FillTrue.cxx:674
Vector_t EndDirection() const
uint16_t i_snippet
Index of hit into snippet.
float startE
Energy at first pt in active TPC volume [GeV].
float plane0VisE
Sum of energy deposited on plane 0 (1st Ind.) [GeV].
bool hasSP
Whether the hit has a SpacePoint.
do i e
float genT
Start time of gen point [mus – t=0 is spill time].
unsigned plane2nhit
Number of hits on plane 2 (Col.)
int G4ID
ID of the particle (taken from G4 – -1 if this particle is not propogated by G4)
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
Point_t const & End() const
float TotalHitEnergy(const detinfo::DetectorClocksData &clockData, const std::vector< art::Ptr< recob::Hit > > &hits)
Vector_t DirectionAtPoint(size_t i) const
int pdg
Particle ID code.
TPCGeo const & TPC(unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified TPC.
float width
Width of fitted gaussian hit [ticks].
uint16_t wire
Wire number.
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
art::ServiceHandle< art::TFileService > tfs
TCEvent evt
Definition: DataStructs.cxx:8
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
float A
Definition: dedx.py:137
Forward iterator browsing all geometry elements in the detector.
Definition: GeometryCore.h:727
int16_t end
End tick of hit [ticks].
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
uint16_t tpc
TPC number.
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
Ionization energy from a Geant4 track.
Definition: SimChannel.h:26
esac echo uname r
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:230
int start_process
Start G4 process of the particle. Values defned as enum in StandardRecord.
bool oncalo
Whether the hit is on the track calorimetry.
const double * PlaneLocation(unsigned int p) const
Definition: TPCGeo.cxx:382
bool ontraj
Whether the hit is on the track trajectory.
double WireAngleToVertical(geo::View_t view, geo::TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
std::vector< short > adcs
List of ADC values.
BEGIN_PROLOG could also be cout
Track from a non-cascading particle.A recob::Track consists of a recob::TrackTrajectory, plus additional members relevant for a &quot;fitted&quot; track:
std::vector< sim::TrackIDE > ChannelToTrackIDEs(detinfo::DetectorClocksData const &clockData, raw::ChannelID_t channel, const double hit_start_time, const double hit_end_time) const
int parent
ID of parent particle.
float numElectrons
number of electrons at the readout for this track ID and time
Definition: SimChannel.h:117
TPC_iterator end_TPC() const
Returns an iterator pointing after the last TPC in the detector.
std::string sub(const std::string &a, const std::string &b)
Definition: TruthText.cxx:100
caf::Wall_t GetWallCross(const geo::BoxBoundedGeo &volume, const TVector3 p0, const TVector3 p1)
Definition: FillTrue.cxx:1052
Vector3D startp
Momentum at first point in the active TPC volume [GeV/c].