LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
CosmicPFParticleTagger_module.cc
Go to the documentation of this file.
1 // 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
17 
22 
23 #include <iterator>
24 
34 
35 namespace cosmic {
36  class CosmicPFParticleTagger;
37 }
38 
40 public:
42 
43  void produce(art::Event& e) override;
44 
45 private:
47  std::string fTrackModuleLabel;
54 };
55 
57 {
58  auto const& tpc = lar::providerFrom<geo::Geometry>()->TPC({0, 0});
59  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
60  auto const detp =
62 
63  fDetHalfHeight = tpc.HalfHeight();
64  fDetWidth = 2. * tpc.HalfWidth();
65  fDetLength = tpc.Length();
66 
67  float fSamplingRate = sampling_rate(clock_data);
68 
69  fPFParticleModuleLabel = p.get<std::string>("PFParticleModuleLabel");
70  fTrackModuleLabel = p.get<std::string>("TrackModuleLabel", "track");
71  fEndTickPadding = p.get<int>("EndTickPadding", 50); // Fudge the TPC edge in ticks...
72  fMaxOutOfTime = p.get<int>("MaxOutOfTime", 4);
73 
74  fTPCXBoundary = p.get<float>("TPCXBoundary", 5);
75  fTPCYBoundary = p.get<float>("TPCYBoundary", 5);
76  fTPCZBoundary = p.get<float>("TPCZBoundary", 5);
77 
78  const double driftVelocity = detp.DriftVelocity(detp.Efield(), detp.Temperature()); // cm/us
79 
81  2 * tpc.HalfWidth() / (driftVelocity * fSamplingRate / 1000); // ~3200 for uB
82  fMinTickDrift = clock_data.Time2Tick(clock_data.TriggerTime());
84 
85  produces<std::vector<anab::CosmicTag>>();
86  produces<art::Assns<anab::CosmicTag, recob::Track>>();
87  produces<art::Assns<recob::PFParticle, anab::CosmicTag>>();
88 }
89 
91 {
92  // Instatiate the output
93  std::unique_ptr<std::vector<anab::CosmicTag>> cosmicTagTrackVector(
94  new std::vector<anab::CosmicTag>);
95  std::unique_ptr<art::Assns<anab::CosmicTag, recob::Track>> assnOutCosmicTagTrack(
97  std::unique_ptr<art::Assns<recob::PFParticle, anab::CosmicTag>> assnOutCosmicTagPFParticle(
99 
100  // Recover handle for PFParticles
102  evt.getByLabel(fPFParticleModuleLabel, pfParticleHandle);
103 
104  if (!pfParticleHandle.isValid()) {
105  evt.put(std::move(cosmicTagTrackVector));
106  evt.put(std::move(assnOutCosmicTagTrack));
107  return;
108  }
109 
110  // Recover the handle for the tracks
112  evt.getByLabel(fTrackModuleLabel, trackHandle);
113 
114  if (!trackHandle.isValid()) {
115  evt.put(std::move(cosmicTagTrackVector));
116  evt.put(std::move(assnOutCosmicTagTrack));
117  return;
118  }
119 
120  // Recover handle for track <--> PFParticle associations
122  evt.getByLabel(fTrackModuleLabel, pfPartToTrackHandle);
123 
124  // Recover the list of associated tracks
125  art::FindManyP<recob::Track> pfPartToTrackAssns(pfParticleHandle, evt, fTrackModuleLabel);
126 
127  // and the hits
128  art::FindManyP<recob::Hit> hitsSpill(trackHandle, evt, fTrackModuleLabel);
129 
130  // The outer loop is going to be over PFParticles
131  for (size_t pfPartIdx = 0; pfPartIdx != pfParticleHandle->size(); pfPartIdx++) {
132  art::Ptr<recob::PFParticle> pfParticle(pfParticleHandle, pfPartIdx);
133 
134  // Recover the track vector
135  std::vector<art::Ptr<recob::Track>> trackVec = pfPartToTrackAssns.at(pfPartIdx);
136 
137  // Is there a track associated to this PFParticle?
138  if (trackVec.empty()) {
139  // We need to make a null CosmicTag to store with this PFParticle to keep sequencing correct
140  std::vector<float> tempPt1, tempPt2;
141  tempPt1.push_back(-999);
142  tempPt1.push_back(-999);
143  tempPt1.push_back(-999);
144  tempPt2.push_back(-999);
145  tempPt2.push_back(-999);
146  tempPt2.push_back(-999);
147  cosmicTagTrackVector->emplace_back(tempPt1, tempPt2, 0., anab::CosmicTagID_t::kNotTagged);
148  util::CreateAssn(evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
149  continue;
150  }
151 
152  // Start the tagging process...
153  int isCosmic = 0;
155  art::Ptr<recob::Track> track1 = trackVec.front();
156 
157  std::vector<art::Ptr<recob::Hit>> hitVec = hitsSpill.at(track1.key());
158 
159  // Recover track end points
160  auto vertexPosition = track1->Vertex();
161  auto vertexDirection = track1->VertexDirection();
162  auto endPosition = track1->End();
163 
164  // In principle there is one track associated to a PFParticle... but with current
165  // technology it can happen that a PFParticle is broken into multiple tracks. Our
166  // aim here is to find the maximum extents of all the tracks which have been
167  // associated to the single PFParticle
168  if (trackVec.size() > 1) {
169  for (size_t trackIdx = 1; trackIdx < trackVec.size(); trackIdx++) {
170  art::Ptr<recob::Track> track(trackVec[trackIdx]);
171 
172  auto trackStart = track->Vertex();
173  auto trackEnd = track->End();
174 
175  // Arc length possibilities for start of track
176  double arcLStartToStart = (trackStart - vertexPosition).Dot(vertexDirection);
177  double arcLStartToEnd = (trackEnd - vertexPosition).Dot(vertexDirection);
178 
179  if (arcLStartToStart < 0. || arcLStartToEnd < 0.) {
180  if (arcLStartToStart < arcLStartToEnd)
181  vertexPosition = trackStart;
182  else
183  vertexPosition = trackEnd;
184  }
185 
186  // Arc length possibilities for end of track
187  double arcLEndToStart = (trackStart - endPosition).Dot(vertexDirection);
188  double arcLEndToEnd = (trackEnd - endPosition).Dot(vertexDirection);
189 
190  if (arcLEndToStart > 0. || arcLEndToEnd > 0.) {
191  if (arcLEndToStart > arcLEndToEnd)
192  endPosition = trackStart;
193  else
194  endPosition = trackEnd;
195  }
196 
197  // add the hits from this track to the collection
198  hitVec.insert(
199  hitVec.end(), hitsSpill.at(track.key()).begin(), hitsSpill.at(track.key()).end());
200  }
201  }
202 
203  // "Track" end points in easily readable form
204  float trackEndPt1_X = vertexPosition.X();
205  float trackEndPt1_Y = vertexPosition.Y();
206  float trackEndPt1_Z = vertexPosition.Z();
207  float trackEndPt2_X = endPosition.X();
208  float trackEndPt2_Y = endPosition.Y();
209  float trackEndPt2_Z = endPosition.Z();
210 
212  // Check that all hits on particle are "in time"
214  int nOutOfTime(0);
215 
216  for (unsigned int p = 0; p < hitVec.size(); p++) {
217  int peakLessRms = hitVec[p]->PeakTimeMinusRMS();
218  int peakPlusRms = hitVec[p]->PeakTimePlusRMS();
219 
220  if (peakLessRms < fMinTickDrift || peakPlusRms > fMaxTickDrift) {
221  if (++nOutOfTime > fMaxOutOfTime) {
222  isCosmic = 1;
224  break; // If one hit is out of time it must be a cosmic ray
225  }
226  }
227  }
228 
230  // Now check the TPC boundaries:
232  if (isCosmic == 0) {
233  // In below we check entry and exit points. Note that a special case of a particle entering
234  // and exiting the same surface is considered to be running parallel to the surface and NOT
235  // entering and exiting.
236  // Also, in what follows we make no assumptions on which end point is the "start" or
237  // "end" of the track being considered.
238  unsigned boundaryMask[] = {0, 0};
239 
240  // Check x extents - note that uboone coordinaes system has x=0 at edge
241  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
242  // Also note that, in theory, any cosmic ray entering or exiting the X surfaces will have presumably
243  // been removed already by the checking of "out of time" hits... but this will at least label
244  // neutrino interaction tracks which exit through the X surfaces of the TPC
245  if (fDetWidth - trackEndPt1_X < fTPCXBoundary)
246  boundaryMask[0] = 0x1;
247  else if (trackEndPt1_X < fTPCXBoundary)
248  boundaryMask[0] = 0x2;
249 
250  if (fDetWidth - trackEndPt2_X < fTPCXBoundary)
251  boundaryMask[1] = 0x1;
252  else if (trackEndPt2_X < fTPCXBoundary)
253  boundaryMask[1] = 0x2;
254 
255  // Check y extents (note coordinate system change)
256  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
257  if (fDetHalfHeight - trackEndPt1_Y < fTPCYBoundary)
258  boundaryMask[0] = 0x10;
259  else if (fDetHalfHeight + trackEndPt1_Y < fTPCYBoundary)
260  boundaryMask[0] = 0x20;
261 
262  if (fDetHalfHeight - trackEndPt2_Y < fTPCYBoundary)
263  boundaryMask[1] = 0x10;
264  else if (fDetHalfHeight + trackEndPt2_Y < fTPCYBoundary)
265  boundaryMask[1] = 0x20;
266 
267  // Check z extents
268  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
269  if (fDetLength - trackEndPt1_Z < fTPCZBoundary)
270  boundaryMask[0] = 0x100;
271  else if (trackEndPt1_Z < fTPCZBoundary)
272  boundaryMask[0] = 0x200;
273 
274  if (fDetLength - trackEndPt2_Z < fTPCZBoundary)
275  boundaryMask[1] = 0x100;
276  else if (trackEndPt2_Z < fTPCZBoundary)
277  boundaryMask[1] = 0x200;
278 
279  unsigned trackMask = boundaryMask[0] | boundaryMask[1];
280  int nBitsSet(0);
281 
282  for (int idx = 0; idx < 12; idx++)
283  if (trackMask & (0x1 << idx)) nBitsSet++;
284 
285  // This should check for the case of a track which is both entering and exiting
286  // but we consider entering and exiting the z boundaries to be a special case (should it be?)
287  if (nBitsSet > 1) {
288  if ((trackMask & 0x300) != 0x300) {
289  isCosmic = 2;
290  if ((trackMask & 0x3) == 0x3)
292  else if ((trackMask & 0x30) == 0x30)
294  else if ((trackMask & 0x3) && (trackMask & 0x30))
296  else if ((trackMask & 0x3) && (trackMask & 0x300))
298  else
300  }
301  // This is the special case of track which appears to enter/exit z boundaries
302  else {
303  isCosmic = 3;
305  }
306  }
307  // This looks for track which enters/exits a boundary but has other endpoint in TPC
308  else if (nBitsSet > 0) {
309  isCosmic = 4;
310  if (trackMask & 0x3)
312  else if (trackMask & 0x30)
314  else if (trackMask & 0x300)
316  }
317  }
318 
319  std::vector<float> endPt1;
320  std::vector<float> endPt2;
321  endPt1.push_back(trackEndPt1_X);
322  endPt1.push_back(trackEndPt1_Y);
323  endPt1.push_back(trackEndPt1_Z);
324  endPt2.push_back(trackEndPt2_X);
325  endPt2.push_back(trackEndPt2_Y);
326  endPt2.push_back(trackEndPt2_Z);
327 
328  float cosmicScore = isCosmic > 0 ? 1. : 0.;
329 
330  // Handle special cases
331  if (isCosmic == 3)
332  cosmicScore = 0.4; // Enter/Exit at opposite Z boundaries
333  else if (isCosmic == 4)
334  cosmicScore = 0.5; // Enter or Exit but not both
335 
336  // Loop through the tracks resulting from this PFParticle and mark them
337  cosmicTagTrackVector->emplace_back(endPt1, endPt2, cosmicScore, tag_id);
338 
339  util::CreateAssn(evt, *cosmicTagTrackVector, trackVec, *assnOutCosmicTagTrack);
340 
341  // Don't forget the association to the PFParticle
342  util::CreateAssn(evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
343  }
344 
345  evt.put(std::move(cosmicTagTrackVector));
346  evt.put(std::move(assnOutCosmicTagTrack));
347  evt.put(std::move(assnOutCosmicTagPFParticle));
348 
349 } // end of produce
350 
Utilities related to art service access.
Float_t x1[n_points_granero]
Definition: compare.C:5
enum anab::cosmic_tag_id CosmicTagID_t
Declaration of signal hit object.
EDProducer(fhicl::ParameterSet const &pset)
Definition: EDProducer.cc:6
Float_t x3[n_points_geant4]
Vector_t VertexDirection() const
Access to track direction at different points.
Definition: Track.h:166
bool isValid() const noexcept
Definition: Handle.h:203
PutHandle< PROD > put(std::unique_ptr< PROD > &&edp, std::string const &instance={})
Definition: Event.h:77
decltype(auto) constexpr end(T &&obj)
ADL-aware version of std::end.
Definition: StdUtils.h:77
#define DEFINE_ART_MODULE(klass)
Definition: ModuleMacros.h:65
key_type key() const noexcept
Definition: Ptr.h:166
Point_t const & Vertex() const
Access to track position at different points.
Definition: Track.h:158
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.
bool getByLabel(std::string const &label, std::string const &instance, Handle< PROD > &result) const
Utility object to perform functions of association.
Provides recob::Track data product.
CosmicPFParticleTagger(fhicl::ParameterSet const &p)
Point_t const & End() const
Access to track position at different points.
Definition: Track.h:159
decltype(auto) constexpr begin(T &&obj)
ADL-aware version of std::begin.
Definition: StdUtils.h:69
TCEvent evt
Definition: DataStructs.cxx:8
Float_t e
Definition: plot.C:35
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
Float_t track
Definition: plot.C:35
art framework interface to geometry description
int fMaxOutOfTime
Max hits that can be out of time before rejecting.