LArSoft  v09_90_00
Liquid Argon Software toolkit - https://larsoft.org/
WaveformTools_tool.cc
Go to the documentation of this file.
1 
8 #include <cmath>
9 #include <numeric> // std::inner_product
10 
11 #include "TProfile.h"
12 #include "TVirtualFFT.h"
13 
14 namespace reco_tool {
15 
17  public:
18  explicit WaveformTools(const fhicl::ParameterSet& pset);
19 
21 
22  void configure(const fhicl::ParameterSet& pset) override;
23 
24  using PeakTuple = std::tuple<size_t, size_t, size_t>; // first bin, peak bin, last bin
25  using PeakTupleVec = std::vector<PeakTuple>;
26 
27  void triangleSmooth(const std::vector<float>&, std::vector<float>&, size_t = 0) const override;
28  void triangleSmooth(const std::vector<double>&,
29  std::vector<double>&,
30  size_t = 0) const override;
31  void medianSmooth(const std::vector<float>&, std::vector<float>&, size_t = 3) const override;
32  void medianSmooth(const std::vector<double>&, std::vector<double>&, size_t = 3) const override;
33  void getTruncatedMeanRMS(const std::vector<double>&,
34  double&,
35  double&,
36  double&,
37  int&) const override;
38  void getTruncatedMeanRMS(const std::vector<float>&,
39  float&,
40  float&,
41  float&,
42  int&) const override;
43  void firstDerivative(const std::vector<float>&, std::vector<float>&) const override;
44  void firstDerivative(const std::vector<double>&, std::vector<double>&) const override;
47  PeakTupleVec&,
48  float,
49  size_t) const override;
52  PeakTupleVec&,
53  double,
54  size_t) const override;
55  void getFFTPower(const std::vector<float>& inputVec,
56  std::vector<float>& outputPowerVec) const override;
57  void getFFTPower(const std::vector<double>& inputVec,
58  std::vector<double>& outputPowerVec) const override;
59 
61  int,
62  HistogramMap&,
66  Waveform<short>&) const override;
68  int,
69  HistogramMap&,
73  Waveform<float>&) const override;
75  int,
76  HistogramMap&,
80  Waveform<double>&) const override;
81 
83  const Waveform<short>&,
84  int,
85  HistogramMap&,
87  Waveform<short>&) const override;
89  const Waveform<float>&,
90  int,
91  HistogramMap&,
93  Waveform<float>&) const override;
95  const Waveform<double>&,
96  int,
97  HistogramMap&,
99  Waveform<double>&) const override;
100 
101  private:
102  template <typename T>
103  void triangleSmooth(const std::vector<T>&, std::vector<T>&, size_t = 0) const;
104  template <typename T>
105  void medianSmooth(const std::vector<T>&, std::vector<T>&, size_t = 3) const;
106  template <typename T>
107  void getTruncatedMeanRMS(const std::vector<T>&, T&, T&, T&, int&) const;
108  template <typename T>
109  void firstDerivative(const std::vector<T>&, std::vector<T>&) const;
110  template <typename T>
111  void findPeaks(typename std::vector<T>::iterator,
112  typename std::vector<T>::iterator,
113  PeakTupleVec&,
114  T,
115  size_t) const;
116 
117  template <typename T>
119  int,
120  HistogramMap&,
121  Waveform<T>&,
122  Waveform<T>&,
123  Waveform<T>&,
124  Waveform<T>&) const;
125 
126  template <typename T>
127  void getOpeningAndClosing(const Waveform<T>&,
128  const Waveform<T>&,
129  int,
130  HistogramMap&,
131  Waveform<T>&,
132  Waveform<T>&) const;
133  };
134 
135  //----------------------------------------------------------------------
136  // Constructor.
138  {
139  configure(pset);
140  }
141 
143  {
144  // Start by recovering the parameters
145  // fThisPlane = pset.get<size_t>("Plane");
146 
147  return;
148  }
149 
150  void WaveformTools::triangleSmooth(const std::vector<double>& inputVec,
151  std::vector<double>& smoothVec,
152  size_t lowestBin) const
153  {
154  triangleSmooth<double>(inputVec, smoothVec, lowestBin);
155 
156  return;
157  }
158 
159  void WaveformTools::triangleSmooth(const std::vector<float>& inputVec,
160  std::vector<float>& smoothVec,
161  size_t lowestBin) const
162  {
163  triangleSmooth<float>(inputVec, smoothVec, lowestBin);
164 
165  return;
166  }
167 
168  template <typename T>
169  void WaveformTools::triangleSmooth(const std::vector<T>& inputVec,
170  std::vector<T>& smoothVec,
171  size_t lowestBin) const
172  {
173  if (inputVec.size() != smoothVec.size()) smoothVec.resize(inputVec.size());
174 
175  // Watch for edge condition
176  if (inputVec.size() > 4) {
177  std::copy(inputVec.begin(), inputVec.begin() + 2 + lowestBin, smoothVec.begin());
178  std::copy(inputVec.end() - 2, inputVec.end(), smoothVec.end() - 2);
179 
180  typename std::vector<T>::iterator curItr = smoothVec.begin() + 2 + lowestBin;
181  typename std::vector<T>::const_iterator curInItr = inputVec.begin() + 1 + lowestBin;
182  typename std::vector<T>::const_iterator stopInItr = inputVec.end() - 3;
183 
184  while (curInItr++ != stopInItr) {
185  // Take the weighted average of five consecutive points centered on current point
186  T newVal = (*(curInItr - 2) + 2. * *(curInItr - 1) + 3. * *curInItr + 2. * *(curInItr + 1) +
187  *(curInItr + 2)) /
188  9.;
189 
190  *curItr++ = newVal;
191  }
192  }
193  else
194  std::copy(inputVec.begin(), inputVec.end(), smoothVec.begin());
195 
196  return;
197  }
198 
199  void WaveformTools::medianSmooth(const std::vector<float>& inputVec,
200  std::vector<float>& smoothVec,
201  size_t nBins) const
202  {
203  medianSmooth<float>(inputVec, smoothVec, nBins);
204 
205  return;
206  }
207 
208  void WaveformTools::medianSmooth(const std::vector<double>& inputVec,
209  std::vector<double>& smoothVec,
210  size_t nBins) const
211  {
212  medianSmooth<double>(inputVec, smoothVec, nBins);
213 
214  return;
215  }
216 
217  template <typename T>
218  void WaveformTools::medianSmooth(const std::vector<T>& inputVec,
219  std::vector<T>& smoothVec,
220  size_t nBins) const
221  {
222  // For our purposes, nBins must be odd
223  if (nBins % 2 == 0) nBins++;
224 
225  // Make sure the input vector is right sized
226  if (inputVec.size() != smoothVec.size()) smoothVec.resize(inputVec.size());
227 
228  // Basic set up
229  typename std::vector<T> medianVec(nBins);
230  typename std::vector<T>::const_iterator startItr = inputVec.begin();
231  typename std::vector<T>::const_iterator stopItr = startItr;
232 
233  std::advance(stopItr, inputVec.size() - nBins);
234 
235  size_t medianBin = nBins / 2;
236  size_t smoothBin = medianBin;
237 
238  // First bins are not smoothed
239  std::copy(startItr, startItr + medianBin, smoothVec.begin());
240 
241  while (std::distance(startItr, stopItr) > 0) {
242  std::copy(startItr, startItr + nBins, medianVec.begin());
243  std::sort(medianVec.begin(), medianVec.end());
244 
245  T medianVal = medianVec[medianBin];
246 
247  smoothVec[smoothBin++] = medianVal;
248 
249  startItr++;
250  }
251 
252  // Last bins are not smoothed
253  std::copy(startItr + medianBin, inputVec.end(), smoothVec.begin() + smoothBin);
254 
255  return;
256  }
257 
258  void WaveformTools::getTruncatedMeanRMS(const std::vector<double>& waveform,
259  double& mean,
260  double& rmsFull,
261  double& rmsTrunc,
262  int& nTrunc) const
263  {
264  getTruncatedMeanRMS<double>(waveform, mean, rmsFull, rmsTrunc, nTrunc);
265  }
266 
267  void WaveformTools::getTruncatedMeanRMS(const std::vector<float>& waveform,
268  float& mean,
269  float& rmsFull,
270  float& rmsTrunc,
271  int& nTrunc) const
272  {
273  getTruncatedMeanRMS<float>(waveform, mean, rmsFull, rmsTrunc, nTrunc);
274  }
275 
276  template <typename T>
277  void WaveformTools::getTruncatedMeanRMS(const std::vector<T>& waveform,
278  T& mean,
279  T& rmsFull,
280  T& rmsTrunc,
281  int& nTrunc) const
282  {
283  // We need to get a reliable estimate of the mean and can't assume the input waveform will be ~zero mean...
284  // Basic idea is to find the most probable value in the ROI presented to us
285  // From that we can develop an average of the true baseline of the ROI.
286  // To do that we employ a map based scheme
287  std::map<int, int> frequencyMap;
288  int mpCount(0);
289  int mpVal(0);
290 
291  for (const auto& val : waveform) {
292  int intVal = std::round(4. * val);
293 
294  frequencyMap[intVal]++;
295 
296  if (frequencyMap.at(intVal) > mpCount) {
297  mpCount = frequencyMap.at(intVal);
298  mpVal = intVal;
299  }
300  }
301 
302  // take a weighted average of two neighbor bins
303  int meanCnt = 0;
304  int meanSum = 0;
305  int binRange = std::min(16, int(frequencyMap.size() / 2 + 1));
306 
307  for (int idx = -binRange; idx <= binRange; idx++) {
308  std::map<int, int>::iterator neighborItr = frequencyMap.find(mpVal + idx);
309 
310  if (neighborItr != frequencyMap.end() && 5 * neighborItr->second > mpCount) {
311  meanSum += neighborItr->first * neighborItr->second;
312  meanCnt += neighborItr->second;
313  }
314  }
315 
316  mean = 0.25 * T(meanSum) / T(meanCnt); // Note that bins were expanded by a factor of 4 above
317 
318  // do rms calculation - the old fashioned way and over all adc values
319  typename std::vector<T> locWaveform = waveform;
320 
321  std::transform(locWaveform.begin(),
322  locWaveform.end(),
323  locWaveform.begin(),
324  std::bind(std::minus<T>(), std::placeholders::_1, mean));
325 
326  // sort in ascending order so we can truncate the sume
327  std::sort(locWaveform.begin(), locWaveform.end(), [](const auto& left, const auto& right) {
328  return std::fabs(left) < std::fabs(right);
329  });
330 
331  // recalculate the rms for truncation
332  rmsFull = std::inner_product(locWaveform.begin(), locWaveform.end(), locWaveform.begin(), 0.);
333  rmsFull = std::sqrt(std::max(T(0.), rmsFull / T(locWaveform.size())));
334 
335  // recalculate the rms for truncation
336  rmsTrunc = std::inner_product(
337  locWaveform.begin(), locWaveform.begin() + meanCnt, locWaveform.begin(), 0.);
338  rmsTrunc = std::sqrt(std::max(T(0.), rmsTrunc / T(meanCnt)));
339  nTrunc = meanCnt;
340 
341  return;
342  }
343 
344  void WaveformTools::firstDerivative(const std::vector<double>& inputVec,
345  std::vector<double>& derivVec) const
346  {
347  firstDerivative<double>(inputVec, derivVec);
348 
349  return;
350  }
351 
352  void WaveformTools::firstDerivative(const std::vector<float>& inputVec,
353  std::vector<float>& derivVec) const
354  {
355  firstDerivative<float>(inputVec, derivVec);
356 
357  return;
358  }
359 
360  template <typename T>
361  void WaveformTools::firstDerivative(const std::vector<T>& inputVec,
362  std::vector<T>& derivVec) const
363  {
364  derivVec.resize(inputVec.size(), 0.);
365 
366  for (size_t idx = 1; idx < derivVec.size() - 1; idx++)
367  derivVec.at(idx) = 0.5 * (inputVec.at(idx + 1) - inputVec.at(idx - 1));
368 
369  return;
370  }
371 
374  PeakTupleVec& peakTupleVec,
375  double threshold,
376  size_t firstTick) const
377  {
378  findPeaks<double>(startItr, stopItr, peakTupleVec, threshold, firstTick);
379 
380  return;
381  }
382 
385  PeakTupleVec& peakTupleVec,
386  float threshold,
387  size_t firstTick) const
388  {
389  findPeaks<float>(startItr, stopItr, peakTupleVec, threshold, firstTick);
390 
391  return;
392  }
393 
394  template <typename T>
396  typename std::vector<T>::iterator stopItr,
397  PeakTupleVec& peakTupleVec,
398  T threshold,
399  size_t firstTick) const
400  {
401  // Need a minimum distance or else nothing to do
402  if (std::distance(startItr, stopItr) > 4) {
403  // This is a divide and conquer algorithm, start by finding the maximum element.
404  typename std::vector<T>::iterator firstItr =
405  std::max_element(startItr, stopItr, [](float left, float right) {
406  return std::fabs(left) < std::fabs(right);
407  });
408 
409  // Are we over threshold?
410  if (std::fabs(*firstItr) > threshold) {
411  // What am I thinking?
412  // First task is to find the "other" lobe max point
413  // Set one to the "first", the other to the "second"
414  // Search backward from first to find start point, forward from second to find end point
415  // Set mid point between first and second as "peak"?
416  typename std::vector<T>::iterator secondItr = firstItr;
417 
418  // Assume if max bin is positive then second lobe is later
419  if (*firstItr > 0) {
420  typename std::vector<T>::iterator tempItr = secondItr;
421 
422  while (tempItr != stopItr) {
423  if (*++tempItr < -threshold) {
424  if (*tempItr < *secondItr) secondItr = tempItr;
425  }
426  else if (secondItr != firstItr)
427  break;
428  }
429  }
430  // Otherwise it goes the other way
431  else {
432  typename std::vector<T>::iterator tempItr = secondItr;
433 
434  while (tempItr != startItr) {
435  if (*--tempItr > threshold) {
436  if (*tempItr > *secondItr) secondItr = tempItr;
437  }
438  else if (secondItr != firstItr)
439  break;
440  }
441 
442  std::swap(firstItr, secondItr);
443  }
444 
445  // It might that no real pulse was found
446  if (firstItr != secondItr) {
447  // Get the "peak" position
448  size_t peakBin =
449  std::distance(startItr, firstItr) + std::distance(firstItr, secondItr) / 2;
450 
451  // Advance (forward or backward) the first and second iterators to get back to zero crossing
452  while (firstItr != startItr)
453  if (*--firstItr < 0.) break;
454  while (secondItr != stopItr)
455  if (*++secondItr > 0.) break;
456 
457  size_t firstBin = std::distance(startItr, firstItr);
458  size_t lastBin = std::distance(startItr, secondItr);
459 
460  // Find leading peaks
461  findPeaks(startItr, firstItr, peakTupleVec, threshold, firstTick);
462 
463  // Save this peak
464  peakTupleVec.push_back(
465  PeakTuple(firstBin + firstTick, peakBin + firstTick, lastBin + firstTick));
466 
467  // Find downstream peaks
468  findPeaks(secondItr,
469  stopItr,
470  peakTupleVec,
471  threshold,
472  firstTick + std::distance(startItr, secondItr));
473  }
474  }
475  }
476 
477  return;
478  }
479 
480  void WaveformTools::getFFTPower(const std::vector<float>& inputVec,
481  std::vector<float>& outputPowerVec) const
482  {
483  std::vector<double> inputDoubleVec(inputVec.size());
484  std::vector<double> outputDoubleVec(inputVec.size() / 2);
485 
486  std::copy(inputVec.begin(), inputVec.end(), inputDoubleVec.begin());
487 
488  getFFTPower(inputDoubleVec, outputDoubleVec);
489 
490  if (outputDoubleVec.size() != outputPowerVec.size())
491  outputPowerVec.resize(outputDoubleVec.size());
492 
493  std::copy(outputDoubleVec.begin(), outputDoubleVec.end(), outputPowerVec.begin());
494 
495  return;
496  }
497 
498  void WaveformTools::getFFTPower(const std::vector<double>& inputVec,
499  std::vector<double>& outputPowerVec) const
500  {
501  // Get the FFT of the response
502  int fftDataSize = inputVec.size();
503 
504  TVirtualFFT* fftr2c = TVirtualFFT::FFT(1, &fftDataSize, "R2C");
505 
506  fftr2c->SetPoints(inputVec.data());
507  fftr2c->Transform();
508 
509  // Recover the results so we can compute the power spectrum
510  size_t halfFFTDataSize(fftDataSize / 2 + 1);
511 
512  std::vector<double> realVals(halfFFTDataSize);
513  std::vector<double> imaginaryVals(halfFFTDataSize);
514 
515  fftr2c->GetPointsComplex(realVals.data(), imaginaryVals.data());
516 
517  if (outputPowerVec.size() != halfFFTDataSize) outputPowerVec.resize(halfFFTDataSize, 0.);
518 
519  std::transform(realVals.begin(),
520  realVals.begin() + halfFFTDataSize,
521  imaginaryVals.begin(),
522  outputPowerVec.begin(),
523  [](const double& real, const double& imaginary) {
524  return std::sqrt(real * real + imaginary * imaginary);
525  });
526 
527  return;
528  }
529 
531  int structuringElement,
532  HistogramMap& histogramMap,
533  Waveform<short>& erosionVec,
534  Waveform<short>& dilationVec,
535  Waveform<short>& averageVec,
536  Waveform<short>& differenceVec) const
537  {
538  getErosionDilationAverageDifference<short>(waveform,
539  structuringElement,
540  histogramMap,
541  erosionVec,
542  dilationVec,
543  averageVec,
544  differenceVec);
545 
546  return;
547  }
548 
550  int structuringElement,
551  HistogramMap& histogramMap,
552  Waveform<float>& erosionVec,
553  Waveform<float>& dilationVec,
554  Waveform<float>& averageVec,
555  Waveform<float>& differenceVec) const
556  {
557  getErosionDilationAverageDifference<float>(waveform,
558  structuringElement,
559  histogramMap,
560  erosionVec,
561  dilationVec,
562  averageVec,
563  differenceVec);
564 
565  return;
566  }
567 
569  int structuringElement,
570  HistogramMap& histogramMap,
571  Waveform<double>& erosionVec,
572  Waveform<double>& dilationVec,
573  Waveform<double>& averageVec,
574  Waveform<double>& differenceVec) const
575  {
576  getErosionDilationAverageDifference<double>(waveform,
577  structuringElement,
578  histogramMap,
579  erosionVec,
580  dilationVec,
581  averageVec,
582  differenceVec);
583 
584  return;
585  }
586 
587  template <typename T>
589  int structuringElement,
590  HistogramMap& histogramMap,
591  Waveform<T>& erosionVec,
592  Waveform<T>& dilationVec,
593  Waveform<T>& averageVec,
594  Waveform<T>& differenceVec) const
595  {
596  // Set the window size
597  int halfWindowSize(structuringElement / 2);
598 
599  // Initialize min and max elements
601  minMaxItr =
602  std::minmax_element(inputWaveform.begin(), inputWaveform.begin() + halfWindowSize);
603 
604  typename Waveform<T>::const_iterator minElementItr = minMaxItr.first;
605  typename Waveform<T>::const_iterator maxElementItr = minMaxItr.second;
606 
607  // Initialize the erosion and dilation vectors
608  erosionVec.resize(inputWaveform.size());
609  dilationVec.resize(inputWaveform.size());
610  averageVec.resize(inputWaveform.size());
611  differenceVec.resize(inputWaveform.size());
612 
613  // Now loop through remaining elements and complete the vectors
614  typename Waveform<T>::iterator minItr = erosionVec.begin();
615  typename Waveform<T>::iterator maxItr = dilationVec.begin();
616  typename Waveform<T>::iterator aveItr = averageVec.begin();
617  typename Waveform<T>::iterator difItr = differenceVec.begin();
618 
619  for (typename Waveform<T>::const_iterator inputItr = inputWaveform.begin();
620  inputItr != inputWaveform.end();
621  inputItr++) {
622  // There are two conditions to check:
623  // 1) is the current min/max element outside the current window?
624  // 2) is the new element smaller/larger than the current min/max?
625 
626  // Make sure we are not running off the end of the vector
627  if (std::distance(inputItr, inputWaveform.end()) > halfWindowSize) {
628  if (std::distance(minElementItr, inputItr) >= halfWindowSize)
629  minElementItr =
630  std::min_element(inputItr - halfWindowSize + 1, inputItr + halfWindowSize + 1);
631  else if (*(inputItr + halfWindowSize) < *minElementItr)
632  minElementItr = inputItr + halfWindowSize;
633 
634  if (std::distance(maxElementItr, inputItr) >= halfWindowSize)
635  maxElementItr =
636  std::max_element(inputItr - halfWindowSize + 1, inputItr + halfWindowSize + 1);
637  else if (*(inputItr + halfWindowSize) > *maxElementItr)
638  maxElementItr = inputItr + halfWindowSize;
639  }
640 
641  // Update the vectors
642  *minItr++ = *minElementItr;
643  *maxItr++ = *maxElementItr;
644  *aveItr++ = 0.5 * (*maxElementItr + *minElementItr);
645  *difItr++ = *maxElementItr - *minElementItr;
646 
647  if (!histogramMap.empty()) {
648  int curBin = std::distance(inputWaveform.begin(), inputItr);
649 
650  histogramMap.at(WAVEFORM)->Fill(curBin, *inputItr);
651  histogramMap.at(EROSION)->Fill(curBin, *minElementItr);
652  histogramMap.at(DILATION)->Fill(curBin, *maxElementItr);
653  histogramMap.at(AVERAGE)->Fill(curBin, 0.5 * (*maxElementItr + *minElementItr));
654  histogramMap.at(DIFFERENCE)->Fill(curBin, *maxElementItr - *minElementItr);
655  }
656  }
657 
658  return;
659  }
660 
662  const Waveform<short>& dilationVec,
663  int structuringElement,
664  HistogramMap& histogramMap,
665  Waveform<short>& openingVec,
666  Waveform<short>& closingVec) const
667  {
668  getOpeningAndClosing<short>(
669  erosionVec, dilationVec, structuringElement, histogramMap, openingVec, closingVec);
670 
671  return;
672  }
673 
675  const Waveform<float>& dilationVec,
676  int structuringElement,
677  HistogramMap& histogramMap,
678  Waveform<float>& openingVec,
679  Waveform<float>& closingVec) const
680  {
681  getOpeningAndClosing<float>(
682  erosionVec, dilationVec, structuringElement, histogramMap, openingVec, closingVec);
683 
684  return;
685  }
686 
688  const Waveform<double>& dilationVec,
689  int structuringElement,
690  HistogramMap& histogramMap,
691  Waveform<double>& openingVec,
692  Waveform<double>& closingVec) const
693  {
694  getOpeningAndClosing<double>(
695  erosionVec, dilationVec, structuringElement, histogramMap, openingVec, closingVec);
696 
697  return;
698  }
699 
700  template <typename T>
702  const Waveform<T>& dilationVec,
703  int structuringElement,
704  HistogramMap& histogramMap,
705  Waveform<T>& openingVec,
706  Waveform<T>& closingVec) const
707  {
708  // Set the window size
709  int halfWindowSize(structuringElement / 2);
710 
711  // Start with the opening, here we get the max element in the input erosion vector
712  typename Waveform<T>::const_iterator maxElementItr =
713  std::max_element(erosionVec.begin(), erosionVec.begin() + halfWindowSize);
714 
715  // Initialize the opening vector
716  openingVec.resize(erosionVec.size());
717 
718  // Now loop through remaining elements and complete the vectors
719  typename Waveform<T>::iterator maxItr = openingVec.begin();
720 
721  for (typename Waveform<T>::const_iterator inputItr = erosionVec.begin();
722  inputItr != erosionVec.end();
723  inputItr++) {
724  // There are two conditions to check:
725  // 1) is the current min/max element outside the current window?
726  // 2) is the new element smaller/larger than the current min/max?
727 
728  // Make sure we are not running off the end of the vector
729  if (std::distance(inputItr, erosionVec.end()) > halfWindowSize) {
730  if (std::distance(maxElementItr, inputItr) >= halfWindowSize)
731  maxElementItr =
732  std::max_element(inputItr - halfWindowSize + 1, inputItr + halfWindowSize + 1);
733  else if (*(inputItr + halfWindowSize) > *maxElementItr)
734  maxElementItr = inputItr + halfWindowSize;
735  }
736 
737  // Update the vectors
738  *maxItr++ = *maxElementItr;
739 
740  if (!histogramMap.empty()) {
741  int curBin = std::distance(erosionVec.begin(), inputItr);
742 
743  histogramMap.at(OPENING)->Fill(curBin, *maxElementItr);
744  }
745  }
746 
747  // Now go with the closling, here we get the min element in the input dilation vector
748  typename Waveform<T>::const_iterator minElementItr =
749  std::min_element(dilationVec.begin(), dilationVec.begin() + halfWindowSize);
750 
751  // Initialize the opening and closing vectors
752  closingVec.resize(dilationVec.size());
753 
754  // Now loop through remaining elements and complete the vectors
755  typename Waveform<T>::iterator minItr = closingVec.begin();
756 
757  for (typename Waveform<T>::const_iterator inputItr = dilationVec.begin();
758  inputItr != dilationVec.end();
759  inputItr++) {
760  // There are two conditions to check:
761  // 1) is the current min/max element outside the current window?
762  // 2) is the new element smaller/larger than the current min/max?
763 
764  // Make sure we are not running off the end of the vector
765  if (std::distance(inputItr, dilationVec.end()) > halfWindowSize) {
766  if (std::distance(minElementItr, inputItr) >= halfWindowSize)
767  minElementItr =
768  std::min_element(inputItr - halfWindowSize + 1, inputItr + halfWindowSize + 1);
769  else if (*(inputItr + halfWindowSize) < *minElementItr)
770  minElementItr = inputItr + halfWindowSize;
771  }
772 
773  // Update the vectors
774  *minItr++ = *minElementItr;
775 
776  if (!histogramMap.empty()) {
777  int curBin = std::distance(dilationVec.begin(), inputItr);
778 
779  histogramMap.at(CLOSING)->Fill(curBin, *minElementItr);
780  histogramMap.at(DOPENCLOSING)->Fill(curBin, *minElementItr - openingVec.at(curBin));
781  }
782  }
783 
784  return;
785  }
786 
788 }
intermediate_table::iterator iterator
void medianSmooth(const std::vector< float > &, std::vector< float > &, size_t=3) const override
WaveformTools(const fhicl::ParameterSet &pset)
constexpr auto const & right(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:102
#define DEFINE_ART_CLASS_TOOL(tool)
Definition: ToolMacros.h:42
void configure(const fhicl::ParameterSet &pset) override
void getErosionDilationAverageDifference(const Waveform< short > &, int, HistogramMap &, Waveform< short > &, Waveform< short > &, Waveform< short > &, Waveform< short > &) const override
std::vector< T > Waveform
Definition: IWaveformTool.h:27
void getOpeningAndClosing(const Waveform< short > &, const Waveform< short > &, int, HistogramMap &, Waveform< short > &, Waveform< short > &) const override
This is the interface class for tools/algorithms that perform various operations on waveforms...
void findPeaks(std::vector< float >::iterator, std::vector< float >::iterator, PeakTupleVec &, float, size_t) const override
std::vector< PeakTuple > PeakTupleVec
Definition: IWaveformTool.h:51
intermediate_table::const_iterator const_iterator
void triangleSmooth(const std::vector< float > &, std::vector< float > &, size_t=0) const override
void firstDerivative(const std::vector< float > &, std::vector< float > &) const override
void getFFTPower(const std::vector< float > &inputVec, std::vector< float > &outputPowerVec) const override
std::map< int, TProfile * > HistogramMap
Definition: IWaveformTool.h:42
constexpr auto const & left(const_AssnsIter< L, R, D, Dir > const &a, const_AssnsIter< L, R, D, Dir > const &b)
Definition: AssnsIter.h:94
double mean(const std::vector< short > &wf, size_t start, size_t nsample)
Definition: UtilFunc.cxx:13
std::tuple< size_t, size_t, size_t > PeakTuple
Definition: IWaveformTool.h:50
std::tuple< size_t, size_t, size_t > PeakTuple
void getTruncatedMeanRMS(const std::vector< double > &, double &, double &, double &, int &) const override