EMShowerAlg.cxx
Go to the documentation of this file.
1 ///////////////////////////////////////////////////////////////////
2 // Implementation of the EMShower algorithm
3 //
4 // Forms EM showers from clusters and associated tracks.
5 // Also provides methods for finding the vertex and further
6 // properties of the shower.
7 //
8 // Mike Wallbank (m.wallbank@sheffield.ac.uk), September 2015
9 ////////////////////////////////////////////////////////////////////
10 
12 #include "cetlib/pow.h"
14 
19 
20 #include "TAxis.h"
21 #include "TCanvas.h"
22 #include "TFile.h"
23 #include "TGraph.h"
24 #include "TH1.h"
25 #include "TLine.h"
26 #include "TMath.h"
27 #include "TMathBase.h"
28 #include "TMultiGraph.h"
29 #include "TProfile.h"
30 
31 #include "range/v3/numeric.hpp"
32 #include "range/v3/view.hpp"
33 
34 using lar::to_element;
35 using namespace ranges;
36 
38  : fDebug{debug}
39  , fMinTrackLength{pset.get<double>("MinTrackLength")}
40  , fdEdxTrackLength{pset.get<double>("dEdxTrackLength")}
41  , fSpacePointSize{pset.get<double>("SpacePointSize")}
42  , fNfitpass{pset.get<unsigned int>("Nfitpass")}
43  , fNfithits{pset.get<std::vector<unsigned int>>("Nfithits")}
44  , fToler{pset.get<std::vector<double>>("Toler")}
45  , fShowerEnergyAlg(pset.get<fhicl::ParameterSet>("ShowerEnergyAlg"))
46  , fCalorimetryAlg(pset.get<fhicl::ParameterSet>("CalorimetryAlg"))
47  , fProjectionMatchingAlg(pset.get<fhicl::ParameterSet>("ProjectionMatchingAlg"))
48  , fDetector{pset.get<std::string>("Detector", "dune35t")} // tmp
49  , fMakeGradientPlot{pset.get<bool>("MakeGradientPlot", false)}
50  , fMakeRMSGradientPlot{pset.get<bool>("MakeRMSGradientPlot", false)}
51  , fNumShowerSegments{pset.get<int>("NumShowerSegments", 4)}
52 {
53  if (fNfitpass != fNfithits.size() || fNfitpass != fToler.size()) {
55  << "EMShowerAlg: fNfithits and fToler need to have size fNfitpass";
56  }
57 }
58 
59 void
61  std::vector<art::Ptr<recob::Cluster>> const& clusters,
62  art::FindManyP<recob::Hit> const& fmh,
63  art::FindManyP<recob::Track> const& fmt,
64  std::map<int, std::vector<int>>& clusterToTracks,
65  std::map<int, std::vector<int>>& trackToClusters) const
66 {
67  std::vector<int> clustersToIgnore = {-999};
69  clusters, fmh, fmt, clustersToIgnore, clusterToTracks, trackToClusters);
70 }
71 
72 void
74  std::vector<art::Ptr<recob::Cluster>> const& clusters,
75  art::FindManyP<recob::Hit> const& fmh,
76  art::FindManyP<recob::Track> const& fmt,
77  std::vector<int> const& clustersToIgnore,
78  std::map<int, std::vector<int>>& clusterToTracks,
79  std::map<int, std::vector<int>>& trackToClusters) const
80 {
81  // Look through all the clusters
82  for (auto const& clusterPtr : clusters) {
83 
84  // Get the hits in this cluster
85  auto const& clusterHits = fmh.at(clusterPtr.key());
86 
87  // Look at all these hits and find the associated tracks
88  for (auto const& clusterHitPtr : clusterHits) {
89  // Get the tracks associated with this hit
90  auto const& clusterHitTracks = fmt.at(clusterHitPtr.key());
91  if (clusterHitTracks.size() > 1) {
92  std::cout << "More than one track associated with this hit!\n";
93  continue;
94  }
95 
96  if (clusterHitTracks.size() < 1) continue;
97 
98  auto const& clusterHitTrackPtr = clusterHitTracks[0];
99  if (clusterHitTrackPtr->Length() < fMinTrackLength) {
100  if (fDebug > 2)
101  std::cout << "Track " << clusterHitTrackPtr->ID() << " is too short! ("
102  << clusterHitTrackPtr->Length() << ")\n";
103  continue;
104  }
105 
106  // Add this cluster to the track map
107  int track = clusterHitTrackPtr.key();
108  int cluster = clusterPtr.key();
109  if (cet::search_all(clustersToIgnore, cluster)) continue;
110  if (not cet::search_all(trackToClusters[track], cluster))
111  trackToClusters[track].push_back(cluster);
112  if (not cet::search_all(clusterToTracks[cluster], track))
113  clusterToTracks[cluster].push_back(track);
114  }
115  }
116 }
117 
118 void
120  std::map<int, std::vector<art::Ptr<recob::Hit>>>& showerHitsMap) const
121 {
122  std::map<int, std::vector<int>> firstTPC;
123  for (auto const& [plane, hits] : showerHitsMap)
124  firstTPC[hits.at(0)->WireID().TPC].push_back(plane);
125 
126  // If all in the same TPC then that's great!
127  if (firstTPC.size() != 2) return;
128 
129  // If they are in more than two TPCs, not much we can do
130  else if (firstTPC.size() > 2)
131  return;
132 
133  // If we get to this point, there should be something we can do!
134 
135  // Find the problem plane
136  int problemPlane = -1;
137  for (auto const& planes : firstTPC | views::values)
138  if (planes.size() == 1) problemPlane = planes[0];
139 
140  // Require three hits
141  if (showerHitsMap.at(problemPlane).size() < 3) return;
142 
143  // and get the other planes with at least three hits
144  std::vector<int> otherPlanes;
145  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
146  if (plane != problemPlane and showerHitsMap.count(plane) and
147  showerHitsMap.at(plane).size() >= 3)
148  otherPlanes.push_back(plane);
149 
150  if (otherPlanes.size() == 0) return;
151 
152  // Look at the hits after the first one
153  unsigned int wrongTPC = showerHitsMap.at(problemPlane).at(0)->WireID().TPC;
154  unsigned int nHits = 0;
155  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt = showerHitsMap.at(problemPlane).begin();
156  hitIt != showerHitsMap.at(problemPlane).end() and (*hitIt)->WireID().TPC == wrongTPC;
157  ++hitIt)
158  ++nHits;
159 
160  // If there are more than two hits in the 'wrong TPC', we can't be sure it is indeed wrong
161  if (nHits > 2) return;
162 
163  // See if at least the next four times as many hits are in a different TPC
164  std::map<int, int> otherTPCs;
166  std::next(showerHitsMap.at(problemPlane).begin(), nHits);
167  hitIt != showerHitsMap.at(problemPlane).end() and
168  std::distance(std::next(showerHitsMap.at(problemPlane).begin(), nHits), hitIt) < 4 * nHits;
169  ++hitIt)
170  ++otherTPCs[(*hitIt)->WireID().TPC];
171 
172  if (otherTPCs.size() > 1) return;
173 
174  // If we get this far, we can move the problem hits from the front of the shower to the back
175  std::map<int, int> tpcCount;
176  for (int const otherPlane : otherPlanes)
178  std::next(showerHitsMap.at(otherPlane).begin());
179  hitIt != showerHitsMap.at(otherPlane).end() and
180  hitIt != std::next(showerHitsMap.at(otherPlane).begin(), 2);
181  ++hitIt)
182  ++tpcCount[(*hitIt)->WireID().TPC];
183 
184  // Remove the first hit if it is in the wrong TPC
185  if (tpcCount.size() == 1 and
186  tpcCount.begin()->first ==
187  (int)(*std::next(showerHitsMap.at(problemPlane).begin(), nHits))->WireID().TPC) {
188  std::vector<art::Ptr<recob::Hit>> naughty_hits;
189  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt = showerHitsMap.at(problemPlane).begin();
190  hitIt != std::next(showerHitsMap.at(problemPlane).begin(), nHits);
191  ++hitIt) {
192  naughty_hits.push_back(*hitIt);
193  showerHitsMap.at(problemPlane).erase(hitIt);
194  }
195  for (auto const& naughty_hit : naughty_hits)
196  showerHitsMap.at(problemPlane).push_back(naughty_hit);
197  }
198 }
199 
200 bool
202  detinfo::DetectorPropertiesData const& detProp,
203  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& showerHitsMap) const
204 {
205  bool consistencyCheck = true;
206 
207  if (showerHitsMap.size() < 2) { consistencyCheck = true; }
208  else if (showerHitsMap.size() == 2) {
209 
210  // With two views, we can check:
211  // -- timing between views is consistent
212  // -- the 3D start point makes sense when projected back onto the individual planes
213 
214  std::vector<art::Ptr<recob::Hit>> startHits;
215  std::vector<int> planes;
216  for (auto const& [plane, hits] : showerHitsMap) {
217  startHits.push_back(hits.front());
218  planes.push_back(plane);
219  }
220 
221  TVector3 showerStartPos = Construct3DPoint_(detProp, startHits.at(0), startHits.at(1));
222  TVector2 proj1 = Project3DPointOntoPlane_(detProp, showerStartPos, planes.at(0));
223  TVector2 proj2 = Project3DPointOntoPlane_(detProp, showerStartPos, planes.at(1));
224 
225  double timingDifference = std::abs(startHits.at(0)->PeakTime() - startHits.at(1)->PeakTime());
226  double projectionDifference = ((HitPosition_(detProp, *startHits.at(0)) - proj1).Mod() +
227  (HitPosition_(detProp, *startHits.at(1)) - proj2).Mod()) /
228  (double)2;
229 
230  if (timingDifference > 40 or projectionDifference > 5 or showerStartPos.X() == -9999 or
231  showerStartPos.Y() == -9999 or showerStartPos.Z() == -9999)
232  consistencyCheck = false;
233 
234  if (fDebug > 1)
235  std::cout << "Timing difference is " << timingDifference << " and projection distance is "
236  << projectionDifference << " (start is (" << showerStartPos.X() << ", "
237  << showerStartPos.Y() << ", " << showerStartPos.Z() << ")\n";
238  }
239  else if (showerHitsMap.size() == 3) {
240 
241  // With three views, we can check:
242  // -- the timing between views is consistent
243  // -- the 3D start point formed by two views and projected back into the third is close to the start point in that view
244 
245  std::map<int, art::Ptr<recob::Hit>> start2DMap;
246  for (auto const& [plane, hits] : showerHitsMap) {
247  start2DMap[plane] = hits.front();
248  }
249 
250  std::map<int, double> projDiff;
251  std::map<int, double> timingDiff;
252 
253  for (int plane = 0; plane < 3; ++plane) {
254 
255  std::vector<int> otherPlanes;
256  for (int otherPlane = 0; otherPlane < 3; ++otherPlane)
257  if (otherPlane != plane) otherPlanes.push_back(otherPlane);
258 
259  TVector3 showerStartPos = Construct3DPoint_(
260  detProp, start2DMap.at(otherPlanes.at(0)), start2DMap.at(otherPlanes.at(1)));
261  TVector2 showerStartProj = Project3DPointOntoPlane_(detProp, showerStartPos, plane);
262 
263  if (fDebug > 2) {
264  std::cout << "Plane... " << plane;
265  std::cout << "\nStart position in this plane is "
266  << HitPosition_(detProp, *start2DMap.at(plane)).X() << ", "
267  << HitPosition_(detProp, *start2DMap.at(plane)).Y() << ")\n";
268  std::cout << "Shower start from other two planes is (" << showerStartPos.X() << ", "
269  << showerStartPos.Y() << ", " << showerStartPos.Z() << ")\n";
270  std::cout << "Projecting the other two planes gives position (" << showerStartProj.X()
271  << ", " << showerStartProj.Y() << ")\n";
272  }
273 
274  double projDiff =
275  std::abs((showerStartProj - HitPosition_(detProp, *start2DMap.at(plane))).Mod());
276  double timeDiff = TMath::Max(
277  std::abs(start2DMap.at(plane)->PeakTime() - start2DMap.at(otherPlanes.at(0))->PeakTime()),
278  std::abs(start2DMap.at(plane)->PeakTime() - start2DMap.at(otherPlanes.at(1))->PeakTime()));
279 
280  if (fDebug > 1)
281  std::cout << "Plane " << plane << " has projDiff " << projDiff << " and timeDiff "
282  << timeDiff << '\n';
283 
284  if (projDiff > 5 or timeDiff > 40) consistencyCheck = false;
285  }
286  }
287 
288  if (fDebug > 1) std::cout << "Consistency check is " << consistencyCheck << '\n';
289 
290  return consistencyCheck;
291 }
292 
293 std::vector<int>
294 shower::EMShowerAlg::CheckShowerPlanes(std::vector<std::vector<int>> const& initialShowers,
295  std::vector<art::Ptr<recob::Cluster>> const& clusters,
296  art::FindManyP<recob::Hit> const& fmh) const
297 {
298  std::vector<int> clustersToIgnore;
299 
300  // Look at each shower
301  for (auto initialShowerIt = initialShowers.cbegin(); initialShowerIt != initialShowers.cend();
302  ++initialShowerIt) {
303 
304  if (std::distance(initialShowers.cbegin(), initialShowerIt) > 0) continue;
305 
306  // Map the clusters and cluster hits to each view
307  std::map<int, std::vector<art::Ptr<recob::Cluster>>> planeClusters;
308  std::map<int, std::vector<art::Ptr<recob::Hit>>> planeHits;
309  for (int const clusterIndex : *initialShowerIt) {
310  art::Ptr<recob::Cluster> const& cluster = clusters.at(clusterIndex);
311  planeClusters[cluster->Plane().Plane].push_back(cluster);
312  for (auto const& hit : fmh.at(cluster.key()))
313  planeHits[hit->WireID().Plane].push_back(hit);
314  }
315 
316  TFile* outFile = new TFile("chargeDistributions.root", "RECREATE");
317  std::map<int, TH1D*> chargeDist;
318  for (auto const& [plane, clusterPtrs] : planeClusters) {
319  for (auto const& clusterPtr : clusterPtrs) {
320  chargeDist[plane] = new TH1D(std::string("chargeDist_Plane" + std::to_string(plane) +
321  "_Cluster" + std::to_string(clusterPtr.key()))
322  .c_str(),
323  "",
324  150,
325  0,
326  1000);
327  auto const& hits = fmh.at(clusterPtr.key());
328  for (auto const& hit : hits | views::transform(to_element)) {
329  chargeDist[plane]->Fill(hit.Integral());
330  }
331  outFile->cd();
332  chargeDist[plane]->Write();
333  }
334  }
335  outFile->Close();
336  delete outFile;
337 
338  // Can't do much with fewer than three views
339  if (planeClusters.size() < 3) continue;
340 
341  // Look at how many clusters each plane has, and the proportion of hits each one uses
342  std::map<int, std::vector<double>> planeClusterSizes;
343  for (std::map<int, std::vector<art::Ptr<recob::Cluster>>>::iterator planeClustersIt =
344  planeClusters.begin();
345  planeClustersIt != planeClusters.end();
346  ++planeClustersIt) {
347  for (std::vector<art::Ptr<recob::Cluster>>::iterator planeClusterIt =
348  planeClustersIt->second.begin();
349  planeClusterIt != planeClustersIt->second.end();
350  ++planeClusterIt) {
351  std::vector<art::Ptr<recob::Hit>> hits = fmh.at(planeClusterIt->key());
352  planeClusterSizes[planeClustersIt->first].push_back(
353  (double)hits.size() / (double)planeHits.at(planeClustersIt->first).size());
354  }
355  }
356 
357  // Find the average hit fraction across all clusters in the plane
358  std::map<int, double> planeClustersAvSizes;
359  for (auto const& [plane, cluster_sizes] : planeClusterSizes) {
360  double const average = accumulate(cluster_sizes, 0.) / cluster_sizes.size();
361  planeClustersAvSizes[plane] = average;
362  }
363 
364  // Now decide if there is one plane which is ruining the reconstruction
365  // If two planes have a low average cluster fraction and one high, this plane likely merges two particle deposits together
366  int badPlane = -1;
367  for (auto const [plane, avg] : planeClustersAvSizes) {
368 
369  // Get averages from other planes and add in quadrature
370  std::vector<double> otherAverages;
371  for (auto const [other_plane, other_avg] : planeClustersAvSizes)
372  if (plane != other_plane) otherAverages.push_back(other_avg);
373 
374  double const sumSquareAvgsOtherPlanes = accumulate(
375  otherAverages, 0., [](double sum, double avg) { return sum + cet::square(avg); });
376  double const quadOtherPlanes = std::sqrt(sumSquareAvgsOtherPlanes);
377 
378  // If this plane has an average higher than the quadratic sum of the
379  // others, it may be bad
380  if (avg >= quadOtherPlanes) badPlane = plane;
381  }
382 
383  if (badPlane != -1) {
384  if (fDebug > 1) std::cout << "Bad plane is " << badPlane << '\n';
385  for (auto const& cluster : planeClusters.at(badPlane))
386  clustersToIgnore.push_back(cluster.key());
387  }
388  }
389 
390  return clustersToIgnore;
391 }
392 
393 TVector3
395  art::Ptr<recob::Hit> const& hit1,
396  art::Ptr<recob::Hit> const& hit2) const
397 {
398 
399  // x is average of the two x's
400  double x = (detProp.ConvertTicksToX(hit1->PeakTime(), hit1->WireID().planeID()) +
401  detProp.ConvertTicksToX(hit2->PeakTime(), hit2->WireID().planeID())) /
402  (double)2;
403 
404  // y and z got from the wire interections
405  geo::WireIDIntersection intersection;
406  fGeom->WireIDsIntersect(hit1->WireID(), hit2->WireID(), intersection);
407 
408  return TVector3(x, intersection.y, intersection.z);
409 }
410 
411 std::unique_ptr<recob::Track>
413  std::vector<art::Ptr<recob::Hit>> const& hits1,
414  std::vector<art::Ptr<recob::Hit>> const& hits2,
415  std::map<int, TVector2> const& showerCentreMap) const
416 {
417 
418  std::unique_ptr<recob::Track> track;
419 
420  std::vector<art::Ptr<recob::Hit>> track1, track2;
421 
422  // Check the TPCs
423  if ((*hits1.begin())->WireID().TPC != (*hits2.begin())->WireID().TPC) {
424  mf::LogWarning("EMShowerAlg") << "Warning: attempting to construct a track from two different "
425  "TPCs. Returning a null track.";
426  return track;
427  }
428 
429  // Check for tracks crossing TPC boundaries
430  std::map<int, int> tpcMap;
431  for (auto const& hit : hits1)
432  ++tpcMap[hit->WireID().TPC];
433  for (auto const& hit : hits2)
434  ++tpcMap[hit->WireID().TPC];
435  if (tpcMap.size() > 1) {
436  mf::LogWarning("EMShowerAlg")
437  << "Warning: attempting to construct a track which crosses more than one TPC -- PMTrack "
438  "can't handle this right now. Returning a track made just from hits in the first TPC it "
439  "traverses.";
440  unsigned int firstTPC1 = hits1.at(0)->WireID().TPC, firstTPC2 = hits2.at(0)->WireID().TPC;
441  for (auto const& hit : hits1)
442  if (hit->WireID().TPC == firstTPC1) track1.push_back(hit);
443  for (auto const& hit : hits2)
444  if (hit->WireID().TPC == firstTPC2) track2.push_back(hit);
445  }
446  else {
447  track1 = hits1;
448  track2 = hits2;
449  }
450 
451  if (fDebug > 1) {
452  std::cout << "About to make a track from these hits:\n";
453  auto print_hits = [this](auto const& track) {
454  for (auto const& hit : track | views::transform(to_element)) {
455  std::cout << "Hit (" << HitCoordinates_(hit).X() << ", " << HitCoordinates_(hit).Y()
456  << ") (real wire " << hit.WireID().Wire << ") in TPC " << hit.WireID().TPC
457  << '\n';
458  }
459  };
460  print_hits(track1);
461  print_hits(track2);
462  }
463 
464  TVector3 trackStart = Construct3DPoint_(detProp, track1.at(0), track2.at(0));
465  pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(detProp, track1, track2, trackStart);
466 
467  if (!pmatrack) {
468  mf::LogInfo("EMShowerAlg") << "Skipping this event because not enough hits in two views";
469  return track;
470  }
471 
472  std::vector<TVector3> xyz, dircos;
473 
474  for (unsigned int i = 0; i < pmatrack->size(); i++) {
475 
476  xyz.push_back((*pmatrack)[i]->Point3D());
477 
478  if (i < pmatrack->size() - 1) {
479  size_t j = i + 1;
480  double mag = 0.0;
481  TVector3 dc(0., 0., 0.);
482  while ((mag == 0.0) and (j < pmatrack->size())) {
483  dc = (*pmatrack)[j]->Point3D();
484  dc -= (*pmatrack)[i]->Point3D();
485  mag = dc.Mag();
486  ++j;
487  }
488  if (mag > 0.0)
489  dc *= 1.0 / mag;
490  else if (!dircos.empty())
491  dc = dircos.back();
492  dircos.push_back(dc);
493  }
494  else
495  dircos.push_back(dircos.back());
496  }
497 
498  // Orient the track correctly
499  std::map<int, double> distanceToVertex, distanceToEnd;
500  TVector3 vertex = *xyz.begin(), end = *xyz.rbegin();
501 
502  // Loop over all the planes and find the distance from the vertex and end
503  // projections to the centre in each plane
504  for (std::map<int, TVector2>::const_iterator showerCentreIt = showerCentreMap.begin();
505  showerCentreIt != showerCentreMap.end();
506  ++showerCentreIt) {
507 
508  // Project the vertex and the end point onto this plane
509  TVector2 vertexProj = Project3DPointOntoPlane_(detProp, vertex, showerCentreIt->first);
510  TVector2 endProj = Project3DPointOntoPlane_(detProp, end, showerCentreIt->first);
511 
512  // Find the distance of each to the centre of the cluster
513  distanceToVertex[showerCentreIt->first] = (vertexProj - showerCentreIt->second).Mod();
514  distanceToEnd[showerCentreIt->first] = (endProj - showerCentreIt->second).Mod();
515  }
516 
517  // Find the average distance to the vertex and the end across the planes
518  double avDistanceToVertex = 0, avDistanceToEnd = 0;
519  for (std::map<int, double>::iterator distanceToVertexIt = distanceToVertex.begin();
520  distanceToVertexIt != distanceToVertex.end();
521  ++distanceToVertexIt)
522  avDistanceToVertex += distanceToVertexIt->second;
523  avDistanceToVertex /= distanceToVertex.size();
524 
525  for (std::map<int, double>::iterator distanceToEndIt = distanceToEnd.begin();
526  distanceToEndIt != distanceToEnd.end();
527  ++distanceToEndIt)
528  avDistanceToEnd += distanceToEndIt->second;
529  if (distanceToEnd.size() != 0) avDistanceToEnd /= distanceToEnd.size();
530 
531  if (fDebug > 2)
532  std::cout << "Distance to vertex is " << avDistanceToVertex << " and distance to end is "
533  << avDistanceToEnd << '\n';
534 
535  // Change order if necessary
536  if (avDistanceToEnd > avDistanceToVertex) {
537  std::reverse(xyz.begin(), xyz.end());
538  std::transform(
539  dircos.begin(), dircos.end(), dircos.begin(), [](TVector3 const& vec) { return -1 * vec; });
540  }
541 
542  if (xyz.size() != dircos.size())
543  mf::LogError("EMShowerAlg") << "Problem converting pma::Track3D to recob::Track";
544 
545  track = std::make_unique<recob::Track>(
548  recob::Track::Flags_t(xyz.size()),
549  false),
550  0,
551  -1.,
552  0,
555  -1);
556 
557  return track;
558 }
559 
560 std::unique_ptr<recob::Track>
562  std::vector<art::Ptr<recob::Hit>> const& track1,
563  std::vector<art::Ptr<recob::Hit>> const& track2) const
564 {
565  std::map<int, TVector2> showerCentreMap;
566  return ConstructTrack(detProp, track1, track2, showerCentreMap);
567 }
568 
569 double
571  detinfo::DetectorPropertiesData const& detProp,
572  std::vector<art::Ptr<recob::Hit>> const& trackHits,
573  std::unique_ptr<recob::Track> const& track) const
574 {
575  assert(not empty(trackHits));
576  if (!track) return -999;
577 
578  recob::Hit const& firstHit = *trackHits.front();
579 
580  // Get the pitch
581  double pitch = 0;
582  try {
583  pitch = lar::util::TrackPitchInView(*track, firstHit.View());
584  }
585  catch (...) {
586  }
587 
588  // Deal with large pitches
589  if (pitch > fdEdxTrackLength) {
590  return fCalorimetryAlg.dEdx_AREA(clockData, detProp, firstHit, pitch);
591  }
592 
593  double totalCharge = 0, totalDistance = 0, avHitTime = 0;
594  unsigned int nHits = 0;
595 
596  for (auto const& hit : trackHits | views::transform(to_element)) {
597  if (totalDistance + pitch < fdEdxTrackLength) {
598  totalDistance += pitch;
599  totalCharge += hit.Integral();
600  avHitTime += hit.PeakTime();
601  ++nHits;
602  }
603  }
604 
605  avHitTime /= (double)nHits;
606 
607  double const dQdx = totalCharge / totalDistance;
608  return fCalorimetryAlg.dEdx_AREA(clockData, detProp, dQdx, avHitTime, firstHit.WireID().Plane);
609 }
610 
611 void
613  detinfo::DetectorPropertiesData const& detProp,
614  const std::map<int, std::vector<art::Ptr<recob::Hit>>>& showerHitsMap,
615  std::unique_ptr<recob::Track>& initialTrack,
616  std::map<int, std::vector<art::Ptr<recob::Hit>>>& initialTrackHits,
617  int plane) const
618 {
619 
620  /// Finding the initial track requires three stages:
621  /// -- find the initial track-like hits in each view
622  /// -- use these to construct a track
623 
624  // Now find the hits belonging to the track
625  if (fDebug > 1)
626  std::cout << " ------------------ Finding initial track hits "
627  "-------------------- \n";
628  initialTrackHits = FindShowerStart_(showerHitsMap);
629  if (fDebug > 1) {
630  std::cout << "Here are the initial shower hits... \n";
631  for (auto const& [plane, hitPtrs] : initialTrackHits) {
632  std::cout << " Plane " << plane << '\n';
633  for (auto const& hit : hitPtrs | views::transform(to_element)) {
634  std::cout << " Hit is (" << HitCoordinates_(hit).X() << " (real hit " << hit.WireID()
635  << "), " << HitCoordinates_(hit).Y() << ")\n";
636  }
637  }
638  }
639  if (fDebug > 1)
640  std::cout << " ------------------ End finding initial track hits "
641  "-------------------- \n";
642 
643  // Now we have the track hits -- can make a track!
644  if (fDebug > 1) std::cout << " ------------------ Finding initial track -------------------- \n";
645  initialTrack = MakeInitialTrack_(detProp, initialTrackHits, showerHitsMap);
646  if (initialTrack and fDebug > 1) {
647  std::cout << "The track start is (" << initialTrack->Vertex().X() << ", "
648  << initialTrack->Vertex().Y() << ", " << initialTrack->Vertex().Z() << ")\n";
649  std::cout << "The track direction is (" << initialTrack->VertexDirection().X() << ", "
650  << initialTrack->VertexDirection().Y() << ", " << initialTrack->VertexDirection().Z()
651  << ")\n";
652  }
653  if (fDebug > 1)
654  std::cout << " ------------------ End finding initial track "
655  "-------------------- \n";
656 }
657 
658 std::vector<art::Ptr<recob::Hit>>
660  std::vector<art::Ptr<recob::Hit>> const& hits,
661  bool perpendicular) const
662 {
663  // Find the charge-weighted centre (in [cm]) of this shower
664  TVector2 centre = ShowerCenter_(detProp, hits);
665 
666  // Find a rough shower 'direction'
667  TVector2 direction = ShowerDirection_(detProp, hits);
668 
669  if (perpendicular) direction = direction.Rotate(TMath::Pi() / 2);
670 
671  // Find how far each hit (projected onto this axis) is from the centre
672  TVector2 pos;
673  std::map<double, art::Ptr<recob::Hit>> hitProjection;
674  for (auto const& hitPtr : hits) {
675  pos = HitPosition_(detProp, *hitPtr) - centre;
676  hitProjection[direction * pos] = hitPtr;
677  }
678 
679  // Get a vector of hits in order of the shower
680  std::vector<art::Ptr<recob::Hit>> showerHits;
682  hitProjection, std::back_inserter(showerHits), [](auto const& pr) { return pr.second; });
683 
684  // Make gradient plot
685  if (fMakeGradientPlot) {
686  std::map<int, TGraph*> graphs;
687  for (auto const& hit : showerHits | views::transform(to_element)) {
688  int tpc = hit.WireID().TPC;
689  if (graphs[tpc] == nullptr) graphs[tpc] = new TGraph();
690  graphs[tpc]->SetPoint(
691  graphs[tpc]->GetN(), HitPosition_(detProp, hit).X(), HitPosition_(detProp, hit).Y());
692  }
693  TMultiGraph* multigraph = new TMultiGraph();
694  for (auto const [color, graph] : graphs) {
695  graph->SetMarkerColor(color);
696  graph->SetMarkerStyle(8);
697  graph->SetMarkerSize(2);
698  multigraph->Add(graph);
699  }
700  TCanvas* canvas = new TCanvas();
701  multigraph->Draw("AP");
702  TLine line;
703  line.SetLineColor(2);
704  line.DrawLine(centre.X() - 1000 * direction.X(),
705  centre.Y() - 1000 * direction.Y(),
706  centre.X() + 1000 * direction.X(),
707  centre.Y() + 1000 * direction.Y());
708  canvas->SaveAs("Gradient.png");
709  delete canvas;
710  delete multigraph;
711  }
712 
713  return showerHits;
714 }
715 
716 std::vector<std::vector<int>>
717 shower::EMShowerAlg::FindShowers(std::map<int, std::vector<int>> const& trackToClusters) const
718 {
719  // Showers are vectors of clusters
720  std::vector<std::vector<int>> showers;
721 
722  // Loop over all tracks
723  for (auto const& clusters : trackToClusters | views::values) {
724 
725  // Find which showers already made are associated with this track
726  std::vector<int> matchingShowers;
727  for (unsigned int shower = 0; shower < showers.size(); ++shower)
728  for (int const cluster : clusters) {
729  if (cet::search_all(showers[shower], cluster) and
730  not cet::search_all(matchingShowers, shower)) {
731  matchingShowers.push_back(shower);
732  }
733  }
734 
735  // THINK THERE PROBABLY CAN BE MORE THAN ONE!
736  // IN FACT, THIS WOULD BE A SUCCESS OF THE SHOWERING METHOD!
737  // // Shouldn't be more than one
738  // if (matchingShowers.size() > 1)
739  // mf::LogInfo("EMShowerAlg") << "Number of showers this track matches is " << matchingShowers.size() << std::endl;
740 
741  // New shower
742  if (matchingShowers.size() < 1) showers.push_back(clusters);
743 
744  // Add to existing shower
745  else {
746  for (int const cluster : clusters) {
747  if (not cet::search_all(showers.at(matchingShowers[0]), cluster))
748  showers.at(matchingShowers.at(0)).push_back(cluster);
749  }
750  }
751  }
752 
753  return showers;
754 }
755 
756 std::map<int, std::vector<art::Ptr<recob::Hit>>>
758  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& orderedShowerMap) const
759 {
760 
761  std::map<int, std::vector<art::Ptr<recob::Hit>>> initialHitsMap;
762 
763  for (auto const& [plane, orderedShower] : orderedShowerMap) {
764  std::vector<art::Ptr<recob::Hit>> initialHits;
765 
766  // Find if the shower is traveling along ticks or wires
767  bool wireDirection = true;
768  std::vector<int> wires;
769  for (auto const& hit : orderedShower | views::transform(to_element))
770  wires.push_back(std::round(HitCoordinates_(hit).X()));
771 
772  cet::sort_all(wires);
773  if (std::abs(*wires.begin() - std::round(HitCoordinates_(**orderedShower.begin()).X())) > 3 and
774  std::abs(*wires.rbegin() - std::round(HitCoordinates_(**orderedShower.begin()).X())) > 3)
775  wireDirection = false;
776 
777  // Deal with showers traveling along wires
778  if (wireDirection) {
779  bool increasing = HitCoordinates_(**orderedShower.rbegin()).X() >
780  HitCoordinates_(**orderedShower.begin()).X();
781  std::map<int, std::vector<art::Ptr<recob::Hit>>> wireHitMap;
782  int multipleWires = 0;
783  for (auto const& hitPtr : orderedShower)
784  wireHitMap[std::round(HitCoordinates_(*hitPtr).X())].push_back(hitPtr);
785 
786  for (auto const& hitPtr : orderedShower) {
787  int wire = std::round(HitCoordinates_(*hitPtr).X());
788  if (wireHitMap[wire].size() > 1) {
789  ++multipleWires;
790  if (multipleWires > 5) break;
791  continue;
792  }
793  else if ((increasing and wireHitMap[wire + 1].size() > 1 and
794  (wireHitMap[wire + 2].size() > 1 or wireHitMap[wire + 3].size() > 1)) or
795  (!increasing and wireHitMap[wire - 1].size() > 1 and
796  (wireHitMap[wire - 2].size() > 1 or wireHitMap[wire - 3].size() > 1))) {
797  if ((increasing and
798  (wireHitMap[wire + 4].size() < 2 and wireHitMap[wire + 5].size() < 2 and
799  wireHitMap[wire + 6].size() < 2 and wireHitMap[wire + 9].size() > 1)) or
800  (!increasing and
801  (wireHitMap[wire - 4].size() < 2 and wireHitMap[wire - 5].size() < 2 and
802  wireHitMap[wire - 6].size() < 2) and
803  wireHitMap[wire - 9].size() > 1))
804  initialHits.push_back(hitPtr);
805  else
806  break;
807  }
808  else
809  initialHits.push_back(hitPtr);
810  }
811  if (!initialHits.size()) initialHits.push_back(*orderedShower.begin());
812  }
813 
814  // Deal with showers travelling along ticks
815  else {
816  bool increasing = HitCoordinates_(**orderedShower.rbegin()).Y() >
817  HitCoordinates_(**orderedShower.begin()).Y();
818  std::map<int, std::vector<art::Ptr<recob::Hit>>> tickHitMap;
819  for (std::vector<art::Ptr<recob::Hit>>::const_iterator hitIt = orderedShower.begin();
820  hitIt != orderedShower.end();
821  ++hitIt)
822  tickHitMap[std::round(HitCoordinates_(**hitIt).Y())].push_back(*hitIt);
823 
824  for (auto const& hitPtr : orderedShower) {
825  int const tick = std::round(HitCoordinates_(*hitPtr).Y());
826  if ((increasing and (tickHitMap[tick + 1].size() or tickHitMap[tick + 2].size() or
827  tickHitMap[tick + 3].size() or tickHitMap[tick + 4].size() or
828  tickHitMap[tick + 5].size())) or
829  (!increasing and (tickHitMap[tick - 1].size() or tickHitMap[tick - 2].size() or
830  tickHitMap[tick - 3].size() or tickHitMap[tick - 4].size() or
831  tickHitMap[tick - 5].size())))
832  break;
833  else
834  initialHits.push_back(hitPtr);
835  }
836  if (initialHits.empty()) initialHits.push_back(*orderedShower.begin());
837  }
838 
839  // Need at least two hits to make a track
840  if (initialHits.size() == 1 and orderedShower.size() > 2)
841  initialHits.push_back(orderedShower[1]);
842 
843  // Quality check -- make sure there isn't a single hit in a different TPC (artefact of tracking failure)
844  std::vector<art::Ptr<recob::Hit>> newInitialHits;
845  std::map<int, int> tpcHitMap;
846  std::vector<int> singleHitTPCs;
847  for (auto const& hit : initialHits | views::transform(to_element))
848  ++tpcHitMap[hit.WireID().TPC];
849 
850  for (auto const [tpc, count] : tpcHitMap)
851  if (count == 1) singleHitTPCs.push_back(tpc);
852 
853  if (singleHitTPCs.size()) {
854  if (fDebug > 2)
855  for (int const tpc : singleHitTPCs)
856  std::cout << "Removed hits in TPC " << tpc << '\n';
857 
858  for (auto const& hitPtr : initialHits)
859  if (not cet::search_all(singleHitTPCs, hitPtr->WireID().TPC))
860  newInitialHits.push_back(hitPtr);
861  if (!newInitialHits.size()) newInitialHits.push_back(*orderedShower.begin());
862  }
863  else
864  newInitialHits = initialHits;
865 
866  initialHitsMap[plane] = newInitialHits;
867  }
868 
869  return initialHitsMap;
870 }
871 
872 std::map<int, std::map<int, bool>>
874  const detinfo::DetectorPropertiesData& detProp,
875  const std::map<int, std::vector<art::Ptr<recob::Hit>>>& showerHitsMap) const
876 {
877 
878  // The map to return
879  std::map<int, std::map<int, bool>> permutations;
880 
881  // Get the properties of the shower hits across the planes which will be used to
882  // determine the likelihood of a particular reorientation permutation
883  // -- relative width in the wire direction (if showers travel along the wire
884  // direction in a particular plane)
885  // -- the RMS gradients (how likely it is the RMS of the hit positions from
886  // central axis increases along a particular orientation)
887 
888  // Find the RMS, RMS gradient and wire widths
889  std::map<int, double> planeRMSGradients, planeRMS;
890  for (auto const& [plane, hitPtrs] : showerHitsMap) {
891  planeRMS[plane] = ShowerHitRMS_(detProp, hitPtrs);
892  planeRMSGradients[plane] = ShowerHitRMSGradient_(detProp, hitPtrs);
893  }
894 
895  // Order these backwards so they can be used to discriminate between planes
896  std::map<double, int> gradientMap;
897  for (int const plane : showerHitsMap | views::keys)
898  gradientMap[std::abs(planeRMSGradients.at(plane))] = plane;
899 
900  std::map<double, int> wireWidthMap = RelativeWireWidth_(showerHitsMap);
901 
902  if (fDebug > 1)
903  for (auto const [gradient, plane] : wireWidthMap)
904  std::cout << "Plane " << plane << " has relative width in wire of " << gradient
905  << "; and an RMS gradient of " << planeRMSGradients[plane] << '\n';
906 
907  // Find the correct permutations
908  int perm = 0;
909  std::vector<std::map<int, bool>> usedPermutations;
910 
911  // Most likely is to not change anything
912  for (int const plane : showerHitsMap | views::keys)
913  permutations[perm][plane] = 0;
914  ++perm;
915 
916  // Use properties of the shower to determine the middle cases
917  for (int const plane : wireWidthMap | views::values) {
918  std::map<int, bool> permutation;
919  permutation[plane] = true;
920  for (int const plane2 : wireWidthMap | views::values)
921  if (plane != plane2) permutation[plane2] = false;
922 
923  if (not cet::search_all(usedPermutations, permutation)) {
924  permutations[perm] = permutation;
925  usedPermutations.push_back(permutation);
926  ++perm;
927  }
928  }
929  for (int const plane : wireWidthMap | views::reverse | views::values) {
930  std::map<int, bool> permutation;
931  permutation[plane] = false;
932  for (int const plane2 : wireWidthMap | views::values)
933  if (plane != plane2) permutation[plane2] = true;
934 
935  if (not cet::search_all(usedPermutations, permutation)) {
936  permutations[perm] = permutation;
937  usedPermutations.push_back(permutation);
938  ++perm;
939  }
940  }
941 
942  // Least likely is to change everything
943  for (int const plane : showerHitsMap | views::keys)
944  permutations[perm][plane] = 1;
945  ++perm;
946 
947  if (fDebug > 1) {
948  std::cout << "Here are the permutations!\n";
949  for (auto const& [index, permutation] : permutations) {
950  std::cout << "Permutation " << index << '\n';
951  for (auto const [plane, value] : permutation)
952  std::cout << " Plane " << plane << " has value " << value << '\n';
953  }
954  }
955 
956  return permutations;
957 }
958 
959 std::unique_ptr<recob::Track>
961  detinfo::DetectorPropertiesData const& detProp,
962  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& initialHitsMap,
963  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& showerHitsMap) const
964 {
965  // Can't do much with just one view
966  if (initialHitsMap.size() < 2) {
967  mf::LogInfo("EMShowerAlg") << "Only one useful view for this shower; nothing can be done\n";
968  return std::unique_ptr<recob::Track>();
969  }
970 
971  std::vector<std::pair<int, int>> initialHitsSize;
972  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::const_iterator initialHitIt =
973  initialHitsMap.begin();
974  initialHitIt != initialHitsMap.end();
975  ++initialHitIt)
976  initialHitsSize.push_back(std::make_pair(initialHitIt->first, initialHitIt->second.size()));
977 
978  // Sort the planes by number of hits
979  std::sort(initialHitsSize.begin(),
980  initialHitsSize.end(),
981  [](std::pair<int, int> const& size1, std::pair<int, int> const& size2) {
982  return size1.second > size2.second;
983  });
984 
985  // Pick the two planes to use to make the track
986  // -- if more than two planes, can choose the two views
987  // more accurately
988  // -- if not, just use the two views available
989 
990  std::vector<int> planes;
991 
992  if (initialHitsSize.size() > 2 and !CheckShowerHits_(detProp, showerHitsMap)) {
993  int planeToIgnore = WorstPlane_(showerHitsMap);
994  if (fDebug > 1)
995  std::cout << "Igoring plane " << planeToIgnore << " in creation of initial track\n";
996  for (std::vector<std::pair<int, int>>::iterator hitsSizeIt = initialHitsSize.begin();
997  hitsSizeIt != initialHitsSize.end() and planes.size() < 2;
998  ++hitsSizeIt) {
999  if (hitsSizeIt->first == planeToIgnore) continue;
1000  planes.push_back(hitsSizeIt->first);
1001  }
1002  }
1003  else
1004  planes = {initialHitsSize.at(0).first, initialHitsSize.at(1).first};
1005 
1006  return ConstructTrack(detProp, initialHitsMap.at(planes.at(0)), initialHitsMap.at(planes.at(1)));
1007 }
1008 
1011  detinfo::DetectorClocksData const& clockData,
1012  detinfo::DetectorPropertiesData const& detProp,
1013  art::PtrVector<recob::Hit> const& hits,
1014  std::unique_ptr<recob::Track> const& initialTrack,
1015  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& initialHitsMap) const
1016 {
1017 
1018  // Find the shower hits on each plane
1019  std::map<int, std::vector<art::Ptr<recob::Hit>>> planeHitsMap;
1020  for (auto const& hitPtr : hits)
1021  planeHitsMap[hitPtr->View()].push_back(hitPtr);
1022 
1023  int bestPlane = -1;
1024  unsigned int highestNumberOfHits = 0;
1025  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
1026 
1027  // Look at each of the planes
1028  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
1029 
1030  // If there's hits on this plane...
1031  if (planeHitsMap.count(plane)) {
1032  dEdx.push_back(FinddEdx_(clockData, detProp, initialHitsMap.at(plane), initialTrack));
1033  totalEnergy.push_back(
1034  fShowerEnergyAlg.ShowerEnergy(clockData, detProp, planeHitsMap.at(plane), plane));
1035  if (planeHitsMap.at(plane).size() > highestNumberOfHits and initialHitsMap.count(plane)) {
1036  bestPlane = plane;
1037  highestNumberOfHits = planeHitsMap.at(plane).size();
1038  }
1039  }
1040 
1041  // If not...
1042  else {
1043  dEdx.push_back(0);
1044  totalEnergy.push_back(0);
1045  }
1046  }
1047 
1048  TVector3 direction, directionError, showerStart, showerStartError;
1049  if (initialTrack) {
1050  direction = initialTrack->VertexDirection<TVector3>();
1051  showerStart = initialTrack->Vertex<TVector3>();
1052  }
1053 
1054  if (fDebug > 0) {
1055  std::cout << "Best plane is " << bestPlane;
1056  std::cout << "\ndE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and " << dEdx[2];
1057  std::cout << "\nTotal energy for each plane is: " << totalEnergy[0] << ", " << totalEnergy[1]
1058  << " and " << totalEnergy[2];
1059  std::cout << "\nThe shower start is (" << showerStart.X() << ", " << showerStart.Y() << ", "
1060  << showerStart.Z() << ")\n";
1061  std::cout << "The shower direction is (" << direction.X() << ", " << direction.Y() << ", "
1062  << direction.Z() << ")\n";
1063  }
1064 
1065  return recob::Shower(direction,
1066  directionError,
1067  showerStart,
1068  showerStartError,
1069  totalEnergy,
1070  totalEnergyError,
1071  dEdx,
1072  dEdxError,
1073  bestPlane);
1074 }
1075 
1078  detinfo::DetectorPropertiesData const& detProp,
1079  art::PtrVector<recob::Hit> const& hits,
1081  int& iok) const
1082 {
1083  iok = 1;
1084 
1085  // Find the shower hits on each plane
1086  std::map<int, std::vector<art::Ptr<recob::Hit>>> planeHitsMap;
1087  for (auto const& hitPtr : hits)
1088  planeHitsMap[hitPtr->WireID().Plane].push_back(hitPtr);
1089 
1090  std::vector<std::vector<art::Ptr<recob::Hit>>> initialTrackHits(3);
1091 
1092  int pl0 = -1;
1093  int pl1 = -1;
1094  unsigned maxhits0 = 0;
1095  unsigned maxhits1 = 0;
1096 
1097  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::iterator planeHits = planeHitsMap.begin();
1098  planeHits != planeHitsMap.end();
1099  ++planeHits) {
1100 
1101  std::vector<art::Ptr<recob::Hit>> showerHits;
1102  OrderShowerHits_(detProp, planeHits->second, showerHits, vertex);
1103  FindInitialTrackHits(showerHits, vertex, initialTrackHits[planeHits->first]);
1104  if ((planeHits->second).size() > maxhits0) {
1105  if (pl0 != -1) {
1106  maxhits1 = maxhits0;
1107  pl1 = pl0;
1108  }
1109  pl0 = planeHits->first;
1110  maxhits0 = (planeHits->second).size();
1111  }
1112  else if ((planeHits->second).size() > maxhits1) {
1113  pl1 = planeHits->first;
1114  maxhits1 = (planeHits->second).size();
1115  }
1116  }
1117  if (pl0 != -1 && pl1 != -1 && initialTrackHits[pl0].size() >= 2 &&
1118  initialTrackHits[pl1].size() >= 2 &&
1119  initialTrackHits[pl0][0]->WireID().TPC == initialTrackHits[pl1][0]->WireID().TPC) {
1120  double xyz[3];
1121  vertex->XYZ(xyz);
1122  TVector3 vtx(xyz);
1123  pma::Track3D* pmatrack =
1124  fProjectionMatchingAlg.buildSegment(detProp, initialTrackHits[pl0], initialTrackHits[pl1]);
1125  std::vector<TVector3> spts;
1126 
1127  for (size_t i = 0; i < pmatrack->size(); ++i) {
1128  if ((*pmatrack)[i]->IsEnabled()) {
1129  TVector3 p3d = (*pmatrack)[i]->Point3D();
1130  spts.push_back(p3d);
1131  }
1132  }
1133  if (spts.size() >= 2) { // at least two space points
1134  TVector3 shwxyz, shwxyzerr;
1135  TVector3 shwdir, shwdirerr;
1136  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
1137  int bestPlane = pl0;
1138  double minpitch = 1000;
1139  std::vector<TVector3> dirs;
1140  if ((spts[0] - vtx).Mag() < (spts.back() - vtx).Mag()) {
1141  shwxyz = spts[0];
1142  size_t i = 5;
1143  if (spts.size() - 1 < 5) i = spts.size() - 1;
1144  shwdir = spts[i] - spts[0];
1145  shwdir = shwdir.Unit();
1146  }
1147  else {
1148  shwxyz = spts.back();
1149  size_t i = 0;
1150  if (spts.size() > 6) i = spts.size() - 6;
1151  shwdir = spts[i] - spts[spts.size() - 1];
1152  shwdir = shwdir.Unit();
1153  }
1154  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
1155  if (planeHitsMap.find(plane) != planeHitsMap.end()) {
1156  totalEnergy.push_back(
1157  fShowerEnergyAlg.ShowerEnergy(clockData, detProp, planeHitsMap[plane], plane));
1158  }
1159  else {
1160  totalEnergy.push_back(0);
1161  }
1162  if (initialTrackHits[plane].size()) {
1163  double fdEdx = 0;
1164  double totQ = 0;
1165  double avgT = 0;
1166  double pitch = 0;
1167  double wirepitch = fGeom->WirePitch(initialTrackHits[plane][0]->WireID().planeID());
1168  double angleToVert =
1170  initialTrackHits[plane][0]->WireID().planeID()) -
1171  0.5 * TMath::Pi();
1172  double cosgamma = std::abs(sin(angleToVert) * shwdir.Y() + cos(angleToVert) * shwdir.Z());
1173  if (cosgamma > 0) pitch = wirepitch / cosgamma;
1174  if (pitch) {
1175  if (pitch < minpitch) {
1176  minpitch = pitch;
1177  bestPlane = plane;
1178  }
1179  int nhits = 0;
1180  std::vector<float> vQ;
1181  for (auto const& hit : initialTrackHits[plane]) {
1182  int w1 = hit->WireID().Wire;
1183  int w0 = initialTrackHits[plane][0]->WireID().Wire;
1184  if (std::abs((w1 - w0) * pitch) < fdEdxTrackLength) {
1185  vQ.push_back(hit->Integral());
1186  totQ += hit->Integral();
1187  avgT += hit->PeakTime();
1188  ++nhits;
1189  }
1190  }
1191  if (totQ) {
1192  double dQdx = TMath::Median(vQ.size(), &vQ[0]) / pitch;
1193  fdEdx = fCalorimetryAlg.dEdx_AREA(
1194  clockData, detProp, dQdx, avgT / nhits, initialTrackHits[plane][0]->WireID().Plane);
1195  }
1196  }
1197  dEdx.push_back(fdEdx);
1198  }
1199  else {
1200  dEdx.push_back(0);
1201  }
1202  }
1203  iok = 0;
1204  if (fDebug > 1) {
1205  std::cout << "Best plane is " << bestPlane;
1206  std::cout << "\ndE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and "
1207  << dEdx[2];
1208  std::cout << "\nTotal energy for each plane is: " << totalEnergy[0] << ", "
1209  << totalEnergy[1] << " and " << totalEnergy[2];
1210  std::cout << "\nThe shower start is (" << shwxyz.X() << ", " << shwxyz.Y() << ", "
1211  << shwxyz.Z() << ")\n";
1212  shwxyz.Print();
1213  }
1214 
1215  return recob::Shower(shwdir,
1216  shwdirerr,
1217  shwxyz,
1218  shwxyzerr,
1219  totalEnergy,
1220  totalEnergyError,
1221  dEdx,
1222  dEdxError,
1223  bestPlane);
1224  }
1225  }
1226  return recob::Shower();
1227 }
1228 
1229 std::vector<recob::SpacePoint>
1231  detinfo::DetectorPropertiesData const& detProp,
1232  std::map<int, std::vector<art::Ptr<recob::Hit>>> const& showerHits,
1233  std::vector<std::vector<art::Ptr<recob::Hit>>>& hitAssns) const
1234 {
1235  // Space points to return
1236  std::vector<recob::SpacePoint> spacePoints;
1237 
1238  // Make space points
1239  // Use the following procedure:
1240  // -- Consider hits plane by plane
1241  // -- For each hit on the first plane, consider the 3D point made by combining with each hit from the second plane
1242  // -- Project this 3D point back into the two planes
1243  // -- Determine how close to a the original hits this point lies
1244  // -- If close enough, make a 3D space point from this point
1245  // -- Discard these used hits in future iterations, along with hits in the
1246  // third plane (if exists) close to the projection of the point into this
1247  // plane
1248 
1249  // Container to hold used hits
1250  std::vector<int> usedHits;
1251 
1252  // Look through plane by plane
1253  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::const_iterator showerHitIt =
1254  showerHits.begin();
1255  showerHitIt != showerHits.end();
1256  ++showerHitIt) {
1257 
1258  // Find the other planes with hits
1259  std::vector<int> otherPlanes;
1260  for (unsigned int otherPlane = 0; otherPlane < fGeom->MaxPlanes(); ++otherPlane)
1261  if ((int)otherPlane != showerHitIt->first and showerHits.count(otherPlane))
1262  otherPlanes.push_back(otherPlane);
1263 
1264  // Can't make space points if we only have one view
1265  if (otherPlanes.size() == 0) return spacePoints;
1266 
1267  // Look at all hits on this plane
1268  for (std::vector<art::Ptr<recob::Hit>>::const_iterator planeHitIt = showerHitIt->second.begin();
1269  planeHitIt != showerHitIt->second.end();
1270  ++planeHitIt) {
1271 
1272  if (std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) != usedHits.end())
1273  continue;
1274 
1275  // Make a 3D point with every hit on the second plane
1276  const std::vector<art::Ptr<recob::Hit>> otherPlaneHits = showerHits.at(otherPlanes.at(0));
1277  for (std::vector<art::Ptr<recob::Hit>>::const_iterator otherPlaneHitIt =
1278  otherPlaneHits.begin();
1279  otherPlaneHitIt != otherPlaneHits.end() and
1280  std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) == usedHits.end();
1281  ++otherPlaneHitIt) {
1282 
1283  if ((*otherPlaneHitIt)->WireID().TPC != (*planeHitIt)->WireID().TPC or
1284  std::find(usedHits.begin(), usedHits.end(), otherPlaneHitIt->key()) != usedHits.end())
1285  continue;
1286 
1287  TVector3 point = Construct3DPoint_(detProp, *planeHitIt, *otherPlaneHitIt);
1288  std::vector<art::Ptr<recob::Hit>> pointHits;
1289  bool truePoint = false;
1290 
1291  if (otherPlanes.size() > 1) {
1292 
1293  TVector2 projThirdPlane = Project3DPointOntoPlane_(detProp, point, otherPlanes.at(1));
1294  const std::vector<art::Ptr<recob::Hit>> otherOtherPlaneHits =
1295  showerHits.at(otherPlanes.at(1));
1296 
1297  for (std::vector<art::Ptr<recob::Hit>>::const_iterator otherOtherPlaneHitIt =
1298  otherOtherPlaneHits.begin();
1299  otherOtherPlaneHitIt != otherOtherPlaneHits.end() and !truePoint;
1300  ++otherOtherPlaneHitIt) {
1301 
1302  if ((*otherOtherPlaneHitIt)->WireID().TPC == (*planeHitIt)->WireID().TPC and
1303  (projThirdPlane - HitPosition_(detProp, **otherOtherPlaneHitIt)).Mod() <
1304  fSpacePointSize) {
1305 
1306  truePoint = true;
1307 
1308  // Remove hits used to make the point
1309  usedHits.push_back(planeHitIt->key());
1310  usedHits.push_back(otherPlaneHitIt->key());
1311  usedHits.push_back(otherOtherPlaneHitIt->key());
1312 
1313  pointHits.push_back(*planeHitIt);
1314  pointHits.push_back(*otherPlaneHitIt);
1315  pointHits.push_back(*otherOtherPlaneHitIt);
1316  }
1317  }
1318  }
1319 
1320  else if ((Project3DPointOntoPlane_(detProp, point, (*planeHitIt)->WireID().Plane) -
1321  HitPosition_(detProp, **planeHitIt))
1322  .Mod() < fSpacePointSize and
1323  (Project3DPointOntoPlane_(detProp, point, (*otherPlaneHitIt)->WireID().Plane) -
1324  HitPosition_(detProp, **otherPlaneHitIt))
1325  .Mod() < fSpacePointSize) {
1326 
1327  truePoint = true;
1328 
1329  usedHits.push_back(planeHitIt->key());
1330  usedHits.push_back(otherPlaneHitIt->key());
1331 
1332  pointHits.push_back(*planeHitIt);
1333  pointHits.push_back(*otherPlaneHitIt);
1334  }
1335 
1336  // Make space point
1337  if (truePoint) {
1338  double xyz[3] = {point.X(), point.Y(), point.Z()};
1339  double xyzerr[6] = {fSpacePointSize,
1344  fSpacePointSize};
1345  double chisq = 0.;
1346  spacePoints.emplace_back(xyz, xyzerr, chisq);
1347  hitAssns.push_back(pointHits);
1348  }
1349 
1350  } // end loop over second plane hits
1351 
1352  } // end loop over first plane hits
1353 
1354  } // end loop over planes
1355 
1356  if (fDebug > 0) {
1357  std::cout << "-------------------- Space points -------------------\n";
1358  std::cout << "There are " << spacePoints.size() << " space points:\n";
1359  if (fDebug > 1)
1360  for (std::vector<recob::SpacePoint>::const_iterator spacePointIt = spacePoints.begin();
1361  spacePointIt != spacePoints.end();
1362  ++spacePointIt) {
1363  const double* xyz = spacePointIt->XYZ();
1364  std::cout << " Space point (" << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << ")\n";
1365  }
1366  }
1367 
1368  return spacePoints;
1369 }
1370 
1371 std::map<int, std::vector<art::Ptr<recob::Hit>>>
1374  int desired_plane) const
1375 {
1376  /// Ordering the shower hits requires three stages:
1377  /// -- putting all the hits in a given plane in some kind of order
1378  /// -- use the properties of the hits in all three planes to check this order
1379  /// -- orient the hits correctly using properties of the shower
1380 
1381  // ------------- Put hits in order ------------
1382 
1383  // Find the shower hits on each plane
1384  std::map<int, std::vector<art::Ptr<recob::Hit>>> showerHitsMap;
1385  for (auto const& hitPtr : shower) {
1386  showerHitsMap[hitPtr->WireID().Plane].push_back(hitPtr);
1387  }
1388 
1389  // Order the hits, get the RMS and the RMS gradient for the hits in this plane
1390  std::map<int, double> planeRMSGradients, planeRMS;
1391  for (auto const& [plane, hits] : showerHitsMap) {
1392  if (desired_plane != plane and desired_plane != -1) continue;
1393  std::vector<art::Ptr<recob::Hit>> orderedHits = FindOrderOfHits_(detProp, hits);
1394  planeRMS[plane] = ShowerHitRMS_(detProp, orderedHits);
1395  planeRMSGradients[plane] = ShowerHitRMSGradient_(detProp, orderedHits);
1396  showerHitsMap[plane] = orderedHits;
1397  }
1398 
1399  if (fDebug > 1) {
1400  for (auto const [plane, shower_hit_rms] : planeRMS) {
1401  std::cout << "Plane " << plane << " has RMS " << shower_hit_rms << " and RMS gradient "
1402  << planeRMSGradients.at(plane) << '\n';
1403  }
1404  }
1405 
1406  if (fDebug > 2) {
1407  std::cout << "\nHits in order; after ordering, before reversing...\n";
1408  for (auto const& [plane, hitPtrs] : showerHitsMap) {
1409  std::cout << " Plane " << plane << '\n';
1410  for (auto const& hit : hitPtrs | views::transform(to_element)) {
1411  std::cout << " Hit at (" << HitCoordinates_(hit).X() << ", " << HitCoordinates_(hit).Y()
1412  << ") -- real wire " << hit.WireID() << ", hit position ("
1413  << HitPosition_(detProp, hit).X() << ", " << HitPosition_(detProp, hit).Y()
1414  << ")\n";
1415  }
1416  }
1417  }
1418 
1419  // ------------- Check between the views to ensure consistency of ordering -------------
1420 
1421  // Check between the views to make sure there isn't a poorly formed shower in just one view
1422  // First, determine the average RMS and RMS gradient across the other planes
1423  std::map<int, double> planeOtherRMS, planeOtherRMSGradients;
1424  for (std::map<int, double>::iterator planeRMSIt = planeRMS.begin(); planeRMSIt != planeRMS.end();
1425  ++planeRMSIt) {
1426  planeOtherRMS[planeRMSIt->first] = 0;
1427  planeOtherRMSGradients[planeRMSIt->first] = 0;
1428  int nOtherPlanes = 0;
1429  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane) {
1430  if (plane != planeRMSIt->first and planeRMS.count(plane)) {
1431  planeOtherRMS[planeRMSIt->first] += planeRMS.at(plane);
1432  planeOtherRMSGradients[planeRMSIt->first] += planeRMSGradients.at(plane);
1433  ++nOtherPlanes;
1434  }
1435  }
1436  planeOtherRMS[planeRMSIt->first] /= (double)nOtherPlanes;
1437  planeOtherRMSGradients[planeRMSIt->first] /= (double)nOtherPlanes;
1438  }
1439 
1440  // Look to see if one plane has a particularly high RMS (compared to the
1441  // others) whilst having a similar gradient
1442  for (auto const& [plane, hitPtrs] : showerHitsMap) {
1443  if (planeRMS.at(plane) > planeOtherRMS.at(plane) * 2) {
1444  if (fDebug > 1) std::cout << "Plane " << plane << " was perpendicular... recalculating\n";
1445  std::vector<art::Ptr<recob::Hit>> orderedHits =
1446  this->FindOrderOfHits_(detProp, hitPtrs, true);
1447  showerHitsMap[plane] = orderedHits;
1448  planeRMSGradients[plane] = this->ShowerHitRMSGradient_(detProp, orderedHits);
1449  }
1450  }
1451 
1452  // ------------- Orient the shower correctly ---------------
1453 
1454  if (fDebug > 1) {
1455  std::cout << "Before reversing, here are the start and end points...\n";
1456  for (auto const& [plane, hitPtrs] : showerHitsMap) {
1457  std::cout << " Plane " << plane << " has start (" << HitCoordinates_(*hitPtrs.front()).X()
1458  << ", " << HitCoordinates_(*hitPtrs.front()).Y() << ") (real wire "
1459  << hitPtrs.front()->WireID() << ") and end ("
1460  << HitCoordinates_(*hitPtrs.back()).X() << ", "
1461  << HitCoordinates_(*hitPtrs.back()).Y() << ") (real wire "
1462  << hitPtrs.back()->WireID() << ")\n";
1463  }
1464  }
1465 
1466  // Use the RMS gradient information to get an initial ordering
1467  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::iterator showerHitsIt =
1468  showerHitsMap.begin();
1469  showerHitsIt != showerHitsMap.end();
1470  ++showerHitsIt) {
1471  double gradient = planeRMSGradients.at(showerHitsIt->first);
1472  if (gradient < 0) std::reverse(showerHitsIt->second.begin(), showerHitsIt->second.end());
1473  }
1474 
1475  if (fDebug > 2) {
1476  std::cout << "\nHits in order; after reversing, before checking isolated hits...\n";
1477  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::iterator showerHitsIt =
1478  showerHitsMap.begin();
1479  showerHitsIt != showerHitsMap.end();
1480  ++showerHitsIt) {
1481  std::cout << " Plane " << showerHitsIt->first << '\n';
1482  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt = showerHitsIt->second.begin();
1483  hitIt != showerHitsIt->second.end();
1484  ++hitIt)
1485  std::cout << " Hit at (" << HitCoordinates_(**hitIt).X() << ", "
1486  << HitCoordinates_(**hitIt).Y() << ") -- real wire " << (*hitIt)->WireID()
1487  << ", hit position (" << HitPosition_(detProp, **hitIt).X() << ", "
1488  << HitPosition_(detProp, **hitIt).Y() << ")\n";
1489  }
1490  }
1491 
1492  CheckIsolatedHits_(showerHitsMap);
1493 
1494  if (fDebug > 2) {
1495  std::cout << "\nHits in order; after checking isolated hits...\n";
1496  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::iterator showerHitsIt =
1497  showerHitsMap.begin();
1498  showerHitsIt != showerHitsMap.end();
1499  ++showerHitsIt) {
1500  std::cout << " Plane " << showerHitsIt->first << '\n';
1501  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt = showerHitsIt->second.begin();
1502  hitIt != showerHitsIt->second.end();
1503  ++hitIt)
1504  std::cout << " Hit at (" << HitCoordinates_(**hitIt).X() << ", "
1505  << HitCoordinates_(**hitIt).Y() << ") -- real wire " << (*hitIt)->WireID()
1506  << ", hit position (" << HitPosition_(detProp, **hitIt).X() << ", "
1507  << HitPosition_(detProp, **hitIt).Y() << ")\n";
1508  }
1509  }
1510 
1511  if (fDebug > 1) {
1512  std::cout << "After reversing and checking isolated hits, here are the "
1513  "start and end points...\n";
1514  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::iterator showerHitsIt =
1515  showerHitsMap.begin();
1516  showerHitsIt != showerHitsMap.end();
1517  ++showerHitsIt)
1518  std::cout << " Plane " << showerHitsIt->first << " has start ("
1519  << HitCoordinates_(*showerHitsIt->second.front()).X() << ", "
1520  << HitCoordinates_(*showerHitsIt->second.front()).Y() << ") (real wire "
1521  << showerHitsIt->second.front()->WireID() << ") and end ("
1522  << HitCoordinates_(*showerHitsIt->second.back()).X() << ", "
1523  << HitCoordinates_(*showerHitsIt->second.back()).Y() << ")\n";
1524  }
1525 
1526  // Check for views in which the shower travels almost along the wire planes
1527  // (shown by a small relative wire width)
1528  std::map<double, int> wireWidths = RelativeWireWidth_(showerHitsMap);
1529  std::vector<int> badPlanes;
1530  if (fDebug > 1) std::cout << "Here are the relative wire widths... \n";
1531  for (auto const [relative_wire_width, plane] : wireWidths) {
1532  if (fDebug > 1)
1533  std::cout << "Plane " << plane << " has relative wire width " << relative_wire_width << '\n';
1534  if (relative_wire_width < 1 / (double)wireWidths.size()) badPlanes.push_back(plane);
1535  }
1536 
1537  std::map<int, std::vector<art::Ptr<recob::Hit>>> ignoredPlanes;
1538  if (badPlanes.size() == 1) {
1539  int const badPlane = badPlanes[0];
1540  if (fDebug > 1) std::cout << "Ignoring plane " << badPlane << " when orientating\n";
1541  ignoredPlanes[badPlane] = showerHitsMap.at(badPlane);
1542  showerHitsMap.erase(badPlane);
1543  }
1544 
1545  // Consider all possible permutations of planes (0/1, oriented
1546  // correctly/incorrectly)
1547  std::map<int, std::map<int, bool>> permutations = GetPlanePermutations_(detProp, showerHitsMap);
1548 
1549  // Go through all permutations until we have a satisfactory orientation
1550  auto const originalShowerHitsMap = showerHitsMap;
1551 
1552  int n = 0;
1553  while (!CheckShowerHits_(detProp, showerHitsMap) and
1554  n < TMath::Power(2, (int)showerHitsMap.size())) {
1555  if (fDebug > 1) std::cout << "Permutation " << n << '\n';
1556  for (int const plane : showerHitsMap | views::keys) {
1557  auto hits = originalShowerHitsMap.at(plane);
1558  if (permutations[n][plane] == 1) { std::reverse(hits.begin(), hits.end()); }
1559  showerHitsMap[plane] = hits;
1560  }
1561  ++n;
1562  }
1563 
1564  // Go back to original if still no consistency
1565  if (!CheckShowerHits_(detProp, showerHitsMap)) showerHitsMap = originalShowerHitsMap;
1566 
1567  if (fDebug > 2) {
1568  std::cout << "End of OrderShowerHits: here are the order of hits:\n";
1569  for (auto const& [plane, hitPtrs] : showerHitsMap) {
1570  std::cout << " Plane " << plane << '\n';
1571  for (auto const& hit : hitPtrs | views::transform(to_element)) {
1572  std::cout << " Hit (" << HitCoordinates_(hit).X() << " (real wire " << hit.WireID()
1573  << "), " << HitCoordinates_(hit).Y() << ") -- pos ("
1574  << HitPosition_(detProp, hit).X() << ", " << HitPosition_(detProp, hit).Y()
1575  << ")\n";
1576  }
1577  }
1578  }
1579 
1580  if (ignoredPlanes.size())
1581  showerHitsMap[ignoredPlanes.begin()->first] = ignoredPlanes.begin()->second;
1582 
1583  return showerHitsMap;
1584 }
1585 
1586 void
1589  std::vector<art::Ptr<recob::Hit>>& showerHits,
1590  art::Ptr<recob::Vertex> const& vertex) const
1591 {
1592 
1593  showerHits = FindOrderOfHits_(detProp, shower);
1594 
1595  // Find TPC for the vertex
1596  double xyz[3];
1597  vertex->XYZ(xyz);
1598  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1599  if (!tpc.isValid && showerHits.size()) tpc = geo::TPCID(showerHits[0]->WireID());
1600 
1601  // Find hits in the same TPC
1602  art::Ptr<recob::Hit> hit0, hit1;
1603  for (auto& hit : showerHits) {
1604  if (hit->WireID().TPC == tpc.TPC) {
1605  if (hit0.isNull()) { hit0 = hit; }
1606  hit1 = hit;
1607  }
1608  }
1609  if (hit0.isNull() || hit1.isNull()) return;
1610  TVector2 coord0 = TVector2(hit0->WireID().Wire, hit0->PeakTime());
1611  TVector2 coord1 = TVector2(hit1->WireID().Wire, hit1->PeakTime());
1612  TVector2 coordvtx = TVector2(fGeom->WireCoordinate(xyz[1], xyz[2], hit0->WireID().planeID()),
1613  detProp.ConvertXToTicks(xyz[0], hit0->WireID().planeID()));
1614  if ((coord1 - coordvtx).Mod() < (coord0 - coordvtx).Mod()) {
1615  std::reverse(showerHits.begin(), showerHits.end());
1616  }
1617 }
1618 
1619 void
1622  std::vector<art::Ptr<recob::Hit>>& trackHits) const
1623 {
1624 
1625  // Find TPC for the vertex
1626  double xyz[3];
1627  vertex->XYZ(xyz);
1628  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1629 
1630  // vertex cannot be projected into a TPC, find the TPC that has the most hits
1631  if (!tpc.isValid) {
1632  std::map<geo::TPCID, unsigned int> tpcmap;
1633  unsigned maxhits = 0;
1634  for (auto const& hit : showerHits) {
1635  ++tpcmap[geo::TPCID(hit->WireID())];
1636  }
1637  for (auto const& t : tpcmap) {
1638  if (t.second > maxhits) {
1639  maxhits = t.second;
1640  tpc = t.first;
1641  }
1642  }
1643  }
1644  if (!tpc.isValid) return;
1645 
1646  double parm[2];
1647  int fitok = 0;
1648  std::vector<double> wfit;
1649  std::vector<double> tfit;
1650  std::vector<double> cfit;
1651 
1652  for (size_t i = 0; i < fNfitpass; ++i) {
1653 
1654  // Fit a straight line through hits
1655  unsigned int nhits = 0;
1656  for (auto& hit : showerHits) {
1657  if (hit->WireID().TPC == tpc.TPC) {
1658  TVector2 coord = HitCoordinates_(*hit);
1659  if (i == 0 ||
1660  (std::abs((coord.Y() - (parm[0] + coord.X() * parm[1])) * cos(atan(parm[1]))) <
1661  fToler[i - 1]) ||
1662  fitok == 1) {
1663  ++nhits;
1664  if (nhits == fNfithits[i] + 1) break;
1665  wfit.push_back(coord.X());
1666  tfit.push_back(coord.Y());
1667  cfit.push_back(1.);
1668  if (i == fNfitpass - 1) { trackHits.push_back(hit); }
1669  }
1670  }
1671  }
1672 
1673  if (i < fNfitpass - 1 && wfit.size()) {
1674  fitok = WeightedFit(wfit.size(), &wfit[0], &tfit[0], &cfit[0], &parm[0]);
1675  }
1676  wfit.clear();
1677  tfit.clear();
1678  cfit.clear();
1679  }
1680 }
1681 
1682 TVector2
1684 {
1685  return TVector2(GlobalWire_(hit.WireID()), hit.PeakTime());
1686 }
1687 
1688 TVector2
1690  recob::Hit const& hit) const
1691 {
1692  geo::PlaneID planeID = hit.WireID().planeID();
1693  return HitPosition_(detProp, HitCoordinates_(hit), planeID);
1694 }
1695 
1696 TVector2
1698  TVector2 const& pos,
1699  geo::PlaneID planeID) const
1700 {
1701  return TVector2(pos.X() * fGeom->WirePitch(planeID), detProp.ConvertTicksToX(pos.Y(), planeID));
1702 }
1703 
1704 double
1706 {
1707  double globalWire = -999;
1708 
1709  // Induction
1710  if (fGeom->SignalType(wireID) == geo::kInduction) {
1711  double wireCentre[3];
1712  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1713  if (wireID.TPC % 2 == 0)
1714  globalWire =
1715  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1716  else
1717  globalWire =
1718  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1719  }
1720 
1721  // Collection
1722  else {
1723  // FOR COLLECTION WIRES, HARD CODE THE GEOMETRY FOR GIVEN DETECTORS
1724  // THIS _SHOULD_ BE TEMPORARY. GLOBAL WIRE SUPPORT IS BEING ADDED TO THE LARSOFT GEOMETRY AND SHOULD BE AVAILABLE SOON
1725  if (fDetector == "dune35t") {
1726  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1727  if (wireID.TPC == 0 or wireID.TPC == 1)
1728  globalWire = wireID.Wire;
1729  else if (wireID.TPC == 2 or wireID.TPC == 3 or wireID.TPC == 4 or wireID.TPC == 5)
1730  globalWire = nwires + wireID.Wire;
1731  else if (wireID.TPC == 6 or wireID.TPC == 7)
1732  globalWire = (2 * nwires) + wireID.Wire;
1733  else
1734  mf::LogError("BlurredClusterAlg")
1735  << "Error when trying to find a global induction plane coordinate for TPC " << wireID.TPC
1736  << " (geometry" << fDetector << ")";
1737  }
1738  else if (fDetector == "dune10kt") {
1739  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1740  // Detector geometry has four TPCs, two on top of each other, repeated along z...
1741  int block = wireID.TPC / 4;
1742  globalWire = (nwires * block) + wireID.Wire;
1743  }
1744  else {
1745  double wireCentre[3];
1746  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1747  if (wireID.TPC % 2 == 0)
1748  globalWire =
1749  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1750  else
1751  globalWire =
1752  fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1753  }
1754  }
1755 
1756  return globalWire;
1757 }
1758 
1759 std::map<double, int>
1761  const std::map<int, std::vector<art::Ptr<recob::Hit>>>& showerHitsMap) const
1762 {
1763 
1764  // Get the wire widths
1765  std::map<int, int> planeWireLength;
1766  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::const_iterator showerHitsIt =
1767  showerHitsMap.begin();
1768  showerHitsIt != showerHitsMap.end();
1769  ++showerHitsIt)
1770  planeWireLength[showerHitsIt->first] =
1771  std::abs(HitCoordinates_(*showerHitsIt->second.front()).X() -
1772  HitCoordinates_(*showerHitsIt->second.back()).X());
1773 
1774  // Find the relative wire width for each plane with respect to the others
1775  std::map<int, double> planeOtherWireLengths;
1776  for (std::map<int, int>::iterator planeWireLengthIt = planeWireLength.begin();
1777  planeWireLengthIt != planeWireLength.end();
1778  ++planeWireLengthIt) {
1779  double quad = 0.;
1780  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
1781  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
1782  quad += cet::square(planeWireLength[plane]);
1783  quad = std::sqrt(quad);
1784  planeOtherWireLengths[planeWireLengthIt->first] =
1785  planeWireLength[planeWireLengthIt->first] / (double)quad;
1786  }
1787 
1788  // Order these backwards
1789  std::map<double, int> wireWidthMap;
1790  for (std::map<int, std::vector<art::Ptr<recob::Hit>>>::const_iterator showerHitsIt =
1791  showerHitsMap.begin();
1792  showerHitsIt != showerHitsMap.end();
1793  ++showerHitsIt)
1794  wireWidthMap[planeOtherWireLengths.at(showerHitsIt->first)] = showerHitsIt->first;
1795 
1796  return wireWidthMap;
1797 }
1798 
1799 TVector2
1801  const std::vector<art::Ptr<recob::Hit>>& showerHits) const
1802 {
1803 
1804  TVector2 pos;
1805  double weight = 1;
1806  double sumx = 0., sumy = 0., sumx2 = 0., sumxy = 0., sumweight = 0.;
1807  for (std::vector<art::Ptr<recob::Hit>>::const_iterator hit = showerHits.begin();
1808  hit != showerHits.end();
1809  ++hit) {
1810  //++nhits;
1811  pos = HitPosition_(detProp, **hit);
1812  weight = cet::square((*hit)->Integral());
1813  sumweight += weight;
1814  sumx += weight * pos.X();
1815  sumy += weight * pos.Y();
1816  sumx2 += weight * pos.X() * pos.X();
1817  sumxy += weight * pos.X() * pos.Y();
1818  }
1819  double gradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1820  TVector2 direction = TVector2(1, gradient).Unit();
1821 
1822  return direction;
1823 }
1824 
1825 TVector2
1827  std::vector<art::Ptr<recob::Hit>> const& showerHits) const
1828 {
1829 
1830  TVector2 pos, chargePoint = TVector2(0, 0);
1831  double totalCharge = 0;
1832  for (std::vector<art::Ptr<recob::Hit>>::const_iterator hit = showerHits.begin();
1833  hit != showerHits.end();
1834  ++hit) {
1835  pos = HitPosition_(detProp, **hit);
1836  chargePoint += (*hit)->Integral() * pos;
1837  totalCharge += (*hit)->Integral();
1838  }
1839  TVector2 centre = chargePoint / totalCharge;
1840 
1841  return centre;
1842 }
1843 
1844 double
1846  const std::vector<art::Ptr<recob::Hit>>& showerHits) const
1847 {
1848 
1849  TVector2 direction = ShowerDirection_(detProp, showerHits);
1850  TVector2 centre = ShowerCenter_(detProp, showerHits);
1851 
1852  std::vector<double> distanceToAxis;
1853  for (std::vector<art::Ptr<recob::Hit>>::const_iterator showerHitsIt = showerHits.begin();
1854  showerHitsIt != showerHits.end();
1855  ++showerHitsIt) {
1856  TVector2 proj = (HitPosition_(detProp, **showerHitsIt) - centre).Proj(direction) + centre;
1857  distanceToAxis.push_back((HitPosition_(detProp, **showerHitsIt) - proj).Mod());
1858  }
1859  double RMS = TMath::RMS(distanceToAxis.begin(), distanceToAxis.end());
1860 
1861  return RMS;
1862 }
1863 
1864 double
1866  detinfo::DetectorPropertiesData const& detProp,
1867  const std::vector<art::Ptr<recob::Hit>>& showerHits) const
1868 {
1869  // Find a rough shower 'direction' and center
1870  TVector2 direction = ShowerDirection_(detProp, showerHits);
1871 
1872  // Bin the hits into discreet chunks
1873  int nShowerSegments = fNumShowerSegments;
1874  double lengthOfShower =
1875  (HitPosition_(detProp, *showerHits.back()) - HitPosition_(detProp, *showerHits.front())).Mod();
1876  double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
1877  std::map<int, std::vector<art::Ptr<recob::Hit>>> showerSegments;
1878  std::map<int, double> segmentCharge;
1879  for (auto const& hitPtr : showerHits) {
1880  auto const& hit = *hitPtr;
1881  int const segment =
1882  (HitPosition_(detProp, hit) - HitPosition_(detProp, *showerHits.front())).Mod() /
1883  lengthOfSegment;
1884  showerSegments[segment].push_back(hitPtr);
1885  segmentCharge[segment] += hit.Integral();
1886  }
1887 
1888  TGraph* graph = new TGraph();
1889  std::vector<std::pair<int, double>> binVsRMS;
1890 
1891  // Loop over the bins to find the distribution of hits as the shower
1892  // progresses
1893  for (auto const& [segment, hitPtrs] : showerSegments) {
1894 
1895  // Get the mean position of the hits in this bin
1896  TVector2 meanPosition(0, 0);
1897  for (auto const& hit : hitPtrs | views::transform(to_element))
1898  meanPosition += HitPosition_(detProp, hit);
1899  meanPosition /= (double)hitPtrs.size();
1900 
1901  // Get the RMS of this bin
1902  std::vector<double> distanceToAxisBin;
1903  for (auto const& hit : hitPtrs | views::transform(to_element)) {
1904  TVector2 proj = (HitPosition_(detProp, hit) - meanPosition).Proj(direction) + meanPosition;
1905  distanceToAxisBin.push_back((HitPosition_(detProp, hit) - proj).Mod());
1906  }
1907 
1908  double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
1909  binVsRMS.emplace_back(segment, RMSBin);
1910  if (fMakeRMSGradientPlot) graph->SetPoint(graph->GetN(), segment, RMSBin);
1911  }
1912 
1913  // Get the gradient of the RMS-bin plot
1914  double sumx = 0., sumy = 0., sumx2 = 0., sumxy = 0., sumweight = 0.;
1915  for (auto const [bin, RMSBin] : binVsRMS) {
1916  double weight = segmentCharge.at(bin);
1917  sumweight += weight;
1918  sumx += weight * bin;
1919  sumy += weight * RMSBin;
1920  sumx2 += weight * bin * bin;
1921  sumxy += weight * bin * RMSBin;
1922  }
1923  double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1924 
1925  if (fMakeRMSGradientPlot) {
1926  TVector2 direction = TVector2(1, RMSgradient).Unit();
1927  TCanvas* canv = new TCanvas();
1928  graph->Draw();
1929  graph->GetXaxis()->SetTitle("Shower segment");
1930  graph->GetYaxis()->SetTitle("RMS of hit distribution");
1931  TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
1932  TLine line;
1933  line.SetLineColor(2);
1934  line.DrawLine(centre.X() - 1000 * direction.X(),
1935  centre.Y() - 1000 * direction.Y(),
1936  centre.X() + 1000 * direction.X(),
1937  centre.Y() + 1000 * direction.Y());
1938  canv->SaveAs("RMSGradient.png");
1939  delete canv;
1940  }
1941  delete graph;
1942 
1943  return RMSgradient;
1944 }
1945 
1946 TVector2
1948  TVector3 const& point,
1949  int plane,
1950  int cryostat) const
1951 {
1952 
1953  TVector2 wireTickPos = TVector2(-999., -999.);
1954 
1955  double pointPosition[3] = {point.X(), point.Y(), point.Z()};
1956 
1957  geo::TPCID tpcID = fGeom->FindTPCAtPosition(pointPosition);
1958  int tpc = 0;
1959  if (tpcID.isValid)
1960  tpc = tpcID.TPC;
1961  else
1962  return wireTickPos;
1963 
1964  // Construct wire ID for this point projected onto the plane
1965  geo::PlaneID planeID = geo::PlaneID(cryostat, tpc, plane);
1966  geo::WireID wireID;
1967  try {
1968  wireID = fGeom->NearestWireID(point, planeID);
1969  }
1970  catch (geo::InvalidWireError const& e) {
1971  wireID = e.suggestedWireID(); // pick the closest valid wire
1972  }
1973 
1974  wireTickPos = TVector2(GlobalWire_(wireID), detProp.ConvertXToTicks(point.X(), planeID));
1975 
1976  return HitPosition_(detProp, wireTickPos, planeID);
1977 }
1978 
1979 int
1981  const std::map<int, std::vector<art::Ptr<recob::Hit>>>& showerHitsMap) const
1982 {
1983  // Get the width of the shower in wire coordinate
1984  std::map<int, int> planeWireLength;
1985  std::map<int, double> planeOtherWireLengths;
1986  for (auto const& [plane, hits] : showerHitsMap)
1987  planeWireLength[plane] =
1988  std::abs(HitCoordinates_(*hits.front()).X() - HitCoordinates_(*hits.back()).X());
1989  for (std::map<int, int>::iterator planeWireLengthIt = planeWireLength.begin();
1990  planeWireLengthIt != planeWireLength.end();
1991  ++planeWireLengthIt) {
1992  double quad = 0.;
1993  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
1994  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
1995  quad += cet::square(planeWireLength[plane]);
1996  quad = std::sqrt(quad);
1997  planeOtherWireLengths[planeWireLengthIt->first] =
1998  planeWireLength[planeWireLengthIt->first] / (double)quad;
1999  }
2000 
2001  if (fDebug > 1)
2002  for (auto const [plane, relative_width] : planeOtherWireLengths) {
2003  std::cout << "Plane " << plane << " has " << planeWireLength[plane]
2004  << " wire width and therefore has relative width in wire of " << relative_width
2005  << '\n';
2006  }
2007 
2008  std::map<double, int> wireWidthMap;
2009  for (int const plane : showerHitsMap | views::keys) {
2010  double wireWidth = planeWireLength.at(plane);
2011  wireWidthMap[wireWidth] = plane;
2012  }
2013 
2014  return wireWidthMap.begin()->second;
2015 }
2016 
2017 Int_t
2019  const Double_t* x,
2020  const Double_t* y,
2021  const Double_t* w,
2022  Double_t* parm) const
2023 {
2024 
2025  Double_t sumx = 0.;
2026  Double_t sumx2 = 0.;
2027  Double_t sumy = 0.;
2028  Double_t sumy2 = 0.;
2029  Double_t sumxy = 0.;
2030  Double_t sumw = 0.;
2031  Double_t eparm[2];
2032 
2033  parm[0] = 0.;
2034  parm[1] = 0.;
2035  eparm[0] = 0.;
2036  eparm[1] = 0.;
2037 
2038  for (Int_t i = 0; i < n; i++) {
2039  sumx += x[i] * w[i];
2040  sumx2 += x[i] * x[i] * w[i];
2041  sumy += y[i] * w[i];
2042  sumy2 += y[i] * y[i] * w[i];
2043  sumxy += x[i] * y[i] * w[i];
2044  sumw += w[i];
2045  }
2046 
2047  if (sumx2 * sumw - sumx * sumx == 0.) return 1;
2048  if (sumx2 - sumx * sumx / sumw == 0.) return 1;
2049 
2050  parm[0] = (sumy * sumx2 - sumx * sumxy) / (sumx2 * sumw - sumx * sumx);
2051  parm[1] = (sumxy - sumx * sumy / sumw) / (sumx2 - sumx * sumx / sumw);
2052 
2053  eparm[0] = sumx2 * (sumx2 * sumw - sumx * sumx);
2054  eparm[1] = (sumx2 - sumx * sumx / sumw);
2055 
2056  if (eparm[0] < 0. || eparm[1] < 0.) return 1;
2057 
2058  eparm[0] = sqrt(eparm[0]) / (sumx2 * sumw - sumx * sumx);
2059  eparm[1] = sqrt(eparm[1]) / (sumx2 - sumx * sumx / sumw);
2060 
2061  return 0;
2062 }
2063 
2064 bool
2066 {
2067  if (hits.empty()) return false;
2068  if (hits.size() > 2000) return true;
2069  if (hits.size() < 20) return true;
2070 
2071  std::map<int, int> hitmap;
2072  unsigned nhits = 0;
2073  for (auto const& hit : hits | views::transform(to_element)) {
2074  ++nhits;
2075  if (nhits > 2) ++hitmap[hit.WireID().Wire];
2076  if (nhits == 20) break;
2077  }
2078  if (float(nhits - 2) / hitmap.size() > 1.4)
2079  return false;
2080  else
2081  return true;
2082 }
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
end
while True: pbar.update(maxval-len(onlies[E][S])) #print iS, "/", len(onlies[E][S]) found = False for...
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
Definition: Vertex.cxx:36
intermediate_table::iterator iterator
TVector2 HitPosition_(detinfo::DetectorPropertiesData const &detProp, recob::Hit const &hit) const
Return the coordinates of this hit in units of cm.
std::vector< recob::SpacePoint > MakeSpacePoints(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &hits, std::vector< std::vector< art::Ptr< recob::Hit >>> &hitAssns) const
Makes space points from the shower hits in each plane.
void FindInitialTrackHits(std::vector< art::Ptr< recob::Hit >> const &showerHits, art::Ptr< recob::Vertex > const &vertex, std::vector< art::Ptr< recob::Hit >> &trackHits) const
<Tingjun to="" document>="">
int WorstPlane_(const std::map< int, std::vector< art::Ptr< recob::Hit >>> &showerHitsMap) const
Returns the plane which is determined to be the least likely to be correct.
double z
z position of intersection
Definition: geo_types.h:805
void cluster(In first, In last, Out result, Pred *pred)
Definition: NNClusters.h:41
shower::ShowerEnergyAlg const fShowerEnergyAlg
Definition: EMShowerAlg.h:277
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
constexpr to_element_t to_element
Definition: ToElement.h:24
pma::ProjectionMatchingAlg const fProjectionMatchingAlg
Definition: EMShowerAlg.h:279
double ShowerEnergy(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &hits, geo::PlaneID::PlaneID_t plane) const
std::string string
Definition: nybbler.cc:12
ROOT::Math::SMatrix< Double32_t, 5, 5, ROOT::Math::MatRepSym< Double32_t, 5 > > SMatrixSym55
Definition: TrackingTypes.h:85
recob::Shower MakeShower(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &hits, std::unique_ptr< recob::Track > const &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &initialTrackHits) const
Makes a recob::Shower object given the hits in the shower and the initial track-like part...
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::vector< Vector_t > convertCollToVector(std::vector< Vector > const &coll)
Definition: TrackingTypes.h:58
auto coord(Vector &v, unsigned int n) noexcept
Returns an object to manage the coordinate n of a vector.
geo::WireID WireID() const
Definition: Hit.h:233
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:211
struct vector vector
TrackTrajectory::Flags_t Flags_t
Definition: Track.h:68
def graph(desc, maker=maker)
Definition: apa.py:294
Vector_t VertexDirection() const
Definition: Track.h:132
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:212
void AssociateClustersAndTracks(std::vector< art::Ptr< recob::Cluster >> const &clusters, art::FindManyP< recob::Hit > const &fmh, art::FindManyP< recob::Track > const &fmt, std::map< int, std::vector< int >> &clusterToTracks, std::map< int, std::vector< int >> &trackToClusters) const
Map associated tracks and clusters together given their associated hits.
Definition: EMShowerAlg.cxx:60
std::map< int, std::map< int, bool > > GetPlanePermutations_(const detinfo::DetectorPropertiesData &detProp, const std::map< int, std::vector< art::Ptr< recob::Hit >>> &showerHitsMap) const
double GlobalWire_(const geo::WireID &wireID) const
Find the global wire position.
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:232
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:580
intermediate_table::const_iterator const_iterator
TFile * outFile
Definition: makeDST.cxx:36
geo::PlaneID Plane() const
Returns the plane ID this cluster lies on.
Definition: Cluster.h:744
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
Cluster finding and building.
double const fdEdxTrackLength
Definition: EMShowerAlg.h:265
constexpr T square(T x)
Definition: pow.h:21
unsigned int const fNfitpass
Definition: EMShowerAlg.h:269
TVector2 ShowerCenter_(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &showerHits) const
Returns the charge-weighted shower center.
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
std::vector< std::vector< int > > FindShowers(std::map< int, std::vector< int >> const &trackToClusters) const
Makes showers given a map between tracks and all clusters associated with them.
weight
Definition: test.py:257
unsigned int Nwires(unsigned int p, unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wires in the specified plane.
std::vector< double > const fToler
Definition: EMShowerAlg.h:271
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
decltype(auto) constexpr size(T &&obj)
ADL-aware version of std::size.
Definition: StdUtils.h:92
void sort_all(RandCont &)
bool const fMakeRMSGradientPlot
Definition: EMShowerAlg.h:285
T abs(T value)
void CheckIsolatedHits_(std::map< int, std::vector< art::Ptr< recob::Hit >>> &showerHitsMap) const
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:184
std::vector< unsigned int > const fNfithits
Definition: EMShowerAlg.h:270
Int_t WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm) const
<Tingjun to="" document>="">
double dEdx(float dqdx, float Efield)
Definition: doAna.cpp:21
fInnerVessel push_back(Point(-578.400000, 0.000000, 0.000000))
TVector3 Construct3DPoint_(detinfo::DetectorPropertiesData const &detProp, art::Ptr< recob::Hit > const &hit1, art::Ptr< recob::Hit > const &hit2) const
Constructs a 3D point (in [cm]) to represent the hits given in two views.
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
bool search_all(FwdCont const &, Datum const &)
const double e
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
Signal from induction planes.
Definition: geo_types.h:145
Collection of exceptions for Geometry system.
A trajectory in space reconstructed from hits.
std::void_t< T > n
std::vector< int > CheckShowerPlanes(std::vector< std::vector< int >> const &initialShowers, std::vector< art::Ptr< recob::Cluster >> const &clusters, art::FindManyP< recob::Hit > const &fmh) const
Takes the initial showers found and tries to resolve issues where one bad view ruins the event...
key_type key() const noexcept
Definition: Ptr.h:216
Point_t const & Vertex() const
Definition: Track.h:124
std::unique_ptr< recob::Track > ConstructTrack(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &track1, std::vector< art::Ptr< recob::Hit >> const &track2, std::map< int, TVector2 > const &showerCentreMap) const
bool isNull() const noexcept
Definition: Ptr.h:173
std::map< int, std::vector< art::Ptr< recob::Hit > > > OrderShowerHits(detinfo::DetectorPropertiesData const &detProp, art::PtrVector< recob::Hit > const &shower, int plane) const
Takes the hits associated with a shower and orders them so they follow the direction of the shower...
tick_as<> tick
Tick number, represented by std::ptrdiff_t.
Definition: electronics.h:75
double ConvertXToTicks(double X, int p, int t, int c) const
double ShowerHitRMS_(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &showerHits) const
double const fMinTrackLength
Definition: EMShowerAlg.h:264
std::vector< Point_t > convertCollToPoint(std::vector< Point > const &coll)
Definition: TrackingTypes.h:55
double distance(double x1, double y1, double z1, double x2, double y2, double z2)
Q_UINT16 values[128]
pma::Track3D * buildSegment(const detinfo::DetectorPropertiesData &clockData, const std::vector< art::Ptr< recob::Hit >> &hits_1, const std::vector< art::Ptr< recob::Hit >> &hits_2={}) const
The data type to uniquely identify a TPC.
Definition: geo_types.h:386
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
auto transform_all(Container &, OutputIt, UnaryOp)
bool isCleanShower(std::vector< art::Ptr< recob::Hit >> const &hits) const
<Tingjun to="" document>="">
bool const fMakeGradientPlot
Definition: EMShowerAlg.h:284
TVector2 Project3DPointOntoPlane_(detinfo::DetectorPropertiesData const &detProp, TVector3 const &point, int plane, int cryostat=0) const
EMShowerAlg(fhicl::ParameterSet const &pset, int debug=0)
Definition: EMShowerAlg.cxx:37
TVector2 ShowerDirection_(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &showerHits) const
void FindInitialTrack(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &hits, std::unique_ptr< recob::Track > &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit >>> &initialTrackHits, int plane) const
Detector simulation of raw signals on wires.
bool CheckShowerHits_(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &showerHitsMap) const
double ConvertTicksToX(double ticks, int p, int t, int c) const
void OrderShowerHits_(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &shower, std::vector< art::Ptr< recob::Hit >> &orderedShower, art::Ptr< recob::Vertex > const &vertex) const
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
std::unique_ptr< recob::Track > MakeInitialTrack_(detinfo::DetectorPropertiesData const &detProp, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &initialHitsMap, std::map< int, std::vector< art::Ptr< recob::Hit >>> const &showerHitsMap) const
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
std::size_t color(std::string const &procname)
double FinddEdx_(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &trackHits, std::unique_ptr< recob::Track > const &track) const
Finds dE/dx for the track given a set of hits.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:218
Contains all timing reference information for the detector.
static unsigned int reverse(QString &chars, unsigned char *level, unsigned int a, unsigned int b)
Definition: qstring.cpp:11649
double y
y position of intersection
Definition: geo_types.h:804
void line(double t, double *p, double &x, double &y, double &z)
TVector2 HitCoordinates_(recob::Hit const &hit) const
Return the coordinates of this hit in global wire/tick space.
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
double TrackPitchInView(recob::Track const &track, geo::View_t view, size_t trajectory_point=0U)
Returns the projected length of track on a wire pitch step [cm].
Definition: TrackUtils.cxx:78
int const fNumShowerSegments
Definition: EMShowerAlg.h:286
calo::CalorimetryAlg const fCalorimetryAlg
Definition: EMShowerAlg.h:278
QTextStream & bin(QTextStream &s)
double dEdx_AREA(detinfo::DetectorClocksData const &clock_data, detinfo::DetectorPropertiesData const &det_prop, recob::Hit const &hit, double pitch, double T0=0) const
std::vector< art::Ptr< recob::Hit > > FindOrderOfHits_(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &hits, bool perpendicular=false) const
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
geo::WireID NearestWireID(geo::Point_t const &point, geo::PlaneID const &planeid) const
Returns the ID of wire closest to position in the specified TPC.
detail::Node< FrameID, bool > PlaneID
Definition: CRTID.h:125
double const fSpacePointSize
Definition: EMShowerAlg.h:266
list x
Definition: train.py:276
IDparameter< geo::TPCID > TPCID
Member type of validated geo::TPCID parameter.
std::map< double, int > RelativeWireWidth_(const std::map< int, std::vector< art::Ptr< recob::Hit >>> &showerHitsMap) const
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:48
constexpr PlaneID const & planeID() const
Definition: geo_types.h:638
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:73
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
art::ServiceHandle< geo::Geometry const > fGeom
Definition: EMShowerAlg.h:274
size_t size() const
Definition: PmaTrack3D.h:108
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
recob::tracking::Plane Plane
Definition: TrackState.h:17
if(!yymsg) yymsg
Utility functions to extract information from recob::Track
std::string to_string(ModuleType const mt)
Definition: ModuleType.h:34
std::string const fDetector
Definition: EMShowerAlg.h:281
double WireAngleToVertical(geo::View_t view, geo::TPCID const &tpcid) const
Returns the angle of the wires in the specified view from vertical.
std::map< int, std::vector< art::Ptr< recob::Hit > > > FindShowerStart_(std::map< int, std::vector< art::Ptr< recob::Hit >>> const &orderedShowerMap) const
decltype(auto) constexpr empty(T &&obj)
ADL-aware version of std::empty.
Definition: StdUtils.h:97
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
double ShowerHitRMSGradient_(detinfo::DetectorPropertiesData const &detProp, const std::vector< art::Ptr< recob::Hit >> &showerHits) const
Returns the gradient of the RMS vs shower segment graph.
vertex reconstruction