LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
fuzzyClusterAlg.cxx
Go to the documentation of this file.
1 //
3 // fuzzyClusterAlg.cxx
4 //
5 // Ben Carls, bcarls@fnal.gov
6 //
8 
9 
10 // C/C++ standard library
11 #include <cmath> // std::sqrt(), std::atan(), std::pow()
12 #include <utility> // std::move()
13 #include <iterator> // std::back_inserter()
14 #include <algorithm> // std::remove_if()
15 #include <functional> // std::mem_fn()
16 
17 // ART and support libraries
19 #include "fhiclcpp/ParameterSet.h"
22 
23 // LArSoft libraries
29 
30 
31 namespace {
32  template <typename T>
33  inline constexpr T sqr(T v) { return v*v; }
34 
35  template <typename T>
36  inline constexpr T sumsq(T a, T b) { return sqr(a) + sqr(b); }
37 
38  template <typename T>
39  inline constexpr T norm(T a, T b) { return std::sqrt(sumsq(a, b)); }
40 
41 } // local namespace
42 
43 
44 
45 namespace cluster {
46 
47  // Define parameters that will tell us if we are doing a normal Hough line merge
48  // or a shower Hough line merge
49  enum class MergeMode: short int {
50  Shower,
51  Normal,
54  }; // MergeMode
55 
56 
59  public:
60  int clusterNumber=-999999;
61  std::vector<protoTrack> clusterProtoTracks;
62 
63  baseCluster(protoTrack protoTrackTemp)
64  {
65  clusterNumber = protoTrackTemp.clusterNumber;
66  clusterProtoTracks.emplace_back(std::move(protoTrackTemp));
67  }
68 
69  void addProtoTracks(std::vector<protoTrack> tracksToAdd)
70  {
71  for(auto& trackToAdd: tracksToAdd)
72  trackToAdd.clusterNumber = clusterNumber;
73  clusterProtoTracks.reserve
74  (clusterProtoTracks.size() + tracksToAdd.size());
75  std::move(tracksToAdd.begin(),tracksToAdd.end(),
76  std::back_inserter(clusterProtoTracks));
77  } // addProtoTracks()
78 
80  {
81  clusterProtoTracks.clear();
82  } // clearProtoTracks()
83 
84  }; // class fuzzyCluster::baseCluster
85 
88  public:
89  showerCluster(protoTrack protoTrackTemp): baseCluster(protoTrackTemp) {}
90  }; // class fuzzyClusterAlg::showerCluster
91 
94  public:
95  trackCluster(protoTrack protoTrackTemp): baseCluster(protoTrackTemp) {}
96  }; // class fuzzyClusterAlg::trackCluster
97 
98 
99 } // namespace cluster
100 
101 
102 
103 
104 namespace cluster{
105  const unsigned int kNO_CLUSTER = UINT_MAX;
106  const unsigned int kNOISE_CLUSTER = UINT_MAX-1;
107 }
108 
109 //----------------------------------------------------------
110 // fuzzyClusterAlg stuff
111 //----------------------------------------------------------
113  : fHBAlg(pset.get< fhicl::ParameterSet >("HoughBaseAlg")),
114  fDBScan(pset.get< fhicl::ParameterSet >("DBScanAlg"))
115 
116 {
117  this->reconfigure(pset);
118 }
119 
120 //----------------------------------------------------------
122 {
123 }
124 
125 //----------------------------------------------------------
127 {
128 
129  fNumberTimeBoundaries = p.get< double >("NumberTimeBoundaries" );
130  fNumberWireBoundaries = p.get< double >("NumberWireBoundaries" );
131  fDoFuzzyRemnantMerge = p.get< bool >("DoFuzzyRemnantMerge" );
132  fFuzzyRemnantMergeCutoff = p.get< double >("FuzzyRemnantMergeCutoff" );
133  fDoTrackClusterMerge = p.get< bool >("DoTrackClusterMerge" );
134  fTrackClusterMergeCutoff = p.get< double >("TrackClusterMergeCutoff" );
135  fChargeAsymAngleCut = p.get< double >("ChargeAsymAngleCut" );
136  fSigmaChargeAsymAngleCut = p.get< double >("SigmaChargeAsymAngleCut" );
137  fDoShowerClusterMerge = p.get< bool >("DoShowerClusterMerge" );
138  fDoShowerTrackClusterMerge = p.get< bool >("DoShowerTrackClusterMerge" );
139  fShowerClusterMergeCutoff = p.get< double >("ShowerClusterMergeCutoff" );
140  fShowerClusterMergeAngle = p.get< double >("ShowerClusterMergeAngle" );
141  fShowerTrackClusterMergeCutoff = p.get< double >("ShowerTrackClusterMergeCutoff" );
142  fShowerTrackClusterMergeAngle = p.get< double >("ShowerTrackClusterMergeAngle" );
143  fShowerLikenessCut = p.get< double >("ShowerLikenessCut" );
144  fMaxVertexLines = p.get< int >("MaxVertexLines" );
145  fVertexLinesCutoff = p.get< double >("VertexLinesCutoff" );
146  fRunHough = p.get< bool >("RunHough" );
147  fGenerateHoughLinesOnly = p.get< bool >("GenerateHoughLinesOnly" );
148  fHBAlg.reconfigure(p.get< fhicl::ParameterSet >("HoughBaseAlg"));
149  fDBScan.reconfigure(p.get< fhicl::ParameterSet >("DBScanAlg"));
150 }
151 
152 
153 //----------------------------------------------------------
155  std::set<uint32_t> badChannels)
156 {
157  // clear all the data member vectors for the new set of hits
158  fps.clear();
159  fpointId_to_clusterId.clear();
160  fnoise.clear();
161  fvisited.clear();
162  fsim.clear();
163  fsim2.clear();
164  fsim3.clear();
165  fclusters.clear();
166  fWirePitch.clear();
167 
168  fBadChannels = badChannels;
169  fBadWireSum.clear();
170 
171  const detinfo::DetectorProperties* detp = lar::providerFrom<detinfo::DetectorPropertiesService>();
173 
174 
175  unsigned int cs=allhits[0]->WireID().Cryostat;
176  unsigned int t=allhits[0]->WireID().TPC;
177 
178  fWirePitch.resize(geom->Nplanes(t, cs), 0.);
179  for (size_t p = 0; p < fWirePitch.size(); ++p) {
180  fWirePitch[p] = geom->WirePitch(p);
181  }
182 
183 
184 
185  // Collect the hits in a useful form,
186  // and take note of the maximum time width
187  fMaxWidth=0.0;
188 
189  double tickToDist = detp->DriftVelocity(detp->Efield(),detp->Temperature());
190  tickToDist *= 1.e-3 * detp->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
191  int dims = 3;//our point is defined by 3 elements:wire#,center of the hit, and the hit width
192  std::vector<double> p(dims);
193  for (auto allhitsItr = allhits.begin(); allhitsItr < allhits.end(); allhitsItr++){
194 
195  p[0] = ((*allhitsItr)->WireID().Wire)*fWirePitch[(*allhitsItr)->WireID().Plane];
196  p[1] = (*allhitsItr)->PeakTime()*tickToDist;
197  p[2] = (*allhitsItr)->Integral(); //width of a hit in cm
198 
199  // check on the maximum width condition
200  if ( p[2] > fMaxWidth ) fMaxWidth = p[2];
201 
202  fps.push_back(p);
203 
204  }
205 
206  mf::LogInfo("fuzzyCluster") << "Initfuzzy: hits vector size is " << fps.size();
207 
208  return;
209 }
210 
211 
212 //----------------------------------------------------------------
214 // This is the algorithm that finds clusters:
215 //
216 // Ben Carls' implementation of fuzzyClusterAlg as much like examples as possible
218 
219  // Don't attempt to run the algorithm if we have 1 or fewer hits
220  if(allhits.size() <= 1)
221  return;
222 
223  mf::LogInfo("fuzzyClusterAlg") << "Clustering " << allhits.size() << " hits";
224 
225 
226  fpointId_to_clusterId.resize(fps.size(), kNO_CLUSTER); // Not zero as before!
227  fnoise.resize(fps.size(), false);
228  fvisited.resize(fps.size(), false);
229 
231  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
232 
233 
234  //factor to make x and y scale the same units
235 // uint32_t channel = allhits[0]->Channel();
236 // double wirePitch = geom->WirePitch(geom->View(channel));
237  uint32_t channel = allhits[0]->WireID().Wire;
238 // double wirePitch[2];
239 // wirePitch[0] = geom->WirePitch(0);
240 // wirePitch[1] = geom->WirePitch(1);
241 // wirePitch[2] = geom->WirePitch(2);
242 
243 // saw this one
244 
245  double xyScale = .001*detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
246  xyScale*=detprop->SamplingRate();
247  // double wire_dist = wirePitch;
248 
249  double tickToDist = detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
250  tickToDist *= 1.e-3 * detprop->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
251 
252 
253  double indcolscaling = 0.; //a parameter to account for the different
254  //characteristic hit width of induction and collection plane
258  geo::SigType_t sigt = geom->SignalType(channel);
259  if(sigt == geo::kInduction)
260  indcolscaling = 0.;
261  else
262  indcolscaling = 1.;
263 
264 
265  unsigned int nClusters = 1;
266  unsigned int nClustersTemp = 1;
267 
268  // Divide up readout window into 9 sections that the Hough transform will be run over individually
271  unsigned int nWires = geom->Nwires(allhits[0]->WireID().Plane);
272  unsigned int nTicks = detprop->ReadOutWindowSize();
273  std::vector<unsigned int> wireBoundaries;
274  std::vector<unsigned int> timeBoundaries;
275  for(size_t i = 0; i < fNumberWireBoundaries+1; i++){
276  wireBoundaries.push_back(i*nWires/fNumberWireBoundaries);
277  }
278  for(size_t i = 0; i < fNumberTimeBoundaries + 1; i++){
279  timeBoundaries.push_back(i*nTicks/fNumberTimeBoundaries);
280  }
281  for(auto hitsItr = allhits.cbegin(); hitsItr != allhits.cend(); ++hitsItr){
282  for(size_t i = 0; i < fNumberWireBoundaries; i++){
283  if(( *hitsItr)->WireID().Wire >= wireBoundaries[i] && (*hitsItr)->WireID().Wire < wireBoundaries[i+1]){
284  for(size_t j = 0; j < fNumberTimeBoundaries; j++){
285  if((*hitsItr)->PeakTime() >= timeBoundaries[j] && (*hitsItr)->PeakTime() < timeBoundaries[j+1]){
286  fpointId_to_clusterId[hitsItr-allhits.cbegin()] = j*fNumberTimeBoundaries+i;
287  }
288  }
289  }
290  }
291  }
292 
293 
294 
295 
296 
297 
298  // Loop over clusters with the Hough line finder to break the clusters up further
299  // list of lines
300  std::vector<protoTrack> protoTracksFound;
301  if(nClustersTemp > 0 && fRunHough)
302  for (unsigned int i = 0; i <= (unsigned int)nClustersTemp-1; ++i){
303  LOG_DEBUG("fuzzyClusterAlg")
304  << "Running Hough transform on protocluster " << i;
305  fHBAlg.Transform(allhits, &fpointId_to_clusterId, i, &nClusters, &protoTracksFound);
306  }
307 
308  // Determine the shower likeness of lines
309  std::vector<showerCluster> showerClusters;
310  std::vector<trackCluster> trackClusters;
311  double totalBkgDistCharge;
312  double fMaxDistance;
313  double distance;
314  double peakTimePerpMin;
315  double peakTimePerpMax;
316  for(auto protoTracksFoundItr = protoTracksFound.begin(); protoTracksFoundItr < protoTracksFound.end(); ++protoTracksFoundItr){
317  totalBkgDistCharge = 0;
318  fMaxDistance = 0.1;
319  for(auto hitsItr = allhits.cbegin(); hitsItr != allhits.cend(); ++hitsItr){
321  //if(fpointId_to_clusterId.at(hitsItr-allhits.cbegin()) < nClustersTemp)
322  //continue;
323  distance = (std::abs((*hitsItr)->PeakTime()-protoTracksFoundItr->clusterSlope*(double)((*hitsItr)->WireID().Wire)-protoTracksFoundItr->clusterIntercept)/(std::sqrt(sqr(xyScale/fWirePitch[(*hitsItr)->WireID().Plane]*protoTracksFoundItr->clusterSlope)+1)));
325  peakTimePerpMin=-(1/protoTracksFoundItr->clusterSlope)*(double)((*hitsItr)->WireID().Wire)+allhits[protoTracksFoundItr->iMinWire]->PeakTime()+(1/protoTracksFoundItr->clusterSlope)*(allhits[protoTracksFoundItr->iMinWire]->WireID().Wire);
326  peakTimePerpMax=-(1/protoTracksFoundItr->clusterSlope)*(double)((*hitsItr)->WireID().Wire)+allhits[protoTracksFoundItr->iMaxWire]->PeakTime()+(1/protoTracksFoundItr->clusterSlope)*(allhits[protoTracksFoundItr->iMaxWire]->WireID().Wire);
327  if(distance > 1*(fMaxDistance+(*hitsItr)->RMS()+indcolscaling)
328  && distance < 25*(fMaxDistance+(*hitsItr)->RMS()+indcolscaling)){
329  if((protoTracksFoundItr->clusterSlope < 0 && (*hitsItr)->PeakTime() < peakTimePerpMin && (*hitsItr)->PeakTime() > peakTimePerpMax)
330  || (protoTracksFoundItr->clusterSlope > 0 && (*hitsItr)->PeakTime() > peakTimePerpMin && (*hitsItr)->PeakTime() < peakTimePerpMax)){
331  if((*hitsItr)->Integral() > 0.1){
332  totalBkgDistCharge+=distance/(*hitsItr)->Integral();
333  }
334  }
335  }
336  }
337  protoTracksFoundItr->showerLikeness = totalBkgDistCharge/(double)protoTracksFoundItr->hits.size();
338  //std::cout << "showerLikeness: " << totalBkgDistCharge/(double)protoTracksFoundItr->hits.size() << std::endl;
339 
340  if(protoTracksFoundItr->showerLikeness > fShowerLikenessCut)
341  showerClusters.push_back(showerCluster(*protoTracksFoundItr));
342  else
343  trackClusters.push_back(trackCluster(*protoTracksFoundItr));
344 
345  }
346 
347 
348 
349  // Merge Hough lines
350  bool trackMerged;
351  bool showerMerged;
352  bool showerTrackMerged;
353 
354  if(fDoTrackClusterMerge && trackClusters.size() > 1){
355  unsigned int i = 0;
356  while(i < trackClusters.size()-1){
357  int ip = trackClusters[i].clusterProtoTracks[0].planeNumber;
358  trackMerged = mergeTrackClusters(i,&trackClusters,xyScale/fWirePitch[ip],
359  fWirePitch[ip],tickToDist);
360  if(trackMerged)
361  continue;
362  else
363  i++;
364  }
365  }
366 
367  if(fDoShowerClusterMerge && showerClusters.size() > 1){
368  unsigned int i = 0;
369  while(i < showerClusters.size()-1){
370  int ip = showerClusters[i].clusterProtoTracks[0].planeNumber;
371  showerMerged = mergeShowerClusters(i,&showerClusters,xyScale/fWirePitch[ip],
372  fWirePitch[ip],tickToDist);
373  if(showerMerged)
374  continue;
375  else
376  i++;
377  }
378  }
379 
380  if(fDoShowerTrackClusterMerge && showerClusters.size() > 0 && trackClusters.size() >0){
381  unsigned int i = 0;
382  while(i < showerClusters.size()){
383  int ip = showerClusters[i].clusterProtoTracks[0].planeNumber;
384  unsigned int j = 0;
385  while(j < trackClusters.size()){
386  // int ipt = trackClusters[j].clusterProtoTracks[0].planeNumber;
387  showerTrackMerged = mergeShowerTrackClusters(&showerClusters[i],&trackClusters[j],
388  xyScale/fWirePitch[ip],
389  fWirePitch[ip],tickToDist);
390  if(showerTrackMerged)
391  continue;
392  else
393  j++;
394  }
395  i++;
396  }
397  }
398 
399  if(fDoShowerClusterMerge && showerClusters.size() > 1){
400  unsigned int i = 0;
401  while(i < showerClusters.size()-1){
402  int ip = showerClusters[i].clusterProtoTracks[0].planeNumber;
403  showerMerged = mergeShowerClusters(i,&showerClusters,xyScale/fWirePitch[ip],
404  fWirePitch[ip],tickToDist);
405  if(showerMerged)
406  continue;
407  else
408  i++;
409  }
410  }
411 
412 
413  // Reassign the merged lines
414  for(auto fpointId_to_clusterIdItr = fpointId_to_clusterId.begin(); fpointId_to_clusterIdItr != fpointId_to_clusterId.end(); ++fpointId_to_clusterIdItr){
415  for(auto trackClustersItr = trackClusters.begin(); trackClustersItr != trackClusters.end(); ++trackClustersItr){
416  for(auto protoTracksFoundItr = trackClustersItr->clusterProtoTracks.begin(); protoTracksFoundItr < trackClustersItr->clusterProtoTracks.end(); ++protoTracksFoundItr){
417  if(*fpointId_to_clusterIdItr == (unsigned int)protoTracksFoundItr->oldClusterNumber)
418  *fpointId_to_clusterIdItr = protoTracksFoundItr->clusterNumber;
419  }
420  }
421  for(auto showerClustersItr = showerClusters.begin(); showerClustersItr != showerClusters.end(); ++showerClustersItr){
422  for(auto protoTracksFoundItr = showerClustersItr->clusterProtoTracks.begin(); protoTracksFoundItr < showerClustersItr->clusterProtoTracks.end(); ++protoTracksFoundItr){
423  if(*fpointId_to_clusterIdItr == (unsigned int)protoTracksFoundItr->oldClusterNumber){
424  *fpointId_to_clusterIdItr = protoTracksFoundItr->clusterNumber;
425  }
426  }
427  }
428  }
429 
430 
431  // Find sizes of all merged lines combined
432  // For protoTracksFoundSizes, key is cluster number and size is the mapped value
433  std::map<int,double> protoTracksFoundSizes;
434  for(auto protoTracksFoundItr = protoTracksFound.begin(); protoTracksFoundItr < protoTracksFound.end(); ++protoTracksFoundItr){
435  double d = ::norm(protoTracksFoundItr->pMin0-protoTracksFoundItr->pMax0, protoTracksFoundItr->pMin1-protoTracksFoundItr->pMax1);
436  if(!protoTracksFoundSizes.count(protoTracksFoundItr->clusterNumber))
437  protoTracksFoundSizes[protoTracksFoundItr->clusterNumber] = d;
438  else
439  protoTracksFoundSizes[protoTracksFoundItr->clusterNumber]+= d;
440  }
441 
442 
443 
444  // If only showing Hough lines, set the fuzzy cluster remnants to have no cluster
446  for(auto allhitsItr = allhits.cbegin(); allhitsItr != allhits.cend(); ++allhitsItr){
447  if(fpointId_to_clusterId.at(allhitsItr-allhits.begin()) < (unsigned int) nClustersTemp )
448  fpointId_to_clusterId.at(allhitsItr-allhits.begin()) = kNO_CLUSTER;
449  }
450  }
451 
452  std::vector< art::Ptr<recob::Hit> > unclusteredhits;
453  std::vector<unsigned int> unclusteredhitsToAllhits;
454  int nDBClusters = 0;
455  bool unclustered;
456  double p0;
457  double p1;
458  double minDistanceShower;
459  // double minDistanceTrack;
461  for(auto allhitsItr = allhits.cbegin(); allhitsItr != allhits.cend(); ++allhitsItr){
462  unclustered = true;
463  // nClusters is the number of fuzzy clusters we found, we only assign hits to lines here
464  // if they are not already part of hough lines
465  if(fpointId_to_clusterId.at(allhitsItr-allhits.begin()) >= (unsigned int) nClustersTemp
466  && fpointId_to_clusterId.at(allhitsItr-allhits.begin()) < nClusters ){
467  unclustered = false;
468  continue;
469  }
470  int ip = (*allhitsItr)->WireID().Plane;
471  p0 = ((*allhitsItr)->WireID().Wire)*fWirePitch[ip];
472  p1 = (*allhitsItr)->PeakTime()*tickToDist;
473 
474  // First try to group it with a shower-like cluster
475  minDistanceShower = 999999;
476  for(auto showerClustersItr = showerClusters.begin(); showerClustersItr != showerClusters.end(); ++showerClustersItr){
477  for(auto protoTracksItr = showerClustersItr->clusterProtoTracks.begin(); protoTracksItr < showerClustersItr->clusterProtoTracks.end(); ++protoTracksItr){
478 
479  distance = PointSegmentDistance( p0, p1, protoTracksItr->pMin0, protoTracksItr->pMin1, protoTracksItr->pMax0, protoTracksItr->pMax1);
480 
481  if(distance > fFuzzyRemnantMergeCutoff)
482  continue;
483 
484  // This line used to have 1/4 instead of 0.25; wthat made it uneffective
485  // (1/4 = 0); but replacing 0.25 sensibly changes performances;
486  // commenting out the line for now [GP]
487  // distance /= std::pow(protoTracksFoundSizes[protoTracksItr->clusterNumber], 0.25);
488  if(distance < minDistanceShower){
489  fpointId_to_clusterId.at(allhitsItr-allhits.begin()) = protoTracksItr->clusterNumber;
490  minDistanceShower = distance;
491  unclustered = false;
492  }
493  }
494  }
495 
496  if(!unclustered)
497  continue;
498 
499  // Failing to group it with a shower-like cluster, try with a track-like cluster
500  // minDistanceTrack = 999999;
501  // for(auto trackClustersItr = trackClusters.begin(); trackClustersItr != trackClusters.end(); ++trackClustersItr){
502  // for(auto protoTracksItr = trackClustersItr->clusterProtoTracks.begin(); protoTracksItr < trackClustersItr->clusterProtoTracks.end(); ++protoTracksItr){
503 
504  // distance = PointSegmentDistance( p0, p1, protoTracksItr->pMin0, protoTracksItr->pMin1, protoTracksItr->pMax0, protoTracksItr->pMax1);
505 
506  // if(distance > fFuzzyRemnantMergeCutoff)
507  // continue;
508 
509  // // commenting out the line for now (see above) [GP]
510  // // distance /= std::pow(protoTracksFoundSizes[protoTracksItr->clusterNumber], 0.25);
511  // if(distance < minDistanceTrack){
512  // fpointId_to_clusterId.at(allhitsItr-allhits.begin()) = protoTracksItr->clusterNumber;
513  // minDistanceTrack = distance;
514  // unclustered = false;
515  // }
516  // }
517  // }
518 
519 
520  if(unclustered){
521  unclusteredhitsToAllhits.push_back(allhitsItr-allhits.begin());
522  unclusteredhits.push_back(*allhitsItr);
523  fpointId_to_clusterId.at(allhitsItr-allhits.begin()) = kNOISE_CLUSTER;
524  }
525 
526  }
527 
528  // Setup DBSCAN for noise and extra hits
529  // Start by getting the ChannelFilter
530  // filter::ChannelFilter chanFilt;
531  // fDBScan.InitScan(unclusteredhits, chanFilt.SetOfBadChannels());
532  // fDBScan.run_cluster();
533 
534  // nDBClusters = fDBScan.fclusters.size();
535  // for(size_t j = 0; j < fDBScan.fpointId_to_clusterId.size(); ++j){
536  // if (fDBScan.fpointId_to_clusterId[j]== kNO_CLUSTER || fDBScan.fpointId_to_clusterId[j]==kNOISE_CLUSTER) {
537  // fpointId_to_clusterId.at(unclusteredhitsToAllhits[j]) = kNOISE_CLUSTER;
538  // }
539  // else {
540  // fpointId_to_clusterId.at(unclusteredhitsToAllhits[j]) = fDBScan.fpointId_to_clusterId[j] + nClusters;
541  // }
542  // }
543  }
544 
545  size_t cid = nClusters + nDBClusters;
546 
547  //mf::LogInfo("fuzzyCluster") << "cid: " << cid ;
548 
549  //for(size_t j = 0; j < fpointId_to_clusterId.size(); ++j)
550  //mf::LogInfo("fuzzyCluster") << "fpointId_to_clusterId[j]: " << fpointId_to_clusterId[j] << " j: " << j ;
551 
552 
553  // Construct clusters, count noise, etc..
554  int noise = 0;
555  unsigned int c;
556  fclusters.resize(cid);
557  for(size_t y = 0; y < fpointId_to_clusterId.size(); ++y){
559  // This shouldn't happen...all points should be clasified by now!
560  mf::LogWarning("fuzzyCluster") << "Unclassified point!";
561  }
563  ++noise;
564  }
565  else {
567  if (c >= cid) {
568  mf::LogWarning("fuzzyCluster") << "Point in cluster " << c
569  << " when only " << cid
570  << " clusters were found [0-" << cid-1
571  << "]";
572  }
573  fclusters[c].push_back(y);
574  }
575  }
576  mf::LogInfo("fuzzyCluster") << "DWM (R*-tree): Found "
577  << cid << " clusters...";
578  for (unsigned int c = 0; c < cid; ++c){
579  mf::LogVerbatim("fuzzyCluster") << "\t" << "Cluster " << c << ":\t"
580  << fclusters[c].size();
581  }
582  mf::LogVerbatim("fuzzyCluster") << "\t" << "...and " << noise << " noise points.";
583 }
584 
585 
586 
587 // Merges based on the distance between line segments
589  trackCluster *trackClusterJ,
590  double xyScale,
591  double wire_dist,
592  double tickToDist)
593 {
594 
595  // If we have zero or one Hough lines, move on
596  //if(trackCluster->size() == 0 || trackCluster->size() == 1)
597  //return false;
598 
600  //if(trackCluster->size() == clusIndexStart+1)
601  //return false;
602 
603  std::vector<unsigned int> toMerge;
604  std::vector<double> mergeSlope;
605  std::vector<double> mergeTheta;
606 
607  // toMerge trackCluster index, toMerge trackCluster proto track index
608  bool potentialBestMerge=false;
609  bool performedBestMerge=false;
610  unsigned int bestTrackClusterProtoTrack;
611  unsigned int bestShowerClusterProtoTrack;
612  // Did we merge left (0) or right (1)?
613  int bestShowerRightLeft = -1;
614  //int bestClusIndexStartRightLeft = -1;
615  double bestToMergeTrackClusterProtoTrackDistance=999999;
616  double x11;
617  double y11;
618  double x12;
619  double y12;
620  double x21;
621  double y21;
622  double x22;
623  double y22;
624 
625  for(auto trackClusterProtoTrackItr = trackClusterJ->clusterProtoTracks.begin();
626  trackClusterProtoTrackItr != trackClusterJ->clusterProtoTracks.end();
627  trackClusterProtoTrackItr++){
628 
629  //for(auto trackClustersToMergeItr = trackClusters->begin()+clusIndexStart+1; trackClustersToMergeItr != trackClusters->end(); trackClustersToMergeItr++){
630  //if(trackClusters->at(clusIndexStart).clusterNumber == trackClustersToMergeItr->clusterNumber)
631  //continue;
632  //std::cout << "Made it here" << std::endl;
633 
634  toMerge.clear();
635  mergeSlope.clear();
636  mergeTheta.clear();
637 
638  //Count up how many lines are in merging distance to clusIndexStartProtoTrackItr
639  int nInDistanceTrackClusterLeft = 1;
640  int nInDistanceTrackClusterRight = 1;
641 
642 
643 
644  for(auto showerClusterProtoTrackItr = showerClusterI->clusterProtoTracks.begin();
645  showerClusterProtoTrackItr != showerClusterI->clusterProtoTracks.end();
646  ++showerClusterProtoTrackItr){
647 
648  double segmentDistance = HoughLineDistance(trackClusterProtoTrackItr->pMin0,trackClusterProtoTrackItr->pMin1,
649  trackClusterProtoTrackItr->pMax0,trackClusterProtoTrackItr->pMax1,
650  showerClusterProtoTrackItr->pMin0,showerClusterProtoTrackItr->pMin1,
651  showerClusterProtoTrackItr->pMax0,showerClusterProtoTrackItr->pMax1);
652  if(segmentDistance<fShowerTrackClusterMergeCutoff)
653  {
654  toMerge.push_back(showerClusterProtoTrackItr-showerClusterI->clusterProtoTracks.begin());
655  mergeSlope.push_back(trackClusterProtoTrackItr->clusterSlope*xyScale);
656 
657 
658  // Sum up number of protoTracks at the vertex
659  //distance between two segments in the plane:
660  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
661  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
662  double x11 = showerClusterProtoTrackItr->pMin0;
663  double y11 = showerClusterProtoTrackItr->pMin1;
664  double x12 = showerClusterProtoTrackItr->pMax0;
665  double y12 = showerClusterProtoTrackItr->pMax1;
666  double x21 = trackClusterProtoTrackItr->pMin0;
667  double y21 = trackClusterProtoTrackItr->pMin1;
668  double x22 = trackClusterProtoTrackItr->pMax0;
669  double y22 = trackClusterProtoTrackItr->pMax1;
670 
671  // Compare toMergerItr min with clusIndexStart max
672  double mergeRightClusIndexStartDist = ::norm(x11-x22, y11-y22);
673  // Compare toMergerItr max with clusIndexStart min
674  double mergeLeftClusIndexStartDist = ::norm(x12-x21, y12-y21);
675 
676  // Are we inside the vertex distance? This is smaller than the merge cutoff
677  if(segmentDistance < fVertexLinesCutoff){
678  if( mergeRightClusIndexStartDist > mergeLeftClusIndexStartDist )
679  ++nInDistanceTrackClusterLeft;
680  else
681  ++nInDistanceTrackClusterRight;
682  }
683 
684 
685  }
686 
687  }// End of loop over trackClustersToMergeItr->clusterProtoTracks.begin()
688 
689 
690  mergeTheta.resize(toMerge.size());
691 
692  // Find the angle between the slopes
693  for(auto mergeThetaItr = mergeTheta.begin(); mergeThetaItr != mergeTheta.end(); ++mergeThetaItr){
694  double toMergeSlope = showerClusterI->clusterProtoTracks[toMerge[mergeThetaItr-mergeTheta.begin()]].clusterSlope*xyScale;
695  mergeTheta[mergeThetaItr-mergeTheta.begin()] = std::atan(std::abs(( toMergeSlope - mergeSlope[mergeThetaItr-mergeTheta.begin()])/(1 + toMergeSlope*mergeSlope[mergeThetaItr-mergeTheta.begin()] )))*(180/TMath::Pi());
696  }
697 
698 
699  // Perform the merge
700  for(auto toMergeItr = toMerge.begin(); toMergeItr != toMerge.end(); toMergeItr++){
701 
702  // Apply the angle cut
703  if(mergeTheta[toMergeItr-toMerge.begin()] > fShowerTrackClusterMergeAngle)
704  continue;
705 
706  // First check averages of charge and sigma charge for hits in lines closest to each other
707  //int closestShower=-1;
708  //int closestTrack=-1;
709  double closestDistance=999999;
710  for (auto showerClusterProtoTrackHitItr = showerClusterI->clusterProtoTracks[*toMergeItr].hits.begin(); showerClusterProtoTrackHitItr != showerClusterI->clusterProtoTracks[*toMergeItr].hits.end(); ++showerClusterProtoTrackHitItr) {
711  for (auto trackClusterProtoTrackHitItr = trackClusterProtoTrackItr->hits.begin(); trackClusterProtoTrackHitItr != trackClusterProtoTrackItr->hits.end(); trackClusterProtoTrackHitItr++) {
712  //double distance = ::norm(clusIndStHitItr->first-(*toMergeHitItr).first,
713  // clusIndStHitItr->second-toMergeHitItr->second);
714 
715  double distance = DistanceBetweenHits(*trackClusterProtoTrackHitItr,
716  *showerClusterProtoTrackHitItr,
717  wire_dist,
718  tickToDist);
719  if(distance < closestDistance){
720  closestDistance = distance;
721  //closestShower=showerClusterProtoTrackHitItr-showerClusterI->clusterProtoTracks[*toMergeItr].hits.begin();
722  //closestTrack=trackClusterProtoTrackHitItr-trackClusterProtoTrackItr->hits.begin();
723  }
724  }
725  }
726 
727 
728  // Veto the merge if the lines are not colinear
729 
730  //distance between two segments in the plane:
731  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
732  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
733  x11 = showerClusterI->clusterProtoTracks[*toMergeItr].pMin0;
734  y11 = showerClusterI->clusterProtoTracks[*toMergeItr].pMin1;
735  x12 = showerClusterI->clusterProtoTracks[*toMergeItr].pMax0;
736  y12 = showerClusterI->clusterProtoTracks[*toMergeItr].pMax1;
737  x21 = trackClusterProtoTrackItr->pMin0;
738  y21 = trackClusterProtoTrackItr->pMin1;
739  x22 = trackClusterProtoTrackItr->pMax0;
740  y22 = trackClusterProtoTrackItr->pMax1;
741  // BUG the double brace syntax is required to work around clang bug 21629
742  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
743  std::array<double, 4> distances = {{
744  // Compare toMergerItr min with clusIndexStart min, if this is the min distance, lines are not colinear, merge is vetoed
745  ::norm(x11-x21, y11-y21),
746  ::norm(x11-x22, y11-y22), // Compare toMergerItr min with clusIndexStart max
747  ::norm(x12-x21, y12-y21), // Compare toMergerItr max with clusIndexStart min
748  // Compare toMergerItr max with clusIndexStart max, if this is the min distance, lines are not colinear, merge is vetoed
749  ::norm(x12-x22, y12-y22)
750  }}; // distances
751 
752  double minDistance = 999999;
753  int minDistanceIndex = -1;
754  for(unsigned int j = 0; j < distances.size(); j++){
755  if (distances[j] < minDistance){
756  minDistance = distances[j];
757  minDistanceIndex = j;
758  }
759  }
760 
761  if(minDistanceIndex == 0 || minDistanceIndex == 3)
762  continue;
763 
764  // How many lines do we have at the merging point? If too many, veto the merge
765  //std::cout << nInDistanceTrackClusterLeft << " " << nInDistanceTrackClusterRight << std::endl;
766 
767  if(nInDistanceTrackClusterLeft > fMaxVertexLines) {
768  trackClusterProtoTrackItr->mergedLeft = true;
769  showerClusterI->clusterProtoTracks[*toMergeItr].mergedRight = true;
770  }
771  if(nInDistanceTrackClusterRight > fMaxVertexLines) {
772  trackClusterProtoTrackItr->mergedRight = true;
773  showerClusterI->clusterProtoTracks[*toMergeItr].mergedLeft = true;
774  }
775 
776 
777  // Check if we merged left or right already for clusIndexStart, we only do it once for each side
778  //if(trackClusterProtoTrackItr->mergedLeft == true && minDistanceIndex == 2)
779  //continue;
780  //if(trackClusterProtoTrackItr->mergedRight == true && minDistanceIndex == 1)
781  //continue;
782  //if(showerClusterI->clusterProtoTracks[*toMergeItr].mergedLeft == true && minDistanceIndex == 1)
783  //continue;
784  //if(showerClusterI->clusterProtoTracks[*toMergeItr].mergedRight == true && minDistanceIndex == 2)
785  //continue;
786 
787  //std::cout << "Potential merge" << std::endl;
788  //std::cout << "main trackClustersItr slope: " << trackClusters->at(*toMergeItr).clusterSlope << " clusIndexStart slope: " << trackClusters->at(clusIndexStart).clusterSlope << std::endl;
789  potentialBestMerge=true;
790 
791 
792  if(minDistance < bestToMergeTrackClusterProtoTrackDistance){
793  bestShowerClusterProtoTrack=*toMergeItr;
794  bestTrackClusterProtoTrack=trackClusterProtoTrackItr-trackClusterJ->clusterProtoTracks.begin();
795 
796  bestToMergeTrackClusterProtoTrackDistance=minDistance;
797 
798  // Did we merge left (0) or right (1)?
799  if(minDistanceIndex == 1){
800  bestShowerRightLeft = 0;
801  //bestClusIndexStartRightLeft = 1;
802  }
803  if(minDistanceIndex == 2){
804  bestShowerRightLeft = 1;
805  //bestClusIndexStartRightLeft = 0;
806  }
807 
808  }
809 
810  }// End of loop over toMerge
811  //}// End of loop over trackClusters->begin()+clusIndexStart+1
812  }//End of loop over trackClusters->at(clusIndexStart).clusterProtoTracks
813 
814  if(potentialBestMerge){
815  showerClusterI->clusterProtoTracks[bestShowerClusterProtoTrack].merged=true;
816  trackClusterJ->clusterProtoTracks[bestTrackClusterProtoTrack].merged=true;
817  if(bestShowerRightLeft == 0){
818  showerClusterI->clusterProtoTracks[bestShowerClusterProtoTrack].mergedLeft = true;
819  trackClusterJ->clusterProtoTracks[bestTrackClusterProtoTrack].mergedRight = true;
820  performedBestMerge=true;
821  }
822  if(bestShowerRightLeft == 1){
823  showerClusterI->clusterProtoTracks[bestShowerClusterProtoTrack].mergedRight = true;
824  trackClusterJ->clusterProtoTracks[bestTrackClusterProtoTrack].mergedLeft = true;
825  performedBestMerge=true;
826  }
827 
828  if(performedBestMerge){
829  showerClusterI->addProtoTracks(trackClusterJ->clusterProtoTracks);
830  trackClusterJ->clearProtoTracks();
831  //std::cout << "Merged shower-track" << std::endl;
832  }
833 
834  }
835 
836 
837 
838  return performedBestMerge;
839 
840 }
841 
842 
843 
844 // Merges based on the distance between line segments
845 bool cluster::fuzzyClusterAlg::mergeTrackClusters(unsigned int clusIndexStart,
846  std::vector<trackCluster> *trackClusters,
847  double xyScale,
848  double wire_dist,
849  double tickToDist)
850 {
851 
852 
853 
854  // If we have zero or one Hough lines, move on
855  if(trackClusters->size() == 0 || trackClusters->size() == 1)
856  return false;
857 
858  // If we reach the last Hough line, move on
859  if(trackClusters->size() == clusIndexStart+1)
860  return false;
861 
862  std::vector<unsigned int> toMerge;
863  std::vector<double> mergeSlope;
864  std::vector<double> mergeTheta;
865 
866  // toMerge trackCluster index, toMerge trackCluster proto track index
867  bool potentialBestMerge=false;
868  bool performedBestMerge=false;
869  unsigned int bestToMergeTrackCluster;
870  unsigned int bestTrackClustersClusIndexStartProtoTrack;
871  unsigned int bestToMergeTrackClusterProtoTrack;
872  // Did we merge left (0) or right (1)?
873  int bestToMergeRightLeft = -1;
874  //int bestClusIndexStartRightLeft = -1;
875  double bestToMergeTrackClusterProtoTrackDistance=999999;
876 
877  for(auto trackClustersClusIndexStartProtoTrackItr = trackClusters->at(clusIndexStart).clusterProtoTracks.begin();
878  trackClustersClusIndexStartProtoTrackItr != trackClusters->at(clusIndexStart).clusterProtoTracks.end();
879  ++trackClustersClusIndexStartProtoTrackItr){
880 
881  //Count up how many lines are in merging distance to clusIndexStartProtoTrackItr
882  int nInDistanceClusIndexStartLeft = 1;
883  int nInDistanceClusIndexStartRight = 1;
884 
885 
886  for(auto trackClustersToMergeItr = trackClusters->begin()+clusIndexStart+1; trackClustersToMergeItr != trackClusters->end(); trackClustersToMergeItr++){
887  if(trackClusters->at(clusIndexStart).clusterNumber == trackClustersToMergeItr->clusterNumber)
888  continue;
889  //std::cout << "Made it here" << std::endl;
890 
891  toMerge.clear();
892  mergeSlope.clear();
893  mergeTheta.clear();
894 
895  for(auto trackClustersToMergeProtoTrackItr = trackClustersToMergeItr->clusterProtoTracks.begin();
896  trackClustersToMergeProtoTrackItr != trackClustersToMergeItr->clusterProtoTracks.end();
897  ++trackClustersToMergeProtoTrackItr){
898 
899  double segmentDistance = HoughLineDistance(trackClustersClusIndexStartProtoTrackItr->pMin0,trackClustersClusIndexStartProtoTrackItr->pMin1,
900  trackClustersClusIndexStartProtoTrackItr->pMax0,trackClustersClusIndexStartProtoTrackItr->pMax1,
901  trackClustersToMergeProtoTrackItr->pMin0,trackClustersToMergeProtoTrackItr->pMin1,
902  trackClustersToMergeProtoTrackItr->pMax0,trackClustersToMergeProtoTrackItr->pMax1);
903  if(segmentDistance<fTrackClusterMergeCutoff)
904  {
905  toMerge.push_back(trackClustersToMergeProtoTrackItr-trackClustersToMergeItr->clusterProtoTracks.begin());
906  mergeSlope.push_back(trackClustersClusIndexStartProtoTrackItr->clusterSlope*xyScale);
907 
908 
909  // Sum up number of protoTracks at the vertex
910  //distance between two segments in the plane:
911  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
912  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
913  double x11 = trackClustersToMergeProtoTrackItr->pMin0;
914  double y11 = trackClustersToMergeProtoTrackItr->pMin1;
915  double x12 = trackClustersToMergeProtoTrackItr->pMax0;
916  double y12 = trackClustersToMergeProtoTrackItr->pMax1;
917  double x21 = trackClustersClusIndexStartProtoTrackItr->pMin0;
918  double y21 = trackClustersClusIndexStartProtoTrackItr->pMin1;
919  double x22 = trackClustersClusIndexStartProtoTrackItr->pMax0;
920  double y22 = trackClustersClusIndexStartProtoTrackItr->pMax1;
921 
922  // Compare toMergerItr min with clusIndexStart max
923  double mergeRightClusIndexStartDist = std::sqrt(sqr(x11-x22) + sqr(y11-y22));
924  // Compare toMergerItr max with clusIndexStart min
925  double mergeLeftClusIndexStartDist = std::sqrt(sqr(x12-x21) + sqr(y12-y21));
926 
927  // Are we inside the vertex distance? This is smaller than the merge cutoff
928  if(segmentDistance < fVertexLinesCutoff){
929  if( mergeRightClusIndexStartDist > mergeLeftClusIndexStartDist )
930  nInDistanceClusIndexStartLeft++;
931  else
932  nInDistanceClusIndexStartRight++;
933  }
934  }
935 
936  }// End of loop over trackClustersToMergeItr->clusterProtoTracks.begin()
937 
938 
939  mergeTheta.resize(toMerge.size());
940 
941  // Find the angle between the slopes
942  for(auto mergeThetaItr = mergeTheta.begin(); mergeThetaItr != mergeTheta.end(); ++mergeThetaItr){
943  double toMergeSlope = trackClustersToMergeItr->clusterProtoTracks[toMerge[mergeThetaItr-mergeTheta.begin()]].clusterSlope*xyScale;
944  mergeTheta[mergeThetaItr-mergeTheta.begin()] = std::atan(std::abs(( toMergeSlope - mergeSlope[mergeThetaItr-mergeTheta.begin()])/(1 + toMergeSlope*mergeSlope[mergeThetaItr-mergeTheta.begin()] )))*(180/TMath::Pi());
945  }
946 
947 
948  // Perform the merge
949  for(auto toMergeItr = toMerge.begin(); toMergeItr != toMerge.end(); toMergeItr++){
950 
951  // First check averages of charge and sigma charge for hits in lines closest to each other
952  int closestToMerge=-1;
953  int closestClusIndexStart=-1;
954  double closestDistance=999999;
955  for (auto toMergeHitItr = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin(); toMergeHitItr != trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.end(); toMergeHitItr++) {
956  for (auto clusIndStHitItr = trackClustersClusIndexStartProtoTrackItr->hits.begin(); clusIndStHitItr != trackClustersClusIndexStartProtoTrackItr->hits.end(); clusIndStHitItr++) {
957  //double distance = std::sqrt(sqr(clusIndStHitItr->first-(*toMergeHitItr).first)+
958  //sqr(clusIndStHitItr->second-toMergeHitItr->second));
959 
960  double distance = DistanceBetweenHits(*clusIndStHitItr,
961  *toMergeHitItr,
962  wire_dist,
963  tickToDist);
964  if(distance < closestDistance){
965  closestDistance = distance;
966  closestToMerge=toMergeHitItr-trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin();
967  closestClusIndexStart=clusIndStHitItr-trackClustersClusIndexStartProtoTrackItr->hits.begin();
968  }
969  }
970  }
971 
972  // Find up to 9 more points closest to closestToMerge on the toMerge[i] line
973  // check if it's closer, insert, delete
974  using Pair_I_D = std::pair<int,double>;
975  std::vector<Pair_I_D> closestToMergeDist;
976  for (auto toMergeHitItr = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin(); toMergeHitItr != trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.end(); ++toMergeHitItr) {
977  if(closestToMerge==toMergeHitItr-trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin())
978  continue;
979  double distance = DistanceBetweenHits(trackClustersClusIndexStartProtoTrackItr->hits[closestClusIndexStart],
980  *toMergeHitItr,
981  wire_dist,
982  tickToDist);
983 
984  bool foundCloser = false;
985  for(auto closestToMergeDistItr = closestToMergeDist.begin(); closestToMergeDistItr != closestToMergeDist.end(); closestToMergeDistItr++) {
986  if(closestToMergeDistItr->second > distance){
987  foundCloser = true;
988  break;
989  }
990  }
991  if(foundCloser
992  || closestToMergeDist.size() < trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.size()-1
993  || closestToMergeDist.size() < 9){
994  closestToMergeDist.emplace_back(toMergeHitItr-trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin(),distance);
995  std::sort(closestToMergeDist.begin(), closestToMergeDist.end(),
996  [](const Pair_I_D& a, const Pair_I_D& b){ return a.second < b.second; }
997  );
998  // std::sort(closestToMergeDist.begin(), closestToMergeDist.end(), boost::bind(&std::pair<int,double>::second,_1) < boost::bind(&std::pair<int,double>::second,_2));
999  }
1000  if(closestToMergeDist.size() > trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.size()-1 ||
1001  closestToMergeDist.size() > 9)
1002  closestToMergeDist.erase(closestToMergeDist.end());
1003  }
1004  //for(auto closestToMergeDistItr = closestToMergeDist.begin(); closestToMergeDistItr != closestToMergeDist.end();
1005  //closestToMergeDistItr++)
1006  //std::cout << closestToMergeDistItr->first << " " << closestToMergeDistItr->second << std::endl;
1007 
1008 
1009 
1010  // Find up to 9 more points closest to closestToMerge on the clusIndexStart line
1011  std::vector<Pair_I_D> closestClusIndexStartDist;
1012  for (auto clusIndexStartHitItr = trackClustersClusIndexStartProtoTrackItr->hits.begin(); clusIndexStartHitItr != trackClustersClusIndexStartProtoTrackItr->hits.end(); ++clusIndexStartHitItr) {
1013  if(closestClusIndexStart==clusIndexStartHitItr-trackClustersClusIndexStartProtoTrackItr->hits.begin())
1014  continue;
1015 
1016  double distance = DistanceBetweenHits(*clusIndexStartHitItr,
1017  trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits[closestToMerge],
1018  wire_dist,
1019  tickToDist);
1020 
1021  bool foundCloser = false;
1022  for(auto closestClusIndexStartDistItr = closestClusIndexStartDist.begin(); closestClusIndexStartDistItr != closestClusIndexStartDist.end(); ++closestClusIndexStartDistItr) {
1023  if(closestClusIndexStartDistItr->second > distance){
1024  foundCloser = true;
1025  break;
1026  }
1027  }
1028  if(foundCloser
1029  || closestClusIndexStartDist.size() < trackClustersClusIndexStartProtoTrackItr->hits.size()-1
1030  || closestClusIndexStartDist.size() < 9){
1031  closestClusIndexStartDist.emplace_back(clusIndexStartHitItr-trackClustersClusIndexStartProtoTrackItr->hits.begin(),distance);
1032  std::sort(closestClusIndexStartDist.begin(), closestClusIndexStartDist.end(),
1033  [](const Pair_I_D& a, const Pair_I_D& b){ return a.second < b.second; }
1034  );
1035  }
1036  if(closestClusIndexStartDist.size() > trackClustersClusIndexStartProtoTrackItr->hits.size()-1 ||
1037  closestClusIndexStartDist.size() > 9)
1038  closestClusIndexStartDist.erase(closestClusIndexStartDist.end());
1039  }
1040 
1041 
1042 
1043  double toMergeAveCharge = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits[closestToMerge]->Integral();
1044  double toMergeAveSigmaCharge = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits[closestToMerge]->SigmaIntegral();
1045  for(auto closestToMergeDistItr = closestToMergeDist.begin(); closestToMergeDistItr != closestToMergeDist.end(); ++closestToMergeDistItr) {
1046  toMergeAveCharge+= trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits[closestToMergeDistItr->first]->Integral();
1047  toMergeAveSigmaCharge+= trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits[closestToMergeDistItr->first]->SigmaIntegral();
1048  }
1049  double clusIndexStartAveCharge = trackClustersClusIndexStartProtoTrackItr->hits[closestClusIndexStart]->Integral();
1050  double clusIndexStartAveSigmaCharge = trackClustersClusIndexStartProtoTrackItr->hits[closestClusIndexStart]->SigmaIntegral();
1051  for(auto closestClusIndexStartDistItr = closestClusIndexStartDist.begin(); closestClusIndexStartDistItr != closestClusIndexStartDist.end(); ++closestClusIndexStartDistItr) {
1052  clusIndexStartAveCharge+= trackClustersClusIndexStartProtoTrackItr->hits[closestClusIndexStartDistItr->first]->Integral();
1053  clusIndexStartAveSigmaCharge+=trackClustersClusIndexStartProtoTrackItr->hits[closestClusIndexStartDistItr->first]->SigmaIntegral();
1054  }
1055 
1056 
1057 
1058  double chargeAsymmetry = std::abs(toMergeAveCharge-clusIndexStartAveCharge)/(toMergeAveCharge+clusIndexStartAveCharge);
1059  double sigmaChargeAsymmetry = std::abs(toMergeAveSigmaCharge-clusIndexStartAveSigmaCharge)/(toMergeAveSigmaCharge+clusIndexStartAveSigmaCharge);
1060  double chargeAsymmetrySinAngle = chargeAsymmetry*std::abs(sin(mergeTheta[toMergeItr-toMerge.begin()]*TMath::Pi()/180));
1061  double sigmaChargeAsymmetrySinAngle = sigmaChargeAsymmetry*std::fabs(sin(mergeTheta[toMergeItr-toMerge.begin()]*TMath::Pi()/180));
1062 
1063  //std::cout << std::endl;
1064  //std::cout << chargeAsymmetry*std::fabs(sin(mergeTheta[toMergeItr-toMerge.begin()]*TMath::Pi()/180)) << std::endl;
1065  //std::cout << sigmaChargeAsymmetry*std::fabs(sin(mergeTheta[toMergeItr-toMerge.begin()]*TMath::Pi()/180)) << std::endl;
1066 
1067 
1068  if(chargeAsymmetrySinAngle > fChargeAsymAngleCut)
1069  continue;
1070 
1071  if(sigmaChargeAsymmetrySinAngle > fSigmaChargeAsymAngleCut)
1072  continue;
1073 
1074 
1075  // Veto the merge if the lines are not colinear
1076 
1077  //distance between two segments in the plane:
1078  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
1079  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
1080  double x11 = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMin0;
1081  double y11 = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMin1;
1082  double x12 = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMax0;
1083  double y12 = trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMax1;
1084  double x21 = trackClustersClusIndexStartProtoTrackItr->pMin0;
1085  double y21 = trackClustersClusIndexStartProtoTrackItr->pMin1;
1086  double x22 = trackClustersClusIndexStartProtoTrackItr->pMax0;
1087  double y22 = trackClustersClusIndexStartProtoTrackItr->pMax1;
1088  // BUG the double brace syntax is required to work around clang bug 21629
1089  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
1090  std::array<double, 4> distances = {{
1091  // Compare toMergerItr min with clusIndexStart min, if this is the min distance, lines are not colinear, merge is vetoed
1092  ::norm(x11-x21, y11-y21),
1093  ::norm(x11-x22, y11-y22), // Compare toMergerItr min with clusIndexStart max
1094  ::norm(x12-x21, y12-y21), // Compare toMergerItr max with clusIndexStart min
1095  // Compare toMergerItr max with clusIndexStart max, if this is the min distance, lines are not colinear, merge is vetoed
1096  ::norm(x12-x22, y12-y22)
1097  }}; // distances
1098 
1099  double minDistance = 999999;
1100  int minDistanceIndex = -1;
1101  for(unsigned int j = 0; j < distances.size(); j++){
1102  if (distances[j] < minDistance){
1103  minDistance = distances[j];
1104  minDistanceIndex = j;
1105  }
1106  }
1107 
1108  if(minDistanceIndex == 0 || minDistanceIndex == 3)
1109  continue;
1110 
1111 
1112  // How many lines do we have at the merging point? If too many, veto the merge
1113  //std::cout << nInDistanceClusIndexStartLeft << " " << nInDistanceClusIndexStartRight << std::endl;
1114 
1115  if(nInDistanceClusIndexStartLeft > fMaxVertexLines) {
1116  trackClustersClusIndexStartProtoTrackItr->mergedLeft = true;
1117  trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedRight = true;
1118  }
1119  if(nInDistanceClusIndexStartRight > fMaxVertexLines) {
1120  trackClustersClusIndexStartProtoTrackItr->mergedRight = true;
1121  trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedLeft = true;
1122  }
1123 
1124 
1125 
1126 
1127  // Check if we merged left or right already for clusIndexStart, we only do it once for each side
1128  if(trackClustersClusIndexStartProtoTrackItr->mergedLeft == true && minDistanceIndex == 2)
1129  continue;
1130  if(trackClustersClusIndexStartProtoTrackItr->mergedRight == true && minDistanceIndex == 1)
1131  continue;
1132  if(trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedLeft == true && minDistanceIndex == 1)
1133  continue;
1134  if(trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedRight == true && minDistanceIndex == 2)
1135  continue;
1136 
1137  //std::cout << "Potential merge" << std::endl;
1138  //std::cout << "main trackClustersItr slope: " << trackClusters->at(*toMergeItr).clusterSlope << " clusIndexStart slope: " << trackClusters->at(clusIndexStart).clusterSlope << std::endl;
1139  potentialBestMerge=true;
1140 
1141 
1142  if(minDistance < bestToMergeTrackClusterProtoTrackDistance){
1143  bestToMergeTrackCluster=trackClustersToMergeItr-trackClusters->begin();
1144  bestToMergeTrackClusterProtoTrack=*toMergeItr;
1145  bestTrackClustersClusIndexStartProtoTrack=trackClustersClusIndexStartProtoTrackItr-trackClusters->at(clusIndexStart).clusterProtoTracks.begin();
1146  bestToMergeTrackClusterProtoTrackDistance=minDistance;
1147 
1148  // Did we merge left (0) or right (1)?
1149  if(minDistanceIndex == 1){
1150  bestToMergeRightLeft = 0;
1151  //bestClusIndexStartRightLeft = 1;
1152  }
1153  if(minDistanceIndex == 2){
1154  bestToMergeRightLeft = 1;
1155  //bestClusIndexStartRightLeft = 0;
1156  }
1157 
1158  }
1159 
1160  }// End of loop over toMerge
1161  }// End of loop over trackClusters->begin()+clusIndexStart+1
1162  }//End of loop over trackClusters->at(clusIndexStart).clusterProtoTracks
1163 
1164  if(potentialBestMerge){
1165  trackClusters->at(bestToMergeTrackCluster).clusterProtoTracks[bestToMergeTrackClusterProtoTrack].merged=true;
1166  trackClusters->at(clusIndexStart).clusterProtoTracks[bestTrackClustersClusIndexStartProtoTrack].merged=true;
1167  if(bestToMergeRightLeft == 0){
1168  trackClusters->at(bestToMergeTrackCluster).clusterProtoTracks[bestToMergeTrackClusterProtoTrack].mergedLeft = true;
1169  trackClusters->at(clusIndexStart).clusterProtoTracks[bestTrackClustersClusIndexStartProtoTrack].mergedRight = true;
1170  performedBestMerge=true;
1171  }
1172  if(bestToMergeRightLeft == 1){
1173  trackClusters->at(bestToMergeTrackCluster).clusterProtoTracks[bestToMergeTrackClusterProtoTrack].mergedRight = true;
1174  trackClusters->at(clusIndexStart).clusterProtoTracks[bestTrackClustersClusIndexStartProtoTrack].mergedLeft = true;
1175  performedBestMerge=true;
1176  }
1177 
1178  if(performedBestMerge){
1179  trackClusters->at(clusIndexStart).addProtoTracks(trackClusters->at(bestToMergeTrackCluster).clusterProtoTracks);
1180  trackClusters->at(bestToMergeTrackCluster).clearProtoTracks();
1181  //std::cout << "Merged track-track" << std::endl;
1182  }
1183 
1184  }
1185 
1186  //lineMerged = true;
1187  //trackClustersClusIndexStartProtoTrackItr->merged = true;
1188  //trackClustersToMergeItr->clusterProtoTracks[*toMergeItr].merged = true;
1189 
1194  //for(auto trackClustersItr = trackClusters->begin(); trackClustersItr != trackClusters->end(); trackClustersItr++){
1195  //if((unsigned int)(*toMergeItr) == trackClustersItr-trackClusters->begin())
1196  //continue;
1197 
1198  //if(trackClustersItr->clusterNumber == trackClusters->at(*toMergeItr).clusterNumber){
1199  //trackClustersItr->clusterNumber = trackClusters->at(clusIndexStart).clusterNumber;
1200  //}
1201  //}
1202  //trackClusters->at(*toMergeItr).clusterNumber = trackClusters->at(clusIndexStart).clusterNumber;
1203 
1204 
1205  return performedBestMerge;
1206 
1207 }
1208 
1209 
1210 
1211 // Merges based on the distance between line segments
1212 bool cluster::fuzzyClusterAlg::mergeShowerClusters(unsigned int clusIndexStart,
1213  std::vector<showerCluster> *showerClusters,
1214  double xyScale,
1215  double wire_dist,
1216  double tickToDist)
1217 {
1218 
1219  // If we have zero or one Hough lines, move on
1220  if(showerClusters->size() == 0 || showerClusters->size() == 1)
1221  return false;
1222 
1223  // If we reach the last Hough line, move on
1224  if(showerClusters->size() == clusIndexStart+1)
1225  return false;
1226 
1227  std::vector<unsigned int> toMerge;
1228  std::vector<double> mergeSlope;
1229  std::vector<double> mergeTheta;
1230 
1231  // toMerge trackCluster index, toMerge trackCluster proto track index
1232  //bool potentialBestMerge=false;
1233  bool performedBestMerge=false;
1234  unsigned int bestToMergeShowerCluster;
1235  unsigned int bestShowerClustersClusIndexStartProtoTrack;
1236  unsigned int bestToMergeShowerClusterProtoTrack;
1237  int bestToMergeRightLeft = -1;
1238  //int bestClusIndexStartRightLeft = -1;
1239  double bestToMergeShowerClusterProtoTrackDistance=999999;
1240 
1241 
1242  for(auto showerClustersClusIndexStartProtoTrackItr = showerClusters->at(clusIndexStart).clusterProtoTracks.begin();
1243  showerClustersClusIndexStartProtoTrackItr != showerClusters->at(clusIndexStart).clusterProtoTracks.end();
1244  ++showerClustersClusIndexStartProtoTrackItr){
1245 
1246  for(auto showerClustersToMergeItr = showerClusters->begin()+clusIndexStart+1; showerClustersToMergeItr != showerClusters->end(); ++showerClustersToMergeItr){
1247  //std::cout << "Made it here" << std::endl;
1248 
1249  toMerge.clear();
1250  mergeSlope.clear();
1251  mergeTheta.clear();
1252 
1253  for(auto showerClustersToMergeProtoTrackItr = showerClustersToMergeItr->clusterProtoTracks.begin();
1254  showerClustersToMergeProtoTrackItr != showerClustersToMergeItr->clusterProtoTracks.end();
1255  ++showerClustersToMergeProtoTrackItr){
1256 
1257  if(showerClustersToMergeProtoTrackItr->clusterNumber == showerClustersClusIndexStartProtoTrackItr->clusterNumber)
1258  continue;
1259 
1260 
1261  double segmentDistance = HoughLineDistance(showerClustersClusIndexStartProtoTrackItr->pMin0,showerClustersClusIndexStartProtoTrackItr->pMin1,
1262  showerClustersClusIndexStartProtoTrackItr->pMax0,showerClustersClusIndexStartProtoTrackItr->pMax1,
1263  showerClustersToMergeProtoTrackItr->pMin0,showerClustersToMergeProtoTrackItr->pMin1,
1264  showerClustersToMergeProtoTrackItr->pMax0,showerClustersToMergeProtoTrackItr->pMax1);
1265  if(segmentDistance<fShowerClusterMergeCutoff)
1266  {
1267  toMerge.push_back(showerClustersToMergeProtoTrackItr-showerClustersToMergeItr->clusterProtoTracks.begin());
1268  mergeSlope.push_back(showerClustersClusIndexStartProtoTrackItr->clusterSlope*xyScale);
1269  }
1270 
1271  }// End of loop over showerClustersToMergeItr->clusterProtoTracks.begin()
1272 
1273 
1274  mergeTheta.resize(toMerge.size());
1275 
1276  // Find the angle between the slopes
1277  for(auto mergeThetaItr = mergeTheta.begin(); mergeThetaItr != mergeTheta.end(); ++mergeThetaItr){
1278  double toMergeSlope = showerClustersToMergeItr->clusterProtoTracks[toMerge[mergeThetaItr-mergeTheta.begin()]].clusterSlope*xyScale;
1279  mergeTheta[mergeThetaItr-mergeTheta.begin()] = std::atan(std::abs(( toMergeSlope - mergeSlope[mergeThetaItr-mergeTheta.begin()])/(1 + toMergeSlope*mergeSlope[mergeThetaItr-mergeTheta.begin()] )))*(180/TMath::Pi());
1280  }
1281 
1282 
1283  // Perform the merge
1284  for(auto toMergeItr = toMerge.begin(); toMergeItr != toMerge.end(); ++toMergeItr){
1285 
1286  // Apply the angle cut
1287  if(mergeTheta[toMergeItr-toMerge.begin()] > fShowerClusterMergeAngle)
1288  continue;
1289 
1290  // Find the closest distance
1291  //int closestToMerge=-1;
1292  //int closestClusIndexStart=-1;
1293  double closestDistance=999999;
1294  for (auto toMergeHitItr = showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin(); toMergeHitItr != showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.end(); ++toMergeHitItr) {
1295  for (auto clusIndStHitItr = showerClustersClusIndexStartProtoTrackItr->hits.begin(); clusIndStHitItr != showerClustersClusIndexStartProtoTrackItr->hits.end(); ++clusIndStHitItr) {
1296  //double distance = ::norm(clusIndStHitItr->first-(*toMergeHitItr).first+
1297  //clusIndStHitItr->second-toMergeHitItr->second);
1298 
1299  double distance = DistanceBetweenHits(*clusIndStHitItr,
1300  *toMergeHitItr,
1301  wire_dist,
1302  tickToDist);
1303  if(distance < closestDistance){
1304  closestDistance = distance;
1305  //closestToMerge=toMergeHitItr-showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].hits.begin();
1306  //closestClusIndexStart=clusIndStHitItr-showerClustersClusIndexStartProtoTrackItr->hits.begin();
1307  }
1308  }
1309  }
1310 
1311 
1312  // Veto the merge if the lines are not colinear
1313 
1314  //distance between two segments in the plane:
1315  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
1316  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
1317  double x11 = showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMin0;
1318  double y11 = showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMin1;
1319  double x12 = showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMax0;
1320  double y12 = showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].pMax1;
1321  double x21 = showerClustersClusIndexStartProtoTrackItr->pMin0;
1322  double y21 = showerClustersClusIndexStartProtoTrackItr->pMin1;
1323  double x22 = showerClustersClusIndexStartProtoTrackItr->pMax0;
1324  double y22 = showerClustersClusIndexStartProtoTrackItr->pMax1;
1325  // BUG the double brace syntax is required to work around clang bug 21629
1326  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
1327  std::array<double, 4> distances = {{
1328  // Compare toMergerItr min with clusIndexStart min, if this is the min distance, lines are not colinear, merge is vetoed
1329  ::norm(x11-x21, y11-y21),
1330  ::norm(x11-x22, y11-y22), // Compare toMergerItr min with clusIndexStart max
1331  ::norm(x12-x21, y12-y21), // Compare toMergerItr max with clusIndexStart min
1332  // Compare toMergerItr max with clusIndexStart max, if this is the min distance, lines are not colinear, merge is vetoed
1333  ::norm(x12-x22, y12-y22)
1334  }}; // distances
1335 
1336  double minDistance = 999999;
1337  int minDistanceIndex = -1;
1338  for(unsigned int j = 0; j < distances.size(); ++j){
1339  if (distances[j] < minDistance){
1340  minDistance = distances[j];
1341  minDistanceIndex = j;
1342  }
1343  }
1344 
1345  if(minDistanceIndex == 0 || minDistanceIndex == 3)
1346  continue;
1347 
1348 
1349 
1350  // Check if we merged left or right already for clusIndexStart, we only do it once for each side
1351  //if(showerClustersClusIndexStartProtoTrackItr->mergedLeft == true && minDistanceIndex == 2)
1352  //continue;
1353  //if(showerClustersClusIndexStartProtoTrackItr->mergedRight == true && minDistanceIndex == 1)
1354  //continue;
1355  //if(showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedLeft == true && minDistanceIndex == 1)
1356  //continue;
1357  //if(showerClustersToMergeItr->clusterProtoTracks[*toMergeItr].mergedRight == true && minDistanceIndex == 2)
1358  //continue;
1359 
1360  //std::cout << "Potential merge" << std::endl;
1361  //std::cout << "main showerClustersItr slope: " << showerClusters->at(*toMergeItr).clusterSlope << " clusIndexStart slope: " << showerClusters->at(clusIndexStart).clusterSlope << std::endl;
1362  performedBestMerge=true;
1363 
1364 
1365  if(closestDistance < bestToMergeShowerClusterProtoTrackDistance){
1366  bestToMergeShowerCluster=showerClustersToMergeItr-showerClusters->begin();
1367  bestToMergeShowerClusterProtoTrack=*toMergeItr;
1368  bestShowerClustersClusIndexStartProtoTrack=showerClustersClusIndexStartProtoTrackItr-showerClusters->at(clusIndexStart).clusterProtoTracks.begin();
1369  // Did we merge left (0) or right (1)?
1370  if(minDistanceIndex == 1){
1371  bestToMergeRightLeft = 0;
1372  //bestClusIndexStartRightLeft = 1;
1373  }
1374  if(minDistanceIndex == 2){
1375  bestToMergeRightLeft = 1;
1376  //bestClusIndexStartRightLeft = 0;
1377  }
1378 
1379  }
1380 
1381  }// End of loop over toMerge
1382  }// End of loop over showerClusters->begin()+clusIndexStart+1
1383  }//End of loop over showerClusters->at(clusIndexStart).clusterProtoTracks
1384 
1385  if(performedBestMerge){
1386  showerClusters->at(bestToMergeShowerCluster).clusterProtoTracks[bestToMergeShowerClusterProtoTrack].merged=true;
1387  showerClusters->at(clusIndexStart).clusterProtoTracks[bestShowerClustersClusIndexStartProtoTrack].merged=true;
1388  if(bestToMergeRightLeft == 0){
1389  showerClusters->at(bestToMergeShowerCluster).clusterProtoTracks[bestToMergeShowerClusterProtoTrack].mergedLeft = true;
1390  showerClusters->at(clusIndexStart).clusterProtoTracks[bestShowerClustersClusIndexStartProtoTrack].mergedRight = true;
1391  }
1392  if(bestToMergeRightLeft == 1){
1393  showerClusters->at(bestToMergeShowerCluster).clusterProtoTracks[bestToMergeShowerClusterProtoTrack].mergedRight = true;
1394  showerClusters->at(clusIndexStart).clusterProtoTracks[bestShowerClustersClusIndexStartProtoTrack].mergedLeft = true;
1395  }
1396 
1397  showerClusters->at(clusIndexStart).addProtoTracks(showerClusters->at(bestToMergeShowerCluster).clusterProtoTracks);
1398  showerClusters->at(bestToMergeShowerCluster).clearProtoTracks();
1399  //std::cout << "Merged shower-shower" << std::endl;
1400 
1401  }
1402 
1403  return performedBestMerge;
1404 
1405 }
1406 
1407 
1408 
1409 //------------------------------------------------------------------------------
1411  art::Ptr<recob::Hit> hit1,
1412  double wire_dist,
1413  double tickToDist)
1414 {
1415  const double pHit0[2] = {
1416  (hit0->Channel())*wire_dist,
1417  hit0->PeakTime()*tickToDist
1418  };
1419  const double pHit1[2] = {
1420  (hit1->Channel())*wire_dist,
1421  hit1->PeakTime()*tickToDist
1422  };
1423 
1424  return ::norm( pHit0[0] - pHit1[0], pHit0[1] - pHit1[1]);
1425 
1426 }
1427 
1428 
1429 
1430 //------------------------------------------------------------------------------
1432  double p1MinLine1,
1433  double p0MaxLine1,
1434  double p1MaxLine1,
1435  double p0MinLine2,
1436  double p1MinLine2,
1437  double p0MaxLine2,
1438  double p1MaxLine2)
1439 {
1440  //distance between two segments in the plane:
1441  // one segment is (x11, y11) to (x12, y12) or (p0MinLine1, p1MinLine1) to (p0MaxLine1, p1MaxLine1)
1442  // the other is (x21, y21) to (x22, y22) or (p0MinLine2, p1MinLine2) to (p0MaxLine2, p1MaxLine2)
1443  double x11 = p0MinLine1;
1444  double y11 = p1MinLine1;
1445  double x12 = p0MaxLine1;
1446  double y12 = p1MaxLine1;
1447  double x21 = p0MinLine2;
1448  double y21 = p1MinLine2;
1449  double x22 = p0MaxLine2;
1450  double y22 = p1MaxLine2;
1451 
1452  if(HoughLineIntersect(x11, y11, x12, y12, x21, y21, x22, y22)) return 0;
1453  // try each of the 4 vertices w/the other segment
1454  std::vector<double> distances;
1455  distances.push_back(PointSegmentDistance(x11, y11, x21, y21, x22, y22));
1456  distances.push_back(PointSegmentDistance(x12, y12, x21, y21, x22, y22));
1457  distances.push_back(PointSegmentDistance(x21, y21, x11, y11, x12, y12));
1458  distances.push_back(PointSegmentDistance(x22, y22, x11, y11, x12, y12));
1459 
1460  double minDistance = 999999;
1461  for(unsigned int j = 0; j < distances.size(); j++){
1462  if (distances[j] < minDistance)
1463  minDistance = distances[j];
1464  }
1465 
1466  return minDistance;
1467 
1468 }
1469 
1470 
1471 
1472 //------------------------------------------------------------------------------
1474  double y11,
1475  double x12,
1476  double y12,
1477  double x21,
1478  double y21,
1479  double x22,
1480  double y22)
1481 {
1482  //whether two segments in the plane intersect:
1483  //one segment is (x11, y11) to (x12, y12)
1484  //the other is (x21, y21) to (x22, y22)
1485 
1486  double dx1 = x12 - x11; // x2-x1
1487  double dy1 = y12 - y11; // y2-y1
1488  double dx2 = x22 - x21; // x4-x3
1489  double dy2 = y22 - y21; // y4-y3
1490  //double delta = dx2*dy1 - dy2*dx1; // (x4-x3)(y2-y1) - (y4-y3)(x2-x1)
1491  double delta = dy2*dx1 - dx2*dy1; // (y4-y3)(x2-x1) - (x4-x3)(y2-y1)
1492  if (delta == 0) return false; // parallel segments
1493 
1494  double t = (dx2*(y11 - y21) + dy2*(x21 - x11)) / delta; // ua
1495  double s = (dx1*(y11 - y21) + dy1*(x21 - x11)) / delta; // ub
1496 
1497  return (0 <= s && s <= 1 && 0 <= t && t <= 1);
1498 
1499 }
1500 
1501 
1502 
1503 //------------------------------------------------------------------------------
1505  double py,
1506  double x1,
1507  double y1,
1508  double x2,
1509  double y2)
1510 {
1511  double dx = x2 - x1;
1512  double dy = y2 - y1;
1513  if ( dx == 0 && dy == 0 ) // the segment's just a point
1514  return ::norm( px - x1, py - y1 );
1515 
1516  // Calculate the t that minimizes the distance.
1517  double t = ((px - x1)*dx + (py - y1)*dy) / ::sumsq(dx, dy);
1518 
1519  // See if this represents one of the segment's
1520  // end points or a point in the middle.
1521  if(t < 0){
1522  dx = px - x1;
1523  dy = py - y1;
1524  }
1525  else if(t > 1) {
1526  dx = px - x2;
1527  dy = py - y2;
1528  }
1529  else if(0 <= t && t <= 1) {
1530  double near_x = x1 + t * dx;
1531  double near_y = y1 + t * dy;
1532  dx = px - near_x;
1533  dy = py - near_y;
1534  }
1535 
1536  return ::norm(dx, dy);
1537 
1538 }
1539 
1540 
1541 
std::vector< std::vector< double > > fsim3
bool mergeShowerClusters(unsigned int k, std::vector< showerCluster > *showerClusters, double xyScale, double wire_dist, double tickToDist)
Float_t s
Definition: plot.C:23
MaybeLogger_< ELseverityLevel::ELsev_info, true > LogVerbatim
const unsigned int kNO_CLUSTER
Definition: DBScanAlg.cxx:253
virtual unsigned int ReadOutWindowSize() const =0
std::vector< bool > fnoise
void run_fuzzy_cluster(const std::vector< art::Ptr< recob::Hit > > &allhits)
virtual void reconfigure(fhicl::ParameterSet const &pset)
double fFuzzyRemnantMergeCutoff
cut off on merging the fuzzy cluster remnants into the nearest shower or track
double fSigmaChargeAsymAngleCut
Cut on product of charge asymmetry and sin of angle between slopes of lines.
Float_t y1[n_points_granero]
Definition: compare.C:5
std::vector< bool > fvisited
bool HoughLineIntersect(double x11, double y11, double x12, double y12, double x21, double y21, double x22, double y22)
trackCluster(protoTrack protoTrackTemp)
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
Float_t x1[n_points_granero]
Definition: compare.C:5
Declaration of signal hit object.
Float_t y
Definition: compare.C:6
std::vector< std::vector< double > > fsim2
std::set< uint32_t > fBadChannels
set of bad channels in this detector
double fTrackClusterMergeCutoff
Max distance between Hough lines before two lines are merged (muon tracks),.
int fMaxVertexLines
Max number of line end points allowed in a Hough line merge region for a merge to happen...
virtual double SamplingRate() const =0
Returns the period of the TPC readout electronics clock.
double fNumberWireBoundaries
Number of boundaries in wires for the drift window to be divided up to make the Hough line finder eas...
std::vector< std::vector< double > > fsim
bool fDoFuzzyRemnantMerge
Tell the algorithm to merge fuzzy cluster remnants into showers or tracks (0-off, 1-on) ...
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
Cluster finding and building.
This stores information about a tracklike cluster.
void addProtoTracks(std::vector< protoTrack > tracksToAdd)
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.
double fShowerTrackClusterMergeAngle
Max angle between slopes before two lines are merged, for lines in shower line regions.
Float_t y2[n_points_geant4]
Definition: compare.C:26
unsigned int noise()
Definition: chem4.cc:265
std::vector< protoTrack > clusterProtoTracks
void InitFuzzy(std::vector< art::Ptr< recob::Hit > > &allhits, std::set< uint32_t > badChannels)
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
T sqr(T v)
size_t Transform(std::vector< art::Ptr< recob::Hit > > const &hits, std::vector< unsigned int > *fpointId_to_clusterId, unsigned int clusterId, unsigned int *nClusters, std::vector< protoTrack > *protoTracks)
const unsigned int kNOISE_CLUSTER
Definition: DBScanAlg.cxx:254
bool fDoTrackClusterMerge
Turn on cut on product of charge asymmetry and sin of angle between slopes of lines.
bool fDoShowerTrackClusterMerge
Turn on cut on product of charge asymmetry and sin of angle between slopes of lines.
bool fDoShowerClusterMerge
Turns on shower Hough line merging (0-off, 1-on)
Signal from induction planes.
Definition: geo_types.h:92
enum geo::_plane_sigtype SigType_t
Enumerate the possible plane projections.
parameter set interface
virtual double Temperature() const =0
T get(std::string const &key) const
Definition: ParameterSet.h:231
baseCluster(protoTrack protoTrackTemp)
std::vector< uint32_t > fBadWireSum
Float_t d
Definition: plot.C:237
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
This stores information about a cluster.
This stores information about a showerlike cluster.
double HoughLineDistance(double p0MinLine1, double p1MinLine1, double p0MaxLine1, double p1MaxLine1, double p0MinLine2, double p1MinLine2, double p0MaxLine2, double p1MaxLine2)
bool mergeTrackClusters(unsigned int k, std::vector< trackCluster > *trackClusters, double xyScale, double wire_dist, double tickToDist)
std::vector< std::vector< double > > fps
the collection of points we are working on
Definition of data types for geometry description.
bool fGenerateHoughLinesOnly
Show only the results of the Hough line finder, hits not in a line will not be clustered.
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
std::vector< unsigned int > fpointId_to_clusterId
mapping point_id -> clusterId
double fShowerClusterMergeAngle
Max angle between slopes before two lines are merged, for lines in shower line regions.
Float_t norm
std::vector< double > fWirePitch
the pitch of the wires in each plane
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
virtual double DriftVelocity(double efield=0., double temperature=0.) const =0
double fNumberTimeBoundaries
Number of boundaries in ticks for the drift window to be divided up to make the Hough line finder eas...
bool mergeShowerTrackClusters(showerCluster *showerClusterI, trackCluster *trackClusterJ, double xyScale, double wire_dist, double tickToDist)
double PointSegmentDistance(double px, double py, double x1, double y1, double x2, double y2)
void reconfigure(fhicl::ParameterSet const &p)
Definition: DBScanAlg.cxx:271
std::vector< std::vector< unsigned int > > fclusters
collection of something
MaybeLogger_< ELseverityLevel::ELsev_warning, false > LogWarning
#define LOG_DEBUG(id)
double fShowerTrackClusterMergeCutoff
Max distance between Hough lines before two lines are merged (electron showers),. ...
virtual double Efield(unsigned int planegap=0) const =0
Returns the nominal electric field in the specified volume.
double fShowerLikenessCut
Cut on shower likeness (larger the more shower like, smaller the less shower like) ...
double fVertexLinesCutoff
Size of the vertex region to count up lines for fMaxVertexLines.
double fShowerClusterMergeCutoff
Max distance between Hough lines before two lines are merged (electron showers),. ...
fuzzyClusterAlg(fhicl::ParameterSet const &pset)
Float_t x2[n_points_geant4]
Definition: compare.C:26
void reconfigure(fhicl::ParameterSet const &p)
recob::tracking::Plane Plane
Definition: TrackState.h:17
raw::ChannelID_t Channel() const
ID of the readout channel the hit was extracted from.
Definition: Hit.h:231
double fChargeAsymAngleCut
Cut on product of charge asymmetry and sin of angle between slopes of lines.
double DistanceBetweenHits(art::Ptr< recob::Hit > hit0, art::Ptr< recob::Hit > hit1, double wire_dist, double tickToDist)
showerCluster(protoTrack protoTrackTemp)
int clusterNumber
Definition: HoughBaseAlg.h:210