LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
CRHitRemoval_module.cc
Go to the documentation of this file.
1 //
3 // Class: CRHitRemoval
4 // Module Type: producer
5 // File: CRHitRemoval_module.cc
6 //
7 // This module produces RecoBase/Hit objects after removing those
8 // deemed to be due to CR muons.
9 //
10 // Configuration parameters:
11 //
12 // CosmicProducerLabels - a list of cosmic ray producers which should be or'ed
13 // HitProducerLabel - the producer of the recob::Hit objects
14 // PFParticleProducerLabel - the producer of the recob::PFParticles to consider
15 // TrackProducerLabel - the producer of the recob::Track objects
16 // CosmicTagThresholds - a vector of thresholds to apply to label as cosmic
17 // EndTickPadding - # ticks to "pad" the end tick to account for possible
18 // uncertainty in drift velocity
19 //
20 // Created by Tracy Usher (usher@slac.stanford.edu) on September 18, 2014
21 //
23 
24 #include <cmath>
25 #include <algorithm>
26 #include <vector>
27 
32 
44 
46 {
47 public:
48 
49  // Copnstructors, destructor.
50  explicit CRHitRemoval(fhicl::ParameterSet const & pset);
51  virtual ~CRHitRemoval();
52 
53  // Overrides.
54  virtual void reconfigure(fhicl::ParameterSet const & pset);
55  virtual void produce(art::Event & e);
56  virtual void beginJob();
57  virtual void endJob();
58 
59 private:
60  // define vector for hits to make sure of uniform use
61  using HitPtrVector = std::vector<art::Ptr<recob::Hit>>;
62 
63  // Methods
64  void collectPFParticleHits(const recob::PFParticle* pfParticle,
65  const art::Handle<std::vector<recob::PFParticle> >& pfParticleHandle,
66  const art::FindManyP<recob::Cluster>& partToClusAssns,
67  const art::FindManyP<recob::Hit>& clusToHitAssns,
68  HitPtrVector& hitVec);
69 
74 
79 
80  void FilterHits(HitPtrVector& hits, HitPtrVector& used_hits);
81 
82  // Fcl parameters.
83  std::vector<std::string> fCosmicProducerLabels;
84  std::string fHitProducerLabel;
86  std::vector<std::string> fTrackProducerLabels;
87  std::vector<std::string> fAssnProducerLabels;
88 
89  std::vector<double> fCosmicTagThresholds;
90 
92 
97 
98  // Statistics.
99  int fNumEvent;
101 };
102 
104 
105 //----------------------------------------------------------------------------
112 CRHitRemoval::CRHitRemoval(fhicl::ParameterSet const & pset) :
113 fNumEvent(0),
114 fNumCRRejects(0)
115 {
116  reconfigure(pset);
117 
118  // let HitCollectionCreator declare that we are going to produce
119  // hits and associations with wires and raw digits
120  // (with no particular product label)
122 
123  // Report.
124  mf::LogInfo("CRHitRemoval") << "CRHitRemoval configured\n";
125 }
126 
127 //----------------------------------------------------------------------------
130 {}
131 
132 //----------------------------------------------------------------------------
140 {
141  fCosmicProducerLabels = pset.get<std::vector<std::string> >("CosmicProducerLabels");
142  fHitProducerLabel = pset.get<std::string>("HitProducerLabel");
143  fPFParticleProducerLabel = pset.get<std::string>("PFParticleProducerLabel");
144  fTrackProducerLabels = pset.get<std::vector<std::string>>("TrackProducerLabels");
145  fAssnProducerLabels = pset.get<std::vector<std::string>>("AssnProducerLabels");
146  fCosmicTagThresholds = pset.get<std::vector<double> >("CosmicTagThresholds");
147  fEndTickPadding = pset.get<int>("EndTickPadding", 50);
148  fMaxOutOfTime = pset.get<int>("MaxOutOfTime", 4);
149 }
150 
151 //----------------------------------------------------------------------------
154 {
155  auto const* detp = lar::providerFrom<detinfo::DetectorPropertiesService>();
156  auto const* geo = lar::providerFrom<geo::Geometry>();
157  auto const* ts = lar::providerFrom<detinfo::DetectorClocksService>();
158 
159  float samplingRate = detp->SamplingRate();
160  float driftVelocity = detp->DriftVelocity( detp->Efield(), detp->Temperature() ); // cm/us
161 
162  fDetectorWidthTicks = 2*geo->DetHalfWidth()/(driftVelocity*samplingRate/1000);
163  fMinTickDrift = ts->Time2Tick(ts->TriggerTime()); // this is the hardware trigger time
165 }
166 
167 //----------------------------------------------------------------------------
181 {
182  ++fNumEvent;
183 
184  // Start by looking up the original hits
186  evt.getByLabel(fHitProducerLabel, hitHandle);
187 
188  // also get the associated wires and raw digits;
189  // we assume they have been created by the same module as the hits
190  art::FindOneP<raw::RawDigit> ChannelHitRawDigits(hitHandle, evt, fHitProducerLabel);
191  art::FindOneP<recob::Wire> ChannelHitWires(hitHandle, evt, fHitProducerLabel);
192 
193  // If there are no hits then there should be no output
194  if (!hitHandle.isValid()) return;
195 
196  HitPtrVector ChHits;
197  art::fill_ptr_vector(ChHits, hitHandle);
198 
199  // this object contains the hit collection
200  // and its associations to wires and raw digits:
201  recob::HitCollectionCreator hcol(*this,
202  evt,
203  /* doWireAssns */ ChannelHitWires.isValid(),
204  /* doRawDigitAssns */ ChannelHitRawDigits.isValid()
205  );
206 
207  // Now recover thre remaining collections of objects in the event store that we need
208  // Recover the PFParticles that are ultimately associated to tracks
209  // This will be the key to recovering the hits
211  evt.getByLabel(fPFParticleProducerLabel, pfParticleHandle);
212 
213  // Without a valid collection of PFParticles we can't do the hit removal
214  if (!pfParticleHandle.isValid())
215  {
216  copyAllHits(ChHits, ChannelHitRawDigits, ChannelHitWires, hcol);
217 
218  // put the hit collection and associations into the event
219  hcol.put_into(evt);
220 
221  return;
222  }
223 
224  // Recover the clusters so we can do associations to the hits
225  // In theory the clusters come from the same producer as the PFParticles
227  evt.getByLabel(fPFParticleProducerLabel, clusterHandle);
228 
229  // If there are no clusters then something is really wrong
230  if (!clusterHandle.isValid())
231  {
232  copyAllHits(ChHits, ChannelHitRawDigits, ChannelHitWires, hcol);
233 
234  // put the hit collection and associations into the event
235  hcol.put_into(evt);
236 
237  return;
238  }
239 
240  // Build the list of cosmic tag producers, associations and thresholds
241  std::vector<art::Handle<std::vector<anab::CosmicTag>>> cosmicHandleVec;
242  std::vector<std::map<int,std::vector<art::Ptr<recob::Track>>>> cosmicToTrackVecMapVec;
243  std::vector<std::map<int,std::vector<art::Ptr<recob::PFParticle>>>> trackToPFParticleVecMapVec;
244  std::vector<double> thresholdVec;
245 
246  for(size_t idx = 0; idx != fCosmicProducerLabels.size(); idx++)
247  {
248  std::string& handleLabel(fCosmicProducerLabels[idx]);
249 
251  evt.getByLabel(handleLabel, cosmicHandle);
252 
253  if (cosmicHandle.isValid())
254  {
255  // Look up the associations to tracks
256  art::FindManyP<recob::Track> cosmicTrackAssns(cosmicHandle, evt, handleLabel);
257 
258  // Get the handle to the tracks
260  evt.getByLabel(fTrackProducerLabels[idx], trackHandle);
261 
262  // This should be the case
263  if (trackHandle.isValid())
264  {
265  std::map<int,std::vector<art::Ptr<recob::Track>>> cosmicToTrackVecMap;
266  std::map<int, std::vector<art::Ptr<recob::PFParticle>>> trackToPFParticleVecMap;
267 
268  // Loop through the cosmic tags
269  for(size_t cosmicIdx = 0; cosmicIdx < cosmicHandle->size(); cosmicIdx++)
270  {
271  art::Ptr<anab::CosmicTag> cosmicTag(cosmicHandle, cosmicIdx);
272 
273  std::vector<art::Ptr<recob::Track>> cosmicToTrackVec = cosmicTrackAssns.at(cosmicTag.key());
274 
275  cosmicToTrackVecMap[cosmicTag.key()] = cosmicToTrackVec;
276 
277  art::FindManyP<recob::PFParticle> trackPFParticleAssns(trackHandle, evt, fAssnProducerLabels[idx]);
278 
279  for(auto& track : cosmicToTrackVec)
280  {
281  std::vector<art::Ptr<recob::PFParticle>> trackToPFParticleVec = trackPFParticleAssns.at(track.key());
282 
283  for(auto& pfParticle : trackToPFParticleVec)
284  trackToPFParticleVecMap[track.key()].push_back(pfParticle);
285  }
286  }
287 
288  // Store these collections
289  cosmicHandleVec.emplace_back(cosmicHandle);
290  cosmicToTrackVecMapVec.emplace_back(cosmicToTrackVecMap);
291  trackToPFParticleVecMapVec.emplace_back(trackToPFParticleVecMap);
292  thresholdVec.push_back(fCosmicTagThresholds[idx]);
293  }
294  }
295  }
296 
297  // No cosmic tags then nothing to do here
298  if (cosmicHandleVec.empty())
299  {
300  copyAllHits(ChHits, ChannelHitRawDigits, ChannelHitWires, hcol);
301 
302  // put the hit collection and associations into the event
303  hcol.put_into(evt);
304 
305  return;
306  }
307 
308  // Now we walk up the remaining list of associations needed to go from CR tags to hits
309  // We'll need to go from tracks to PFParticles
310  // From PFParticles we go to clusters
311  art::FindManyP<recob::Cluster> clusterAssns(pfParticleHandle, evt, fPFParticleProducerLabel);
312 
313  // Likewise, recover the collection of associations to hits
314  art::FindManyP<recob::Hit> clusterHitAssns(clusterHandle, evt, fPFParticleProducerLabel);
315 
316  // No point double counting hits
317  std::set<const recob::PFParticle*> taggedSet;
318 
319  // Start the identification of hits to remove. The outer loop is over the various producers of
320  // the CosmicTag objects we're examininig
321  for(size_t idx = 0; idx != cosmicHandleVec.size(); idx++)
322  {
323  // Obviously, dereference the handle and associations
324  const art::Handle<std::vector<anab::CosmicTag> >& cosmicHandle(cosmicHandleVec[idx]);
325  const std::map<int,std::vector<art::Ptr<recob::Track>>>& crTagTrackVec(cosmicToTrackVecMapVec[idx]);
326  const std::map<int,std::vector<art::Ptr<recob::PFParticle>>>& trackToPFParticleVecMap(trackToPFParticleVecMapVec[idx]);
327 
328  for(size_t crIdx = 0; crIdx != cosmicHandle->size(); crIdx++)
329  {
330  art::Ptr<anab::CosmicTag> cosmicTag(cosmicHandle, crIdx);
331 
332  // If this was tagged as a CR muon then we have work to do!
333  if (cosmicTag->CosmicScore() > thresholdVec[idx])
334  {
335  // Recover the associated track
336  std::vector<art::Ptr<recob::Track>> trackVec(crTagTrackVec.at(cosmicTag.key()));
337 
338  // Loop over the tracks (almost always only 1)
339  for(const auto& track : trackVec)
340  {
341  std::map<int,std::vector<art::Ptr<recob::PFParticle>>>::const_iterator trackToPFParticleVecItr = trackToPFParticleVecMap.find(track.key());
342 
343  if (trackToPFParticleVecItr != trackToPFParticleVecMap.end())
344  {
345  // Loop through them
346  for(const auto& pfParticlePtr : trackToPFParticleVecItr->second)
347  {
348  // Get bare pointer
349  const recob::PFParticle* pfParticle = pfParticlePtr.get();
350 
351  // A cosmic ray must be a primary (by fiat)
352  while(!pfParticle->IsPrimary()) pfParticle = art::Ptr<recob::PFParticle>(pfParticleHandle,pfParticle->Parent()).get();
353 
354  // Add to our list of tagged PFParticles
355  taggedSet.insert(pfParticle);
356  }
357  }
358  }
359  }
360  }
361  }
362 
363  // If no PFParticles have been tagged then nothing to do
364  if (!taggedSet.empty())
365  {
366  // This may all seem backwards... but what you want to do is remove all the hits which are associated to tagged
367  // cosmic ray tracks/PFParticles and what you want to leave is all other hits. This includes hits on other PFParticles
368  // as well as unassociated (as yet) hits.
369  // One also needs to deal with a slight complication with hits in 2D which are shared between untagged PFParticles and
370  // tagged ones... we should leave these in.
371 
372  // All that is left is to go through the PFParticles which have not been tagged and collect up all their hits
373  // to output to our new collection
374  // Note that this SHOULD take care of the case of shared 2D hits automagically since if the PFParticle has not
375  // been tagged and it shares hits we'll pick those up here.
376  HitPtrVector taggedHits;
377  HitPtrVector untaggedHits;
378 
379  // Loop through the PFParticles and build out the list of hits on untagged PFParticle trees
380  for(const auto& pfParticle : *pfParticleHandle)
381  {
382  // Start with only primaries
383  if (!pfParticle.IsPrimary()) continue;
384 
385  // Temporary container for these hits
386  HitPtrVector tempHits;
387 
388  // Find the hits associated to this untagged PFParticle
389  collectPFParticleHits(&pfParticle, pfParticleHandle, clusterAssns, clusterHitAssns, tempHits);
390 
391  // One more possible chance at identifying tagged hits...
392  // Check these hits to see if any lie outside time window
393  bool goodHits(true);
394 
395  if (taggedSet.find(&pfParticle) != taggedSet.end()) goodHits = false;
396 
397  if (goodHits)
398  {
399  int nOutOfTime(0);
400 
401  for(const auto& hit : tempHits)
402  {
403  // Check on out of time hits
404  if (hit->PeakTimeMinusRMS() < fMinTickDrift || hit->PeakTimePlusRMS() > fMaxTickDrift) nOutOfTime++;
405 
406  if (nOutOfTime > fMaxOutOfTime)
407  {
408  goodHits = false;
409  break;
410  }
411  }
412  }
413 
414  if (goodHits) std::copy(tempHits.begin(),tempHits.end(),std::back_inserter(untaggedHits));
415  else std::copy(tempHits.begin(),tempHits.end(),std::back_inserter(taggedHits));
416  }
417 
418  // First task - remove hits from the tagged hit collection that are inthe untagged hits (shared hits)
419  FilterHits(taggedHits,untaggedHits);
420 
421  // Now filter the tagged hits from the total hit collection
422  FilterHits(ChHits, taggedHits);
423  }
424 
425  // Copy our new hit collection to the output
426  copyInTimeHits(ChHits, ChannelHitRawDigits, ChannelHitWires, hcol);
427 
428  // put the hit collection and associations into the event
429  hcol.put_into(evt);
430 
431 }
432 
433 //----------------------------------------------------------------------------
449  const art::Handle<std::vector<recob::PFParticle> >& pfParticleHandle,
450  const art::FindManyP<recob::Cluster>& partToClusAssns,
451  const art::FindManyP<recob::Hit>& clusToHitAssns,
452  HitPtrVector& hitVec)
453 {
454  // Recover the clusters associated to the input PFParticle
455  std::vector<art::Ptr<recob::Cluster> > clusterVec = partToClusAssns.at(pfParticle->Self());
456 
457  int minTick(fMinTickDrift);
458  int maxTick(fMaxTickDrift);
459 
460  // Loop over the clusters and grab the associated hits
461  for(const auto& cluster : clusterVec)
462  {
463  std::vector<art::Ptr<recob::Hit> > clusHitVec = clusToHitAssns.at(cluster.key());
464  hitVec.insert(hitVec.end(), clusHitVec.begin(), clusHitVec.end());
465 
466  int minHitTick = (*std::min_element(clusHitVec.begin(),clusHitVec.end(),[](const auto& hit,const auto& min){return hit->PeakTimeMinusRMS() < min->PeakTimeMinusRMS();}))->PeakTimeMinusRMS();
467  int maxHitTick = (*std::max_element(clusHitVec.begin(),clusHitVec.end(),[](const auto& hit,const auto& max){return hit->PeakTimePlusRMS() > max->PeakTimePlusRMS();}))->PeakTimePlusRMS();
468 
469  if (minHitTick < minTick) minTick = minHitTick;
470  if (maxHitTick < maxTick) maxTick = maxHitTick;
471  }
472 
473  // Loop over the daughters of this particle and remove their hits as well
474  for(const auto& daughterId : pfParticle->Daughters())
475  {
476  art::Ptr<recob::PFParticle> daughter(pfParticleHandle, daughterId);
477 
478  collectPFParticleHits(daughter.get(), pfParticleHandle, partToClusAssns, clusToHitAssns, hitVec);
479  }
480 
481  return;
482 }
483 
485  art::FindOneP<raw::RawDigit>& rawDigitAssns,
486  art::FindOneP<recob::Wire>& wireAssns,
487  recob::HitCollectionCreator& newHitCollection)
488 {
489  for(const auto& hitPtr : inputHits)
490  {
491  art::Ptr<recob::Wire> wire = wireAssns.at(hitPtr.key());
492  art::Ptr<raw::RawDigit> rawdigits = rawDigitAssns.at(hitPtr.key());
493 
494  // just copy it
495  newHitCollection.emplace_back(*hitPtr, wire, rawdigits);
496  }
497 
498  return;
499 }
500 
502  art::FindOneP<raw::RawDigit>& rawDigitAssns,
503  art::FindOneP<recob::Wire>& wireAssns,
504  recob::HitCollectionCreator& newHitCollection)
505 {
506  for(const auto& hitPtr : inputHits)
507  {
508  // Check on out of time hits
509  if (hitPtr->PeakTimeMinusRMS() < fMinTickDrift || hitPtr->PeakTimePlusRMS() > fMaxTickDrift) continue;
510 
511  art::Ptr<recob::Wire> wire = wireAssns.at(hitPtr.key());
512  art::Ptr<raw::RawDigit> rawdigits = rawDigitAssns.at(hitPtr.key());
513 
514  // just copy it
515  newHitCollection.emplace_back(*hitPtr, wire, rawdigits);
516  }
517 
518  return;
519 }
520 
521 //----------------------------------------------------------------------------
522 // Filter a collection of hits (set difference).
523 // This function is copied from Track3DKalmanHit_module.cc
524 //
525 // Arguments:
526 //
527 // hits - Hit collection from which hits should be removed.
528 // used_hits - Hits to remove.
529 //
531 {
532  if(used_hits.size() > 0)
533  {
534  // Make sure both hit collections are sorted.
535  std::stable_sort(hits.begin(), hits.end());
536  std::stable_sort(used_hits.begin(), used_hits.end());
537 
538  // Do set difference operation.
539  std::vector<art::Ptr<recob::Hit>>::iterator it
540  = std::set_difference(hits.begin(), hits.end(), used_hits.begin(), used_hits.end(), hits.begin());
541 
542  // Truncate hit collection.
543  hits.erase(it, hits.end());
544  }
545 }
546 
547 
548 //----------------------------------------------------------------------------
551 {
552  double aveCRPerEvent = fNumEvent > 0 ? double(fNumCRRejects) / double(fNumEvent) : 0.;
553 
554  mf::LogInfo("CRHitRemoval")
555  << "CRHitRemoval statistics:\n"
556  << " Number of events = " << fNumEvent << "\n"
557  << " Number of Cosmic Rays found = " << fNumCRRejects
558  << ", " << aveCRPerEvent << " average/event";
559 }
key_type key() const
Definition: Ptr.h:356
const std::vector< size_t > & Daughters() const
Returns the collection of daughter particles.
Definition: PFParticle.h:114
virtual void reconfigure(fhicl::ParameterSet const &pset)
std::string fPFParticleProducerLabel
PFParticle producer.
size_t Self() const
Returns the index of this particle.
Definition: PFParticle.h:92
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Declaration of signal hit object.
int fEndTickPadding
Padding the end tick.
void copyInTimeHits(std::vector< art::Ptr< recob::Hit >> &, art::FindOneP< raw::RawDigit > &, art::FindOneP< recob::Wire > &, recob::HitCollectionCreator &)
Cluster finding and building.
static void declare_products(ModuleType &producer, std::string instance_name="", bool doWireAssns=true, bool doRawDigitAssns=true)
Declares the hit products we are going to fill.
Definition: HitCreator.h:1117
int fNumCRRejects
Number of tracks produced.
float & CosmicScore()
Definition: CosmicTag.h:65
void collectPFParticleHits(const recob::PFParticle *pfParticle, const art::Handle< std::vector< recob::PFParticle > > &pfParticleHandle, const art::FindManyP< recob::Cluster > &partToClusAssns, const art::FindManyP< recob::Hit > &clusToHitAssns, HitPtrVector &hitVec)
virtual ~CRHitRemoval()
Destructor.
bool isValid() const
Definition: Handle.h:190
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
Helper functions to create a hit.
Int_t max
Definition: plot.C:27
void hits()
Definition: readHits.C:15
A class handling a collection of hits and its associations.
Definition: HitCreator.h:513
std::vector< std::string > fAssnProducerLabels
Track to PFParticle assns producer.
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:42
Provides recob::Track data product.
size_t Parent() const
Definition: PFParticle.h:96
parameter set interface
std::vector< art::Ptr< recob::Hit >> HitPtrVector
std::string fHitProducerLabel
The full collection of hits.
T get(std::string const &key) const
Definition: ParameterSet.h:231
int fMaxTickDrift
Ending tick.
bool IsPrimary() const
Returns whether the particle is the root of the flow.
Definition: PFParticle.h:86
void emplace_back(recob::Hit &&hit, art::Ptr< recob::Wire > const &wire=art::Ptr< recob::Wire >(), art::Ptr< raw::RawDigit > const &digits=art::Ptr< raw::RawDigit >())
Adds the specified hit to the data collection.
Definition: HitCreator.cxx:245
virtual void endJob()
End job method.
std::vector< double > fCosmicTagThresholds
Thresholds for tagging.
Declaration of cluster object.
Detector simulation of raw signals on wires.
virtual void produce(art::Event &e)
Hierarchical representation of particle flow.
Definition: PFParticle.h:44
Utility object to perform functions of association.
int fMaxOutOfTime
Max hits that can be out of time before rejecting.
T const * get() const
Definition: Ptr.h:321
bool getByLabel(std::string const &label, std::string const &productInstanceName, Handle< PROD > &result) const
Definition: DataViewImpl.h:344
Int_t min
Definition: plot.C:26
CRHitRemoval(fhicl::ParameterSet const &pset)
int fDetectorWidthTicks
Effective drift time in ticks.
std::vector< std::string > fTrackProducerLabels
Track producer.
int fNumEvent
Number of events seen.
TCEvent evt
Definition: DataStructs.cxx:5
void fill_ptr_vector(std::vector< Ptr< T >> &ptrs, H const &h)
Definition: Ptr.h:464
Float_t e
Definition: plot.C:34
Namespace collecting geometry-related classes utilities.
Float_t track
Definition: plot.C:34
int fMinTickDrift
Starting tick.
void FilterHits(HitPtrVector &hits, HitPtrVector &used_hits)
virtual void beginJob()
Begin job method.
art framework interface to geometry description
void copyAllHits(std::vector< art::Ptr< recob::Hit >> &, art::FindOneP< raw::RawDigit > &, art::FindOneP< recob::Wire > &, recob::HitCollectionCreator &)
std::vector< std::string > fCosmicProducerLabels
List of cosmic tagger producers.