All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 
11 #include "cetlib/container_algorithms.h"
12 #include "cetlib/pow.h"
13 #include "messagefacility/MessageLogger/MessageLogger.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 
37 shower::EMShowerAlg::EMShowerAlg(fhicl::ParameterSet const& pset, int const debug)
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()) {
54  throw art::Exception(art::errors::Configuration)
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};
68  AssociateClustersAndTracks(
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;
165  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt =
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)
177  for (std::vector<art::Ptr<recob::Hit>>::iterator hitIt =
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
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());
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
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
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;
681  cet::transform_all(
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>>
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>
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,
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 
1079  art::PtrVector<recob::Hit> const& hits,
1080  art::Ptr<recob::Vertex> const& vertex,
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 =
1169  fGeom->WireAngleToVertical(fGeom->Plane(plane).View(),
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>
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,
1340  fSpacePointSize,
1341  fSpacePointSize,
1342  fSpacePointSize,
1343  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>>>
1373  art::PtrVector<recob::Hit> const& shower,
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
1588  std::vector<art::Ptr<recob::Hit>> const& shower,
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
1620 shower::EMShowerAlg::FindInitialTrackHits(std::vector<art::Ptr<recob::Hit>> const& showerHits,
1621  art::Ptr<recob::Vertex> const& vertex,
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
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
2065 shower::EMShowerAlg::isCleanShower(std::vector<art::Ptr<recob::Hit>> const& hits) const
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 }
process_name vertex
Definition: cheaterreco.fcl:51
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
&lt;Tingjun to=&quot;&quot; document&gt;=&quot;&quot;&gt;
then if[["$THISISATEST"==1]]
Definition: neoSmazza.sh:95
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
constexpr to_element_t to_element
Definition: ToElement.h:24
BEGIN_PROLOG true icarus_rawdigitfilter FilterTools FilterPlane1 Plane
static constexpr Sample_t transform(Sample_t sample)
process_name opflash particleana ie x
process_name cluster
Definition: cheaterreco.fcl:51
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...
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
TrackTrajectory::Flags_t Flags_t
Vector_t VertexDirection() const
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::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
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
process_name use argoneut_mc_hitfinder track
process_name hit
Definition: cheaterreco.fcl:51
then echo echo For and will not be changed by echo further linking echo echo B echo The symbol is in the uninitialized data multiple common symbols may appear with the echo same name If the symbol is defined the common echo symbols are treated as undefined references For more echo details on common see the discussion of warn common echo in *Note Linker see the discussion of warn common echo in *Note Linker such as a global int variable echo as opposed to a large global array echo echo I echo The symbol is an indirect reference to another symbol This echo is a GNU extension to the a out object file format which is echo rarely used echo echo N echo The symbol is a debugging symbol echo echo R echo The symbol is in a read only data section echo echo S echo The symbol is in an uninitialized data section for small echo objects echo echo T echo The symbol is in the the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo W echo The symbol is a weak symbol that has not been specifically echo tagged as a weak object symbol When a weak defined symbol echo is linked with a normal defined the normal defined echo symbol is used with no error When a weak undefined symbol echo is linked and the symbol is not the value of the echo weak symbol becomes zero with no error echo echo echo The symbol is a stabs symbol in an a out object file In echo this the next values printed are the stabs other echo the stabs desc and the stab type Stabs symbols are echo used to hold debugging information For more echo see *Note or object file format specific echo echo For Mac OS X
TVector2 ShowerCenter_(detinfo::DetectorPropertiesData const &detProp, std::vector< art::Ptr< recob::Hit >> const &showerHits) const
Returns the charge-weighted shower center.
process_name shower
Definition: cheaterreco.fcl:51
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.
TString outFile
constexpr details::BinObj< T > bin(T value)
Returns a wrapper to print the specified data in binary format.
IDparameter< geo::PlaneID > PlaneID
Member type of validated geo::PlaneID parameter.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
T abs(T value)
void CheckIsolatedHits_(std::map< int, std::vector< art::Ptr< recob::Hit >>> &showerHitsMap) const
Int_t WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm) const
&lt;Tingjun to=&quot;&quot; document&gt;=&quot;&quot;&gt;
Collection of exceptions for Geometry system.
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.
process_name opflash particleana ie ie y
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
IDparameter< geo::WireID > WireID
Member type of validated geo::WireID parameter.
Signal from induction planes.
Definition: geo_types.h:145
A trajectory in space reconstructed from hits.
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...
Point_t const & Vertex() const
auto end(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:585
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
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
return match has_match and(match.match_pdg==11 or match.match_pdg==-11)
std::vector< Point_t > convertCollToPoint(std::vector< Point > const &coll)
Definition: TrackingTypes.h:55
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
bool isCleanShower(std::vector< art::Ptr< recob::Hit >> const &hits) const
&lt;Tingjun to=&quot;&quot; document&gt;=&quot;&quot;&gt;
float dEdx(detinfo::DetectorClocksData const &clockData, detinfo::DetectorPropertiesData const &detProp, const TCSlice &slc, TP3D &tp3d)
Definition: PFPUtils.cxx:2687
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
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
BEGIN_PROLOG Z planes
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
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.
std::string to_string(WindowPattern const &pattern)
double y
y position of intersection
Definition: geo_types.h:804
TVector2 HitCoordinates_(recob::Hit const &hit) const
Return the coordinates of this hit in global wire/tick space.
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:79
do i e
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
temporary value
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
std::size_t count(Cont const &cont)
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:406
size_t size() const
Definition: PmaTrack3D.h:111
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
bool empty(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:555
Utility functions to extract information from recob::Track
BEGIN_PROLOG could also be cout
auto const detProp
std::map< int, std::vector< art::Ptr< recob::Hit > > > FindShowerStart_(std::map< int, std::vector< art::Ptr< recob::Hit >>> const &orderedShowerMap) 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.