LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
TrackShowerSeparationAlg.cxx
Go to the documentation of this file.
1 // Class: TrackShowerSeparationAlg
3 // File: TrackShowerSeparationAlg.cxx
4 // Author: Mike Wallbank (m.wallbank@sheffield.ac.uk), November 2015
5 //
6 // Track/shower separation class.
7 // Provides methods for removing hits associated with track-like
8 // objects.
9 // To be run after track reconstruction, before shower reconstruction.
11 
13 #include "fhiclcpp/ParameterSet.h"
14 
15 #include "TMathBase.h"
16 #include "TVector2.h"
17 
19 {
20  this->reconfigure(pset);
21 }
22 
24 {
25  fConeAngle = pset.get<double>("ConeAngle");
26  fCylinderRadius = pset.get<double>("CylinderRadius");
27  fTrackVertexCut = pset.get<double>("TrackVertexCut");
28  fCylinderCut = pset.get<double>("CylinderCut");
29  fShowerConeCut = pset.get<double>("ShowerConeCut");
30 
31  fDebug = pset.get<int>("Debug", 0);
32 }
33 
34 std::vector<art::Ptr<recob::Hit>> shower::TrackShowerSeparationAlg::SelectShowerHits(
35  int event,
37  const std::vector<art::Ptr<recob::Track>>& tracks,
38  const std::vector<art::Ptr<recob::SpacePoint>>& spacePoints,
39  const art::FindManyP<recob::Hit>& fmht,
40  const art::FindManyP<recob::Track>& fmth,
42  const art::FindManyP<recob::Track>& fmtsp) const
43 {
44 
45  // Ok, here we are again
46  // Playing the game in which no one wins, but everyone loses
47  // Trying to separate tracks from showers
48  // Ode to track/shower separation
49  // M Wallbank, Oct 2016
50 
51  // Showers are comprised of two topologically different parts:
52  // -- the 'shower track' (the initial part of the shower)
53  // -- the 'shower cone' (the part of the shower after the initial track when showering happens)
54 
55  // -
56  // --
57  // - -- --
58  // -- --- ---
59  // -- ---- --
60  // ----------- ----- - -- ---
61  // --- ---
62  // -- ---
63  // {=========}{==============================}
64  // shower track shower cone
65 
66  std::map<int, std::unique_ptr<ReconTrack>> reconTracks;
67  for (std::vector<art::Ptr<recob::Track>>::const_iterator trackIt = tracks.begin();
68  trackIt != tracks.end();
69  ++trackIt) {
70  std::unique_ptr<ReconTrack> track = std::make_unique<ReconTrack>(trackIt->key());
71  track->SetVertex((*trackIt)->Vertex<TVector3>());
72  track->SetEnd((*trackIt)->End<TVector3>());
73  track->SetVertexDir((*trackIt)->VertexDirection<TVector3>());
74  track->SetLength((*trackIt)->Length());
75  track->SetDirection(Gradient(*trackIt));
76  track->SetHits(fmht.at(trackIt->key()));
77  track->SetSpacePoints(fmspt.at(trackIt->key()));
78  const std::vector<art::Ptr<recob::SpacePoint>> spsss = fmspt.at(trackIt->key());
79  reconTracks[trackIt->key()] = std::move(track);
80  }
81 
82  // Consider the space point cylinder situation
83  double avCylinderSpacePoints = 0;
84  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
85  trackIt != reconTracks.end();
86  ++trackIt) {
87  // Get the 3D properties of the track
88  TVector3 point = trackIt->second->Vertex();
89  TVector3 direction = trackIt->second->Direction();
90 
91  // Count space points in the volume around the track
93  spacePoints.begin();
94  spacePointIt != spacePoints.end();
95  ++spacePointIt) {
96  const std::vector<art::Ptr<recob::Track>> spTracks = fmtsp.at(spacePointIt->key());
97  if (find_if(spTracks.begin(), spTracks.end(), [&trackIt](const art::Ptr<recob::Track>& t) {
98  return (int)t.key() == trackIt->first;
99  }) != spTracks.end())
100  continue;
101  // Get the properties of this space point
102  TVector3 pos = SpacePointPos(*spacePointIt);
103  TVector3 proj = ProjPoint(pos, direction, point);
104  if ((pos - proj).Mag() < fCylinderRadius)
105  trackIt->second->AddCylinderSpacePoint(spacePointIt->key());
106  }
107  avCylinderSpacePoints += trackIt->second->CylinderSpacePointRatio();
108  }
109  avCylinderSpacePoints /= (double)reconTracks.size();
110 
111  if (fDebug > 1) {
112  std::cout << std::endl << "Cylinder space point ratios:" << std::endl;
113  for (std::map<int, std::unique_ptr<ReconTrack>>::const_iterator trackIt = reconTracks.begin();
114  trackIt != reconTracks.end();
115  ++trackIt)
116  std::cout << " Track " << trackIt->first << " has cylinder space point ratio "
117  << trackIt->second->CylinderSpacePointRatio() << " (event average "
118  << avCylinderSpacePoints << ")" << std::endl;
119  }
120 
121  // Identify tracks
122  if (fDebug > 0) std::cout << std::endl << "Identifying tracks:" << std::endl;
123  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
124  trackIt != reconTracks.end();
125  ++trackIt)
126  if (trackIt->second->CylinderSpacePointRatio() / avCylinderSpacePoints < fCylinderCut) {
127  if (fDebug > 0)
128  std::cout << " Making track " << trackIt->first << " a track (Type I)" << std::endl;
129  trackIt->second->MakeTrack();
130  }
131 
132  // Identify further tracks
133  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
134  trackIt != reconTracks.end();
135  ++trackIt) {
136  if (trackIt->second->IsTrack()) continue;
137  for (std::map<int, std::unique_ptr<ReconTrack>>::const_iterator otherTrackIt =
138  reconTracks.begin();
139  otherTrackIt != reconTracks.end();
140  ++otherTrackIt) {
141  if (trackIt->first == otherTrackIt->first or !otherTrackIt->second->IsTrack()) continue;
142  if ((trackIt->second->Vertex() - otherTrackIt->second->Vertex()).Mag() < fTrackVertexCut or
143  (trackIt->second->Vertex() - otherTrackIt->second->End()).Mag() < fTrackVertexCut or
144  (trackIt->second->End() - otherTrackIt->second->Vertex()).Mag() < fTrackVertexCut or
145  (trackIt->second->End() - otherTrackIt->second->End()).Mag() < fTrackVertexCut) {
146  if (fDebug > 0)
147  std::cout << " Making track " << trackIt->first << " a track (Type II)" << std::endl;
148  trackIt->second->MakeTrack();
149  }
150  }
151  }
152 
153  // Consider removing false tracks by looking at their closest approach to any other track
154 
155  // Consider the space point cone situation
156  std::vector<art::Ptr<recob::SpacePoint>> showerSpacePoints;
157  for (std::vector<art::Ptr<recob::SpacePoint>>::const_iterator spacePointIt = spacePoints.begin();
158  spacePointIt != spacePoints.end();
159  ++spacePointIt) {
160  bool showerSpacePoint = true;
161  const std::vector<art::Ptr<recob::Track>> spacePointTracks = fmtsp.at(spacePointIt->key());
162  for (std::vector<art::Ptr<recob::Track>>::const_iterator trackIt = spacePointTracks.begin();
163  trackIt != spacePointTracks.end();
164  ++trackIt)
165  if (reconTracks[trackIt->key()]->IsTrack()) showerSpacePoint = false;
166  if (showerSpacePoint) showerSpacePoints.push_back(*spacePointIt);
167  }
168 
169  // Identify tracks which slipped through and shower tracks
170  // For the moment, until the track tagging gets better at least, don't try to identify tracks from this
171  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
172  trackIt != reconTracks.end();
173  ++trackIt) {
175  showerSpacePoints.begin();
176  spacePointIt != showerSpacePoints.end();
177  ++spacePointIt) {
178  bool associatedSpacePoint = false;
179  const std::vector<art::Ptr<recob::Track>> spTracks = fmtsp.at(spacePointIt->key());
180  for (std::vector<art::Ptr<recob::Track>>::const_iterator spTrackIt = spTracks.begin();
181  spTrackIt != spTracks.end();
182  ++spTrackIt)
183  if ((int)spTrackIt->key() == trackIt->first) associatedSpacePoint = true;
184  if (associatedSpacePoint) continue;
185  if ((SpacePointPos(*spacePointIt) - trackIt->second->Vertex())
186  .Angle(trackIt->second->Direction()) < fConeAngle * TMath::Pi() / 180) {
187  trackIt->second->AddForwardSpacePoint(spacePointIt->key());
188  trackIt->second->AddForwardTrack(spTracks.at(0).key());
189  }
190  if ((SpacePointPos(*spacePointIt) - trackIt->second->Vertex())
191  .Angle(-1 * trackIt->second->Direction()) < fConeAngle * TMath::Pi() / 180) {
192  trackIt->second->AddBackwardSpacePoint(spacePointIt->key());
193  trackIt->second->AddBackwardTrack(spTracks.at(0).key());
194  }
195  }
196  }
197  if (fDebug > 0) std::cout << std::endl << "Identifying showers:" << std::endl;
198  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
199  trackIt != reconTracks.end();
200  ++trackIt) {
201  if (fDebug > 1)
202  std::cout << " Track " << trackIt->first << " has space point cone size "
203  << trackIt->second->ConeSize() << " and track cone size "
204  << trackIt->second->TrackConeSize() << std::endl;
205  if (TMath::Abs(trackIt->second->ConeSize()) > 30 and
206  TMath::Abs(trackIt->second->TrackConeSize()) > 3) {
207  trackIt->second->MakeShower();
208  if (fDebug > 0)
209  std::cout << " Making track " << trackIt->first << " a shower (Type I)" << std::endl;
210  if (trackIt->second->ConeSize() < 0) trackIt->second->FlipTrack();
211  }
212  }
213 
214  // Look for shower cones
215  std::cout << std::endl << " Shower cones:" << std::endl;
216  for (std::map<int, std::unique_ptr<ReconTrack>>::const_iterator trackIt = reconTracks.begin();
217  trackIt != reconTracks.end();
218  ++trackIt) {
219  if (trackIt->second->IsShower()) {
220  if (fDebug > 1) std::cout << " Track " << trackIt->first << std::endl;
221  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator otherTrackIt = reconTracks.begin();
222  otherTrackIt != reconTracks.end();
223  ++otherTrackIt) {
224  if (trackIt->first == otherTrackIt->first or !otherTrackIt->second->IsUndetermined())
225  continue;
226  if ((otherTrackIt->second->Vertex() - trackIt->second->Vertex())
227  .Angle(trackIt->second->Direction()) < fConeAngle * TMath::Pi() / 180 or
228  (otherTrackIt->second->End() - trackIt->second->Vertex())
229  .Angle(trackIt->second->Direction()) < fConeAngle * TMath::Pi() / 180) {
230  std::cout << " " << otherTrackIt->first << std::endl;
231  otherTrackIt->second->MakeShower();
232  if (fDebug > 0)
233  std::cout << " Making track " << otherTrackIt->first << " a shower (Type II)"
234  << std::endl;
235  }
236  }
237  }
238  }
239 
240  // Look at remaining undetermined tracks
241  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
242  trackIt != reconTracks.end();
243  ++trackIt) {
244  if (trackIt->second->IsUndetermined()) { trackIt->second->MakeShower(); }
245  }
246 
247  std::cout << std::endl << "Event " << event << " track shower separation:" << std::endl;
248  std::cout << "Shower initial tracks are:" << std::endl;
249  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
250  trackIt != reconTracks.end();
251  ++trackIt)
252  if (trackIt->second->IsShowerTrack()) std::cout << " " << trackIt->first << std::endl;
253 
254  std::cout << "Track tracks are:" << std::endl;
255  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
256  trackIt != reconTracks.end();
257  ++trackIt)
258  if (trackIt->second->IsTrack()) std::cout << " " << trackIt->first << std::endl;
259 
260  // Shower hits -- select all hits which aren't associated with a determined track
261  std::vector<art::Ptr<recob::Hit>> showerHits;
262  for (std::vector<art::Ptr<recob::Hit>>::const_iterator hitIt = hits.begin(); hitIt != hits.end();
263  ++hitIt) {
264  bool showerHit = true;
265  const std::vector<art::Ptr<recob::Track>> hitTracks = fmth.at(hitIt->key());
266  for (std::vector<art::Ptr<recob::Track>>::const_iterator hitTrackIt = hitTracks.begin();
267  hitTrackIt != hitTracks.end();
268  ++hitTrackIt)
269  if (reconTracks[hitTrackIt->key()]->IsTrack()) showerHit = false;
270  if (showerHit) showerHits.push_back(*hitIt);
271  }
272 
273  return showerHits;
274 }
275 
277  std::map<int, std::unique_ptr<ReconTrack>>& reconTracks) const
278 {
279 
280  // Consider the cones for each track
281  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
282  trackIt != reconTracks.end();
283  ++trackIt) {
284 
285  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator otherTrackIt = reconTracks.begin();
286  otherTrackIt != reconTracks.end();
287  ++otherTrackIt) {
288 
289  if (trackIt->first == otherTrackIt->first) continue;
290  if ((otherTrackIt->second->Vertex() - trackIt->second->Vertex())
291  .Angle(trackIt->second->VertexDirection()) < fConeAngle * TMath::Pi() / 180 or
292  (otherTrackIt->second->End() - trackIt->second->Vertex())
293  .Angle(trackIt->second->VertexDirection()) < fConeAngle * TMath::Pi() / 180) {
294  trackIt->second->AddForwardTrack(otherTrackIt->first);
295  otherTrackIt->second->AddShowerTrack(trackIt->first);
296  }
297  if ((otherTrackIt->second->Vertex() - trackIt->second->Vertex())
298  .Angle(-1 * trackIt->second->VertexDirection()) < fConeAngle * TMath::Pi() / 180 or
299  (otherTrackIt->second->End() - trackIt->second->Vertex())
300  .Angle(-1 * trackIt->second->VertexDirection()) < fConeAngle * TMath::Pi() / 180)
301  trackIt->second->AddBackwardTrack(otherTrackIt->first);
302  }
303  }
304 
305  // Determine if any of these tracks are actually shower tracks
306  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
307  trackIt != reconTracks.end();
308  ++trackIt) {
309 
310  if (!trackIt->second->ShowerTrackCandidate()) continue;
311 
312  std::cout << "Track " << trackIt->first
313  << " is a candidate, with shower cone tracks:" << std::endl;
314  const std::vector<int>& showerConeTracks = trackIt->second->ForwardConeTracks();
315  for (std::vector<int>::const_iterator showerConeTrackIt = showerConeTracks.begin();
316  showerConeTrackIt != showerConeTracks.end();
317  ++showerConeTrackIt)
318  std::cout << " " << *showerConeTrackIt << std::endl;
319 
320  bool isBestCandidate = true;
321  const std::vector<int>& showerTracks = trackIt->second->ShowerTracks();
322  for (std::vector<int>::const_iterator showerTrackIt = showerTracks.begin();
323  showerTrackIt != showerTracks.end();
324  ++showerTrackIt) {
325  if (!reconTracks[*showerTrackIt]->ShowerTrackCandidate()) continue;
326  if (std::find(showerConeTracks.begin(), showerConeTracks.end(), *showerTrackIt) ==
327  showerConeTracks.end())
328  continue;
329  if (reconTracks[*showerTrackIt]->IsShowerTrack()) continue;
330  if (trackIt->second->TrackConeSize() < reconTracks[*showerTrackIt]->TrackConeSize())
331  isBestCandidate = false;
332  }
333 
334  if (isBestCandidate) trackIt->second->MakeShowerTrack();
335  }
336 
337  // Determine which tracks are shower cones
338  std::vector<int> showerTracks;
339  for (std::map<int, std::unique_ptr<ReconTrack>>::iterator trackIt = reconTracks.begin();
340  trackIt != reconTracks.end();
341  ++trackIt) {
342  if (trackIt->second->IsShowerTrack()) {
343  showerTracks.push_back(trackIt->first);
344  const std::vector<int>& coneTracks = trackIt->second->ForwardConeTracks();
345  for (std::vector<int>::const_iterator coneTrackIt = coneTracks.begin();
346  coneTrackIt != coneTracks.end();
347  ++coneTrackIt)
348  reconTracks[*coneTrackIt]->MakeShowerCone();
349  }
350  }
351 
352  return showerTracks;
353 }
354 
355 TVector3 shower::TrackShowerSeparationAlg::Gradient(const std::vector<TVector3>& points,
356  const std::unique_ptr<TVector3>& dir) const
357 {
358 
359  int nhits = 0;
360  double sumx = 0., sumy = 0., sumz = 0., sumx2 = 0., sumxy = 0., sumxz = 0.;
361  for (std::vector<TVector3>::const_iterator pointIt = points.begin(); pointIt != points.end();
362  ++pointIt) {
363  ++nhits;
364  sumx += pointIt->X();
365  sumy += pointIt->Y();
366  sumz += pointIt->Z();
367  sumx2 += pointIt->X() * pointIt->X();
368  sumxy += pointIt->X() * pointIt->Y();
369  sumxz += pointIt->X() * pointIt->Z();
370  }
371 
372  double dydx = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
373  double yint = (sumy * sumx2 - sumx * sumxy) / (nhits * sumx2 - sumx * sumx);
374  double dzdx = (nhits * sumxz - sumx * sumz) / (nhits * sumx2 - sumx * sumx);
375  double zint = (sumz * sumx2 - sumx * sumxz) / (nhits * sumx2 - sumx * sumx);
376  TVector2 directionXY = TVector2(1, dydx).Unit(), directionXZ = TVector2(1, dzdx).Unit();
377  TVector3 direction = TVector3(1, dydx, dzdx).Unit();
378  TVector3 intercept = TVector3(0, yint, zint);
379 
380  // Make sure the best fit direction is pointing correctly
381  if (dir and TMath::Abs(direction.Angle(*dir)) > TMath::Pi() / 2.) direction *= -1;
382 
383  return direction;
384 }
385 
387 {
388 
389  std::vector<TVector3> points;
390  std::unique_ptr<TVector3> dir;
391 
392  for (unsigned int traj = 0; traj < track->NumberTrajectoryPoints(); ++traj)
393  points.push_back(track->LocationAtPoint<TVector3>(traj));
394  dir = std::make_unique<TVector3>(track->VertexDirection<TVector3>());
395 
396  return Gradient(points, dir);
397 }
398 
400  const std::vector<art::Ptr<recob::SpacePoint>>& spacePoints) const
401 {
402 
403  std::vector<TVector3> points;
404  std::unique_ptr<TVector3> dir;
405 
406  for (std::vector<art::Ptr<recob::SpacePoint>>::const_iterator spacePointIt = spacePoints.begin();
407  spacePointIt != spacePoints.end();
408  ++spacePointIt)
409  points.push_back(SpacePointPos(*spacePointIt));
410 
411  return Gradient(points, dir);
412 }
413 
414 TVector3 shower::TrackShowerSeparationAlg::ProjPoint(const TVector3& point,
415  const TVector3& direction,
416  const TVector3& origin) const
417 {
418  return (point - origin).Dot(direction) * direction + origin;
419 }
420 
422  const art::Ptr<recob::SpacePoint>& spacePoint) const
423 {
424  const double* xyz = spacePoint->XYZ();
425  return TVector3(xyz[0], xyz[1], xyz[2]);
426 }
427 
429  const std::vector<art::Ptr<recob::SpacePoint>>& spacePoints) const
430 {
431 
432  TVector3 point = SpacePointPos(spacePoints.at(0));
433  TVector3 direction = Gradient(spacePoints);
434 
435  std::vector<double> distances;
436  for (std::vector<art::Ptr<recob::SpacePoint>>::const_iterator spacePointIt = spacePoints.begin();
437  spacePointIt != spacePoints.end();
438  ++spacePointIt) {
439  TVector3 pos = SpacePointPos(*spacePointIt);
440  TVector3 proj = ProjPoint(pos, direction, point);
441  distances.push_back((pos - proj).Mag());
442  }
443 
444  double rms = TMath::RMS(distances.begin(), distances.end());
445 
446  return rms;
447 }
void reconfigure(fhicl::ParameterSet const &pset)
Read in configurable parameters from provided parameter set.
double SpacePointsRMS(const std::vector< art::Ptr< recob::SpacePoint >> &spacePoints) const
Point_t const & LocationAtPoint(size_t i) const
Access to track position at different points.
Definition: Track.h:160
TVector3 ProjPoint(const TVector3 &point, const TVector3 &direction, const TVector3 &origin=TVector3(0, 0, 0)) const
size_t NumberTrajectoryPoints() const
Various functions related to the presence and the number of (valid) points.
Definition: Track.h:136
Vector_t VertexDirection() const
Access to track direction at different points.
Definition: Track.h:166
for(Int_t i=0;i< nentries;i++)
Definition: comparison.C:30
intermediate_table::const_iterator const_iterator
std::vector< int > InitialTrackLikeSegment(std::map< int, std::unique_ptr< ReconTrack >> &reconTracks) const
TVector3 SpacePointPos(const art::Ptr< recob::SpacePoint > &spacePoint) const
Return 3D point of this space point.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
void hits()
Definition: readHits.C:15
TrackShowerSeparationAlg(fhicl::ParameterSet const &pset)
T get(std::string const &key) const
Definition: ParameterSet.h:314
const Double32_t * XYZ() const
Definition: SpacePoint.h:78
TDirectory * dir
Definition: macro.C:5
Float_t proj
Definition: plot.C:35
TVector3 Gradient(const std::vector< TVector3 > &points, const std::unique_ptr< TVector3 > &dir) const
std::vector< art::Ptr< recob::Hit > > SelectShowerHits(int event, const std::vector< art::Ptr< recob::Hit >> &hits, const std::vector< art::Ptr< recob::Track >> &tracks, const std::vector< art::Ptr< recob::SpacePoint >> &spacePoints, const art::FindManyP< recob::Hit > &fmht, const art::FindManyP< recob::Track > &fmth, const art::FindManyP< recob::SpacePoint > &fmspt, const art::FindManyP< recob::Track > &fmtsp) const
Float_t track
Definition: plot.C:35
constexpr Point origin()
Returns a origin position with a point of the specified type.
Definition: geo_vectors.h:229
Event finding and building.