All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PMAlgCosmicTagger.cxx
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////////////////////////
2 // Class: PMAlgCosmicTagger
3 // Author: L. Whitehead (leigh.howard.whitehead@cern.ch),
4 // R. Sulej (robert.sulej@cern.ch) March 2017
5 ////////////////////////////////////////////////////////////////////////////////////////////////////
6 
15 
16 #include "messagefacility/MessageLogger/MessageLogger.h"
17 
19 
20 #include <numeric> // std::accumulate
21 
22 void
25 {
26  // Get the detector dimensions
27  GetDimensions();
28 
29  mf::LogInfo("pma::PMAlgCosmicTagger")
30  << "Passed " << tracks.size() << " tracks for tagging cosmics.";
31 
32  size_t n = 0;
33 
34  if (fTagOutOfDriftTracks) n += outOfDriftWindow(tracks);
35  if (fTagFullHeightTracks) n += fullHeightCrossing(tracks);
36  if (fTagFullWidthTracks) n += fullWidthCrossing(tracks);
37  if (fTagFullLengthTracks) n += fullLengthCrossing(tracks);
38  if (fTagNonBeamT0Tracks) n += nonBeamT0Tag(clockData, tracks);
39  if (fTagTopFrontBack) n += tagTopFrontBack(tracks);
40  if (fTagApparentStopper) n += tagApparentStopper(tracks);
41 
42  mf::LogInfo("pma::PMAlgCosmicTagger") << "...tagged " << n << " cosmic-like tracks.";
43 }
44 
45 size_t
47 {
48  mf::LogInfo("pma::PMAlgCosmicTagger") << " - tag tracks out of 1 drift window;";
49  size_t n = 0;
50 
51  auto const* geom = lar::providerFrom<geo::Geometry>();
52 
53  for (auto& t : tracks.tracks()) {
54 
55  pma::Track3D& trk = *(t.Track());
56 
57  double min, max, p;
58  bool node_out_of_drift_min = false;
59  bool node_out_of_drift_max = false;
60  for (size_t nidx = 0; nidx < trk.Nodes().size(); ++nidx) {
61  auto const& node = *(trk.Nodes()[nidx]);
62  auto const& tpcGeo = geom->TPC(node.TPC(), node.Cryo());
63  // DetectDriftDirection returns a short int, but switch requires an int
64  int driftDir = abs(tpcGeo.DetectDriftDirection());
65  p = node.Point3D()[driftDir - 1];
66  switch (driftDir) {
67  case 1:
68  min = tpcGeo.MinX();
69  max = tpcGeo.MaxX();
70  break;
71  case 2:
72  min = tpcGeo.MinY();
73  max = tpcGeo.MaxY();
74  break;
75  case 3:
76  min = tpcGeo.MinZ();
77  max = tpcGeo.MaxZ();
78  break;
79  default:
80  throw cet::exception("PMAlgCosmicTagger")
81  << "Drift direction unknown: " << driftDir << std::endl;
82  }
83  if (p < min - fOutOfDriftMargin) { node_out_of_drift_min = true; }
84  if (p > max + fOutOfDriftMargin) { node_out_of_drift_max = true; }
85  }
86 
87  if (node_out_of_drift_min && node_out_of_drift_max) {
90  ++n;
91  }
92  else if (node_out_of_drift_min || node_out_of_drift_max) {
95  ++n;
96  }
97  }
98 
99  mf::LogInfo("pma::PMAlgCosmicTagger") << " - Tagged " << n << " tracks out of 1 drift window.";
100 
101  return n;
102 }
103 
104 // Leigh: Make use of the fact that our cathode and anode crossing tracks have a reconstructed T0.
105 // Check to see if this time is consistent with the beam
106 size_t
109 {
110  size_t n = 0;
111 
112  // Search through all of the tracks
113  for (auto& t : tracks.tracks()) {
114 
115  // Non zero T0 means we reconstructed it
116  if (t.Track()->GetT0() != 0.0) {
117  mf::LogInfo("pma::PMAlgCosmicTagger") << " - track with T0 = " << t.Track()->GetT0();
118 
119  if (fabs(t.Track()->GetT0() - trigger_offset(clockData)) > fNonBeamT0Margin) {
120  ++n;
121  t.Track()->SetTagFlag(pma::Track3D::kCosmic);
122  t.Track()->SetTagFlag(pma::Track3D::kBeamIncompatible);
123  }
124  }
125  }
126 
127  mf::LogInfo("pma::PMAlgCosmicTagger") << " - Tagged " << n << " non-beam T0 tracks.";
128  return n;
129 }
130 
131 size_t
133 {
134 
135  size_t n = 0;
136 
137  auto const* geom = lar::providerFrom<geo::Geometry>();
138 
139  short int hIdx = ConvertDirToInt(geom->TPC(0, 0).HeightDir());
140  short int lIdx = ConvertDirToInt(geom->TPC(0, 0).LengthDir());
141 
142  // Loop over the tracks
143  for (auto& t : tracks.tracks()) {
144 
145  // Get the first and last positions from the track.
146  auto const& node0 = *(t.Track()->Nodes()[0]);
147  auto const& node1 = *(t.Track()->Nodes()[t.Track()->Nodes().size() - 1]);
148 
149  // Check which end is the vertex (assume the largest height)
150  TVector3 vtx =
151  (node0.Point3D()[hIdx] > node1.Point3D()[hIdx]) ? node0.Point3D() : node1.Point3D();
152  TVector3 end =
153  (node0.Point3D()[hIdx] <= node1.Point3D()[hIdx]) ? node0.Point3D() : node1.Point3D();
154 
155  // Check we have a track starting at the top of the detector
156  bool top = isTopVertex(vtx, fTopFrontBackMargin, hIdx);
157 
158  // Check the track ends at the front or back of the detector
159  bool frontBack = isFrontBackVertex(end, fTopFrontBackMargin, lIdx);
160 
161  // Check we path both criteria but without letting either the start or end of the track fulfill both
162  if (top && frontBack) {
163  ++n;
164  t.Track()->SetTagFlag(pma::Track3D::kCosmic);
165  t.Track()->SetTagFlag(pma::Track3D::kGeometry_YZ);
166  }
167  }
168 
169  mf::LogInfo("pma::PMAlgCosmicTagger")
170  << " - Tagged " << n << " tracks crossing from top to front/back." << std::endl;
171 
172  return n;
173 }
174 
175 size_t
177 {
178 
179  size_t n = 0;
180 
181  // Tracks entering from the top of the detector that stop in the fiducial volume
182  // are very likely to be cosmics that leave through the APA, but have their
183  // drift coordinate incorrectly set due to lack of T0
184  auto const* geom = lar::providerFrom<geo::Geometry>();
185 
186  short int hIdx = ConvertDirToInt(geom->TPC(0, 0).HeightDir());
187 
188  // Loop over the tracks
189  for (auto& t : tracks.tracks()) {
190 
191  // Get the first and last positions from the track.
192  auto const& node0 = *(t.Track()->Nodes()[0]);
193  auto const& node1 = *(t.Track()->Nodes()[t.Track()->Nodes().size() - 1]);
194 
195  // Check which end is the vertex (assume the largest height)
196  TVector3 vtx =
197  (node0.Point3D()[hIdx] > node1.Point3D()[hIdx]) ? node0.Point3D() : node1.Point3D();
198  TVector3 end =
199  (node0.Point3D()[hIdx] <= node1.Point3D()[hIdx]) ? node0.Point3D() : node1.Point3D();
200 
201  if (fabs(vtx[hIdx] - fDimensionsMax[hIdx]) < fApparentStopperMargin) {
202  // Check the other element to see if it ends away from the bottom of the detector
203  if (fabs(end[hIdx] - fDimensionsMin[hIdx]) > 5. * fApparentStopperMargin) {
204 
205  // We now need to loop over all of the tracks to see if any start within fStopperBuffer of our end point.
206  bool foundTrack = false;
207  for (auto const& tt : tracks.tracks()) {
208  // Don't match with itself!
209  if ((&tt) == (&t)) continue;
210 
211  // Compare this track with our main track
212  TVector3 trkVtx = (tt.Track()->Nodes()[0])->Point3D();
213  TVector3 trkEnd = (tt.Track()->Nodes()[tt.Track()->Nodes().size() - 1])->Point3D();
214 
215  if ((end - trkVtx).Mag() < fStopperBuffer || (end - trkEnd).Mag() < fStopperBuffer) {
216  foundTrack = true;
217  break;
218  }
219  }
220  if (foundTrack) {
221  // This isn't really a stopping particle, so move on
222  continue;
223  }
224 
225  // If we don't mind about tagging all stopping particles then this satisfies our requirements
226  if (!fVetoActualStopper) {
227  ++n;
228  t.Track()->SetTagFlag(pma::Track3D::kCosmic);
229  t.Track()->SetTagFlag(pma::Track3D::kGeometry_Y);
230  continue;
231  }
232 
233  // If we want to actually ignore the stopping particles, use de/dx...
234  // Store the number of sigma from the mean for the final dedx point in each view
235  std::vector<float> nSigmaPerView;
236 
237  // Loop over the views
238  for (auto const view : geom->Views()) {
239 
240  // Get the dedx for this track and view
241  std::map<size_t, std::vector<double>> dedx;
242  t.Track()->GetRawdEdxSequence(dedx, view);
243 
244  std::vector<double> trk_dedx;
245 
246  for (int h = t.Track()->NextHit(-1, view); h != -1; h = t.Track()->NextHit(h, view)) {
247  // If this is the last hit then this method won't work
248  if (h > t.Track()->PrevHit(t.Track()->size(), view)) break;
249  // Make sure we have a reasonable value
250  if (dedx[h][5] / dedx[h][6] <= 0 || dedx[h][5] / dedx[h][6] > 1e6) continue;
251  trk_dedx.push_back(dedx[h][5] / dedx[h][6]);
252  }
253 
254  if (trk_dedx.size() == 0) {
255  mf::LogInfo("pma::PMAlgCosmicTagger")
256  << "View " << view << " has no hits." << std::endl;
257  continue;
258  }
259 
260  double sum = std::accumulate(std::begin(trk_dedx), std::end(trk_dedx), 0.0);
261  double mean = sum / static_cast<double>(trk_dedx.size());
262  double accum = 0.0;
263  std::for_each(std::begin(trk_dedx), std::end(trk_dedx), [&](const double d) {
264  accum += (d - mean) * (d - mean);
265  });
266  double stdev = sqrt(accum / static_cast<double>(trk_dedx.size() - 1));
267 
268  mf::LogInfo("pma::PMAlgCosmicTagger")
269  << " View " << view << " has average dedx " << mean << " +/- " << stdev
270  << " and final dedx " << trk_dedx[trk_dedx.size() - 1] << std::endl;
271 
272  nSigmaPerView.push_back(fabs((trk_dedx[trk_dedx.size() - 1] - mean) / stdev));
273  }
274 
275  bool notStopper = true;
276  short unsigned int n2Sigma = 0;
277  short unsigned int n3Sigma = 0;
278  for (auto const nSigma : nSigmaPerView) {
279  if (nSigma >= 2.0) ++n2Sigma;
280  if (nSigma >= 3.0) ++n3Sigma;
281  }
282 
283  if (n3Sigma > 0) notStopper = false;
284  if (n2Sigma == nSigmaPerView.size()) notStopper = false;
285 
286  if (notStopper) {
287  ++n;
288  t.Track()->SetTagFlag(pma::Track3D::kCosmic);
289  t.Track()->SetTagFlag(pma::Track3D::kGeometry_Y);
290  }
291  } // Check on bottom position
292  } // Check on top position
293  } // End loop over tracks
294 
295  mf::LogInfo("pma::PMAlgCosmicTagger")
296  << " - Tagged " << n << " tracks stopping in the detector after starting at the top."
297  << std::endl;
298 
299  return n;
300 }
301 
302 size_t
304 {
305 
306  // Just use the first tpc to get the height dimension (instead of assuming y).
307  auto const* geom = lar::providerFrom<geo::Geometry>();
308  TVector3 dir = geom->TPC(0, 0).HeightDir();
309 
310  size_t n = fullCrossingTagger(tracks, ConvertDirToInt(dir));
311 
312  mf::LogInfo("pma::PMAlgCosmicTagger")
313  << " - Tagged " << n << " tracks crossing the full detector height";
314  return n;
315 }
316 
317 size_t
319 {
320 
321  // Just use the first tpc to get the width dimension (instead of assuming x).
322  auto const* geom = lar::providerFrom<geo::Geometry>();
323  TVector3 dir = geom->TPC(0, 0).WidthDir();
324 
325  size_t n = fullCrossingTagger(tracks, ConvertDirToInt(dir));
326 
327  mf::LogInfo("pma::PMAlgCosmicTagger")
328  << " - Tagged " << n << " tracks crossing the full detector width";
329  return n;
330 }
331 
332 size_t
334 {
335 
336  // Just use the first tpc to get the length dimension (instead of assuming z).
337  auto const* geom = lar::providerFrom<geo::Geometry>();
338  TVector3 dir = geom->TPC(0, 0).LengthDir();
339 
340  size_t n = fullCrossingTagger(tracks, ConvertDirToInt(dir));
341 
342  mf::LogInfo("pma::PMAlgCosmicTagger")
343  << " - Tagged " << n << " tracks crossing the full detector length";
344  return n;
345 }
346 
347 size_t
349 {
350 
351  if (direction == -1) {
352  mf::LogWarning("pma::PMAlgCosmicTagger")
353  << " - Could not recognise direction, not attempting to perform fullCrossingTagger.";
354  return 0;
355  }
356 
357  size_t n = 0;
358 
359  double detDim = fDimensionsMax[direction] - fDimensionsMin[direction];
360 
362  switch (direction) {
363  case 0: dirTag = pma::Track3D::kGeometry_XX; break;
364  case 1: dirTag = pma::Track3D::kGeometry_YY; break;
365  case 2: dirTag = pma::Track3D::kGeometry_ZZ; break;
366  default: dirTag = pma::Track3D::kNotTagged; break;
367  }
368 
369  // Loop over the tracks
370  for (auto& t : tracks.tracks()) {
371 
372  // Get the first and last positions from the track.
373  auto const& node0 = *(t.Track()->Nodes()[0]);
374  auto const& node1 = *(t.Track()->Nodes()[t.Track()->Nodes().size() - 1]);
375 
376  // Get the length of the track in the requested direction
377  double trkDim = fabs(node0.Point3D()[direction] - node1.Point3D()[direction]);
378 
379  if ((detDim - trkDim) < fFullCrossingMargin) {
380  ++n;
381  t.Track()->SetTagFlag(pma::Track3D::kCosmic);
382  t.Track()->SetTagFlag(dirTag);
383  mf::LogInfo("pma::PMAlgCosmicTagger") << " -- track tagged in direction " << direction
384  << " with " << trkDim << " (c.f. " << detDim << ")";
385  }
386  }
387 
388  return n;
389 }
390 
391 bool
392 pma::PMAlgCosmicTagger::isTopVertex(const TVector3& pos, double tolerance, short int dirIndx) const
393 {
394 
395  return (fabs(pos[dirIndx] - fDimensionsMax[dirIndx]) < tolerance);
396 }
397 
398 bool
400  double tolerance,
401  short int dirIndx) const
402 {
403 
404  bool front = (fabs(pos[dirIndx] - fDimensionsMin[dirIndx]) < tolerance);
405  bool back = (fabs(pos[dirIndx] - fDimensionsMax[dirIndx]) < tolerance);
406 
407  return front || back;
408 }
409 
410 void
412 {
413 
414  // Need to find the minimum and maximum height values from the geometry.
415  double minX = 1.e6;
416  double maxX = -1.e6;
417  double minY = 1.e6;
418  double maxY = -1.e6;
419  double minZ = 1.e6;
420  double maxZ = -1.e6;
421 
422  auto const* geom = lar::providerFrom<geo::Geometry>();
423 
424  // Since we can stack TPCs, we can't just use geom::TPCGeom::Height()
425  for (geo::TPCID const& tID : geom->IterateTPCIDs()) {
426  geo::TPCGeo const& TPC = geom->TPC(tID);
427 
428  // We need to make sure we only include the real TPCs
429  // We have dummy TPCs in the protoDUNE and DUNE geometries
430  // The dummy ones have a drift distance of only ~13 cm.
431  if (TPC.DriftDistance() < 25.0) { continue; }
432 
433  // get center in world coordinates
434  double origin[3] = {0.};
435  double center[3] = {0.};
436  TPC.LocalToWorld(origin, center);
437  double tpcDim[3] = {TPC.HalfWidth(), TPC.HalfHeight(), 0.5 * TPC.Length()};
438 
439  if (center[0] - tpcDim[0] < minX) minX = center[0] - tpcDim[0];
440  if (center[0] + tpcDim[0] > maxX) maxX = center[0] + tpcDim[0];
441  if (center[1] - tpcDim[1] < minY) minY = center[1] - tpcDim[1];
442  if (center[1] + tpcDim[1] > maxY) maxY = center[1] + tpcDim[1];
443  if (center[2] - tpcDim[2] < minZ) minZ = center[2] - tpcDim[2];
444  if (center[2] + tpcDim[2] > maxZ) maxZ = center[2] + tpcDim[2];
445  } // for all TPC
446 
447  fDimensionsMin.clear();
448  fDimensionsMax.clear();
449  fDimensionsMin.push_back(minX);
450  fDimensionsMin.push_back(minY);
451  fDimensionsMin.push_back(minZ);
452  fDimensionsMax.push_back(maxX);
453  fDimensionsMax.push_back(maxY);
454  fDimensionsMax.push_back(maxZ);
455 }
456 
457 short int
459 {
460 
461  if (dir.X() > 0.99) return 0;
462  if (dir.Y() > 0.99) return 1;
463  if (dir.Z() > 0.99)
464  return 2;
465 
466  else
467  return -1;
468 }
size_t fullWidthCrossing(pma::TrkCandidateColl &tracks) const
size_t size() const
Utilities related to art service access.
ClusterModuleLabel join with tracks
void SetTagFlag(ETag value)
Definition: PmaTrack3D.h:77
Implementation of the Projection Matching Algorithm.
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
auto const tolerance
pdgs p
Definition: selectors.fcl:22
Geometry information for a single TPC.
Definition: TPCGeo.h:38
std::vector< pma::Node3D * > const & Nodes() const noexcept
Definition: PmaTrack3D.h:338
Implementation of the Projection Matching Algorithm.
BEGIN_PROLOG TPC
double Length() const
Length is associated with z coordinate [cm].
Definition: TPCGeo.h:115
size_t tagApparentStopper(pma::TrkCandidateColl &tracks) const
walls no top
Definition: selectors.fcl:105
while getopts h
Access the description of detector geometry.
T abs(T value)
walls no front
Definition: selectors.fcl:105
size_t outOfDriftWindow(pma::TrkCandidateColl &tracks) const
bool isFrontBackVertex(const TVector3 &pos, double tolerance, short int dirIndx) const
size_t nonBeamT0Tag(detinfo::DetectorClocksData const &clockData, pma::TrkCandidateColl &tracks) const
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
short int ConvertDirToInt(const TVector3 &dir) const
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
void tag(detinfo::DetectorClocksData const &clockData, pma::TrkCandidateColl &tracks)
tuple dir
Definition: dropbox.py:28
Track finding helper for the Projection Matching Algorithm.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
double HalfHeight() const
Height is associated with y coordinate [cm].
Definition: TPCGeo.h:111
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
double DriftDistance() const
Definition: TPCGeo.h:155
Contains all timing reference information for the detector.
size_t tagTopFrontBack(pma::TrkCandidateColl &tracks) const
int trigger_offset(DetectorClocksData const &data)
size_t fullHeightCrossing(pma::TrkCandidateColl &tracks) const
size_t fullCrossingTagger(pma::TrkCandidateColl &tracks, int direction) const
bool isTopVertex(const TVector3 &pos, double tolerance, short int dirIndx) const
void LocalToWorld(const double *tpc, double *world) const
Transform point from local TPC frame to world frame.
Definition: TPCGeo.h:563
size_t fullLengthCrossing(pma::TrkCandidateColl &tracks) const
art framework interface to geometry description
double HalfWidth() const
Width is associated with x coordinate [cm].
Definition: TPCGeo.h:107
std::vector< TrkCandidate > const & tracks() const
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:227
Encapsulate the construction of a single detector plane.