LArSoft  v06_85_00
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>(xyz, dircos, dEdx);
527 
528  return track;
529 
530 }
531 
532 std::unique_ptr<recob::Track> shower::EMShowerAlg::ConstructTrack(std::vector<art::Ptr<recob::Hit> > const& track1,
533  std::vector<art::Ptr<recob::Hit> > const& track2) {
534 
535  std::map<int,TVector2> showerCentreMap;
536 
537  return this->ConstructTrack(track1, track2, showerCentreMap);
538 
539 }
540 
541 double shower::EMShowerAlg::FinddEdx(std::vector<art::Ptr<recob::Hit> > const& trackHits, std::unique_ptr<recob::Track> const& track) {
542 
543  double totalCharge = 0, totalDistance = 0, avHitTime = 0;
544  unsigned int nHits = 0;
545 
546  if (!track)
547  return -999;
548 
549  // size_t trajectory_point = 0;
550  // double wirePitch = fGeom->WirePitch(trackHits.at(0)->View(), 1, 0);
551  // double angleToVert = fGeom->WireAngleToVertical(trackHits.at(0)->View(), 1, 0) - 0.5*::util::pi<>();
552  // const TVector3& dir = track->DirectionAtPoint(trajectory_point);
553  // //(sin(angleToVert),cos(angleToVert)) is the direction perpendicular to wire
554  // double cosgamma = std::abs(std::sin(angleToVert)*dir.Y() +
555  // std::cos(angleToVert)*dir.Z());
556 
557  // if(cosgamma < 1.e-5)
558  // throw cet::exception("Track") << "cosgamma is basically 0, that can't be right\n";
559  // double pitch = wirePitch/cosgamma;
560 
561  // Get the pitch
562  double pitch = 0;
563  try { pitch = lar::util::TrackPitchInView(*track, trackHits.at(0)->View()); }
564  catch(...) { pitch = 0; }
565 
566  // Deal with large pitches
567  if (pitch > fdEdxTrackLength) {
568  double dEdx = fCalorimetryAlg.dEdx_AREA(*trackHits.begin(), pitch);
569  return dEdx;
570  }
571 
572  for (std::vector<art::Ptr<recob::Hit> >::const_iterator trackHitIt = trackHits.begin(); trackHitIt != trackHits.end(); ++trackHitIt) {
573  if (totalDistance + pitch < fdEdxTrackLength) {
574  totalDistance += pitch;
575  totalCharge += (*trackHitIt)->Integral();
576  avHitTime += (*trackHitIt)->PeakTime();
577  ++nHits;
578  }
579  }
580 
581  avHitTime /= (double)nHits;
582 
583  double dQdx = totalCharge / totalDistance;
584  double dEdx = fCalorimetryAlg.dEdx_AREA(dQdx, avHitTime, trackHits.at(0)->WireID().Plane);
585 
586  return dEdx;
587 
588 }
589 
590 void shower::EMShowerAlg::FindInitialTrack(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap,
591  std::unique_ptr<recob::Track>& initialTrack,
592  std::map<int,std::vector<art::Ptr<recob::Hit> > >& initialTrackHits, int plane) {
593 
598 
599  // // First, order the hits into the correct shower order in each plane
600  // if (fDebug > 1)
601  // std::cout << " ------------------ Ordering shower hits -------------------- " << std::endl;
602  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHitsMap = OrderShowerHits(hits, plane);
603  // if (fDebug > 1)
604  // std::cout << " ------------------ End ordering shower hits -------------------- " << std::endl;
605 
606  // Now find the hits belonging to the track
607  if (fDebug > 1)
608  std::cout << " ------------------ Finding initial track hits -------------------- " << std::endl;
609  initialTrackHits = FindShowerStart(showerHitsMap);
610  if (fDebug > 1) {
611  std::cout << "Here are the initial shower hits... " << std::endl;
612  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator initialTrackHitsIt = initialTrackHits.begin(); initialTrackHitsIt != initialTrackHits.end(); ++initialTrackHitsIt) {
613  std::cout << " Plane " << initialTrackHitsIt->first << std::endl;
614  for (std::vector<art::Ptr<recob::Hit> >::iterator initialTrackHitIt = initialTrackHitsIt->second.begin(); initialTrackHitIt != initialTrackHitsIt->second.end(); ++initialTrackHitIt)
615  std::cout << " Hit is (" << HitCoordinates(*initialTrackHitIt).X() << " (real hit " << (*initialTrackHitIt)->WireID() << "), " << HitCoordinates(*initialTrackHitIt).Y() << ")" << std::endl;
616  }
617  }
618  if (fDebug > 1)
619  std::cout << " ------------------ End finding initial track hits -------------------- " << std::endl;
620 
621  // Now we have the track hits -- can make a track!
622  if (fDebug > 1)
623  std::cout << " ------------------ Finding initial track -------------------- " << std::endl;
624  initialTrack = MakeInitialTrack(initialTrackHits, showerHitsMap);
625  if (initialTrack and fDebug > 1) {
626  std::cout << "The track start is (" << initialTrack->Vertex().X() << ", " << initialTrack->Vertex().Y() << ", " << initialTrack->Vertex().Z() << ")" << std::endl;
627  std::cout << "The track direction is (" << initialTrack->VertexDirection().X() << ", " << initialTrack->VertexDirection().Y() << ", " << initialTrack->VertexDirection().Z() << ")" << std::endl;
628  }
629  if (fDebug > 1)
630  std::cout << " ------------------ End finding initial track -------------------- " << std::endl;
631 
632  // // Fill correct or incorrect direction histogram
633  // std::map<int,int> trackHits;
634  // for (art::PtrVector<recob::Hit>::const_iterator hitIt = hits.begin(); hitIt != hits.end(); ++hitIt)
635  // ++trackHits[FindTrackID(*hitIt)];
636  // int trueTrack = -9999;
637  // for (std::map<int,int>::iterator trackHitIt = trackHits.begin(); trackHitIt != trackHits.end(); ++trackHitIt)
638  // if (trackHitIt->second/(double)hits.size() > 0.8)
639  // trueTrack = trackHitIt->first;
640  // if (trueTrack != -9999) {
641  // const simb::MCParticle* trueParticle = backtracker->TrackIDToParticle(trueTrack);
642  // TVector3 trueStart = trueParticle->Position().Vect();
643  // if (initialTrack) {
644  // TVector3 recoStart = initialTrack->Vertex();
645  // if ((recoStart-trueStart).Mag() < 5)
646  // hTrueDirection->Fill(1);
647  // else
648  // hTrueDirection->Fill(0);
649  // }
650  // }
651  // else
652  // hTrueDirection->Fill(0);
653 
654  return;
655 
656 }
657 
658 std::vector<art::Ptr<recob::Hit> > shower::EMShowerAlg::FindOrderOfHits(std::vector<art::Ptr<recob::Hit> > const& hits, bool perpendicular) {
659 
660  // Find the charge-weighted centre (in [cm]) of this shower
661  TVector2 centre = ShowerCentre(hits);
662 
663  // Find a rough shower 'direction'
664  TVector2 direction = ShowerDirection(hits);
665 
666  if (perpendicular)
667  direction = direction.Rotate(TMath::Pi()/2);
668 
669  // Find how far each hit (projected onto this axis) is from the centre
670  TVector2 pos;
671  std::map<double,art::Ptr<recob::Hit> > hitProjection;
672  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = hits.begin(); hit != hits.end(); ++hit) {
673  pos = HitPosition(*hit) - centre;
674  hitProjection[direction*pos] = *hit;
675  }
676 
677  // Get a vector of hits in order of the shower
678  std::vector<art::Ptr<recob::Hit> > showerHits;
679  std::transform(hitProjection.begin(), hitProjection.end(), std::back_inserter(showerHits), [](std::pair<double,art::Ptr<recob::Hit> > const& hit) { return hit.second; });
680 
681  // Make gradient plot
682  if (fMakeGradientPlot) {
683  std::map<int,TGraph*> graphs;
684  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHits.begin(); hitIt != showerHits.end(); ++hitIt) {
685  int tpc = (*hitIt)->WireID().TPC;
686  if (graphs[tpc] == nullptr)
687  graphs[tpc] = new TGraph();
688  graphs[tpc]->SetPoint(graphs[tpc]->GetN(), HitPosition(*hitIt).X(), HitPosition(*hitIt).Y());
689  //graphs[tpc]->SetPoint(graphs[tpc]->GetN(), HitCoordinates(*hitIt).X(), HitCoordinates(*hitIt).Y());
690  }
691  TMultiGraph* multigraph = new TMultiGraph();
692  for (std::map<int,TGraph*>::iterator graphIt = graphs.begin(); graphIt != graphs.end(); ++graphIt) {
693  graphIt->second->SetMarkerColor(graphIt->first);
694  graphIt->second->SetMarkerStyle(8);
695  graphIt->second->SetMarkerSize(2);
696  multigraph->Add(graphIt->second);
697  }
698  TCanvas* canvas = new TCanvas();
699  multigraph->Draw("AP");
700  TLine line;
701  line.SetLineColor(2);
702  line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
703  canvas->SaveAs("Gradient.png");
704  delete canvas; delete multigraph;
705  }
706 
707  return showerHits;
708 
709 }
710 
711 std::vector<std::vector<int> > shower::EMShowerAlg::FindShowers(std::map<int,std::vector<int> > const& trackToClusters) {
712 
713  // Showers are vectors of clusters
714  std::vector<std::vector<int> > showers;
715 
716  // Loop over all tracks
717  for (std::map<int,std::vector<int> >::const_iterator trackToClusterIt = trackToClusters.begin(); trackToClusterIt != trackToClusters.end(); ++ trackToClusterIt) {
718 
719  // Find which showers already made are associated with this track
720  std::vector<int> matchingShowers;
721  for (unsigned int shower = 0; shower < showers.size(); ++shower)
722  for (std::vector<int>::const_iterator cluster = trackToClusterIt->second.begin(); cluster != trackToClusterIt->second.end(); ++cluster)
723  if ( (std::find(showers.at(shower).begin(), showers.at(shower).end(), *cluster) != showers.at(shower).end()) and
724  (std::find(matchingShowers.begin(), matchingShowers.end(), shower)) == matchingShowers.end() )
725  matchingShowers.push_back(shower);
726 
727  // THINK THERE PROBABLY CAN BE MORE THAN ONE!
728  // IN FACT, THIS WOULD BE A SUCCESS OF THE SHOWERING METHOD!
729  // // Shouldn't be more than one
730  // if (matchingShowers.size() > 1)
731  // mf::LogInfo("EMShowerAlg") << "Number of showers this track matches is " << matchingShowers.size() << std::endl;
732 
733  // New shower
734  if (matchingShowers.size() < 1)
735  showers.push_back(trackToClusterIt->second);
736 
737  // Add to existing shower
738  else {
739  for (std::vector<int>::const_iterator cluster = trackToClusterIt->second.begin(); cluster != trackToClusterIt->second.end(); ++cluster)
740  if (std::find(showers.at(matchingShowers.at(0)).begin(), showers.at(matchingShowers.at(0)).end(), *cluster) == showers.at(matchingShowers.at(0)).end())
741  showers.at(matchingShowers.at(0)).push_back(*cluster);
742  }
743  }
744 
745  return showers;
746 
747 }
748 
749 std::map<int,std::vector<art::Ptr<recob::Hit> > > shower::EMShowerAlg::FindShowerStart(std::map<int,std::vector<art::Ptr<recob::Hit> > > const& orderedShowerMap) {
750 
751  std::map<int,std::vector<art::Ptr<recob::Hit> > > initialHitsMap;
752 
753  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator orderedShowerIt = orderedShowerMap.begin(); orderedShowerIt != orderedShowerMap.end(); ++orderedShowerIt) {
754 
755  std::vector<art::Ptr<recob::Hit> > initialHits;
756  const std::vector<art::Ptr<recob::Hit> > orderedShower = orderedShowerIt->second;
757 
758  // Find if the shower is travelling along ticks or wires
759  bool wireDirection = true;
760  std::vector<int> wires;
761  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
762  wires.push_back(std::round(HitCoordinates(*hitIt).X()));
763  std::sort(wires.begin(), wires.end());
764  if (TMath::Abs(*wires.begin()-std::round(HitCoordinates(*orderedShower.begin()).X())) > 3 and
765  TMath::Abs(*wires.rbegin()-std::round(HitCoordinates(*orderedShower.begin()).X())) > 3)
766  wireDirection = false;
767 
768  // Deal with showers travelling along wires
769  if (wireDirection) {
770  bool increasing = HitCoordinates(*orderedShower.rbegin()).X() > HitCoordinates(*orderedShower.begin()).X();
771  std::map<int,std::vector<art::Ptr<recob::Hit> > > wireHitMap;
772  int multipleWires = 0;
773  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
774  wireHitMap[std::round(HitCoordinates(*hitIt).X())].push_back(*hitIt);
775  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt) {
776  int wire = std::round(HitCoordinates(*hitIt).X());
777  if (wireHitMap[wire].size() > 1) {
778  ++multipleWires;
779  if (multipleWires > 5) break;
780  continue;
781  }
782  else if ( (increasing and wireHitMap[wire+1].size() > 1 and (wireHitMap[wire+2].size() > 1 or wireHitMap[wire+3].size() > 1)) or
783  (!increasing and wireHitMap[wire-1].size() > 1 and (wireHitMap[wire-2].size() > 1 or wireHitMap[wire-3].size() > 1)) ) {
784  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
785  (!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) )
786  initialHits.push_back(*hitIt);
787  else
788  break;
789  }
790  else
791  initialHits.push_back(*hitIt);
792  }
793  if (!initialHits.size()) initialHits.push_back(*orderedShower.begin());
794  }
795 
796  // Deal with showers travelling along ticks
797  else {
798  bool increasing = HitCoordinates(*orderedShower.rbegin()).Y() > HitCoordinates(*orderedShower.begin()).Y();
799  std::map<int,std::vector<art::Ptr<recob::Hit> > > tickHitMap;
800  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt)
801  tickHitMap[std::round(HitCoordinates(*hitIt).Y())].push_back(*hitIt);
802  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hitIt = orderedShower.begin(); hitIt != orderedShower.end(); ++hitIt) {
803  int tick = std::round(HitCoordinates(*hitIt).Y());
804  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
805  (!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())) )
806  break;
807  else
808  initialHits.push_back(*hitIt);
809  }
810  if (!initialHits.size()) initialHits.push_back(*orderedShower.begin());
811  }
812 
813  // Need at least two hits to make a track
814  if (initialHits.size() == 1 and orderedShower.size() > 2)
815  initialHits.push_back(orderedShower.at(1));
816 
817  // Quality check -- make sure there isn't a single hit in a different TPC (artefact of tracking failure)
818  std::vector<art::Ptr<recob::Hit> > newInitialHits;
819  std::map<int,int> tpcHitMap;
820  std::vector<int> singleHitTPCs;
821  for (std::vector<art::Ptr<recob::Hit> >::iterator initialHitIt = initialHits.begin(); initialHitIt != initialHits.end(); ++initialHitIt)
822  ++tpcHitMap[(*initialHitIt)->WireID().TPC];
823  for (std::map<int,int>::iterator tpcIt = tpcHitMap.begin(); tpcIt != tpcHitMap.end(); ++tpcIt)
824  if (tpcIt->second == 1) singleHitTPCs.push_back(tpcIt->first);
825  if (singleHitTPCs.size()) {
826  if (fDebug > 2)
827  for (std::vector<int>::iterator tpcIt = singleHitTPCs.begin(); tpcIt != singleHitTPCs.end(); ++tpcIt)
828  std::cout << "Removed hits in TPC " << *tpcIt << std::endl;
829  for (std::vector<art::Ptr<recob::Hit> >::iterator initialHitIt = initialHits.begin(); initialHitIt != initialHits.end(); ++initialHitIt)
830  if (std::find(singleHitTPCs.begin(), singleHitTPCs.end(), (*initialHitIt)->WireID().TPC) == singleHitTPCs.end())
831  newInitialHits.push_back(*initialHitIt);
832  if (!newInitialHits.size()) newInitialHits.push_back(*orderedShower.begin());
833  }
834  else
835  newInitialHits = initialHits;
836 
837  initialHitsMap[orderedShowerIt->first] = newInitialHits;
838 
839  }
840 
841  return initialHitsMap;
842 
843 }
844 
845 std::map<int,std::map<int,bool> > shower::EMShowerAlg::GetPlanePermutations(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
846 
847  // The map to return
848  std::map<int,std::map<int,bool> > permutations;
849 
850  // Get the properties of the shower hits across the planes which will be used to
851  // determine the likelihood of a particular reorientation permutation
852  // -- relative width in the wire direction (if showers travel along the wire
853  // direction in a particular plane)
854  // -- the RMS gradients (how likely it is the RMS of the hit positions from
855  // central axis increases along a particular orientation)
856 
857  // Find the RMS, RMS gradient and wire widths
858  std::map<int,double> planeRMSGradients, planeRMS;
859  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
860  planeRMS[showerHitsIt->first] = ShowerHitRMS(showerHitsIt->second);
861  planeRMSGradients[showerHitsIt->first] = ShowerHitRMSGradient(showerHitsIt->second);
862  }
863 
864  // Order these backwards so they can be used to discriminate between planes
865  std::map<double,int> gradientMap;
866  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
867  gradientMap[TMath::Abs(planeRMSGradients.at(showerHitsIt->first))] = showerHitsIt->first;
868 
869  std::map<double,int> wireWidthMap = RelativeWireWidth(showerHitsMap);
870 
871  if (fDebug > 1)
872  for (std::map<double,int>::const_iterator wireWidthIt = wireWidthMap.begin(); wireWidthIt != wireWidthMap.end(); ++wireWidthIt)
873  std::cout << "Plane " << wireWidthIt->second << " has relative width in wire of " << wireWidthIt->first << "; and an RMS gradient of " << planeRMSGradients[wireWidthIt->second] << std::endl;
874 
875  // Find the correct permutations
876  int perm = 0;
877  std::vector<std::map<int,bool> > usedPermutations;
878 
879  // Most likely is to not change anything
880  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
881  permutations[perm][showerHitsIt->first] = 0;
882  ++perm;
883 
884  // Use properties of the shower to determine the middle cases
885  for (std::map<double,int>::iterator wireWidthIt = wireWidthMap.begin(); wireWidthIt != wireWidthMap.end(); ++wireWidthIt) {
886  std::map<int,bool> permutation;
887  permutation[wireWidthIt->second] = 1;
888  for (std::map<double,int>::iterator wireWidth2It = wireWidthMap.begin(); wireWidth2It != wireWidthMap.end(); ++wireWidth2It)
889  if (wireWidthIt->second != wireWidth2It->second)
890  permutation[wireWidth2It->second] = 0;
891  if (std::find(usedPermutations.begin(), usedPermutations.end(), permutation) == usedPermutations.end()) {
892  permutations[perm] = permutation;
893  usedPermutations.push_back(permutation);
894  ++perm;
895  }
896  }
897  for (std::map<double,int>::reverse_iterator wireWidthIt = wireWidthMap.rbegin(); wireWidthIt != wireWidthMap.rend(); ++wireWidthIt) {
898  std::map<int,bool> permutation;
899  permutation[wireWidthIt->second] = 0;
900  for (std::map<double,int>::iterator wireWidth2It = wireWidthMap.begin(); wireWidth2It != wireWidthMap.end(); ++wireWidth2It)
901  if (wireWidthIt->second != wireWidth2It->second)
902  permutation[wireWidth2It->second] = 1;
903  if (std::find(usedPermutations.begin(), usedPermutations.end(), permutation) == usedPermutations.end()) {
904  permutations[perm] = permutation;
905  usedPermutations.push_back(permutation);
906  ++perm;
907  }
908  }
909 
910  // Least likely is to change everything
911  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
912  permutations[perm][showerHitsIt->first] = 1;
913  ++perm;
914 
915  if (fDebug > 1) {
916  std::cout << "Here are the permutations!" << std::endl;
917  for (std::map<int,std::map<int,bool> >::iterator permIt = permutations.begin(); permIt != permutations.end(); ++permIt) {
918  std::cout << "Permutation " << permIt->first << std::endl;
919  for (std::map<int,bool>::iterator planePermIt = permIt->second.begin(); planePermIt != permIt->second.end(); ++planePermIt)
920  std::cout << " Plane " << planePermIt->first << " has value " << planePermIt->second << std::endl;
921  }
922  }
923 
924  return permutations;
925 
926 }
927 
928 std::unique_ptr<recob::Track> shower::EMShowerAlg::MakeInitialTrack(std::map<int,std::vector<art::Ptr<recob::Hit> > > const& initialHitsMap,
929  std::map<int,std::vector<art::Ptr<recob::Hit> > > const& showerHitsMap) {
930 
931  // Can't do much with just one view
932  if (initialHitsMap.size() < 2) {
933  mf::LogInfo("EMShowerAlg") << "Only one useful view for this shower; nothing can be done" << std::endl;
934  return std::unique_ptr<recob::Track>();
935  }
936 
937  std::vector<std::pair<int,int> > initialHitsSize;
938  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator initialHitIt = initialHitsMap.begin(); initialHitIt != initialHitsMap.end(); ++initialHitIt)
939  initialHitsSize.push_back(std::make_pair(initialHitIt->first, initialHitIt->second.size()));
940 
941  // Sort the planes by number of hits
942  std::sort(initialHitsSize.begin(), initialHitsSize.end(), [](std::pair<int,int> const& size1, std::pair<int,int> const& size2) { return size1.second > size2.second; });
943 
944  // Pick the two planes to use to make the track
945  // -- if more than two planes, can choose the two views
946  // more accurately
947  // -- if not, just use the two views available
948 
949  std::vector<int> planes;
950 
951  if (initialHitsSize.size() > 2 and !CheckShowerHits(showerHitsMap)) {
952  int planeToIgnore = WorstPlane(showerHitsMap);
953  if (fDebug > 1)
954  std::cout << "Igoring plane " << planeToIgnore << " in creation of initial track" << std::endl;
955  for (std::vector<std::pair<int,int> >::iterator hitsSizeIt = initialHitsSize.begin(); hitsSizeIt != initialHitsSize.end() and planes.size() < 2; ++hitsSizeIt) {
956  if (hitsSizeIt->first == planeToIgnore)
957  continue;
958  planes.push_back(hitsSizeIt->first);
959  }
960  }
961  else
962  planes = {initialHitsSize.at(0).first, initialHitsSize.at(1).first};
963 
964  return ConstructTrack(initialHitsMap.at(planes.at(0)), initialHitsMap.at(planes.at(1)));
965 
966 }
967 
969  std::unique_ptr<recob::Track> const& initialTrack,
970  std::map<int,std::vector<art::Ptr<recob::Hit> > > const& initialHitsMap) {
971 
972  //return recob::Shower();
973 
974  // Find the shower hits on each plane
975  std::map<int,std::vector<art::Ptr<recob::Hit> > > planeHitsMap;
976  for (art::PtrVector<recob::Hit>::const_iterator hit = hits.begin(); hit != hits.end(); ++hit)
977  planeHitsMap[(*hit)->View()].push_back(*hit);
978 
979  int bestPlane = -1;
980  unsigned int highestNumberOfHits = 0;
981  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
982 
983  // Look at each of the planes
984  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
985 
986  // If there's hits on this plane...
987  if (planeHitsMap.count(plane)) {
988  dEdx.push_back(FinddEdx(initialHitsMap.at(plane), initialTrack));
989  totalEnergy.push_back(fShowerEnergyAlg.ShowerEnergy(planeHitsMap.at(plane), plane));
990  if (planeHitsMap.at(plane).size() > highestNumberOfHits and initialHitsMap.count(plane)) {
991  bestPlane = plane;
992  highestNumberOfHits = planeHitsMap.at(plane).size();
993  }
994  }
995 
996  // If not...
997  else {
998  dEdx.push_back(0);
999  totalEnergy.push_back(0);
1000  }
1001 
1002  }
1003 
1004  TVector3 direction, directionError, showerStart, showerStartError;
1005  if (initialTrack) {
1006  direction = initialTrack->VertexDirection();
1007  showerStart = initialTrack->Vertex();
1008  }
1009 
1010  if (fDebug > 0) {
1011  std::cout << "Best plane is " << bestPlane << std::endl;
1012  std::cout << "dE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and " << dEdx[2] << std::endl;
1013  std::cout << "Total energy for each plane is: " << totalEnergy[0] << ", " << totalEnergy[1] << " and " << totalEnergy[2] << std::endl;
1014  std::cout << "The shower start is (" << showerStart.X() << ", " << showerStart.Y() << ", " << showerStart.Z() << ")" << std::endl;
1015  std::cout << "The shower direction is (" << direction.X() << ", " << direction.Y() << ", " << direction.Z() << ")" << std::endl;
1016  }
1017 
1018  return recob::Shower(direction, directionError, showerStart, showerStartError, totalEnergy, totalEnergyError, dEdx, dEdxError, bestPlane);
1019 
1020 }
1021 
1024  int & iok) {
1025 
1026  iok = 1;
1027 
1028  // Find the shower hits on each plane
1029  std::map<int,std::vector<art::Ptr<recob::Hit> > > planeHitsMap;
1030  for (art::PtrVector<recob::Hit>::const_iterator hit = hits.begin(); hit != hits.end(); ++hit)
1031  planeHitsMap[(*hit)->WireID().Plane].push_back(*hit);
1032 
1033  std::vector<std::vector<art::Ptr<recob::Hit> > > initialTrackHits(3);
1034 
1035  int pl0 = -1;
1036  int pl1 = -1;
1037  unsigned maxhits0 = 0;
1038  unsigned maxhits1 = 0;
1039 
1040  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeHits = planeHitsMap.begin(); planeHits != planeHitsMap.end(); ++planeHits) {
1041 
1042  std::vector<art::Ptr<recob::Hit> > showerHits;
1043  OrderShowerHits(planeHits->second, showerHits, vertex);
1044  //if (!isCleanShower(showerHits)) continue;
1045  FindInitialTrackHits(showerHits, vertex, initialTrackHits[planeHits->first]);
1046  if ((planeHits->second).size()>maxhits0){
1047  if (pl0!=-1){
1048  maxhits1 = maxhits0;
1049  pl1 = pl0;
1050  }
1051  pl0 = planeHits->first;
1052  maxhits0 = (planeHits->second).size();
1053  }
1054  else if ((planeHits->second).size()>maxhits1){
1055  pl1 = planeHits->first;
1056  maxhits1 = (planeHits->second).size();
1057  }
1058 
1059  }
1060  //std::cout<<pl0<<" "<<pl1<<std::endl;
1061 // if (pl0!=-1&&pl1!=-1) {
1062 // pl0 = 1;
1063 // pl1 = 2;
1064 // }
1065  if (pl0!=-1&&pl1!=-1
1066  &&initialTrackHits[pl0].size()>=2
1067  &&initialTrackHits[pl1].size()>=2
1068  &&initialTrackHits[pl0][0]->WireID().TPC==
1069  initialTrackHits[pl1][0]->WireID().TPC){
1070  double xyz[3];
1071  vertex->XYZ(xyz);
1072  TVector3 vtx(xyz);
1073 // std::vector<art::Ptr<recob::Hit>> alltrackhits;
1074 // for (size_t i = 0; i<3; ++i){
1075 // for (auto const&hit : initialTrackHits[i]){
1076 // alltrackhits.push_back(hit);
1077 // }
1078 // }
1079  //std::cout<<"vertex "<<xyz[0]<<" "<<xyz[1]<<" "<<xyz[2]<<std::endl;
1080  //for (auto const&hit : initialTrackHits[pl0]) std::cout<<*hit<<std::endl;
1081  //for (auto const&hit : initialTrackHits[pl1]) std::cout<<*hit<<std::endl;
1082  pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(initialTrackHits[pl0], initialTrackHits[pl1]);
1083  //std::cout<<pmatrack->size()<<std::endl;
1084  //pma::Track3D* pmatrack = fProjectionMatchingAlg.buildSegment(alltrackhits);
1085  std::vector<TVector3> spts;
1086 
1087 // points are shifted now by tracking code, commented out shifts here
1088 // double xshift = pmatrack->GetXShift();
1089 // bool has_shift = (xshift != 0.0);
1090  for (size_t i = 0; i<pmatrack->size(); ++i){
1091  if ((*pmatrack)[i]->IsEnabled()){
1092  TVector3 p3d = (*pmatrack)[i]->Point3D();
1093 // if (has_shift) p3d.SetX(p3d.X() + xshift);
1094  //std::cout<<p3d.X()<<" "<<p3d.Y()<<" "<<p3d.Z()<<std::endl;
1095  spts.push_back(p3d);
1096  }
1097  }
1098  if (spts.size()>=2){ //at least two space points
1099  TVector3 shwxyz, shwxyzerr;
1100  TVector3 shwdir, shwdirerr;
1101  std::vector<double> totalEnergy, totalEnergyError, dEdx, dEdxError;
1102  int bestPlane = pl0;
1103  double minpitch = 1000;
1104  std::vector<TVector3> dirs;
1105  if ((spts[0]-vtx).Mag()<(spts.back()-vtx).Mag()){
1106  shwxyz = spts[0];
1107  size_t i = 5;
1108  if (spts.size()-1<5) i = spts.size()-1;
1109  shwdir = spts[i] - spts[0];
1110  shwdir = shwdir.Unit();
1111  }
1112  else{
1113  shwxyz = spts.back();
1114  size_t i = 0;
1115  if (spts.size()>6) i = spts.size() - 6;
1116  shwdir = spts[i] - spts[spts.size()-1];
1117  shwdir = shwdir.Unit();
1118  }
1119  //std::cout<<shwxyz.X()<<" "<<shwxyz.Y()<<" "<<shwxyz.Z()<<std::endl;
1120  //std::cout<<shwdir.X()<<" "<<shwdir.Y()<<" "<<shwdir.Z()<<std::endl;
1121  for (unsigned int plane = 0; plane < fGeom->MaxPlanes(); ++plane) {
1122  if (planeHitsMap.find(plane)!=planeHitsMap.end()){
1123  totalEnergy.push_back(fShowerEnergyAlg.ShowerEnergy(planeHitsMap[plane], plane));
1124  }
1125  else{
1126  totalEnergy.push_back(0);
1127  }
1128  if (initialTrackHits[plane].size()){
1129  double fdEdx = 0;
1130  double totQ = 0;
1131  double avgT = 0;
1132  double pitch = 0;
1133  double wirepitch = fGeom->WirePitch(initialTrackHits[plane][0]->WireID().planeID());
1134  double angleToVert = fGeom->WireAngleToVertical(fGeom->Plane(plane).View(),initialTrackHits[plane][0]->WireID().planeID()) - 0.5*TMath::Pi();
1135  double cosgamma = std::abs(sin(angleToVert)*shwdir.Y()+
1136  cos(angleToVert)*shwdir.Z());
1137  if (cosgamma>0) pitch = wirepitch/cosgamma;
1138  if (pitch){
1139  if (pitch<minpitch){
1140  minpitch = pitch;
1141  bestPlane = plane;
1142  }
1143  int nhits = 0;
1144  //std::cout<<"pitch = "<<pitch<<std::endl;
1145  std::vector<float> vQ;
1146  for (auto const& hit: initialTrackHits[plane]){
1147  //std::cout<<hit->WireID()<<" "<<hit->PeakTime()<<" "<<std::abs((hit->WireID().Wire-initialTrackHits[plane][0]->WireID().Wire)*pitch)<<" "<<fdEdxTrackLength<<std::endl;
1148  int w1 = hit->WireID().Wire;
1149  int w0 = initialTrackHits[plane][0]->WireID().Wire;
1150  if (std::abs((w1-w0)*pitch)<fdEdxTrackLength){
1151  vQ.push_back(hit->Integral());
1152  totQ += hit->Integral();
1153  avgT+= hit->PeakTime();
1154  ++nhits;
1155  //std::cout<<hit->WireID()<<" "<<hit->PeakTime()<<" "<<hit->Integral()<<" "<<totQ<<" "<<avgT<<std::endl;
1156  }
1157  }
1158  if (totQ) {
1159  //double dQdx = totQ/(nhits*pitch);
1160  //std::sort(vQ.begin(), vQ.end());
1161  //double dQdx = vQ[vQ.size()/2]/pitch;
1162  double dQdx = TMath::Median(vQ.size(), &vQ[0])/pitch;
1163  fdEdx = fCalorimetryAlg.dEdx_AREA(dQdx, avgT/nhits, initialTrackHits[plane][0]->WireID().Plane);
1164  }
1165  }
1166  dEdx.push_back(fdEdx);
1167  }
1168  else{
1169  dEdx.push_back(0);
1170  }
1171  }
1172  iok = 0;
1173  if (fDebug > 1) {
1174  std::cout << "Best plane is " << bestPlane << std::endl;
1175  std::cout << "dE/dx for each plane is: " << dEdx[0] << ", " << dEdx[1] << " and " << dEdx[2] << std::endl;
1176  std::cout << "Total energy for each plane is: " << totalEnergy[0] << ", " << totalEnergy[1] << " and " << totalEnergy[2] << std::endl;
1177  std::cout << "The shower start is (" << shwxyz.X() << ", " << shwxyz.Y() << ", " << shwxyz.Z() << ")" << std::endl;
1178  shwxyz.Print();
1179  }
1180 
1181  return recob::Shower(shwdir, shwdirerr, shwxyz, shwxyzerr, totalEnergy, totalEnergyError, dEdx, dEdxError, bestPlane);
1182  }
1183  }
1184  return recob::Shower();
1185 }
1186 
1187 std::vector<recob::SpacePoint> shower::EMShowerAlg::MakeSpacePoints(std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHits,
1189 
1190  // Space points to return
1191  std::vector<recob::SpacePoint> spacePoints;
1192 
1193  // // Order by charge
1194  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeIt = showerHits.begin(); planeIt != showerHits.end(); ++planeIt)
1195  // 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(); });
1196 
1197  // Make space points
1198  // Use the following procedure:
1199  // -- Consider hits plane by plane
1200  // -- For each hit on the first plane, consider the 3D point made by combining with each hit from the second plane
1201  // -- Project this 3D point back into the two planes
1202  // -- Determine how close to a the original hits this point lies
1203  // -- If close enough, make a 3D space point from this point
1204  // // -- Discard these used hits in future iterations, along with hits in the
1205  // // third plane (if exists) close to the projection of the point into this plane
1206 
1207  // Container to hold used hits
1208  std::vector<int> usedHits;
1209 
1210  // Look through plane by plane
1211  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitIt = showerHits.begin(); showerHitIt != showerHits.end(); ++showerHitIt) {
1212 
1213  // Find the other planes with hits
1214  std::vector<int> otherPlanes;
1215  for (unsigned int otherPlane = 0; otherPlane < fGeom->MaxPlanes(); ++otherPlane)
1216  if ((int)otherPlane != showerHitIt->first and showerHits.count(otherPlane))
1217  otherPlanes.push_back(otherPlane);
1218 
1219  // Can't make space points if we only have one view
1220  if (otherPlanes.size() == 0)
1221  return spacePoints;
1222 
1223  // Look at all hits on this plane
1224  for (std::vector<art::Ptr<recob::Hit> >::const_iterator planeHitIt = showerHitIt->second.begin(); planeHitIt != showerHitIt->second.end(); ++planeHitIt) {
1225 
1226  if (std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) != usedHits.end())
1227  continue;
1228 
1229  // Make a 3D point with every hit on the second plane
1230  const std::vector<art::Ptr<recob::Hit> > otherPlaneHits = showerHits.at(otherPlanes.at(0));
1231  for (std::vector<art::Ptr<recob::Hit> >::const_iterator otherPlaneHitIt = otherPlaneHits.begin();
1232  otherPlaneHitIt != otherPlaneHits.end() and std::find(usedHits.begin(), usedHits.end(), planeHitIt->key()) == usedHits.end();
1233  ++otherPlaneHitIt) {
1234 
1235  if ((*otherPlaneHitIt)->WireID().TPC != (*planeHitIt)->WireID().TPC or
1236  std::find(usedHits.begin(), usedHits.end(), otherPlaneHitIt->key()) != usedHits.end())
1237  continue;
1238 
1239  TVector3 point = Construct3DPoint(*planeHitIt, *otherPlaneHitIt);
1240  std::vector<art::Ptr<recob::Hit> > pointHits;
1241  bool truePoint = false;
1242 
1243  if (otherPlanes.size() > 1) {
1244 
1245  TVector2 projThirdPlane = Project3DPointOntoPlane(point, otherPlanes.at(1));
1246  const std::vector<art::Ptr<recob::Hit> > otherOtherPlaneHits = showerHits.at(otherPlanes.at(1));
1247 
1248  for (std::vector<art::Ptr<recob::Hit> >::const_iterator otherOtherPlaneHitIt = otherOtherPlaneHits.begin();
1249  otherOtherPlaneHitIt != otherOtherPlaneHits.end() and !truePoint;
1250  ++otherOtherPlaneHitIt) {
1251 
1252  if ((*otherOtherPlaneHitIt)->WireID().TPC == (*planeHitIt)->WireID().TPC and
1253  (projThirdPlane-HitPosition(*otherOtherPlaneHitIt)).Mod() < fSpacePointSize) {
1254 
1255  truePoint = true;
1256 
1257  // Remove hits used to make the point
1258  usedHits.push_back(planeHitIt->key());
1259  usedHits.push_back(otherPlaneHitIt->key());
1260  usedHits.push_back(otherOtherPlaneHitIt->key());
1261 
1262  pointHits.push_back(*planeHitIt);
1263  pointHits.push_back(*otherPlaneHitIt);
1264  pointHits.push_back(*otherOtherPlaneHitIt);
1265 
1266  }
1267  }
1268  }
1269 
1270  else if ((Project3DPointOntoPlane(point, (*planeHitIt)->WireID().Plane) - HitPosition(*planeHitIt)).Mod() < fSpacePointSize and
1271  (Project3DPointOntoPlane(point, (*otherPlaneHitIt)->WireID().Plane) - HitPosition(*otherPlaneHitIt)).Mod() < fSpacePointSize) {
1272 
1273  truePoint = true;
1274 
1275  usedHits.push_back(planeHitIt->key());
1276  usedHits.push_back(otherPlaneHitIt->key());
1277 
1278  pointHits.push_back(*planeHitIt);
1279  pointHits.push_back(*otherPlaneHitIt);
1280 
1281  }
1282 
1283  // Make space point
1284  if (truePoint) {
1285  double xyz[3] = {point.X(), point.Y(), point.Z()};
1286  double xyzerr[6] = {fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize, fSpacePointSize};
1287  double chisq = 0.;
1288  spacePoints.emplace_back(xyz, xyzerr, chisq);
1289  hitAssns.push_back(pointHits);
1290  }
1291 
1292  } // end loop over second plane hits
1293 
1294  } // end loop over first plane hits
1295 
1296  } // end loop over planes
1297 
1298  if (fDebug > 0) {
1299  std::cout << "-------------------- Space points -------------------" << std::endl;
1300  std::cout << "There are " << spacePoints.size() << " space points:" << std::endl;
1301  if (fDebug > 1)
1302  for (std::vector<recob::SpacePoint>::const_iterator spacePointIt = spacePoints.begin(); spacePointIt != spacePoints.end(); ++spacePointIt) {
1303  const double* xyz = spacePointIt->XYZ();
1304  std::cout << " Space point (" << xyz[0] << ", " << xyz[1] << ", " << xyz[2] << ")" << std::endl;
1305  }
1306  }
1307 
1308  return spacePoints;
1309 
1310 }
1311 
1312 std::map<int,std::vector<art::Ptr<recob::Hit> > > shower::EMShowerAlg::OrderShowerHits(art::PtrVector<recob::Hit> const& shower, int plane) {
1313 
1318 
1319  // ------------- Put hits in order ------------
1320 
1321  // // Find the true start for reconstruction validation purposes
1322  // std::vector<art::Ptr<recob::Hit> > showerHitsVector;
1323  // std::map<int,int> trueParticleHits;
1324  // for (art::PtrVector<recob::Hit>::const_iterator showerHitIt = shower.begin(); showerHitIt != shower.end(); ++showerHitIt) {
1325  // showerHitsVector.push_back(*showerHitIt);
1326  // ++trueParticleHits[FindParticleID(*showerHitIt)];
1327  // }
1328  // int trueParticleID = FindTrueParticle(showerHitsVector);
1329  // const simb::MCParticle* trueParticle = bt_serv->TrackIDToParticle(trueParticleID);
1330  // TVector3 trueStart3D = trueParticle->Position().Vect();
1331  // double purity = trueParticleHits[trueParticleID]/(double)shower.size();
1332 
1333  // Find the shower hits on each plane
1334  std::map<int,std::vector<art::Ptr<recob::Hit> > > showerHitsMap;
1335  for (art::PtrVector<recob::Hit>::const_iterator hit = shower.begin(); hit != shower.end(); ++hit)
1336  showerHitsMap[(*hit)->WireID().Plane].push_back(*hit);
1337 
1338  // if (purity < 0.9)
1339  // return showerHitsMap;
1340 
1341  // Order the hits, get the RMS and the RMS gradient for the hits in this plane
1342  std::map<int,double> planeRMSGradients, planeRMS;
1343  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1344  if (plane != showerHitsIt->first and plane != -1)
1345  continue;
1346  std::vector<art::Ptr<recob::Hit> > orderedHits = FindOrderOfHits(showerHitsIt->second);
1347  planeRMS[showerHitsIt->first] = ShowerHitRMS(orderedHits);
1348  //TVector2 trueStart2D = Project3DPointOntoPlane(trueStart3D, showerHitsIt->first);
1349  planeRMSGradients[showerHitsIt->first] = ShowerHitRMSGradient(orderedHits);
1350  showerHitsMap[showerHitsIt->first] = orderedHits;
1351  }
1352 
1353  if (fDebug > 1)
1354  for (std::map<int,double>::iterator planeRMSIt = planeRMS.begin(); planeRMSIt != planeRMS.end(); ++planeRMSIt)
1355  std::cout << "Plane " << planeRMSIt->first << " has RMS " << planeRMSIt->second << " and RMS gradient " << planeRMSGradients.at(planeRMSIt->first) << std::endl;
1356 
1357  if (fDebug > 2) {
1358  std::cout << std::endl << "Hits in order; after ordering, before reversing..." << std::endl;
1359  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1360  std::cout << " Plane " << showerHitsIt->first << std::endl;
1361  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1362  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1363  }
1364  }
1365 
1366  // ------------- Check between the views to ensure consistency of ordering -------------
1367 
1368  // Check between the views to make sure there isn't a poorly formed shower in just one view
1369  // First, determine the average RMS and RMS gradient across the other planes
1370  std::map<int,double> planeOtherRMS, planeOtherRMSGradients;
1371  for (std::map<int,double>::iterator planeRMSIt = planeRMS.begin(); planeRMSIt != planeRMS.end(); ++planeRMSIt) {
1372  planeOtherRMS[planeRMSIt->first] = 0;
1373  planeOtherRMSGradients[planeRMSIt->first] = 0;
1374  int nOtherPlanes = 0;
1375  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane) {
1376  if (plane != planeRMSIt->first and planeRMS.count(plane)) {
1377  planeOtherRMS[planeRMSIt->first] += planeRMS.at(plane);
1378  planeOtherRMSGradients[planeRMSIt->first] += planeRMSGradients.at(plane);
1379  ++nOtherPlanes;
1380  }
1381  }
1382  planeOtherRMS[planeRMSIt->first] /= (double)nOtherPlanes;
1383  planeOtherRMSGradients[planeRMSIt->first] /= (double)nOtherPlanes;
1384  }
1385 
1386  // Look to see if one plane has a particularly high RMS (compared to the others) whilst having a similar gradient
1387  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1388  if (planeRMS.at(showerHitsIt->first) > planeOtherRMS.at(showerHitsIt->first) * 2) {
1389  //and TMath::Abs(planeRMSGradients.at(showerHitsIt->first) / planeOtherRMSGradients.at(showerHitsIt->first)) < 0.1) {
1390  if (fDebug > 1)
1391  std::cout << "Plane " << showerHitsIt->first << " was perpendicular... recalculating" << std::endl;
1392  std::vector<art::Ptr<recob::Hit> > orderedHits = this->FindOrderOfHits(showerHitsIt->second, true);
1393  showerHitsMap[showerHitsIt->first] = orderedHits;
1394  planeRMSGradients[showerHitsIt->first] = this->ShowerHitRMSGradient(orderedHits);
1395  }
1396  }
1397 
1398  // ------------- Orient the shower correctly ---------------
1399 
1400  if (fDebug > 1) {
1401  std::cout << "Before reversing, here are the start and end points..." << std::endl;
1402  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1403  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;
1404  }
1405 
1406  // Use the RMS gradient information to get an initial ordering
1407  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1408  double gradient = planeRMSGradients.at(showerHitsIt->first);
1409  if (gradient < 0)
1410  std::reverse(showerHitsIt->second.begin(), showerHitsIt->second.end());
1411  }
1412 
1413  if (fDebug > 2) {
1414  std::cout << std::endl << "Hits in order; after reversing, before checking isolated hits..." << std::endl;
1415  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1416  std::cout << " Plane " << showerHitsIt->first << std::endl;
1417  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1418  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1419  }
1420  }
1421 
1422  CheckIsolatedHits(showerHitsMap);
1423 
1424  if (fDebug > 2) {
1425  std::cout << std::endl << "Hits in order; after checking isolated hits..." << std::endl;
1426  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1427  std::cout << " Plane " << showerHitsIt->first << std::endl;
1428  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = showerHitsIt->second.begin(); hitIt != showerHitsIt->second.end(); ++hitIt)
1429  std::cout << " Hit at (" << HitCoordinates(*hitIt).X() << ", " << HitCoordinates(*hitIt).Y() << ") -- real wire " << (*hitIt)->WireID() << ", hit position (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1430  }
1431  }
1432 
1433  if (fDebug > 1) {
1434  std::cout << "After reversing and checking isolated hits, here are the start and end points..." << std::endl;
1435  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1436  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;
1437  }
1438 
1439  // Check for views in which the shower travels almost along the wire planes
1440  // (shown by a small relative wire width)
1441  std::map<double,int> wireWidths = RelativeWireWidth(showerHitsMap);
1442  std::vector<int> badPlanes;
1443  if (fDebug > 1)
1444  std::cout << "Here are the relative wire widths... " << std::endl;
1445  for (std::map<double,int>::iterator wireWidthIt = wireWidths.begin(); wireWidthIt != wireWidths.end(); ++wireWidthIt) {
1446  if (fDebug > 1)
1447  std::cout << "Plane " << wireWidthIt->second << " has relative wire width " << wireWidthIt->first << std::endl;
1448  if (wireWidthIt->first < 1/(double)wireWidths.size())
1449  badPlanes.push_back(wireWidthIt->second);
1450  }
1451 
1452  std::map<int,std::vector<art::Ptr<recob::Hit> > > ignoredPlanes;
1453  if (badPlanes.size() == 1) {
1454  int badPlane = badPlanes.at(0);
1455  if (fDebug > 1)
1456  std::cout << "Ignoring plane " << badPlane << " when orientating" << std::endl;
1457  ignoredPlanes[badPlane] = showerHitsMap.at(badPlane);
1458  showerHitsMap.erase(showerHitsMap.find(badPlane));
1459  }
1460 
1461  // Consider all possible permutations of planes (0/1, oriented correctly/incorrectly)
1462  std::map<int,std::map<int,bool> > permutations = GetPlanePermutations(showerHitsMap);
1463 
1464  // Go through all permutations until we have a satisfactory orientation
1465  std::map<int,std::vector<art::Ptr<recob::Hit> > > originalShowerHitsMap = showerHitsMap;
1466  int n = 0;
1467  while (!CheckShowerHits(showerHitsMap) and n < TMath::Power(2,(int)showerHitsMap.size())) {
1468  if (fDebug > 1)
1469  std::cout << "Permutation " << n << std::endl;
1470  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
1471  std::vector<art::Ptr<recob::Hit> > hits = originalShowerHitsMap.at(showerHitsIt->first);
1472  if (permutations[n][showerHitsIt->first] == 1) {
1473  std::reverse(hits.begin(), hits.end());
1474  showerHitsMap[showerHitsIt->first] = hits;
1475  }
1476  else
1477  showerHitsMap[showerHitsIt->first] = hits;
1478  }
1479  ++n;
1480  }
1481 
1482  // Go back to original if still no consistency
1483  if (!CheckShowerHits(showerHitsMap))
1484  showerHitsMap = originalShowerHitsMap;
1485 
1486  if (fDebug > 2) {
1487  std::cout << "End of OrderShowerHits: here are the order of hits:" << std::endl;
1488  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator planeHitsIt = showerHitsMap.begin(); planeHitsIt != showerHitsMap.end(); ++planeHitsIt) {
1489  std::cout << " Plane " << planeHitsIt->first << std::endl;
1490  for (std::vector<art::Ptr<recob::Hit> >::iterator hitIt = planeHitsIt->second.begin(); hitIt != planeHitsIt->second.end(); ++hitIt)
1491  std::cout << " Hit (" << HitCoordinates(*hitIt).X() << " (real wire " << (*hitIt)->WireID() << "), " << HitCoordinates(*hitIt).Y() << ") -- pos (" << HitPosition(*hitIt).X() << ", " << HitPosition(*hitIt).Y() << ")" << std::endl;
1492  }
1493  }
1494 
1495  if (ignoredPlanes.size())
1496  showerHitsMap[ignoredPlanes.begin()->first] = ignoredPlanes.begin()->second;
1497 
1498  return showerHitsMap;
1499 
1500 }
1501 
1503  std::vector<art::Ptr<recob::Hit> >& showerHits,
1505 
1506  showerHits = FindOrderOfHits(shower);
1507 
1508  // Find TPC for the vertex
1509  double xyz[3];
1510  vertex->XYZ(xyz);
1511  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1512  if (!tpc.isValid&&showerHits.size()) tpc = geo::TPCID(showerHits[0]->WireID());
1513  //std::cout<<tpc<<std::endl;
1514  // Find hits in the same TPC
1515  art::Ptr<recob::Hit> hit0, hit1;
1516  for (auto &hit: showerHits){
1517  if (hit->WireID().TPC==tpc.TPC){
1518  if (hit0.isNull()){
1519  hit0 = hit;
1520  }
1521  hit1 = hit;
1522  }
1523  }
1524  if (hit0.isNull()||hit1.isNull()) return;
1525  TVector2 coord0 = TVector2(hit0->WireID().Wire, hit0->PeakTime());
1526  TVector2 coord1 = TVector2(hit1->WireID().Wire, hit1->PeakTime());
1527  TVector2 coordvtx = TVector2(fGeom->WireCoordinate(xyz[1], xyz[2], hit0->WireID().planeID()),
1528  fDetProp->ConvertXToTicks(xyz[0], hit0->WireID().planeID()));
1529 // std::cout<<coord0.X()<<" "<<coord0.Y()<<std::endl;
1530 // std::cout<<coord1.X()<<" "<<coord1.Y()<<std::endl;
1531 // std::cout<<coordvtx.X()<<" "<<coordvtx.Y()<<std::endl;
1532 // std::cout<<hit0->WireID()<<" "<<hit1->WireID()<<std::endl;
1533  if ((coord1-coordvtx).Mod()<(coord0-coordvtx).Mod()){
1534  std::reverse(showerHits.begin(), showerHits.end());
1535  }
1536  //std::cout<<showerHits[0]->WireID()<<" "<<showerHits.back()->WireID()<<std::endl;
1537 }
1538 
1541  std::vector<art::Ptr<recob::Hit> >& trackHits){
1542 
1543  // Find TPC for the vertex
1544  //std::cout<<"here"<<std::endl;
1545  double xyz[3];
1546  vertex->XYZ(xyz);
1547  //std::cout<<xyz[0]<<" "<<xyz[1]<<" "<<xyz[2]<<std::endl;
1548  geo::TPCID tpc = fGeom->FindTPCAtPosition(xyz);
1549  //std::cout<<tpc<<std::endl;
1550  //vertex cannot be projected into a TPC, find the TPC that has the most hits
1551  if (!tpc.isValid){
1552  std::map<geo::TPCID, unsigned int> tpcmap;
1553  unsigned maxhits = 0;
1554  for (auto const&hit : showerHits){
1555  ++tpcmap[geo::TPCID(hit->WireID())];
1556  }
1557  for (auto const&t : tpcmap){
1558  if (t.second > maxhits){
1559  maxhits = t.second;
1560  tpc = t.first;
1561  }
1562  }
1563  }
1564  //std::cout<<tpc<<std::endl;
1565  //if (!tpc.isValid&&showerHits.size()) tpc = geo::TPCID(showerHits[0]->WireID());
1566  if (!tpc.isValid) return;
1567  //std::cout<<"here 1"<<std::endl;
1568 
1569  double parm[2];
1570  int fitok = 0;
1571  std::vector<double> wfit;
1572  std::vector<double> tfit;
1573  std::vector<double> cfit;
1574 
1575  for (size_t i = 0; i<fNfitpass; ++i){
1576 
1577  // Fit a straight line through hits
1578  unsigned int nhits = 0;
1579  for (auto &hit: showerHits){
1580  //std::cout<<i<<" "<<hit->WireID()<<" "<<tpc<<std::endl;
1581  if (hit->WireID().TPC==tpc.TPC){
1582  TVector2 coord = HitCoordinates(hit);
1583  //std::cout<<i<<" "<<hit->WireID()<<" "<<hit->PeakTime()<<std::endl;
1584  if (i==0||(std::abs((coord.Y()-(parm[0]+coord.X()*parm[1]))*cos(atan(parm[1])))<fToler[i-1])||fitok==1){
1585  ++nhits;
1586  if (nhits==fNfithits[i]+1) break;
1587  wfit.push_back(coord.X());
1588  tfit.push_back(coord.Y());
1589  //cfit.push_back(hit->Integral());
1590  cfit.push_back(1.);
1591  if (i==fNfitpass-1) {
1592  trackHits.push_back(hit);
1593  }
1594  //std::cout<<*hit<<std::endl;
1595 //
1596 //<<hit->PeakTime()<<" "<<std::abs((coord.Y()-(parm[0]+coord.X()*parm[1]))*cos(atan(parm[1])))<<std::endl;
1597  }
1598  }
1599  }
1600 
1601  if (i<fNfitpass-1&&wfit.size()){
1602  fitok = WeightedFit(wfit.size(), &wfit[0], &tfit[0], &cfit[0], &parm[0]);
1603  }
1604  wfit.clear();
1605  tfit.clear();
1606  cfit.clear();
1607  }
1608 
1609 }
1610 
1611 
1613 
1614  return TVector2(GlobalWire(hit->WireID()), hit->PeakTime());
1615 
1616 }
1617 
1619 
1620  geo::PlaneID planeID = hit->WireID().planeID();
1621 
1622  return HitPosition(HitCoordinates(hit), planeID);
1623 
1624 }
1625 
1626 TVector2 shower::EMShowerAlg::HitPosition(TVector2 const& pos, geo::PlaneID planeID) {
1627 
1628  return TVector2(pos.X() * fGeom->WirePitch(planeID),
1629  fDetProp->ConvertTicksToX(pos.Y(), planeID));
1630 
1631 }
1632 
1634 
1635  double globalWire = -999;
1636 
1637  // Induction
1638  if (fGeom->SignalType(wireID) == geo::kInduction) {
1639  double wireCentre[3];
1640  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1641  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1642  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1643  }
1644 
1645  // Collection
1646  else {
1647  // FOR COLLECTION WIRES, HARD CODE THE GEOMETRY FOR GIVEN DETECTORS
1648  // THIS _SHOULD_ BE TEMPORARY. GLOBAL WIRE SUPPORT IS BEING ADDED TO THE LARSOFT GEOMETRY AND SHOULD BE AVAILABLE SOON
1649  if (fDetector == "dune35t") {
1650  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1651  if (wireID.TPC == 0 or wireID.TPC == 1) globalWire = wireID.Wire;
1652  else if (wireID.TPC == 2 or wireID.TPC == 3 or wireID.TPC == 4 or wireID.TPC == 5) globalWire = nwires + wireID.Wire;
1653  else if (wireID.TPC == 6 or wireID.TPC == 7) globalWire = (2*nwires) + wireID.Wire;
1654  else mf::LogError("BlurredClusterAlg") << "Error when trying to find a global induction plane coordinate for TPC " << wireID.TPC << " (geometry" << fDetector << ")";
1655  }
1656  else if (fDetector == "dune10kt") {
1657  unsigned int nwires = fGeom->Nwires(wireID.Plane, 0, wireID.Cryostat);
1658  // Detector geometry has four TPCs, two on top of each other, repeated along z...
1659  int block = wireID.TPC / 4;
1660  globalWire = (nwires*block) + wireID.Wire;
1661  }
1662  else {
1663  double wireCentre[3];
1664  fGeom->WireIDToWireGeo(wireID).GetCenter(wireCentre);
1665  if (wireID.TPC % 2 == 0) globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 0, wireID.Cryostat);
1666  else globalWire = fGeom->WireCoordinate(wireCentre[1], wireCentre[2], wireID.Plane, 1, wireID.Cryostat);
1667  }
1668  }
1669 
1670  return globalWire;
1671 
1672 }
1673 
1674 std::map<double,int> shower::EMShowerAlg::RelativeWireWidth(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
1675 
1676  // Get the wire widths
1677  std::map<int,int> planeWireLength;
1678  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1679  planeWireLength[showerHitsIt->first] = TMath::Abs(HitCoordinates(showerHitsIt->second.front()).X() - HitCoordinates(showerHitsIt->second.back()).X());
1680 
1681  // Find the relative wire width for each plane with respect to the others
1682  std::map<int,double> planeOtherWireLengths;
1683  for (std::map<int,int>::iterator planeWireLengthIt = planeWireLength.begin(); planeWireLengthIt != planeWireLength.end(); ++planeWireLengthIt) {
1684  double quad = 0.;
1685  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
1686  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
1687  quad += TMath::Power(planeWireLength[plane],2);
1688  quad = TMath::Sqrt(quad);
1689  planeOtherWireLengths[planeWireLengthIt->first] = planeWireLength[planeWireLengthIt->first] / (double)quad;
1690  }
1691 
1692  // Order these backwards
1693  std::map<double,int> wireWidthMap;
1694  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
1695  wireWidthMap[planeOtherWireLengths.at(showerHitsIt->first)] = showerHitsIt->first;
1696 
1697  return wireWidthMap;
1698 
1699 }
1700 
1702 
1703  TVector2 pos;
1704  //double weight;
1705  double weight = 1;
1706  //int nhits = 0;
1707  double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1708  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = showerHits.begin(); hit != showerHits.end(); ++hit) {
1709  //++nhits;
1710  pos = HitPosition(*hit);
1711  weight = TMath::Power((*hit)->Integral(),2);
1712  sumweight += weight;
1713  sumx += weight * pos.X();
1714  sumy += weight * pos.Y();
1715  sumx2 += weight * pos.X() * pos.X();
1716  sumxy += weight * pos.X() * pos.Y();
1717  }
1718  //double gradient = (nhits * sumxy - sumx * sumy) / (nhits * sumx2 - sumx * sumx);
1719  double gradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1720  TVector2 direction = TVector2(1,gradient).Unit();
1721 
1722  return direction;
1723 
1724 }
1725 
1727 
1728  TVector2 pos, chargePoint = TVector2(0,0);
1729  double totalCharge = 0;
1730  for (std::vector<art::Ptr<recob::Hit> >::const_iterator hit = showerHits.begin(); hit != showerHits.end(); ++hit) {
1731  pos = HitPosition(*hit);
1732  chargePoint += (*hit)->Integral() * pos;
1733  totalCharge += (*hit)->Integral();
1734  }
1735  TVector2 centre = chargePoint / totalCharge;
1736 
1737  return centre;
1738 
1739 }
1740 
1742 
1743  TVector2 direction = ShowerDirection(showerHits);
1744  TVector2 centre = ShowerCentre(showerHits);
1745 
1746  std::vector<double> distanceToAxis;
1747  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1748  TVector2 proj = (HitPosition(*showerHitsIt) - centre).Proj(direction) + centre;
1749  distanceToAxis.push_back((HitPosition(*showerHitsIt) - proj).Mod());
1750  }
1751  double RMS = TMath::RMS(distanceToAxis.begin(), distanceToAxis.end());
1752 
1753  return RMS;
1754 
1755 }
1756 
1757 double shower::EMShowerAlg::ShowerHitRMSGradient(const std::vector<art::Ptr<recob::Hit> >& showerHits, TVector2 trueStart) {
1758 
1759  // Don't forget to clean up the header file!
1760 
1761  // Find a rough shower 'direction' and centre
1762  TVector2 direction = ShowerDirection(showerHits);
1763 
1764  //std::cout << std::endl << "Number of hits in this shower: " << showerHits.size() << std::endl;
1765 
1766  // for (int i = 0; i < 100; ++i) {
1767 
1768  // // Bin the hits into discreet chunks
1769  // //int nSegmentHits = fNumSegmentHits;
1770  // int nSegmentHits = i;
1771  // int nShowerSegments = showerHits.size() / (double)nSegmentHits;
1772  // //int nShowerSegments = fNumShowerSegments;
1773  // double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
1774  // double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
1775  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
1776  // std::map<int,double> segmentCharge;
1777  // for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1778  // showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
1779  // segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
1780  // }
1781 
1782  // TGraph* graph = new TGraph();
1783  // std::vector<std::pair<int,double> > binVsRMS;
1784 
1785  // // Loop over the bins to find the distribution of hits as the shower progresses
1786  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
1787 
1788  // // Get the mean position of the hits in this bin
1789  // TVector2 meanPosition(0,0);
1790  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
1791  // meanPosition += HitPosition(*hitInSegmentIt);
1792  // meanPosition /= (double)showerSegmentIt->second.size();
1793 
1794  // // Get the RMS of this bin
1795  // std::vector<double> distanceToAxisBin;
1796  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
1797  // TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
1798  // distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
1799  // }
1800 
1801  // double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
1802  // binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
1803  // if (fMakeRMSGradientPlot)
1804  // graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
1805 
1806  // }
1807 
1808  // // Get the gradient of the RMS-bin plot
1809 
1810  // // OLD
1811  // int nhits1 = 0;
1812  // double sumx1=0., sumy1=0., sumx21=0., sumxy1=0.;
1813  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1814  // ++nhits1;
1815  // sumx1 += binVsRMSIt->first;
1816  // sumy1 += binVsRMSIt->second;
1817  // sumx21 += binVsRMSIt->first * binVsRMSIt->first;
1818  // sumxy1 += binVsRMSIt->first * binVsRMSIt->second;
1819  // }
1820  // double RMSgradient1 = (nhits1 * sumxy1 - sumx1 * sumy1) / (nhits1 * sumx21 - sumx1 * sumx1);
1821 
1822  // // NEW
1823  // double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1824  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1825  // //double weight = showerSegments.at(binVsRMSIt->first).size();
1826  // double weight = TMath::Power(segmentCharge.at(binVsRMSIt->first),2);
1827  // sumweight += weight;
1828  // sumx += weight * binVsRMSIt->first;
1829  // sumy += weight * binVsRMSIt->second;
1830  // sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
1831  // sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
1832  // }
1833  // double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1834 
1835  // // PCA
1836  // TPrincipal* pca = new TPrincipal(2,"");
1837  // double point[2];
1838  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1839  // if (fDebug > 2)
1840  // std::cout << "Number of hits in segment " << binVsRMSIt->first << " is " << showerSegments.at(binVsRMSIt->first).size() << std::endl;
1841  // for (int nhit = 0; nhit < (int)showerSegments.at(binVsRMSIt->first).size(); ++nhit) {
1842  // point[0] = binVsRMSIt->first;
1843  // point[1] = binVsRMSIt->second;
1844  // pca->AddRow(point);
1845  // }
1846  // }
1847  // pca->MakePrincipals();
1848  // TVector2 RMSgradientPCA = TVector2( (*pca->GetEigenVectors())[0][0], (*pca->GetEigenVectors())[1][0] ).Unit();
1849 
1850  // if (fDebug > 1)
1851  // std::cout << "RMS gradient without weighting: " << RMSgradient1 << ", and with weighting: " << RMSgradient << "; PCA with weighting: " << RMSgradientPCA.Y()/RMSgradientPCA.X() << std::endl;
1852 
1853  // if (fMakeRMSGradientPlot) {
1854  // TVector2 direction = TVector2(1,RMSgradient).Unit();
1855  // TVector2 direction1 = TVector2(1,RMSgradient1).Unit();
1856  // TCanvas* canv = new TCanvas();
1857  // graph->Draw();
1858  // TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
1859  // TLine line, line1, line2;
1860  // line.SetLineColor(3);
1861  // line1.SetLineColor(4);
1862  // line2.SetLineColor(5);
1863  // line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
1864  // line1.DrawLine(centre.X()-1000*direction1.X(),centre.Y()-1000*direction1.Y(),centre.X()+1000*direction1.X(),centre.Y()+1000*direction1.Y());
1865  // line2.DrawLine(centre.X()-1000*RMSgradientPCA.X(),centre.Y()-1000*RMSgradientPCA.Y(),centre.X()+1000*RMSgradientPCA.X(),centre.Y()+1000*RMSgradientPCA.Y());
1866  // canv->SaveAs("RMSGradient.png");
1867  // delete canv;
1868  // }
1869  // delete graph; delete pca;
1870 
1871  // //std::cout << "Number of hits per bin " << i << " gives gradient of " << RMSgradient << std::endl;
1872 
1873  // double distanceFromStart = 0, distanceFromEnd = 0;
1874  // if (RMSgradient > 0) {
1875  // distanceFromStart = (trueStart - HitPosition(showerHits.front())).Mod();
1876  // distanceFromEnd = (trueStart - HitPosition(showerHits.back())).Mod();
1877  // }
1878  // if (RMSgradient < 0) {
1879  // distanceFromStart = (trueStart - HitPosition(showerHits.back())).Mod();
1880  // distanceFromEnd = (trueStart - HitPosition(showerHits.front())).Mod();
1881  // }
1882  // bool correct = distanceFromStart < distanceFromEnd;
1883  // hNumHitsInSegment->Fill(i,correct);
1884 
1885  // }
1886 
1887 
1888 
1889 
1890  // for (int i = 0; i < 100; ++i) {
1891 
1892  // // Bin the hits into discreet chunks
1893  // int nShowerSegments = i;
1894  // double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
1895  // double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
1896  // std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
1897  // std::map<int,double> segmentCharge;
1898  // for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
1899  // showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
1900  // segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
1901  // }
1902 
1903  // TGraph* graph = new TGraph();
1904  // std::vector<std::pair<int,double> > binVsRMS;
1905 
1906  // // Loop over the bins to find the distribution of hits as the shower progresses
1907  // for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
1908 
1909  // // Get the mean position of the hits in this bin
1910  // TVector2 meanPosition(0,0);
1911  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
1912  // meanPosition += HitPosition(*hitInSegmentIt);
1913  // meanPosition /= (double)showerSegmentIt->second.size();
1914 
1915  // // Get the RMS of this bin
1916  // std::vector<double> distanceToAxisBin;
1917  // for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
1918  // TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
1919  // distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
1920  // }
1921 
1922  // double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
1923  // binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
1924  // if (fMakeRMSGradientPlot)
1925  // graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
1926 
1927  // }
1928 
1929  // // Get the gradient of the RMS-bin plot
1930 
1931  // // OLD
1932  // int nhits1 = 0;
1933  // double sumx1=0., sumy1=0., sumx21=0., sumxy1=0.;
1934  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1935  // ++nhits1;
1936  // sumx1 += binVsRMSIt->first;
1937  // sumy1 += binVsRMSIt->second;
1938  // sumx21 += binVsRMSIt->first * binVsRMSIt->first;
1939  // sumxy1 += binVsRMSIt->first * binVsRMSIt->second;
1940  // }
1941  // double RMSgradient1 = (nhits1 * sumxy1 - sumx1 * sumy1) / (nhits1 * sumx21 - sumx1 * sumx1);
1942 
1943  // // NEW
1944  // double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
1945  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1946  // //double weight = showerSegments.at(binVsRMSIt->first).size();
1947  // double weight = TMath::Power(segmentCharge.at(binVsRMSIt->first),2);
1948  // sumweight += weight;
1949  // sumx += weight * binVsRMSIt->first;
1950  // sumy += weight * binVsRMSIt->second;
1951  // sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
1952  // sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
1953  // }
1954  // double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
1955 
1956  // // PCA
1957  // TPrincipal* pca = new TPrincipal(2,"");
1958  // double point[2];
1959  // for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
1960  // if (fDebug > 2)
1961  // std::cout << "Number of hits in segment " << binVsRMSIt->first << " is " << showerSegments.at(binVsRMSIt->first).size() << std::endl;
1962  // for (int nhit = 0; nhit < (int)showerSegments.at(binVsRMSIt->first).size(); ++nhit) {
1963  // point[0] = binVsRMSIt->first;
1964  // point[1] = binVsRMSIt->second;
1965  // pca->AddRow(point);
1966  // }
1967  // }
1968  // pca->MakePrincipals();
1969  // TVector2 RMSgradientPCA = TVector2( (*pca->GetEigenVectors())[0][0], (*pca->GetEigenVectors())[1][0] ).Unit();
1970 
1971  // if (fDebug > 1)
1972  // std::cout << "RMS gradient without weighting: " << RMSgradient1 << ", and with weighting: " << RMSgradient << "; PCA with weighting: " << RMSgradientPCA.Y()/RMSgradientPCA.X() << std::endl;
1973 
1974  // if (fMakeRMSGradientPlot) {
1975  // TVector2 direction = TVector2(1,RMSgradient).Unit();
1976  // TVector2 direction1 = TVector2(1,RMSgradient1).Unit();
1977  // TCanvas* canv = new TCanvas();
1978  // graph->Draw();
1979  // TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
1980  // TLine line, line1, line2;
1981  // line.SetLineColor(3);
1982  // line1.SetLineColor(4);
1983  // line2.SetLineColor(5);
1984  // line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
1985  // line1.DrawLine(centre.X()-1000*direction1.X(),centre.Y()-1000*direction1.Y(),centre.X()+1000*direction1.X(),centre.Y()+1000*direction1.Y());
1986  // line2.DrawLine(centre.X()-1000*RMSgradientPCA.X(),centre.Y()-1000*RMSgradientPCA.Y(),centre.X()+1000*RMSgradientPCA.X(),centre.Y()+1000*RMSgradientPCA.Y());
1987  // canv->SaveAs("RMSGradient.png");
1988  // delete canv;
1989  // }
1990  // delete graph; delete pca;
1991 
1992  // //std::cout << "Number of hits per bin " << i << " gives gradient of " << RMSgradient << std::endl;
1993 
1994  // double distanceFromStart = 0, distanceFromEnd = 0;
1995  // if (RMSgradient > 0) {
1996  // distanceFromStart = (trueStart - HitPosition(showerHits.front())).Mod();
1997  // distanceFromEnd = (trueStart - HitPosition(showerHits.back())).Mod();
1998  // }
1999  // if (RMSgradient < 0) {
2000  // distanceFromStart = (trueStart - HitPosition(showerHits.back())).Mod();
2001  // distanceFromEnd = (trueStart - HitPosition(showerHits.front())).Mod();
2002  // }
2003  // bool correct = distanceFromStart < distanceFromEnd;
2004  // hNumSegments->Fill(i,correct);
2005 
2006  // }
2007 
2008 
2009 
2010 
2011 
2012 
2013 
2014 
2015 
2016 
2017 
2018 
2019 
2020 
2021 
2022 
2023  // Bin the hits into discreet chunks
2024  int nShowerSegments = fNumShowerSegments;
2025  double lengthOfShower = (HitPosition(showerHits.back()) - HitPosition(showerHits.front())).Mod();
2026  double lengthOfSegment = lengthOfShower / (double)nShowerSegments;
2027  std::map<int,std::vector<art::Ptr<recob::Hit> > > showerSegments;
2028  std::map<int,double> segmentCharge;
2029  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitsIt = showerHits.begin(); showerHitsIt != showerHits.end(); ++showerHitsIt) {
2030  showerSegments[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment].push_back(*showerHitsIt);
2031  segmentCharge[(int)(HitPosition(*showerHitsIt)-HitPosition(showerHits.front())).Mod() / lengthOfSegment] += (*showerHitsIt)->Integral();
2032  }
2033 
2034  TGraph* graph = new TGraph();
2035  std::vector<std::pair<int,double> > binVsRMS;
2036 
2037  // Loop over the bins to find the distribution of hits as the shower progresses
2038  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::iterator showerSegmentIt = showerSegments.begin(); showerSegmentIt != showerSegments.end(); ++showerSegmentIt) {
2039 
2040  // Get the mean position of the hits in this bin
2041  TVector2 meanPosition(0,0);
2042  for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt)
2043  meanPosition += HitPosition(*hitInSegmentIt);
2044  meanPosition /= (double)showerSegmentIt->second.size();
2045 
2046  // Get the RMS of this bin
2047  std::vector<double> distanceToAxisBin;
2048  for (std::vector<art::Ptr<recob::Hit> >::iterator hitInSegmentIt = showerSegmentIt->second.begin(); hitInSegmentIt != showerSegmentIt->second.end(); ++hitInSegmentIt) {
2049  TVector2 proj = (HitPosition(*hitInSegmentIt) - meanPosition).Proj(direction) + meanPosition;
2050  distanceToAxisBin.push_back((HitPosition(*hitInSegmentIt) - proj).Mod());
2051  }
2052 
2053  double RMSBin = TMath::RMS(distanceToAxisBin.begin(), distanceToAxisBin.end());
2054  binVsRMS.push_back(std::make_pair(showerSegmentIt->first, RMSBin));
2056  graph->SetPoint(graph->GetN(), showerSegmentIt->first, RMSBin);
2057 
2058  }
2059 
2060  // Get the gradient of the RMS-bin plot
2061  double sumx=0., sumy=0., sumx2=0., sumxy=0., sumweight = 0.;
2062  for (std::vector<std::pair<int,double> >::iterator binVsRMSIt = binVsRMS.begin(); binVsRMSIt != binVsRMS.end(); ++binVsRMSIt) {
2063  //double weight = showerSegments.at(binVsRMSIt->first).size();
2064  //double weight = 1;
2065  double weight = segmentCharge.at(binVsRMSIt->first);
2066  sumweight += weight;
2067  sumx += weight * binVsRMSIt->first;
2068  sumy += weight * binVsRMSIt->second;
2069  sumx2 += weight * binVsRMSIt->first * binVsRMSIt->first;
2070  sumxy += weight * binVsRMSIt->first * binVsRMSIt->second;
2071  }
2072  double RMSgradient = (sumweight * sumxy - sumx * sumy) / (sumweight * sumx2 - sumx * sumx);
2073 
2074  if (fMakeRMSGradientPlot) {
2075  TVector2 direction = TVector2(1,RMSgradient).Unit();
2076  TCanvas* canv = new TCanvas();
2077  graph->Draw();
2078  graph->GetXaxis()->SetTitle("Shower segment");
2079  graph->GetYaxis()->SetTitle("RMS of hit distribution");
2080  TVector2 centre = TVector2(graph->GetMean(1), graph->GetMean(2));
2081  TLine line;
2082  line.SetLineColor(2);
2083  line.DrawLine(centre.X()-1000*direction.X(),centre.Y()-1000*direction.Y(),centre.X()+1000*direction.X(),centre.Y()+1000*direction.Y());
2084  canv->SaveAs("RMSGradient.png");
2085  delete canv;
2086  }
2087  delete graph;
2088 
2089  return RMSgradient;
2090 
2091 }
2092 
2093 TVector2 shower::EMShowerAlg::Project3DPointOntoPlane(TVector3 const& point, int plane, int cryostat) {
2094 
2095  TVector2 wireTickPos = TVector2(-999., -999.);
2096 
2097  double pointPosition[3] = {point.X(), point.Y(), point.Z()};
2098 
2099  geo::TPCID tpcID = fGeom->FindTPCAtPosition(pointPosition);
2100  int tpc = 0;
2101  if (tpcID.isValid)
2102  tpc = tpcID.TPC;
2103  else
2104  return wireTickPos;
2105 
2106  // Construct wire ID for this point projected onto the plane
2107  geo::PlaneID planeID = geo::PlaneID(cryostat, tpc, plane);
2108  geo::WireID wireID;
2109  try{
2110  wireID = fGeom->NearestWireID(point, planeID);
2111  }
2112  catch(geo::InvalidWireError const& e) {
2113  wireID = e.suggestedWireID(); // pick the closest valid wire
2114  }
2115 
2116  wireTickPos = TVector2(GlobalWire(wireID),
2117  fDetProp->ConvertXToTicks(point.X(), planeID));
2118 
2119  // wireTickPos = TVector2(fGeom->WireCoordinate(point.Y(), point.Z(), planeID.Plane, tpc % 2, planeID.Cryostat),
2120  // fDetProp->ConvertXToTicks(point.X(), planeID.Plane, tpc % 2, planeID.Cryostat));
2121 
2122  //return wireTickPos;
2123  return HitPosition(wireTickPos, planeID);
2124 
2125 }
2126 
2127 int shower::EMShowerAlg::WorstPlane(const std::map<int,std::vector<art::Ptr<recob::Hit> > >& showerHitsMap) {
2128 
2129  // Get the width of the shower in wire coordinate
2130  std::map<int,int> planeWireLength;
2131  std::map<int,double> planeOtherWireLengths;
2132  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt)
2133  planeWireLength[showerHitsIt->first] = TMath::Abs(HitCoordinates(showerHitsIt->second.front()).X() - HitCoordinates(showerHitsIt->second.back()).X());
2134  for (std::map<int,int>::iterator planeWireLengthIt = planeWireLength.begin(); planeWireLengthIt != planeWireLength.end(); ++planeWireLengthIt) {
2135  double quad = 0.;
2136  for (int plane = 0; plane < (int)fGeom->MaxPlanes(); ++plane)
2137  if (plane != planeWireLengthIt->first and planeWireLength.count(plane))
2138  quad += TMath::Power(planeWireLength[plane],2);
2139  quad = TMath::Sqrt(quad);
2140  planeOtherWireLengths[planeWireLengthIt->first] = planeWireLength[planeWireLengthIt->first] / (double)quad;
2141  }
2142 
2143  if (fDebug > 1)
2144  for (std::map<int,double>::const_iterator planeOtherWireLengthIt = planeOtherWireLengths.begin(); planeOtherWireLengthIt != planeOtherWireLengths.end(); ++planeOtherWireLengthIt)
2145  std::cout << "Plane " << planeOtherWireLengthIt->first << " has " << planeWireLength[planeOtherWireLengthIt->first] << " wire width and therefore has relative width in wire of " << planeOtherWireLengthIt->second << std::endl;
2146 
2147  std::map<double,int> wireWidthMap;
2148  for (std::map<int,std::vector<art::Ptr<recob::Hit> > >::const_iterator showerHitsIt = showerHitsMap.begin(); showerHitsIt != showerHitsMap.end(); ++showerHitsIt) {
2149  double wireWidth = planeWireLength.at(showerHitsIt->first);
2150  wireWidthMap[wireWidth] = showerHitsIt->first;
2151  }
2152 
2153  return wireWidthMap.begin()->second;
2154 
2155 }
2156 
2157 Int_t shower::EMShowerAlg::WeightedFit(const Int_t n, const Double_t *x, const Double_t *y, const Double_t *w, Double_t *parm){
2158 
2159  Double_t sumx=0.;
2160  Double_t sumx2=0.;
2161  Double_t sumy=0.;
2162  Double_t sumy2=0.;
2163  Double_t sumxy=0.;
2164  Double_t sumw=0.;
2165  Double_t eparm[2];
2166 
2167  parm[0] = 0.;
2168  parm[1] = 0.;
2169  eparm[0] = 0.;
2170  eparm[1] = 0.;
2171 
2172  for (Int_t i=0; i<n; i++) {
2173  sumx += x[i]*w[i];
2174  sumx2 += x[i]*x[i]*w[i];
2175  sumy += y[i]*w[i];
2176  sumy2 += y[i]*y[i]*w[i];
2177  sumxy += x[i]*y[i]*w[i];
2178  sumw += w[i];
2179  }
2180 
2181  if (sumx2*sumw-sumx*sumx==0.) return 1;
2182  if (sumx2-sumx*sumx/sumw==0.) return 1;
2183 
2184  parm[0] = (sumy*sumx2-sumx*sumxy)/(sumx2*sumw-sumx*sumx);
2185  parm[1] = (sumxy-sumx*sumy/sumw)/(sumx2-sumx*sumx/sumw);
2186 
2187  eparm[0] = sumx2*(sumx2*sumw-sumx*sumx);
2188  eparm[1] = (sumx2-sumx*sumx/sumw);
2189 
2190  if (eparm[0]<0. || eparm[1]<0.) return 1;
2191 
2192  eparm[0] = sqrt(eparm[0])/(sumx2*sumw-sumx*sumx);
2193  eparm[1] = sqrt(eparm[1])/(sumx2-sumx*sumx/sumw);
2194 
2195  return 0;
2196 
2197 }
2198 
2200 
2201  if (!hits.size()) return false;
2202  if (hits.size()>2000) return true;
2203  if (hits.size()<20) return true;
2204  std::map<int, int> hitmap;
2205  unsigned nhits = 0;
2206  for (auto const&hit : hits){
2207  ++nhits;
2208  if (nhits>2)
2209  ++hitmap[hit->WireID().Wire];
2210  if (nhits==20) break;
2211  }
2212  //std::cout<<hits.size()<<" "<<float(nhits-2)/hitmap.size()<<std::endl;
2213  if (float(nhits-2)/hitmap.size()>1.4) return false;
2214  else return true;
2215 }
2216 
2218  : fGeom(lar::providerFrom<geo::Geometry>())
2219  , fDetProp(lar::providerFrom<detinfo::DetectorPropertiesService>())
2220  {}
2221 
2222 
2223 // // Code to make wire maps showing the global wire coordinates
2224 // struct TPCWire {
2225 // int fPlane, fTPC, fWire, fGlobalWire;
2226 // TVector3 fStart, fEnd;
2227 // TPCWire(int plane, int tpc, int wire, int globalWire, TVector3 start, TVector3 end) {
2228 // fPlane = plane;
2229 // fTPC = tpc;
2230 // fWire = wire;
2231 // fGlobalWire = globalWire;
2232 // fStart = start;
2233 // fEnd = end;
2234 // }
2235 // TPCWire() { }
2236 // void SetProps(int plane, int tpc, int wire, int globalWire, TVector3 start, TVector3 end) {
2237 // fPlane = plane;
2238 // fTPC = tpc;
2239 // fWire = wire;
2240 // fGlobalWire = globalWire;
2241 // fStart = start;
2242 // fEnd = end;
2243 // }
2244 // };
2245 
2246 // void shower::EMShowerAlg::MakePicture() {
2247 
2248 // std::vector<TPCWire> allWires;
2249 
2250 // for (geo::WireID const& wireID : fGeom->IterateWireIDs()) {
2251 
2252 // if (wireID.TPC % 2 == 0)
2253 // continue;
2254 
2255 // double xyzStart[3], xyzEnd[3];
2256 // fGeom->WireEndPoints(wireID, xyzStart, xyzEnd);
2257 // int globalWire = GlobalWire(wireID);
2258 
2259 // allWires.emplace_back(wireID.Plane, wireID.TPC, wireID.Wire, globalWire, TVector3(xyzStart[0],xyzStart[1],xyzStart[2]), TVector3(xyzEnd[0],xyzEnd[1],xyzEnd[2]));
2260 
2261 // } // for all wires
2262 
2263 // TCanvas* uplane = new TCanvas();
2264 // TCanvas* vplane = new TCanvas();
2265 // TCanvas* zplane = new TCanvas();
2266 // TText* number = new TText();
2267 // number->SetTextSize(0.002);
2268 // TLine* line = new TLine(0,100,0,100);
2269 // line->SetLineWidth(0.5);
2270 // uplane->Range(-5,-100,160,140);
2271 // vplane->Range(-5,-100,160,140);
2272 // zplane->Range(-5,-100,160,140);
2273 
2274 // for (std::vector<TPCWire>::iterator wireIt = allWires.begin(); wireIt != allWires.end(); ++wireIt) {
2275 // if (wireIt->fPlane == 0)
2276 // uplane->cd();
2277 // else if (wireIt->fPlane == 1)
2278 // vplane->cd();
2279 // else if (wireIt->fPlane == 2)
2280 // zplane->cd();
2281 // line->DrawLine(wireIt->fStart.Z(), wireIt->fStart.Y(), wireIt->fEnd.Z(), wireIt->fEnd.Y());
2282 // number->DrawText(wireIt->fStart.Z(), wireIt->fStart.Y(), (std::to_string(wireIt->fGlobalWire)+" ("+std::to_string(wireIt->fWire)+")").c_str());
2283 // number->DrawText(wireIt->fEnd.Z(), wireIt->fEnd.Y(), (std::to_string(wireIt->fGlobalWire)+" ("+std::to_string(wireIt->fWire)+")").c_str());
2284 // }
2285 
2286 // uplane->SaveAs("UPlane.pdf");
2287 // vplane->SaveAs("VPlane.pdf");
2288 // zplane->SaveAs("ZPlane.pdf");
2289 
2290 // }
2291 
2292 //
2293 // // Timing code...
2294 //
2295 // auto start_time = std::chrono::high_resolution_clock::now();
2296 // // Put stuff here!
2297 // auto duration = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::high_resolution_clock::now() - start_time).count();
2298 // std::cout << "Duration is " << duration/1000000.0 << " s " << std::endl;;
2299 //
2300 
2302 
2304 
2305  // Make a map of the tracks which are associated with this shower and the charge each contributes
2306  std::map<int,double> trackMap;
2307  for (std::vector<art::Ptr<recob::Hit> >::const_iterator showerHitIt = showerHits.begin(); showerHitIt != showerHits.end(); ++showerHitIt) {
2308  art::Ptr<recob::Hit> hit = *showerHitIt;
2309  int trackID = FindParticleID(hit);
2310  trackMap[trackID] += hit->Integral();
2311  }
2312 
2313  // Pick the track with the highest charge as the 'true track'
2314  double highestCharge = 0;
2315  int showerTrack = 0;
2316  for (std::map<int,double>::iterator trackIt = trackMap.begin(); trackIt != trackMap.end(); ++trackIt) {
2317  if (trackIt->second > highestCharge) {
2318  highestCharge = trackIt->second;
2319  showerTrack = trackIt->first;
2320  }
2321  }
2322 
2323  return showerTrack;
2324 
2325 }
2326 
2328 
2330 
2331  double particleEnergy = 0;
2332  int likelyTrackID = 0;
2333  std::vector<sim::TrackIDE> trackIDs = bt_serv->HitToTrackIDEs(hit);
2334  for (unsigned int idIt = 0; idIt < trackIDs.size(); ++idIt) {
2335  if (trackIDs.at(idIt).energy > particleEnergy) {
2336  particleEnergy = trackIDs.at(idIt).energy;
2337  likelyTrackID = TMath::Abs(trackIDs.at(idIt).trackID);
2338  }
2339  }
2340 
2341  return likelyTrackID;
2342 
2343 }
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
TVector3 VertexDirection() const
Covariance matrices are either set or not.
Definition: Track.h:247
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.
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)
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)
bool CheckShowerHits(std::map< int, std::vector< art::Ptr< recob::Hit > > > const &showerHitsMap)
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
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
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)
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
TVector3 Vertex() const
Covariance matrices are either set or not.
Definition: Track.h:245
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