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