LArSoft  v06_85_00
Liquid Argon Software toolkit - http://larsoft.org/
HoughBaseAlg.cxx
Go to the documentation of this file.
1 
19 // our header
21 
22 
23 // C/C++ standard library
24 #include <fstream>
25 #include <cmath> // std::sqrt()
26 #include <algorithm> // std::lower_bound(), std::min(), std::fill(), ...
27 #include <vector>
28 #include <stdint.h> // uint32_t
29 #include <limits> // std::numeric_limits<>
30 
31 // ROOT/CLHEP libraries
32 #include "CLHEP/Random/RandFlat.h"
33 #include <TStopwatch.h>
34 
35 // art libraries
36 #include "fhiclcpp/ParameterSet.h"
44 
45 
46 // larsoft libraries
47 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom<>()
60 #include "larevt/CalibrationDBI/Interface/ChannelStatusService.h"
61 #include "larevt/CalibrationDBI/Interface/ChannelStatusProvider.h"
62 
63 constexpr double PI = M_PI; // or CLHEP::pi in CLHEP/Units/PhysicalConstants.h
64 
65 #define a0 0 /*-4.172325e-7f*/ /*(-(float)0x7)/((float)0x1000000); */
66 #define a1 1.000025f /*((float)0x1922253)/((float)0x1000000)*2/Pi; */
67 #define a2 -2.652905e-4f /*(-(float)0x2ae6)/((float)0x1000000)*4/(Pi*Pi); */
68 #define a3 -0.165624f /*(-(float)0xa45511)/((float)0x1000000)*8/(Pi*Pi*Pi); */
69 #define a4 -1.964532e-3f /*(-(float)0x30fd3)/((float)0x1000000)*16/(Pi*Pi*Pi*Pi); */
70 #define a5 1.02575e-2f /*((float)0x191cac)/((float)0x1000000)*32/(Pi*Pi*Pi*Pi*Pi); */
71 #define a6 -9.580378e-4f /*(-(float)0x3af27)/((float)0x1000000)*64/(Pi*Pi*Pi*Pi*Pi*Pi); */
72 
73 #define _sin(x) ((((((a6*(x) + a5)*(x) + a4)*(x) + a3)*(x) + a2)*(x) + a1)*(x) + a0)
74 #define _cos(x) _sin(TMath::Pi()*0.5 - (x))
75 
76 template <typename T>
77 inline T sqr(T v) { return v * v; }
78 
79 
80 //------------------------------------------------------------------------------
81 template <typename K, typename C, size_t S, typename A, unsigned int SC>
83  (Key_t key_begin, Key_t key_end)
84 {
85  unchecked_add_range_max
86  (key_begin, key_end, +1, std::numeric_limits<SubCounter_t>::max());
87 } // cluster::HoughTransformCounters<>::increment(begin, end)
88 
89 
90 template <typename K, typename C, size_t S, typename A, unsigned int SC>
92  (Key_t key_begin, Key_t key_end)
93 {
94  unchecked_add_range_max
95  (key_begin, key_end, -1, std::numeric_limits<SubCounter_t>::max());
96 } // cluster::HoughTransformCounters<>::decrement(begin, end)
97 
98 
99 template <typename K, typename C, size_t S, typename A, unsigned int SC>
102  (SubCounter_t current_max) const
103 {
105  { Base_t::make_const_iterator(Base_t::counter_map.end(), 0), current_max };
106 
107  typename BaseMap_t::const_iterator iCBlock = Base_t::counter_map.begin(),
108  cend = Base_t::counter_map.end();
109  while (iCBlock != cend) {
110  const CounterBlock_t& block = iCBlock->second;
111  for (size_t index = 0; index < block.size(); ++index) {
112  if (block[index] > max.second)
113  max = { Base_t::make_const_iterator(iCBlock, index), block[index] };
114  ++iCBlock;
115  } // for elements in this block
116  } // while blocks
117  return max;
118 } // cluster::HoughTransformCounters<>::get_max(SubCounter_t)
119 
120 
121 template <typename K, typename C, size_t S, typename A, unsigned int SC>
124  { return get_max(std::numeric_limits<SubCounter_t>::max()); }
125 
126 
127 template <typename K, typename C, size_t S, typename A, unsigned int SC>
130  Key_t key_begin, Key_t key_end, SubCounter_t value,
131  typename BaseMap_t::iterator iIP
132 ) {
133  if (key_begin > key_end) return value;
134  CounterKey_t key(key_begin);
135  size_t left = key_end - key_begin;
136  while (true) {
137  if ((iIP == Base_t::counter_map.end()) || (iIP->first != key.block)) {
138  // we don't have that block yet
139  iIP = Base_t::counter_map.insert(iIP, { key.block, {}});
140  } // if need to add a block
141  CounterBlock_t& block = iIP->second;
142  size_t n = std::min(left, Base_t::NCounters - key.counter);
143  block.fill(key.counter, n, value);
144  if (left -= n <= 0) break;
145  key.next_block();
146  ++iIP;
147  } // while
148  return value;
149 } // cluster::HoughTransformCounters<>::unchecked_set_range()
150 
151 
152 template <typename K, typename C, size_t S, typename A, unsigned int SC>
155  (Key_t key_begin, Key_t key_end, SubCounter_t value)
156 {
157  return unchecked_set_range(key_begin, key_end, value,
158  Base_t::counter_map.lower_bound(CounterKey_t(key_begin).block));
159 } // cluster::HoughTransformCounters<>::unchecked_set_range(no hint)
160 
161 
162 template <typename K, typename C, size_t S, typename A, unsigned int SC>
165  Key_t key_begin, Key_t key_end, SubCounter_t delta,
166  typename BaseMap_t::iterator iIP,
167  SubCounter_t min_max /* = std::numeric_limits<SubCounter_t>::min() */
168 ) {
170  { Base_t::make_const_iterator(Base_t::counter_map.end(), 0), min_max };
171  if (key_begin > key_end) return max;
172  CounterKey_t key(key_begin);
173  size_t left = key_end - key_begin;
174  while (true) {
175  if ((iIP == Base_t::counter_map.end()) || (iIP->first != key.block)) {
176  // we don't have that block yet
177  iIP = Base_t::counter_map.insert(iIP, { key.block, {}});
178  } // if need to add a block
179  CounterBlock_t& block = iIP->second;
180  size_t n = std::min(left, Base_t::NCounters - key.counter);
181  left -= n;
182  while (n--) {
183  SubCounter_t value = (block[key.counter] += delta);
184  if (value > max.second) {
185  max = { Base_t::make_const_iterator(iIP, key.counter), value };
186  }
187  ++(key.counter);
188  } // for key.counter
189  if (left <= 0) break;
190  key.next_block();
191  ++iIP;
192  } // while
193  return max;
194 } // cluster::HoughTransformCounters<>::unchecked_add_range_max()
195 
196 
197 template <typename K, typename C, size_t S, typename A, unsigned int SC>
200  Key_t key_begin, Key_t key_end, SubCounter_t delta,
201  SubCounter_t min_max /* = std::numeric_limits<SubCounter_t>::min() */
202 ) {
203  return unchecked_add_range_max(key_begin, key_end, delta,
204  Base_t::counter_map.lower_bound(CounterKey_t(key_begin).block), min_max);
205 } // cluster::HoughTransformCounters<>::unchecked_add_range_max(no hint)
206 
207 
208 
209 
210 //------------------------------------------------------------------------------
212 {
213  this->reconfigure(pset);
214 }
215 
216 //------------------------------------------------------------------------------
218 {
219 }
220 
221 //------------------------------------------------------------------------------
223 {
224  fMaxLines = pset.get< int >("MaxLines" );
225  fMinHits = pset.get< int >("MinHits" );
226  fSaveAccumulator = pset.get< int >("SaveAccumulator" );
227  fNumAngleCells = pset.get< int >("NumAngleCells" );
228  fMaxDistance = pset.get< float >("MaxDistance" );
229  fMaxSlope = pset.get< float >("MaxSlope" );
230  fRhoZeroOutRange = pset.get< int >("RhoZeroOutRange" );
231  fThetaZeroOutRange = pset.get< int >("ThetaZeroOutRange" );
232  fRhoResolutionFactor = pset.get< float >("RhoResolutionFactor" );
233  fPerCluster = pset.get< int >("HitsPerCluster" );
234  fMissedHits = pset.get< int >("MissedHits" );
235  fMissedHitsDistance = pset.get< float >("MissedHitsDistance" );
236  fMissedHitsToLineSize = pset.get< float >("MissedHitsToLineSize" );
237  return;
238 }
239 
240 //------------------------------------------------------------------------------
242 {
243  //m_accum=NULL;
244 }
245 
246 
247 //------------------------------------------------------------------------------
250  std::vector<unsigned int> *fpointId_to_clusterId,
251  unsigned int clusterId, // The id of the cluster we are examining
252  unsigned int *nClusters,
253  std::vector<protoTrack> *linesFound
254  )
255 {
256 
257  int nClustersTemp = *nClusters;
258 
259  geo::GeometryCore const* geom = lar::providerFrom<geo::Geometry>();
260  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
261  lariov::ChannelStatusProvider const* channelStatus
262  = lar::providerFrom<lariov::ChannelStatusService>();
263 
264  // uint32_t channel = hits[0]->Channel();
265  unsigned int wire = 0;
266  unsigned int wireMax = 0;
267  unsigned int cs=hits[0]->WireID().Cryostat;
268  unsigned int t=hits[0]->WireID().TPC;
269  geo::WireID const& wireid = hits[0]->WireID();
270 
271 
272  //mf::LogInfo("HoughBaseAlg") << "nClusters is: " << *nClusters;
273 
274 
275  geo::SigType_t sigt = geom->SignalType(wireid);
276  std::vector<int> skip;
277 
278  std::vector<double> wire_pitch(geom->Nplanes(t, cs), 0.);
279  for (size_t p = 0; p < wire_pitch.size(); ++p) {
280  wire_pitch[p] = geom->WirePitch(p);
281  }
282 
283  //factor to make x and y scale the same units
284  std::vector<double> xyScale(geom->Nplanes(t, cs), 0.);
285 
287  double driftVelFactor = 0.001*detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
288 
289  for(size_t p = 0; p < xyScale.size(); ++p)
290  xyScale[p] = driftVelFactor * detprop->SamplingRate()/wire_pitch[p];
291 
292  float tickToDist = driftVelFactor * detprop->SamplingRate();
293  //tickToDist *= 1.e-3 * detprop->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
294 
295 
296  //mf::LogInfo("HoughBaseAlg") << "xyScale: " << xyScale;
297  //mf::LogInfo("HoughBaseAlg") << "tickToDist: " << tickToDist;
298 
299  int x, y;
300  //unsigned int channel, plane, wire, tpc, cstat;
301  //there must be a better way to find which plane a cluster comes from
302  const int dx = geom->Cryostat(hits[0]->WireID().Cryostat).TPC(hits[0]->WireID().TPC).Plane(hits[0]->WireID().Plane).Nwires();//number of wires
303  // const int dy = detprop->ReadOutWindowSize(); // number of time samples.
304  const int dy = detprop->NumberTimeSamples();//number of time samples.
305  skip.clear();
306  skip.resize(hits.size());
307  std::vector<int> listofxmax;
308  std::vector<int> listofymax;
309  std::vector<int> hitsTemp; //indecies ofcandidate hits
310  std::vector<int> sequenceHolder; //wire numbers of hits in list
311  std::vector<int> channelHolder; //channels of hits in list
312  std::vector<int> currentHits; //working vector of hits
313  std::vector<int> lastHits; //best list of hits
314  std::vector<art::Ptr<recob::Hit> > clusterHits;
315  float indcolscaling = 0.; //a parameter to account for the different
320  if(sigt == geo::kInduction)
321  indcolscaling = 0.;
322  else
323  indcolscaling = 1.;
324  //indcolscaling = 0;
325  float centerofmassx = 0;
326  float centerofmassy = 0;
327  float denom = 0;
328  float intercept=0.;
329  float slope = 0.;
330  //this array keeps track of the hits that have already been associated with a line.
331  int xMax = 0;
332  int yMax = 0;
333  int yClearStart;
334  int yClearEnd;
335  int xClearStart;
336  int xClearEnd;
337  int maxCell = 0;
338  float rho;
339  float theta;
340  int accDx(0), accDy(0);
341  float pCornerMin[2];
342  float pCornerMax[2];
343  //float pCorner0[2];
344  //float pCorner1[2];
345  //bool newChannel = false;
346  //unsigned int lastChannel;
347 
348  unsigned int fMaxWire = 0;
349  int iMaxWire = 0;
350  unsigned int fMinWire = 99999999;
351  int iMinWire = -1;
352 
353 
354 
355 
370 
371  mf::LogInfo("HoughBaseAlg") << "dealing with " << hits.size() << " hits";
372 
373  HoughTransform c;
374 
379  //mf::LogInfo("HoughBaseAlg") << "Beginning PPHT";
380 
381  c.GetAccumSize(accDy, accDx);
382 
383  // Define the prototrack object
384  protoTrack protoTrackToLoad;
385 
386 
387  // The number of lines we've found
388  unsigned int nLinesFound = 0;
389  std::vector<unsigned int> accumPoints(hits.size(),0);
390  int nAccum = 0;
391 
393  int count = 0;
394  for(auto fpointId_to_clusterIdItr = fpointId_to_clusterId->begin(); fpointId_to_clusterIdItr != fpointId_to_clusterId->end();fpointId_to_clusterIdItr++)
395  if(*fpointId_to_clusterIdItr == clusterId)
396  count++;
397 
398  unsigned int randInd;
399 
402  CLHEP::HepRandomEngine & engine = rng -> getEngine();
403  CLHEP::RandFlat flat(engine);
404  TStopwatch w;
405  //float timeTotal = 0;
406 
407  for( ; count > 0; ){
408 
411  randInd = (unsigned int)(flat.fire()*hits.size());
412 
413  //std::cout << count << " " << randInd << std::endl;
414 
416  if(fpointId_to_clusterId->at(randInd) != clusterId)
417  continue;
418 
419  --count;
420 
422  if(skip[randInd]==1){
423  continue;
424  }
425 
427  if(accumPoints[randInd])
428  continue;
429  accumPoints[randInd]=1;
430 
432  for(auto listofxmaxItr = listofxmax.begin(); listofxmaxItr != listofxmax.end(); ++listofxmaxItr) {
433  yClearStart = listofymax[listofxmaxItr-listofxmax.begin()] - fRhoZeroOutRange;
434  if (yClearStart < 0) yClearStart = 0;
435 
436  yClearEnd = listofymax[listofxmaxItr-listofxmax.begin()] + fRhoZeroOutRange;
437  if (yClearEnd >= accDy) yClearEnd = accDy - 1;
438 
439  xClearStart = *listofxmaxItr - fThetaZeroOutRange;
440  if (xClearStart < 0) xClearStart = 0;
441 
442  xClearEnd = *listofxmaxItr + fThetaZeroOutRange;
443  if (xClearEnd >= accDx) xClearEnd = accDx - 1;
444 
445  for (y = yClearStart; y <= yClearEnd; ++y){
446  for (x = xClearStart; x <= xClearEnd; ++x){
447  c.SetCell(y,x,0);
448  }
449  }
450  }
451 
453  uint32_t channel = hits[randInd]->Channel();
454  wireMax = hits[randInd]->WireID().Wire;
455 
457  //w.Start();
458  std::array<int, 3> max = c.AddPointReturnMax(wireMax, (int)(hits[randInd]->PeakTime()));
459  maxCell = max[0];
460  xMax = max[1];
461  yMax = max[2];
462  //w.Stop();
463  //std::cout << "Real Time: " << w.RealTime() << std::endl;
464  //timeTotal += w.CpuTime();
465  ++nAccum;
466 
467  //mf::LogVerbatim("HoughBaseAlg") << "cout: " << count << " maxCell: " << maxCell << std::endl;
468  //mf::LogVerbatim("HoughBaseAlg") << "xMax: " << xMax << " yMax: " << yMax << std::endl;
469 
472  //TF1 *threshGaus = new TF1("threshGaus","(1/([0]*std::sqrt(2*TMath::Pi())))*exp(-0.5*pow(((x-[1])/[0]),2))");
473  //double sigma = std::sqrt(((double)nAccum/(double)accDx)*(1-1/(double)accDx));
474  //double mean = (double)nAccum/(double)accDx;
475  //threshGaus->SetParameter(0,sigma);
476  //threshGaus->SetParameter(1,mean);
477  //mf::LogVerbatim("HoughBaseAlg") << "threshGaus mean: " << mean << " sigma: " << sigma << " accDx: " << accDx << std::endl;
478  //mf::LogVerbatim("HoughBaseAlg") << "nAccum: " << nAccum << std::endl;
479  //mf::LogVerbatim("HoughBaseAlg") << "threshGaus integral range: " << mean-2*sigma << " to " << maxCell << std::endl;
480  //mf::LogVerbatim("HoughBaseAlg") << "threshGaus integral: " << threshGaus->Integral(mean-2*sigma,maxCell) << std::endl;
481  //mf::LogVerbatim("HoughBaseAlg") << "threshGaus integral: " << threshGaus->Integral(0,maxCell) << std::endl;
482 
483 
485  //double poisProbSum = 0;
486  //for(int j = 0; j <= maxCell; j++){
487  //double poisProb = TMath::Poisson(j,mean);
488  //poisProbSum+=poisProb;
489  //mf::LogVerbatim("HoughBaseAlg") << "Poisson: " << poisProb << std::endl;
490  //}
491  //mf::LogVerbatim("HoughBaseAlg") << "Poisson prob sum: " << poisProbSum << std::endl;
492  //mf::LogVerbatim("HoughBaseAlg") << "Probability it is higher: " << 1-poisProbSum << std::endl;
493 
494  // Continue if the probability of finding a point, (1-poisProbSum) is the probability of finding a
495  // value of maxCell higher than what it currently is
496  //if( (1-poisProbSum) > 1e-13)
497  //continue;
498 
499 
500  // The threshold calculation using a Binomial distribution instead
501  double binomProbSum = TMath::BinomialI(1/(double)accDx,nAccum,maxCell);
502  //std::cout << "nAccum: " << nAccum << std::endl;
503  //std::cout << "maxCell: " << maxCell << std::endl;
504  //std::cout << "BinomialI: " << binomProbSum << std::endl;
505  //std::cout << std::endl;
506  //mf::LogVerbatim("HoughBaseAlg") << "Probability it is higher: " << 1-binomProbSum << std::endl;
507  //Continue if the probability of finding a point, (1-poisProbSum) is the probability of finding a
508  //value of maxCell higher than what it currently is
509  if( binomProbSum > 1e-21)
510  continue;
511 
512 
513 
515  //if (maxCell < fMinHits)
516  //continue;
517 
518 
520  denom = centerofmassx = centerofmassy = 0;
521 
522  if(xMax > 0 && yMax > 0 && xMax + 1 < accDx && yMax + 1 < accDy){
523  for(int i = -1; i < 2; ++i){
524  for(int j = -1; j < 2; ++j){
525  denom += c.GetCell(yMax+i,xMax+j);
526  centerofmassx += j*c.GetCell(yMax+i,xMax+j);
527  centerofmassy += i*c.GetCell(yMax+i,xMax+j);
528  }
529  }
530  centerofmassx /= denom;
531  centerofmassy /= denom;
532  }
533  else centerofmassx = centerofmassy = 0;
534 
536  listofxmax.push_back(xMax);
537  listofymax.push_back(yMax);
538 
539  // Find the lines equation
540  c.GetEquation(yMax+centerofmassy, xMax+centerofmassx, rho, theta);
541  LOG_DEBUG("HoughBaseAlg")
542  << "Transform(II) found maximum at (d=" << rho << " a=" << theta << ")"
543  " from absolute maximum " << c.GetCell(yMax,xMax)
544  << " at (d=" << yMax << ", a=" << xMax << ")";
545  slope = -1./tan(theta);
546  intercept = (rho/sin(theta));
547  float distance;
548 
549  if(!std::isinf(slope) && !std::isnan(slope)){
550  channelHolder.clear();
551  sequenceHolder.clear();
552  fMaxWire = 0;
553  iMaxWire = 0;
554  fMinWire = 99999999;
555  iMinWire = -1;
556  hitsTemp.clear();
557  for(auto hitsItr = hits.cbegin(); hitsItr != hits.cend(); ++hitsItr){
558  wire = (*hitsItr)->WireID().Wire;
559  if(fpointId_to_clusterId->at(hitsItr - hits.begin()) != clusterId)
560  continue;
561  channel = (*hitsItr)->Channel();
562  distance = (std::abs((*hitsItr)->PeakTime()-slope*(float)((*hitsItr)->WireID().Wire)-intercept)/(std::sqrt(sqr(xyScale[(*hitsItr)->WireID().Plane]*slope)+1.)));
563  if(distance < fMaxDistance+(*hitsItr)->RMS()+indcolscaling && skip[hitsItr-hits.begin()]!=1){
564  hitsTemp.push_back(hitsItr-hits.begin());
565  sequenceHolder.push_back(wire);
566  channelHolder.push_back(channel);
567  }
568  }
569 
570  if(hitsTemp.size() < 5) continue;
571  currentHits.clear();
572  lastHits.clear();
573  int j;
574  currentHits.push_back(0);
575  for(auto sequenceHolderItr = sequenceHolder.begin(); sequenceHolderItr+1 != sequenceHolder.end(); ++sequenceHolderItr) {
576  j = 1;
577  while(channelStatus->IsBad(sequenceHolderItr-sequenceHolder.begin()+j)) j++;
578  if(sequenceHolder[sequenceHolderItr-sequenceHolder.begin()+1]-sequenceHolder[sequenceHolderItr-sequenceHolder.begin()] <= j + fMissedHits) currentHits.push_back(sequenceHolderItr-sequenceHolder.begin()+1);
579  else if(currentHits.size() > lastHits.size()) {
580  lastHits = currentHits;
581  currentHits.clear();
582  }
583  else currentHits.clear();
584  }
585  if(currentHits.size() > lastHits.size()) lastHits = currentHits;
586 
587  clusterHits.clear();
588 
589  //if(lastHits.size() < 5) continue;
590  if(lastHits.size() < (unsigned int)fMinHits) continue;
591 
592 
593 
594 
595 
596 
597 
605  //int missedHits=0;
606  //int lastHitsChannel = 0;
607  //fMaxWire = 0;
608  //iMaxWire = 0;
609  //fMinWire = 99999999;
610  //iMinWire = -1;
611  //newChannel = false;
612  //lastChannel = hits[hitsTemp[lastHits[0]]]->Channel();
613  //for(auto lastHitsItr = lastHits.begin(); lastHitsItr != lastHits.end()-1; ++lastHitsItr) {
614 
615  //newChannel = false;
616  //if(slope < 0){
617  //if(hits[hitsTemp[*lastHitsItr+1]]->Channel() != lastChannel){
618  //newChannel = true;
619  //}
620  //}
621  //if(slope > 0 || !newChannel){
622 
624  //pCorner0[0] = (hits[hitsTemp[*lastHitsItr]]->Channel())*wire_dist;
625  //pCorner0[1] = hits[hitsTemp[*lastHitsItr]]->PeakTime()*tickToDist;
626  //pCorner1[0] = (hits[hitsTemp[*lastHitsItr+1]]->Channel())*wire_dist;
627  //pCorner1[1] = hits[hitsTemp[*lastHitsItr+1]]->PeakTime()*tickToDist;
630  //if((pCorner0[0]-pCorner1[0])*(pCorner0[0]-pCorner1[0]) + (pCorner0[1]-pCorner1[1])*(pCorner0[1]-pCorner1[1]) > fMissedHitsDistance*fMissedHitsDistance)
631  //missedHits++;
633  //} else if (slope < 0 && newChannel){
636  //pCorner0[0] = (hits[hitsTemp[lastHits[lastHitsChannel]]]->Channel())*wire_dist;
637  //pCorner0[1] = hits[hitsTemp[lastHits[lastHitsChannel]]]->PeakTime()*tickToDist;
638  //pCorner1[0] = (hits[hitsTemp[*lastHitsItr+1]]->Channel())*wire_dist;
639  //pCorner1[1] = hits[hitsTemp[*lastHitsItr+1]]->PeakTime()*tickToDist;
642  //if((pCorner0[0]-pCorner1[0])*(pCorner0[0]-pCorner1[0]) + (pCorner0[1]-pCorner1[1])*(pCorner0[1]-pCorner1[1]) > fMissedHitsDistance*fMissedHitsDistance)
643  //missedHits++;
644  //lastChannel=hits[hitsTemp[*lastHitsItr+1]]->Channel();
645  //lastHitsChannel=lastHitsItr-lastHits.begin()+1;
646  //}
647  //}
651  //if((float)missedHits/((float)lastHits.size()-1) > fMissedHitsToLineSize)
652  //continue;
653 
654 
655 
656 
657 
658 
659 
660  if(std::abs(slope)>fMaxSlope ){
661  continue;
662  }
663 
664  //std::cout << std::endl;
665  //std::cout << "Found line!" << std::endl
666  //<< "Slope: " << slope << std::endl
667  //<< "Intercept: " << intercept << std::endl
668  //<< "Number of hits: " << lastHits.size() << std::endl
669  //<< "Wire: " << fMinWire << " Peak time: "
670  //<< hits[iMinWire]->PeakTime() << std::endl
671  //<< "Wire: " << fMaxWire << " Peak time: "
672  //<< hits[iMaxWire]->PeakTime() << std::endl;
673 
674 
675  // Add new line to list of lines
676  float totalQ = 0;
677  std::vector< art::Ptr<recob::Hit> > lineHits;
678  nClustersTemp++;
680  for(auto lastHitsItr = lastHits.begin(); lastHitsItr != lastHits.end(); ++lastHitsItr) {
681  fpointId_to_clusterId->at(hitsTemp[(*lastHitsItr)]) = nClustersTemp-1;
682  //clusterHits.push_back(hits[hitsTemp[(*lastHitsItr)]]);
683  //totalQ += clusterHits.back()->Integral();
684  totalQ += hits[hitsTemp[(*lastHitsItr)]]->Integral();
685  wire = hits[hitsTemp[(*lastHitsItr)]]->WireID().Wire;
686 
687  if(!accumPoints[hitsTemp[(*lastHitsItr)]])
688  count--;
689 
690  skip[hitsTemp[(*lastHitsItr)]]=1;
691 
692  lineHits.push_back(hits[hitsTemp[(*lastHitsItr)]]);
693 
694 
696  if(accumPoints[hitsTemp[(*lastHitsItr)]])
697  c.SubtractPoint(wire, (int)(hits[hitsTemp[(*lastHitsItr)]]->PeakTime()));
698 
699  if(wire < fMinWire){
700  fMinWire = wire;
701  iMinWire = hitsTemp[(*lastHitsItr)];
702  }
703  if(wire > fMaxWire){
704  fMaxWire = wire;
705  iMaxWire = hitsTemp[(*lastHitsItr)];
706  }
707  }
708  int pnum = hits[iMinWire]->WireID().Plane;
709  pCornerMin[0] = (hits[iMinWire]->WireID().Wire)*wire_pitch[pnum];
710  pCornerMin[1] = hits[iMinWire]->PeakTime()*tickToDist;
711  pCornerMax[0] = (hits[iMaxWire]->WireID().Wire)*wire_pitch[pnum];
712  pCornerMax[1] = hits[iMaxWire]->PeakTime()*tickToDist;
713 
717  protoTrackToLoad.Init(nClustersTemp-1,
718  pnum,
719  slope,
720  intercept,
721  totalQ,
722  pCornerMin[0],
723  pCornerMin[1],
724  pCornerMax[0],
725  pCornerMax[1],
726  iMinWire,
727  iMaxWire,
728  fMinWire,
729  fMaxWire,
730  lineHits);
731  linesFound->push_back(protoTrackToLoad);
732 
733  }
734 
735 
736  nLinesFound++;
737 
738  if(nLinesFound>(unsigned int)fMaxLines)
739  break;
740 
741  }
742 
743  //std::cout << "Average cpu time: " << timeTotal/nAccum << std::endl;
744  //std::cout << "Total cpu time: " << timeTotal << std::endl;
745 
746 
747 
748 
749 
750  lastHits.clear();
751 
752  listofxmax.clear();
753  listofymax.clear();
754 
755  // saves a bitmap image of the accumulator (useful for debugging),
756  // with scaling based on the maximum cell value
757  if(fSaveAccumulator){
758  unsigned char *outPix = new unsigned char [accDx*accDy];
759  //finds the maximum cell in the accumulator for image scaling
760  int cell, pix = 0, maxCell = 0;
761  for (int y = 0; y < accDy; ++y){
762  for (int x = 0; x < accDx; ++x){
763  cell = c.GetCell(y,x);
764  if (cell > maxCell) maxCell = cell;
765  }
766  }
767  for (int y = 0; y < accDy; ++y){
768  for (int x = 0; x < accDx; ++x){
769  //scales the pixel weights based on the maximum cell value
770  if(maxCell > 0)
771  pix = (int)((1500*c.GetCell(y,x))/maxCell);
772  outPix[y*accDx + x] = pix;
773  }
774  }
775 
776  HLSSaveBMPFile("houghaccum.bmp", outPix, accDx, accDy);
777  delete [] outPix;
778  }// end if saving accumulator
779 
780  *nClusters=nClustersTemp;
781 
782  return 1;
783 }
784 
785 
786 //------------------------------------------------------------------------------
788 {
789 }
790 
791 
792 //------------------------------------------------------------------------------
793 inline int cluster::HoughTransform::GetCell(int row, int col) const {
794  return m_accum[row][col];
795 } // cluster::HoughTransform::GetCell()
796 
797 
798 //------------------------------------------------------------------------------
799 // returns a vector<int> where the first is the overall maximum,
800 // the second is the max x value, and the third is the max y value.
801 inline std::array<int, 3> cluster::HoughTransform::AddPointReturnMax(int x, int y)
802 {
803  if ((x > (int) m_dx) || (y > (int) m_dy) || x<0.0 || y<0.0) {
804  std::array<int, 3> max;
805  max.fill(0);
806  return max;
807  }
808  return DoAddPointReturnMax(x, y, false); // false = add
809 }
810 
811 
812 
813 //------------------------------------------------------------------------------
815 {
816  if ((x > (int) m_dx) || (y > (int) m_dy) || x<0.0 || y<0.0)
817  return false;
818  DoAddPointReturnMax(x, y, true); // true = subtract
819  return true;
820 }
821 
822 
823 //------------------------------------------------------------------------------
824 void cluster::HoughTransform::Init(unsigned int dx,
825  unsigned int dy,
826  float rhores,
827  unsigned int numACells)
828 {
829  m_numAngleCells=numACells;
830  m_rhoResolutionFactor = rhores;
831 
832  m_accum.clear();
833  //--- BEGIN issue #19494 -----------------------------------------------------
834  // BulkAllocator.h is currently broken; see issue #19494 and comment in header.
835 #if 0
836  // set the custom allocator for nodes to allocate large chunks of nodes;
837  // one node is 40 bytes plus the size of the counters block.
838  // The math over there sets a bit less than 10 MiB per chunk.
839  // to find out the right type name to put here, comment out this line
840  // (it will suppress some noise), set bDebug to true in
841  // lardata/Utilities/BulkAllocator.h and run this module;
842  // all BulkAllocator instances will advertise that they are being created,
843  // mentioning their referring type. You can also simplyfy it by using the
844  // available typedefs, like here:
846  std::_Rb_tree_node
847  <std::pair<const DistancesMap_t::Key_t, DistancesMap_t::CounterBlock_t>>
848  >::SetChunkSize(
849  10 * ((1048576 / (40 + sizeof(DistancesMap_t::CounterBlock_t))) & ~0x1FFU)
850  );
851 #endif // 0
852  //--- END issue #19494 -------------------------------------------------------
853 
854  //m_accum.resize(m_numAngleCells);
855  m_numAccumulated = 0;
856  // m_cosTable.clear();
857  // m_sinTable.clear();
858  //m_cosTable.resize(m_numAngleCells);
859  //m_sinTable.resize(m_numAngleCells);
860  //if (dx == m_dx && dy == m_dy)
861  //return;
862  m_dx = dx;
863  m_dy = dy;
864  m_rowLength = (unsigned int)(m_rhoResolutionFactor*2 * std::sqrt(dx*dx + dy*dy));
865  m_accum.resize(m_numAngleCells);
866  //for(int i = 0; i < m_numAngleCells; i++)
867  //m_accum[i].resize((unsigned int)(m_rowLength));
868 
869  // this math must be coherent with the one in GetEquation()
870  double angleStep = PI/m_numAngleCells;
871  m_cosTable.resize(m_numAngleCells);
872  m_sinTable.resize(m_numAngleCells);
873  for (size_t iAngleStep = 0; iAngleStep < m_numAngleCells; ++iAngleStep) {
874  double a = iAngleStep * angleStep;
875  m_cosTable[iAngleStep] = cos(a);
876  m_sinTable[iAngleStep] = sin(a);
877  }
878 }
879 
880 
881 //------------------------------------------------------------------------------
883  (float row, float col, float &rho, float &theta) const
884 {
885  theta = (TMath::Pi()*row)/m_numAngleCells;
886  rho = (col - (m_rowLength/2.))/m_rhoResolutionFactor;
887 } // cluster::HoughTransform::GetEquation()
888 
889 //------------------------------------------------------------------------------
890 int cluster::HoughTransform::GetMax(int &xmax, int &ymax) const
891 {
892  int maxVal = -1;
893  for(unsigned int i = 0; i < m_accum.size(); i++){
894 
895  DistancesMap_t::PairValue_t max_counter = m_accum[i].get_max(maxVal);
896  if (max_counter.second > maxVal) {
897  maxVal = max_counter.second;
898  xmax = i;
899  ymax = max_counter.first.key();
900  }
901  } // for angle
902 
903  return maxVal;
904 }
905 
906 //------------------------------------------------------------------------------
907 // returns a vector<int> where the first is the overall maximum,
908 // the second is the max x value, and the third is the max y value.
910  (int x, int y, bool bSubtract /* = false */)
911 {
912  std::array<int, 3> max;
913  max.fill(-1);
914 
915  // max_val is the current maximum number of hits aligned on a line so far;
916  // currently the code ignores all the lines with just two aligned hits
917  int max_val = 2;
918  //int max_val = minHits-1;
919 
920  const int distCenter = (int)(m_rowLength/2.);
921 
922  // prime the lastDist variable so our linear fill works below
923  // lastDist represents next distance to be incremented (but see below)
924  int lastDist = (int)(distCenter + (m_rhoResolutionFactor*x));
925 
926 
927  // loop through all angles a from 0 to 180 degrees
928  // (the value of the angle is established in definition of m_cosTable and
929  // m_sinTable in HoughTransform::Init()
930  for (size_t iAngleStep = 1; iAngleStep < m_numAngleCells; ++iAngleStep) {
931 
932  // Calculate the basic line equation dist = cos(a)*x + sin(a)*y.
933  // Shift to center of row to cover negative values;
934  // this math must also be coherent with the one in GetEquation()
935  const int dist = (int) (distCenter + m_rhoResolutionFactor
936  * (m_cosTable[iAngleStep]*x + m_sinTable[iAngleStep]*y)
937  );
938 
939  /*
940  * For this angle, we are going to increment all the cells starting from the
941  * last distance in the previous loop, up to the current one (dist),
942  * with the exception that if we are incrementing more than one cell,
943  * we do not increment dist cell itself (it will be incremented in the
944  * next angle).
945  * The cell of the last distance is always incremented,
946  * whether it was also for the previous angle (in case there was only one
947  * distance to be incremented) or not (if there was a sequence of distances
948  * to increment, and then the last distance was not).
949  * First we increment the last cell of our range; this provides us with a
950  * hint of where the immediate previous cell should be, which saves us a
951  * look up.
952  * We collect and return information about the local maximum among the cells
953  * we are increasing.
954  */
955 
956  // establish the range of cells to increase: [ first_dist, end_dist [ ;
957  // also set lastDist so that it points to the next cell to be incremented,
958  // according to the rules described above
959  int first_dist;
960  int end_dist;
961  if(lastDist == dist) {
962  // the range is [ dist, dist + 1 [ (that is, [ dist ]
963  first_dist = dist;
964  end_dist = dist + 1;
965  }
966  else {
967  // the range is [ lastDist, dist [ or ] dist, lastDist]
968  first_dist = dist > lastDist? lastDist: dist + 1;
969  end_dist = dist > lastDist? dist: lastDist + 1;
970  }
971 
972  // sanity check to make sure we stay within our row
973  // if (dist >= 0 && dist<m_rowLength){
974 
975  // DEBUG
976 // const float a = iAngleStep / m_numAngleCells * PI;
977 // std::cout << "AD " << iAngleStep << " " << dist
978 // << "\n" << a << " [ " << first_dist << " ; " << end_dist << " ["
979 // << std::endl;
980 
981  DistancesMap_t& distMap = m_accum[iAngleStep];
982  if (bSubtract) {
983  distMap.decrement(first_dist, end_dist);
984  }
985  else {
986  DistancesMap_t::PairValue_t max_counter
987  = distMap.increment_and_get_max(first_dist, end_dist, max_val);
988 
989  if (max_counter.second > max_val) {
990  // DEBUG
991  // std::cout << " <NEW MAX " << max_val << " => " << max_counter.second << " >" << std::endl;
992  // BUG the double brace syntax is required to work around clang bug 21629
993  // (https://bugs.llvm.org/show_bug.cgi?id=21629)
994  max = {{ max_counter.second, max_counter.first.key(), (int) iAngleStep }};
995  max_val = max_counter.second;
996  }
997  }
998  lastDist = dist;
999 
1000  // DEBUG
1001  // std::cout << "\n (max " << max[1] << " => " << max[0] << ")" << std::endl;
1002  // }
1003  } // for angles
1004  if (bSubtract) --m_numAccumulated;
1005  else ++m_numAccumulated;
1006 
1007  //mf::LogVerbatim("HoughBaseAlg") << "Add point says xmax: " << *xmax << " ymax: " << *ymax << std::endl;
1008 
1009  return max;
1010 } // cluster::HoughTransform::DoAddPointReturnMax()
1011 
1012 
1013 //------------------------------------------------------------------------------
1014 //this method saves a BMP image of the Hough Accumulator, which can be viewed with gimp
1015 void cluster::HoughBaseAlg::HLSSaveBMPFile(const char *fileName, unsigned char *pix, int dx, int dy)
1016 {
1017  std::ofstream bmpFile(fileName, std::ios::binary);
1018  bmpFile.write("B", 1);
1019  bmpFile.write("M", 1);
1020  int bitsOffset = 54 +256*4;
1021  int size = bitsOffset + dx*dy; //header plus 256 entry LUT plus pixels
1022  bmpFile.write((const char *)&size, 4);
1023  int reserved = 0;
1024  bmpFile.write((const char *)&reserved, 4);
1025  bmpFile.write((const char *)&bitsOffset, 4);
1026  int bmiSize = 40;
1027  bmpFile.write((const char *)&bmiSize, 4);
1028  bmpFile.write((const char *)&dx, 4);
1029  bmpFile.write((const char *)&dy, 4);
1030  short planes = 1;
1031  bmpFile.write((const char *)&planes, 2);
1032  short bitCount = 8;
1033  bmpFile.write((const char *)&bitCount, 2);
1034  int i, temp = 0;
1035  for (i=0; i<6; i++)
1036  bmpFile.write((const char *)&temp, 4); // zero out optional color info
1037  // write a linear LUT
1038  char lutEntry[4]; // blue,green,red
1039  lutEntry[3] = 0; // reserved part
1040  for (i=0; i<256; i++)
1041  {
1042  lutEntry[0] = lutEntry[1] = lutEntry[2] = i;
1043  bmpFile.write(lutEntry, sizeof lutEntry);
1044  }
1045  // write the actual pixels
1046  bmpFile.write((const char *)pix, dx*dy);
1047 }
1048 
1049 
1050 //------------------------------------------------------------------------------
1052  std::vector<recob::Cluster> & ccol,
1053  std::vector< art::PtrVector<recob::Hit> > & clusHitsOut,
1054  art::Event const& evt,
1055  std::string const& label)
1056 {
1057  std::vector<int> skip;
1058 
1059  art::FindManyP<recob::Hit> fmh(clusIn, evt, label);
1060 
1061  geo::GeometryCore const* geom = lar::providerFrom<geo::Geometry>();
1062  // const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
1063 // lariov::ChannelStatusProvider const* channelStatus
1064 // = lar::providerFrom<lariov::ChannelStatusService>();
1065  HoughTransform c;
1066 
1067  // Get the random number generator
1069  CLHEP::HepRandomEngine & engine = rng -> getEngine();
1070  CLHEP::RandFlat flat(engine);
1071 
1072  // prepare the algorithm to compute the cluster characteristics;
1073  // we use the "standard" one here; configuration would happen here,
1074  // but we are using the default configuration for that algorithm
1076 
1077  std::vector< art::Ptr<recob::Hit> > hit;
1078 
1079  for(auto view : geom->Views() ){
1080 
1081  LOG_DEBUG("HoughBaseAlg") << "Analyzing view " << view;
1082 
1083  art::PtrVector<recob::Cluster>::const_iterator clusterIter = clusIn.begin();
1084  int clusterID = 0;//the unique ID of the cluster
1085 
1086  size_t cinctr = 0;
1087  while(clusterIter != clusIn.end()) {
1088 
1089  LOG_DEBUG("HoughBaseAlg") << "Analyzing cinctr=" << cinctr << " which is in view " << (*clusterIter)->View();
1090 
1091  hit.clear();
1092  if(fPerCluster){
1093  if((*clusterIter)->View() == view) hit = fmh.at(cinctr);
1094  }
1095  else{
1096  while(clusterIter != clusIn.end()){
1097  if( (*clusterIter)->View() == view ){
1098 
1099  hit = fmh.at(cinctr);
1100  }// end if cluster is in correct view
1101  clusterIter++;
1102  ++cinctr;
1103  }//end loop over clusters
1104  }//end if not fPerCluster
1105  if(hit.size() == 0){
1106  if(fPerCluster){
1107  clusterIter++;
1108  ++cinctr;
1109  }
1110  continue;
1111  }
1112 
1113  LOG_DEBUG("HoughBaseAlg") << "We have all the hits..." << hit.size();
1114 
1115  /*
1116  //factor to make x and y scale the same units
1117  double xyScale = .001*detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
1118  xyScale *= detprop->SamplingRate()/geom->WirePitch(p,t,cs);
1119 
1120  int x, y;
1121  int dx = geom->Cryostat(cs).TPC(t).Plane(p).Nwires();//number of wires
1122  const int dy = detprop->ReadOutWindowSize(); // number of time samples.
1123  skip.clear();
1124  skip.resize(hit.size());
1125  std::vector<int> listofxmax;
1126  std::vector<int> listofymax;
1127  std::vector<int> hitTemp; //indecies ofcandidate hits
1128  std::vector<int> sequenceHolder; //channels of hits in list
1129  std::vector<int> currentHits; //working vector of hits
1130  std::vector<int> lastHits; //best list of hits
1131  art::PtrVector<recob::Hit> clusterHits;
1132  double indcolscaling = 0.; //a parameter to account for the different
1133  //characteristic hit width of induction and collection plane
1134  double centerofmassx = 0;
1135  double centerofmassy = 0;
1136  double denom = 0;
1137  double intercept=0.;
1138  double slope = 0.;
1139  //this array keeps track of the hits that have already been associated with a line.
1140  int xMax = 0;
1141  int yMax = 0;
1142  double rho;
1143  double theta;
1144  int accDx(0), accDy(0);
1145 
1146 
1147  //Init specifies the size of the two-dimensional accumulator
1148  //(based on the arguments, number of wires and number of time samples).
1149  //adds all of the hits (that have not yet been associated with a line) to the accumulator
1150  c.Init(dx,dy,fRhoResolutionFactor,fNumAngleCells);
1151 
1152 
1153  // count is how many points are left to randomly insert
1154  unsigned int count = hit.size();
1155  std::vector<unsigned int> accumPoints;
1156  accumPoints.resize(hit.size());
1157  int nAccum = 0;
1158  unsigned int nLinesFound = 0;
1159 
1160  for( ; count > 0; count--){
1161 
1162 
1163  // The random hit we are examining
1164  unsigned int randInd = (unsigned int)(flat.fire()*hit.size());
1165 
1166  // Skip if it's already in a line
1167  if(skip[randInd]==1)
1168  continue;
1169 
1170  // If we have already accumulated the point, skip it
1171  if(accumPoints[randInd])
1172  continue;
1173  accumPoints[randInd]=1;
1174 
1175  // zeroes out the neighborhood of all previous lines
1176  for(unsigned int i = 0; i < listofxmax.size(); ++i){
1177  int yClearStart = listofymax[i] - fRhoZeroOutRange;
1178  if (yClearStart < 0) yClearStart = 0;
1179 
1180  int yClearEnd = listofymax[i] + fRhoZeroOutRange;
1181  if (yClearEnd >= accDy) yClearEnd = accDy - 1;
1182 
1183  int xClearStart = listofxmax[i] - fThetaZeroOutRange;
1184  if (xClearStart < 0) xClearStart = 0;
1185 
1186  int xClearEnd = listofxmax[i] + fThetaZeroOutRange;
1187  if (xClearEnd >= accDx) xClearEnd = accDx - 1;
1188 
1189  for (y = yClearStart; y <= yClearEnd; ++y){
1190  for (x = xClearStart; x <= xClearEnd; ++x){
1191  c.SetCell(y,x,0);
1192  }
1193  }
1194  }// end loop over size of listxmax
1195 
1196  //find the weightiest cell in the accumulator.
1197  int maxCell = 0;
1198  unsigned int wireMax = hit[randInd]->WireID().Wire;
1199  xMax = 0;
1200  yMax = 0;
1201 
1202  // Add the randomly selected point to the accumulator
1203  maxCell = c.AddPointReturnMax(wireMax, (int)(hit[randInd]->PeakTime()), &yMax, &xMax, fMinHits);
1204  nAccum++;
1205 
1206  // Continue if the biggest maximum for the randomly selected point is smaller than fMinHits
1207  if (maxCell < fMinHits)
1208  continue;
1209 
1210  // Find the center of mass of the 3x3 cell system (with maxCell at the center).
1211  denom = centerofmassx = centerofmassy = 0;
1212 
1213  if(xMax > 0 && yMax > 0 && xMax + 1 < accDx && yMax + 1 < accDy){
1214  for(int i = -1; i < 2; ++i){
1215  for(int j = -1; j < 2; ++j){
1216  denom += c.GetCell(yMax+i,xMax+j);
1217  centerofmassx += j*c.GetCell(yMax+i,xMax+j);
1218  centerofmassy += i*c.GetCell(yMax+i,xMax+j);
1219  }
1220  }
1221  centerofmassx /= denom;
1222  centerofmassy /= denom;
1223  }
1224  else centerofmassx = centerofmassy = 0;
1225 
1226  //fill the list of cells that have already been found
1227  listofxmax.push_back(xMax);
1228  listofymax.push_back(yMax);
1229 
1230  // Find the lines equation
1231  c.GetEquation(yMax+centerofmassy, xMax+centerofmassx, rho, theta);
1232  //c.GetEquation(yMax, xMax, rho, theta);
1233  slope = -1./tan(theta);
1234  intercept = (rho/sin(theta));
1235  //mf::LogVerbatim("HoughBaseAlg") << std::endl;
1236  //mf::LogVerbatim("HoughBaseAlg") << "slope: " << slope << " intercept: " << intercept << std::endl;
1237  //mf::LogInfo("HoughBaseAlg") << "slope: " << slope << " intercept: " << intercept;
1238  double distance;
1242  if(sigt == geo::kInduction)
1243  indcolscaling = 5.;
1244  else
1245  indcolscaling = 0.;
1246  // What is this?
1247  indcolscaling = 0;
1248 
1249  if(!std::isinf(slope) && !std::isnan(slope)){
1250  sequenceHolder.clear();
1251  hitTemp.clear();
1252  for(size_t i = 0; i < hit.size(); ++i){
1253  distance = (TMath::Abs(hit[i]->PeakTime()-slope*(double)(hit[i]->WireID().Wire)-intercept)/(std::sqrt(pow(xyScale*slope,2)+1)));
1254 
1255  if(distance < fMaxDistance+hit[i]->RMS()+indcolscaling && skip[i]!=1){
1256  hitTemp.push_back(i);
1257  sequenceHolder.push_back(hit[i]->Channel());
1258  }
1259 
1260  }// end loop over hits
1261 
1262  if(hitTemp.size() < 2) continue;
1263  currentHits.clear();
1264  lastHits.clear();
1265  int j;
1266  currentHits.push_back(0);
1267  for(size_t i = 0; i + 1 < sequenceHolder.size(); ++i){
1268  j = 1;
1269  while((channelStatus->IsBad(sequenceHolder[i]+j)) == true) j++;
1270  if(sequenceHolder[i+1]-sequenceHolder[i] <= j + fMissedHits) currentHits.push_back(i+1);
1271  else if(currentHits.size() > lastHits.size()) {
1272  lastHits = currentHits;
1273  currentHits.clear();
1274  }
1275  else currentHits.clear();
1276  }
1277 
1278 
1279  if(currentHits.size() > lastHits.size()) lastHits = currentHits;
1280 
1281 
1282 
1283 
1284  // Check if lastHits has hits with big gaps in it
1285  uint32_t channel = hit[0]->Channel();
1286  double wirePitch = geom->WirePitch(geom->View(channel));
1287  double wire_dist = wirePitch;
1288  double tickToDist = detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
1289  tickToDist *= 1.e-3 * detprop->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
1290  //std::cout << "New line" << std::endl;
1291  int missedHits=0;
1292  for(size_t i = 0; i < lastHits.size()-1; ++i) {
1293  //std::cout << hit[hitTemp[lastHits[i]]]->Channel() << std::endl;
1294  double pCorner0[2];
1295  pCorner0[0] = (hit[hitTemp[lastHits[i]]]->Channel())*wire_dist;
1296  pCorner0[1] = hit[hitTemp[lastHits[i]]]->PeakTime()*tickToDist;
1297  double pCorner1[2];
1298  pCorner1[0] = (hit[hitTemp[lastHits[i+1]]]->Channel())*wire_dist;
1299  pCorner1[1] = hit[hitTemp[lastHits[i+1]]]->PeakTime()*tickToDist;
1300  //std::cout << std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) << std::endl;
1301  if(std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) > fMissedHitsDistance )
1302  missedHits++;
1303  }
1304  //std::cout << "missedHits " << missedHits << std::endl;
1305  //std::cout << "lastHits.size() " << lastHits.size() << std::endl;
1306  //std::cout << "missedHits/lastHits.size() " << (double)missedHits/(double)lastHits.size() << std::endl;
1307  if((double)missedHits/(double)lastHits.size() > fMissedHitsToLineSize)
1308  continue;
1309 
1310 
1311 
1312 
1313 
1314  clusterHits.clear();
1315  double totalQ = 0.;
1316  if(lastHits.size() < 5) continue;
1317 
1318 
1319  for(size_t i = 0; i < lastHits.size(); ++i) {
1320  clusterHits.push_back(hit[hitTemp[lastHits[i]]]);
1321  totalQ += clusterHits.back()->Integral();
1322  skip[hitTemp[lastHits[i]]]=1;
1323  }
1324  //protection against very steep uncorrelated hits
1325  if(std::abs(slope)>fMaxSlope
1326  && std::abs((*clusterHits.begin())->Channel()-
1327  clusterHits[clusterHits.size()-1]->Channel())>=0
1328  )
1329  continue;
1330 
1331 
1332 
1333  unsigned int sw = (*clusterHits.begin())->WireID().Wire;
1334  unsigned int ew = (*(clusterHits.end()-1))->WireID().Wire;
1335 
1336  recob::Cluster cluster(sw, 0.,
1337  (*clusterHits.begin())->PeakTime(), 0.,
1338  ew, 0.,
1339  (clusterHits[clusterHits.size()-1])->PeakTime(), 0.,
1340  slope, 0.,
1341  -999., 0.,
1342  totalQ,
1343  geom->View((*clusterHits.begin())->Channel()),
1344  clusterID);
1345 
1346  ++clusterID;
1347  ccol.push_back(cluster);
1348  clusHitsOut.push_back(clusterHits);
1349 
1350  //Turn off hit sharing. T. Yang 9/14/12
1351  // //allow double assignment of first and last hits
1352  // for(size_t i = 0; i < lastHits.size(); ++i){
1353  // if(skip[hitTemp[lastHits[i]]] ==1){
1354  // channel = hit[hitTemp[lastHits[i]]]->Channel();
1355  // if( channel == sc || channel == ec) skip[i] = 0;
1356  // }
1357  // }
1358 
1359  }// end if !std::isnan
1360 
1361  nLinesFound++;
1362 
1363  if(nLinesFound>(unsigned int)fMaxLines)
1364  break;
1365 
1366 
1367  }// end loop over hits*/
1368 
1369  std::vector<double> slopevec;
1370  std::vector<ChargeInfo_t> totalQvec;
1371  std::vector< art::PtrVector<recob::Hit> > planeClusHitsOut;
1372  this->FastTransform(hit,planeClusHitsOut,slopevec,totalQvec );
1373 
1374  LOG_DEBUG("HoughBaseAlg") << "Made it through FastTransform" << planeClusHitsOut.size();
1375 
1376  for(size_t xx = 0; xx < planeClusHitsOut.size(); ++xx){
1377  auto const& hits = planeClusHitsOut.at(xx);
1378  recob::Hit const& FirstHit = *hits.front();
1379  recob::Hit const& LastHit = *hits.back();
1380  const unsigned int sw = FirstHit.WireID().Wire;
1381  const unsigned int ew = LastHit.WireID().Wire;
1382 // ChargeInfo_t const& charge_info = totalQvec.at(xx); // delegating to algos
1383 
1384  // feed the algorithm with all the cluster hits
1385  ClusterParamAlgo.ImportHits(hits);
1386 
1387  // create the recob::Cluster directly in the vector;
1388  // NOTE usually we would use cluster::ClusterCreator to save some typing and
1389  // some mistakes. In this case, we don't want to pull in the dependency on
1390  // ClusterFinder, where ClusterCreator currently lives
1391  ccol.emplace_back(
1392  float(sw), // start_wire
1393  0., // sigma_start_wire
1394  FirstHit.PeakTime(), // start_tick
1395  FirstHit.SigmaPeakTime(), // sigma_start_tick
1396  ClusterParamAlgo.StartCharge().value(), // start_charge
1397  ClusterParamAlgo.StartAngle().value(), // start_angle
1398  ClusterParamAlgo.StartOpeningAngle().value(), // start_opening
1399  float(ew), // end_wire
1400  0., // sigma_end_wire,
1401  LastHit.PeakTime(), // end_tick
1402  LastHit.SigmaPeakTime(), // sigma_end_tick
1403  ClusterParamAlgo.EndCharge().value(), // end_charge
1404  ClusterParamAlgo.EndAngle().value(), // end_angle
1405  ClusterParamAlgo.EndOpeningAngle().value(), // end_opening
1406  ClusterParamAlgo.Integral().value(), // integral
1407  ClusterParamAlgo.IntegralStdDev().value(), // integral_stddev
1408  ClusterParamAlgo.SummedADC().value(), // summedADC
1409  ClusterParamAlgo.SummedADCStdDev().value(), // summedADC_stddev
1410  ClusterParamAlgo.NHits(), // n_hits
1411  ClusterParamAlgo.MultipleHitDensity(), // multiple_hit_density
1412  ClusterParamAlgo.Width(), // width
1413  clusterID, // ID
1414  FirstHit.View(), // view
1415  FirstHit.WireID().planeID(), // plane
1416  recob::Cluster::Sentry // sentry
1417  );
1418 
1419  ++clusterID;
1420  clusHitsOut.push_back(planeClusHitsOut.at(xx));
1421  }
1422 
1423 
1424  hit.clear();
1425  // lastHits.clear();
1426  if(clusterIter != clusIn.end()){
1427  clusterIter++;
1428  ++cinctr;
1429  }
1430  // listofxmax.clear();
1431  // listofymax.clear();
1432  }//end loop over clusters
1433 
1434  }// end loop over views
1435 
1436  return ccol.size();
1437 
1438 }
1439 
1440 //------------------------------------------------------------------------------
1442  std::vector< art::PtrVector<recob::Hit> > & clusHitsOut )
1443  {
1444  std::vector<double> slopevec;
1445  std::vector<ChargeInfo_t> totalQvec;
1446  return FastTransform( clusIn, clusHitsOut, slopevec, totalQvec );
1447 
1448  }
1449 
1450 
1451 
1452 //------------------------------------------------------------------------------
1454  std::vector< art::PtrVector<recob::Hit> > & clusHitsOut,
1455  std::vector<double> &slopevec, std::vector<ChargeInfo_t>& totalQvec )
1456 {
1457  std::vector<int> skip;
1458 
1459  //art::FindManyP<recob::Hit> fmh(clusIn, evt, label);
1460 
1461  geo::GeometryCore const* geom = lar::providerFrom<geo::Geometry>();
1462  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
1463  lariov::ChannelStatusProvider const* channelStatus
1464  = lar::providerFrom<lariov::ChannelStatusService>();
1465 
1466  // Get the random number generator
1468  CLHEP::HepRandomEngine & engine = rng -> getEngine();
1469  CLHEP::RandFlat flat(engine);
1470 
1471  std::vector< art::Ptr<recob::Hit> > hit;
1472 
1473 // for(size_t cs = 0; cs < geom->Ncryostats(); ++cs){
1474 // for(size_t t = 0; t < geom->Cryostat(cs).NTPC(); ++t){
1475 // for(unsigned int p = 0; p < geom->Cryostat(cs).TPC(t).Nplanes(); ++p) {
1476 // art::PtrVector<recob::Cluster>::const_iterator clusterIter = clusIn.begin();
1477 // int clusterID = 0;//the unique ID of the cluster
1478 
1479 
1480 
1481 
1482  size_t cinctr = 0;
1483  //while(clusterIter != clusIn.end()) {
1484  hit.clear();
1485  for(std::vector < art::Ptr < recob::Hit > >::const_iterator ii=clusIn.begin();ii!=clusIn.end();ii++)
1486  hit.push_back((*ii)); // this is new
1487 
1488  if(hit.size() == 0){
1489  if(fPerCluster){
1490  ++cinctr;
1491  }
1492  return -1;
1493  }
1494 
1495  unsigned int cs=hit.at(0)->WireID().Cryostat;
1496  unsigned int t=hit.at(0)->WireID().TPC;
1497  unsigned int p=hit.at(0)->WireID().Plane;
1498  geo::WireID const& wireid = hit.at(0)->WireID();
1499 
1500  geo::SigType_t sigt = geom->SignalType(wireid);
1501 
1502  // if(fPerCluster){
1503  // if((*clusterIter)->View() == view) hit = fmh.at(cinctr);
1504  // }
1505  // else{
1506  // while(clusterIter != clusIn.end()){
1507  // if( (*clusterIter)->View() == view ){
1508 
1509  // hit = fmh.at(cinctr);
1510  // }// end if cluster is in correct view
1511  // clusterIter++;
1512  // ++cinctr;
1513  // }//end loop over clusters
1514  // }//end if not fPerCluster
1515 
1516  if(hit.size() == 0){
1517  if(fPerCluster){
1518  // clusterIter++;
1519  ++cinctr;
1520  }
1521  return -1; //continue;
1522  }
1523 
1524  std::vector<double> wire_pitch(geom->Nplanes(t, cs), 0.);
1525  for (size_t p = 0; p < wire_pitch.size(); ++p) {
1526  wire_pitch[p] = geom->WirePitch(p);
1527  }
1528 
1529  //factor to make x and y scale the same units
1530  std::vector<double> xyScale(geom->Nplanes(t, cs), 0.);
1531 
1533  double driftVelFactor = 0.001*detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
1534 
1535  for(size_t p = 0; p < xyScale.size(); ++p)
1536  xyScale[p] = driftVelFactor * detprop->SamplingRate()/wire_pitch[p];
1537 
1538  int x = 0, y = 0;
1539  int dx = geom->Cryostat(cs).TPC(t).Plane(p).Nwires();//number of wires
1540  const int dy = detprop->ReadOutWindowSize(); // number of time samples.
1541  skip.clear();
1542  skip.resize(hit.size());
1543  std::vector<int> listofxmax;
1544  std::vector<int> listofymax;
1545  std::vector<int> hitTemp; //indecies ofcandidate hits
1546  std::vector<int> sequenceHolder; //channels of hits in list
1547  std::vector<int> currentHits; //working vector of hits
1548  std::vector<int> lastHits; //best list of hits
1549  art::PtrVector<recob::Hit> clusterHits;
1550  float indcolscaling = 0.; //a parameter to account for the different
1551  //characteristic hit width of induction and collection plane
1552  float centerofmassx = 0;
1553  float centerofmassy = 0;
1554  float denom = 0;
1555  float intercept=0.;
1556  float slope = 0.;
1557  //this array keeps track of the hits that have already been associated with a line.
1558  int xMax = 0;
1559  int yMax = 0;
1560  float rho;
1561  float theta;
1562  int accDx(0), accDy(0);
1563 
1564 
1565  HoughTransform c;
1566  //Init specifies the size of the two-dimensional accumulator
1567  //(based on the arguments, number of wires and number of time samples).
1568  //adds all of the hits (that have not yet been associated with a line) to the accumulator
1570 
1571  // count is how many points are left to randomly insert
1572  unsigned int count = hit.size();
1573  std::vector<unsigned int> accumPoints;
1574  accumPoints.resize(hit.size());
1575  int nAccum = 0;
1576  unsigned int nLinesFound = 0;
1577 
1578  for( ; count > 0; count--){
1579 
1580 
1581  // The random hit we are examining
1582  unsigned int randInd = (unsigned int)(flat.fire()*hit.size());
1583 
1584  LOG_DEBUG("HoughBaseAlg") << "randInd=" << randInd << " and size is " << hit.size();
1585 
1586  // Skip if it's already in a line
1587  if(skip.at(randInd)==1)
1588  continue;
1589 
1590  // If we have already accumulated the point, skip it
1591  if(accumPoints.at(randInd))
1592  continue;
1593  accumPoints.at(randInd)=1;
1594 
1595  // zeroes out the neighborhood of all previous lines
1596  for(unsigned int i = 0; i < listofxmax.size(); ++i){
1597  int yClearStart = listofymax.at(i) - fRhoZeroOutRange;
1598  if (yClearStart < 0) yClearStart = 0;
1599 
1600  int yClearEnd = listofymax.at(i) + fRhoZeroOutRange;
1601  if (yClearEnd >= accDy) yClearEnd = accDy - 1;
1602 
1603  int xClearStart = listofxmax.at(i) - fThetaZeroOutRange;
1604  if (xClearStart < 0) xClearStart = 0;
1605 
1606  int xClearEnd = listofxmax.at(i) + fThetaZeroOutRange;
1607  if (xClearEnd >= accDx) xClearEnd = accDx - 1;
1608 
1609  for (y = yClearStart; y <= yClearEnd; ++y){
1610  for (x = xClearStart; x <= xClearEnd; ++x){
1611  c.SetCell(y,x,0);
1612  }
1613  }
1614  }// end loop over size of listxmax
1615 
1616 
1617  //find the weightiest cell in the accumulator.
1618  int maxCell = 0;
1619  unsigned int wireMax = hit.at(randInd)->WireID().Wire;
1620 
1621  // Add the randomly selected point to the accumulator
1622  std::array<int, 3> max = c.AddPointReturnMax(wireMax,
1623  (int)(hit.at(randInd)->PeakTime()));
1624  maxCell = max.at(0);
1625  xMax = max.at(1);
1626  yMax = max.at(2);
1627  nAccum++;
1628 
1629  // Continue if the biggest maximum for the randomly selected point is smaller than fMinHits
1630  if (maxCell < fMinHits)
1631  continue;
1632 
1633  // Find the center of mass of the 3x3 cell system (with maxCell at the center).
1634  denom = centerofmassx = centerofmassy = 0;
1635 
1636  if(xMax > 0 && yMax > 0 && xMax + 1 < accDx && yMax + 1 < accDy){
1637  for(int i = -1; i < 2; ++i){
1638  for(int j = -1; j < 2; ++j){
1639  int cell = c.GetCell(yMax+i,xMax+j);
1640  denom += cell;
1641  centerofmassx += j*cell;
1642  centerofmassy += i*cell;
1643  }
1644  }
1645  centerofmassx /= denom;
1646  centerofmassy /= denom;
1647  }
1648  else centerofmassx = centerofmassy = 0;
1649 
1650  //fill the list of cells that have already been found
1651  listofxmax.push_back(xMax);
1652  listofymax.push_back(yMax);
1653 
1654  // Find the lines equation
1655  c.GetEquation(yMax+centerofmassy, xMax+centerofmassx, rho, theta);
1656  //c.GetEquation(yMax, xMax, rho, theta);
1657  LOG_DEBUG("HoughBaseAlg")
1658  << "Transform(I) found maximum at (d=" << rho << " a=" << theta << ")"
1659  " from absolute maximum " << c.GetCell(yMax,xMax)
1660  << " at (d=" << yMax << ", a=" << xMax << ")";
1661  slope = -1./tan(theta);
1662  intercept = (rho/sin(theta));
1663  //mf::LogVerbatim("HoughBaseAlg") << std::endl;
1664  //mf::LogVerbatim("HoughBaseAlg") << "slope: " << slope << " intercept: " << intercept << std::endl;
1665  //mf::LogInfo("HoughBaseAlg") << "slope: " << slope << " intercept: " << intercept;
1666  double distance;
1670  if(sigt == geo::kInduction)
1671  indcolscaling = 5.;
1672  else
1673  indcolscaling = 0.;
1674  // What is this?
1675  //indcolscaling = 0;
1676 
1677 
1678  // note this doesn't work for wrapped wire planes!
1679  if(!std::isinf(slope) && !std::isnan(slope)){
1680  sequenceHolder.clear();
1681  hitTemp.clear();
1682  for(size_t i = 0; i < hit.size(); ++i){
1683  distance = (TMath::Abs(hit.at(i)->PeakTime()-slope*(double)(hit.at(i)->WireID().Wire)-intercept)/(std::sqrt(pow(xyScale[hit.at(i)->WireID().Plane]*slope,2)+1)));
1684 
1685  if(distance < fMaxDistance+hit.at(i)->RMS()+indcolscaling && skip.at(i)!=1){
1686  hitTemp.push_back(i);
1687  sequenceHolder.push_back(hit.at(i)->Channel());
1688  }
1689 
1690  }// end loop over hits
1691 
1692  if(hitTemp.size() < 2) continue;
1693  currentHits.clear();
1694  lastHits.clear();
1695  int j;
1696  currentHits.push_back(0);
1697  for(size_t i = 0; i + 1 < sequenceHolder.size(); ++i){
1698  j = 1;
1699  while((channelStatus->IsBad(sequenceHolder.at(i)+j)) == true) j++;
1700  if(sequenceHolder.at(i+1)-sequenceHolder.at(i) <= j + fMissedHits) currentHits.push_back(i+1);
1701  else if(currentHits.size() > lastHits.size()) {
1702  lastHits = currentHits;
1703  currentHits.clear();
1704  }
1705  else currentHits.clear();
1706  }
1707 
1708 
1709  if(currentHits.size() > lastHits.size()) lastHits = currentHits;
1710 
1711 
1712 
1713  // Check if lastHits has hits with big gaps in it
1714  // lastHits[i] is ordered in increasing channel and then increasing peak time,
1715  // as a consequence, if the line has a negative slope and there are multiple hits in the line for a channel,
1716  // we have to go back to the first hit (in terms of lastHits[i]) of that channel to find the distance
1717  // between hits
1718  //std::cout << "New line" << std::endl;
1719  double tickToDist = detprop->DriftVelocity(detprop->Efield(),detprop->Temperature());
1720  tickToDist *= 1.e-3 * detprop->SamplingRate(); // 1e-3 is conversion of 1/us to 1/ns
1721  int missedHits=0;
1722  int lastHitsChannel = 0;//lastHits.at(0);
1723  int nHitsPerChannel = 1;
1724 
1725  LOG_DEBUG("HoughBaseAlg") << "filling the pCorner arrays around here..."
1726  << "\n but first, lastHits size is " << lastHits.size()
1727  << " and lastHitsChannel=" << lastHitsChannel;
1728 
1729  double pCorner0[2];
1730  double pCorner1[2];
1731  unsigned int lastChannel = hit.at(hitTemp.at(lastHits.at(0)))->Channel();
1732 
1733  for(size_t i = 0; i < lastHits.size()-1; ++i) {
1734  bool newChannel = false;
1735  if(slope < 0){
1736  if(hit.at(hitTemp.at(lastHits.at(i+1)))->Channel() != lastChannel){
1737  newChannel = true;
1738  }
1739  if(hit.at(hitTemp.at(lastHits.at(i+1)))->Channel() == lastChannel)
1740  nHitsPerChannel++;
1741  }
1742 
1743 
1745 
1746  if(slope > 0 || (!newChannel && nHitsPerChannel <= 1)){
1747 
1748  //std::cout << hits[hitsTemp[lastHits[i]]]->Channel() << " " << hits[hitsTemp[lastHits[i]]]->PeakTime() << std::endl;
1749  pCorner0[0] = (hit.at(hitTemp.at(lastHits.at(i)))->Channel())*wire_pitch[0];
1750  pCorner0[1] = hit.at(hitTemp.at(lastHits.at(i)))->PeakTime()*tickToDist;
1751  pCorner1[0] = (hit.at(hitTemp.at(lastHits.at(i+1)))->Channel())*wire_pitch[0];
1752  pCorner1[1] = hit.at(hitTemp.at(lastHits.at(i+1)))->PeakTime()*tickToDist;
1753  //std::cout << std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) << std::endl;
1754  if(std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) > fMissedHitsDistance )
1755  missedHits++;
1756  }
1757 
1758 
1759  else if (slope < 0 && newChannel && nHitsPerChannel > 1){
1760 
1761  //std::cout << hits[hitsTemp[lastHits[lastHitsChannel]]]->Channel() << " " << hits[hitsTemp[lastHits[lastHitsChannel]]]->PeakTime() << std::endl;
1762  pCorner0[0] = (hit.at(hitTemp.at(lastHits.at(lastHitsChannel)))->Channel())*wire_pitch[0];
1763  pCorner0[1] = hit.at(hitTemp.at(lastHits.at(lastHitsChannel)))->PeakTime()*tickToDist;
1764  pCorner1[0] = (hit.at(hitTemp.at(lastHits.at(i+1)))->Channel())*wire_pitch[0];
1765  pCorner1[1] = hit.at(hitTemp.at(lastHits.at(i+1)))->PeakTime()*tickToDist;
1766  //std::cout << std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) << std::endl;
1767  if(std::sqrt( pow(pCorner0[0]-pCorner1[0],2) + pow(pCorner0[1]-pCorner1[1],2)) > fMissedHitsDistance )
1768  missedHits++;
1769  lastChannel=hit.at(hitTemp.at(lastHits.at(i)))->Channel();
1770  lastHitsChannel=i+1;
1771  nHitsPerChannel=0;
1772  }
1773  }
1774 
1775  //std::cout << "missedHits " << missedHits << std::endl;
1776  //std::cout << "lastHits.size() " << lastHits.size() << std::endl;
1777  //std::cout << "missedHits/lastHits.size() " << (double)missedHits/((double)lastHits.size()-1) << std::endl;
1778  if((double)missedHits/((double)lastHits.size()-1) > fMissedHitsToLineSize)
1779  continue;
1780 
1781 
1782 
1783 
1784  clusterHits.clear();
1785  if(lastHits.size() < 5) continue;
1786 
1787  // reduce rounding errors by using double (RMS is very sensitive to them)
1788  lar::util::StatCollector<double> integralQ, summedQ;
1789 
1790  for(size_t i = 0; i < lastHits.size(); ++i) {
1791  clusterHits.push_back(hit.at(hitTemp.at(lastHits.at(i))));
1792  integralQ.add(clusterHits.back()->Integral());
1793  summedQ.add(clusterHits.back()->SummedADC());
1794  skip.at(hitTemp.at(lastHits.at(i)))=1;
1795  }
1796  //protection against very steep uncorrelated hits
1797  if(std::abs(slope)>fMaxSlope)
1798  continue;
1799 
1800  clusHitsOut.push_back(clusterHits);
1801  slopevec.push_back(slope);
1802  totalQvec.emplace_back(
1803  integralQ.Sum(), integralQ.RMS(), // TODO biased value; should unbias?
1804  summedQ.Sum(), summedQ.RMS() // TODO biased value; should unbias?
1805  );
1806  //Turn off hit sharing. T. Yang 9/14/12
1807  // //allow double assignment of first and last hits
1808  // for(size_t i = 0; i < lastHits.size(); ++i){
1809  // if(skip[hitTemp[lastHits[i]]] ==1){
1810  // channel = hit[hitTemp[lastHits[i]]]->Channel();
1811  // if( channel == sc || channel == ec) skip[i] = 0;
1812  // }
1813  // }
1814 
1815  }// end if !std::isnan
1816 
1817  nLinesFound++;
1818 
1819  if(nLinesFound>(unsigned int)fMaxLines)
1820  break;
1821 
1822 
1823  }// end loop over hits
1824 
1825  // saves a bitmap image of the accumulator (useful for debugging),
1826  // with scaling based on the maximum cell value
1827  if(fSaveAccumulator){
1828  //finds the maximum cell in the accumulator for image scaling
1829  int cell, pix = 0, maxCell = 0;
1830  for (y = 0; y < accDy; ++y){
1831  for (x = 0; x < accDx; ++x){
1832  cell = c.GetCell(y,x);
1833  if (cell > maxCell) maxCell = cell;
1834  }
1835  }
1836 
1837  std::unique_ptr<unsigned char[]> outPix(new unsigned char [accDx*accDy]);
1838  unsigned int PicIndex = 0;
1839  for (y = 0; y < accDy; ++y){
1840  for (x = 0; x < accDx; ++x){
1841  //scales the pixel weights based on the maximum cell value
1842  if(maxCell > 0)
1843  pix = (int)((1500*c.GetCell(y,x))/maxCell);
1844  outPix[PicIndex++] = pix;
1845  }
1846  }
1847 
1848  HLSSaveBMPFile("houghaccum.bmp", outPix.get(), accDx, accDy);
1849  }// end if saving accumulator
1850 
1851  hit.clear();
1852  lastHits.clear();
1853  // if(clusterIter != clusIn.end()){
1854  // clusterIter++;
1855  // ++cinctr;
1856  // }
1857  listofxmax.clear();
1858  listofymax.clear();
1859  //}//end loop over clusters
1860 
1861  // }//end loop over planes
1862  // }// end loop over tpcs
1863  // }// end loop over cryostats
1864 
1865  return clusHitsOut.size();
1866 
1867 }
1868 
1869 
1870 
1871 
1872 
1873 //------------------------------------------------------------------------------
1875  double & slope,
1876  double & intercept)
1877 {
1878  HoughTransform c;
1879 
1881  const detinfo::DetectorProperties* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
1882 
1883  int dx = geom->Nwires(0); //number of wires
1884  const int dy = detprop->ReadOutWindowSize(); // number of time samples.
1885 
1887 
1888  for(unsigned int i=0;i < hits.size(); ++i){
1889  c.AddPointReturnMax(hits[i]->WireID().Wire, (int)(hits[i]->PeakTime()));
1890  }// end loop over hits
1891 
1892  //gets the actual two-dimensional size of the accumulator
1893  int accDx = 0;
1894  int accDy = 0;
1895  c.GetAccumSize(accDy, accDx);
1896 
1897  //find the weightiest cell in the accumulator.
1898  int xMax = 0;
1899  int yMax = 0;
1900  c.GetMax(yMax,xMax);
1901 
1902  //find the center of mass of the 3x3 cell system (with maxCell at the center).
1903  float centerofmassx = 0.;
1904  float centerofmassy = 0.;
1905  float denom = 0.;
1906 
1907  if(xMax > 0 && yMax > 0 && xMax+1 < accDx && yMax+1 < accDy){
1908  for(int i = -1; i < 2; ++i){
1909  for(int j = -1; j < 2; ++j){
1910  denom += c.GetCell(yMax+i,xMax+j);
1911  centerofmassx += j*c.GetCell(yMax+i,xMax+j);
1912  centerofmassy += i*c.GetCell(yMax+i,xMax+j);
1913  }
1914  }
1915  centerofmassx /= denom;
1916  centerofmassy /= denom;
1917  }
1918  else centerofmassx = centerofmassy = 0;
1919 
1920  float rho = 0.;
1921  float theta = 0.;
1922  c.GetEquation(yMax+centerofmassy, xMax+centerofmassx, rho, theta);
1923  LOG_DEBUG("HoughBaseAlg")
1924  << "Transform(III) found maximum at (d=" << rho << " a=" << theta << ")"
1925  " from absolute maximum " << c.GetCell(yMax,xMax)
1926  << " at (d=" << yMax << ", a=" << xMax << ")";
1927  slope = -1./tan(theta);
1928  intercept = rho/sin(theta);
1929 
1932 
1933  return hits.size();
1934 }
1935 
1936 
1937 
1938 
1939 
1940 
1941 
typename Base_t::SubCounter_t SubCounter_t
Definition: HoughBaseAlg.h:308
Float_t x
Definition: compare.C:6
PlaneID const & planeID() const
Definition: geo_types.h:355
void Init(unsigned int dx, unsigned int dy, float rhores, unsigned int numACells)
virtual unsigned int ReadOutWindowSize() const =0
Double_t xx
Definition: macro.C:12
Utilities related to art service access.
typename Traits_t::CounterBlock_t CounterBlock_t
Definition: CountersMap.h:165
float fRhoResolutionFactor
Factor determining the resolution in rho.
Definition: HoughBaseAlg.h:625
virtual void reconfigure(fhicl::ParameterSet const &pset)
Encapsulate the construction of a single cyostat.
const std::string label
int GetMax(int &xmax, int &ymax) const
intermediate_table::iterator iterator
KEY Key_t
type of counter key in the map
Definition: CountersMap.h:147
MaybeLogger_< ELseverityLevel::ELsev_info, false > LogInfo
geo::WireID WireID() const
Initial tdc tick for hit.
Definition: Hit.h:234
size_t FastTransform(const std::vector< art::Ptr< recob::Cluster > > &clusIn, std::vector< recob::Cluster > &ccol, std::vector< art::PtrVector< recob::Hit > > &clusHitsOut, art::Event const &evt, std::string const &label)
Declaration of signal hit object.
Float_t y
Definition: compare.C:6
std::set< geo::View_t > const & Views() const
Returns a list of possible views in the detector.
typename Base_t::CounterKey_t CounterKey_t
Definition: HoughBaseAlg.h:455
geo::View_t View() const
View for the plane of the hit.
Definition: Hit.h:233
WireID_t Wire
Index of the wire within its plane.
Definition: geo_types.h:313
SigType_t SignalType(geo::PlaneID const &pid) const
Returns the type of signal on the channels of specified TPC plane.
std::pair< const_iterator, SubCounter_t > PairValue_t
Pair identifying a counter and its current value.
Definition: HoughBaseAlg.h:313
Classes gathering simple statistics.
bool SubtractPoint(int x, int y)
geo::Length_t WirePitch(geo::PlaneID const &planeid) const
Returns the distance between two consecutive wires.
Weight_t RMS() const
Returns the root mean square.
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.
constexpr double PI
void SetCell(int row, int col, int value)
Definition: HoughBaseAlg.h:492
static const SentryArgument_t Sentry
An instance of the sentry object.
Definition: Cluster.h:182
int fMaxLines
Max number of lines that can be found.
Definition: HoughBaseAlg.h:613
PairValue_t unchecked_add_range_max(Key_t key_begin, Key_t key_end, SubCounter_t delta, typename BaseMap_t::iterator start, SubCounter_t min_max=std::numeric_limits< SubCounter_t >::min())
auto vector(Vector const &v)
Returns a manipulator which will print the specified array.
Definition: DumpUtils.h:265
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)
float fMissedHitsDistance
Distance between hits in a hough line before a hit is considered missed.
Definition: HoughBaseAlg.h:630
reference back()
Definition: PtrVector.h:393
int fSaveAccumulator
Save bitmap image of accumulator for debugging?
Definition: HoughBaseAlg.h:616
unsigned int Nplanes(unsigned int tpc=0, unsigned int cstat=0) const
Returns the total number of wire planes in the specified TPC.
Int_t max
Definition: plot.C:27
void hits()
Definition: readHits.C:15
intermediate_table::const_iterator const_iterator
std::array< int, 3 > DoAddPointReturnMax(int x, int y, bool bSubtract=false)
void push_back(Ptr< U > const &p)
Definition: PtrVector.h:441
Signal from induction planes.
Definition: geo_types.h:92
Weight_t Sum() const
Returns the weighted sum of the values.
void GetAccumSize(int &numRows, int &numCols)
Definition: HoughBaseAlg.h:493
enum geo::_plane_sigtype SigType_t
Enumerate the possible plane projections.
Wrapper for ClusterParamsAlgBase objects to accept diverse input.
T get(std::string const &key) const
Definition: ParameterSet.h:231
iterator end()
Definition: PtrVector.h:237
float fMaxDistance
Max distance that a hit can be from a line to be considered part of that line.
Definition: HoughBaseAlg.h:621
Int_t col[ntarg]
Definition: Style.C:29
Aggressive allocator reserving a lot of memory in advance.
Definition: BulkAllocator.h:92
CryostatGeo const & Cryostat(geo::CryostatID const &cryoid) const
Returns the specified cryostat.
float fMaxSlope
Max slope a line can have.
Definition: HoughBaseAlg.h:622
Wrapper for ClusterParamsAlgBase objects to accept arbitrary input.
Description of geometry of one entire detector.
Declaration of cluster object.
int GetCell(int row, int col) const
SubCounter_t decrement(Key_t key)
Decrements by 1 the specified counter.
Definition: HoughBaseAlg.h:343
std::array< int, 3 > AddPointReturnMax(int x, int y)
int fRhoZeroOutRange
Range in rho over which to zero out area around previously found lines in the accumulator.
Definition: HoughBaseAlg.h:623
Detector simulation of raw signals on wires.
Encapsulate the geometry of a wire.
data_t::const_iterator const_iterator
Definition: PtrVector.h:61
void GetEquation(float row, float col, float &rho, float &theta) const
PairValue_t get_max() const
Increments by 1 the specified counters and returns the maximum.
CountersMap with access optimized for Hough Transform algorithm.
Definition: HoughBaseAlg.h:293
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:104
Float_t sw
Definition: plot.C:23
float PeakTime() const
Time of the signal peak, in tick units.
Definition: Hit.h:219
typename Base_t::CounterBlock_t CounterBlock_t
Definition: HoughBaseAlg.h:309
std::string value(boost::any const &)
Utility object to perform functions of association.
Encapsulate the construction of a single detector plane.
const TPCGeo & TPC(unsigned int itpc) const
Return the itpc&#39;th TPC in the cryostat.
Int_t min
Definition: plot.C:26
void ImportHits(Iter begin, Iter end)
Calls SetHits() with the hits in the sequence.
unsigned int Nwires() const
Number of wires in this plane.
Definition: PlaneGeo.h:250
SubCounter_t increment(Key_t key)
Increments by 1 the specified counter.
Definition: HoughBaseAlg.h:336
void Init(unsigned int num=999999, unsigned int pnum=999999, float slope=999999, float intercept=999999, float totalQTemp=-999999, float Min0=999999, float Min1=999999, float Max0=-999999, float Max1=-999999, int iMinWireTemp=999999, int iMaxWireTemp=-999999, int minWireTemp=999999, int maxWireTemp=-999999, std::vector< art::Ptr< recob::Hit >> hitsTemp=std::vector< art::Ptr< recob::Hit >>())
Definition: HoughBaseAlg.h:234
#define LOG_DEBUG(id)
Char_t n[5]
HoughBaseAlg(fhicl::ParameterSet const &pset)
std::vector< evd::details::RawDigitInfo_t >::const_iterator end(RawDigitCacheDataClass const &cache)
float SigmaPeakTime() const
Uncertainty for the signal peak, in tick units.
Definition: Hit.h:220
PlaneGeo const & Plane(geo::View_t view) const
Return the plane in the tpc with View_t view.
Definition: TPCGeo.cxx:298
2D representation of charge deposited in the TDC/wire plane
Definition: Hit.h:49
Counter_t SubCounter_t
Type of the subcounter (that is, the actual counter)
Definition: CountersMap.h:162
Interface to class computing cluster parameters.
int fThetaZeroOutRange
Range in theta over which to zero out area around previously found lines in the accumulator.
Definition: HoughBaseAlg.h:624
Float_t e
Definition: plot.C:34
recob::tracking::Plane Plane
Definition: TrackState.h:17
PairValue_t increment_and_get_max(Key_t key_begin, Key_t key_end)
Increments by 1 the specified counters and returns the maximum.
Definition: HoughBaseAlg.h:386
void clear()
Definition: PtrVector.h:537
Float_t w
Definition: plot.C:23
Collects statistics on a single quantity (weighted)
float fMissedHitsToLineSize
Ratio of missed hits to line size for a line to be considered a fake.
Definition: HoughBaseAlg.h:631
art framework interface to geometry description
Encapsulate the construction of a single detector plane.
void add(Data_t value, Weight_t weight=Weight_t(1.0))
Adds one entry with specified value and weight.
T sqr(T v)
void HLSSaveBMPFile(char const *, unsigned char *, int, int)
SubCounter_t unchecked_set_range(Key_t key_begin, Key_t key_end, SubCounter_t value, typename BaseMap_t::iterator start)