LArSoft  v10_04_05
Liquid Argon Software toolkit - https://larsoft.org/
TCShowerAlg.cxx
Go to the documentation of this file.
1 #include "TCShowerAlg.h"
2 
4 
10 
11 namespace {
12  struct pfpStuff {
16  std::vector<art::Ptr<recob::Hit>> hits;
17  std::vector<int> clsIDs;
18  double score;
19  };
20 
21  bool comparePFP(const pfpStuff& l, const pfpStuff& r)
22  {
23  art::Ptr<recob::Vertex> const& lvtx = l.vtx;
24  art::Ptr<recob::Vertex> const& rvtx = r.vtx;
25 
26  double const lz = l.hits.size();
27  double const rz = r.hits.size();
28 
29  // RSF: USED TO BE 50
30  constexpr int hitthres = 80;
31 
32  if (lz > hitthres && rz <= hitthres) return false;
33 
34  if (lz <= hitthres && rz > hitthres) return true;
35 
36  return lvtx->position().Z() > rvtx->position().Z();
37  }
38 }
39 
40 namespace shower {
41 
42  TCShowerAlg::TCShowerAlg(fhicl::ParameterSet const& pset)
43  : fCalorimetryAlg(pset.get<fhicl::ParameterSet>("CalorimetryAlg"))
44  , fProjectionMatchingAlg(pset.get<fhicl::ParameterSet>("ProjectionMatchingAlg"))
45  {}
46 
48  detinfo::DetectorPropertiesData const& detProp,
50  std::vector<art::Ptr<recob::Cluster>> const& clusterlist,
51  std::vector<art::Ptr<recob::Hit>> const& hitlist,
52  art::FindManyP<recob::Hit> const& cls_fm,
53  art::FindManyP<recob::Cluster> const& clspfp_fm,
54  art::FindManyP<recob::Vertex> const& vtxpfp_fm,
55  art::FindManyP<recob::Cluster> const& hitcls_fm,
56  art::FindManyP<recob::Track> const& trkpfp_fm)
57  {
58  totalEnergy.resize(2);
59  totalEnergyErr.resize(2);
60  dEdx.resize(2);
61  dEdxErr.resize(2);
62 
63  std::vector<pfpStuff> allpfps;
64 
65  // put together pfparticle information
66  auto const& plane_2 = art::ServiceHandle<geo::WireReadout>()->Get().Plane({0, 0, 2});
67  for (size_t i = 0; i < pfplist.size(); ++i) {
68  pfpStuff thispfp;
69  thispfp.hits.clear();
70  thispfp.clsIDs.clear();
71  thispfp.pfp = pfplist[i];
72 
73  std::vector<art::Ptr<recob::Vertex>> thisvtxlist = vtxpfp_fm.at(pfplist[i].key());
74  if (thisvtxlist.size()) thispfp.vtx = thisvtxlist[0];
75 
76  std::vector<art::Ptr<recob::Track>> thistrklist = trkpfp_fm.at(pfplist[i].key());
77  if (thistrklist.size()) thispfp.trk = thistrklist[0];
78 
79  std::vector<art::Ptr<recob::Cluster>> thisclusterlist = clspfp_fm.at(pfplist[i].key());
80  std::vector<int> clustersize;
81 
82  for (size_t j = 0; j < thisclusterlist.size(); ++j) {
83 
84  thispfp.clsIDs.push_back(thisclusterlist[j]->ID());
85 
86  std::vector<art::Ptr<recob::Hit>> thishitlist = cls_fm.at(thisclusterlist[j].key());
87  clustersize.push_back((int)thishitlist.size());
88 
89  for (size_t k = 0; k < thishitlist.size(); ++k) {
90  thispfp.hits.push_back(thishitlist[k]);
91  } // loop through hits
92 
93  } // loop through clusters
94 
95  if (clustersize.size() == 3) {
96  if (!thispfp.vtx) continue;
97  if (!thispfp.trk) continue;
98 
99  allpfps.push_back(thispfp);
100 
101  double tick = detProp.ConvertXToTicks(thispfp.vtx->position().X(), plane_2.ID());
102  int wire = plane_2.WireCoordinate(thispfp.vtx->position());
103 
104  std::cout << "pfp " << thispfp.pfp->Self() + 1 << " cluster sizes " << clustersize[0] << ":"
105  << clustersize[1] << ":" << clustersize[2] << " vertex " << thispfp.vtx->ID()
106  << " " << tick << ":" << wire << " z " << thispfp.vtx->position().Z()
107  << std::endl;
108 
109  } // add pfp to list
110 
111  } // loop through pfparticles
112 
113  std::sort(allpfps.begin(), allpfps.end(), comparePFP);
114  std::reverse(allpfps.begin(), allpfps.end());
115 
116  std::cout << "sorted pfps: ";
117  for (size_t i = 0; i < allpfps.size(); ++i)
118  std::cout << allpfps[i].pfp->Self() + 1 << " ";
119  std::cout << std::endl;
120 
121  bool showerCandidate = false;
122 
123  auto const& wireReadoutGeom = art::ServiceHandle<geo::WireReadout>()->Get();
124  for (size_t i = 0; i < allpfps.size(); ++i) {
125 
126  showerHits.clear();
127 
128  art::Ptr<recob::Vertex> pfpvtx = allpfps[i].vtx;
129  art::Ptr<recob::Track> pfptrk = allpfps[i].trk;
130  std::vector<art::Ptr<recob::Hit>> pfphits = allpfps[i].hits;
131  std::vector<art::Ptr<recob::Cluster>> pfpcls = clspfp_fm.at(allpfps[i].pfp.key());
132 
133  std::cout << "pfp " << allpfps[i].pfp->Self() + 1 << " hits " << pfphits.size() << std::endl;
134 
135  TVector3 vtx;
136  vtx[0] = pfpvtx->position().X();
137  vtx[1] = pfpvtx->position().Y();
138  vtx[2] = pfpvtx->position().Z();
139 
140  if (pfptrk->Vertex().Z() < pfptrk->End().Z()) {
141  shwvtx = pfptrk->Vertex();
142  shwDir = pfptrk->VertexDirection();
143  }
144  else {
145  shwvtx = pfptrk->End();
146  shwDir = -pfptrk->EndDirection();
147  }
148 
149  int tolerance = 60; // how many shower like cluster you need to define a shower
150  double pullTolerance = 0.7; // hits should be evenly distributed around the track
151  double maxDist = 20; // how far a shower like cluster can be from the track
152  double minDistVert = 15; // exclude tracks near the vertex
153 
154  // TODO: count number of shower-like hits hits "behind" vertex
155  // if high, pick an earlier cluster and refit hits
156  // this is going to take some restructuring
157 
158  if (pfphits.size() < 30) continue;
159  if (pfphits.size() > 500) continue;
160  // adjust tolerances for short tracks
161  if (pfphits.size() < 90) {
162  tolerance = 50;
163  pullTolerance = 0.9;
164  }
165  if (pfphits.size() > 400)
166  tolerance = 200;
167  else if (pfphits.size() > 100)
168  tolerance = 100; // RSF added used to be 100, 100
169 
170  // add pfp hits to shower
171  for (size_t ii = 0; ii < pfphits.size(); ++ii) {
172  if (addShowerHit(pfphits[ii], showerHits)) showerHits.push_back(pfphits[ii]);
173  } // loop over pfphits
174 
175  int nShowerHits = 0;
176  double showerHitPull = 0;
177 
178  geo::Point_t pfpStart = shwvtx;
179  geo::Point_t pfpPt2 = shwvtx + shwDir; // a second point along the track
180 
181  // track vertex
182  std::map<geo::PlaneID, double> trk_tick1;
183  std::map<geo::PlaneID, double> trk_wire1;
184 
185  // second track point
186  std::map<geo::PlaneID, double> trk_tick2;
187  std::map<geo::PlaneID, double> trk_wire2;
188 
189  for (auto const& plane : wireReadoutGeom.Iterate<geo::PlaneGeo>()) {
190  auto const& planeid = plane.ID();
191  trk_tick1[planeid] = detProp.ConvertXToTicks(pfpStart.X(), planeid);
192  trk_wire1[planeid] = plane.WireCoordinate(pfpStart);
193  trk_tick2[planeid] = detProp.ConvertXToTicks(pfpPt2.X(), planeid);
194  trk_wire2[planeid] = plane.WireCoordinate(pfpPt2);
195  }
196 
197  for (size_t j = 0; j < clusterlist.size(); ++j) {
198  std::vector<art::Ptr<recob::Hit>> cls_hitlist = cls_fm.at(clusterlist[j].key());
199 
200  if (clusterlist[j]->ID() > 0 && cls_hitlist.size() > 10) continue;
201  if (cls_hitlist.size() > 50) continue;
202 
203  bool isGoodCluster = false; // true if the hit belongs to a cluster that
204  // should be added to the shower
205 
206  bool skipit = false; // skip clusters already in the pfp
207  for (size_t k = 0; k < allpfps[i].clsIDs.size(); ++k) {
208  if (allpfps[i].clsIDs[k] == clusterlist[j]->ID()) skipit = true;
209  }
210  if (skipit) continue;
211 
212  for (size_t jj = 0; jj < cls_hitlist.size(); ++jj) {
213  int isGoodHit = goodHit(clockData,
214  detProp,
215  cls_hitlist[jj],
216  maxDist,
217  minDistVert,
218  trk_wire1,
219  trk_tick1,
220  trk_wire2,
221  trk_tick2);
222 
223  if (isGoodHit == -1) {
224  isGoodCluster = false;
225  break;
226  }
227  else if (isGoodHit == 1) {
228  isGoodCluster = true;
229  }
230 
231  } // loop over hits in cluster
232 
233  // add hits to shower
234  if (isGoodCluster) {
235  for (size_t jj = 0; jj < cls_hitlist.size(); ++jj) {
236  nShowerHits++;
237 
238  int showerHitPullAdd = 0;
239  goodHit(clockData,
240  detProp,
241  cls_hitlist[jj],
242  maxDist,
243  minDistVert,
244  trk_wire1,
245  trk_tick1,
246  trk_wire2,
247  trk_tick2,
248  showerHitPullAdd);
249  showerHitPull += showerHitPullAdd;
250 
251  if (addShowerHit(cls_hitlist[jj], showerHits)) showerHits.push_back(cls_hitlist[jj]);
252 
253  } // loop over hits in cluster
254  } // cluster contains hit close to track
255 
256  } // loop through cluserlist
257 
258  showerHitPull /= nShowerHits;
259 
260  std::cout << "shower hits " << showerHits.size() << " " << nShowerHits << " shower pull "
261  << showerHitPull << std::endl;
262 
263  if (nShowerHits > tolerance && std::abs(showerHitPull) < pullTolerance) {
264  showerCandidate = true;
265  std::cout << "SHOWER CANDIDATE" << std::endl;
266  // loop over hits to find those that aren't associated with any clusters
267  if (nShowerHits > 400) maxDist *= 2; // TODO: optimize this threshold
268  for (size_t k = 0; k < hitlist.size(); ++k) {
269  std::vector<art::Ptr<recob::Cluster>> hit_clslist = hitcls_fm.at(hitlist[k].key());
270  if (hit_clslist.size()) continue;
271 
272  int isGoodHit = goodHit(clockData,
273  detProp,
274  hitlist[k],
275  maxDist * 2,
276  minDistVert * 2,
277  trk_wire1,
278  trk_tick1,
279  trk_wire2,
280  trk_tick2);
281  if (isGoodHit == 1 && addShowerHit(hitlist[k], showerHits))
282  showerHits.push_back(hitlist[k]);
283  } // loop over hits
284 
285  // loop over clusters to see if any fall within the shower
286  for (size_t k = 0; k < clusterlist.size(); ++k) {
287  std::vector<art::Ptr<recob::Hit>> cls_hitlist = cls_fm.at(clusterlist[k].key());
288  if (clusterlist[k]->ID() > 0 && cls_hitlist.size() > 50) continue;
289 
290  double thisDist = maxDist;
291  double thisMin = minDistVert;
292 
293  if (cls_hitlist.size() < 10) {
294  thisDist *= 4;
295  thisMin *= 4;
296  }
297  else if (cls_hitlist.size() < 30)
298  thisDist *= 2;
299 
300  int nhits = 0;
301  int ngoodhits = 0;
302 
303  // are the cluster hits close?
304  for (size_t kk = 0; kk < cls_hitlist.size(); ++kk) {
305  nhits++;
306  int isGoodHit = goodHit(clockData,
307  detProp,
308  cls_hitlist[kk],
309  thisDist,
310  thisMin,
311  trk_wire1,
312  trk_tick1,
313  trk_wire2,
314  trk_tick2);
315  if (isGoodHit == -1) {
316  ngoodhits = 0;
317  break;
318  }
319  else if (isGoodHit == 1) {
320  ngoodhits++;
321  }
322  } // loop over cluster hits
323 
324  double fracGood = (double)ngoodhits / nhits;
325 
326  bool isGoodTrack = fracGood > 0.4;
327 
328  if (isGoodTrack) {
329  for (size_t kk = 0; kk < cls_hitlist.size(); ++kk) {
330  if (addShowerHit(cls_hitlist[kk], showerHits)) showerHits.push_back(cls_hitlist[kk]);
331  } // loop over hits to add them to showe
332  }
333 
334  } // loop through clusterlist
335 
336  } // decide if shower
337 
338  if (showerCandidate) {
339  std::cout << "THIS IS THE SHOWER PFP: " << allpfps[i].pfp->Self() + 1 << std::endl;
340  break;
341  }
342 
343  } // loop through allpfps
344 
345  if (showerCandidate) return 1;
346 
347  return 0;
348  } // makeShowers
349 
350  // -----------------------------------------------------
351  // return -1 if hit is too close to track vertex or has a wide opening angle
352  // return 1 if hit is close to the shower axis
353  // return 0 otherwise
354 
356  detinfo::DetectorPropertiesData const& detProp,
357  art::Ptr<recob::Hit> const& hit,
358  double const maxDist,
359  double const minDistVert,
360  std::map<geo::PlaneID, double> const& trk_wire1,
361  std::map<geo::PlaneID, double> const& trk_tick1,
362  std::map<geo::PlaneID, double> const& trk_wire2,
363  std::map<geo::PlaneID, double> const& trk_tick2) const
364  {
365  int pull = 0;
366  return goodHit(clockData,
367  detProp,
368  hit,
369  maxDist,
370  minDistVert,
371  trk_wire1,
372  trk_tick1,
373  trk_wire2,
374  trk_tick2,
375  pull);
376 
377  } // goodHit
378 
379  // -----------------------------------------------------
380  // return -1 if hit is too close to track vertex or has a wide opening angle
381  // return 1 if hit is close to the shower axis
382  // return 0 otherwise
383 
385  detinfo::DetectorPropertiesData const& detProp,
386  art::Ptr<recob::Hit> const& hit,
387  double maxDist,
388  double const minDistVert,
389  std::map<geo::PlaneID, double> const& trk_wire1,
390  std::map<geo::PlaneID, double> const& trk_tick1,
391  std::map<geo::PlaneID, double> const& trk_wire2,
392  std::map<geo::PlaneID, double> const& trk_tick2,
393  int& pull) const
394  {
395  double wirePitch =
396  art::ServiceHandle<geo::WireReadout>()->Get().Plane(hit->WireID()).WirePitch();
397  double tickToDist = detProp.DriftVelocity(detProp.Efield(), detProp.Temperature());
398  tickToDist *= 1.e-3 * sampling_rate(clockData); // 1e-3 is conversion of 1/us to 1/ns
399  double UnitsPerTick = tickToDist / wirePitch;
400 
401  double x0 = hit->WireID().Wire;
402  double y0 = hit->PeakTime() * UnitsPerTick;
403 
404  double x1 = trk_wire1.at(hit->WireID());
405  double y1 = trk_tick1.at(hit->WireID()) * UnitsPerTick;
406 
407  double x2 = trk_wire2.at(hit->WireID());
408  double y2 = trk_tick2.at(hit->WireID()) * UnitsPerTick;
409 
410  double distToVert = std::hypot(x0 - x1, y0 - y1);
411  if (distToVert < minDistVert) return -1;
412 
413  if (x2 > x1) {
414  if (distToVert < 50)
415  maxDist /= 4;
416  else if (distToVert < 100)
417  maxDist /= 2; // trying to exclude photon showers
418  }
419 
420  // exclude cluster if it's "behind" the vertex
421  double a = std::hypot(x2 - x1, y2 - y1);
422  double b = std::hypot(x0 - x1, y0 - y1);
423  double c = std::hypot(x0 - x2, y0 - y2);
424  double costheta = -(pow(c, 2) - pow(a, 2) - pow(b, 2)) / (2 * a * b);
425  if (costheta < 0) return -1;
426 
427  double dist =
428  std::abs((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) / std::hypot(y2 - y1, x2 - x1);
429 
430  if (dist < maxDist) {
431  if (((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1) > 0)
432  pull = 1;
433  else
434  pull = -1;
435  return 1;
436  }
437 
438  return 0;
439 
440  } // goodHit
441 
442  // -----------------------------------------------------
443 
445  std::vector<art::Ptr<recob::Hit>> showerhits) const
446  {
447 
448  for (size_t i = 0; i < showerhits.size(); ++i) {
449  if (hit.key() == showerhits[i].key()) return false;
450  }
451 
452  return true;
453 
454  } // addShowerHit
455 
456  // -----------------------------------------------------
457 
458 } // namespace shower
TRandom r
Definition: spectrum.C:23
std::vector< double > totalEnergyErr
Definition: TCShowerAlg.h:44
bool addShowerHit(art::Ptr< recob::Hit > hit, std::vector< art::Ptr< recob::Hit >> showerhits) const
Float_t y1[n_points_granero]
Definition: compare.C:5
Float_t x1[n_points_granero]
Definition: compare.C:5
std::vector< double > dEdx
Definition: TCShowerAlg.h:45
double Temperature() const
In kelvin.
constexpr auto abs(T v)
Returns the absolute value of the argument.
Vector_t VertexDirection() const
Access to track direction at different points.
Definition: Track.h:166
cout<< "Opened file "<< fin<< " ixs= "<< ixs<< endl;if(ixs==0) hhh=(TH1F *) fff-> Get("h1")
Definition: AddMC.C:8
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:430
geo::WireID const & WireID() const
Initial tdc tick for hit.
Definition: Hit.h:290
geo::Point_t shwvtx
Definition: TCShowerAlg.h:41
int makeShowers(detinfo::DetectorClocksData const &dataClock, detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::PFParticle >> const &pfplist, std::vector< art::Ptr< recob::Cluster >> const &clusterlist, std::vector< art::Ptr< recob::Hit >> const &hitlist, art::FindManyP< recob::Hit > const &cls_fm, art::FindManyP< recob::Cluster > const &clspfp_fm, art::FindManyP< recob::Vertex > const &vtxpfp_fm, art::FindManyP< recob::Cluster > const &hitcls_fm, art::FindManyP< recob::Track > const &trkpfp_fm)
Definition: TCShowerAlg.cxx:47
Float_t y2[n_points_geant4]
Definition: compare.C:26
double Efield(unsigned int planegap=0) const
kV/cm
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:289
geo::Vector_t shwDir
Definition: TCShowerAlg.h:39
void hits()
Definition: readHits.C:15
parameter set interface
key_type key() const noexcept
Definition: Ptr.h:166
Geometry information for a single wire plane.The plane is represented in the geometry by a solid whic...
Definition: PlaneGeo.h:67
Point_t const & Vertex() const
Access to track position at different points.
Definition: Track.h:158
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:73
double ConvertXToTicks(double X, int p, int t, int c) const
double DriftVelocity(double efield=0., double temperature=0.) const
cm/us
Declaration of cluster object.
Definition of data types for geometry description.
Detector simulation of raw signals on wires.
ROOT::Math::PositionVector3D< ROOT::Math::Cartesian3D< double >, ROOT::Math::GlobalCoordinateSystemTag > Point_t
Type for representation of position in physical 3D space.
Definition: geo_vectors.h:180
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:226
decltype(auto) get(T &&obj)
ADL-aware version of std::to_string.
Definition: StdUtils.h:120
double dist(const TReal *x, const TReal *y, const unsigned int dimension)
Contains all timing reference information for the detector.
Vector_t EndDirection() const
Access to track direction at different points.
Definition: Track.h:167
std::vector< double > totalEnergy
Definition: TCShowerAlg.h:43
Point_t const & End() const
Access to track position at different points.
Definition: Track.h:159
int goodHit(detinfo::DetectorClocksData const &dataClock, detinfo::DetectorPropertiesData const &detProp, art::Ptr< recob::Hit > const &, double maxDist, double minDistVert, std::map< geo::PlaneID, double > const &trk_wire1, std::map< geo::PlaneID, double > const &trk_tick1, std::map< geo::PlaneID, double > const &trk_wire2, std::map< geo::PlaneID, double > const &trk_tick2) const
Float_t x2[n_points_geant4]
Definition: compare.C:26
double sampling_rate(DetectorClocksData const &data)
Returns the period of the TPC readout electronics clock.
std::vector< art::Ptr< recob::Hit > > showerHits
Definition: TCShowerAlg.h:48
std::vector< double > dEdxErr
Definition: TCShowerAlg.h:46
const Point_t & position() const
Return vertex 3D position.
Definition: Vertex.h:64