LArSoft  v07_13_02
Liquid Argon Software toolkit - http://larsoft.org/
EMShowerAlg.cxx
Go to the documentation of this file.
1 // 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
10 
12 
13 shower::EMShowerAlg::EMShowerAlg(fhicl::ParameterSet const& pset) : fDetProp(lar::providerFrom<detinfo::DetectorPropertiesService>()),
14  fShowerEnergyAlg(pset.get<fhicl::ParameterSet>("ShowerEnergyAlg")),
15  fCalorimetryAlg(pset.get<fhicl::ParameterSet>("CalorimetryAlg")),
16  fProjectionMatchingAlg(pset.get<fhicl::ParameterSet>("ProjectionMatchingAlg")) {
17 
18  fMinTrackLength = pset.get<double>("MinTrackLength");
19  fdEdxTrackLength = pset.get<double>("dEdxTrackLength");
20  fSpacePointSize = pset.get<double>("SpacePointSize");
21  fNfitpass = pset.get<unsigned int>("Nfitpass");
22  fNfithits = pset.get<std::vector<unsigned int> >("Nfithits");
23  fToler = pset.get<std::vector<double> >("Toler");
24  if (fNfitpass!=fNfithits.size() ||
25  fNfitpass!=fToler.size()) {
27  << "EMShowerAlg: fNfithits and fToler need to have size fNfitpass";
28  }
29  fDetector = pset.get<std::string>("Detector","dune35t");
30 
31  hTrueDirection = tfs->make<TH1I>("trueDir","",2,0,2);
32 
33  //this->MakePicture();
34  // tmp
35  fMakeGradientPlot = pset.get<bool>("MakeGradientPlot",false);
36  fMakeRMSGradientPlot = pset.get<bool>("MakeRMSGradientPlot",false);
37  fNumShowerSegments = pset.get<int>("NumShowerSegments",4);
38  hNumHitsInSegment = tfs->make<TProfile>("NumHitsInSegment","",100,0,100);
39  hNumSegments = tfs->make<TProfile>("NumSegments","",100,0,100);
40 
41 }
42 
44  art::FindManyP<recob::Hit> const& fmh,
46  std::map<int,std::vector<int> >& clusterToTracks,
47  std::map<int,std::vector<int> >& trackToClusters) {
48 
49  std::vector<int> clustersToIgnore = {-999};
50  this->AssociateClustersAndTracks(clusters, fmh, fmt, clustersToIgnore, clusterToTracks, trackToClusters);
51 
52  return;
53 
54 }
55 
57  art::FindManyP<recob::Hit> const& fmh,
59  std::vector<int> const& clustersToIgnore,
60  std::map<int,std::vector<int> >& clusterToTracks,
61  std::map<int,std::vector<int> >& trackToClusters) {
62 
63  // Look through all the clusters
64  for (std::vector<art::Ptr<recob::Cluster> >::const_iterator clusterIt = clusters.begin(); clusterIt != clusters.end(); ++clusterIt) {
65 
66  // Get the hits in this cluster
67  std::vector<art::Ptr<recob::Hit> > clusterHits = fmh.at(clusterIt->key());
68 
69  // Look at all these hits and find the associated tracks
70  for (std::vector<art::Ptr<recob::Hit> >::iterator clusterHitIt = clusterHits.begin(); clusterHitIt != clusterHits.end(); ++clusterHitIt) {
71 
72  // Get the tracks associated with this hit
73  std::vector<art::Ptr<recob::Track> > clusterHitTracks = fmt.at(clusterHitIt->key());
74  if (clusterHitTracks.size() > 1) { std::cout << "More than one track associated with this hit!" << std::endl; continue; }
75  if (clusterHitTracks.size() < 1) continue;
76  if (clusterHitTracks.at(0)->Length() < fMinTrackLength) {
77  if (fDebug > 2)
78  std::cout << "Track " << clusterHitTracks.at(0)->ID() << " is too short! (" << clusterHitTracks.at(0)->Length() << ")" << std::endl;
79  continue;
80  }
81 
82  // Add this cluster to the track map
83  int track = clusterHitTracks.at(0).key();
84  //int trackID = clusterHitTracks.at(0)->ID();
85  int cluster = (*clusterIt).key();
86  if (std::find(clustersToIgnore.begin(), clustersToIgnore.end(), cluster) != clustersToIgnore.end())
87  continue;
88  if (std::find(trackToClusters[track].begin(), trackToClusters[track].end(), cluster) == trackToClusters[track].end())
89  trackToClusters[track].push_back(cluster);
90  if (std::find(clusterToTracks[cluster].begin(), clusterToTracks[cluster].end(), track) == clusterToTracks[cluster].end())
91  clusterToTracks[cluster].push_back(track);
92 
93  }
94 
95  }
96 
97  return;
98 
99 }
100 
102 
103  std::map<int,std::vector<int> > firstTPC;
104  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
105  firstTPC[showerHitsIt->second.at(0)->WireID().TPC].push_back(showerHitsIt->first);
106 
107  // If all in the same TPC then that's great!
108  if (firstTPC.size() == 1)
109  return;
110 
111  // If they are in more than two TPCs, not much we can do
112  else if (firstTPC.size() > 2)
113  return;
114 
115  // If we get to this point, there should be something we can do!
116 
117  // Find the problem plane
118  int problemPlane = -1;
119  for (std::map<int,std::vector<int> >::iterator firstTPCIt = firstTPC.begin(); firstTPCIt != firstTPC.end(); ++firstTPCIt)
120  if (firstTPCIt->second.size() == 1)
121  problemPlane = firstTPCIt->second.at(0);
122 
123  // Require three hits
124  if (showerHitsMap.at(problemPlane).size() < 3)
125  return;
126 
127  // and get the other planes with at least three hits
128  std::vector<int> otherPlanes;
129  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
130  if (plane != problemPlane and
131  showerHitsMap.count(plane) and
132  showerHitsMap.at(plane).size() >= 3)
133  otherPlanes.push_back(plane);
134 
135  if (otherPlanes.size() == 0)
136  return;
137 
138  // Look at the hits after the first one
139  unsigned int wrongTPC = showerHitsMap.at(problemPlane).at(0)->WireID().TPC;
140  unsigned int nHits = 0;
141  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsMap.at(problemPlane).begin();
142  hitIt != showerHitsMap.at(problemPlane).end() and (*hitIt)->WireID().TPC == wrongTPC;
143  ++hitIt)
144  ++nHits;
145 
146  // If there are more than two hits in the 'wrong TPC', we can't be sure it is indeed wrong
147  if (nHits > 2)
148  return;
149 
150  // See if at least the next four times as many hits are in a different TPC
151  std::map<int,int> otherTPCs;
152  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = std::next(showerHitsMap.at(problemPlane).begin(),nHits);
153  hitIt != showerHitsMap.at(problemPlane).end() and std::distance(std::next(showerHitsMap.at(problemPlane).begin(),nHits),hitIt) < 4*nHits;
154  ++hitIt)
155  ++otherTPCs[(*hitIt)->WireID().TPC];
156 
157  if (otherTPCs.size() > 1)
158  return;
159 
160  // If we get this far, we can move the problem hits from the front of the shower to the back
161  std::map<int,int> tpcCount;
162  for (std::vector<int>::iterator otherPlaneIt = otherPlanes.begin(); otherPlaneIt != otherPlanes.end(); ++otherPlaneIt)
163  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = std::next(showerHitsMap.at(*otherPlaneIt).begin());
164  hitIt != showerHitsMap.at(*otherPlaneIt).end() and hitIt != std::next(showerHitsMap.at(*otherPlaneIt).begin(),2);
165  ++hitIt)
166  ++tpcCount[(*hitIt)->WireID().TPC];
167 
168  // Remove the first hit if it is in the wrong TPC
169  if (tpcCount.size() == 1 and tpcCount.begin()->first == (int)(*std::next(showerHitsMap.at(problemPlane).begin(),nHits))->WireID().TPC) {
170  std::vector<art::Ptr<recob::Hit> > naughty_hits;
171  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsMap.at(problemPlane).begin(); hitIt != std::next(showerHitsMap.at(problemPlane).begin(),nHits); ++hitIt) {
172  naughty_hits.push_back(*hitIt);
173  showerHitsMap.at(problemPlane).erase(hitIt);
174  }
175  for (std::vector<art::Ptr<recob::Hit> >::iterator naughty_hitIt = naughty_hits.begin(); naughty_hitIt != naughty_hits.end(); ++naughty_hitIt)
176  showerHitsMap.at(problemPlane).push_back(*naughty_hitIt);
177  }
178 
179  return;
180 
181 }
182 
183 bool shower::EMShowerAlg::CheckShowerHits(std::map<int,std::vector<art::Ptr<recob::Hit> > > const& showerHitsMap) {
184 
185  bool consistencyCheck = true;
186 
187  if (showerHitsMap.size() < 2)
188  consistencyCheck = true;
189 
190  else if (showerHitsMap.size() == 2) {
191 
192  // With two views, we can check:
193  // -- timing between views is consistent
194  // -- the 3D start point makes sense when projected back onto the individual planes
195 
196  std::vector<art::Ptr<recob::Hit> > startHits;
197  std::vector<int> planes;
198  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
199  startHits.push_back(showerHitsIt->second.front());
200  planes.push_back(showerHitsIt->first);
201  }
202 
203  TVector3 showerStartPos = Construct3DPoint(startHits.at(0), startHits.at(1));
204  TVector2 proj1 = Project3DPointOntoPlane(showerStartPos, planes.at(0));
205  TVector2 proj2 = Project3DPointOntoPlane(showerStartPos, planes.at(1));
206 
207  double timingDifference = TMath::Abs( startHits.at(0)->PeakTime() - startHits.at(1)->PeakTime() );
208  double projectionDifference = ( (HitPosition(startHits.at(0)) - proj1).Mod() + (HitPosition(startHits.at(1)) - proj2).Mod() ) / (double)2;
209 
210  if (timingDifference > 40 or
211  projectionDifference > 5 or
212  showerStartPos.X() == -9999 or showerStartPos.Y() == -9999 or showerStartPos.Z() == -9999)
213  consistencyCheck = false;
214 
215  if (fDebug > 1)
216  std::cout << "Timing difference is " << timingDifference << " and projection distance is " << projectionDifference << " (start is (" << showerStartPos.X() << ", " << showerStartPos.Y() << ", " << showerStartPos.Z() << ")" << std::endl;
217 
218  }
219 
220  else if (showerHitsMap.size() == 3) {
221 
222  // With three views, we can check:
223  // -- the timing between views is consistent
224  // -- the 3D start point formed by two views and projected back into the third is close to the start point in that view
225 
226  std::map<int,art::Ptr<recob::Hit> > start2DMap;
227  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitIt = showerHitsMap.begin(); showerHitIt != showerHitsMap.end(); ++showerHitIt)
228  start2DMap[showerHitIt->first] = showerHitIt->second.front();
229 
230  std::map<int,double> projDiff;
231  std::map<int,double> timingDiff;
232 
233  for (int plane = 0; plane < 3; ++plane) {
234 
235  std::vector<int> otherPlanes;
236  for (int otherPlane = 0; otherPlane < 3; ++otherPlane)
237  if (otherPlane != plane)
238  otherPlanes.push_back(otherPlane);
239 
240  TVector3 showerStartPos = Construct3DPoint(start2DMap.at(otherPlanes.at(0)), start2DMap.at(otherPlanes.at(1)));
241  TVector2 showerStartProj = Project3DPointOntoPlane(showerStartPos, plane);
242 
243  if (fDebug > 2) {
244  std::cout << "Plane... " << plane << std::endl;
245  std::cout << "Start position in this plane is " << HitPosition(start2DMap.at(plane)).X() << ", " << HitPosition(start2DMap.at(plane)).Y() << ")" << std::endl;
246  std::cout << "Shower start from other two planes is (" << showerStartPos.X() << ", " << showerStartPos.Y() << ", " << showerStartPos.Z() << ")" << std::endl;
247  std::cout << "Projecting the other two planes gives position (" << showerStartProj.X() << ", " << showerStartProj.Y() << ")" << std::endl;
248  }
249 
250  double projDiff = TMath::Abs((showerStartProj-HitPosition(start2DMap.at(plane))).Mod());
251  double timeDiff = TMath::Max(TMath::Abs(start2DMap.at(plane)->PeakTime() - start2DMap.at(otherPlanes.at(0))->PeakTime()),
252  TMath::Abs(start2DMap.at(plane)->PeakTime() - start2DMap.at(otherPlanes.at(1))->PeakTime()));
253 
254  if (fDebug > 1)
255  std::cout << "Plane " << plane << " has projDiff " << projDiff << " and timeDiff " << timeDiff << std::endl;
256 
257  if (projDiff > 5 or timeDiff > 40)
258  consistencyCheck = false;
259 
260  }
261 
262  }
263 
264  if (fDebug > 1)
265  std::cout << "Consistency check is " << consistencyCheck << std::endl;
266 
267  return consistencyCheck;
268 
269 }
270 
271 std::vector<int> shower::EMShowerAlg::CheckShowerPlanes(std::vector<std::vector<int> > const& initialShowers,
272  std::vector<art::Ptr<recob::Cluster> > const& clusters,
273  art::FindManyP<recob::Hit> const& fmh) {
274 
275  std::vector<int> clustersToIgnore;
276 
277  // // Look at each shower
278  // for (std::vector<std::vector<int> >::const_iterator initialShowerIt = initialShowers.begin(); initialShowerIt != initialShowers.end(); ++initialShowerIt) {
279 
280  // // Map the clusters and cluster hits to each view
281  // std::map<int,std::vector<art::Ptr<recob::Cluster> > > planeClusters;
282  // std::map<int,std::vector<art::Ptr<recob::Hit> > > planeClusterHits;
283  // for (std::vector<int>::const_iterator clusterIt = initialShowerIt->begin(); clusterIt != initialShowerIt->end(); ++clusterIt) {
284  // art::Ptr<recob::Cluster> cluster = clusters.at(*clusterIt);
285  // std::vector<art::Ptr<recob::Hit> > hits = fmh.at(cluster.key());
286  // planeClusters[cluster->Plane().Plane].push_back(cluster);
287  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt)
288  // planeClusterHits[cluster.key()].push_back(*hitIt);
289  // }
290 
291  // // Can't do much with fewer than three views
292  // if (planeClusters.size() < 3)
293  // continue;
294 
295  // // Look at the average RMS of clusters in each view
296  // std::map<int,double> avRMS;
297  // for (std::map<int,std::vector<art::Ptr<recob::Cluster> > >::iterator planeClusterIt = planeClusters.begin(); planeClusterIt != planeClusters.end(); ++planeClusterIt) {
298  // std::cout << "Plane " << planeClusterIt->first << std::endl;
299  // for (std::vector<art::Ptr<recob::Cluster> >::iterator clusterIt = planeClusterIt->second.begin(); clusterIt != planeClusterIt->second.end(); ++clusterIt) {
300  // double rms = ShowerHitRMS(planeClusterHits.at(clusterIt->key()));
301  // std::cout << "Cluster " << clusterIt->key() << " has RMS " << rms << std::endl;
302  // }
303  // }
304  // }
305 
306 
307  // Look at each shower
308  for (std::vector<std::vector<int> >::const_iterator initialShowerIt = initialShowers.begin(); initialShowerIt != initialShowers.end(); ++initialShowerIt) {
309 
310  if (std::distance(initialShowers.begin(),initialShowerIt) > 0)
311  continue;
312 
313  // Map the clusters and cluster hits to each view
314  std::map<int,std::vector<art::Ptr<recob::Cluster> > > planeClusters;
315  std::map<int,std::vector<art::Ptr<recob::Hit> > > planeHits;
316  for (std::vector<int>::const_iterator clusterIt = initialShowerIt->begin(); clusterIt != initialShowerIt->end(); ++clusterIt) {
317  art::Ptr<recob::Cluster> cluster = clusters.at(*clusterIt);
318  std::vector<art::Ptr<recob::Hit> > hits = fmh.at(cluster.key());
319  planeClusters[cluster->Plane().Plane].push_back(cluster);
320  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt)
321  planeHits[(*hitIt)->WireID().Plane].push_back(*hitIt);
322  }
323 
324  TFile* outFile = new TFile("chargeDistributions.root","RECREATE");
325  std::map<int,TH1D*> chargeDist;
326  for (std::map<int,std::vector<art::Ptr<recob::Cluster> > >::iterator planeIt = planeClusters.begin(); planeIt != planeClusters.end(); ++planeIt) {
327  for (std::vector<art::Ptr<recob::Cluster> >::iterator clusterIt = planeIt->second.begin(); clusterIt != planeIt->second.end(); ++clusterIt) {
328  chargeDist[planeIt->first] = new TH1D(std::string("chargeDist_Plane"+std::to_string(planeIt->first)+"_Cluster"+std::to_string(clusterIt->key())).c_str(),"",150,0,1000);
329  std::vector<art::Ptr<recob::Hit> > hits = fmh.at(clusterIt->key());
330  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt)
331  chargeDist[planeIt->first]->Fill((*hitIt)->Integral());
332  outFile->cd();
333  chargeDist[planeIt->first]->Write();
334  }
335  }
336  outFile->Close();
337  delete outFile;
338 
339  // Can't do much with fewer than three views
340  if (planeClusters.size() < 3)
341  continue;
342 
343  // Look at how many clusters each plane has, and the proportion of hits each one uses
344  std::map<int,std::vector<double> > planeClusterSizes;
345  for (std::map<int,std::vector<art::Ptr<recob::Cluster> > >::iterator planeClustersIt = planeClusters.begin(); planeClustersIt != planeClusters.end(); ++planeClustersIt) {
346  for (std::vector<art::Ptr<recob::Cluster> >::iterator planeClusterIt = planeClustersIt->second.begin(); planeClusterIt != planeClustersIt->second.end(); ++planeClusterIt) {
347  std::vector<art::Ptr<recob::Hit> > hits = fmh.at(planeClusterIt->key());
348  planeClusterSizes[planeClustersIt->first].push_back((double)hits.size()/(double)planeHits.at(planeClustersIt->first).size());
349  }
350  }
351 
352  // Find the average hit fraction across all clusters in the plane
353  std::map<int,double> planeClustersAvSizes;
354  for (std::map<int,std::vector<double> >::iterator planeClusterSizesIt = planeClusterSizes.begin(); planeClusterSizesIt != planeClusterSizes.end(); ++planeClusterSizesIt) {
355  double average = 0;
356  for (std::vector<double>::iterator planeClusterSizeIt = planeClusterSizesIt->second.begin(); planeClusterSizeIt != planeClusterSizesIt->second.end(); ++planeClusterSizeIt)
357  average += *planeClusterSizeIt;
358  average /= planeClusterSizesIt->second.size();
359  planeClustersAvSizes[planeClusterSizesIt->first] = average;
360  }
361 
362  // Now decide if there is one plane which is ruining the reconstruction
363  // If two planes have a low average cluster fraction and one high, this plane likely merges two particle deposits together
364  int badPlane = -1;
365  for (std::map<int,double>::iterator clusterAvSizeIt = planeClustersAvSizes.begin(); clusterAvSizeIt != planeClustersAvSizes.end(); ++clusterAvSizeIt) {
366 
367  // Get averages from other planes and add in quadrature
368  std::vector<double> otherAverages;
369  for (std::map<int,double>::iterator otherClustersAvSizeIt = planeClustersAvSizes.begin(); otherClustersAvSizeIt != planeClustersAvSizes.end(); ++otherClustersAvSizeIt)
370  if (clusterAvSizeIt->first != otherClustersAvSizeIt->first)
371  otherAverages.push_back(otherClustersAvSizeIt->second);
372  double quadOtherPlanes = 0;
373  for (std::vector<double>::iterator otherAvIt = otherAverages.begin(); otherAvIt != otherAverages.end(); ++otherAvIt)
374  quadOtherPlanes += TMath::Power(*otherAvIt,2);
375  quadOtherPlanes = TMath::Sqrt(quadOtherPlanes);
376 
377  // If this plane has an average higher than the quadratic sum of the others, it may be bad
378  if (clusterAvSizeIt->second >= quadOtherPlanes)
379  badPlane = clusterAvSizeIt->first;
380 
381  }
382 
383  if (badPlane != -1) {
384  if (fDebug > 1)
385  std::cout << "Bad plane is " << badPlane << std::endl;
386  for (std::vector<art::Ptr<recob::Cluster> >::iterator clusterIt = planeClusters.at(badPlane).begin(); clusterIt != planeClusters.at(badPlane).end(); ++clusterIt)
387  clustersToIgnore.push_back(clusterIt->key());
388  }
389 
390  }
391 
392  return clustersToIgnore;
393 
394 }
395 
397 
398  // x is average of the two x's
399  double x = (fDetProp->ConvertTicksToX(hit1->PeakTime(), hit1->WireID().planeID()) + fDetProp->ConvertTicksToX(hit2->PeakTime(), hit2->WireID().planeID())) / (double)2;
400 
401  // y and z got from the wire interections
402  geo::WireIDIntersection intersection;
403  fGeom->WireIDsIntersect(hit1->WireID(), hit2->WireID(), intersection);
404 
405  return TVector3(x, intersection.y, intersection.z);
406 
407 }
408 
409 std::unique_ptr<recob::Track> shower::EMShowerAlg::ConstructTrack(std::vector<art::Ptr<recob::Hit> > const& hits1,
410  std::vector<art::Ptr<recob::Hit> > const& hits2,
411  std::map<int,TVector2> const& showerCentreMap) {
412 
413  std::unique_ptr<recob::Track> track;
414 
415  std::vector<art::Ptr<recob::Hit> > track1, track2;
416 
417  // Check the TPCs
418  if ((*hits1.begin())->WireID().TPC != (*hits2.begin())->WireID().TPC) {
419  mf::LogWarning("EMShowerAlg") << "Warning: attempting to construct a track from two different TPCs. Returning a null track.";
420  return track;
421  }
422 
423  // Check for tracks crossing TPC boundaries
424  std::map<int,int> tpcMap;
425  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits1.begin(); hitIt != hits1.end(); ++hitIt)
426  ++tpcMap[(*hitIt)->WireID().TPC];
427  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits2.begin(); hitIt != hits2.end(); ++hitIt)
428  ++tpcMap[(*hitIt)->WireID().TPC];
429  if (tpcMap.size() > 1) {
430  mf::LogWarning("EMShowerAlg") << "Warning: attempting to construct a track which crosses more than one TPC -- PMTrack can't handle this right now. Returning a track made just from hits in the first TPC it traverses.";
431  unsigned int firstTPC1 = hits1.at(0)->WireID().TPC, firstTPC2 = hits2.at(0)->WireID().TPC;
432  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits1.begin(); hitIt != hits1.end(); ++hitIt)
433  if ((*hitIt)->WireID().TPC == firstTPC1) track1.push_back(*hitIt);
434  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = hits2.begin(); hitIt != hits2.end(); ++hitIt)
435  if ((*hitIt)->WireID().TPC == firstTPC2) track2.push_back(*hitIt);
436  }
437  else {
438  track1 = hits1;
439  track2 = hits2;
440  }
441 
442  if (fDebug > 1) {
443  std::cout << "About to make a track from these hits:" << std::endl;
444  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit1 = track1.begin(); hit1 != track1.end(); ++hit1)
445  std::cout << "Hit (" << HitCoordinates(*hit1).X() << ", " << HitCoordinates(*hit1).Y() << ") (real wire " << (*hit1)->WireID().Wire << ") in TPC " << (*hit1)->WireID().TPC << std::endl;
446  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit2 = track2.begin(); hit2 != track2.end(); ++hit2)
447  std::cout << "Hit (" << HitCoordinates(*hit2).X() << ", " << HitCoordinates(*hit2).Y() << ") (real wire " << (*hit2)->WireID().Wire << ") in TPC " << (*hit2)->WireID().TPC << std::endl;
448  }
449 
450  TVector3 trackStart = Construct3DPoint(track1.at(0), track2.at(0));
451  pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(track1, track2, trackStart);
452 
453  if (!pmatrack) {
454  mf::LogInfo("EMShowerAlg") << "Skipping this event because not enough hits in two views";
455  return track;
456  }
457 
458  std::vector<TVector3> xyz, dircos;
459  // std::vector<std::vector<double> > dEdx; // Right now, not finding the dE/dx for these tracks. Can extend if needed.
460 
461  for (unsigned int i = 0; i < pmatrack->size(); i++) {
462 
463  xyz.push_back((*pmatrack)[i]->Point3D());
464 
465  if (i < pmatrack->size()-1) {
466  size_t j = i+1;
467  double mag = 0.0;
468  TVector3 dc(0., 0., 0.);
469  while ((mag == 0.0) and (j < pmatrack->size())) {
470  dc = (*pmatrack)[j]->Point3D();
471  dc -= (*pmatrack)[i]->Point3D();
472  mag = dc.Mag();
473  ++j;
474  }
475  if (mag > 0.0) dc *= 1.0 / mag;
476  else if (!dircos.empty()) dc = dircos.back();
477  // TVector3 dc((*pmatrack)[i+1]->Point3D());
478  // dc -= (*pmatrack)[i]->Point3D();
479  // dc *= 1.0 / dc.Mag();
480  dircos.push_back(dc);
481  }
482  else dircos.push_back(dircos.back());
483 
484  }
485 
486  // Orient the track correctly
487  std::map<int,double> distanceToVertex, distanceToEnd;
488  TVector3 vertex = *xyz.begin(), end = *xyz.rbegin();
489 
490  // Loop over all the planes and find the distance from the vertex and end projections to the centre in each plane
491  for (std::map<int,TVector2>::const_iterator showerCentreIt = showerCentreMap.begin(); showerCentreIt != showerCentreMap.end(); ++showerCentreIt) {
492 
493  // Project the vertex and the end point onto this plane
494  TVector2 vertexProj = Project3DPointOntoPlane(vertex, showerCentreIt->first);
495  TVector2 endProj = Project3DPointOntoPlane(end, showerCentreIt->first);
496 
497  // Find the distance of each to the centre of the cluster
498  distanceToVertex[showerCentreIt->first] = (vertexProj - showerCentreIt->second).Mod();
499  distanceToEnd[showerCentreIt->first] = (endProj - showerCentreIt->second).Mod();
500 
501  }
502 
503  // Find the average distance to the vertex and the end across the planes
504  double avDistanceToVertex = 0, avDistanceToEnd = 0;
505  for (std::map<int,double>::iterator distanceToVertexIt = distanceToVertex.begin(); distanceToVertexIt != distanceToVertex.end(); ++distanceToVertexIt)
506  avDistanceToVertex += distanceToVertexIt->second;
507  avDistanceToVertex /= distanceToVertex.size();
508 
509  for (std::map<int,double>::iterator distanceToEndIt = distanceToEnd.begin(); distanceToEndIt != distanceToEnd.end(); ++distanceToEndIt)
510  avDistanceToEnd += distanceToEndIt->second;
511  if (distanceToEnd.size() != 0)
512  avDistanceToEnd /= distanceToEnd.size();
513 
514  if (fDebug > 2)
515  std::cout << "Distance to vertex is " << avDistanceToVertex << " and distance to end is " << avDistanceToEnd << std::endl;
516 
517  // Change order if necessary
518  if (avDistanceToEnd > avDistanceToVertex) {
519  std::reverse(xyz.begin(), xyz.end());
520  std::transform(dircos.begin(), dircos.end(), dircos.begin(), [](TVector3 const& vec){return -1*vec;});
521  }
522 
523  if (xyz.size() != dircos.size())
524  mf::LogError("EMShowerAlg") << "Problem converting pma::Track3D to recob::Track";
525 
526  track = std::make_unique<recob::Track>(recob::TrackTrajectory(recob::tracking::convertCollToPoint(xyz),
528  recob::Track::Flags_t(xyz.size()), false),
530 
531  return track;
532 
533 }
534 
535 std::unique_ptr<recob::Track> shower::EMShowerAlg::ConstructTrack(std::vector<art::Ptr<recob::Hit> > const& track1,
536  std::vector<art::Ptr<recob::Hit> > const& track2) {
537 
538  std::map<int,TVector2> showerCentreMap;
539 
540  return this->ConstructTrack(track1, track2, showerCentreMap);
541 
542 }
543 
544 double shower::EMShowerAlg::FinddEdx(std::vector<art::Ptr<recob::Hit> > const& trackHits, std::unique_ptr<recob::Track> const& track) {
545 
546  double totalCharge = 0, totalDistance = 0, avHitTime = 0;
547  unsigned int nHits = 0;
548 
549  if (!track)
550  return -999;
551 
552  // size_t trajectory_point = 0;
553  // double wirePitch = fGeom->WirePitch(trackHits.at(0)->View(), 1, 0);
554  // double angleToVert = fGeom->WireAngleToVertical(trackHits.at(0)->View(), 1, 0) - 0.5*::util::pi<>();
555  // const TVector3& dir = track->DirectionAtPoint(trajectory_point);
556  // //(sin(angleToVert),cos(angleToVert)) is the direction perpendicular to wire
557  // double cosgamma = std::abs(std::sin(angleToVert)*dir.Y() +
558  // std::cos(angleToVert)*dir.Z());
559 
560  // if(cosgamma < 1.e-5)
561  // throw cet::exception("Track") << "cosgamma is basically 0, that can't be right\n";
562  // double pitch = wirePitch/cosgamma;
563 
564  // Get the pitch
565  double pitch = 0;
566  try { pitch = lar::util::TrackPitchInView(*track, trackHits.at(0)->View()); }
567  catch(...) { pitch = 0; }
568 
569  // Deal with large pitches
570  if (pitch > fdEdxTrackLength) {
571  double dEdx = fCalorimetryAlg.dEdx_AREA(*trackHits.begin(), pitch);
572  return dEdx;
573  }
574 
575  for (std::vector<art::Ptr<recob::Hit> >::const_iterator trackHitIt = trackHits.begin(); trackHitIt != trackHits.end(); ++trackHitIt) {
576  if (totalDistance + pitch < fdEdxTrackLength) {
577  totalDistance += pitch;
578  totalCharge += (*trackHitIt)->Integral();
579  avHitTime += (*trackHitIt)->PeakTime();
580  ++nHits;
581  }
582  }
583 
584  avHitTime /= (double)nHits;
585 
586  double dQdx = totalCharge / totalDistance;
587  double dEdx = fCalorimetryAlg.dEdx_AREA(dQdx, avHitTime, trackHits.at(0)->WireID().Plane);
588 
589  return dEdx;
590 
591 }
592 
593 void shower::EMShowerAlg::FindInitialTrack(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap,
594  std::unique_ptr<recob::Track>& initialTrack,
595  std::map<int,std::vector<art::Ptr<recob::Hit> > >& initialTrackHits, int plane) {
596 
601 
602  // // First, order the hits into the correct shower order in each plane
603  // if (fDebug > 1)
604  // std::cout << " ------------------ Ordering shower hits -------------------- " << std::endl;
605  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHitsMap = OrderShowerHits(hits, plane);
606  // if (fDebug > 1)
607  // std::cout << " ------------------ End ordering shower hits -------------------- " << std::endl;
608 
609  // Now find the hits belonging to the track
610  if (fDebug > 1)
611  std::cout << " ------------------ Finding initial track hits -------------------- " << std::endl;
612  initialTrackHits = FindShowerStart(showerHitsMap);
613  if (fDebug > 1) {
614  std::cout << "Here are the initial shower hits... " << std::endl;
615  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator initialTrackHitsIt = initialTrackHits.begin(); initialTrackHitsIt != initialTrackHits.end(); ++initialTrackHitsIt) {
616  std::cout << " Plane " << initialTrackHitsIt->first << std::endl;
617  for (std::vector<art::Ptr<recob::Hit> >::iterator initialTrackHitIt = initialTrackHitsIt->second.begin(); initialTrackHitIt != initialTrackHitsIt->second.end(); ++initialTrackHitIt)
618  std::cout << " Hit is (" << HitCoordinates(*initialTrackHitIt).X() << " (real hit " << (*initialTrackHitIt)->WireID() << "), " << HitCoordinates(*initialTrackHitIt).Y() << ")" << std::endl;
619  }
620  }
621  if (fDebug > 1)
622  std::cout << " ------------------ End finding initial track hits -------------------- " << std::endl;
623 
624  // Now we have the track hits -- can make a track!
625  if (fDebug > 1)
626  std::cout << " ------------------ Finding initial track -------------------- " << std::endl;
627  initialTrack = MakeInitialTrack(initialTrackHits, showerHitsMap);
628  if (initialTrack and fDebug > 1) {
629  std::cout << "The track start is (" << initialTrack->Vertex().X() << ", " << initialTrack->Vertex().Y() << ", " << initialTrack->Vertex().Z() << ")" << std::endl;
630  std::cout << "The track direction is (" << initialTrack->VertexDirection().X() << ", " << initialTrack->VertexDirection().Y() << ", " << initialTrack->VertexDirection().Z() << ")" << std::endl;
631  }
632  if (fDebug > 1)
633  std::cout << " ------------------ End finding initial track -------------------- " << std::endl;
634 
635  // // Fill correct or incorrect direction histogram
636  // std::map<int,int> trackHits;
637  // for (art::PtrVector<recob::Hit>::const_iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt)
638  // ++trackHits[FindTrackID(*hitIt)];
639  // int trueTrack = -9999;
640  // for (std::map<int,int>::iterator trackHitIt = trackHits.begin(); trackHitIt != trackHits.end(); ++trackHitIt)
641  // if (trackHitIt->second/(double)hits.size() > 0.8)
642  // trueTrack = trackHitIt->first;
643  // if (trueTrack != -9999) {
644  // const simb::MCParticle* trueParticle = backtracker->TrackIDToParticle(trueTrack);
645  // TVector3 trueStart = trueParticle->Position().Vect();
646  // if (initialTrack) {
647  // TVector3 recoStart = initialTrack->Vertex();
648  // if ((recoStart-trueStart).Mag() < 5)
649  // hTrueDirection->Fill(1);
650  // else
651  // hTrueDirection->Fill(0);
652  // }
653  // }
654  // else
655  // hTrueDirection->Fill(0);
656 
657  return;
658 
659 }
660 
661 std::vector<art::Ptr<recob::Hit> > shower::EMShowerAlg::FindOrderOfHits(std::vector<art::Ptr<recob::Hit> > const& hits, bool perpendicular) {
662 
663  // Find the charge-weighted centre (in [cm]) of this shower
664  TVector2 centre = ShowerCentre(hits);
665 
666  // Find a rough shower 'direction'
667  TVector2 direction = ShowerDirection(hits);
668 
669  if (perpendicular)
670  direction = direction.Rotate(TMath::Pi()/2);
671 
672  // Find how far each hit (projected onto this axis) is from the centre
673  TVector2 pos;
674  std::map<double,art::Ptr<recob::Hit> > hitProjection;
675  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = hits.begin(); hit != hits.end(); ++hit) {
676  pos = HitPosition(*hit) - centre;
677  hitProjection[direction*pos] = *hit;
678  }
679 
680  // Get a vector of hits in order of the shower
681  std::vector<art::Ptr<recob::Hit> > showerHits;
682  std::transform(hitProjection.begin(), hitProjection.end(), std::back_inserter(showerHits), [](std::pair<double,art::Ptr<recob::Hit> > const& hit) { return hit.second; });
683 
684  // Make gradient plot
685  if (fMakeGradientPlot) {
686  std::map<int,TGraph*> graphs;
687  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHits.begin(); hitIt != showerHits.end(); ++hitIt) {
688  int tpc = (*hitIt)->WireID().TPC;
689  if (graphs[tpc] == nullptr)
690  graphs[tpc] = new TGraph();
691  graphs[tpc]->SetPoint(graphs[tpc]->GetN(), HitPosition(*hitIt).X(), HitPosition(*hitIt).Y());
692  //graphs[tpc]->SetPoint(graphs[tpc]->GetN(), HitCoordinates(*hitIt).X(), HitCoordinates(*hitIt).Y());
693  }
694  TMultiGraph* multigraph = new TMultiGraph();
695  for (std::map<int,TGraph*>::iterator graphIt = graphs.begin(); graphIt != graphs.end(); ++graphIt) {
696  graphIt->second->SetMarkerColor(graphIt->first);
697  graphIt->second->SetMarkerStyle(8);
698  graphIt->second->SetMarkerSize(2);
699  multigraph->Add(graphIt->second);
700  }
701  TCanvas* canvas = new TCanvas();
702  multigraph->Draw("AP");
703  TLine line;
704  line.SetLineColor(2);
705  line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
706  canvas->SaveAs("Gradient.png");
707  delete canvas; delete multigraph;
708  }
709 
710  return showerHits;
711 
712 }
713 
714 std::vector<std::vector<int> > shower::EMShowerAlg::FindShowers(std::map<int,std::vector<int> > const& trackToClusters) {
715 
716  // Showers are vectors of clusters
717  std::vector<std::vector<int> > showers;
718 
719  // Loop over all tracks
720  for (std::map<int,std::vector<int> >::const_iterator trackToClusterIt = trackToClusters.begin(); trackToClusterIt != trackToClusters.end(); ++ trackToClusterIt) {
721 
722  // Find which showers already made are associated with this track
723  std::vector<int> matchingShowers;
724  for (unsigned int shower = 0; shower < showers.size(); ++shower)
725  for (std::vector<int>::const_iterator cluster = trackToClusterIt->second.begin(); cluster != trackToClusterIt->second.end(); ++cluster)
726  if ( (std::find(showers.at(shower).begin(), showers.at(shower).end(), *cluster) != showers.at(shower).end()) and
727  (std::find(matchingShowers.begin(), matchingShowers.end(), shower)) == matchingShowers.end() )
728  matchingShowers.push_back(shower);
729 
730  // THINK THERE PROBABLY CAN BE MORE THAN ONE!
731  // IN FACT, THIS WOULD BE A SUCCESS OF THE SHOWERING METHOD!
732  // // Shouldn't be more than one
733  // if (matchingShowers.size() > 1)
734  // mf::LogInfo("EMShowerAlg") << "Number of showers this track matches is " << matchingShowers.size() << std::endl;
735 
736  // New shower
737  if (matchingShowers.size() < 1)
738  showers.push_back(trackToClusterIt->second);
739 
740  // Add to existing shower
741  else {
742  for (std::vector<int>::const_iterator cluster = trackToClusterIt->second.begin(); cluster != trackToClusterIt->second.end(); ++cluster)
743  if (std::find(showers.at(matchingShowers.at(0)).begin(), showers.at(matchingShowers.at(0)).end(), *cluster) == showers.at(matchingShowers.at(0)).end())
744  showers.at(matchingShowers.at(0)).push_back(*cluster);
745  }
746  }
747 
748  return showers;
749 
750 }
751 
752 std::map<int,std::vector<art::Ptr<recob::Hit> > > shower::EMShowerAlg::FindShowerStart(std::map<int,std::vector<art::Ptr<recob::Hit> > > const& orderedShowerMap) {
753 
754  std::map<int,std::vector<art::Ptr<recob::Hit> > > initialHitsMap;
755 
756  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator orderedShowerIt = orderedShowerMap.begin(); orderedShowerIt != orderedShowerMap.end(); ++orderedShowerIt) {
757 
758  std::vector<art::Ptr<recob::Hit> > initialHits;
759  const std::vector<art::Ptr<recob::Hit> > orderedShower = orderedShowerIt->second;
760 
761  // Find if the shower is travelling along ticks or wires
762  bool wireDirection = true;
763  std::vector<int> wires;
764  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
765  wires.push_back(std::round(HitCoordinates(*hitIt).X()));
766  std::sort(wires.begin(), wires.end());
767  if (TMath::Abs(*wires.begin()-std::round(HitCoordinates(*orderedShower.begin()).X())) > 3 and
768  TMath::Abs(*wires.rbegin()-std::round(HitCoordinates(*orderedShower.begin()).X())) > 3)
769  wireDirection = false;
770 
771  // Deal with showers travelling along wires
772  if (wireDirection) {
773  bool increasing = HitCoordinates(*orderedShower.rbegin()).X() > HitCoordinates(*orderedShower.begin()).X();
774  std::map<int,std::vector<art::Ptr<recob::Hit> > > wireHitMap;
775  int multipleWires = 0;
776  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
777  wireHitMap[std::round(HitCoordinates(*hitIt).X())].push_back(*hitIt);
778  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt) {
779  int wire = std::round(HitCoordinates(*hitIt).X());
780  if (wireHitMap[wire].size() > 1) {
781  ++multipleWires;
782  if (multipleWires > 5) break;
783  continue;
784  }
785  else if ( (increasing and wireHitMap[wire+1].size() > 1 and (wireHitMap[wire+2].size() > 1 or wireHitMap[wire+3].size() > 1)) or
786  (!increasing and wireHitMap[wire-1].size() > 1 and (wireHitMap[wire-2].size() > 1 or wireHitMap[wire-3].size() > 1)) ) {
787  if ( (increasing and (wireHitMap[wire+4].size() < 2 and wireHitMap[wire+5].size() < 2 and wireHitMap[wire+6].size() < 2 and wireHitMap[wire+9].size() > 1)) or
788  (!increasing and (wireHitMap[wire-4].size() < 2 and wireHitMap[wire-5].size() < 2 and wireHitMap[wire-6].size() < 2) and wireHitMap[wire-9].size() > 1) )
789  initialHits.push_back(*hitIt);
790  else
791  break;
792  }
793  else
794  initialHits.push_back(*hitIt);
795  }
796  if (!initialHits.size()) initialHits.push_back(*orderedShower.begin());
797  }
798 
799  // Deal with showers travelling along ticks
800  else {
801  bool increasing = HitCoordinates(*orderedShower.rbegin()).Y() > HitCoordinates(*orderedShower.begin()).Y();
802  std::map<int,std::vector<art::Ptr<recob::Hit> > > tickHitMap;
803  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
804  tickHitMap[std::round(HitCoordinates(*hitIt).Y())].push_back(*hitIt);
805  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt) {
806  int tick = std::round(HitCoordinates(*hitIt).Y());
807  if ( (increasing and (tickHitMap[tick+1].size() or tickHitMap[tick+2].size() or tickHitMap[tick+3].size() or tickHitMap[tick+4].size() or tickHitMap[tick+5].size())) or
808  (!increasing and (tickHitMap[tick-1].size() or tickHitMap[tick-2].size() or tickHitMap[tick-3].size() or tickHitMap[tick-4].size() or tickHitMap[tick-5].size())) )
809  break;
810  else
811  initialHits.push_back(*hitIt);
812  }
813  if (!initialHits.size()) initialHits.push_back(*orderedShower.begin());
814  }
815 
816  // Need at least two hits to make a track
817  if (initialHits.size() == 1 and orderedShower.size() > 2)
818  initialHits.push_back(orderedShower.at(1));
819 
820  // Quality check -- make sure there isn't a single hit in a different TPC (artefact of tracking failure)
821  std::vector<art::Ptr<recob::Hit> > newInitialHits;
822  std::map<int,int> tpcHitMap;
823  std::vector<int> singleHitTPCs;
824  for (std::vector<art::Ptr<recob::Hit> >::iterator initialHitIt = initialHits.begin(); initialHitIt != initialHits.end(); ++initialHitIt)
825  ++tpcHitMap[(*initialHitIt)->WireID().TPC];
826  for (std::map<int,int>::iterator tpcIt = tpcHitMap.begin(); tpcIt != tpcHitMap.end(); ++tpcIt)
827  if (tpcIt->second == 1) singleHitTPCs.push_back(tpcIt->first);
828  if (singleHitTPCs.size()) {
829  if (fDebug > 2)
830  for (std::vector<int>::iterator tpcIt = singleHitTPCs.begin(); tpcIt != singleHitTPCs.end(); ++tpcIt)
831  std::cout << "Removed hits in TPC " << *tpcIt << std::endl;
832  for (std::vector<art::Ptr<recob::Hit> >::iterator initialHitIt = initialHits.begin(); initialHitIt != initialHits.end(); ++initialHitIt)
833  if (std::find(singleHitTPCs.begin(), singleHitTPCs.end(), (*initialHitIt)->WireID().TPC) == singleHitTPCs.end())
834  newInitialHits.push_back(*initialHitIt);
835  if (!newInitialHits.size()) newInitialHits.push_back(*orderedShower.begin());
836  }
837  else
838  newInitialHits = initialHits;
839 
840  initialHitsMap[orderedShowerIt->first] = newInitialHits;
841 
842  }
843 
844  return initialHitsMap;
845 
846 }
847 
848 std::map<int,std::map<int,bool> > shower::EMShowerAlg::GetPlanePermutations(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
849 
850  // The map to return
851  std::map<int,std::map<int,bool> > permutations;
852 
853  // Get the properties of the shower hits across the planes which will be used to
854  // determine the likelihood of a particular reorientation permutation
855  // -- relative width in the wire direction (if showers travel along the wire
856  // direction in a particular plane)
857  // -- the RMS gradients (how likely it is the RMS of the hit positions from
858  // central axis increases along a particular orientation)
859 
860  // Find the RMS, RMS gradient and wire widths
861  std::map<int,double> planeRMSGradients, planeRMS;
862  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
863  planeRMS[showerHitsIt->first] = ShowerHitRMS(showerHitsIt->second);
864  planeRMSGradients[showerHitsIt->first] = ShowerHitRMSGradient(showerHitsIt->second);
865  }
866 
867  // Order these backwards so they can be used to discriminate between planes
868  std::map<double,int> gradientMap;
869  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
870  gradientMap[TMath::Abs(planeRMSGradients.at(showerHitsIt->first))] = showerHitsIt->first;
871 
872  std::map<double,int> wireWidthMap = RelativeWireWidth(showerHitsMap);
873 
874  if (fDebug > 1)
875  for (std::map<double,int>::const_iterator wireWidthIt = wireWidthMap.begin(); wireWidthIt != wireWidthMap.end(); ++wireWidthIt)
876  std::cout << "Plane " << wireWidthIt->second << " has relative width in wire of " << wireWidthIt->first << "; and an RMS gradient of " << planeRMSGradients[wireWidthIt->second] << std::endl;
877 
878  // Find the correct permutations
879  int perm = 0;
880  std::vector<std::map<int,bool> > usedPermutations;
881 
882  // Most likely is to not change anything
883  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
884  permutations[perm][showerHitsIt->first] = 0;
885  ++perm;
886 
887  // Use properties of the shower to determine the middle cases
888  for (std::map<double,int>::iterator wireWidthIt = wireWidthMap.begin(); wireWidthIt != wireWidthMap.end(); ++wireWidthIt) {
889  std::map<int,bool> permutation;
890  permutation[wireWidthIt->second] = 1;
891  for (std::map<double,int>::iterator wireWidth2It = wireWidthMap.begin(); wireWidth2It != wireWidthMap.end(); ++wireWidth2It)
892  if (wireWidthIt->second != wireWidth2It->second)
893  permutation[wireWidth2It->second] = 0;
894  if (std::find(usedPermutations.begin(), usedPermutations.end(), permutation) == usedPermutations.end()) {
895  permutations[perm] = permutation;
896  usedPermutations.push_back(permutation);
897  ++perm;
898  }
899  }
900  for (std::map<double,int>::reverse_iterator wireWidthIt = wireWidthMap.rbegin(); wireWidthIt != wireWidthMap.rend(); ++wireWidthIt) {
901  std::map<int,bool> permutation;
902  permutation[wireWidthIt->second] = 0;
903  for (std::map<double,int>::iterator wireWidth2It = wireWidthMap.begin(); wireWidth2It != wireWidthMap.end(); ++wireWidth2It)
904  if (wireWidthIt->second != wireWidth2It->second)
905  permutation[wireWidth2It->second] = 1;
906  if (std::find(usedPermutations.begin(), usedPermutations.end(), permutation) == usedPermutations.end()) {
907  permutations[perm] = permutation;
908  usedPermutations.push_back(permutation);
909  ++perm;
910  }
911  }
912 
913  // Least likely is to change everything
914  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
915  permutations[perm][showerHitsIt->first] = 1;
916  ++perm;
917 
918  if (fDebug > 1) {
919  std::cout << "Here are the permutations!" << std::endl;
920  for (std::map<int,std::map<int,bool> >::iterator permIt = permutations.begin(); permIt != permutations.end(); ++permIt) {
921  std::cout << "Permutation " << permIt->first << std::endl;
922  for (std::map<int,bool>::iterator planePermIt = permIt->second.begin(); planePermIt != permIt->second.end(); ++planePermIt)
923  std::cout << " Plane " << planePermIt->first << " has value " << planePermIt->second << std::endl;
924  }
925  }
926 
927  return permutations;
928 
929 }
930 
931 std::unique_ptr<recob::Track> shower::EMShowerAlg::MakeInitialTrack(std::map<int,std::vector<art::Ptr<recob::Hit> > > const& initialHitsMap,
932  std::map<int,std::vector<art::Ptr<recob::Hit> > > const& showerHitsMap) {
933 
934  // Can't do much with just one view
935  if (initialHitsMap.size() < 2) {
936  mf::LogInfo("EMShowerAlg") << "Only one useful view for this shower; nothing can be done" << std::endl;
937  return std::unique_ptr<recob::Track>();
938  }
939 
940  std::vector<std::pair<int,int> > initialHitsSize;
941  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator initialHitIt = initialHitsMap.begin(); initialHitIt != initialHitsMap.end(); ++initialHitIt)
942  initialHitsSize.push_back(std::make_pair(initialHitIt->first, initialHitIt->second.size()));
943 
944  // Sort the planes by number of hits
945  std::sort(initialHitsSize.begin(), initialHitsSize.end(), [](std::pair<int,int> const& size1, std::pair<int,int> const& size2) { return size1.second > size2.second; });
946 
947  // Pick the two planes to use to make the track
948  // -- if more than two planes, can choose the two views
949  // more accurately
950  // -- if not, just use the two views available
951 
952  std::vector<int> planes;
953 
954  if (initialHitsSize.size() > 2 and !CheckShowerHits(showerHitsMap)) {
955  int planeToIgnore = WorstPlane(showerHitsMap);
956  if (fDebug > 1)
957  std::cout << "Igoring plane " << planeToIgnore << " in creation of initial track" << std::endl;
958  for (std::vector<std::pair<int,int> >::iterator hitsSizeIt = initialHitsSize.begin(); hitsSizeIt != initialHitsSize.end() and planes.size() < 2; ++hitsSizeIt) {
959  if (hitsSizeIt->first == planeToIgnore)
960  continue;
961  planes.push_back(hitsSizeIt->first);
962  }
963  }
964  else
965  planes = {initialHitsSize.at(0).first, initialHitsSize.at(1).first};
966 
967  return ConstructTrack(initialHitsMap.at(planes.at(0)), initialHitsMap.at(planes.at(1)));
968 
969 }
970 
972  std::unique_ptr<recob::Track> const& initialTrack,
973  std::map<int,std::vector<art::Ptr<recob::Hit> > > const& initialHitsMap) {
974 
975  //return recob::Shower();
976 
977  // Find the shower hits on each plane
978  std::map<int,std::vector<art::Ptr<recob::Hit> > > planeHitsMap;
979  for (art::PtrVector<recob::Hit>::const_iterator hit = hits.begin(); hit != hits.end(); ++hit)
980  planeHitsMap[(*hit)->View()].push_back(*hit);
981 
982  int bestPlane = -1;
983  unsigned int highestNumberOfHits = 0;
984  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
985 
986  // Look at each of the planes
987  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
988 
989  // If there's hits on this plane...
990  if (planeHitsMap.count(plane)) {
991  dEdx.push_back(FinddEdx(initialHitsMap.at(plane), initialTrack));
992  totalEnergy.push_back(fShowerEnergyAlg.ShowerEnergy(planeHitsMap.at(plane), plane));
993  if (planeHitsMap.at(plane).size() > highestNumberOfHits and initialHitsMap.count(plane)) {
994  bestPlane = plane;
995  highestNumberOfHits = planeHitsMap.at(plane).size();
996  }
997  }
998 
999  // If not...
1000  else {
1001  dEdx.push_back(0);
1002  totalEnergy.push_back(0);
1003  }
1004 
1005  }
1006 
1007  TVector3 direction, directionError, showerStart, showerStartError;
1008  if (initialTrack) {
1009  direction = initialTrack->VertexDirection<TVector3>();
1010  showerStart = initialTrack->Vertex<TVector3>();
1011  }
1012 
1013  if (fDebug > 0) {
1014  std::cout << "Best plane is " << bestPlane << std::endl;
1015  std::cout << "dE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and " << dEdx[2] << std::endl;
1016  std::cout << "Total energy for each plane is: " << totalEnergy[0] << ", " << totalEnergy[1] << " and " << totalEnergy[2] << std::endl;
1017  std::cout << "The shower start is (" << showerStart.X() << ", " << showerStart.Y() << ", " << showerStart.Z() << ")" << std::endl;
1018  std::cout << "The shower direction is (" << direction.X() << ", " << direction.Y() << ", " << direction.Z() << ")" << std::endl;
1019  }
1020 
1021  return recob::Shower(direction, directionError, showerStart, showerStartError, totalEnergy, totalEnergyError, dEdx, dEdxError, bestPlane);
1022 
1023 }
1024 
1027  int & iok) {
1028 
1029  iok = 1;
1030 
1031  // Find the shower hits on each plane
1032  std::map<int,std::vector<art::Ptr<recob::Hit> > > planeHitsMap;
1033  for (art::PtrVector<recob::Hit>::const_iterator hit = hits.begin(); hit != hits.end(); ++hit)
1034  planeHitsMap[(*hit)->WireID().Plane].push_back(*hit);
1035 
1036  std::vector<std::vector<art::Ptr<recob::Hit> > > initialTrackHits(3);
1037 
1038  int pl0 = -1;
1039  int pl1 = -1;
1040  unsigned maxhits0 = 0;
1041  unsigned maxhits1 = 0;
1042 
1043  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeHits = planeHitsMap.begin(); planeHits != planeHitsMap.end(); ++planeHits) {
1044 
1045  std::vector<art::Ptr<recob::Hit> > showerHits;
1046  OrderShowerHits(planeHits->second, showerHits, vertex);
1047  //if (!isCleanShower(showerHits)) continue;
1048  FindInitialTrackHits(showerHits, vertex, initialTrackHits[planeHits->first]);
1049  if ((planeHits->second).size()>maxhits0){
1050  if (pl0!=-1){
1051  maxhits1 = maxhits0;
1052  pl1 = pl0;
1053  }
1054  pl0 = planeHits->first;
1055  maxhits0 = (planeHits->second).size();
1056  }
1057  else if ((planeHits->second).size()>maxhits1){
1058  pl1 = planeHits->first;
1059  maxhits1 = (planeHits->second).size();
1060  }
1061 
1062  }
1063  //std::cout<<pl0<<" "<<pl1<<std::endl;
1064 // if (pl0!=-1&&pl1!=-1) {
1065 // pl0 = 1;
1066 // pl1 = 2;
1067 // }
1068  if (pl0!=-1&&pl1!=-1
1069  &&initialTrackHits[pl0].size()>=2
1070  &&initialTrackHits[pl1].size()>=2
1071  &&initialTrackHits[pl0][0]->WireID().TPC==
1072  initialTrackHits[pl1][0]->WireID().TPC){
1073  double xyz[3];
1074  vertex->XYZ(xyz);
1075  TVector3 vtx(xyz);
1076 // std::vector<art::Ptr<recob::Hit>> alltrackhits;
1077 // for (size_t i = 0; i<3; ++i){
1078 // for (auto const&hit : initialTrackHits[i]){
1079 // alltrackhits.push_back(hit);
1080 // }
1081 // }
1082  //std::cout<<"vertex "<<xyz[0]<<" "<<xyz[1]<<" "<<xyz[2]<<std::endl;
1083  //for (auto const&hit : initialTrackHits[pl0]) std::cout<<*hit<<std::endl;
1084  //for (auto const&hit : initialTrackHits[pl1]) std::cout<<*hit<<std::endl;
1085  pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(initialTrackHits[pl0], initialTrackHits[pl1]);
1086  //std::cout<<pmatrack->size()<<std::endl;
1087  //pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(alltrackhits);
1088  std::vector<TVector3> spts;
1089 
1090 // points are shifted now by tracking code, commented out shifts here
1091 // double xshift = pmatrack->GetXShift();
1092 // bool has_shift = (xshift != 0.0);
1093  for (size_t i = 0; i<pmatrack->size(); ++i){
1094  if ((*pmatrack)[i]->IsEnabled()){
1095  TVector3 p3d = (*pmatrack)[i]->Point3D();
1096 // if (has_shift) p3d.SetX(p3d.X() + xshift);
1097  //std::cout<<p3d.X()<<" "<<p3d.Y()<<" "<<p3d.Z()<<std::endl;
1098  spts.push_back(p3d);
1099  }
1100  }
1101  if (spts.size()>=2){ //at least two space points
1102  TVector3 shwxyz, shwxyzerr;
1103  TVector3 shwdir, shwdirerr;
1104  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
1105  int bestPlane = pl0;
1106  double minpitch = 1000;
1107  std::vector<TVector3> dirs;
1108  if ((spts[0]-vtx).Mag()<(spts.back()-vtx).Mag()){
1109  shwxyz = spts[0];
1110  size_t i = 5;
1111  if (spts.size()-1<5) i = spts.size()-1;
1112  shwdir = spts[i] - spts[0];
1113  shwdir = shwdir.Unit();
1114  }
1115  else{
1116  shwxyz = spts.back();
1117  size_t i = 0;
1118  if (spts.size()>6) i = spts.size() - 6;
1119  shwdir = spts[i] - spts[spts.size()-1];
1120  shwdir = shwdir.Unit();
1121  }
1122  //std::cout<<shwxyz.X()<<" "<<shwxyz.Y()<<" "<<shwxyz.Z()<<std::endl;
1123  //std::cout<<shwdir.X()<<" "<<shwdir.Y()<<" "<<shwdir.Z()<<std::endl;
1124  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
1125  if (planeHitsMap.find(plane)!=planeHitsMap.end()){
1126  totalEnergy.push_back(fShowerEnergyAlg.ShowerEnergy(planeHitsMap[plane], plane));
1127  }
1128  else{
1129  totalEnergy.push_back(0);
1130  }
1131  if (initialTrackHits[plane].size()){
1132  double fdEdx = 0;
1133  double totQ = 0;
1134  double avgT = 0;
1135  double pitch = 0;
1136  double wirepitch = fGeom->WirePitch(initialTrackHits[plane][0]->WireID().planeID());
1137  double angleToVert = fGeom->WireAngleToVertical(fGeom->Plane(plane).View(),initialTrackHits[plane][0]->WireID().planeID()) - 0.5*TMath::Pi();
1138  double cosgamma = std::abs(sin(angleToVert)*shwdir.Y()+
1139  cos(angleToVert)*shwdir.Z());
1140  if (cosgamma>0) pitch = wirepitch/cosgamma;
1141  if (pitch){
1142  if (pitch<minpitch){
1143  minpitch = pitch;
1144  bestPlane = plane;
1145  }
1146  int nhits = 0;
1147  //std::cout<<"pitch = "<<pitch<<std::endl;
1148  std::vector<float> vQ;
1149  for (auto const& hit: initialTrackHits[plane]){
1150  //std::cout<<hit->WireID()<<" "<<hit->PeakTime()<<" "<<std::abs((hit->WireID().Wire-initialTrackHits[plane][0]->WireID().Wire)*pitch)<<" "<<fdEdxTrackLength<<std::endl;
1151  int w1 = hit->WireID().Wire;
1152  int w0 = initialTrackHits[plane][0]->WireID().Wire;
1153  if (std::abs((w1-w0)*pitch)<fdEdxTrackLength){
1154  vQ.push_back(hit->Integral());
1155  totQ += hit->Integral();
1156  avgT+= hit->PeakTime();
1157  ++nhits;
1158  //std::cout<<hit->WireID()<<" "<<hit->PeakTime()<<" "<<hit->Integral()<<" "<<totQ<<" "<<avgT<<std::endl;
1159  }
1160  }
1161  if (totQ) {
1162  //double dQdx = totQ/(nhits*pitch);
1163  //std::sort(vQ.begin(), vQ.end());
1164  //double dQdx = vQ[vQ.size()/2]/pitch;
1165  double dQdx = TMath::Median(vQ.size(), &vQ[0])/pitch;
1166  fdEdx = fCalorimetryAlg.dEdx_AREA(dQdx, avgT/nhits, initialTrackHits[plane][0]->WireID().Plane);
1167  }
1168  }
1169  dEdx.push_back(fdEdx);
1170  }
1171  else{
1172  dEdx.push_back(0);
1173  }
1174  }
1175  iok = 0;
1176  if (fDebug > 1) {
1177  std::cout << "Best plane is " << bestPlane << std::endl;
1178  std::cout << "dE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and " << dEdx[2] << std::endl;
1179  std::cout << "Total energy for each plane is: " << totalEnergy[0] << ", " << totalEnergy[1] << " and " << totalEnergy[2] << std::endl;
1180  std::cout << "The shower start is (" << shwxyz.X() << ", " << shwxyz.Y() << ", " << shwxyz.Z() << ")" << std::endl;
1181  shwxyz.Print();
1182  }
1183 
1184  return recob::Shower(shwdir, shwdirerr, shwxyz, shwxyzerr, totalEnergy, totalEnergyError, dEdx, dEdxError, bestPlane);
1185  }
1186  }
1187  return recob::Shower();
1188 }
1189 
1190 std::vector<recob::SpacePoint> shower::EMShowerAlg::MakeSpacePoints(std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHits,
1192 
1193  // Space points to return
1194  std::vector<recob::SpacePoint> spacePoints;
1195 
1196  // // Order by charge
1197  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeIt = showerHits.begin(); planeIt != showerHits.end(); ++planeIt)
1198  // std::sort(planeIt->second.begin(), planeIt->second.end(), [](const art::Ptr<recob::Hit>& h1, const art::Ptr<recob::Hit>& h2) { return h1->Integral() > h2->Integral(); });
1199 
1200  // Make space points
1201  // Use the following procedure:
1202  // -- Consider hits plane by plane
1203  // -- For each hit on the first plane, consider the 3D point made by combining with each hit from the second plane
1204  // -- Project this 3D point back into the two planes
1205  // -- Determine how close to a the original hits this point lies
1206  // -- If close enough, make a 3D space point from this point
1207  // // -- Discard these used hits in future iterations, along with hits in the
1208  // // third plane (if exists) close to the projection of the point into this plane
1209 
1210  // Container to hold used hits
1211  std::vector<int> usedHits;
1212 
1213  // Look through plane by plane
1214  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitIt = showerHits.begin(); showerHitIt != showerHits.end(); ++showerHitIt) {
1215 
1216  // Find the other planes with hits
1217  std::vector<int> otherPlanes;
1218  for (unsigned int otherPlane = 0; otherPlane < fGeom->MaxPlanes(); ++otherPlane)
1219  if ((int)otherPlane != showerHitIt->first and showerHits.count(otherPlane))
1220  otherPlanes.push_back(otherPlane);
1221 
1222  // Can't make space points if we only have one view
1223  if (otherPlanes.size() == 0)
1224  return spacePoints;
1225 
1226  // Look at all hits on this plane
1227  for (std::vector<art::Ptr<recob::Hit> >::const_iterator planeHitIt = showerHitIt->second.begin(); planeHitIt != showerHitIt->second.end(); ++planeHitIt) {
1228 
1229  if (std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) != usedHits.end())
1230  continue;
1231 
1232  // Make a 3D point with every hit on the second plane
1233  const std::vector<art::Ptr<recob::Hit> > otherPlaneHits = showerHits.at(otherPlanes.at(0));
1234  for (std::vector<art::Ptr<recob::Hit> >::const_iterator otherPlaneHitIt = otherPlaneHits.begin();
1235  otherPlaneHitIt != otherPlaneHits.end() and std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) == usedHits.end();
1236  ++otherPlaneHitIt) {
1237 
1238  if ((*otherPlaneHitIt)->WireID().TPC != (*planeHitIt)->WireID().TPC or
1239  std::find(usedHits.begin(), usedHits.end(), otherPlaneHitIt->key()) != usedHits.end())
1240  continue;
1241 
1242  TVector3 point = Construct3DPoint(*planeHitIt, *otherPlaneHitIt);
1243  std::vector<art::Ptr<recob::Hit> > pointHits;
1244  bool truePoint = false;
1245 
1246  if (otherPlanes.size() > 1) {
1247 
1248  TVector2 projThirdPlane = Project3DPointOntoPlane(point, otherPlanes.at(1));
1249  const std::vector<art::Ptr<recob::Hit> > otherOtherPlaneHits = showerHits.at(otherPlanes.at(1));
1250 
1251  for (std::vector<art::Ptr<recob::Hit> >::const_iterator otherOtherPlaneHitIt = otherOtherPlaneHits.begin();
1252  otherOtherPlaneHitIt != otherOtherPlaneHits.end() and !truePoint;
1253  ++otherOtherPlaneHitIt) {
1254 
1255  if ((*otherOtherPlaneHitIt)->WireID().TPC == (*planeHitIt)->WireID().TPC and
1256  (projThirdPlane-HitPosition(*otherOtherPlaneHitIt)).Mod() < fSpacePointSize) {
1257 
1258  truePoint = true;
1259 
1260  // Remove hits used to make the point
1261  usedHits.push_back(planeHitIt->key());
1262  usedHits.push_back(otherPlaneHitIt->key());
1263  usedHits.push_back(otherOtherPlaneHitIt->key());
1264 
1265  pointHits.push_back(*planeHitIt);
1266  pointHits.push_back(*otherPlaneHitIt);
1267  pointHits.push_back(*otherOtherPlaneHitIt);
1268 
1269  }
1270  }
1271  }
1272 
1273  else if ((Project3DPointOntoPlane(point, (*planeHitIt)->WireID().Plane) - HitPosition(*planeHitIt)).Mod() < fSpacePointSize and
1274  (Project3DPointOntoPlane(point, (*otherPlaneHitIt)->WireID().Plane) - HitPosition(*otherPlaneHitIt)).Mod() < fSpacePointSize) {
1275 
1276  truePoint = true;
1277 
1278  usedHits.push_back(planeHitIt->key());
1279  usedHits.push_back(otherPlaneHitIt->key());
1280 
1281  pointHits.push_back(*planeHitIt);
1282  pointHits.push_back(*otherPlaneHitIt);
1283 
1284  }
1285 
1286  // Make space point
1287  if (truePoint) {
1288  double xyz[3] = {point.X(), point.Y(), point.Z()};
1289  double xyzerr[6] = {fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize};
1290  double chisq = 0.;
1291  spacePoints.emplace_back(xyz, xyzerr, chisq);
1292  hitAssns.push_back(pointHits);
1293  }
1294 
1295  } // end loop over second plane hits
1296 
1297  } // end loop over first plane hits
1298 
1299  } // end loop over planes
1300 
1301  if (fDebug > 0) {
1302  std::cout << "-------------------- Space points -------------------" << std::endl;
1303  std::cout << "There are " << spacePoints.size() << " space points:" << std::endl;
1304  if (fDebug > 1)
1305  for (std::vector<recob::SpacePoint>::const_iterator spacePointIt = spacePoints.begin(); spacePointIt != spacePoints.end(); ++spacePointIt) {
1306  const double* xyz = spacePointIt->XYZ();
1307  std::cout << " Space point (" << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << ")" << std::endl;
1308  }
1309  }
1310 
1311  return spacePoints;
1312 
1313 }
1314 
1315 std::map<int,std::vector<art::Ptr<recob::Hit> > > shower::EMShowerAlg::OrderShowerHits(art::PtrVector<recob::Hit> const& shower, int plane) {
1316 
1321 
1322  // ------------- Put hits in order ------------
1323 
1324  // // Find the true start for reconstruction validation purposes
1325  // std::vector<art::Ptr<recob::Hit> > showerHitsVector;
1326  // std::map<int,int> trueParticleHits;
1327  // for (art::PtrVector<recob::Hit>::const_iterator showerHitIt = shower.begin(); showerHitIt != shower.end(); ++showerHitIt) {
1328  // showerHitsVector.push_back(*showerHitIt);
1329  // ++trueParticleHits[FindParticleID(*showerHitIt)];
1330  // }
1331  // int trueParticleID = FindTrueParticle(showerHitsVector);
1332  // const simb::MCParticle* trueParticle = bt_serv->TrackIDToParticle(trueParticleID);
1333  // TVector3 trueStart3D = trueParticle->Position().Vect();
1334  // double purity = trueParticleHits[trueParticleID]/(double)shower.size();
1335 
1336  // Find the shower hits on each plane
1337  std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHitsMap;
1338  for (art::PtrVector<recob::Hit>::const_iterator hit = shower.begin(); hit != shower.end(); ++hit)
1339  showerHitsMap[(*hit)->WireID().Plane].push_back(*hit);
1340 
1341  // if (purity < 0.9)
1342  // return showerHitsMap;
1343 
1344  // Order the hits, get the RMS and the RMS gradient for the hits in this plane
1345  std::map<int,double> planeRMSGradients, planeRMS;
1346  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1347  if (plane != showerHitsIt->first and plane != -1)
1348  continue;
1349  std::vector<art::Ptr<recob::Hit> > orderedHits = FindOrderOfHits(showerHitsIt->second);
1350  planeRMS[showerHitsIt->first] = ShowerHitRMS(orderedHits);
1351  //TVector2 trueStart2D = Project3DPointOntoPlane(trueStart3D, showerHitsIt->first);
1352  planeRMSGradients[showerHitsIt->first] = ShowerHitRMSGradient(orderedHits);
1353  showerHitsMap[showerHitsIt->first] = orderedHits;
1354  }
1355 
1356  if (fDebug > 1)
1357  for (std::map<int,double>::iterator planeRMSIt = planeRMS.begin(); planeRMSIt != planeRMS.end(); ++planeRMSIt)
1358  std::cout << "Plane " << planeRMSIt->first << " has RMS " << planeRMSIt->second << " and RMS gradient " << planeRMSGradients.at(planeRMSIt->first) << std::endl;
1359 
1360  if (fDebug > 2) {
1361  std::cout << std::endl << "Hits in order; after ordering, before reversing..." << std::endl;
1362  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1363  std::cout << " Plane " << showerHitsIt->first << std::endl;
1364  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1365  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1366  }
1367  }
1368 
1369  // ------------- Check between the views to ensure consistency of ordering -------------
1370 
1371  // Check between the views to make sure there isn't a poorly formed shower in just one view
1372  // First, determine the average RMS and RMS gradient across the other planes
1373  std::map<int,double> planeOtherRMS, planeOtherRMSGradients;
1374  for (std::map<int,double>::iterator planeRMSIt = planeRMS.begin(); planeRMSIt != planeRMS.end(); ++planeRMSIt) {
1375  planeOtherRMS[planeRMSIt->first] = 0;
1376  planeOtherRMSGradients[planeRMSIt->first] = 0;
1377  int nOtherPlanes = 0;
1378  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane) {
1379  if (plane != planeRMSIt->first and planeRMS.count(plane)) {
1380  planeOtherRMS[planeRMSIt->first] += planeRMS.at(plane);
1381  planeOtherRMSGradients[planeRMSIt->first] += planeRMSGradients.at(plane);
1382  ++nOtherPlanes;
1383  }
1384  }
1385  planeOtherRMS[planeRMSIt->first] /= (double)nOtherPlanes;
1386  planeOtherRMSGradients[planeRMSIt->first] /= (double)nOtherPlanes;
1387  }
1388 
1389  // Look to see if one plane has a particularly high RMS (compared to the others) whilst having a similar gradient
1390  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1391  if (planeRMS.at(showerHitsIt->first) > planeOtherRMS.at(showerHitsIt->first) * 2) {
1392  //and TMath::Abs(planeRMSGradients.at(showerHitsIt->first) / planeOtherRMSGradients.at(showerHitsIt->first)) < 0.1) {
1393  if (fDebug > 1)
1394  std::cout << "Plane " << showerHitsIt->first << " was perpendicular... recalculating" << std::endl;
1395  std::vector<art::Ptr<recob::Hit> > orderedHits = this->FindOrderOfHits(showerHitsIt->second, true);
1396  showerHitsMap[showerHitsIt->first] = orderedHits;
1397  planeRMSGradients[showerHitsIt->first] = this->ShowerHitRMSGradient(orderedHits);
1398  }
1399  }
1400 
1401  // ------------- Orient the shower correctly ---------------
1402 
1403  if (fDebug > 1) {
1404  std::cout << "Before reversing, here are the start and end points..." << std::endl;
1405  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1406  std::cout << " Plane " << showerHitsIt->first << " has start (" << HitCoordinates(showerHitsIt->second.front()).X() << ", " << HitCoordinates(showerHitsIt->second.front()).Y() << ") (real wire " << showerHitsIt->second.front()->WireID() << ") and end (" << HitCoordinates(showerHitsIt->second.back()).X() << ", " << HitCoordinates(showerHitsIt->second.back()).Y() << ") (real wire " << showerHitsIt->second.back()->WireID() << ")" << std::endl;
1407  }
1408 
1409  // Use the RMS gradient information to get an initial ordering
1410  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1411  double gradient = planeRMSGradients.at(showerHitsIt->first);
1412  if (gradient < 0)
1413  std::reverse(showerHitsIt->second.begin(), showerHitsIt->second.end());
1414  }
1415 
1416  if (fDebug > 2) {
1417  std::cout << std::endl << "Hits in order; after reversing, before checking isolated hits..." << std::endl;
1418  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1419  std::cout << " Plane " << showerHitsIt->first << std::endl;
1420  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1421  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1422  }
1423  }
1424 
1425  CheckIsolatedHits(showerHitsMap);
1426 
1427  if (fDebug > 2) {
1428  std::cout << std::endl << "Hits in order; after checking isolated hits..." << std::endl;
1429  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1430  std::cout << " Plane " << showerHitsIt->first << std::endl;
1431  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1432  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1433  }
1434  }
1435 
1436  if (fDebug > 1) {
1437  std::cout << "After reversing and checking isolated hits, here are the start and end points..." << std::endl;
1438  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1439  std::cout << " Plane " << showerHitsIt->first << " has start (" << HitCoordinates(showerHitsIt->second.front()).X() << ", " << HitCoordinates(showerHitsIt->second.front()).Y() << ") (real wire " << showerHitsIt->second.front()->WireID() << ") and end (" << HitCoordinates(showerHitsIt->second.back()).X() << ", " << HitCoordinates(showerHitsIt->second.back()).Y() << ")" << std::endl;
1440  }
1441 
1442  // Check for views in which the shower travels almost along the wire planes
1443  // (shown by a small relative wire width)
1444  std::map<double,int> wireWidths = RelativeWireWidth(showerHitsMap);
1445  std::vector<int> badPlanes;
1446  if (fDebug > 1)
1447  std::cout << "Here are the relative wire widths... " << std::endl;
1448  for (std::map<double,int>::iterator wireWidthIt = wireWidths.begin(); wireWidthIt != wireWidths.end(); ++wireWidthIt) {
1449  if (fDebug > 1)
1450  std::cout << "Plane " << wireWidthIt->second << " has relative wire width " << wireWidthIt->first << std::endl;
1451  if (wireWidthIt->first < 1/(double)wireWidths.size())
1452  badPlanes.push_back(wireWidthIt->second);
1453  }
1454 
1455  std::map<int,std::vector<art::Ptr<recob::Hit> > > ignoredPlanes;
1456  if (badPlanes.size() == 1) {
1457  int badPlane = badPlanes.at(0);
1458  if (fDebug > 1)
1459  std::cout << "Ignoring plane " << badPlane << " when orientating" << std::endl;
1460  ignoredPlanes[badPlane] = showerHitsMap.at(badPlane);
1461  showerHitsMap.erase(showerHitsMap.find(badPlane));
1462  }
1463 
1464  // Consider all possible permutations of planes (0/1, oriented correctly/incorrectly)
1465  std::map<int,std::map<int,bool> > permutations = GetPlanePermutations(showerHitsMap);
1466 
1467  // Go through all permutations until we have a satisfactory orientation
1468  std::map<int,std::vector<art::Ptr<recob::Hit> > > originalShowerHitsMap = showerHitsMap;
1469  int n = 0;
1470  while (!CheckShowerHits(showerHitsMap) and n < TMath::Power(2,(int)showerHitsMap.size())) {
1471  if (fDebug > 1)
1472  std::cout << "Permutation " << n << std::endl;
1473  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1474  std::vector<art::Ptr<recob::Hit> > hits = originalShowerHitsMap.at(showerHitsIt->first);
1475  if (permutations[n][showerHitsIt->first] == 1) {
1476  std::reverse(hits.begin(), hits.end());
1477  showerHitsMap[showerHitsIt->first] = hits;
1478  }
1479  else
1480  showerHitsMap[showerHitsIt->first] = hits;
1481  }
1482  ++n;
1483  }
1484 
1485  // Go back to original if still no consistency
1486  if (!CheckShowerHits(showerHitsMap))
1487  showerHitsMap = originalShowerHitsMap;
1488 
1489  if (fDebug > 2) {
1490  std::cout << "End of OrderShowerHits: here are the order of hits:" << std::endl;
1491  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeHitsIt = showerHitsMap.begin(); planeHitsIt != showerHitsMap.end(); ++planeHitsIt) {
1492  std::cout << " Plane " << planeHitsIt->first << std::endl;
1493  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = planeHitsIt->second.begin(); hitIt != planeHitsIt->second.end(); ++hitIt)
1494  std::cout << " Hit (" << HitCoordinates(*hitIt).X() << " (real wire " << (*hitIt)->WireID() << "), " << HitCoordinates(*hitIt).Y() << ") -- pos (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1495  }
1496  }
1497 
1498  if (ignoredPlanes.size())
1499  showerHitsMap[ignoredPlanes.begin()->first] = ignoredPlanes.begin()->second;
1500 
1501  return showerHitsMap;
1502 
1503 }
1504 
1506  std::vector<art::Ptr<recob::Hit> >& showerHits,
1508 
1509  showerHits = FindOrderOfHits(shower);
1510 
1511  // Find TPC for the vertex
1512  double xyz[3];
1513  vertex->XYZ(xyz);
1514  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1515  if (!tpc.isValid&&showerHits.size()) tpc = geo::TPCID(showerHits[0]->WireID());
1516  //std::cout<<tpc<<std::endl;
1517  // Find hits in the same TPC
1518  art::Ptr<recob::Hit> hit0, hit1;
1519  for (auto &hit: showerHits){
1520  if (hit->WireID().TPC==tpc.TPC){
1521  if (hit0.isNull()){
1522  hit0 = hit;
1523  }
1524  hit1 = hit;
1525  }
1526  }
1527  if (hit0.isNull()||hit1.isNull()) return;
1528  TVector2 coord0 = TVector2(hit0->WireID().Wire, hit0->PeakTime());
1529  TVector2 coord1 = TVector2(hit1->WireID().Wire, hit1->PeakTime());
1530  TVector2 coordvtx = TVector2(fGeom->WireCoordinate(xyz[1], xyz[2], hit0->WireID().planeID()),
1531  fDetProp->ConvertXToTicks(xyz[0], hit0->WireID().planeID()));
1532 // std::cout<<coord0.X()<<" "<<coord0.Y()<<std::endl;
1533 // std::cout<<coord1.X()<<" "<<coord1.Y()<<std::endl;
1534 // std::cout<<coordvtx.X()<<" "<<coordvtx.Y()<<std::endl;
1535 // std::cout<<hit0->WireID()<<" "<<hit1->WireID()<<std::endl;
1536  if ((coord1-coordvtx).Mod()<(coord0-coordvtx).Mod()){
1537  std::reverse(showerHits.begin(), showerHits.end());
1538  }
1539  //std::cout<<showerHits[0]->WireID()<<" "<<showerHits.back()->WireID()<<std::endl;
1540 }
1541 
1544  std::vector<art::Ptr<recob::Hit> >& trackHits){
1545 
1546  // Find TPC for the vertex
1547  //std::cout<<"here"<<std::endl;
1548  double xyz[3];
1549  vertex->XYZ(xyz);
1550  //std::cout<<xyz[0]<<" "<<xyz[1]<<" "<<xyz[2]<<std::endl;
1551  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1552  //std::cout<<tpc<<std::endl;
1553  //vertex cannot be projected into a TPC, find the TPC that has the most hits
1554  if (!tpc.isValid){
1555  std::map<geo::TPCID, unsigned int> tpcmap;
1556  unsigned maxhits = 0;
1557  for (auto const&hit : showerHits){
1558  ++tpcmap[geo::TPCID(hit->WireID())];
1559  }
1560  for (auto const&t : tpcmap){
1561  if (t.second > maxhits){
1562  maxhits = t.second;
1563  tpc = t.first;
1564  }
1565  }
1566  }
1567  //std::cout<<tpc<<std::endl;
1568  //if (!tpc.isValid&&showerHits.size()) tpc = geo::TPCID(showerHits[0]->WireID());
1569  if (!tpc.isValid) return;
1570  //std::cout<<"here 1"<<std::endl;
1571 
1572  double parm[2];
1573  int fitok = 0;
1574  std::vector<double> wfit;
1575  std::vector<double> tfit;
1576  std::vector<double> cfit;
1577 
1578  for (size_t i = 0; i<fNfitpass; ++i){
1579 
1580  // Fit a straight line through hits
1581  unsigned int nhits = 0;
1582  for (auto &hit: showerHits){
1583  //std::cout<<i<<" "<<hit->WireID()<<" "<<tpc<<std::endl;
1584  if (hit->WireID().TPC==tpc.TPC){
1585  TVector2 coord = HitCoordinates(hit);
1586  //std::cout<<i<<" "<<hit->WireID()<<" "<<hit->PeakTime()<<std::endl;
1587  if (i==0||(std::abs((coord.Y()-(parm[0]+coord.X()*parm[1]))*cos(atan(parm[1])))<fToler[i-1])||fitok==1){
1588  ++nhits;
1589  if (nhits==fNfithits[i]+1) break;
1590  wfit.push_back(coord.X());
1591  tfit.push_back(coord.Y());
1592  //cfit.push_back(hit->Integral());
1593  cfit.push_back(1.);
1594  if (i==fNfitpass-1) {
1595  trackHits.push_back(hit);
1596  }
1597  //std::cout<<*hit<<std::endl;
1598 //
1599 //<<hit->PeakTime()<<" "<<std::abs((coord.Y()-(parm[0]+coord.X()*parm[1]))*cos(atan(parm[1])))<<std::endl;
1600  }
1601  }
1602  }
1603 
1604  if (i<fNfitpass-1&&wfit.size()){
1605  fitok = WeightedFit(wfit.size(), &wfit[0], &tfit[0], &cfit[0], &parm[0]);
1606  }
1607  wfit.clear();
1608  tfit.clear();
1609  cfit.clear();
1610  }
1611 
1612 }
1613 
1614 
1616 
1617  return TVector2(GlobalWire(hit->WireID()), hit->PeakTime());
1618 
1619 }
1620 
1622 
1623  geo::PlaneID planeID = hit->WireID().planeID();
1624 
1625  return HitPosition(HitCoordinates(hit), planeID);
1626 
1627 }
1628 
1629 TVector2 shower::EMShowerAlg::HitPosition(TVector2 const& pos, geo::PlaneID planeID) {
1630 
1631  return TVector2(pos.X() * fGeom->WirePitch(planeID),
1632  fDetProp->ConvertTicksToX(pos.Y(), planeID));
1633 
1634 }
1635 
1637 
1638  double globalWire = -999;
1639 
1640  // Induction
1641  if (fGeom->SignalType(wireID) == geo::kInduction) {
1642  double wireCentre[3];
1643  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1644  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1645  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1646  }
1647 
1648  // Collection
1649  else {
1650  // FOR COLLECTION WIRES, HARD CODE THE GEOMETRY FOR GIVEN DETECTORS
1651  // THIS _SHOULD_ BE TEMPORARY. GLOBAL WIRE SUPPORT IS BEING ADDED TO THE LARSOFT GEOMETRY AND SHOULD BE AVAILABLE SOON
1652  if (fDetector == "dune35t") {
1653  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1654  if (wireID.TPC == 0 or wireID.TPC == 1) globalWire = wireID.Wire;
1655  else if (wireID.TPC == 2 or wireID.TPC == 3 or wireID.TPC == 4 or wireID.TPC == 5) globalWire = nwires + wireID.Wire;
1656  else if (wireID.TPC == 6 or wireID.TPC == 7) globalWire = (2*nwires) + wireID.Wire;
1657  else mf::LogError("BlurredClusterAlg") << "Error when trying to find a global induction plane coordinate for TPC " << wireID.TPC << " (geometry" << fDetector << ")";
1658  }
1659  else if (fDetector == "dune10kt") {
1660  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1661  // Detector geometry has four TPCs, two on top of each other, repeated along z...
1662  int block = wireID.TPC / 4;
1663  globalWire = (nwires*block) + wireID.Wire;
1664  }
1665  else {
1666  double wireCentre[3];
1667  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1668  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1669  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1670  }
1671  }
1672 
1673  return globalWire;
1674 
1675 }
1676 
1677 std::map<double,int> shower::EMShowerAlg::RelativeWireWidth(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
1678 
1679  // Get the wire widths
1680  std::map<int,int> planeWireLength;
1681  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1682  planeWireLength[showerHitsIt->first] = TMath::Abs(HitCoordinates(showerHitsIt->second.front()).X() - HitCoordinates(showerHitsIt->second.back()).X());
1683 
1684  // Find the relative wire width for each plane with respect to the others
1685  std::map<int,double> planeOtherWireLengths;
1686  for (std::map<int,int>::iterator planeWireLengthIt = planeWireLength.begin(); planeWireLengthIt != planeWireLength.end(); ++planeWireLengthIt) {
1687  double quad = 0.;
1688  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
1689  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
1690  quad += TMath::Power(planeWireLength[plane],2);
1691  quad = TMath::Sqrt(quad);
1692  planeOtherWireLengths[planeWireLengthIt->first] = planeWireLength[planeWireLengthIt->first] / (double)quad;
1693  }
1694 
1695  // Order these backwards
1696  std::map<double,int> wireWidthMap;
1697  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1698  wireWidthMap[planeOtherWireLengths.at(showerHitsIt->first)] = showerHitsIt->first;
1699 
1700  return wireWidthMap;
1701 
1702 }
1703 
1705 
1706  TVector2 pos;
1707  //double weight;
1708  double weight = 1;
1709  //int nhits = 0;
1710  double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1711  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = showerHits.begin(); hit != showerHits.end(); ++hit) {
1712  //++nhits;
1713  pos = HitPosition(*hit);
1714  weight = TMath::Power((*hit)->Integral(),2);
1715  sumweight += weight;
1716  sumx += weight * pos.X();
1717  sumy += weight * pos.Y();
1718  sumx2 += weight * pos.X() * pos.X();
1719  sumxy += weight * pos.X() * pos.Y();
1720  }
1721  //double gradient = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
1722  double gradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1723  TVector2 direction = TVector2(1,gradient).Unit();
1724 
1725  return direction;
1726 
1727 }
1728 
1730 
1731  TVector2 pos, chargePoint = TVector2(0,0);
1732  double totalCharge = 0;
1733  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = showerHits.begin(); hit != showerHits.end(); ++hit) {
1734  pos = HitPosition(*hit);
1735  chargePoint += (*hit)->Integral() * pos;
1736  totalCharge += (*hit)->Integral();
1737  }
1738  TVector2 centre = chargePoint / totalCharge;
1739 
1740  return centre;
1741 
1742 }
1743 
1745 
1746  TVector2 direction = ShowerDirection(showerHits);
1747  TVector2 centre = ShowerCentre(showerHits);
1748 
1749  std::vector<double> distanceToAxis;
1750  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1751  TVector2 proj = (HitPosition(*showerHitsIt) - centre).Proj(direction) + centre;
1752  distanceToAxis.push_back((HitPosition(*showerHitsIt) - proj).Mod());
1753  }
1754  double RMS = TMath::RMS(distanceToAxis.begin(), distanceToAxis.end());
1755 
1756  return RMS;
1757 
1758 }
1759 
1760 double shower::EMShowerAlg::ShowerHitRMSGradient(const std::vector<art::Ptr<recob::Hit> >& showerHits, TVector2 trueStart) {
1761 
1762  // Don't forget to clean up the header file!
1763 
1764  // Find a rough shower 'direction' and centre
1765  TVector2 direction = ShowerDirection(showerHits);
1766 
1767  //std::cout << std::endl << "Number of hits in this shower: " << showerHits.size() << std::endl;
1768 
1769  // for (int i = 0; i < 100; ++i) {
1770 
1771  // // Bin the hits into discreet chunks
1772  // //int nSegmentHits = fNumSegmentHits;
1773  // int nSegmentHits = i;
1774  // int nShowerSegments = showerHits.size() / (double)nSegmentHits;
1775  // //int nShowerSegments = fNumShowerSegments;
1776  // double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
1777  // double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
1778  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
1779  // std::map<int,double> segmentCharge;
1780  // for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1781  // showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
1782  // segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
1783  // }
1784 
1785  // TGraph* graph = new TGraph();
1786  // std::vector<std::pair<int,double> > binVsRMS;
1787 
1788  // // Loop over the bins to find the distribution of hits as the shower progresses
1789  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
1790 
1791  // // Get the mean position of the hits in this bin
1792  // TVector2 meanPosition(0,0);
1793  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
1794  // meanPosition += HitPosition(*hitInSegmentIt);
1795  // meanPosition /= (double)showerSegmentIt->second.size();
1796 
1797  // // Get the RMS of this bin
1798  // std::vector<double> distanceToAxisBin;
1799  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
1800  // TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
1801  // distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
1802  // }
1803 
1804  // double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
1805  // binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
1806  // if (fMakeRMSGradientPlot)
1807  // graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
1808 
1809  // }
1810 
1811  // // Get the gradient of the RMS-bin plot
1812 
1813  // // OLD
1814  // int nhits1 = 0;
1815  // double sumx1=0., sumy1=0., sumx21=0., sumxy1=0.;
1816  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1817  // ++nhits1;
1818  // sumx1 += binVsRMSIt->first;
1819  // sumy1 += binVsRMSIt->second;
1820  // sumx21 += binVsRMSIt->first * binVsRMSIt->first;
1821  // sumxy1 += binVsRMSIt->first * binVsRMSIt->second;
1822  // }
1823  // double RMSgradient1 = (nhits1 * sumxy1 - sumx1 * sumy1) / (nhits1 * sumx21 - sumx1 * sumx1);
1824 
1825  // // NEW
1826  // double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1827  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1828  // //double weight = showerSegments.at(binVsRMSIt->first).size();
1829  // double weight = TMath::Power(segmentCharge.at(binVsRMSIt->first),2);
1830  // sumweight += weight;
1831  // sumx += weight * binVsRMSIt->first;
1832  // sumy += weight * binVsRMSIt->second;
1833  // sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
1834  // sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
1835  // }
1836  // double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1837 
1838  // // PCA
1839  // TPrincipal* pca = new TPrincipal(2,"");
1840  // double point[2];
1841  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1842  // if (fDebug > 2)
1843  // std::cout << "Number of hits in segment " << binVsRMSIt->first << " is " << showerSegments.at(binVsRMSIt->first).size() << std::endl;
1844  // for (int nhit = 0; nhit < (int)showerSegments.at(binVsRMSIt->first).size(); ++nhit) {
1845  // point[0] = binVsRMSIt->first;
1846  // point[1] = binVsRMSIt->second;
1847  // pca->AddRow(point);
1848  // }
1849  // }
1850  // pca->MakePrincipals();
1851  // TVector2 RMSgradientPCA = TVector2( (*pca->GetEigenVectors())[0][0], (*pca->GetEigenVectors())[1][0] ).Unit();
1852 
1853  // if (fDebug > 1)
1854  // std::cout << "RMS gradient without weighting: " << RMSgradient1 << ", and with weighting: " << RMSgradient << "; PCA with weighting: " << RMSgradientPCA.Y()/RMSgradientPCA.X() << std::endl;
1855 
1856  // if (fMakeRMSGradientPlot) {
1857  // TVector2 direction = TVector2(1,RMSgradient).Unit();
1858  // TVector2 direction1 = TVector2(1,RMSgradient1).Unit();
1859  // TCanvas* canv = new TCanvas();
1860  // graph->Draw();
1861  // TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
1862  // TLine line, line1, line2;
1863  // line.SetLineColor(3);
1864  // line1.SetLineColor(4);
1865  // line2.SetLineColor(5);
1866  // line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
1867  // line1.DrawLine(centre.X()-1000*direction1.X(),centre.Y()-1000*direction1.Y(),centre.X()+1000*direction1.X(),centre.Y()+1000*direction1.Y());
1868  // line2.DrawLine(centre.X()-1000*RMSgradientPCA.X(),centre.Y()-1000*RMSgradientPCA.Y(),centre.X()+1000*RMSgradientPCA.X(),centre.Y()+1000*RMSgradientPCA.Y());
1869  // canv->SaveAs("RMSGradient.png");
1870  // delete canv;
1871  // }
1872  // delete graph; delete pca;
1873 
1874  // //std::cout << "Number of hits per bin " << i << " gives gradient of " << RMSgradient << std::endl;
1875 
1876  // double distanceFromStart = 0, distanceFromEnd = 0;
1877  // if (RMSgradient > 0) {
1878  // distanceFromStart = (trueStart - HitPosition(showerHits.front())).Mod();
1879  // distanceFromEnd = (trueStart - HitPosition(showerHits.back())).Mod();
1880  // }
1881  // if (RMSgradient < 0) {
1882  // distanceFromStart = (trueStart - HitPosition(showerHits.back())).Mod();
1883  // distanceFromEnd = (trueStart - HitPosition(showerHits.front())).Mod();
1884  // }
1885  // bool correct = distanceFromStart < distanceFromEnd;
1886  // hNumHitsInSegment->Fill(i,correct);
1887 
1888  // }
1889 
1890 
1891 
1892 
1893  // for (int i = 0; i < 100; ++i) {
1894 
1895  // // Bin the hits into discreet chunks
1896  // int nShowerSegments = i;
1897  // double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
1898  // double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
1899  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
1900  // std::map<int,double> segmentCharge;
1901  // for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1902  // showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
1903  // segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
1904  // }
1905 
1906  // TGraph* graph = new TGraph();
1907  // std::vector<std::pair<int,double> > binVsRMS;
1908 
1909  // // Loop over the bins to find the distribution of hits as the shower progresses
1910  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
1911 
1912  // // Get the mean position of the hits in this bin
1913  // TVector2 meanPosition(0,0);
1914  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
1915  // meanPosition += HitPosition(*hitInSegmentIt);
1916  // meanPosition /= (double)showerSegmentIt->second.size();
1917 
1918  // // Get the RMS of this bin
1919  // std::vector<double> distanceToAxisBin;
1920  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
1921  // TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
1922  // distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
1923  // }
1924 
1925  // double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
1926  // binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
1927  // if (fMakeRMSGradientPlot)
1928  // graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
1929 
1930  // }
1931 
1932  // // Get the gradient of the RMS-bin plot
1933 
1934  // // OLD
1935  // int nhits1 = 0;
1936  // double sumx1=0., sumy1=0., sumx21=0., sumxy1=0.;
1937  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1938  // ++nhits1;
1939  // sumx1 += binVsRMSIt->first;
1940  // sumy1 += binVsRMSIt->second;
1941  // sumx21 += binVsRMSIt->first * binVsRMSIt->first;
1942  // sumxy1 += binVsRMSIt->first * binVsRMSIt->second;
1943  // }
1944  // double RMSgradient1 = (nhits1 * sumxy1 - sumx1 * sumy1) / (nhits1 * sumx21 - sumx1 * sumx1);
1945 
1946  // // NEW
1947  // double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1948  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1949  // //double weight = showerSegments.at(binVsRMSIt->first).size();
1950  // double weight = TMath::Power(segmentCharge.at(binVsRMSIt->first),2);
1951  // sumweight += weight;
1952  // sumx += weight * binVsRMSIt->first;
1953  // sumy += weight * binVsRMSIt->second;
1954  // sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
1955  // sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
1956  // }
1957  // double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1958 
1959  // // PCA
1960  // TPrincipal* pca = new TPrincipal(2,"");
1961  // double point[2];
1962  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1963  // if (fDebug > 2)
1964  // std::cout << "Number of hits in segment " << binVsRMSIt->first << " is " << showerSegments.at(binVsRMSIt->first).size() << std::endl;
1965  // for (int nhit = 0; nhit < (int)showerSegments.at(binVsRMSIt->first).size(); ++nhit) {
1966  // point[0] = binVsRMSIt->first;
1967  // point[1] = binVsRMSIt->second;
1968  // pca->AddRow(point);
1969  // }
1970  // }
1971  // pca->MakePrincipals();
1972  // TVector2 RMSgradientPCA = TVector2( (*pca->GetEigenVectors())[0][0], (*pca->GetEigenVectors())[1][0] ).Unit();
1973 
1974  // if (fDebug > 1)
1975  // std::cout << "RMS gradient without weighting: " << RMSgradient1 << ", and with weighting: " << RMSgradient << "; PCA with weighting: " << RMSgradientPCA.Y()/RMSgradientPCA.X() << std::endl;
1976 
1977  // if (fMakeRMSGradientPlot) {
1978  // TVector2 direction = TVector2(1,RMSgradient).Unit();
1979  // TVector2 direction1 = TVector2(1,RMSgradient1).Unit();
1980  // TCanvas* canv = new TCanvas();
1981  // graph->Draw();
1982  // TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
1983  // TLine line, line1, line2;
1984  // line.SetLineColor(3);
1985  // line1.SetLineColor(4);
1986  // line2.SetLineColor(5);
1987  // line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
1988  // line1.DrawLine(centre.X()-1000*direction1.X(),centre.Y()-1000*direction1.Y(),centre.X()+1000*direction1.X(),centre.Y()+1000*direction1.Y());
1989  // line2.DrawLine(centre.X()-1000*RMSgradientPCA.X(),centre.Y()-1000*RMSgradientPCA.Y(),centre.X()+1000*RMSgradientPCA.X(),centre.Y()+1000*RMSgradientPCA.Y());
1990  // canv->SaveAs("RMSGradient.png");
1991  // delete canv;
1992  // }
1993  // delete graph; delete pca;
1994 
1995  // //std::cout << "Number of hits per bin " << i << " gives gradient of " << RMSgradient << std::endl;
1996 
1997  // double distanceFromStart = 0, distanceFromEnd = 0;
1998  // if (RMSgradient > 0) {
1999  // distanceFromStart = (trueStart - HitPosition(showerHits.front())).Mod();
2000  // distanceFromEnd = (trueStart - HitPosition(showerHits.back())).Mod();
2001  // }
2002  // if (RMSgradient < 0) {
2003  // distanceFromStart = (trueStart - HitPosition(showerHits.back())).Mod();
2004  // distanceFromEnd = (trueStart - HitPosition(showerHits.front())).Mod();
2005  // }
2006  // bool correct = distanceFromStart < distanceFromEnd;
2007  // hNumSegments->Fill(i,correct);
2008 
2009  // }
2010 
2011 
2012 
2013 
2014 
2015 
2016 
2017 
2018 
2019 
2020 
2021 
2022 
2023 
2024 
2025 
2026  // Bin the hits into discreet chunks
2027  int nShowerSegments = fNumShowerSegments;
2028  double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
2029  double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
2030  std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
2031  std::map<int,double> segmentCharge;
2032  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
2033  showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
2034  segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
2035  }
2036 
2037  TGraph* graph = new TGraph();
2038  std::vector<std::pair<int,double> > binVsRMS;
2039 
2040  // Loop over the bins to find the distribution of hits as the shower progresses
2041  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
2042 
2043  // Get the mean position of the hits in this bin
2044  TVector2 meanPosition(0,0);
2045  for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
2046  meanPosition += HitPosition(*hitInSegmentIt);
2047  meanPosition /= (double)showerSegmentIt->second.size();
2048 
2049  // Get the RMS of this bin
2050  std::vector<double> distanceToAxisBin;
2051  for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
2052  TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
2053  distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
2054  }
2055 
2056  double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
2057  binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
2059  graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
2060 
2061  }
2062 
2063  // Get the gradient of the RMS-bin plot
2064  double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
2065  for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
2066  //double weight = showerSegments.at(binVsRMSIt->first).size();
2067  //double weight = 1;
2068  double weight = segmentCharge.at(binVsRMSIt->first);
2069  sumweight += weight;
2070  sumx += weight * binVsRMSIt->first;
2071  sumy += weight * binVsRMSIt->second;
2072  sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
2073  sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
2074  }
2075  double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
2076 
2077  if (fMakeRMSGradientPlot) {
2078  TVector2 direction = TVector2(1,RMSgradient).Unit();
2079  TCanvas* canv = new TCanvas();
2080  graph->Draw();
2081  graph->GetXaxis()->SetTitle("Shower segment");
2082  graph->GetYaxis()->SetTitle("RMS of hit distribution");
2083  TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
2084  TLine line;
2085  line.SetLineColor(2);
2086  line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
2087  canv->SaveAs("RMSGradient.png");
2088  delete canv;
2089  }
2090  delete graph;
2091 
2092  return RMSgradient;
2093 
2094 }
2095 
2096 TVector2 shower::EMShowerAlg::Project3DPointOntoPlane(TVector3 const& point, int plane, int cryostat) {
2097 
2098  TVector2 wireTickPos = TVector2(-999., -999.);
2099 
2100  double pointPosition[3] = {point.X(), point.Y(), point.Z()};
2101 
2102  geo::TPCID tpcID = fGeom->FindTPCAtPosition(pointPosition);
2103  int tpc = 0;
2104  if (tpcID.isValid)
2105  tpc = tpcID.TPC;
2106  else
2107  return wireTickPos;
2108 
2109  // Construct wire ID for this point projected onto the plane
2110  geo::PlaneID planeID = geo::PlaneID(cryostat, tpc, plane);
2111  geo::WireID wireID;
2112  try{
2113  wireID = fGeom->NearestWireID(point, planeID);
2114  }
2115  catch(geo::InvalidWireError const& e) {
2116  wireID = e.suggestedWireID(); // pick the closest valid wire
2117  }
2118 
2119  wireTickPos = TVector2(GlobalWire(wireID),
2120  fDetProp->ConvertXToTicks(point.X(), planeID));
2121 
2122  // wireTickPos = TVector2(fGeom->WireCoordinate(point.Y(), point.Z(), planeID.Plane, tpc % 2, planeID.Cryostat),
2123  // fDetProp->ConvertXToTicks(point.X(), planeID.Plane, tpc % 2, planeID.Cryostat));
2124 
2125  //return wireTickPos;
2126  return HitPosition(wireTickPos, planeID);
2127 
2128 }
2129 
2130 int shower::EMShowerAlg::WorstPlane(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
2131 
2132  // Get the width of the shower in wire coordinate
2133  std::map<int,int> planeWireLength;
2134  std::map<int,double> planeOtherWireLengths;
2135  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
2136  planeWireLength[showerHitsIt->first] = TMath::Abs(HitCoordinates(showerHitsIt->second.front()).X() - HitCoordinates(showerHitsIt->second.back()).X());
2137  for (std::map<int,int>::iterator planeWireLengthIt = planeWireLength.begin(); planeWireLengthIt != planeWireLength.end(); ++planeWireLengthIt) {
2138  double quad = 0.;
2139  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
2140  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
2141  quad += TMath::Power(planeWireLength[plane],2);
2142  quad = TMath::Sqrt(quad);
2143  planeOtherWireLengths[planeWireLengthIt->first] = planeWireLength[planeWireLengthIt->first] / (double)quad;
2144  }
2145 
2146  if (fDebug > 1)
2147  for (std::map<int,double>::const_iterator planeOtherWireLengthIt = planeOtherWireLengths.begin(); planeOtherWireLengthIt != planeOtherWireLengths.end(); ++planeOtherWireLengthIt)
2148  std::cout << "Plane " << planeOtherWireLengthIt->first << " has " << planeWireLength[planeOtherWireLengthIt->first] << " wire width and therefore has relative width in wire of " << planeOtherWireLengthIt->second << std::endl;
2149 
2150  std::map<double,int> wireWidthMap;
2151  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
2152  double wireWidth = planeWireLength.at(showerHitsIt->first);
2153  wireWidthMap[wireWidth] = showerHitsIt->first;
2154  }
2155 
2156  return wireWidthMap.begin()->second;
2157 
2158 }
2159 
2160 Int_t shower::EMShowerAlg::WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm){
2161 
2162  Double_t sumx=0.;
2163  Double_t sumx2=0.;
2164  Double_t sumy=0.;
2165  Double_t sumy2=0.;
2166  Double_t sumxy=0.;
2167  Double_t sumw=0.;
2168  Double_t eparm[2];
2169 
2170  parm[0] = 0.;
2171  parm[1] = 0.;
2172  eparm[0] = 0.;
2173  eparm[1] = 0.;
2174 
2175  for (Int_t i=0; i<n; i++) {
2176  sumx += x[i]*w[i];
2177  sumx2 += x[i]*x[i]*w[i];
2178  sumy += y[i]*w[i];
2179  sumy2 += y[i]*y[i]*w[i];
2180  sumxy += x[i]*y[i]*w[i];
2181  sumw += w[i];
2182  }
2183 
2184  if (sumx2*sumw-sumx*sumx==0.) return 1;
2185  if (sumx2-sumx*sumx/sumw==0.) return 1;
2186 
2187  parm[0] = (sumy*sumx2-sumx*sumxy)/(sumx2*sumw-sumx*sumx);
2188  parm[1] = (sumxy-sumx*sumy/sumw)/(sumx2-sumx*sumx/sumw);
2189 
2190  eparm[0] = sumx2*(sumx2*sumw-sumx*sumx);
2191  eparm[1] = (sumx2-sumx*sumx/sumw);
2192 
2193  if (eparm[0]<0. || eparm[1]<0.) return 1;
2194 
2195  eparm[0] = sqrt(eparm[0])/(sumx2*sumw-sumx*sumx);
2196  eparm[1] = sqrt(eparm[1])/(sumx2-sumx*sumx/sumw);
2197 
2198  return 0;
2199 
2200 }
2201 
2203 
2204  if (!hits.size()) return false;
2205  if (hits.size()>2000) return true;
2206  if (hits.size()<20) return true;
2207  std::map<int, int> hitmap;
2208  unsigned nhits = 0;
2209  for (auto const&hit : hits){
2210  ++nhits;
2211  if (nhits>2)
2212  ++hitmap[hit->WireID().Wire];
2213  if (nhits==20) break;
2214  }
2215  //std::cout<<hits.size()<<" "<<float(nhits-2)/hitmap.size()<<std::endl;
2216  if (float(nhits-2)/hitmap.size()>1.4) return false;
2217  else return true;
2218 }
2219 
2221  : fGeom(lar::providerFrom<geo::Geometry>())
2222  , fDetProp(lar::providerFrom<detinfo::DetectorPropertiesService>())
2223  {}
2224 
2225 
2226 // // Code to make wire maps showing the global wire coordinates
2227 // struct TPCWire {
2228 // int fPlane, fTPC, fWire, fGlobalWire;
2229 // TVector3 fStart, fEnd;
2230 // TPCWire(int plane, int tpc, int wire, int globalWire, TVector3 start, TVector3 end) {
2231 // fPlane = plane;
2232 // fTPC = tpc;
2233 // fWire = wire;
2234 // fGlobalWire = globalWire;
2235 // fStart = start;
2236 // fEnd = end;
2237 // }
2238 // TPCWire() { }
2239 // void SetProps(int plane, int tpc, int wire, int globalWire, TVector3 start, TVector3 end) {
2240 // fPlane = plane;
2241 // fTPC = tpc;
2242 // fWire = wire;
2243 // fGlobalWire = globalWire;
2244 // fStart = start;
2245 // fEnd = end;
2246 // }
2247 // };
2248 
2249 // void shower::EMShowerAlg::MakePicture() {
2250 
2251 // std::vector<TPCWire> allWires;
2252 
2253 // for (geo::WireID const& wireID : fGeom->IterateWireIDs()) {
2254 
2255 // if (wireID.TPC % 2 == 0)
2256 // continue;
2257 
2258 // double xyzStart[3], xyzEnd[3];
2259 // fGeom->WireEndPoints(wireID, xyzStart, xyzEnd);
2260 // int globalWire = GlobalWire(wireID);
2261 
2262 // allWires.emplace_back(wireID.Plane, wireID.TPC, wireID.Wire, globalWire, TVector3(xyzStart[0],xyzStart[1],xyzStart[2]), TVector3(xyzEnd[0],xyzEnd[1],xyzEnd[2]));
2263 
2264 // } // for all wires
2265 
2266 // TCanvas* uplane = new TCanvas();
2267 // TCanvas* vplane = new TCanvas();
2268 // TCanvas* zplane = new TCanvas();
2269 // TText* number = new TText();
2270 // number->SetTextSize(0.002);
2271 // TLine* line = new TLine(0,100,0,100);
2272 // line->SetLineWidth(0.5);
2273 // uplane->Range(-5,-100,160,140);
2274 // vplane->Range(-5,-100,160,140);
2275 // zplane->Range(-5,-100,160,140);
2276 
2277 // for (std::vector<TPCWire>::iterator wireIt = allWires.begin(); wireIt != allWires.end(); ++wireIt) {
2278 // if (wireIt->fPlane == 0)
2279 // uplane->cd();
2280 // else if (wireIt->fPlane == 1)
2281 // vplane->cd();
2282 // else if (wireIt->fPlane == 2)
2283 // zplane->cd();
2284 // line->DrawLine(wireIt->fStart.Z(), wireIt->fStart.Y(), wireIt->fEnd.Z(), wireIt->fEnd.Y());
2285 // number->DrawText(wireIt->fStart.Z(), wireIt->fStart.Y(), (std::to_string(wireIt->fGlobalWire)+" ("+std::to_string(wireIt->fWire)+")").c_str());
2286 // number->DrawText(wireIt->fEnd.Z(), wireIt->fEnd.Y(), (std::to_string(wireIt->fGlobalWire)+" ("+std::to_string(wireIt->fWire)+")").c_str());
2287 // }
2288 
2289 // uplane->SaveAs("UPlane.pdf");
2290 // vplane->SaveAs("VPlane.pdf");
2291 // zplane->SaveAs("ZPlane.pdf");
2292 
2293 // }
2294 
2295 //
2296 // // Timing code...
2297 //
2298 // auto start_time = std::chrono::high_resolution_clock::now();
2299 // // Put stuff here!
2300 // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
2301 // std::cout << "Duration is " << duration/1000000.0 << " s " << std::endl;;
2302 //
2303 
2305 
2307 
2308  // Make a map of the tracks which are associated with this shower and the charge each contributes
2309  std::map<int,double> trackMap;
2310  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitIt = showerHits.begin(); showerHitIt != showerHits.end(); ++showerHitIt) {
2311  art::Ptr<recob::Hit> hit = *showerHitIt;
2312  int trackID = FindParticleID(hit);
2313  trackMap[trackID] += hit->Integral();
2314  }
2315 
2316  // Pick the track with the highest charge as the 'true track'
2317  double highestCharge = 0;
2318  int showerTrack = 0;
2319  for (std::map<int,double>::iterator trackIt = trackMap.begin(); trackIt != trackMap.end(); ++trackIt) {
2320  if (trackIt->second > highestCharge) {
2321  highestCharge = trackIt->second;
2322  showerTrack = trackIt->first;
2323  }
2324  }
2325 
2326  return showerTrack;
2327 
2328 }
2329 
2331 
2333 
2334  double particleEnergy = 0;
2335  int likelyTrackID = 0;
2336  std::vector<sim::TrackIDE> trackIDs = bt_serv->HitToTrackIDEs(hit);
2337  for (unsigned int idIt = 0; idIt < trackIDs.size(); ++idIt) {
2338  if (trackIDs.at(idIt).energy > particleEnergy) {
2339  particleEnergy = trackIDs.at(idIt).energy;
2340  likelyTrackID = TMath::Abs(trackIDs.at(idIt).trackID);
2341  }
2342  }
2343 
2344  return likelyTrackID;
2345 
2346 }
Float_t x
Definition: compare.C:6
TProfile * hNumSegments
Definition: EMShowerAlg.h:251
key_type key() const
Definition: Ptr.h:356
geo::Length_t WireCoordinate(double YPos, double ZPos, geo::PlaneID const &planeid) const
Returns the index of the nearest wire to the specified position.
void XYZ(double *xyz) const
Legacy method to access vertex position, preserved to avoid breaking code. Please try to use Vertex::...
Definition: Vertex.cxx:37
double GlobalWire(const geo::WireID &wireID)
Find the global wire position.
PlaneID const & planeID() const
Definition: geo_types.h:355
double z
z position of intersection
Definition: geo_types.h:494
std::vector< double > fToler
Definition: EMShowerAlg.h:231
double ShowerEnergy(std::vector< art::Ptr< recob::Hit > > const &hits, int plane)
Finds the total energy deposited by the shower in this view.
PlaneGeo const & Plane(unsigned int const p, unsigned int const tpc=0, unsigned int const cstat=0) const
Returns the specified wire.
Int_t WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm)
<Tingjun to="" document>="">
void FindInitialTrackHits(std::vector< art::Ptr< recob::Hit > >const &showerHits, art::Ptr< recob::Vertex > const &vertex, std::vector< art::Ptr< recob::Hit > > &trackHits)
<Tingjun to="" document>="">
EMShowerAlg(fhicl::ParameterSet const &pset)
Definition: EMShowerAlg.cxx:13
double dEdx_AREA(art::Ptr< recob::Hit > hit, double pitch, double T0=0) const
intermediate_table::iterator iterator
std::vector< recob::SpacePoint > MakeSpacePoints(std::map< int, std::vector< art::Ptr< recob::Hit > > > hits, std::vector< std::vector< art::Ptr< recob::Hit > > > &hitAssns)
Makes space points from the shower hits in each plane.
ROOT::Math::SMatrix< Double32_t, 5, 5, ROOT::Math::MatRepSym< Double32_t, 5 > > SMatrixSym55
Definition: TrackingTypes.h:85
T::provider_type const * providerFrom()
Returns a constant pointer to the provider of specified service.
Definition: ServiceUtil.h:77
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
std::map< int, std::vector< art::Ptr< recob::Hit > > > FindShowerStart(std::map< int, std::vector< art::Ptr< recob::Hit > > > const &orderedShowerMap)
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
Initial tdc tick for hit.
Definition: Hit.h:234
iterator begin()
Definition: PtrVector.h:223
Float_t y
Definition: compare.C:6
TVector3 Construct3DPoint(art::Ptr< recob::Hit > const &hit1, art::Ptr< recob::Hit > const &hit2)
Constructs a 3D point (in [cm]) to represent the hits given in two views.
::fhicl::TupleAs< Point(::geo::Length_t,::geo::Length_t,::geo::Length_t)> Point3D
Atom object for reading a 3D point or vector (centimeters).
Float_t Y
Definition: plot.C:39
The data type to uniquely identify a Plane.
Definition: geo_types.h:250
bool isValid
Whether this ID points to a valid element.
Definition: geo_types.h:129
TVector2 Project3DPointOntoPlane(TVector3 const &point, int plane, int cryostat=0)
TrackTrajectory::Flags_t Flags_t
Definition: Track.h:71
bool CheckShowerHits(std::map< int, std::vector< art::Ptr< recob::Hit > > > const &showerHitsMap)
Vector_t VertexDirection() const
Access to track direction at different points.
Definition: Track.h:135
std::map< int, std::vector< art::Ptr< recob::Hit > > > OrderShowerHits(const art::PtrVector< recob::Hit > &shower, int plane)
Takes the hits associated with a shower and orders them so they follow the direction of the shower...
CryostatID_t Cryostat
Index of cryostat.
Definition: geo_types.h:130
for(int i=0;i< 401;i++)
float Integral() const
Integral under the calibrated signal waveform of the hit, in tick x ADC units.
Definition: Hit.h:225
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
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.
TVector2 HitPosition(art::Ptr< recob::Hit > const &hit)
Return the coordinates of this hit in units of cm.
int FindParticleID(const art::Ptr< recob::Hit > &hit)
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
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.
virtual double ConvertXToTicks(double X, int p, int t, int c) const =0
TVector2 ShowerDirection(const std::vector< art::Ptr< recob::Hit > > &showerHits)
Returns a rough charge-weighted shower &#39;direction&#39; given the hits in the shower.
bool isCleanShower(std::vector< art::Ptr< recob::Hit > > const &hits)
<Tingjun to="" document>="">
calo::CalorimetryAlg fCalorimetryAlg
Definition: EMShowerAlg.h:240
TVector2 ShowerCentre(const std::vector< art::Ptr< recob::Hit > > &showerHits)
Returns the charge-weighted shower centre.
geo::TPCID FindTPCAtPosition(double const worldLoc[3]) const
Returns the ID of the TPC at specified location.
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
std::unique_ptr< recob::Track > MakeInitialTrack(std::map< int, std::vector< art::Ptr< recob::Hit > > > const &initialHitsMap, std::map< int, std::vector< art::Ptr< recob::Hit > > > const &showerHitsMap)
Takes initial track hits from multiple views and forms a track object which best represents the start...
View_t View() const
Which coordinate does this plane measure.
Definition: PlaneGeo.h:171
void hits()
Definition: readHits.C:15
unsigned int MaxPlanes() const
Returns the largest number of planes among all TPCs in this detector.
if(nlines<=0)
std::vector< std::vector< int > > FindShowers(std::map< int, std::vector< int > > const &trackToClusters)
Makes showers given a map between tracks and all clusters associated with them.
intermediate_table::const_iterator const_iterator
Signal from induction planes.
Definition: geo_types.h:92
A trajectory in space reconstructed from hits.
int WorstPlane(const std::map< int, std::vector< art::Ptr< recob::Hit > > > &showerHitsMap)
Returns the plane which is determined to be the least likely to be correct.
parameter set interface
unsigned int fNfitpass
Definition: EMShowerAlg.h:229
T get(std::string const &key) const
Definition: ParameterSet.h:231
std::vector< evd::details::RawDigitInfo_t >::const_iterator begin(RawDigitCacheDataClass const &cache)
pma::Track3D * buildSegment(const std::vector< art::Ptr< recob::Hit > > &hits_1, const std::vector< art::Ptr< recob::Hit > > &hits_2=std::vector< art::Ptr< recob::Hit > >()) const
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)
Map associated tracks and clusters together given their associated hits.
Definition: EMShowerAlg.cxx:43
Point_t const & Vertex() const
Access to track position at different points.
Definition: Track.h:127
iterator end()
Definition: PtrVector.h:237
std::string fDetector
Definition: EMShowerAlg.h:243
shower::ShowerEnergyAlg fShowerEnergyAlg
Definition: EMShowerAlg.h:239
pma::ProjectionMatchingAlg fProjectionMatchingAlg
Definition: EMShowerAlg.h:241
std::map< int, std::map< int, bool > > GetPlanePermutations(const std::map< int, std::vector< art::Ptr< recob::Hit > > > &showerHitsMap)
std::vector< Point_t > convertCollToPoint(std::vector< Point > const &coll)
Definition: TrackingTypes.h:55
General LArSoft Utilities.
double ShowerHitRMS(const std::vector< art::Ptr< recob::Hit > > &showerHits)
Returns the RMS of the hits from the central shower &#39;axis&#39; along the length of the shower...
The data type to uniquely identify a TPC.
Definition: geo_types.h:195
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:258
art::ServiceHandle< geo::Geometry > fGeom
Definition: EMShowerAlg.h:234
std::unique_ptr< recob::Track > ConstructTrack(std::vector< art::Ptr< recob::Hit > > const &track1, std::vector< art::Ptr< recob::Hit > > const &track2, std::map< int, TVector2 > const &showerCentreMap)
double FinddEdx(std::vector< art::Ptr< recob::Hit > > const &trackHits, std::unique_ptr< recob::Track > const &track)
Finds dE/dx for the track given a set of hits.
Detector simulation of raw signals on wires.
double ShowerHitRMSGradient(const std::vector< art::Ptr< recob::Hit > > &showerHits, TVector2 trueStart=TVector2(0, 0))
Returns the gradient of the RMS vs shower segment graph.
void FindInitialTrack(const std::map< int, std::vector< art::Ptr< recob::Hit > > > &hits, std::unique_ptr< recob::Track > &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit > > > &initialTrackHits, int plane)
Finds the initial track-like part of the shower and the hits in all views associated with it...
data_t::const_iterator const_iterator
Definition: PtrVector.h:61
void CheckIsolatedHits(std::map< int, std::vector< art::Ptr< recob::Hit > > > &showerHitsMap)
Checks the hits across the views in a given shower to determine if there is one in the incorrect TPC...
bool WireIDsIntersect(WireID const &wid1, WireID const &wid2, geo::Point_t &intersection) const
Computes the intersection between two wires.
cet::coded_exception< errors::ErrorCodes, ExceptionDetail::translate > Exception
Definition: Exception.h:66
virtual double ConvertTicksToX(double ticks, int p, int t, int c) const =0
double weight
Definition: plottest35.C:25
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
T * make(ARGS...args) const
std::string to_string(Flag_t< Storage > const flag)
Convert a flag into a stream (shows its index).
Definition: BitMask.h:187
art::ServiceHandle< art::TFileService > tfs
Definition: EMShowerAlg.h:236
LArSoft-specific namespace.
TProfile * hNumHitsInSegment
Definition: EMShowerAlg.h:251
double y
y position of intersection
Definition: geo_types.h:493
Float_t proj
Definition: plot.C:34
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
std::vector< art::Ptr< recob::Hit > > FindOrderOfHits(std::vector< art::Ptr< recob::Hit > > const &hits, bool perpendicular=false)
detinfo::DetectorProperties const * fDetProp
Definition: EMShowerAlg.h:235
Exception thrown on invalid wire number.
Definition: Exceptions.h:42
recob::Shower MakeShower(art::PtrVector< recob::Hit > const &hits, std::unique_ptr< recob::Track > const &initialTrack, std::map< int, std::vector< art::Ptr< recob::Hit > > > const &initialTrackHits)
Makes a recob::Shower object given the hits in the shower and the initial track-like part...
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.
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)
Takes the initial showers found and tries to resolve issues where one bad view ruins the event...
Char_t n[5]
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
TVector2 HitCoordinates(art::Ptr< recob::Hit > const &hit)
Return the coordinates of this hit in global wire/tick space.
bool isNull() const
Definition: Ptr.h:328
double TrackPitchInView(recob::Track const &track, geo::View_t view, size_t trajectory_point=0)
Provides projected wire pitch for the view.
Definition: TrackUtils.cxx:76
void GetCenter(double *xyz, double localz=0.0) const
Fills the world coordinate of a point on the wire.
Definition: WireGeo.cxx:68
std::vector< unsigned int > fNfithits
Definition: EMShowerAlg.h:230
TPCID_t TPC
Index of the TPC within its cryostat.
Definition: geo_types.h:203
Float_t e
Definition: plot.C:34
size_t size() const
Definition: PmaTrack3D.h:76
geo::WireID suggestedWireID() const
Returns a better wire ID.
Definition: Exceptions.h:120
recob::tracking::Plane Plane
Definition: TrackState.h:17
Float_t X
Definition: plot.C:39
Namespace collecting geometry-related classes utilities.
Float_t track
Definition: plot.C:34
Float_t w
Definition: plot.C:23
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< double, int > RelativeWireWidth(const std::map< int, std::vector< art::Ptr< recob::Hit > > > &showerHitsMap)
WireGeo const & WireIDToWireGeo(geo::WireID const &wireid) const
Returns the specified wire.
int FindTrueParticle(const std::vector< art::Ptr< recob::Hit > > &showerHits)
vertex reconstruction