BackTrackerCore.cxx
Go to the documentation of this file.
1 //
2 // BackTrackerCore.cxx
3 // Created by Brian Rebel on 3/13/17.
4 // Major rewrite, Leo Bellantoni Mar 2020
5 //
6 
7 // Framework includes
9 
10 #include "nug4/ParticleNavigation/EmEveIdCalculator.h"
12 
13 // GArSoft includes
14 #include "Utilities/AssociationUtil.h"
17 #include "CoreUtils/ServiceUtil.h"
19 #include "Geometry/GeometryGAr.h"
20 
21 #include "TMath.h"
22 
23 
24 
25 namespace gar{
26  namespace cheat{
27 
28  //--------------------------------------------------------------------------
30  : fClocks(nullptr), fGeo(nullptr) {
31 
32  fClocks = gar::providerFrom<detinfo::DetectorClocksServiceGAr>();
33  fGeo = gar::providerFrom<geo::GeometryGAr>();
34 
35  fDisableRebuild = pset.get<bool >("DisableRebuild", false);
36 
37  fG4ModuleLabel = pset.get<std::string>("G4ModuleLabel", "geant");
38 
39  fRawTPCDataLabel = pset.get<std::string>("RawTPCDataLabel", "daq");
40 
41  fRawCaloDataLabel = pset.get<std::string>("RawCaloDataLabel", "daqsipm");
42  fRawCaloDataECALInstance = pset.get<std::string>("RawCaloDataECALInstance", "ECAL" );
43  fECALtimeResolution = pset.get<double >("ECALtimeResolution", 1.0);
44  fMinHitEnergyFraction = pset.get<double >("MinHitEnergyFraction", 0.1);
45  fMinCaloHitEnergyFrac = pset.get<double >("MinCaloHitEnergyFrac", 0.1);
46 
47  fTrackLabel = pset.get<std::string>("TrackLabel", "track");
48  fTPCClusterLabel = pset.get<std::string>("TPCClusterLabel", "tpccluster");
49  fTrackFracMCP = pset.get<double >("TrackFracMCP", 0.8);
50 
51  fClusterLabel = pset.get<std::string>("ClusterLabel", "calocluster");
52  fClusterECALInstance = pset.get<std::string>("ClusterECALInstance", "ECAL" );
53  fClusterFracMCP = pset.get<double >("ClusterFracMCP", 0.8);
54 
55  fSplitEDeps = pset.get<bool >("SplitEDeps", true);
56 
57  fECALTrackToTPCTrack = new std::unordered_map<int, int>;
58  return;
59  }
60 
61  //--------------------------------------------------------------------------
63 
64 
65 
66 
67 
68  //----------------------------------------------------------------------
70  if (!fHasMC) {
71  throw cet::exception("BackTrackerCore::TrackIDToParticle")
72  << "Attempting to backtrack without MC truth information";
73  }
74 
75  // What to do for negative trackID? ParticleList::find(key) does
76  // std::map<int,simb::MCParticle*>.find( abs(key) ) so a track ID
77  // corresponding to a radiated photon for example gets the original
78  // parent of that photon. In most parts of GArSoft, trackIDs are
79  // non-negative; the exception is in the EnergyDeposit class.
80  auto part_it = fParticleList.find(id);
81 
82  if (part_it == fParticleList.end()) {
83  MF_LOG_WARNING("BackTrackerCore::TrackIDToParticle")
84  << "can't find particle with track id " << id
85  << " in sim::ParticleList returning null pointer";
86  return nullptr;
87  }
88 
89  return part_it->second;
90  }
91 
92 
93 
94  //----------------------------------------------------------------------
96  if (!fHasMC) {
97  throw cet::exception("BackTrackerCore::FindEve")
98  << "Attempting to backtrack without MC truth information";
99  }
100 
101  int EveTrackId = fParticleList.EveId( p->TrackId() );
102  return TrackIDToParticle(EveTrackId);
103  }
104 
105 
106 
107  //----------------------------------------------------------------------
109  if (!fHasMC) {
110  throw cet::exception("BackTrackerCore::FindTPCEve")
111  << "Attempting to backtrack without MC truth information";
112  }
113 
114  // If I had ever been here before I would probably know just what to do / Don't you?
115  int dejaVu = p->TrackId();
116  if ( fECALTrackToTPCTrack->find(dejaVu) != fECALTrackToTPCTrack->end() ) {
117  return TrackIDToParticle( fECALTrackToTPCTrack->at(dejaVu) );
118  }
119 
120  simb::MCParticle* walker = p;
121  if (walker==nullptr) return nullptr;
122  while ( walker != nullptr &&
123  !fGeo->PointInGArTPC( TVector3(walker->Vx(),walker->Vy(),walker->Vz()) ) ) {
124  // Walk up the ParticleList not the event store so someday somebody can
125  // change the ParticleList and this will still work.
126  int mommaTID = fParticleList[walker->TrackId()]->Mother();
127  if (mommaTID == 0) {
128  // you are at the top of the tree
129  break;
130  }
131  simb::MCParticle* momma = TrackIDToParticle( mommaTID );
132  walker = momma;
133  }
134  (*fECALTrackToTPCTrack)[dejaVu] = walker->TrackId();
135  return walker;
136  }
137 
138 
139 
140  //----------------------------------------------------------------------
142  if (!fHasMC) {
143  throw cet::exception("BackTrackerCore::FindTPCEve")
144  << "Attempting to backtrack without MC truth information";
145  }
146 
147  // If I had ever been here before I would probably know just what to do / Don't you?
148  if ( fECALTrackToTPCTrack->find(trackID) != fECALTrackToTPCTrack->end() ) {
149  return TrackIDToParticle( fECALTrackToTPCTrack->at(trackID) );
150  }
151 
152  // Negative track ID, as found in EnergyDeposit or CaloEnergyDeposit,
153  // gets turned into positve track ID corresponding to parent of EM
154  // that created that particular EnergyDeposit or CaloEnergyDeposit
155  simb::MCParticle* walker = TrackIDToParticle(trackID);
156  while ( walker != nullptr &&
157  !fGeo->PointInGArTPC( TVector3(walker->Vx(),walker->Vy(),walker->Vz()) ) ) {
158  // Walk up the ParticleList not the event store so someday somebody can
159  // change the ParticleList and this will still work.
160  int mommaTID = fParticleList[walker->TrackId()]->Mother();
161  if (mommaTID == 0) {
162  // you are at the top of the tree
163  break;
164  }
165  simb::MCParticle* momma = TrackIDToParticle( mommaTID );
166  walker = momma;
167  }
168 
169  (*fECALTrackToTPCTrack)[trackID] = walker->TrackId();
170  return walker;
171  }
172 
173 
174 
175  //----------------------------------------------------------------------
177  simb::MCParticle* const afterbear) const {
178  if (!fHasMC) {
179  throw cet::exception("BackTrackerCore::IsForebearOf")
180  << "Attempting to backtrack without MC truth information";
181  }
182 
183  if (forebear==nullptr || afterbear==nullptr) return false;
184 
185  int stopper = forebear->TrackId();
186  int walker = afterbear->TrackId();
187  while ( walker!=stopper ) {
188  // Walk up the ParticleList not the event store so someday somebody can
189  // change the ParticleList and this will still work.
190  int momma = fParticleList[walker]->Mother();
191  if (momma == 0) {
192  return false;
193  } else {
194  walker = momma;
195  }
196  }
197  return true;
198  }
199 
200 
201 
202  //----------------------------------------------------------------------
205  if (!fHasMC) {
206  throw cet::exception("BackTrackerCore::ParticleToMCTruth")
207  << "Attempting to backtrack without MC truth information";
208  }
209 
210  int id = p->TrackId();
211  // find the entry in the MCTruth collection for this track id.
212  // The std::map fTrackIDToMCTrutheIndex will not contain keys < 0
213  size_t mct = fTrackIDToMCTruthIndex.find(std::abs(id))->second;
214 
215  if( mct > fMCTruthList.size() ) {
216  throw cet::exception("BackTrackerCore::ParticleToMCTruth")
217  << "attempting to find MCTruth index for out-of-range value: "
218  << mct << "/" << fMCTruthList.size();
219  }
220  return fMCTruthList[mct];
221  }
222 
223  //----------------------------------------------------------------------
224  std::vector<HitIDE>
226  if (!fHasMC || !fHasHits) {
227  throw cet::exception("BackTrackerCore::HitToHitIDEs")
228  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
229  }
230 
231  // By cutting on the StartTime and EndTime for this hit, we get only the
232  // IDEs for this hit; ides.size() should basically be the number of
233  // MCParticles that contributed to this hit.
234  std::vector<HitIDE> ides;
235  ides = this->ChannelToHitIDEs(hit->Channel(),hit->StartTime(),hit->EndTime());
236  return ides;
237  }
238 
239  //----------------------------------------------------------------------
240  std::vector<HitIDE>
242  if (!fHasMC || !fHasHits) {
243  throw cet::exception("BackTrackerCore::HitToHitIDEs")
244  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
245  }
246 
247  // By cutting on the StartTime and EndTime for this hit, we get only the
248  // IDEs for this hit; ides.size() should basically be the number of
249  // MCParticles that contributed to this hit.
250  std::vector<HitIDE> ides;
251  ides = this->ChannelToHitIDEs(hit.Channel(),hit.StartTime(),hit.EndTime());
252  return ides;
253  }
254 
255 
256 
257  //----------------------------------------------------------------------
258  std::vector<art::Ptr<rec::Hit>>
260  std::vector<art::Ptr<rec::Hit>> const& allhits,
261  bool checkNeutrals) const {
262  // returns a subset of the hits in the allhits collection that match
263  // the MC particle passed as an argument
264 
265  if (!fHasMC || !fHasHits) {
266  throw cet::exception("BackTrackerCore::ParticleToHits")
267  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
268  }
269 
270  std::vector<art::Ptr<rec::Hit>> hitList;
271  int PDGpid = p->PdgCode();
272  bool obviousNeutral = PDGpid==22 || PDGpid==2112 || PDGpid==111 ||
273  abs(PDGpid)==14 || abs(PDGpid)==12;
274  if (!checkNeutrals && obviousNeutral) return hitList;
275 
276  int tkID = p->TrackId();
277  std::vector<HitIDE> hids;
278 
279  for (auto hit : allhits) {
280  hids.clear();
281 
282  hids = this->ChannelToHitIDEs(hit->Channel(),hit->StartTime(),hit->EndTime());
283 
284  for (auto const& hid : hids) {
285  if ( hid.trackID==tkID && hid.energyFrac>fMinHitEnergyFraction ) {
286  hitList.push_back(hit);
287  }
288  }
289  }
290 
291  return hitList;
292  }
293 
294 
295 
296  //----------------------------------------------------------------------
297  std::vector<HitIDE>
299  double const start, double const stop) const {
300 
301  // loop over the energy deposits in the channel and grab those in time window
302 
303  if(start<0 || stop <0)
304  MF_LOG_WARNING("BackTrackerCore::ChannelToHitIDEs") << "start and/or stop times are negative!";
305  std::vector<HitIDE> hitIDEs;
306 
307  if(fChannelToEDepCol.size() < channel){
308  MF_LOG_WARNING("BackTrackerCore::ChannelToHitIDEs")
309  << "Attempting to find energy deposits for channel " << channel
310  << " while there are only " << fChannelToEDepCol.size()
311  << " channels available, returning an empty vector.";
312  return hitIDEs;
313  }
314 
315  auto chanEDeps = fChannelToEDepCol[channel];
316 
317  if(chanEDeps.size() < 1){
318  MF_LOG_WARNING("BackTrackerCore::ChannelToHitIDEs")
319  << "No sdp::EnergyDeposits for selected channel: " << channel
320  << ". There is no way to backtrack the given hit, returning"
321  << " an empty vector.";
322  return hitIDEs;
323  }
324 
325  std::map<int,size_t> tidmap; // Maps track IDs to index into hitIDEs
326 
327  // first get the total energy represented by all track ids for
328  // this channel and range of tdc values
329  unsigned short tdc = 0;
330  float chanpos[3]={0.,0.,0};
331  fGeo->ChannelToPosition(channel, chanpos);
332 
333  // loop over all EnergyDeposits for this channel and
334  // calculate a weighted average, in contributed energy,
335  // 4-position and 4-momentum
336  double totalEallTracks = 0.0;
337  size_t itraj=0;
338  for (auto const& edepfrac : chanEDeps) {
339 
340  auto edep = edepfrac.first;
341  float weight = edepfrac.second;
342  if(weight<0 || weight>1)
343  MF_LOG_WARNING("BackTrackerCore::ChannelToHitIDEs") << "bad weight (" << weight << ")";
344  if (edep->TrackID() == sdp::NoParticleId) continue;
345 
346  tdc = fClocks->TPCG4Time2TDC
347  (edep->Time() +TMath::Abs(edep->X()-chanpos[0]) *fInverseVelocity);
348  if ( (unsigned int)start <= tdc && tdc <= (unsigned int)stop) {
349  float energy = edep->Energy() * weight;
350  MF_LOG_DEBUG("BackTrackerCore::ChannelToHitIDEs") << "edep energy: " << edep->Energy()
351  << ", weight: " << weight << ", contributed energy: " << energy;
352  totalEallTracks += energy;
353 
354  TLorentzVector simpos(edep->X(),edep->Y(),edep->Z(),edep->Time());
355  TLorentzVector simmom = EnergyDepositToMomentum(edep->TrackID(),simpos,itraj);
356  simpos *= energy;
357  simmom *= energy;
358 
359 
360  // EnergyDeposits can contain negative track IDs corresponding to tracks
361  // created in showers. The absolute magnitude of the track is the track
362  // id of the parent of the EM showering process. That is the particle
363  // to which we want to assign this energy for backtracking purposes.
364  int tid = abs( edep->TrackID() );
365  auto tidmapiter = tidmap.find(tid);
366  if (tidmapiter == tidmap.end()) {
367  hitIDEs.emplace_back(tid, 0.0, energy, simpos, simmom);
368  tidmap[tid] = hitIDEs.size()-1;
369  } else {
370  hitIDEs.at(tidmapiter->second).energyTot += energy;
371  hitIDEs.at(tidmapiter->second).position += simpos;
372  hitIDEs.at(tidmapiter->second).momentum += simmom;
373  }
374  }
375  }
376 
377  /* DEB hits without edeps
378  std::cout << "Channel " << channel << ", at (z,y) = (" << chanpos[2] << ", "
379  << chanpos[1] << ") has " << chanEDeps.size() << " edeps, and " <<
380  hitIDEs.size() << " are in-time between " << start << " and " << stop
381  << std::endl; */
382 
383  // loop over the hitIDEs to set the fractional energy for each TrackID
384  for (size_t i = 0; i < hitIDEs.size(); ++i) {
385  hitIDEs[i].energyFrac = hitIDEs[i].energyTot / totalEallTracks;
386  hitIDEs[i].position *= 1.0/totalEallTracks;
387  hitIDEs[i].momentum *= 1.0/totalEallTracks;
388  }
389 
390  // remove duplicate HitIDEs (not that any should be there)
391  size_t nbefore = hitIDEs.size();
392  std::sort(hitIDEs.begin(),hitIDEs.end());
393  hitIDEs.erase(std::unique(hitIDEs.begin(),hitIDEs.end()),hitIDEs.end());
394  size_t nafter = hitIDEs.size();
395  if(nbefore!=nafter)
396  MF_LOG_WARNING("BackTrackerCore::ChannelToHitIDEs") << "found and removed "
397  << nbefore-nafter << " duplicate HitIDEs (not expected for single channel)";
398 
399  return hitIDEs;
400  }
401 
402 
403 
404  //----------------------------------------------------------------------
405  std::pair<double,double>
407  std::vector<art::Ptr<rec::Hit> > const& hits, bool weightByCharge) const {
408 
409  if (!fHasMC || !fHasHits) {
410  throw cet::exception("BackTrackerCore::HitCollectionPurity")
411  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
412  }
413 
414 
415  int trackIDin = p->TrackId();
416 
417  float weight;
418  float desired = 0.0;
419  float total = 0.0;
420  for (auto hit : hits) {
421  std::vector<HitIDE> hitIDEs = this->HitToHitIDEs(hit);
422 
423  weight = (weightByCharge) ? hit->Signal() : 1.0;
424  total += weight;
425 
426  for (auto iHitIDE : hitIDEs) {
427  // Don't double count if this hit has > 1 of the desired GEANT trackIDs
428  if (iHitIDE.trackID == trackIDin &&
429  iHitIDE.energyFrac >= fMinHitEnergyFraction) {
430  desired += weight;
431  break;
432  }
433  }
434  } // end loop over hits
435 
436  double purity = 0.0;
437  double uncertainty = 0.0;
438  if (total > 0.0) {
439  purity = desired/total;
440  uncertainty = std::sqrt( desired*(total -desired)/total )/total;
441  }
442  return std::make_pair(purity,uncertainty);
443  }
444 
445 
446 
447  //----------------------------------------------------------------------
448  std::pair<double,double>
450  std::vector<art::Ptr<rec::Hit> > const& hits,
451  std::vector<art::Ptr<rec::Hit> > const& allhits, bool weightByCharge) const {
452 
453  if (!fHasMC || !fHasHits) {
454  throw cet::exception("BackTrackerCore::HitCollectionEfficiency")
455  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
456  }
457 
458  int trackIDin = p->TrackId();
459 
460  float weight;
461  float desired = 0.0;
462  for (auto hit : hits) {
463  std::vector<HitIDE> hitIDEs = this->HitToHitIDEs(hit);
464 
465  weight = (weightByCharge) ? hit->Signal() : 1.0;
466 
467  for (auto iHitIDE : hitIDEs) {
468  // Don't double count if this hit has > 1 of the desired GEANT track IDs
469  if (iHitIDE.trackID == trackIDin &&
470  iHitIDE.energyFrac >= fMinHitEnergyFraction) {
471  desired += weight;
472  break;
473  }
474  }
475  } // end loop over hits
476 
477  // Next figure out how many hits in the whole collection are associated with this id
478  float total = 0.0;
479  if (desired>0) {
480  for (auto hit : allhits) {
481  std::vector<HitIDE> hitIDEs = this->HitToHitIDEs(hit);
482 
483  weight = (weightByCharge) ? hit->Signal() : 1.0;
484 
485  for (auto iHitIDE : hitIDEs) {
486  // Don't double count if this hit has > 1 of the desired GEANT track IDs
487  if (iHitIDE.trackID == trackIDin &&
488  iHitIDE.energyFrac >= fMinHitEnergyFraction) {
489  total += weight;
490  break;
491  }
492  }
493  } // end loop over all hits
494  }
495 
496  double efficiency = 0.0;
497  double uncertainty = 0.0;
498  if (total > 0.0) {
499  efficiency = desired/total;
500  uncertainty = std::sqrt( desired*(total -desired)/total )/total;
501  }
502  return std::make_pair(efficiency,uncertainty);
503  }
504 
505 
506 
507 
508 
509  //----------------------------------------------------------------------
510  std::vector<CalIDE>
512  if (!fHasMC || !fHasCalHits) {
513  throw cet::exception("BackTrackerCore::CaloHitToCalIDEs")
514  << "Attempting to backtrack without MC truth or gar::rec::CaloHit information";
515  }
516 
517  // Cut on Time for this hit +/- ECAL time resolution given in BackTracker.fcl
518  std::vector<CalIDE> ides;
519  ides = this->CellIDToCalIDEs(hit->CellID(),hit->Time().first);
520  return ides;
521  }
522 
523  //----------------------------------------------------------------------
524  std::vector<CalIDE>
526  if (!fHasMC || !fHasCalHits) {
527  throw cet::exception("BackTrackerCore::CaloHitToCalIDEs")
528  << "Attempting to backtrack without MC truth or gar::rec::CaloHit information";
529  }
530 
531  // Cut on Time for this hit +/- ECALtimeResolution given in BackTracker.fcl
532  std::vector<CalIDE> ides;
533  ides = this->CellIDToCalIDEs(hit.CellID(),hit.Time().first);
534  return ides;
535  }
536 
537 
538 
539  //----------------------------------------------------------------------
540  std::vector<art::Ptr<rec::CaloHit>>
542  std::vector<art::Ptr<rec::CaloHit>> const& allhits) const {
543  // returns a subset of the CaloHits in the allhits collection that match
544  // the MC particle passed as an argument
545 
546  if (!fHasMC || !fHasHits) {
547  throw cet::exception("BackTrackerCore::ParticleToCaloHits")
548  << "Attempting to backtrack without MC truth or gar::rec::CaloHit information";
549  }
550 
551  std::vector<art::Ptr<rec::CaloHit>> calHitList;
552  int tkID = p->TrackId();
553  std::vector<CalIDE> calhids;
554 
555  for (auto hit : allhits) {
556  calhids.clear();
557 
558  calhids = this->CellIDToCalIDEs(hit->CellID(),hit->Time().first);
559 
560  for (auto const& hid : calhids) {
561  if ( hid.trackID==tkID && hid.energyFrac>fMinCaloHitEnergyFrac ) {
562  calHitList.push_back(hit);
563  }
564  }
565  }
566  return calHitList;
567  }
568 
569 
570 
571  //----------------------------------------------------------------------
572  std::vector<CalIDE>
574  float const time) const {
575 
576  // loop over the energy deposits in the channel and grab those in time window
577 
578  std::vector<CalIDE> calIDEs;
579 
580  std::vector<const sdp::CaloDeposit*> cellEDeps;
581  try {
582  cellEDeps = fCellIDToEDepCol.at(cell);
583  }
584  catch (std::out_of_range &) {
585  MF_LOG_WARNING("BackTrackerCore::CellIDToCalIDEs")
586  << "No sdp::EnergyDeposits for selected ECAL cell: " << cell
587  << ". There is no way to backtrack the given calorimeter hit,"
588  << " returning an empty vector.";
589  return calIDEs;
590  }
591 
592  std::map<int,size_t> tidmap; // Maps track IDs to index into calIDEs
593 
594  // Get the total energy produced by all track ids for this cell & time
595  float start = time -fECALtimeResolution;
596  float stop = time +fECALtimeResolution;
597 
598  double totalEallTracks = 0.0;
599  for (auto const& edep : cellEDeps) {
600  if (edep->TrackID() == sdp::NoParticleId) continue;
601 
602  if ( start<=edep->Time() && edep->Time()<=stop) {
603  float energy = edep->Energy();
604  totalEallTracks += energy;
605  int tid = edep->TrackID();
606  // Chase the tid up to the parent which started in the gas.
607  // tid < 0 is possible here, but FindTPCEve calls
608  // TrackIDToParticle, which fixes that little issue.
609  simb::MCParticle* TPCEve = FindTPCEve(tid);
610  int tidTPC;
611  if (TPCEve!=nullptr) {
612  tidTPC = TPCEve->TrackId();
613  } else {
614  tidTPC = tid;
615  }
616  auto tidmapiter = tidmap.find(tidTPC);
617  if (tidmapiter == tidmap.end()) {
618  calIDEs.emplace_back(tidTPC, 0.0, energy);
619  tidmap[tidTPC] = calIDEs.size()-1;
620  } else {
621  calIDEs.at(tidmapiter->second).energyTot += energy;
622  }
623  }
624  }
625 
626  // loop over the hitIDEs to set the fractional energy for each TrackID
627  for (size_t i = 0; i < calIDEs.size(); ++i) {
628  calIDEs[i].energyFrac = calIDEs[i].energyTot / totalEallTracks;
629  }
630  return calIDEs;
631  }
632 
633 
634 
635  //----------------------------------------------------------------------
636  std::pair<double,double>
638  std::vector<art::Ptr<rec::CaloHit> > const& hits, bool weightByCharge) const {
639 
640  if (!fHasMC || !fHasHits) {
641  throw cet::exception("BackTrackerCore::CaloHitPurity")
642  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
643  }
644 
645 
646  int trackIDin = p->TrackId();
647 
648  float weight;
649  float desired = 0.0;
650  float total = 0.0;
651  for (auto hit : hits) {
652  std::vector<CalIDE> calIDEs = this->CaloHitToCalIDEs(hit);
653 
654  weight = (weightByCharge) ? hit->Energy() : 1.0;
655  total += weight;
656 
657  for (auto iCalIDE : calIDEs) {
658  // Don't double count if this hit has > 1 of the desired GEANT trackIDs
659  if (iCalIDE.trackID == trackIDin &&
660  iCalIDE.energyFrac >= fMinCaloHitEnergyFrac) {
661  desired += weight;
662  break;
663  }
664  }
665  } // end loop over hits
666 
667  double purity = 0.0;
668  double uncertainty = 0.0;
669  if (total > 0.0) {
670  purity = desired/total;
671  uncertainty = std::sqrt( desired*(total -desired)/total )/total;
672  }
673  return std::make_pair(purity,uncertainty);
674  }
675 
676 
677 
678  //----------------------------------------------------------------------
679  std::pair<double,double>
681  std::vector<art::Ptr<rec::CaloHit> > const& hits,
682  std::vector<art::Ptr<rec::CaloHit> > const& allhits, bool weightByCharge) const {
683 
684  if (!fHasMC || !fHasHits) {
685  throw cet::exception("BackTrackerCore::CaloHitEfficiency")
686  << "Attempting to backtrack without MC truth or gar::rec::Hit information";
687  }
688 
689  int trackIDin = p->TrackId();
690 
691  float weight;
692  float desired = 0.0;
693  for (auto hit : hits) {
694  std::vector<CalIDE> calIDEs = this->CaloHitToCalIDEs(hit);
695 
696  weight = (weightByCharge) ? hit->Energy() : 1.0;
697 
698  for (auto iCalIDE : calIDEs) {
699  // Don't double count if this hit has > 1 of the desired GEANT track IDs
700  if (iCalIDE.trackID == trackIDin &&
701  iCalIDE.energyFrac >= fMinCaloHitEnergyFrac) {
702  desired += weight;
703  break;
704  }
705  }
706  } // end loop over hits
707 
708  // Next figure out how many hits in the whole collection are associated with this id
709  float total = 0.0;
710  if (desired>0.0) {
711  for (auto hit : allhits) {
712  std::vector<CalIDE> calIDEs = this->CaloHitToCalIDEs(hit);
713 
714  weight = (weightByCharge) ? hit->Energy() : 1.0;
715 
716  for (auto iCalIDE : calIDEs) {
717  // Don't double count if this hit has > 1 of the desired GEANT track IDs
718  if (iCalIDE.trackID == trackIDin &&
719  iCalIDE.energyFrac >= fMinCaloHitEnergyFrac) {
720  total += weight;
721  break;
722  }
723  }
724  } // end loop over all hits
725  }
726 
727  double efficiency = 0.0;
728  double uncertainty = 0.0;
729  if (total > 0.0) {
730  efficiency = desired/total;
731  uncertainty = std::sqrt( desired*(total -desired)/total )/total;
732  }
733  return std::make_pair(efficiency,uncertainty);
734  }
735 
736 
737 
738 
739 
740  //----------------------------------------------------------------------
741  std::vector<art::Ptr<rec::Hit>> const
743 
744  //std::cout << "BT:TrackToHits called, read map with " << fTrackIDToHits.size() << " entries" << std::endl;
745 
746  // Evidently, use of std::unordered_map keeps this method from being const
747  std::vector<art::Ptr<gar::rec::Hit>> retval;
748  if ( !fTrackIDToHits.empty() ) {
749  retval = fTrackIDToHits[ t->getIDNumber() ];
750  }
751  // useful for debugging, but reduces performance
752  /*size_t nduplicate = 0;
753  for(size_t i=0; i<retval.size(); i++) {
754  for(size_t j=i+1; j<retval.size(); j++) {
755  if(*retval[i]==*retval[j]) nduplicate++;
756  }
757  }
758  if(nduplicate!=0) std::cout << nduplicate << " duplicate hits matched to track" << std::endl;*/
759  return retval;
760  }
761  //-----------------------------------------------------------------------
762  std::vector<art::Ptr<rec::Hit>> const
764 
765  // Evidently, use of std::unordered_map keeps this method from being const
766  std::vector<art::Ptr<gar::rec::Hit>> retval;
767  if ( !fTPCClusterIDToHits.empty() ) {
768  retval = fTPCClusterIDToHits[ clust->getIDNumber() ];
769  }
770  return retval;
771  }
772 
773  //-----------------------------------------------------------------------
774  //std::vector<art::Ptr<rec::TPCCluster>> const
775  std::vector<const rec::TPCCluster*> const
777 
778  // Evidently, use of std::unordered_map keeps this method from being const
779  //std::vector<art::Ptr<gar::rec::TPCCluster>> retval;
780  std::vector<const gar::rec::TPCCluster*> retval;
781  if ( !fTrackIDToClusters.empty() ) {
782  retval = fTrackIDToClusters[ t->getIDNumber() ];
783  }
784  return retval;
785  }
786 
787  //-----------------------------------------------------------------------
789 
790  double etot = 0.; // total energy
791  std::vector<art::Ptr<rec::Hit>> const hits = TrackToHits(t); // all of this track's hits
792  std::vector<HitIDE> allIdes;
793 
794  // loop over hits, get IDEs, and sum up energy deposits
795  for(auto const& hit : hits) {
796  std::vector<HitIDE> ides = HitToHitIDEs(hit);
797  allIdes.insert(allIdes.end(),ides.begin(),ides.end());
798 
799  }// for hits
800 
801  /*size_t pretotal = allIdes.size();
802 
803  // remove duplicate HitIdes
804  // comment out for now since we could have meaningful duplicate HitIDEs
805  // e.g. a common sdp::EnergyDeposit split evenly among channels
806  std::sort(allIdes.begin(),allIdes.end());
807  allIdes.erase( std::unique(allIdes.begin(),allIdes.end()), allIdes.end());
808  size_t posttotal = allIdes.size();
809 
810  if(pretotal!=posttotal) std::cout << "removed " << pretotal-posttotal << " duplicated IDEs" << std::endl;*/
811 
812  for(auto const& ide : allIdes) {
813  etot += ide.energyTot;
814  }// for ides
815 
816  return etot;
817  }
818 
819 
820 
821  //----------------------------------------------------------------------
822  std::vector<std::pair<simb::MCParticle*,float>>
824  // Can't be const because it uses TrackToHits
825 
826  std::vector<art::Ptr<gar::rec::Hit>> const hitCol = TrackToHits(t);
827  std::vector<HitIDE> hitIDECol;
828  for (auto hit : hitCol) {
829  std::vector<HitIDE> IDEsThisHit = HitToHitIDEs(hit);
830  hitIDECol.insert(hitIDECol.end(), IDEsThisHit.begin(),IDEsThisHit.end());
831  }
832 
833  // A tree to accumulate the found energy for each GEANT/GENIE track
834  std::map<int,float> lTrackIdToEnergy;
835  for (auto hitIDE : hitIDECol) {
836  lTrackIdToEnergy[hitIDE.trackID] += hitIDE.energyFrac * hitIDE.energyTot;
837  }
838 
839  // There are still electrons in lTrackIdToEnergy that have parents in
840  // lTrackIDToEnergy... these should be consolidated. Also find total Energy
841  std::map<int,float>::iterator iTrackIdTo = lTrackIdToEnergy.begin();
842  for (; iTrackIdTo != lTrackIdToEnergy.end(); ++iTrackIdTo) {
843  simb::MCParticle* iPart = TrackIDToParticle(iTrackIdTo->first);
844  if ( iPart->PdgCode() == 11 && iPart->Mother()!=0 ) {
845  if ( lTrackIdToEnergy.count(iPart->Mother())==1 ) {
846  lTrackIdToEnergy[iPart->Mother()] += iTrackIdTo->second;
847  iTrackIdTo = lTrackIdToEnergy.erase(iTrackIdTo);
848  if (iTrackIdTo != lTrackIdToEnergy.begin()) --iTrackIdTo;
849  }
850  }
851  }
852 
853  // Next, sort the map by value. If there are two entries with the exact same
854  // ionization, only one is found in resulting set! But the digitization scale
855  // for edep is eVs (single molecular ionizations) i.e. 1e-5 or less so this should
856  // be negligible for tracks of interesting ionizations.
857  // Declaring the type of the sorting predicate
858  typedef std::function<bool(std::pair<int,float>, std::pair<int,float>)> Comparator;
859  // Declaring a set that will store the pairs using above comparison logic
860  std::set<std::pair<int,float>, Comparator> setOfTracks(
861  lTrackIdToEnergy.begin(), lTrackIdToEnergy.end(),
862  [](std::pair<int,float> a ,std::pair<int,float> b) {
863  return a.second > b.second;
864  }
865  );
866 
867  // Make the returned vector
868  float Etot = 0.0;
869  auto iTrackSet = setOfTracks.begin();
870  for (; iTrackSet!=setOfTracks.end(); ++iTrackSet) {
871  Etot += iTrackSet->second; // Can't do this in loop on lTrackIdToEnergy
872  }
873 
874  std::pair<simb::MCParticle*,float> emptee(nullptr,0.0);
875  std::vector<std::pair<simb::MCParticle*,float>> retval(setOfTracks.size(),emptee);
876  std::vector<std::pair<simb::MCParticle*,float>>::iterator iRetval = retval.begin();
877  iTrackSet = setOfTracks.begin();
878  for (; iTrackSet != setOfTracks.end(); ++iTrackSet,++iRetval) {
879  iRetval->first = TrackIDToParticle(iTrackSet->first);
880  iRetval->second = iTrackSet->second / Etot;
881  }
882 
883  return retval;
884  }
885 
886 
887 
888  //----------------------------------------------------------------------
889  std::vector<art::Ptr<rec::Track>>
892 
893  // Can't be const because it uses TrackToMCParticles
894  std::vector<art::Ptr<rec::Track>> retval;
895  std::vector<std::pair<simb::MCParticle*,float>> fromMatch;
896  int desiredTrackId = p->TrackId();
897 
898  for (art::Ptr<rec::Track> iTrack : tracks) {
899  // de-ref the art::Ptr and create a bare pointer for
900  // TrackToMCParticles call, managing const-correctness as best we can
901  rec::Track* argument = const_cast<rec::Track*>( &(*iTrack) );
902  fromMatch = TrackToMCParticles( argument );
903  for (std::pair<simb::MCParticle*,float> matches : fromMatch) {
904  if ( matches.first->TrackId() == desiredTrackId &&
905  matches.second > fTrackFracMCP) {
906  retval.push_back( iTrack );
907  }
908  }
909  }
910  return retval;
911  }
912 
913 
914 
915 
916 
917  //----------------------------------------------------------------------
918  std::vector<art::Ptr<rec::CaloHit>> const
920 
921  // Evidently, use of std::unordered_map keeps this method from being const
922  std::vector<art::Ptr<gar::rec::CaloHit>> retval;
923  if ( !fClusterIDToCaloHits.empty() ) {
924  retval = fClusterIDToCaloHits[ c->getIDNumber() ];
925  }
926  return retval;
927  }
928 
929 
930 
931  //----------------------------------------------------------------------
932  std::vector<std::pair<simb::MCParticle*,float>>
934  // Can't be const because it uses TrackToHits
935 
936  std::vector<art::Ptr<gar::rec::CaloHit>> const hitCol = ClusterToCaloHits(c);
937  std::vector<CalIDE> hitIDECol;
938  for (auto hit : hitCol) {
939  std::vector<CalIDE> IDEsThisHit = CaloHitToCalIDEs(hit);
940  hitIDECol.insert(hitIDECol.end(), IDEsThisHit.begin(),IDEsThisHit.end());
941  }
942 
943  // A tree is a good way to accumulate the info we need
944  std::map<int,float> lClusterIdToEnergy;
945  for (auto calIDE : hitIDECol) {
946  simb::MCParticle* thisTrack = TrackIDToParticle(calIDE.trackID);
947  simb::MCParticle* incomingTrack = FindTPCEve(thisTrack);
948  int iTrackID = incomingTrack->TrackId();
949  lClusterIdToEnergy[iTrackID] += calIDE.energyFrac * calIDE.energyTot;
950  }
951 
952  // Next, sort the map by value.
953  // Declaring the type of the sorting predicate
954  typedef std::function<bool(std::pair<int,float>, std::pair<int,float>)> Comparator;
955  // Declaring a set that will store the pairs using above comparison logic
956  std::set<std::pair<int,float>, Comparator> setOfTracks(
957  lClusterIdToEnergy.begin(), lClusterIdToEnergy.end(),
958  [](std::pair<int,float> a ,std::pair<int,float> b) {
959  return a.second > b.second;
960  }
961  );
962 
963  // Make the returned vector. Could have no tracks at all?
964  float Etot = 0.0;
965  auto iTrackSet = setOfTracks.begin();
966  for (; iTrackSet!=setOfTracks.end(); ++iTrackSet) {
967  Etot += iTrackSet->second; // Can't do this in loop on lClusterIdToEnergy
968  }
969 
970  std::pair<simb::MCParticle*,float> emptee(nullptr,0.0);
971  std::vector<std::pair<simb::MCParticle*,float>> retval(lClusterIdToEnergy.size(),emptee);
972 
973  std::vector<std::pair<simb::MCParticle*,float>>::iterator iRetval = retval.begin();
974  iTrackSet = setOfTracks.begin();
975  for (; iTrackSet != setOfTracks.end(); ++iTrackSet,++iRetval) {
976  iRetval->first = TrackIDToParticle(iTrackSet->first);
977  iRetval->second = iTrackSet->second / Etot;
978  }
979 
980  return retval;
981  }
982 
983 
984 
985  //----------------------------------------------------------------------
986  std::vector<art::Ptr<rec::Cluster>>
988  std::vector<art::Ptr<rec::Cluster>> const& clusters) {
989 
990  // Can't be const because it uses ClusterToMCParticles
991  std::vector<art::Ptr<rec::Cluster>> retval;
992  std::vector<std::pair<simb::MCParticle*,float>> fromMatch;
993  int desiredTrackId = p->TrackId();
994 
995  for (art::Ptr<rec::Cluster> iCluster : clusters) {
996  // de-ref the art::Ptr and create a bare pointer for
997  // TrackToMCParticles call, managing const-correctness as best we can
998  rec::Cluster* argument = const_cast<rec::Cluster*>( &(*iCluster) );
999  fromMatch = ClusterToMCParticles( argument );
1000  for (std::pair<simb::MCParticle*,float> matches : fromMatch) {
1001  if ( matches.first->TrackId() == desiredTrackId &&
1002  matches.second > fClusterFracMCP) {
1003  retval.push_back( iCluster );
1004  }
1005  }
1006  }
1007  return retval;
1008  }
1009 
1010 
1011 
1012  //----------------------------------------------------------------------
1014  rec::Cluster* const c) {
1015  std::vector<simb::MCParticle*> partsIsParts = MCPartsInCluster(c);
1016  for (simb::MCParticle* clusPart : partsIsParts) {
1017  if (IsForebearOf(clusPart,p)) return true;
1018  }
1019  return false;
1020  }
1021 
1022 
1023 
1024  //----------------------------------------------------------------------
1026  rec::Cluster* const c) {
1027  std::vector<simb::MCParticle*> partsIsParts = MCPartsInCluster(c);
1028 
1029  for (simb::MCParticle* clusPart : partsIsParts) {
1030  if (IsForebearOf(p,clusPart)) return true;
1031  }
1032  return false;
1033  }
1034 
1035 
1036 
1037  //----------------------------------------------------------------------
1038  std::vector<simb::MCParticle*>
1040 
1041  std::vector<int> trackIdsInCluster;
1042  std::vector<art::Ptr<rec::CaloHit>> const caloHits = ClusterToCaloHits(c);
1043  for (art::Ptr iCaloHit : caloHits) {
1044  std::vector<CalIDE> IDEsThisHit = CaloHitToCalIDEs(iCaloHit);
1045  for ( CalIDE iIDE : IDEsThisHit ) trackIdsInCluster.push_back(iIDE.trackID);
1046  }
1047 
1048  std::sort(trackIdsInCluster.begin(),trackIdsInCluster.end());
1050  std::unique(trackIdsInCluster.begin(),trackIdsInCluster.end());
1051  trackIdsInCluster.resize(std::distance(trackIdsInCluster.begin(),itr));
1052 
1053  std::vector<simb::MCParticle*> retval;
1054  for ( int trackId : trackIdsInCluster) {
1055  simb::MCParticle* pahtay = TrackIDToParticle(trackId);
1056  retval.push_back(pahtay);
1057  }
1058  return retval;
1059  }
1060 
1061 
1062 
1063 
1064 
1065  //----------------------------------------------------------------------
1066  TLorentzVector BackTrackerCore::EnergyDepositToMomentum(const int& trackID,
1067  const TLorentzVector& position, size_t& startTrajIndex) const {
1068 
1069  auto const& mcp = TrackIDToParticle(trackID); // MCParticle
1070  float dr=FLT_MAX, dt=FLT_MAX; // spatial and temporal distance
1071 
1072  // stepping through the trajectory, the distance should decrease until
1073  // min dist found (could be starting point)
1074  for(;startTrajIndex<mcp->NumberTrajectoryPoints(); startTrajIndex++){
1075 
1076  if( (position - mcp->Position(startTrajIndex)).Vect().Mag() < dr &&
1077  abs((position - mcp->Position(startTrajIndex)).T()) < dt) {
1078 
1079  dr = (position - mcp->Position(startTrajIndex)).Vect().Mag();
1080  dt = abs((position - mcp->Position(startTrajIndex)).T());
1081  } else {
1082  break;
1083  }
1084 
1085  } // for trajectory points
1086 
1087  return mcp->Momentum(startTrajIndex);
1088 
1089  } // def EnergyDepositToMomentum()
1090 
1091 
1092 
1093 
1094 
1095  } // cheat
1096 } // gar
std::vector< art::Ptr< rec::Cluster > > MCParticleToClusters(simb::MCParticle *const p, std::vector< art::Ptr< rec::Cluster >> const &clusters)
double fClusterFracMCP
min frac of ionization in a cluster for matching to an MCParticle
intermediate_table::iterator iterator
std::vector< CalIDE > CaloHitToCalIDEs(art::Ptr< rec::CaloHit > const &hit) const
int PdgCode() const
Definition: MCParticle.h:212
float StartTime() const
Definition: Hit.h:67
std::vector< simb::MCParticle * > MCPartsInCluster(rec::Cluster *const c)
std::vector< art::Ptr< rec::Track > > MCParticleToTracks(simb::MCParticle *const p, std::vector< art::Ptr< rec::Track >> const &tracks)
std::vector< art::Ptr< rec::Hit > > const TrackToHits(rec::Track *const t)
std::vector< std::vector< std::pair< const sdp::EnergyDeposit *, float const > > > fChannelToEDepCol
convenience collections of EnergyDeposits for each channel
art::Ptr< simb::MCTruth > const ParticleToMCTruth(simb::MCParticle *const p) const
raw::CellID_t CellID() const
Definition: CaloHit.h:72
std::unordered_map< rec::IDNumber, std::vector< const rec::TPCCluster * > > fTrackIDToClusters
Reco track ID to track&#39;s clusters.
std::string string
Definition: nybbler.cc:12
int Mother() const
Definition: MCParticle.h:213
std::pair< float, float > Time() const
Definition: CaloHit.h:71
bool PointInGArTPC(TVector3 const &point) const
std::vector< const rec::TPCCluster * > const TrackToClusters(rec::Track *const t)
bool IsForebearOf(simb::MCParticle *const forebear, simb::MCParticle *const afterbear) const
const detinfo::DetectorClocks * fClocks
Detector clock information.
struct vector vector
std::vector< art::Ptr< rec::Hit > > ParticleToHits(simb::MCParticle *const p, std::vector< art::Ptr< rec::Hit >> const &allhits, bool checkNeutrals=false) const
double fMinHitEnergyFraction
min frac of ionization a track has to count in a TPC hit
bool MCParticleCreatedCluster(simb::MCParticle *const p, rec::Cluster *const c)
std::string fRawCaloDataECALInstance
instance name for the ECAL raw hits
float EndTime() const
Definition: Hit.h:68
std::string fClusterLabel
label for ECAL cluster producing module
uint8_t channel
Definition: CRTFragment.hh:201
std::unordered_map< raw::CellID_t, std::vector< const sdp::CaloDeposit * > > fCellIDToEDepCol
convenience collections of EnergyDeposit for each cell
Particle class.
const geo::GeometryCore * fGeo
pointer to the geometry
weight
Definition: test.py:257
gar::rec::IDNumber getIDNumber() const
Definition: TPCCluster.cxx:32
static const int NoParticleId
Definition: sim.h:30
std::unordered_map< int, int > fTrackIDToMCTruthIndex
int TrackId() const
Definition: MCParticle.h:210
double fTrackFracMCP
min frac of ionization in a track for matching to an MCParticle
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::Hit > > > fTrackIDToHits
Reco track ID to track&#39;s hits.
simb::MCParticle * FindTPCEve(simb::MCParticle *const p) const
T abs(T value)
std::vector< std::pair< simb::MCParticle *, float > > ClusterToMCParticles(rec::Cluster *const c)
std::string fClusterECALInstance
instance name for the ECAL clusters
std::pair< double, double > HitEfficiency(simb::MCParticle *const p, std::vector< art::Ptr< rec::Hit > > const &hits, std::vector< art::Ptr< rec::Hit > > const &allhits, bool weightByCharge=false) const
std::string fRawTPCDataLabel
label for TPC readout module
uint32_t Channel_t
Definition: RawDigit.h:35
sim::ParticleList fParticleList
Maps MCParticle::TrackId() to same MCParticle.
std::string fTPCClusterLabel
label for TPCCluster producing module
const double a
T get(std::string const &key) const
Definition: ParameterSet.h:271
std::pair< double, double > CaloHitEfficiency(simb::MCParticle *const p, std::vector< art::Ptr< rec::CaloHit >> const &hits, std::vector< art::Ptr< rec::CaloHit >> const &allhits, bool weightByCharge=false) const
simb::MCParticle * TrackIDToParticle(int const &id) const
std::string fTrackLabel
label for final track producing module
gar::rec::IDNumber getIDNumber() const
Definition: Cluster.cxx:106
p
Definition: test.py:223
TLorentzVector EnergyDepositToMomentum(const int &trackID, const TLorentzVector &position, size_t &startTrajIndex) const
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::Hit > > > fTPCClusterIDToHits
Reco TPC cluster ID to cluster&#39;s hits.
std::pair< double, double > HitPurity(simb::MCParticle *const p, std::vector< art::Ptr< rec::Hit >> const &hits, bool weightByCharge=false) const
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::CaloHit > > > fClusterIDToCaloHits
Reco ECAL cluster ID to CaloHits.
std::vector< HitIDE > HitToHitIDEs(art::Ptr< rec::Hit > const &hit) const
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
std::unordered_map< int, int > * fECALTrackToTPCTrack
results of previous FindTPCEve calls
virtual double TPCG4Time2TDC(double g4time) const =0
Given G4 time [ns], returns corresponding TPC electronics clock count [tdc].
long long int CellID_t
Definition: CaloRawDigit.h:24
bool ClusterCreatedMCParticle(simb::MCParticle *const p, rec::Cluster *const c)
simb::MCParticle * FindEve(simb::MCParticle *const p) const
Detector simulation of raw signals on wires.
std::string fG4ModuleLabel
label for geant4 module
std::vector< CalIDE > CellIDToCalIDEs(raw::CellID_t const &cellID, float const time) const
double TrackToTotalEnergy(rec::Track *const t)
std::vector< art::Ptr< rec::CaloHit > > ParticleToCaloHits(simb::MCParticle *const p, std::vector< art::Ptr< rec::CaloHit >> const &allhits) const
std::vector< HitIDE > ChannelToHitIDEs(raw::Channel_t const &channel, double const start, double const stop) const
Definition: tracks.py:1
General GArSoft Utilities.
unsigned int Channel() const
Definition: Hit.h:64
code to link reconstructed objects back to the MC truth information
Definition: BackTracker.cc:22
bool fSplitEDeps
use weights from PRFs to break true energy deposits into channel specific contributions ...
std::string fRawCaloDataLabel
label for ECAL readout module
std::vector< std::pair< simb::MCParticle *, float > > TrackToMCParticles(rec::Track *const t)
BackTrackerCore(fhicl::ParameterSet const &pset)
#define MF_LOG_DEBUG(id)
static bool * b
Definition: config.cpp:1043
std::pair< double, double > CaloHitPurity(simb::MCParticle *const p, std::vector< art::Ptr< rec::CaloHit >> const &hits, bool weightByCharge=false) const
gar::rec::IDNumber getIDNumber() const
Definition: Track.cxx:42
std::vector< art::Ptr< simb::MCTruth > > fMCTruthList
all the MCTruths for the event
#define MF_LOG_WARNING(category)
std::vector< art::Ptr< rec::Hit > > const TPCClusterToHits(rec::TPCCluster *const clust)
std::vector< art::Ptr< rec::CaloHit > > const ClusterToCaloHits(rec::Cluster *const c)
double fECALtimeResolution
time resolution for hits in ECAL, nsec.
art framework interface to geometry description
double fInverseVelocity
inverse drift velocity
void ChannelToPosition(unsigned int const channel, float *const worldLoc) const
bool fDisableRebuild
for switching off backtracker&#39;s rebuild of the MCParticle tables
double fMinCaloHitEnergyFrac
min frac of ionization a track has to count in a CaloHit
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33