All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ROIFinderMorphological_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file ROIFinderMorphological.cc
3 /// \author T. Usher
4 ////////////////////////////////////////////////////////////////////////
5 
6 #include <cmath>
8 #include "art/Utilities/ToolMacros.h"
9 #include "art/Utilities/make_tool.h"
10 #include "art_root_io/TFileService.h"
11 #include "messagefacility/MessageLogger/MessageLogger.h"
12 #include "cetlib_except/exception.h"
15 #include "larcore/CoreUtils/ServiceUtil.h" // lar::providerFrom()
16 #include "icarus_signal_processing/WaveformTools.h"
17 
18 #include "TH1F.h"
19 #include "TH2F.h"
20 #include "TProfile.h"
21 
22 #include <fstream>
23 
24 namespace icarus_tool
25 {
26 
28 {
29 public:
30  explicit ROIFinderMorphological(const fhicl::ParameterSet& pset);
31 
33 
34  void configure(const fhicl::ParameterSet& pset) override;
35  void initializeHistograms(art::TFileDirectory&) const override;
36  size_t plane() const override {return fPlane;}
37 
38  void FindROIs(const Waveform&, size_t, size_t, double, CandidateROIVec&) const override;
39 
40 private:
41  // The actual ROI finding algorithm based on the difference vec
43  const Waveform&,
44  const Waveform&,
45  int,
46  int,
47  float,
48  CandidateROIVec&) const;
49 
50  // The actual ROI finding algorithm based on the dilation vec
52  const Waveform&,
53  const Waveform&,
54  int,
55  int,
56  float,
57  CandidateROIVec&) const;
58 
59  // Average the input waveform
60  void smoothInputWaveform(const Waveform&, Waveform&) const;
61 
62  // Actual histogram initialization...
63  enum HistogramType : int
64  {
69  };
70 
71  icarus_tool::HistogramMap initializeHistograms(size_t, size_t, size_t) const;
72 
73  // Member variables from the fhicl file
74  size_t fPlane; ///< Tool can be plane dependent
75  bool fUseDifference; ///< If true use differences, else dilation
76  float fNumSigma; ///< "# sigma" rms noise for ROI threshold
77  int fNumBinsToAve; ///< Controls the smoothing
78  int fMax2MinDistance; ///< Minimum allow peak to peak distance
79  float fMax2MinHeight; ///< Minimum peak to peak height (box cut)
80  int fMaxLengthCut; ///< Minimum length of the maximum
81  int fStructuringElement; ///< The window size
82  unsigned short fPreROIPad; ///< ROI padding
83  unsigned short fPostROIPad; ///< ROI padding
84  unsigned short fMaxPadLen; ///< Don't let padding be larger than this
85  bool fOutputHistograms; ///< Output histograms?
86  bool fOutputWaveforms; ///< Output waveforms?
87 
88  std::vector<float> fAveWeightVec; ///< Weight vector for smoothing
89  float fWeightSum; ///< sum of weights for smoothing
90 
91  art::TFileDirectory* fHistDirectory;
92 
93  // Global histograms
95  TH1F* fDiffRmsHist;
98  TH1F* fDiffMaxHist;
107 
108  icarus_signal_processing::WaveformTools<float> fWaveformTool;
109 
110  // Services
111  const geo::GeometryCore* fGeometry = lar::providerFrom<geo::Geometry>();
112 };
113 
114 //----------------------------------------------------------------------
115 // Constructor.
116 ROIFinderMorphological::ROIFinderMorphological(const fhicl::ParameterSet& pset)
117 {
118  configure(pset);
119 }
120 
122 {
123 }
124 
125 void ROIFinderMorphological::configure(const fhicl::ParameterSet& pset)
126 {
127  // Start by recovering the parameters
128  std::vector<unsigned short> zin;
129 
130  fPlane = pset.get< size_t >("Plane" );
131  fUseDifference = pset.get< bool >("UseDifference", true);
132  fNumSigma = pset.get< float >("NumSigma" );
133  fNumBinsToAve = pset.get< int >("NumBinsToAve" );
134  fMax2MinDistance = pset.get< int >("Max2MinDistance" );
135  fMax2MinHeight = pset.get< int >("Max2MinHeight" );
136  fMaxLengthCut = pset.get< int >("MaxLengthCut" );
137  fStructuringElement = pset.get< int >("StructuringElement" );
138  zin = pset.get< std::vector<unsigned short>>("roiLeadTrailPad" );
139  fMaxPadLen = pset.get< unsigned short >("MaxPadLen", 200);
140  fOutputHistograms = pset.get< bool >("OutputHistograms", false);
141  fOutputWaveforms = pset.get< bool >("OutputWaveforms", false);
142 
143  if(zin.size() != 2) {
144  throw art::Exception(art::errors::Configuration)
145  << "Plane ROI pad size != 2";
146  }
147 
148  // put the ROI pad sizes into more variables
149  fPreROIPad = zin[0];
150  fPostROIPad = zin[1];
151 
152  // If asked, define the global histograms
153  if (fOutputHistograms)
154  {
155  // Access ART's TFileService, which will handle creating and writing
156  // histograms and n-tuples for us.
157  art::ServiceHandle<art::TFileService> tfs;
158 
159  fHistDirectory = tfs.get();
160 
161  // Make a directory for these histograms
162  art::TFileDirectory dir = fHistDirectory->mkdir(Form("ROIPlane_%1zu",fPlane));
163 
164  fDiffMeanHist = dir.make<TH1F>("DiffMean", ";Diff Mean;", 100, -20., 20.);
165  fDiffRmsHist = dir.make<TH1F>("DiffRms", ";Diff RMS;", 200, 0., 10.);
166  fDiffFullRmsHist = dir.make<TH1F>("DiffFRms", ";Diff RMS;", 200, 0., 10.);
167  fDTruncBinsHist = dir.make<TH1F>("DTruncBn", "D trunc B", 500, 0., 1000.);
168  fDiffMaxHist = dir.make<TH1F>("DiffMax", ";Diff Max;", 200, 0., 200.);
169  fNumSigmaHist = dir.make<TH1F>("NSigma", ";#sigma;", 200, 0., 40.);
170  fThresholdHist = dir.make<TH1F>("Threshold", ";Threshold;", 200, 0., 40.);
171  fNumSigNextHist = dir.make<TH1F>("NSigNext", ";#sigma;", 200, 0., 50.);
172  fMaxDiffLength = dir.make<TH1F>("MaxLength", ";Delta t", 200, 0., 200.);
173  fDeltaTicksHist = dir.make<TH1F>("DeltaTix", ";Delta t", 200, 0., 200.);
174 
175  fDTixVDLenHist = dir.make<TH2F>("DTixVDLen", ";Delta t;DLength", 100, 0., 100., 100, 0., 100.);
176  fDTixVDiffHist = dir.make<TH2F>("DTixVDiff", ";Delta t;Max Diff", 100, 0., 100., 100, 0., 100.);
177  fDiffVDilHist = dir.make<TH2F>("DiffVDil", ";Max Diff;Max Dilation", 100, 0., 200., 100, 0., 200.);
178  }
179 
180  // precalculate the weight vector to use in the smoothing
181  fAveWeightVec.resize(fNumBinsToAve);
182 
183  if (fNumBinsToAve > 1)
184  {
185  for(int idx = 0; idx < fNumBinsToAve/2; idx++)
186  {
187  float weight = idx + 1;
188 
189  fAveWeightVec.at(idx) = weight;
190  fAveWeightVec.at(fNumBinsToAve - idx - 1) = weight;
191  }
192 
193  // Watch for case of fNumBinsToAve being odd
194  if (fNumBinsToAve % 2 > 0) fAveWeightVec.at(fNumBinsToAve/2) = fNumBinsToAve/2 + 1;
195  }
196  else fAveWeightVec.at(0) = 1.;
197 
198  fWeightSum = std::accumulate(fAveWeightVec.begin(),fAveWeightVec.end(), 0.);
199 
200  return;
201 }
202 
203 void ROIFinderMorphological::FindROIs(const Waveform& waveform, size_t channel, size_t cnt, double rmsNoise, CandidateROIVec& roiVec) const
204 {
205  // The idea here is to consider the input waveform - if an induction plane then it is already in differential form,
206  // if a collection plane then we form the differential - then smooth and look for ROIs. The technique for actually
207  // finding ROI's will be to compute the erosion and dilation vectors, get their average/difference and then use these to determine
208  // candidate ROI's
209 
210  // Smooth the input waveform
211  Waveform smoothWaveform;
212 
213  smoothInputWaveform(waveform, smoothWaveform);
214 
215  // We make lots of vectors... erosion, dilation, average and difference
216  Waveform erosionVec;
217  Waveform dilationVec;
218  Waveform averageVec;
219  Waveform differenceVec;
220 
221  // Compute the morphological filter vectors
222  fWaveformTool.getErosionDilationAverageDifference(smoothWaveform, fStructuringElement, erosionVec, dilationVec, averageVec, differenceVec);
223 
224  // Use the average vector to find ROI's
225  float fullRMS;
226  float truncRMS;
227  float truncMean;
228  float nSig(2.5);
229  int nTrunc;
230  int range;
231 
232  if (fUseDifference)
233  {
234  Waveform zeroSuppressed(differenceVec.size());
235 
236  fWaveformTool.getTruncatedMean(differenceVec, truncMean, nTrunc, range);
237 
238  std::transform(differenceVec.begin(),differenceVec.end(),zeroSuppressed.begin(),[truncMean](auto& val){return val - truncMean;});
239 
240  fWaveformTool.getTruncatedRMS(zeroSuppressed, nSig, fullRMS, truncRMS, nTrunc);
241  }
242  else
243  {
244  Waveform zeroSuppressed(dilationVec.size());
245 
246  fWaveformTool.getTruncatedMean(dilationVec, truncMean, nTrunc, range);
247 
248  std::transform(dilationVec.begin(),dilationVec.end(),zeroSuppressed.begin(),[truncMean](auto& val){return val - truncMean;});
249 
250  fWaveformTool.getTruncatedRMS(zeroSuppressed, nSig, fullRMS, truncRMS, nTrunc);
251  }
252 
253  // Calculate a threshold to use based on the truncated mand and rms...
254  float threshold = truncMean + fNumSigma * std::max(float(0.02),truncRMS);
255 
256  // Define the histogram map which will be referenced later
257  icarus_tool::HistogramMap histogramMap;
258 
259  if (fOutputWaveforms)
260  {
261  // Define histograms for this particular channel?
262  histogramMap = initializeHistograms(channel, cnt, waveform.size());
263 
264  for(size_t curBin = 0; curBin < waveform.size(); curBin++)
265  {
266  histogramMap.at(WAVEFORMHIST)->Fill( curBin, waveform[curBin], 1.);
267  histogramMap.at(WAVEFORM)->Fill( curBin, smoothWaveform[curBin], 1.);
268  histogramMap.at(EROSION)->Fill( curBin, erosionVec[curBin], 1.);
269  histogramMap.at(DILATION)->Fill( curBin, dilationVec[curBin], 1.);
270  histogramMap.at(AVERAGE)->Fill( curBin, averageVec[curBin], 1.);
271  histogramMap.at(DIFFERENCE)->Fill( curBin, differenceVec[curBin], 1.);
272  histogramMap.at(TRUNCMEANHIST)->Fill(curBin, truncMean, 1.);
273  histogramMap.at(TRUNCRMSHIST)->Fill( curBin, threshold, 1.);
274  }
275  }
276 
277  // If histogramming, do the global hists here
278  if (fOutputHistograms)
279  {
280  Waveform::iterator maxItr;
281 
282  if (fUseDifference) maxItr = std::max_element(differenceVec.begin(),differenceVec.end());
283  else maxItr = std::max_element(dilationVec.begin(),dilationVec.end());
284 
285  float maxDiff = *maxItr;
286  float nSigma = (maxDiff - truncMean) / std::max(float(0.5),truncRMS);
287  int dTruncBins = int(differenceVec.size()) - nTrunc;
288 
289  fDiffMeanHist->Fill(truncMean, 1.);
290  fDiffRmsHist->Fill(truncRMS, 1.);
291  fDiffFullRmsHist->Fill(fullRMS, 1.);
292  fDTruncBinsHist->Fill(std::min(dTruncBins,999), 1.);
293  fDiffMaxHist->Fill(maxDiff, 1.);
294  fNumSigmaHist->Fill(std::min(nSigma,float(39.9)), 1.);
295  fThresholdHist->Fill(std::min(threshold,float(39.9)), 1.);
296 
297  if (fUseDifference)
298  {
299  if (std::distance(differenceVec.begin(),maxItr) > 4 * fStructuringElement)
300  {
301  maxDiff = *std::max_element(differenceVec.begin(),maxItr-4*fStructuringElement);
302  nSigma = (maxDiff - truncMean) / std::max(float(0.5),truncRMS);
303 
304  fNumSigNextHist->Fill(nSigma, 1.);
305  }
306 
307  if (std::distance(maxItr, differenceVec.end()) > 4 * fStructuringElement)
308  {
309  maxDiff = *std::max_element(maxItr+4*fStructuringElement,differenceVec.end());
310  nSigma = (maxDiff - truncMean) / std::max(float(0.5),truncRMS);
311 
312  fNumSigNextHist->Fill(nSigma, 1.);
313  }
314  }
315  else
316  {
317  if (std::distance(dilationVec.begin(),maxItr) > 4 * fStructuringElement)
318  {
319  maxDiff = *std::max_element(dilationVec.begin(),maxItr-4*fStructuringElement);
320  nSigma = (maxDiff - truncMean) / std::max(float(0.5),truncRMS);
321 
322  fNumSigNextHist->Fill(nSigma, 1.);
323  }
324 
325  if (std::distance(maxItr, dilationVec.end()) > 4 * fStructuringElement)
326  {
327  maxDiff = *std::max_element(maxItr+4*fStructuringElement,dilationVec.end());
328  nSigma = (maxDiff - truncMean) / std::max(float(0.5),truncRMS);
329 
330  fNumSigNextHist->Fill(nSigma, 1.);
331  }
332  }
333  }
334 
335  if (fUseDifference) findROICandidatesDifference(differenceVec, erosionVec, dilationVec, 0, averageVec.size(), threshold, roiVec);
336  else findROICandidatesDilation( differenceVec, erosionVec, dilationVec, 0, averageVec.size(), threshold, roiVec);
337 
338  if (roiVec.empty()) return;
339 
340  // pad the ROIs
341  for(auto& roi : roiVec)
342  {
343  if (!histogramMap.empty())
344  {
345  histogramMap.at(ROIHISTOGRAM)->Fill(int(roi.first), std::max(5.*truncRMS,1.));
346  histogramMap.at(ROIHISTOGRAM)->Fill(int(roi.second), std::max(5.*truncRMS,1.));
347  }
348 
349  // For longer than normal pulse trains we could use a bit extra padding
350  unsigned short halfROILen = (roi.second - roi.first) / 2;
351  unsigned short preROIPad = std::min(std::max(fPreROIPad,halfROILen),fMaxPadLen);
352  unsigned short postROIPad = std::min(std::max(fPostROIPad,halfROILen),fMaxPadLen);
353 
354  // low ROI end
355  roi.first = std::max(int(roi.first - preROIPad),0);
356  // high ROI end
357  roi.second = std::min(roi.second + postROIPad, waveform.size() - 1);
358  }
359 
360  // merge overlapping (or touching) ROI's
361  if(roiVec.size() > 1)
362  {
363  // temporary vector for merged ROIs
364  CandidateROIVec tempRoiVec;
365 
366  // Loop through candidate roi's
367  size_t startRoi = roiVec.front().first;
368  size_t stopRoi = startRoi;
369 
370  for(auto& roi : roiVec)
371  {
372  // Should we merge roi's?
373  if (roi.first <= stopRoi + 50)
374  {
375  // Make sure the merge gets the right start/end times
376  startRoi = std::min(startRoi,roi.first);
377  stopRoi = std::max(stopRoi,roi.second);
378  }
379  else
380  {
381  tempRoiVec.push_back(CandidateROI(startRoi,stopRoi));
382 
383  startRoi = roi.first;
384  stopRoi = roi.second;
385  }
386  }
387 
388  // Make sure to get the last one
389  tempRoiVec.push_back(CandidateROI(startRoi,stopRoi));
390 
391  roiVec = tempRoiVec;
392  }
393 
394  return;
395 }
396 
398  const Waveform& erosionVec,
399  const Waveform& dilationVec,
400  int startTick,
401  int stopTick,
402  float threshold,
403  CandidateROIVec& roiCandidateVec) const
404 {
405  int roiLength = stopTick - startTick;
406 
407  if (roiLength > 0)
408  {
409  // The idea here is to find the difference and use that as the seed for searching the
410  // erosion and dilation vectors for the end points
411  Waveform::const_iterator maxItr = std::max_element(differenceVec.begin()+startTick,differenceVec.begin()+stopTick);
412 
413  int maxTick = std::distance(differenceVec.begin(),maxItr);
414  float maxDifference = *maxItr;
415 
416  // Accomodate a special case of slowly rising waveforms where the difference will be under threshold but we
417  // do have a definite region of interest
418  float dilationVal = dilationVec[maxTick];
419 
420  // No point continuing if not over threshold
421  if (maxDifference > threshold || dilationVal > threshold)
422  {
423  // move forward to find the length of the top
424  while(*maxItr == maxDifference) maxItr++;
425 
426  int deltaTicks = std::distance(differenceVec.begin(),maxItr) - maxTick;
427 
428  // Start by finding maximum range of the erosion vector at this extremum
429  int maxCandRoiTick = maxTick;
430 
431  // The test on the erosion vector takes care of special case of slowly rising pulses which are characteristic of
432  // tracks running into the wire plane
433  while(++maxCandRoiTick < stopTick)
434  {
435  float difference = differenceVec.at(maxCandRoiTick);
436  float erosion = erosionVec.at(maxCandRoiTick);
437 
438  if (difference < threshold && erosion < 0.5 * threshold) break;
439  }
440 
441  maxCandRoiTick = std::min(maxCandRoiTick,stopTick);
442 
443  // Now do the dilation vector
444  int minCandRoiTick = maxTick;
445 
446  while(--minCandRoiTick >= startTick)
447  {
448  float difference = differenceVec.at(minCandRoiTick);
449  float erosion = erosionVec.at(minCandRoiTick);
450 
451  if (difference < threshold && erosion < 0.5 * threshold) break;
452  }
453 
454  // make sure we have not gone under
455  minCandRoiTick = std::max(minCandRoiTick, startTick);
456 
457  int max2MinDiff = maxCandRoiTick - minCandRoiTick;
458 
459  if (fOutputHistograms && !(startTick > 0 || stopTick < int(differenceVec.size())))
460  {
461  float maxDilation = *std::max_element(dilationVec.begin() + minCandRoiTick, dilationVec.begin() + maxCandRoiTick);
462 
463  fMaxDiffLength->Fill(std::min(deltaTicks,199), 1.);
464  fDeltaTicksHist->Fill(max2MinDiff, 1.);
465  fDTixVDLenHist->Fill(max2MinDiff, deltaTicks, 1.);
466  fDTixVDiffHist->Fill(max2MinDiff, maxDifference, 1.);
467  fDiffVDilHist->Fill(maxDifference, maxDilation, 1.);
468  }
469 
470  // Make sure we have a legitimate candidate
471  if ((max2MinDiff > fMax2MinDistance || maxDifference > fMax2MinHeight) && deltaTicks > fMaxLengthCut)
472  {
473  // Before saving this ROI, look for candidates preceeding this one
474  // Note that preceeding snippet will reference to the current roiStartTick
475  findROICandidatesDifference(differenceVec, erosionVec, dilationVec, startTick, minCandRoiTick, threshold, roiCandidateVec);
476 
477  // Save this ROI
478  roiCandidateVec.push_back(CandidateROI(minCandRoiTick, maxCandRoiTick));
479 
480  // Now look for candidate ROI's downstream of this one
481  findROICandidatesDifference(differenceVec, erosionVec, dilationVec, maxCandRoiTick+1, stopTick, threshold, roiCandidateVec);
482  }
483  }
484  }
485 
486  return;
487 }
488 
489 
491  const Waveform& erosionVec,
492  const Waveform& dilationVec,
493  int startTick,
494  int stopTick,
495  float threshold,
496  CandidateROIVec& roiCandidateVec) const
497 {
498  int roiLength = stopTick - startTick;
499 
500  if (roiLength > 0)
501  {
502  // The idea here is to find the difference and use that as the seed for searching the
503  // erosion and dilation vectors for the end points
504  //Waveform::const_iterator maxItr = std::max_element(differenceVec.begin()+startTick,differenceVec.begin()+stopTick,[](const auto& left, const auto& right){return std::fabs(left) < std::fabs(right);});
505  Waveform::const_iterator maxItr = std::max_element(dilationVec.begin()+startTick,dilationVec.begin()+stopTick);
506 
507  int maxTick = std::distance(dilationVec.begin(),maxItr);
508  float maxDilation = *maxItr;
509 
510  // move forward to find the length of the top
511  while(*maxItr == maxDilation) maxItr++;
512 
513  int deltaTicks = std::distance(dilationVec.begin(),maxItr) - maxTick;
514 
515  // No point continuing if not over threshold
516  if (maxDilation > threshold)
517  {
518  // Start by finding maximum range of the erosion vector at this extremum
519  int maxCandRoiTick = std::distance(dilationVec.begin(),maxItr);
520 
521  // The test on the erosion vector takes care of special case of slowly rising pulses which are characteristic of
522  // tracks running into the wire plane
523  while(++maxCandRoiTick < stopTick)
524  {
525  float dilation = dilationVec.at(maxCandRoiTick);
526  float erosion = erosionVec.at(maxCandRoiTick);
527 
528  if (dilation < threshold && erosion < 0.5 * threshold) break;
529  }
530 
531  maxCandRoiTick = std::min(maxCandRoiTick,stopTick);
532 
533  // Now do the dilation vector
534  int minCandRoiTick = maxTick;
535 
536  while(--minCandRoiTick >= startTick)
537  {
538  float dilation = dilationVec.at(minCandRoiTick);
539  float erosion = erosionVec.at(minCandRoiTick);
540 
541  if (dilation < threshold && erosion < 0.5 * threshold) break;
542  }
543 
544  // make sure we have not gone under
545  minCandRoiTick = std::max(minCandRoiTick, startTick);
546 
547  int max2MinDiff = maxCandRoiTick - minCandRoiTick;
548 
549  if (fOutputHistograms && !(startTick > 0 || stopTick < int(dilationVec.size())))
550  {
551  float maxDifference = *std::max_element(differenceVec.begin() + minCandRoiTick, differenceVec.begin() + maxCandRoiTick);
552 
553  fMaxDiffLength->Fill(std::min(deltaTicks,199), 1.);
554  fDeltaTicksHist->Fill(max2MinDiff, 1.);
555  fDTixVDLenHist->Fill(max2MinDiff, deltaTicks, 1.);
556  fDTixVDiffHist->Fill(max2MinDiff, maxDilation, 1.);
557  fDiffVDilHist->Fill(maxDifference, maxDilation, 1.);
558  }
559 
560  // Make sure we have a legitimate candidate
561  if ((max2MinDiff > fMax2MinDistance || maxDilation > fMax2MinHeight) && deltaTicks > fMaxLengthCut)
562  {
563  // Before saving this ROI, look for candidates preceeding this one
564  // Note that preceeding snippet will reference to the current roiStartTick
565  findROICandidatesDilation(differenceVec, erosionVec, dilationVec, startTick, minCandRoiTick, threshold, roiCandidateVec);
566 
567  // Save this ROI
568  roiCandidateVec.push_back(CandidateROI(minCandRoiTick, maxCandRoiTick));
569 
570  // Now look for candidate ROI's downstream of this one
571  findROICandidatesDilation(differenceVec, erosionVec, dilationVec, maxCandRoiTick+1, stopTick, threshold, roiCandidateVec);
572  }
573  }
574  }
575 
576  return;
577 }
578 
579 void ROIFinderMorphological::smoothInputWaveform(const Waveform& inputWaveform, Waveform& outputWaveform) const
580 {
581  // Vector smoothing - take the 10 bin average
582  int halfBins = fNumBinsToAve / 2;
583 
584  outputWaveform.resize(inputWaveform.size());
585 
586  // Make sure smoothing makes sense
587  if (halfBins > 0)
588  {
589  // To facilitate handling the bins at the ends of the input waveform we embed in a slightly larger
590  // vector which has zeroes on the ends
591  Waveform tempWaveform(inputWaveform.size()+fNumBinsToAve);
592 
593  // Set the edge bins which can't be smoothed to zero
594  std::fill(tempWaveform.begin(),tempWaveform.begin()+halfBins,0.);
595  std::fill(tempWaveform.end()-halfBins,tempWaveform.end(),0.);
596 
597  // Copy in the input waveform
598  std::copy(inputWaveform.begin(),inputWaveform.end(),tempWaveform.begin()+halfBins);
599 
600  // Now do the smoothing
601  for(size_t idx = 0; idx < inputWaveform.size(); idx++)
602  {
603  float weightedSum(0.);
604 
605  for(int wIdx = 0; wIdx < fNumBinsToAve; wIdx++) weightedSum += fAveWeightVec.at(wIdx) * tempWaveform.at(idx + wIdx);
606 
607  outputWaveform.at(idx) = weightedSum / fWeightSum;
608  }
609  }
610  else std::copy(inputWaveform.begin(),inputWaveform.end(),outputWaveform.begin());
611 
612  return;
613 }
614 
615 void ROIFinderMorphological::initializeHistograms(art::TFileDirectory& histDir) const
616 {
617  // It is assumed that the input TFileDirectory has been set up to group histograms into a common
618  // folder at the calling routine's level. Here we create one more level of indirection to keep
619  // histograms made by this tool separate.
620 /*
621  std::string dirName = "ROIFinderPlane_" + std::to_string(fPlane);
622 
623  art::TFileDirectory dir = histDir.mkdir(dirName.c_str());
624 
625  auto const* detprop = lar::providerFrom<detinfo::DetectorPropertiesService>();
626  double samplingRate = detprop->SamplingRate();
627  double numBins = fROIFinderVec.size();
628  double maxFreq = 500. / samplingRate;
629  std::string histName = "ROIFinderPlane_" + std::to_string(fPlane);
630 
631  TH1D* hist = dir.make<TH1D>(histName.c_str(), "ROIFinder;Frequency(MHz)", numBins, 0., maxFreq);
632 
633  for(int bin = 0; bin < numBins; bin++)
634  {
635  double freq = maxFreq * double(bin + 0.5) / double(numBins);
636 
637  hist->Fill(freq, fROIFinderVec.at(bin).Re());
638  }
639 */
640 
641  return;
642 }
643 
644 icarus_tool::HistogramMap ROIFinderMorphological::initializeHistograms(size_t channel, size_t cnt, size_t waveformSize) const
645 {
646  icarus_tool::HistogramMap histogramMap;
647 
648  if (fOutputWaveforms)
649  {
650  // Try to limit to the wire number (since we are already segregated by plane)
651  std::vector<geo::WireID> wids = fGeometry->ChannelToWire(channel);
652  size_t cryo = wids[0].Cryostat;
653  size_t tpc = wids[0].TPC;
654 // size_t plane = wids[0].Plane;
655  size_t wire = wids[0].Wire;
656 
657  // Make a directory for these histograms
658  art::TFileDirectory dir = fHistDirectory->mkdir(Form("Event_%03zu/C%1zuT%1zuP%1zu/Wire_%05zu",cnt,cryo,tpc,fPlane,wire));
659 
660  // We keep track of four histograms:
661  try
662  {
663  histogramMap[icarus_tool::WAVEFORM] =
664  dir.make<TProfile>("SmoothWaveform", "Waveform", waveformSize, 0, waveformSize, -500., 500.);
665  histogramMap[icarus_tool::EROSION] =
666  dir.make<TProfile>("Erosion", "Erosion", waveformSize, 0, waveformSize, -500., 500.);
667  histogramMap[icarus_tool::DILATION] =
668  dir.make<TProfile>("Dilation", "Dilation", waveformSize, 0, waveformSize, -500., 500.);
669  histogramMap[icarus_tool::AVERAGE] =
670  dir.make<TProfile>("Average", "Average", waveformSize, 0, waveformSize, -500., 500.);
671  histogramMap[icarus_tool::DIFFERENCE] =
672  dir.make<TProfile>("Difference", "Difference", waveformSize, 0, waveformSize, -500., 500.);
673 
674  // This is a kludge so that the ROI histogram ends up in the same diretory as the waveforms
675  histogramMap[ROIHISTOGRAM] =
676  dir.make<TProfile>("ROI", "ROI", waveformSize, 0, waveformSize, -500., 500.);
677 
678  // Keep kludging so we can see the truncated mean and threshold that gets applied
679  histogramMap[TRUNCMEANHIST] =
680  dir.make<TProfile>("TruncatedMean", "Truncated Mean", waveformSize, 0, waveformSize, -500., 500.);
681  histogramMap[TRUNCRMSHIST] =
682  dir.make<TProfile>("TruncatedRMS", "Truncated rms", waveformSize, 0, waveformSize, -500., 500.);
683 
684  // Also, if smoothing then we would like to keep track of the original waveform too
685  histogramMap[WAVEFORMHIST] =
686  dir.make<TProfile>("InputWaveform", "Waveform", waveformSize, 0, waveformSize, -500., 500.);
687  } catch(...)
688  {
689  std::cout << "Caught exception trying to make new hists, tpc,plane,cnt,wire: " << tpc << ", " << fPlane << ", " << cnt << ", " << wire << std::endl;
690  }
691  }
692 
693  return histogramMap;
694 }
695 
696 DEFINE_ART_CLASS_TOOL(ROIFinderMorphological)
697 }
Utilities related to art service access.
static constexpr Sample_t transform(Sample_t sample)
float fMax2MinHeight
Minimum peak to peak height (box cut)
void FindROIs(const Waveform &, size_t, size_t, double, CandidateROIVec &) const override
ROIFinderMorphological(const fhicl::ParameterSet &pset)
int fMaxLengthCut
Minimum length of the maximum.
std::vector< geo::WireID > ChannelToWire(raw::ChannelID_t const channel) const
Returns a list of wires connected to the specified TPC channel.
float fWeightSum
sum of weights for smoothing
void initializeHistograms(art::TFileDirectory &) const override
unsigned short fMaxPadLen
Don&#39;t let padding be larger than this.
icarus_signal_processing::WaveformTools< float > fWaveformTool
double distance(geo::Point_t const &point, CathodeDesc_t const &cathode)
Returns the distance of a point from the cathode.
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
Description of geometry of one entire detector.
int fMax2MinDistance
Minimum allow peak to peak distance.
tuple dir
Definition: dropbox.py:28
float fNumSigma
&quot;# sigma&quot; rms noise for ROI threshold
void findROICandidatesDifference(const Waveform &, const Waveform &, const Waveform &, int, int, float, CandidateROIVec &) const
void smoothInputWaveform(const Waveform &, Waveform &) const
void configure(const fhicl::ParameterSet &pset) override
void findROICandidatesDilation(const Waveform &, const Waveform &, const Waveform &, int, int, float, CandidateROIVec &) const
T copy(T const &v)
bool fUseDifference
If true use differences, else dilation.
std::vector< float > fAveWeightVec
Weight vector for smoothing.
art::ServiceHandle< art::TFileService > tfs
size_t fPlane
Tool can be plane dependent.
art framework interface to geometry description
BEGIN_PROLOG could also be cout