LArSoft  v09_90_00
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 
60  auto const* geo = lar::providerFrom<geo::Geometry>();
61  auto const clock_data = art::ServiceHandle<detinfo::DetectorClocksService const>()->DataForJob();
62  auto const detp =
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 
83  2 * geo->DetHalfWidth() / (driftVelocity * fSamplingRate / 1000); // ~3200 for uB
84  fMinTickDrift = clock_data.Time2Tick(clock_data.TriggerTime());
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 
93 {
94  // Instatiate the output
95  std::unique_ptr<std::vector<anab::CosmicTag>> cosmicTagTrackVector(
96  new std::vector<anab::CosmicTag>);
97  std::unique_ptr<art::Assns<anab::CosmicTag, recob::Track>> assnOutCosmicTagTrack(
99  std::unique_ptr<art::Assns<recob::PFParticle, anab::CosmicTag>> assnOutCosmicTagPFParticle(
101 
102  // Recover handle for PFParticles
104  evt.getByLabel(fPFParticleModuleLabel, pfParticleHandle);
105 
106  if (!pfParticleHandle.isValid()) {
107  evt.put(std::move(cosmicTagTrackVector));
108  evt.put(std::move(assnOutCosmicTagTrack));
109  return;
110  }
111 
112  // Recover the handle for the tracks
114  evt.getByLabel(fTrackModuleLabel, trackHandle);
115 
116  if (!trackHandle.isValid()) {
117  evt.put(std::move(cosmicTagTrackVector));
118  evt.put(std::move(assnOutCosmicTagTrack));
119  return;
120  }
121 
122  // Recover handle for track <--> PFParticle associations
124  evt.getByLabel(fTrackModuleLabel, pfPartToTrackHandle);
125 
126  // Recover the list of associated tracks
127  art::FindManyP<recob::Track> pfPartToTrackAssns(pfParticleHandle, evt, fTrackModuleLabel);
128 
129  // and the hits
130  art::FindManyP<recob::Hit> hitsSpill(trackHandle, evt, fTrackModuleLabel);
131 
132  // The outer loop is going to be over PFParticles
133  for (size_t pfPartIdx = 0; pfPartIdx != pfParticleHandle->size(); pfPartIdx++) {
134  art::Ptr<recob::PFParticle> pfParticle(pfParticleHandle, pfPartIdx);
135 
136  // Recover the track vector
137  std::vector<art::Ptr<recob::Track>> trackVec = pfPartToTrackAssns.at(pfPartIdx);
138 
139  // Is there a track associated to this PFParticle?
140  if (trackVec.empty()) {
141  // We need to make a null CosmicTag to store with this PFParticle to keep sequencing correct
142  std::vector<float> tempPt1, tempPt2;
143  tempPt1.push_back(-999);
144  tempPt1.push_back(-999);
145  tempPt1.push_back(-999);
146  tempPt2.push_back(-999);
147  tempPt2.push_back(-999);
148  tempPt2.push_back(-999);
149  cosmicTagTrackVector->emplace_back(tempPt1, tempPt2, 0., anab::CosmicTagID_t::kNotTagged);
150  util::CreateAssn(evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
151  continue;
152  }
153 
154  // Start the tagging process...
155  int isCosmic = 0;
157  art::Ptr<recob::Track> track1 = trackVec.front();
158 
159  std::vector<art::Ptr<recob::Hit>> hitVec = hitsSpill.at(track1.key());
160 
161  // Recover track end points
162  auto vertexPosition = track1->Vertex();
163  auto vertexDirection = track1->VertexDirection();
164  auto endPosition = track1->End();
165 
166  // In principle there is one track associated to a PFParticle... but with current
167  // technology it can happen that a PFParticle is broken into multiple tracks. Our
168  // aim here is to find the maximum extents of all the tracks which have been
169  // associated to the single PFParticle
170  if (trackVec.size() > 1) {
171  for (size_t trackIdx = 1; trackIdx < trackVec.size(); trackIdx++) {
172  art::Ptr<recob::Track> track(trackVec[trackIdx]);
173 
174  auto trackStart = track->Vertex();
175  auto trackEnd = track->End();
176 
177  // Arc length possibilities for start of track
178  double arcLStartToStart = (trackStart - vertexPosition).Dot(vertexDirection);
179  double arcLStartToEnd = (trackEnd - vertexPosition).Dot(vertexDirection);
180 
181  if (arcLStartToStart < 0. || arcLStartToEnd < 0.) {
182  if (arcLStartToStart < arcLStartToEnd)
183  vertexPosition = trackStart;
184  else
185  vertexPosition = trackEnd;
186  }
187 
188  // Arc length possibilities for end of track
189  double arcLEndToStart = (trackStart - endPosition).Dot(vertexDirection);
190  double arcLEndToEnd = (trackEnd - endPosition).Dot(vertexDirection);
191 
192  if (arcLEndToStart > 0. || arcLEndToEnd > 0.) {
193  if (arcLEndToStart > arcLEndToEnd)
194  endPosition = trackStart;
195  else
196  endPosition = trackEnd;
197  }
198 
199  // add the hits from this track to the collection
200  hitVec.insert(
201  hitVec.end(), hitsSpill.at(track.key()).begin(), hitsSpill.at(track.key()).end());
202  }
203  }
204 
205  // "Track" end points in easily readable form
206  float trackEndPt1_X = vertexPosition.X();
207  float trackEndPt1_Y = vertexPosition.Y();
208  float trackEndPt1_Z = vertexPosition.Z();
209  float trackEndPt2_X = endPosition.X();
210  float trackEndPt2_Y = endPosition.Y();
211  float trackEndPt2_Z = endPosition.Z();
212 
214  // Check that all hits on particle are "in time"
216  int nOutOfTime(0);
217 
218  for (unsigned int p = 0; p < hitVec.size(); p++) {
219  int peakLessRms = hitVec[p]->PeakTimeMinusRMS();
220  int peakPlusRms = hitVec[p]->PeakTimePlusRMS();
221 
222  if (peakLessRms < fMinTickDrift || peakPlusRms > fMaxTickDrift) {
223  if (++nOutOfTime > fMaxOutOfTime) {
224  isCosmic = 1;
226  break; // If one hit is out of time it must be a cosmic ray
227  }
228  }
229  }
230 
232  // Now check the TPC boundaries:
234  if (isCosmic == 0) {
235  // In below we check entry and exit points. Note that a special case of a particle entering
236  // and exiting the same surface is considered to be running parallel to the surface and NOT
237  // entering and exiting.
238  // Also, in what follows we make no assumptions on which end point is the "start" or
239  // "end" of the track being considered.
240  unsigned boundaryMask[] = {0, 0};
241 
242  // Check x extents - note that uboone coordinaes system has x=0 at edge
243  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
244  // Also note that, in theory, any cosmic ray entering or exiting the X surfaces will have presumably
245  // been removed already by the checking of "out of time" hits... but this will at least label
246  // neutrino interaction tracks which exit through the X surfaces of the TPC
247  if (fDetWidth - trackEndPt1_X < fTPCXBoundary)
248  boundaryMask[0] = 0x1;
249  else if (trackEndPt1_X < fTPCXBoundary)
250  boundaryMask[0] = 0x2;
251 
252  if (fDetWidth - trackEndPt2_X < fTPCXBoundary)
253  boundaryMask[1] = 0x1;
254  else if (trackEndPt2_X < fTPCXBoundary)
255  boundaryMask[1] = 0x2;
256 
257  // Check y extents (note coordinate system change)
258  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
259  if (fDetHalfHeight - trackEndPt1_Y < fTPCYBoundary)
260  boundaryMask[0] = 0x10;
261  else if (fDetHalfHeight + trackEndPt1_Y < fTPCYBoundary)
262  boundaryMask[0] = 0x20;
263 
264  if (fDetHalfHeight - trackEndPt2_Y < fTPCYBoundary)
265  boundaryMask[1] = 0x10;
266  else if (fDetHalfHeight + trackEndPt2_Y < fTPCYBoundary)
267  boundaryMask[1] = 0x20;
268 
269  // Check z extents
270  // Note this counts the case where the track enters and exits the same surface as a "1", not a "2"
271  if (fDetLength - trackEndPt1_Z < fTPCZBoundary)
272  boundaryMask[0] = 0x100;
273  else if (trackEndPt1_Z < fTPCZBoundary)
274  boundaryMask[0] = 0x200;
275 
276  if (fDetLength - trackEndPt2_Z < fTPCZBoundary)
277  boundaryMask[1] = 0x100;
278  else if (trackEndPt2_Z < fTPCZBoundary)
279  boundaryMask[1] = 0x200;
280 
281  unsigned trackMask = boundaryMask[0] | boundaryMask[1];
282  int nBitsSet(0);
283 
284  for (int idx = 0; idx < 12; idx++)
285  if (trackMask & (0x1 << idx)) nBitsSet++;
286 
287  // This should check for the case of a track which is both entering and exiting
288  // but we consider entering and exiting the z boundaries to be a special case (should it be?)
289  if (nBitsSet > 1) {
290  if ((trackMask & 0x300) != 0x300) {
291  isCosmic = 2;
292  if ((trackMask & 0x3) == 0x3)
294  else if ((trackMask & 0x30) == 0x30)
296  else if ((trackMask & 0x3) && (trackMask & 0x30))
298  else if ((trackMask & 0x3) && (trackMask & 0x300))
300  else
302  }
303  // This is the special case of track which appears to enter/exit z boundaries
304  else {
305  isCosmic = 3;
307  }
308  }
309  // This looks for track which enters/exits a boundary but has other endpoint in TPC
310  else if (nBitsSet > 0) {
311  isCosmic = 4;
312  if (trackMask & 0x3)
314  else if (trackMask & 0x30)
316  else if (trackMask & 0x300)
318  }
319  }
320 
321  std::vector<float> endPt1;
322  std::vector<float> endPt2;
323  endPt1.push_back(trackEndPt1_X);
324  endPt1.push_back(trackEndPt1_Y);
325  endPt1.push_back(trackEndPt1_Z);
326  endPt2.push_back(trackEndPt2_X);
327  endPt2.push_back(trackEndPt2_Y);
328  endPt2.push_back(trackEndPt2_Z);
329 
330  float cosmicScore = isCosmic > 0 ? 1. : 0.;
331 
332  // Handle special cases
333  if (isCosmic == 3)
334  cosmicScore = 0.4; // Enter/Exit at opposite Z boundaries
335  else if (isCosmic == 4)
336  cosmicScore = 0.5; // Enter or Exit but not both
337 
338  // Loop through the tracks resulting from this PFParticle and mark them
339  cosmicTagTrackVector->emplace_back(endPt1, endPt2, cosmicScore, tag_id);
340 
341  util::CreateAssn(evt, *cosmicTagTrackVector, trackVec, *assnOutCosmicTagTrack);
342 
343  // Don't forget the association to the PFParticle
344  util::CreateAssn(evt, *cosmicTagTrackVector, pfParticle, *assnOutCosmicTagPFParticle);
345  }
346 
347  evt.put(std::move(cosmicTagTrackVector));
348  evt.put(std::move(assnOutCosmicTagTrack));
349  evt.put(std::move(assnOutCosmicTagPFParticle));
350 
351 } // end of produce
352 
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
Provides recob::Track data product.
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.
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.
Namespace collecting geometry-related classes utilities.
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.