All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CandHitICARUS_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file CandHitICARUS.cc
3 /// \author T. Usher
4 ////////////////////////////////////////////////////////////////////////
5 
7 
8 #include "art/Utilities/ToolMacros.h"
9 #include "art/Utilities/make_tool.h"
10 #include "messagefacility/MessageLogger/MessageLogger.h"
11 #include "cetlib_except/exception.h"
13 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
14 
15 #include <cmath>
16 #include <fstream>
17 
18 namespace reco_tool
19 {
20 
22 {
23 public:
24  explicit CandHitICARUS(const fhicl::ParameterSet& pset);
25 
26  void findHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t&,
27  size_t,
28  size_t,
29  size_t,
30  HitCandidateVec&) const override;
31 
32  void MergeHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t&,
33  const HitCandidateVec&,
34  MergeHitCandidateVec&) const override;
35 
36 private:
37 
38  void findHitCandidates(std::vector<float>::const_iterator,
39  std::vector<float>::const_iterator,
40  size_t,
41  double,
42  HitCandidateVec&) const;
43 
44  void expandHit(HitCandidate& h, std::vector<float> holder, HitCandidateVec how);
45  void prova() {return ;}
46 
47  int fInd1Width; //INITIAL WIDTH FOR INDUCTION HITFINDING.
48  int fInd2Width; //INITIAL WIDTH FOR INDUCTION HITFINDING.
49  int fColWidth; //INITIAL WIDTH FOR COLLECTION HITFINDING.
50  unsigned int fInd1Window; //INITIAL WINDOW FOR INDUCTION HITFINDING.
51  unsigned int fInd2Window; //INITIAL WINDOW FOR INDUCTION HITFINDING.
52  unsigned int fColWindow; //INITIAL WINDOW FOR COLLECTION HITFINDING.
53  int fInd1Threshold; //THRESHOLD FOR INDUCTION HITFINDING.
54  int fInd2Threshold; //THRESHOLD FOR INDUCTION HITFINDING.
55  int fColThreshold; //THRESHOLD FOR COLLECTION HITFINDING.
56  int fInd1Above; //MINIMAL NUMBER OF TICKS ABOVE THRESHOLD FOR INDUCTION HITFINDING.
58  int fColAbove;
59  int fInd1Fall;
60  int fInd2Fall;
61  int fColFall;
62  float fMinHitHeight; //< Drop candidate hits with height less than this
63  size_t fNumInterveningTicks; //< Number ticks between candidate hits to merge
64 
65  const geo::GeometryCore* fGeometry = lar::providerFrom<geo::Geometry>();
66 };
67 
68 //----------------------------------------------------------------------
69 // Constructor.
70 CandHitICARUS::CandHitICARUS(const fhicl::ParameterSet& pset)
71 {
72  // Start by recovering the parameters
73 
74  fInd1Width = pset.get< int >("Ind1Width");
75  fInd2Width = pset.get< int >("Ind2Width");
76  fColWidth = pset.get< int >("ColWidth");
77  fInd1Window = pset.get< unsigned int >("Ind1Window");
78  fInd2Window = pset.get< unsigned int >("Ind2Window");
79  fColWindow = pset.get< unsigned int >("ColWindow");
80  fInd1Threshold = pset.get< int >("Ind1Threshold");
81  fInd2Threshold = pset.get< int >("Ind2Threshold");
82  fColThreshold = pset.get< int >("ColThreshold");
83  fInd1Above = pset.get< int >("Ind1Above");
84  fInd2Above = pset.get< int >("Ind2Above");
85  fColAbove = pset.get< int >("ColAbove");
86  fInd1Fall = pset.get< int >("Ind1Fall");
87  fInd2Fall = pset.get< int >("Ind2Fall");
88  fColFall = pset.get< int >("ColFall");
89  fMinHitHeight = pset.get< float >("MinHitHeight", 1.0);
90  fNumInterveningTicks = pset.get< size_t >("NumInterveningTicks", 6);
91 
92  return;
93 }
94 
95 void CandHitICARUS::findHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t& rangeData,
96  size_t roiStart,
97  size_t channel,
98  size_t cnt,
99  HitCandidateVec& hits) const
100 {
101  // get the WireID for this hit
102  std::vector<geo::WireID> wids = fGeometry->ChannelToWire(channel);
103  // for now, just take the first option returned from ChannelToWire
104  geo::WireID wid = wids[0];
105  // We need to know the plane to look up parameters
106  geo::PlaneID::PlaneID_t plane = wid.Plane;
107  //int wire = wid.Wire;
108 
109  const Waveform& waveform = rangeData.data();
110 
111  // if(plane==1) return;
112  // if(wire>2639) return;
113  // if(plane==0&&wire==528)
114  // for( int j=0;j<4096;j++)
115  // std::cout << " j " << j << " waveform " << waveform[j] << std::endl;
116  int iflag;
117  int localbellow,rising;
118  int begin;
119  // int nSamp=digitVec->Samples();
120  int lastcomputedmean,count;
121  int peakheight;
122  int localminidx,localmin;
123  // int jj, jcount;
124  // float area;
125  HitCandidate h;
126  //std::vector<HitCandidate> hits;
127  unsigned int i;
128  // Hit finding parameters
129  const int rise=5;
130 
131  double threshold=0;
132  unsigned int window=0;
133  int abovecut(0),fall(0);
134  unsigned int width(0);
135 
136 
137  // initialize parameters
138  iflag=0; // equal to one if we are within a hit candidate
139  peakheight=-9999; // last found hit maximum
140  begin=-1; // last found hit initial sample
141  localbellow=0; // number of times we are bellow peakheight
142  lastcomputedmean=0; // the value we compare with to know if we have a hit
143  count=0;
144  for(unsigned int j=0;j<window;j++)
145  count+=waveform[j];
146  lastcomputedmean=(count>=0)? 0 : count/window;
147  // negpeakwidth=0;
148  // if(lastcomputedmean<0) negpeakwidth++;
149  localmin=9999;
150  localminidx=-1;
151 
152  // loop on the selected samples
153 
154  //std::cout << "candhitfinderICARUS " << std::endl;
155 
156  if(plane == 0) threshold=fInd1Threshold;
157  else if(plane == 1) threshold=fInd2Threshold;
158  else if(plane == 2) threshold=fColThreshold;
159  if(plane == 0) window=fInd1Window;
160  else if(plane == 1) window=fInd2Window;
161  else if(plane == 2) window=fColWindow;
162  if(plane == 0) abovecut=fInd1Above;
163  else if(plane == 1) abovecut=fInd2Above;
164  else if(plane == 2) abovecut=fColAbove;
165  if(plane == 0) fall=fInd1Fall;
166  else if(plane == 1) fall=fInd2Fall;
167  else if(plane == 2) fall=fColFall;
168  if(plane == 0) width=fInd1Width;
169  else if(plane == 1) width=fInd2Width;
170  else if(plane == 2) width=fColWidth;
171 
172  for( i=0;i<4096;i++)
173  { //2
174  //std::cout << " i " << i << " waveform " << waveform[i] << std::endl;
175  // skip sharp peaks
176  //if(abs(waveform[i]-lastcomputedmean)>100)
177  // continue;
178 
179  if(!iflag)
180  lastcomputedmean=0;
181 
182  if(waveform[i]-lastcomputedmean>threshold) // we're within a hit OR hit group
183  { //3
184  // if(iwire==4526&&plane==2&&cryostat==0&&tpc==0)
185  // std::cout << " over threshold bin " << i << std::endl;
186  iflag=1;
187 
188  // we're in the beginning of the hit
189  if(begin<0) {
190 
191  begin=i; // hit starting point
192  }
193 
194  // keep peak info
195  if(waveform[i]-lastcomputedmean>peakheight)
196  {
197  peakheight=waveform[i]-lastcomputedmean;
198  // h.hitCenter=waveform[i];
199  h.hitHeight=peakheight;
200 // h.iWire=iw;
201  h.hitCenter=i;
202  // std::cout << " hitcenter " << i << std::endl;
203  localbellow=0;
204  }
205 
206  // resolve close hits
207  // if(*(pf+i)-(peakheight+lastcomputedmean)<-threshold) // we're in the slope down
208  if(waveform[i]-(peakheight+lastcomputedmean)<-1) // we're in the slope down
209  {
210  localbellow++;
211  // std::cout << " i " << i << " localbellow " << localbellow << " abovecut " << abovecut << std::endl;
212  }
213  if(localbellow>abovecut)
214  { //4
215  // keep local minimum as border between consecutive hits
216  if(waveform[i]<localmin) {localmin=waveform[i];localminidx=i;}
217 
218  // count the number of rising samples within the following n=<rise> samples
219  rising=0;
220  for(int l=0;l<rise;l++)
221  {
222  if(i+l<4096) {
223  if(waveform[i+l+1]-waveform[i+l]>0) rising++;
224  else if(waveform[i+l+1]-waveform[i+l]<0) rising--;
225  }
226  }
227  // std::cout << " rising " << rising << " abovecut " << abovecut << std::endl;
228  // if after a slope down there's a slope up save the previous hit
229  if(rising>abovecut)
230  { //5
231  h.startTick=begin;
232  // h.finDrift=i+iniSamp;
233  h.stopTick=localminidx;
234 
235  //std::cout << " saving previous hit " << begin << " fin " << localminidx << std::endl;
236 
237  if((h.stopTick-h.hitCenter)>=fall && h.stopTick-h.startTick>width)
238  { //6
239  h.minTick=h.startTick;
240  h.maxTick=h.stopTick;
241  // std::cout << " adding hit case 1" << std::endl;
242  h.hitSigma = 0.5*(h.stopTick-h.startTick);
243 
244  hits.push_back(h);
245  peakheight=-9999;
246  h.hitHeight=0;
247  //begin=i+iniSamp+1;
248  begin=localminidx+1;
249  localbellow=0;
250  localminidx=-1;
251  localmin=9999;
252  }
253  }
254  }
255  }
256  else // outside the hit
257  { //3
258  //if ( typ == BasicData::ISBASICPLANE_PMT && iw==1){
259  // cout << "out hit " << iflag << "iadc " << h.iAdcMax <<endl;
260  // cout << " in, fin " << begin << " " << i+iniSamp << "peak "<<h.iDrift <<endl;}
261  if (iflag==1 && h.hitHeight) //just getting out of the latest hit
262  { //4
263  h.startTick=begin;
264  h.stopTick=i;
265 
266  if((h.stopTick-h.hitCenter)>=fall && (h.stopTick-h.startTick)>width)
267  { //5
268  h.minTick=h.startTick;
269  h.maxTick=h.stopTick;
270  //if(iwire==4526&&plane==1&&cryostat==0&&tpc==0)
271  //std::cout << " adding hit case 2, tick " << i << std::endl;
272  // if(cryostat==0&&tpc==0&&plane==2&&h.iWire==2656)
273  // std::cout << " before expand ini " << h.iniDrift << " fin " << h.finDrift << std::endl;
274  //expandHit(h,waveform,hits);
275 
276  // if(cryostat==0&&tpc==0&&plane==2&&h.iWire==2656)
277  // std::cout << " after expand ini " << h.iniDrift << " fin " << h.finDrift << std::endl;
278  h.hitSigma = 0.5*(h.stopTick-h.startTick);
279 
280  hits.push_back(h);
281  //InsertHit(&h);
282  // if ( typ != BasicData::ISBASICPLANE_PMT)
283 
284  }
285 
286  peakheight=-9999;
287  begin=-1;
288  iflag=0;
289  localbellow=0;
290  }
291 
292  }
293 
294  //keep the last mean value to which we have to come back after the hit
295  if(i>=window && window) {
296  if(waveform[i]-count/window>-10)
297  {
298  count+=waveform[i];
299  count-=waveform[i-window];
300  // if((float) count/window<0) negpeakwidth++;
301  // else negpeakwidth=0;
302  }
303  }
304  } //end loop on samples
305 
306  //if we were within a hit while reaching last sample, keep it
307  if(iflag==1 && h.hitHeight) //just getting out of the latest hit
308  { //3
309  h.startTick=begin;
310  h.stopTick=i-1;
311 
312  if((h.stopTick-h.hitCenter)>=fall && (h.stopTick-h.startTick)>width)
313  {
314  // if(cryostat==0&&tpc==0&&plane==2&&h.iWire==2656)
315 // std::cout << " before expand ini " << h.iniDrift << " fin " << h.finDrift << std::endl;
316  // expandHit(h,waveform,hits);
317 
318  // if(cryostat==0&&tpc==0&&plane==2&&h.iWire==2656)
319  // std::cout << " after expand ini " << h.iniDrift << " fin " << h.finDrift << std::endl;
320  h.minTick=h.startTick;
321  h.maxTick=h.stopTick;
322  //std::cout << " adding hit case 3 " << i << std::endl;
323 
324  h.hitSigma = 0.5*(h.stopTick-h.startTick);
325  hits.push_back(h);
326  // InsertHit(&h);
327  }
328  }
329  // if(hits.size())
330  // std::cout << " wire " << wire << " found hits " << hits.size() << std::endl;
331 
332 
333 
334  return;
335 }
336 
337 void CandHitICARUS::findHitCandidates(std::vector<float>::const_iterator startItr,
338  std::vector<float>::const_iterator stopItr,
339  size_t roiStartTick,
340  double roiThreshold,
341  HitCandidateVec& hitCandidateVec) const
342 {
343  // Need a minimum number of ticks to do any work here
344  if (std::distance(startItr,stopItr) > 4)
345  {
346  // Find the highest peak in the range given
347  auto maxItr = std::max_element(startItr, stopItr);
348 
349  float maxValue = *maxItr;
350  int maxTime = std::distance(startItr,maxItr);
351 
352  if (maxValue > roiThreshold)
353  {
354  // backwards to find first bin for this candidate hit
355  auto firstItr = std::distance(startItr,maxItr) > 2 ? maxItr - 1 : startItr;
356 
357  while(firstItr != startItr)
358  {
359  // Check for pathology where waveform goes too negative
360  if (*firstItr < -roiThreshold) break;
361 
362  // Check both sides of firstItr and look for min/inflection point
363  if (*firstItr < *(firstItr+1) && *firstItr <= *(firstItr-1)) break;
364 
365  firstItr--;
366  }
367 
368  int firstTime = std::distance(startItr,firstItr);
369 
370  // Recursive call to find all candidate hits earlier than this peak
371  findHitCandidates(startItr, firstItr + 1, roiStartTick, roiThreshold, hitCandidateVec);
372 
373  // forwards to find last bin for this candidate hit
374  auto lastItr = std::distance(maxItr,stopItr) > 2 ? maxItr + 1 : stopItr - 1;
375 
376  while(lastItr != stopItr - 1)
377  {
378  // Check for pathology where waveform goes too negative
379  if (*lastItr < -roiThreshold) break;
380 
381  // Check both sides of firstItr and look for min/inflection point
382  if (*lastItr <= *(lastItr+1) && *lastItr < *(lastItr-1)) break;
383 
384  lastItr++;
385  }
386 
387  int lastTime = std::distance(startItr,lastItr);
388 
389  // Now save this candidate's start and max time info
390  HitCandidate hitCandidate;
391  hitCandidate.startTick = roiStartTick + firstTime;
392  hitCandidate.stopTick = roiStartTick + lastTime;
393  hitCandidate.maxTick = roiStartTick + firstTime;
394  hitCandidate.minTick = roiStartTick + lastTime;
395  hitCandidate.maxDerivative = *(startItr + firstTime);
396  hitCandidate.minDerivative = *(startItr + lastTime);
397  hitCandidate.hitCenter = roiStartTick + maxTime;
398  hitCandidate.hitSigma = std::max(2.,float(lastTime - firstTime) / 6.);
399  hitCandidate.hitHeight = maxValue;
400 
401  hitCandidateVec.push_back(hitCandidate);
402 
403  // Recursive call to find all candidate hits later than this peak
404  findHitCandidates(lastItr + 1, stopItr, roiStartTick + std::distance(startItr,lastItr + 1), roiThreshold, hitCandidateVec);
405  }
406  }
407 
408  return;
409 }
410 
411 void CandHitICARUS::MergeHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t& rangeData,
412  const HitCandidateVec& hitCandidateVec,
413  MergeHitCandidateVec& mergedHitsVec) const
414 {
415  // If nothing on the input end then nothing to do
416  if (hitCandidateVec.empty()) return;
417 
418  // The idea is to group hits that "touch" so they can be part of common fit, those that
419  // don't "touch" are fit independently. So here we build the output vector to achieve that
420  // Get a container for the hits...
421  HitCandidateVec groupedHitVec;
422 
423  // Initialize the end of the last hit which we'll set to the first input hit's stop
424  size_t lastStopTick = hitCandidateVec.front().stopTick;
425 
426  // Step through the input hit candidates and group them by proximity
427  for(const auto& hitCandidate : hitCandidateVec)
428  {
429  // Small pulse height hits should not be considered?
430  if (hitCandidate.hitHeight > fMinHitHeight)
431  {
432  // Check condition that we have a new grouping
433  if (hitCandidate.startTick > lastStopTick + fNumInterveningTicks && !groupedHitVec.empty())
434  {
435  mergedHitsVec.emplace_back(groupedHitVec);
436 
437  groupedHitVec.clear();
438  }
439 
440  // Add the current hit to the current group
441  groupedHitVec.emplace_back(hitCandidate);
442 
443  lastStopTick = hitCandidate.stopTick;
444  }
445  }
446 
447  // Check end condition
448  if (!groupedHitVec.empty()) mergedHitsVec.emplace_back(groupedHitVec);
449 
450  return;
451 }
452 
453  void CandHitICARUS::expandHit(HitCandidate& h, std::vector<float> holder, HitCandidateVec how)
454  {
455  // Given a hit or hit candidate <hit> expand its limits to the closest minima
456  int nsamp=50;
457  int cut=1;
458  int upordown;
459  int found=0;
460 
461  unsigned int first=h.startTick;
462  unsigned int last =h.stopTick;
463 
464  std::vector<HitCandidate>::iterator hiter;
465  std::vector<HitCandidate> hlist;
466 
467  // fill list of existing hits on this wire
468  for(unsigned int j=0;j<how.size();j++)
469  {
470  HitCandidate h2=how[j];
471  if(h2.hitCenter!=h.hitCenter)
472  hlist.push_back(h2);
473  }
474 
475 
476  // look for first sample
477  while(!found)
478  {
479  if(first==0)
480  break;
481 
482  for(hiter=hlist.begin();hiter!=hlist.end();hiter++)
483  {
484  HitCandidate h2=*hiter;
485  if(first==h2.stopTick)
486  found=1;
487  }
488 
489  if(found==1) break;
490 
491  upordown=0;
492  for(int l=0;l<nsamp/2;l++)
493  {
494  if(first-nsamp/2+l<4095) {
495  if(holder[first-nsamp/2+l+1]-holder[first-nsamp/2+l]>0) upordown++;
496  else if(holder[first-nsamp/2+l+1]-holder[first-nsamp/2+l]<0) upordown--;
497  } }
498  //std::cout << " checking " << first << " upordown " << upordown << std::endl;
499  if(upordown>cut)
500  first--;
501  else
502  found=1;
503  }
504 
505  // look for last sample
506  found=0;
507  while(!found)
508  {
509  if(last==4095)
510  {
511  found=1;
512  break;
513  }
514 
515  for(hiter=hlist.begin();hiter!=hlist.end();hiter++)
516  {
517  HitCandidate h2=*hiter;
518  if(first==h2.startTick)
519  found=1;
520  }
521 
522  if(found==1) break;
523 
524  upordown=0;
525  for(int l=0;l<nsamp/2;l++)
526  {
527  if(last+nsamp/2-l>0) {
528  if(holder[last+nsamp/2-l]-holder[last+nsamp/2-l-1]>0) upordown++;
529  else if(holder[last+nsamp/2-l]-holder[last+nsamp/2-l-1]<0) upordown--;
530  } }
531 
532  if(upordown<-cut)
533  last++;
534  else
535  found=1;
536  }
537 
538  h.startTick=first;
539  h.stopTick=last;
540  }
541 
542 DEFINE_ART_CLASS_TOOL(CandHitICARUS)
543 }
Utilities related to art service access.
unsigned int PlaneID_t
Type for the ID number.
Definition: geo_types.h:473
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
while getopts h
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
Description of geometry of one entire detector.
auto begin(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:573
CandHitICARUS(const fhicl::ParameterSet &pset)
const geo::GeometryCore * fGeometry
void expandHit(HitCandidate &h, std::vector< float > holder, HitCandidateVec how)
This provides an interface for tools which are tasked with finding candidate hits on input waveforms...
void MergeHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t &, const HitCandidateVec &, MergeHitCandidateVec &) const override
std::size_t count(Cont const &cont)
std::vector< HitCandidateVec > MergeHitCandidateVec
void findHitCandidates(const recob::Wire::RegionsOfInterest_t::datarange_t &, size_t, size_t, size_t, HitCandidateVec &) const override
art framework interface to geometry description
std::vector< HitCandidate > HitCandidateVec