BackTracker_service.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 //
4 // \file: BackTracker_service.cc
5 //
6 // brebel@fnal.gov
7 // modified Feb - Mar 2020 Leo Bellantoni, bellanto@fnal.gov
8 //
9 //
10 ////////////////////////////////////////////////////////////////////////
11 
12 // GArSoft includes
13 #include "MCCheater/BackTracker.h"
14 #include "Geometry/GeometryGAr.h"
15 
16 // Framework includes
20 #include "canvas/Persistency/Common/FindMany.h"
21 #include "canvas/Persistency/Common/FindManyP.h"
22 #include "canvas/Persistency/Common/FindOneP.h"
23 
24 #include "nug4/ParticleNavigation/EmEveIdCalculator.h"
25 
28 
29 namespace gar {
30  namespace cheat {
31 
32  //----------------------------------------------------------------------
35  : BackTrackerCore(pset) {
36  reg.sPreProcessEvent.watch(this, &BackTracker::Rebuild);
38  fSTFU = 0;
39  }
40 
41  //----------------------------------------------------------------------
43 
44  //----------------------------------------------------------------------
46 
47 
48 
49  //----------------------------------------------------------------------
51  // Just drop the ScheduleContext that art requires.
52  RebuildNoSC(evt);
53  }
54 
56  // do nothing if this is data
57  if (evt.isRealData()) return;
58 
59  // do nothing if we are asked to do nothing
60  if (fDisableRebuild) return;
61 
62 
63 
64  // We have a new event, so clear the collections from the previous events
65  // Just the MC collections now, others as needed
66  fParticleList.clear();
67  fMCTruthList .clear();
68  fTrackIDToMCTruthIndex.clear();
69 
70 
71 
72  // get the MCParticles from the event
73 
74  try
75  {
76  auto partCol = evt.getValidHandle<std::vector<simb::MCParticle> >(fG4ModuleLabel);
77  if (partCol.failedToGet()) {
78  ++fSTFU;
79  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
80  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
81  << "failed to get handle to simb::MCParticle from " << fG4ModuleLabel
82  << ", return";
83  }
84  return;
85  }
86 
87  // get mapping from MCParticles to MCTruths; loop to fill fTrackIDToMCTruthIndex
88  art::FindOneP<simb::MCTruth> fo(partCol, evt, fG4ModuleLabel);
89  if( !fo.isValid() ){
90  ++fSTFU;
91  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
92  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
93  << "failed to associate MCTruth to MCParticle with " << fG4ModuleLabel
94  << "; all attempts to backtrack will fail\n";
95  }
96  return;
97 
98  } else {
99  for (size_t iPart = 0; iPart < partCol->size(); ++iPart) {
100 
101  simb::MCParticle *part = new simb::MCParticle(partCol->at(iPart));
102  fParticleList.Add(part);
103 
104  // get the simb::MCTruth associated to this MCParticle
105  try {
106  art::Ptr<simb::MCTruth> mct = fo.at(iPart);
107  if (fMCTruthList.size() < 1) {
108  fMCTruthList.push_back(mct);
109  } else {
110  // check that we are not adding a simb::MCTruth twice to
111  // the collection we know that all the particles for a
112  // given simb::MCTruth are put into the collection of
113  // particles at the same time, so we can just check that the
114  // current ::art::Ptr has a different id than the last one put
115  if (!(mct == fMCTruthList.back())) fMCTruthList.push_back(mct);
116  }
117 
118  // Fill the track id to mctruth index map. partCol will not contain
119  // negative track ids.
120  fTrackIDToMCTruthIndex[partCol->at(iPart).TrackId()] = fMCTruthList.size() - 1;
121  }
122  catch (cet::exception &ex) {
123  ++fSTFU;
124  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
125  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
126  << "unable to find MCTruth from ParticleList created in "
127  << fG4ModuleLabel
128  << "; all attempts to backtrack will fail\n"
129  << "message from caught exception:\n" << ex;
130  }
131  }
132  } // end loop over MCParticles
133  }
134 
135  }
136 
137 
138  catch (cet::exception &ex)
139  {
140  return;
141  }
142 
143  // Register the electromagnetic Eve calculator
144  fParticleList.AdoptEveIdCalculator(new sim::EmEveIdCalculator);
145 
146  fHasMC = true;
147 
148 
149 
150  // Inverse of drift velocity and longitudinal diffusion constant will
151  // be needed by the backtracker when fHasHits, and also the geometry
152  auto detProp = gar::providerFrom<detinfo::DetectorPropertiesService>();
153  fInverseVelocity = 1.0/detProp->DriftVelocity(detProp->Efield(),
154  detProp->Temperature());
155 
156  auto garProp = gar::providerFrom<detinfo::GArPropertiesService>();
157  fLongDiffConst = std::sqrt(2.0 * garProp->LongitudinalDiffusion());
158 
159  fGeo = gar::providerFrom<geo::GeometryGAr>();
160 
161  // Create the channel to energy deposit collection. Start by
162  // looking for the RawDigit collection from the event and create
163  // a FindMany mapping between the digits and energy deposits if it exists.
164  for (auto vec : fChannelToEDepCol) vec.clear();
165  fChannelToEDepCol.clear();
166  auto digCol = evt.getHandle<std::vector<raw::RawDigit>>(fRawTPCDataLabel);
167  if (!digCol) {
168  ++fSTFU;
169  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
170  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
171  << "Unable to find RawDigits in " << fRawTPCDataLabel <<
172  "; no backtracking in TPC will be possible" <<
173  "\n Well did you EXPECT RawDigits in this file?";
174  }
175 
176  } else {
177  art::FindMany<sdp::EnergyDeposit, float> fmEnergyDep(digCol, evt, fRawTPCDataLabel);
178  if (!fmEnergyDep.isValid()) {
179  ++fSTFU;
180  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
181  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
182  << "Unable to find valid association between RawDigits and "
183  << "energy deposits in " << fRawTPCDataLabel <<
184  "; no backtracking in TPC will be possible" <<
185  "\n Well did you EXPECT those Assns in this file?";
186  }
187 
188  } else {
189  fChannelToEDepCol.resize(fGeo->NChannels());
190  ++fSTFU;
191  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
192  MF_LOG_DEBUG("BackTracker_service::RebuildNoSC")
193  << "There are " << fChannelToEDepCol.size()
194  << " channels in the geometry";
195  }
196 
197  std::vector<float const*> depweights;
198  std::vector<const sdp::EnergyDeposit*> eDeps;
199  for (size_t iDig = 0; iDig < digCol->size(); ++iDig) {
200  eDeps.clear();
201  depweights.clear();
202  fmEnergyDep.get(iDig, eDeps, depweights); // uses vector::insert
203  if (eDeps.size() < 1) continue;
204 
205  for(size_t iDep=0; iDep<eDeps.size(); iDep++) {
206  float w = 1.;
207  if(fSplitEDeps) w = *depweights[iDep];
208  fChannelToEDepCol[ (*digCol)[iDig].Channel() ].emplace_back(std::make_pair(eDeps[iDep],w));
209 
210  MF_LOG_DEBUG("BackTracker_service::RebuildNoSC") << "eDep\t" << iDep << " from RawDigit \t" << iDig
211  << "\t TrkID, energy, dl, position:\t " << eDeps[iDep]->TrackID()
212  << "\t " << eDeps[iDep]->Energy() << "\t " << eDeps[iDep]->dX()
213  << "\t " << eDeps[iDep]->X() << "\t " << eDeps[iDep]->Y()
214  << "\t " << eDeps[iDep]->Z() << std::endl;
215 
216  }
217  }
218  fHasHits = true;
219  }
220  }
221 
222 
223 
224  // Create the CellID to energy deposit collection. Start by
225  // looking for the CaloRawDigit collection from the event and create
226  // a FindMany mapping between these digits and CaloDeposits if it exists.
227  fECALTrackToTPCTrack->clear();
228  fCellIDToEDepCol.clear();
230  auto caloDigCol = evt.getHandle<std::vector<raw::CaloRawDigit>>(ecalrawtag);
231  if (!caloDigCol) {
232  ++fSTFU;
233  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
234  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
235  << "Unable to find CaloRawDigits in " << fRawCaloDataLabel <<
236  "; no backtracking in ECAL will be possible" <<
237  "\n Well did you EXPECT CaloRawDigits in this file?";
238  }
239 
240  } else {
241  art::FindMany<sdp::CaloDeposit> fmCaloDep(caloDigCol, evt, ecalrawtag);
242  if (!fmCaloDep.isValid()) {
243  ++fSTFU;
244  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
245  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
246  << "Unable to find valid association between CaloRawDigits and "
247  << "calorimeter energy deposits in " << fRawCaloDataLabel <<
248  "; no backtracking in ECAL will be possible" <<
249  "\n Well did you EXPECT those Assns in this file?";
250  }
251 
252  } else {
253  std::vector<const sdp::CaloDeposit*> CeDeps;
254  for (size_t iCalDig = 0; iCalDig < caloDigCol->size(); ++iCalDig) {
255  CeDeps.clear();
256  fmCaloDep.get(iCalDig, CeDeps); // uses vector::insert
257  if (CeDeps.size() < 1) continue;
258  fCellIDToEDepCol[ (*caloDigCol)[iCalDig].CellID() ] = CeDeps;
259  }
260  fHasCalHits = true;
261  }
262  }
263 
264 
265 
266  // Create an unordered map of IDNumbers of reco'd Tracks to the hits in those tracks
267  // Just to keep the code comprehensible, first map Tracks to TPCClusters, then
268  // TPCClusters to Hits, then build the combined map.
269  //std::unordered_map< rec::IDNumber, std::vector<const rec::TPCCluster*> > lTrackIDToTPCClusters;
270  fTrackIDToClusters.clear();
271  auto recoTrackCol = evt.getHandle<std::vector<rec::Track>>(fTrackLabel);
272  if (!recoTrackCol) {
273  ++fSTFU;
274  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
275  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
276  << "Unable to find rec::Tracks in " << fTrackLabel <<
277  "; no backtracking of reconstructed tracks will be possible" <<
278  "\n Well did you EXPECT tracks in this file?";
279  }
280 
281  } else {
282  art::FindMany<rec::TPCCluster> fmTPCClusts(recoTrackCol, evt, fTrackLabel);
283  if (!fmTPCClusts.isValid()) {
284  ++fSTFU;
285  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
286  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
287  << "Unable to find valid association between Tracks and "
288  << "TPCClusters in " << fTrackLabel <<
289  "; no backtracking of reconstructed tracks will be possible" <<
290  "\n Well did you EXPECT those Assns in this file?";
291  }
292 
293  } else {
294  //std::vector<const rec::TPCCluster*> tpclusThisTrack;
295  std::vector<const rec::TPCCluster*> tpclusThisTrack;
296  for (size_t iTrack = 0; iTrack < recoTrackCol->size(); ++iTrack) {
297  tpclusThisTrack.clear();
298  fmTPCClusts.get(iTrack, tpclusThisTrack); // uses vector::insert
299  if (tpclusThisTrack.size() < 1) continue;
300  //lTrackIDToTPCClusters[ (*recoTrackCol)[iTrack].getIDNumber() ] = tpclusThisTrack;
301  fTrackIDToClusters[ (*recoTrackCol)[iTrack].getIDNumber() ] = tpclusThisTrack;
302  }
303  }
304  }
305 
306  // Construct map of TPCCluster to Hits
307  //std::unordered_map< rec::IDNumber,std::vector<art::Ptr<rec::Hit>> > lTPClusIDsToHits;
308  fTPCClusterIDToHits.clear();
309  auto tpclusCol = evt.getHandle<std::vector<rec::TPCCluster>>(fTPCClusterLabel);
310  if (!tpclusCol) {
311  ++fSTFU;
312  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
313  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
314  << "Unable to find rec::TPCClusters in " << fTPCClusterLabel <<
315  "; no backtracking of reconstructed tracks will be possible" <<
316  "\n Well did you EXPECT TPCClusters in this file?";
317  }
318 
319  } else {
320  art::FindManyP<rec::Hit> fmHits(tpclusCol, evt, fTPCClusterLabel);
321  if (!fmHits.isValid()) {
322  ++fSTFU;
323  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
324  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
325  << "Unable to find valid association between TPCClusters and "
326  << "Hits in " << fTPCClusterLabel <<
327  "; no backtracking of reconstructed tracks will be possible" <<
328  "\n Well did you EXPECT those Assns in this file?";
329  }
330 
331  } else {
332  std::vector<art::Ptr<rec::Hit>> hitsThisTPCCluster;
333  for (size_t iTPClus = 0; iTPClus < tpclusCol->size(); ++iTPClus) {
334  hitsThisTPCCluster.clear();
335  fmHits.get(iTPClus, hitsThisTPCCluster); // uses vector::insert
336  if (hitsThisTPCCluster.size() < 1) continue;
337  //lTPClusIDsToHits[(*tpclusCol)[iTPClus].getIDNumber()] = hitsThisTPCCluster;
338  fTPCClusterIDToHits[(*tpclusCol)[iTPClus].getIDNumber()] = hitsThisTPCCluster;
339  }
340  }
341  }
342 
343  // Now compound the lists to make fTrackIDToHits
344  fTrackIDToHits.clear();
345  //if ( !lTrackIDToTPCClusters.empty() && !lTPClusIDsToHits.empty()) {
346  if ( !fTrackIDToClusters.empty() && !fTPCClusterIDToHits.empty()) {
347  for (auto aTrack : *recoTrackCol) {
348  std::vector<const rec::TPCCluster*> tpclusThisTrack =
349  //std::vector<art::Ptr<rec::TPCCluster>> tpclusThisTrack =
350  //lTrackIDToTPCClusters[ aTrack.getIDNumber() ];
351  fTrackIDToClusters[ aTrack.getIDNumber() ];
352  std::vector<art::Ptr<rec::Hit>> hitsThisTrack;
353  for (const rec::TPCCluster* aTPClus : tpclusThisTrack) {
354  //for (const art::Ptr<rec::TPCCluster> aTPClus : tpclusThisTrack) {
355  std::vector<art::Ptr<rec::Hit>> hitsThisClus =
356  //lTPClusIDsToHits[aTPClus->getIDNumber()];
357  fTPCClusterIDToHits[aTPClus->getIDNumber()];
358  hitsThisTrack.insert( hitsThisTrack.end(),
359  hitsThisClus.begin(),hitsThisClus.end() );
360  }
361  // Explicit assumption is that each hit is in at most 1 cluster so
362  // there are no duplicates in hitsThisTrack
363  fTrackIDToHits[aTrack.getIDNumber()] = hitsThisTrack;
364  }
365  }
366  fHasTracks = true;
367 
368 
369 
370  // Create an unordered map of IDNumbers of reco'd Clusters to the CaloHits in those tracks
372  auto recoClusterCol = evt.getHandle<std::vector<rec::Cluster>>(ecalclustertag);
373  if (!recoClusterCol) {
374  ++fSTFU;
375  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
376  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
377  << "Unable to find rec::Clusters in " << fClusterLabel << ", "
378  << fClusterECALInstance << " instance; no backtracking of ECAL "
379  << "clusters will be possible" <<
380  "\n Well did you EXPECT ECAL Clusters in this file?";
381  }
382 
383  } else {
384  art::FindManyP<rec::CaloHit> fmCaloHits(recoClusterCol, evt, ecalclustertag);
385  if (!fmCaloHits.isValid()) {
386  ++fSTFU;
387  if (fSTFU<=10) { // Ye who comprehend messagelogger, doeth ye better.
388  MF_LOG_WARNING("BackTracker_service::RebuildNoSC")
389  << "Unable to find valid association between Clusters and "
390  << "CaloHits in " << fClusterLabel << ", " << fClusterECALInstance
391  << " instance; no backtracking of reconstructed tracks will be possible" <<
392  "\n Well did you EXPECT those Assns in this file?";
393  }
394 
395  } else {
396  std::vector<art::Ptr<rec::CaloHit>> caloHitsThisCluster;
397  for (size_t iCluster = 0; iCluster < recoClusterCol->size(); ++iCluster) {
398  caloHitsThisCluster.clear();
399  fmCaloHits.get(iCluster, caloHitsThisCluster); // uses vector::insert
400  if (caloHitsThisCluster.size() < 1) continue;
401  fClusterIDToCaloHits[ (*recoClusterCol)[iCluster].getIDNumber() ] = caloHitsThisCluster;
402  }
403  }
404  }
405  fHasClusters = true;
406 
407  return;
408  }
409 
410 
411 
412 
413 
415  } // namespace cheat
416 } // namespace gar
double fLongDiffConst
longitudinal diffusion constant
std::vector< std::vector< std::pair< const sdp::EnergyDeposit *, float const > > > fChannelToEDepCol
convenience collections of EnergyDeposits for each channel
std::unordered_map< rec::IDNumber, std::vector< const rec::TPCCluster * > > fTrackIDToClusters
Reco track ID to track&#39;s clusters.
Handle< PROD > getHandle(SelectorBase const &) const
Definition: DataViewImpl.h:382
BackTracker(fhicl::ParameterSet const &pset, art::ActivityRegistry &reg)
std::string fRawCaloDataECALInstance
instance name for the ECAL raw hits
std::string fClusterLabel
label for ECAL cluster producing module
std::unordered_map< raw::CellID_t, std::vector< const sdp::CaloDeposit * > > fCellIDToEDepCol
convenience collections of EnergyDeposit for each cell
const geo::GeometryCore * fGeo
pointer to the geometry
std::unordered_map< int, int > fTrackIDToMCTruthIndex
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::Hit > > > fTrackIDToHits
Reco track ID to track&#39;s hits.
void RebuildNoSC(art::Event const &evt)
bool isRealData() const
std::string fClusterECALInstance
instance name for the ECAL clusters
void Rebuild(art::Event const &evt, art::ScheduleContext)
std::string fRawTPCDataLabel
label for TPC readout module
sim::ParticleList fParticleList
Maps MCParticle::TrackId() to same MCParticle.
std::string fTPCClusterLabel
label for TPCCluster producing module
std::string fTrackLabel
label for final track producing module
ValidHandle< PROD > getValidHandle(InputTag const &tag) const
Definition: DataViewImpl.h:441
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::Hit > > > fTPCClusterIDToHits
Reco TPC cluster ID to cluster&#39;s hits.
std::unordered_map< rec::IDNumber, std::vector< art::Ptr< rec::CaloHit > > > fClusterIDToCaloHits
Reco ECAL cluster ID to CaloHits.
std::unordered_map< int, int > * fECALTrackToTPCTrack
results of previous FindTPCEve calls
GlobalSignal< detail::SignalResponseType::FIFO, void(Event const &, ScheduleContext)> sPreProcessEvent
std::string fG4ModuleLabel
label for geant4 module
General GArSoft Utilities.
#define DEFINE_ART_SERVICE(svc)
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
#define MF_LOG_DEBUG(id)
TCEvent evt
Definition: DataStructs.cxx:7
std::vector< art::Ptr< simb::MCTruth > > fMCTruthList
all the MCTruths for the event
#define MF_LOG_WARNING(category)
art framework interface to geometry description
double fInverseVelocity
inverse drift velocity
bool fDisableRebuild
for switching off backtracker&#39;s rebuild of the MCParticle tables
cet::coded_exception< error, detail::translate > exception
Definition: exception.h:33
QTextStream & endl(QTextStream &s)