All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CosmicPFParticleTagger_module.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 // Class: CosmicPFParticleTagger
3 // Module Type: producer
4 // File: CosmicPFParticleTagger_module.cc
5 // This module checks timing and TPC volume boundaries as a
6 // way to tag potential cosmic rays
7 // This particular module uses PFParticles as input and handles
8 // special cases associated with them.
9 // This module started life as CosmicTrackTagger_module, written
10 // by Sarah Lockwitz, and small alterations made to handle the
11 // PFParticle input
12 //
13 // Generated at Wed Sep 17 19:17:00 2014 by Tracy Usher by cloning CosmicTrackTagger
14 // from art v1_02_02.
15 // artmod -e beginJob -e reconfigure -e endJob producer trkf::CosmicPFParticleTagger
16 ////////////////////////////////////////////////////////////////////////
17 
18 #include "art/Framework/Core/EDProducer.h"
19 #include "art/Framework/Core/ModuleMacros.h"
20 #include "art/Framework/Principal/Event.h"
21 #include "art/Framework/Services/Registry/ServiceHandle.h"
22 
23 #include <iterator>
24 
34 
35 namespace cosmic {
36  class CosmicPFParticleTagger;
37 }
38 
39 class cosmic::CosmicPFParticleTagger : public art::EDProducer {
40 public:
41  explicit CosmicPFParticleTagger(fhicl::ParameterSet const& p);
42 
43  void produce(art::Event& e) override;
44 
45 private:
47  std::string fTrackModuleLabel;
51  int fMaxOutOfTime; ///< Max hits that can be out of time before rejecting
54 };
55 
56 cosmic::CosmicPFParticleTagger::CosmicPFParticleTagger(fhicl::ParameterSet const& p) : EDProducer{p}
57 {
58 
59  //////// fSptalg = new cosmic::SpacePointAlg(p.get<fhicl::ParameterSet>("SpacePointAlg"));
60  auto const* geo = lar::providerFrom<geo::Geometry>();
61  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
62  auto const detp =
63  art::ServiceHandle<detinfo::DetectorPropertiesService const>()->DataForJob(clock_data);
64 
65  fDetHalfHeight = geo->DetHalfHeight();
66  fDetWidth = 2. * geo->DetHalfWidth();
67  fDetLength = geo->DetLength();
68 
69  float fSamplingRate = sampling_rate(clock_data);
70 
71  fPFParticleModuleLabel = p.get<std::string>("PFParticleModuleLabel");
72  fTrackModuleLabel = p.get<std::string>("TrackModuleLabel", "track");
73  fEndTickPadding = p.get<int>("EndTickPadding", 50); // Fudge the TPC edge in ticks...
74  fMaxOutOfTime = p.get<int>("MaxOutOfTime", 4);
75 
76  fTPCXBoundary = p.get<float>("TPCXBoundary", 5);
77  fTPCYBoundary = p.get<float>("TPCYBoundary", 5);
78  fTPCZBoundary = p.get<float>("TPCZBoundary", 5);
79 
80  const double driftVelocity = detp.DriftVelocity(detp.Efield(), detp.Temperature()); // cm/us
81 
82  fDetectorWidthTicks =
83  2 * geo->DetHalfWidth() / (driftVelocity * fSamplingRate / 1000); // ~3200 for uB
84  fMinTickDrift = clock_data.Time2Tick(clock_data.TriggerTime());
85  fMaxTickDrift = fMinTickDrift + fDetectorWidthTicks + fEndTickPadding;
86 
87  produces<std::vector<anab::CosmicTag>>();
88  produces<art::Assns<anab::CosmicTag, recob::Track>>();
89  produces<art::Assns<recob::PFParticle, anab::CosmicTag>>();
90 }
91 
92 void
94 {
95  // Instatiate the output
96  std::unique_ptr<std::vector<anab::CosmicTag>> cosmicTagTrackVector(
97  new std::vector<anab::CosmicTag>);
98  std::unique_ptr<art::Assns<anab::CosmicTag, recob::Track>> assnOutCosmicTagTrack(
99  new art::Assns<anab::CosmicTag, recob::Track>);
100  std::unique_ptr<art::Assns<recob::PFParticle, anab::CosmicTag>> assnOutCosmicTagPFParticle(
101  new art::Assns<recob::PFParticle, anab::CosmicTag>);
102 
103  // Recover handle for PFParticles
104  art::Handle<std::vector<recob::PFParticle>> pfParticleHandle;
105  evt.getByLabel(fPFParticleModuleLabel, pfParticleHandle);
106 
107  if (!pfParticleHandle.isValid()) {
108  evt.put(std::move(cosmicTagTrackVector));
109  evt.put(std::move(assnOutCosmicTagTrack));
110  return;
111  }
112 
113  // Recover the handle for the tracks
114  art::Handle<std::vector<recob::Track>> trackHandle;
115  evt.getByLabel(fTrackModuleLabel, trackHandle);
116 
117  if (!trackHandle.isValid()) {
118  evt.put(std::move(cosmicTagTrackVector));
119  evt.put(std::move(assnOutCosmicTagTrack));
120  return;
121  }
122 
123  // Recover handle for track <--> PFParticle associations
124  art::Handle<art::Assns<recob::PFParticle, recob::Track>> pfPartToTrackHandle;
125  evt.getByLabel(fTrackModuleLabel, pfPartToTrackHandle);
126 
127  // Recover the list of associated tracks
128  art::FindManyP<recob::Track> pfPartToTrackAssns(pfParticleHandle, evt, fTrackModuleLabel);
129 
130  // and the hits
131  art::FindManyP<recob::Hit> hitsSpill(trackHandle, evt, fTrackModuleLabel);
132 
133  // The outer loop is going to be over PFParticles
134  for (size_t pfPartIdx = 0; pfPartIdx != pfParticleHandle->size(); pfPartIdx++) {
135  art::Ptr<recob::PFParticle> pfParticle(pfParticleHandle, pfPartIdx);
136 
137  // Recover the track vector
138  std::vector<art::Ptr<recob::Track>> trackVec = pfPartToTrackAssns.at(pfPartIdx);
139 
140  // Is there a track associated to this PFParticle?
141  if (trackVec.empty()) {
142  // We need to make a null CosmicTag to store with this PFParticle to keep sequencing correct
143  std::vector<float> tempPt1, tempPt2;
144  tempPt1.push_back(-999);
145  tempPt1.push_back(-999);
146  tempPt1.push_back(-999);
147  tempPt2.push_back(-999);
148  tempPt2.push_back(-999);
149  tempPt2.push_back(-999);
150  cosmicTagTrackVector->emplace_back(tempPt1, tempPt2, 0., anab::CosmicTagID_t::kNotTagged);
151  util::CreateAssn(*this, evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
152  continue;
153  }
154 
155  // Start the tagging process...
156  int isCosmic = 0;
158  art::Ptr<recob::Track> track1 = trackVec.front();
159 
160  std::vector<art::Ptr<recob::Hit>> hitVec = hitsSpill.at(track1.key());
161 
162  // Recover track end points
163  auto vertexPosition = track1->Vertex();
164  auto vertexDirection = track1->VertexDirection();
165  auto endPosition = track1->End();
166 
167  // In principle there is one track associated to a PFParticle... but with current
168  // technology it can happen that a PFParticle is broken into multiple tracks. Our
169  // aim here is to find the maximum extents of all the tracks which have been
170  // associated to the single PFParticle
171  if (trackVec.size() > 1) {
172  for (size_t trackIdx = 1; trackIdx < trackVec.size(); trackIdx++) {
173  art::Ptr<recob::Track> track(trackVec[trackIdx]);
174 
175  auto trackStart = track->Vertex();
176  auto trackEnd = track->End();
177 
178  // Arc length possibilities for start of track
179  double arcLStartToStart = (trackStart - vertexPosition).Dot(vertexDirection);
180  double arcLStartToEnd = (trackEnd - vertexPosition).Dot(vertexDirection);
181 
182  if (arcLStartToStart < 0. || arcLStartToEnd < 0.) {
183  if (arcLStartToStart < arcLStartToEnd)
184  vertexPosition = trackStart;
185  else
186  vertexPosition = trackEnd;
187  }
188 
189  // Arc length possibilities for end of track
190  double arcLEndToStart = (trackStart - endPosition).Dot(vertexDirection);
191  double arcLEndToEnd = (trackEnd - endPosition).Dot(vertexDirection);
192 
193  if (arcLEndToStart > 0. || arcLEndToEnd > 0.) {
194  if (arcLEndToStart > arcLEndToEnd)
195  endPosition = trackStart;
196  else
197  endPosition = trackEnd;
198  }
199 
200  // add the hits from this track to the collection
201  hitVec.insert(
202  hitVec.end(), hitsSpill.at(track.key()).begin(), hitsSpill.at(track.key()).end());
203  }
204  }
205 
206  // "Track" end points in easily readable form
207  float trackEndPt1_X = vertexPosition.X();
208  float trackEndPt1_Y = vertexPosition.Y();
209  float trackEndPt1_Z = vertexPosition.Z();
210  float trackEndPt2_X = endPosition.X();
211  float trackEndPt2_Y = endPosition.Y();
212  float trackEndPt2_Z = endPosition.Z();
213 
214  /////////////////////////////////////
215  // Check that all hits on particle are "in time"
216  /////////////////////////////////////
217  int nOutOfTime(0);
218 
219  for (unsigned int p = 0; p < hitVec.size(); p++) {
220  int peakLessRms = hitVec[p]->PeakTimeMinusRMS();
221  int peakPlusRms = hitVec[p]->PeakTimePlusRMS();
222 
223  if (peakLessRms < fMinTickDrift || peakPlusRms > fMaxTickDrift) {
224  if (++nOutOfTime > fMaxOutOfTime) {
225  isCosmic = 1;
227  break; // If one hit is out of time it must be a cosmic ray
228  }
229  }
230  }
231 
232  /////////////////////////////////
233  // Now check the TPC boundaries:
234  /////////////////////////////////
235  if (isCosmic == 0) {
236  // In below we check entry and exit points. Note that a special case of a particle entering
237  // and exiting the same surface is considered to be running parallel to the surface and NOT
238  // entering and exiting.
239  // Also, in what follows we make no assumptions on which end point is the "start" or
240  // "end" of the track being considered.
241  unsigned boundaryMask[] = {0, 0};
242 
243  // Check x extents - note that uboone coordinaes system has x=0 at edge
244  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
245  // Also note that, in theory, any cosmic ray entering or exiting the X surfaces will have presumably
246  // been removed already by the checking of "out of time" hits... but this will at least label
247  // neutrino interaction tracks which exit through the X surfaces of the TPC
248  if (fDetWidth - trackEndPt1_X < fTPCXBoundary)
249  boundaryMask[0] = 0x1;
250  else if (trackEndPt1_X < fTPCXBoundary)
251  boundaryMask[0] = 0x2;
252 
253  if (fDetWidth - trackEndPt2_X < fTPCXBoundary)
254  boundaryMask[1] = 0x1;
255  else if (trackEndPt2_X < fTPCXBoundary)
256  boundaryMask[1] = 0x2;
257 
258  // Check y extents (note coordinate system change)
259  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
260  if (fDetHalfHeight - trackEndPt1_Y < fTPCYBoundary)
261  boundaryMask[0] = 0x10;
262  else if (fDetHalfHeight + trackEndPt1_Y < fTPCYBoundary)
263  boundaryMask[0] = 0x20;
264 
265  if (fDetHalfHeight - trackEndPt2_Y < fTPCYBoundary)
266  boundaryMask[1] = 0x10;
267  else if (fDetHalfHeight + trackEndPt2_Y < fTPCYBoundary)
268  boundaryMask[1] = 0x20;
269 
270  // Check z extents
271  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
272  if (fDetLength - trackEndPt1_Z < fTPCZBoundary)
273  boundaryMask[0] = 0x100;
274  else if (trackEndPt1_Z < fTPCZBoundary)
275  boundaryMask[0] = 0x200;
276 
277  if (fDetLength - trackEndPt2_Z < fTPCZBoundary)
278  boundaryMask[1] = 0x100;
279  else if (trackEndPt2_Z < fTPCZBoundary)
280  boundaryMask[1] = 0x200;
281 
282  unsigned trackMask = boundaryMask[0] | boundaryMask[1];
283  int nBitsSet(0);
284 
285  for (int idx = 0; idx < 12; idx++)
286  if (trackMask & (0x1 << idx)) nBitsSet++;
287 
288  // This should check for the case of a track which is both entering and exiting
289  // but we consider entering and exiting the z boundaries to be a special case (should it be?)
290  if (nBitsSet > 1) {
291  if ((trackMask & 0x300) != 0x300) {
292  isCosmic = 2;
293  if ((trackMask & 0x3) == 0x3)
295  else if ((trackMask & 0x30) == 0x30)
297  else if ((trackMask & 0x3) && (trackMask & 0x30))
299  else if ((trackMask & 0x3) && (trackMask & 0x300))
301  else
303  }
304  // This is the special case of track which appears to enter/exit z boundaries
305  else {
306  isCosmic = 3;
308  }
309  }
310  // This looks for track which enters/exits a boundary but has other endpoint in TPC
311  else if (nBitsSet > 0) {
312  isCosmic = 4;
313  if (trackMask & 0x3)
315  else if (trackMask & 0x30)
317  else if (trackMask & 0x300)
319  }
320  }
321 
322  std::vector<float> endPt1;
323  std::vector<float> endPt2;
324  endPt1.push_back(trackEndPt1_X);
325  endPt1.push_back(trackEndPt1_Y);
326  endPt1.push_back(trackEndPt1_Z);
327  endPt2.push_back(trackEndPt2_X);
328  endPt2.push_back(trackEndPt2_Y);
329  endPt2.push_back(trackEndPt2_Z);
330 
331  float cosmicScore = isCosmic > 0 ? 1. : 0.;
332 
333  // Handle special cases
334  if (isCosmic == 3)
335  cosmicScore = 0.4; // Enter/Exit at opposite Z boundaries
336  else if (isCosmic == 4)
337  cosmicScore = 0.5; // Enter or Exit but not both
338 
339  // Loop through the tracks resulting from this PFParticle and mark them
340  cosmicTagTrackVector->emplace_back(endPt1, endPt2, cosmicScore, tag_id);
341 
342  util::CreateAssn(*this, evt, *cosmicTagTrackVector, trackVec, *assnOutCosmicTagTrack);
343 
344  // Don't forget the association to the PFParticle
345  util::CreateAssn(*this, evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
346  }
347 
348  evt.put(std::move(cosmicTagTrackVector));
349  evt.put(std::move(assnOutCosmicTagTrack));
350  evt.put(std::move(assnOutCosmicTagPFParticle));
351 
352 } // end of produce
353 
354 DEFINE_ART_MODULE(cosmic::CosmicPFParticleTagger)
Utilities related to art service access.
enum anab::cosmic_tag_id CosmicTagID_t
Declaration of signal hit object.
pdgs p
Definition: selectors.fcl:22
process_name use argoneut_mc_hitfinder track
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
Provides recob::Track data product.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
bool CreateAssn(art::Event &evt, std::vector< T > const &a, art::Ptr< U > const &b, art::Assns< U, T > &assn, std::string a_instance, size_t index=UINT_MAX)
Creates a single one-to-one association.
BEGIN_PROLOG cosmic
do i e
CosmicPFParticleTagger(fhicl::ParameterSet const &p)
TCEvent evt
Definition: DataStructs.cxx:8
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
art framework interface to geometry description
int fMaxOutOfTime
Max hits that can be out of time before rejecting.