All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
ROIMorphological2D_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file ROIMorphological2D.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 "icarus_signal_processing/WaveformTools.h"
16 #include "icarus_signal_processing/Filters/FFTFilterFunctions.h"
17 #include "icarus_signal_processing/Denoising.h"
18 
19 #include "TH1F.h"
20 #include "TH2F.h"
21 #include "TProfile.h"
22 #include <TTree.h>
23 #include <TFile.h>
24 
25 #include <fstream>
26 
27 namespace icarus_tool
28 {
29 
31 {
32 public:
33  explicit ROIMorphological2D(const fhicl::ParameterSet& pset);
34 
36 
37  void configure(const fhicl::ParameterSet& pset) override;
38  void initializeHistograms(art::TFileDirectory&) override;
39 
40  void FindROIs(const art::Event&, const ArrayFloat&, const std::vector<raw::ChannelID_t>&, const geo::PlaneID&, ArrayFloat&, ArrayBool&) override;
41 
42 private:
43  // This is for the baseline...
44  float getMedian(const icarus_signal_processing::VectorFloat, const unsigned int) const;
45 
46  bool fOutputHistograms; ///< Diagnostic histogram output
47 
48  // fhicl parameters
49  std::vector<size_t> fStructuringElement; ///< Structuring element for morphological filter
50  std::vector<float> fThreshold; ///< Threshold to apply for saving signal
51 
52  // Parameters for Butterworth Filter
53 // unsigned int fButterworthOrder; ///< Order parameter for Butterworth filter
54 // unsigned int fButterworthThreshold; ///< Threshold for Butterworth filter
55 
56  // tuple output if requested
57  std::vector<float> fMedianVec;
58  std::vector<float> fRMSVec;
59  std::vector<float> fMinValVec;
60  std::vector<float> fMaxValVec;
61  std::vector<float> fRangeVec;
62  std::vector<bool> fHasROIVec;
63 
64  TTree* fTupleTree; ///< output analysis tree
65 
66 // std::unique_ptr<icarus_signal_processing::IFFTFilterFunction> fButterworthFilter;
67 };
68 
69 //----------------------------------------------------------------------
70 // Constructor.
71 ROIMorphological2D::ROIMorphological2D(const fhicl::ParameterSet& pset) : fOutputHistograms(false)
72 {
73  configure(pset);
74 }
75 
77 {
78 }
79 
80 void ROIMorphological2D::configure(const fhicl::ParameterSet& pset)
81 {
82  // Start by recovering the parameters
83  fStructuringElement = pset.get<std::vector<size_t> >("StructuringElement", std::vector<size_t>()={8,16});
84  fThreshold = pset.get<std::vector<float> >("Threshold", std::vector<float>()={2.75,2.75,2.75});
85 
86 // fButterworthOrder = pset.get<unsigned int >("ButterworthOrder", 2);
87 // fButterworthThreshold = pset.get<unsigned int >("ButterworthThreshld", 30);
88 
89 // fButterworthFilter = std::make_unique<icarus_signal_processing::HighPassButterworthFilter>(fButterworthThreshold,fButterworthOrder,4096);
90 
91  return;
92 }
93 
94 void ROIMorphological2D::FindROIs(const art::Event& event, const ArrayFloat& constInputImage, const std::vector<raw::ChannelID_t>& channelVec, const geo::PlaneID& planeID, ArrayFloat& morphedWaveforms, ArrayBool& outputROIs)
95 {
96  if (morphedWaveforms.size() != constInputImage.size()) morphedWaveforms.resize(constInputImage.size(),icarus_signal_processing::VectorFloat(constInputImage[0].size()));
97 
98  for(auto& morph : morphedWaveforms) std::fill(morph.begin(),morph.end(),0.); // explicit initialization
99 
100  // Make a local copy of the input image so we can do some smoothing
101  ArrayFloat inputImage(constInputImage.size(),VectorFloat(constInputImage[0].size()));
102 
103  // get an instance of the waveform tools
104  icarus_signal_processing::WaveformTools<float> waveformTools;
105 
106  for(size_t waveIdx = 0; waveIdx < inputImage.size(); waveIdx++) waveformTools.triangleSmooth(constInputImage[waveIdx],inputImage[waveIdx]);
107 
108 // ArrayFloat inputImage(constInputImage);
109 
110 // for(auto& waveform : inputImage) (*fButterworthFilter)(waveform);
111 
112  // Use this to get the 2D Dilation of each waveform
113  icarus_signal_processing::Dilation2D(fStructuringElement[0],fStructuringElement[1])(inputImage.begin(),inputImage.size(),morphedWaveforms.begin());
114 
115  if (fOutputHistograms)
116  {
117  fMedianVec.clear();
118  fRMSVec.clear();
119  fMinValVec.clear();
120  fMaxValVec.clear();
121  fRangeVec.clear();
122  fHasROIVec.clear();
123  }
124 
125  // Now traverse each waveform and look for the ROIs
126  for(size_t waveIdx = 0; waveIdx < morphedWaveforms.size(); waveIdx++)
127  {
128  // We start working with the morphed waveform
129  VectorFloat& morphedWave = morphedWaveforms[waveIdx];
130 
131  // We need to zero suppress so we can find the rms
132  float median = getMedian(morphedWave, morphedWave.size());
133 
134  for(auto& val : morphedWave) val -= median;
135 
136 // float threshold = rms * fThreshold[planeID.Plane];
137  float threshold = fThreshold[planeID.Plane];
138 
139  // Right size the selected values array
140  VectorBool& selVals = outputROIs[waveIdx];
141 
142  if (selVals.size() != morphedWave.size()) selVals.resize(morphedWave.size());
143 
144  std::fill(selVals.begin(),selVals.end(),false);
145 
146  bool hasROI(false);
147 
148  for(size_t idx = 0; idx < morphedWave.size(); idx++)
149  {
150  if (morphedWave[idx] > threshold)
151  {
152  selVals[idx] = true;
153  hasROI = true;
154  }
155  }
156 
157  if (fOutputHistograms)
158  {
159  VectorFloat rmsVec = morphedWave;
160  size_t maxIdx = 0.75 * rmsVec.size();
161 
162  std::nth_element(rmsVec.begin(), rmsVec.begin() + maxIdx, rmsVec.end());
163 
164  float rms = std::sqrt(std::inner_product(rmsVec.begin(), rmsVec.begin() + maxIdx, rmsVec.begin(), 0.) / float(maxIdx));
165  float minVal = *std::min_element(morphedWave.begin(),morphedWave.end());
166  float maxVal = *std::max_element(morphedWave.begin(),morphedWave.end());
167 
168  fMedianVec.emplace_back(median);
169  fRMSVec.emplace_back(rms);
170  fMinValVec.emplace_back(minVal);
171  fMaxValVec.emplace_back(maxVal);
172  fRangeVec.emplace_back(maxVal-minVal);
173  fHasROIVec.emplace_back(hasROI);
174  }
175  }
176 
177  if (fOutputHistograms) fTupleTree->Fill();
178 
179  return;
180 }
181 
182 float ROIMorphological2D::getMedian(icarus_signal_processing::VectorFloat vals, const unsigned int nVals) const
183 {
184  float median(0.);
185 
186  if (nVals > 2)
187  {
188  if (nVals % 2 == 0)
189  {
190  const auto m1 = vals.begin() + nVals / 2 - 1;
191  const auto m2 = vals.begin() + nVals / 2;
192  std::nth_element(vals.begin(), m1, vals.begin() + nVals);
193  const auto e1 = *m1;
194  std::nth_element(vals.begin(), m2, vals.begin() + nVals);
195  const auto e2 = *m2;
196  median = (e1 + e2) / 2.0;
197  }
198  else
199  {
200  const auto m = vals.begin() + nVals / 2;
201  std::nth_element(vals.begin(), m, vals.begin() + nVals);
202  median = *m;
203  }
204  }
205 
206  return median;
207 }
208 
209 void ROIMorphological2D::initializeHistograms(art::TFileDirectory& histDir)
210 {
211  // It is assumed that the input TFileDirectory has been set up to group histograms into a common
212  // folder at the calling routine's level. Here we create one more level of indirection to keep
213  // histograms made by this tool separate.
214 
215  fTupleTree = histDir.make<TTree>("ROIFinder", "Tree by ROIMorphological2D_tool");
216 
217  fTupleTree->Branch("medians", "std::vector<float>", &fMedianVec);
218  fTupleTree->Branch("RMS", "std::vector<float>", &fRMSVec);
219  fTupleTree->Branch("minvals", "std::vector<float>", &fMinValVec);
220  fTupleTree->Branch("maxvals", "std::vector<float>", &fMaxValVec);
221  fTupleTree->Branch("range", "std::vector<float>", &fRangeVec);
222  fTupleTree->Branch("hasROI", "std::vector<bool>", &fHasROIVec);
223 
224  fOutputHistograms = true;
225 
226  return;
227 }
228 
229 DEFINE_ART_CLASS_TOOL(ROIMorphological2D)
230 }
std::vector< bool > VectorBool
Definition: IROILocator.h:34
std::vector< size_t > fStructuringElement
Structuring element for morphological filter.
std::vector< float > fThreshold
Threshold to apply for saving signal.
ROIMorphological2D(const fhicl::ParameterSet &pset)
std::vector< VectorBool > ArrayBool
Definition: IROILocator.h:36
The data type to uniquely identify a Plane.
Definition: geo_types.h:472
std::size_t size(FixedBins< T, C > const &) noexcept
Definition: FixedBins.h:561
std::vector< VectorFloat > ArrayFloat
Definition: IROILocator.h:37
tuple m
now if test mode generate materials, CRT shell, world, gdml header else just generate CRT shell for u...
bool fOutputHistograms
Diagnostic histogram output.
float getMedian(const icarus_signal_processing::VectorFloat, const unsigned int) const
void fill(const art::PtrVector< recob::Hit > &hits, int only_plane)
std::vector< float > VectorFloat
Definition: IROILocator.h:35
PlaneID_t Plane
Index of the plane within its TPC.
Definition: geo_types.h:493
void initializeHistograms(art::TFileDirectory &) override
TTree * fTupleTree
output analysis tree
void FindROIs(const art::Event &, const ArrayFloat &, const std::vector< raw::ChannelID_t > &, const geo::PlaneID &, ArrayFloat &, ArrayBool &) override
This provides an interface for tools which are tasked with finding ROI&#39;s in input waveforms...
void configure(const fhicl::ParameterSet &pset) override
physics pm2 e1
art framework interface to geometry description