All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PeakFitterGaussian_tool.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 /// \file PeakFitterGaussian.cc
3 /// \author T. Usher
4 ////////////////////////////////////////////////////////////////////////
5 
7 #include "larreco/RecoAlg/GausFitCache.h" // hit::GausFitCache
10 
11 #include "art_root_io/TFileService.h"
12 #include "art/Framework/Services/Registry/ServiceHandle.h"
13 #include "art/Utilities/ToolMacros.h"
14 #include "messagefacility/MessageLogger/MessageLogger.h"
15 
16 #include <cassert>
17 #include <fstream>
18 
19 #include "TF1.h"
20 #include "TH1F.h"
21 
22 namespace reco_tool
23 {
24 
25 /// Customized function cache for Gaussians with a baseline.
26 ///
27 /// The baseline parameter is always the last one.
29 
30 public:
31  /// Constructor (see base class constructor).
32  BaselinedGausFitCache(std::string const& new_name="BaselinedGausFitCache")
33  : hit::GausFitCache(new_name)
34  {}
35 
36 protected:
37 
38  /// Creates and returns the function with specified number of Gaussians.
39  ///
40  /// The formula is `gaus(0) + gaus(3) + ... + gaus(3*(nFunc-1)) + [nFunc*3]`.
41  virtual TF1* CreateFunction(size_t nFunc) const
42  {
43  // add the Gaussians first
44  std::string formula;
45  std::size_t iGaus = 0;
46  while (iGaus < nFunc) formula += "gaus(" + std::to_string(3 * (iGaus++)) + ") + ";
47  formula += "[" + std::to_string(3 * nFunc) + "]";
48 
49  std::string const func_name = FunctionName(nFunc);
50  auto* pF = new TF1(func_name.c_str(), formula.c_str());
51  pF->SetParName(iGaus * 3, "baseline");
52  return pF;
53  } // CreateFunction()
54 
55 }; // BaselinedGausFitCache
56 
57 
59 {
60 public:
61  explicit PeakFitterGaussian(const fhicl::ParameterSet& pset);
62 
63  void findPeakParameters(const std::vector<float>&,
66  double&,
67  int&) const override;
68 
69 private:
70  // Member variables from the fhicl file
71  const double fMinWidth; ///< minimum initial width for gaussian fit
72  const double fMaxWidthMult; ///< multiplier for max width for gaussian fit
73  const double fPeakRange; ///< set range limits for peak center
74  const double fAmpRange; ///< set range limit for peak amplitude
75  const bool fFloatBaseline; ///< Allow baseline to "float" away from zero
76  const bool fOutputHistograms; ///< If true will generate summary style histograms
77 
79  TH1F* fROISizeHist;
88 
89  mutable BaselinedGausFitCache fFitCache; ///< Preallocated ROOT functions for the fits.
90 
91  mutable TH1F fHistogram;
92 
93  const geo::GeometryCore* fGeometry = lar::providerFrom<geo::Geometry>();
94 };
95 
96 //----------------------------------------------------------------------
97 // Constructor.
98 PeakFitterGaussian::PeakFitterGaussian(const fhicl::ParameterSet& pset):
99  fMinWidth(pset.get<double>("MinWidth", 0.5)),
100  fMaxWidthMult (pset.get<double>("MaxWidthMult", 3.)),
101  fPeakRange(pset.get<double>("PeakRangeFact", 2.)),
102  fAmpRange(pset.get<double>("PeakAmpRange", 2.)),
103  fFloatBaseline(pset.get< bool >("FloatBaseline", false)),
104  fOutputHistograms(pset.get< bool >("OutputHistograms", false))
105 {
106  fHistogram = TH1F("PeakFitterHitSignal","",500,0.,500.);
107 
108  fHistogram.Sumw2();
109 
110  std::string function = "Gaus(0)";
111 
112  // If asked, define the global histograms
113  if (fOutputHistograms)
114  {
115  // Access ART's TFileService, which will handle creating and writing
116  // histograms and n-tuples for us.
117  art::ServiceHandle<art::TFileService> tfs;
118 
119  // Make a directory for these histograms
120  art::TFileDirectory dir = tfs->mkdir("PeakFit");
121 
122  fNumCandHitsHist = dir.make<TH1F>("NumCandHits", "# Candidate Hits", 100, 0., 100.);
123  fROISizeHist = dir.make<TH1F>("ROISize", "ROI Size", 400, 0., 400.);
124  fCandPeakPositionHist = dir.make<TH1F>("CPeakPosition", "Peak Position", 200, 0., 400.);
125  fCandPeakWidHist = dir.make<TH1F>("CPeadWidth", "Peak Width", 100, 0., 25.);
126  fCandPeakAmpitudeHist = dir.make<TH1F>("CPeakAmplitude", "Peak Amplitude", 100, 0., 200.);
127  fCandBaselineHist = dir.make<TH1F>("CBaseline", "Baseline", 200, -25., 25.);
128  fFitPeakPositionHist = dir.make<TH1F>("FPeakPosition", "Peak Position", 200, 0., 400.);
129  fFitPeakWidHist = dir.make<TH1F>("FPeadWidth", "Peak Width", 100, 0., 25.);
130  fFitPeakAmpitudeHist = dir.make<TH1F>("FPeakAmplitude", "Peak Amplitude", 100, 0., 200.);
131  fFitBaselineHist = dir.make<TH1F>("FBaseline", "Baseline", 200, -25., 25.);
132  }
133 
134  return;
135 }
136 
137 // --------------------------------------------------------------------------------------------
138 void PeakFitterGaussian::findPeakParameters(const std::vector<float>& roiSignalVec,
139  const ICandidateHitFinder::HitCandidateVec& hitCandidateVec,
140  PeakParamsVec& peakParamsVec,
141  double& chi2PerNDF,
142  int& NDF) const
143 {
144  // The following is a translation of the original FitGaussians function in the original
145  // GausHitFinder module originally authored by Jonathan Asaadi
146  //
147  // *** NOTE: this algorithm assumes the reference time for input hit candidates is to
148  // the first tick of the input waveform (ie 0)
149  //
150  if (hitCandidateVec.empty()) return;
151 
152  // in case of a fit failure, set the chi-square to infinity
153  chi2PerNDF = std::numeric_limits<double>::infinity();
154 
155  int startTime = hitCandidateVec.front().startTick;
156  int endTime = hitCandidateVec.back().stopTick;
157  int roiSize = endTime - startTime;
158 
159  // Check to see if we need a bigger histogram for fitting
160  if (roiSize > fHistogram.GetNbinsX())
161  {
162  std::string histName = "PeakFitterHitSignal_" + std::to_string(roiSize);
163  fHistogram = TH1F(histName.c_str(),"",roiSize,0.,roiSize);
164  fHistogram.Sumw2();
165  }
166 
167  for(int idx = 0; idx < roiSize; idx++) fHistogram.SetBinContent(idx+1,roiSignalVec[startTime+idx]);
168 
169  // Build the string to describe the fit formula
170 #if 0
171  std::string equation = "gaus(0)";
172 
173  for(size_t idx = 1; idx < hitCandidateVec.size(); idx++) equation += "+gaus(" + std::to_string(3*idx) + ")";
174 
175  // Set the baseline if so desired
176  float baseline(0.);
177 
178  if (fFloatBaseline)
179  {
180  baseline = roiSignalVec[startTime];
181 
182  equation += "+" + std::to_string(baseline);
183  }
184 
185  // Now define the complete function to fit
186  TF1 Gaus("Gaus",equation.c_str(),0,roiSize,TF1::EAddToList::kNo);
187 #else
188  unsigned int const nGaus = hitCandidateVec.size();
189  assert(fFitCache.Get(nGaus));
190  TF1& Gaus = *(fFitCache.Get(nGaus));
191 
192  // Set the baseline if so desired
193  float baseline(0.);
194 
195  if (fFloatBaseline)
196  {
197  baseline = roiSignalVec[startTime];
198  Gaus.SetParameter(nGaus * 3, baseline);
199  Gaus.SetParLimits( nGaus * 3, baseline - 12., baseline + 12.);
200  }
201  else Gaus.FixParameter(nGaus * 3, baseline); // last parameter is the baseline
202 
203 #endif // 0
204 
205  if (fOutputHistograms)
206  {
207  fNumCandHitsHist->Fill(hitCandidateVec.size(), 1.);
208  fROISizeHist->Fill(roiSize, 1.);
209  fCandBaselineHist->Fill(baseline, 1.);
210  }
211 
212  // ### Setting the parameters for the Gaussian Fit ###
213  int parIdx{0};
214  for(auto const& candidateHit : hitCandidateVec)
215  {
216  double const peakMean = candidateHit.hitCenter - float(startTime);
217  double const peakWidth = candidateHit.hitSigma;
218  double const amplitude = candidateHit.hitHeight - baseline;
219  double const meanLowLim = std::max(peakMean - fPeakRange * peakWidth, 0.);
220  double const meanHiLim = std::min(peakMean + fPeakRange * peakWidth, double(roiSize));
221 
222  if (fOutputHistograms)
223  {
224  fCandPeakPositionHist->Fill(peakMean, 1.);
225  fCandPeakWidHist->Fill(peakWidth, 1.);
226  fCandPeakAmpitudeHist->Fill(amplitude, 1.);
227  }
228 
229  Gaus.SetParameter( parIdx, amplitude);
230  Gaus.SetParameter(1+parIdx, peakMean);
231  Gaus.SetParameter(2+parIdx, peakWidth);
232  Gaus.SetParLimits( parIdx, 0.1 * amplitude, fAmpRange * amplitude);
233  Gaus.SetParLimits(1+parIdx, meanLowLim, meanHiLim);
234  Gaus.SetParLimits(2+parIdx, std::max(fMinWidth, 0.1 * peakWidth), fMaxWidthMult * peakWidth);
235 
236  parIdx += 3;
237  }
238 
239  int fitResult{-1};
240 
241  try
242  { fitResult = fHistogram.Fit(&Gaus,"QNWB","", 0., roiSize);}
243  catch(...)
244  {mf::LogWarning("GausHitFinder") << "Fitter failed finding a hit";}
245 
246  // If the fit result is not zero there was an error
247  if (!fitResult)
248  {
249  // ##################################################
250  // ### Getting the fitted parameters from the fit ###
251  // ##################################################
252  chi2PerNDF = (Gaus.GetChisquare() / Gaus.GetNDF());
253  NDF = Gaus.GetNDF();
254 
255  int parIdx { 0 };
256  for(size_t idx = 0; idx < hitCandidateVec.size(); idx++)
257  {
258  PeakFitParams_t peakParams;
259 
260  peakParams.peakAmplitude = Gaus.GetParameter(parIdx);
261  peakParams.peakAmplitudeError = Gaus.GetParError( parIdx);
262  peakParams.peakCenter = Gaus.GetParameter(parIdx + 1) + float(startTime);
263  peakParams.peakCenterError = Gaus.GetParError( parIdx + 1);
264  peakParams.peakSigma = Gaus.GetParameter(parIdx + 2);
265  peakParams.peakSigmaError = Gaus.GetParError( parIdx + 2);
266 
267  if (fOutputHistograms)
268  {
269  fFitPeakPositionHist->Fill(peakParams.peakCenter, 1.);
270  fFitPeakWidHist->Fill(peakParams.peakSigma, 1.);
271  fFitPeakAmpitudeHist->Fill(peakParams.peakAmplitude, 1.);
272  }
273 
274  peakParamsVec.emplace_back(peakParams);
275 
276  parIdx += 3;
277  }
278 
279  if (fOutputHistograms) fFitBaselineHist->Fill(Gaus.GetParameter(3*nGaus), 1.);
280  }
281 #if 0
282  Gaus.Delete();
283 #endif // 0
284  return;
285 }
286 
287 DEFINE_ART_CLASS_TOOL(PeakFitterGaussian)
288 }
Utilities related to art service access.
void findPeakParameters(const std::vector< float > &, const ICandidateHitFinder::HitCandidateVec &, PeakParamsVec &, double &, int &) const override
const double fPeakRange
set range limits for peak center
const double fMaxWidthMult
multiplier for max width for gaussian fit
const bool fOutputHistograms
If true will generate summary style histograms.
static constexpr bool
process_name hit
Definition: cheaterreco.fcl:51
PeakFitterGaussian(const fhicl::ParameterSet &pset)
A set of TF1 linear sum of base functions (Gaussians)
Definition: GausFitCache.h:46
const double fAmpRange
set range limit for peak amplitude
BaselinedGausFitCache fFitCache
Preallocated ROOT functions for the fits.
const geo::GeometryCore * fGeometry
BEGIN_PROLOG baseline
BaselinedGausFitCache(std::string const &new_name="BaselinedGausFitCache")
Constructor (see base class constructor).
virtual TF1 * Get(size_t nFunc)
Returns a function sum of nFunc base functions.
Description of geometry of one entire detector.
GausFitCache(std::string new_name="GausFitCache")
Constructor; optionally set the name of the repository.
Definition: GausFitCache.h:49
tuple dir
Definition: dropbox.py:28
virtual TF1 * CreateFunction(size_t nFunc) const
const bool fFloatBaseline
Allow baseline to &quot;float&quot; away from zero.
std::string to_string(WindowPattern const &pattern)
virtual std::string FunctionName(size_t nFunc) const
Returns a name for the function with nFunc base functions.
Provide caches for TF1 functions to be used with ROOT fitters.
art::ServiceHandle< art::TFileService > tfs
art framework interface to geometry description
const double fMinWidth
minimum initial width for gaussian fit
std::vector< HitCandidate > HitCandidateVec