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