GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
GPeak.cxx
Go to the documentation of this file.
1#include "GPeak.h"
2
3#include "TGraph.h"
4#include "TVirtualFitter.h"
5#include "TFitResult.h"
6#include "TFitResultPtr.h"
7
8#include "Globals.h"
9#include "GRootFunctions.h"
10#include "TGRSIFunctions.h"
11#include "GCanvas.h"
12
13GPeak* GPeak::fLastFit = nullptr;
14
15GPeak::GPeak(Double_t cent, Double_t xlow, Double_t xhigh, Option_t*)
16 : TF1("photopeakbg", GRootFunctions::PhotoPeakBG, xlow, xhigh, 7),
17 fBGFit("background", GRootFunctions::StepBG, xlow, xhigh, 6)
18{
19 Clear("");
20 if(cent > xhigh || cent < xlow) {
21 // out of range...
22 if(xlow > cent) {
23 std::swap(xlow, cent);
24 }
25 if(xlow > xhigh) {
26 std::swap(xlow, xhigh);
27 }
28 if(cent > xhigh) {
29 std::swap(cent, xhigh);
30 }
31 }
32
33 TF1::SetRange(xlow, xhigh);
34
35 fBGFit.SetNpx(1000);
36 fBGFit.SetLineStyle(2);
37 fBGFit.SetLineColor(kBlack);
38
39 SetName(Form("Chan%d_%d_to_%d", static_cast<Int_t>(cent), static_cast<Int_t>(xlow), static_cast<Int_t>(xhigh)));
40 InitNames();
41 TF1::SetParameter("centroid", cent);
42
43 SetParent(nullptr);
44 // TF1::SetDirectory(0);
45 fBGFit.SetParent(nullptr);
46 fBGFit.SetBit(TObject::kCanDelete, false);
47 // fBGFit.SetDirectory(0);
48}
49
50GPeak::GPeak(Double_t cent, Double_t xlow, Double_t xhigh, TF1* bg, Option_t*)
51 : TF1("photopeakbg", GRootFunctions::PhotoPeakBG, xlow, xhigh, 7)
52{
53 Clear("");
54 if(cent > xhigh || cent < xlow) {
55 // out of range...
56 if(xlow > cent) {
57 std::swap(xlow, cent);
58 }
59 if(xlow > xhigh) {
60 std::swap(xlow, xhigh);
61 }
62 if(cent > xhigh) {
63 std::swap(cent, xhigh);
64 }
65 }
66 TF1::SetRange(xlow, xhigh);
67 SetName(Form("Chan%d_%d_to_%d", static_cast<Int_t>(cent), static_cast<Int_t>(xlow), static_cast<Int_t>(xhigh)));
68 InitNames();
69 TF1::SetParameter("centroid", cent);
70
71 if(bg != nullptr) {
72 fBGFit.Clear();
73 fBGFit.Copy(*bg);
74 } else {
75 fBGFit = TF1("BGFit", GRootFunctions::StepBG, xlow, xhigh, 10);
76 }
77
78 fBGFit.SetNpx(1000);
79 fBGFit.SetLineStyle(2);
80 fBGFit.SetLineColor(kBlack);
81
82 SetParent(nullptr);
83 // SetDirectory(0);
84 fBGFit.SetParent(nullptr);
85 // fBGFit.SetDirectory(0);
86}
87
89 : TF1("photopeakbg", GRootFunctions::PhotoPeakBG, 0, 1000, 10),
90 fBGFit("background", GRootFunctions::StepBG, 0, 1000, 10)
91{
92
93 Clear();
94 InitNames();
95 fBGFit.SetNpx(1000);
96 fBGFit.SetLineStyle(2);
97 fBGFit.SetLineColor(kBlack);
98
99 SetParent(nullptr);
100 // SetDirectory(0);
101 fBGFit.SetParent(nullptr);
102 // fBGFit.SetDirectory(0);
103}
104
105GPeak::GPeak(const GPeak& peak) : TF1(peak)
106{
107 SetParent(nullptr);
108 // SetDirectory(0);
109 fBGFit.SetParent(nullptr);
110 // fBGFit.SetDirectory(0);
111 peak.Copy(*this);
112}
113
115{
116 TF1::SetParName(0, "Height");
117 TF1::SetParName(1, "centroid");
118 TF1::SetParName(2, "sigma");
119 TF1::SetParName(3, "R");
120 TF1::SetParName(4, "beta");
121 TF1::SetParName(5, "step");
122 TF1::SetParName(6, "bg_offset");
123}
124
125void GPeak::Copy(TObject& obj) const
126{
127 TF1::Copy(obj);
128 (static_cast<GPeak&>(obj)).fInitFlag = fInitFlag;
129 (static_cast<GPeak&>(obj)).fArea = fArea;
130 (static_cast<GPeak&>(obj)).fDArea = fDArea;
131 (static_cast<GPeak&>(obj)).fSum = fSum;
132 (static_cast<GPeak&>(obj)).fDSum = fDSum;
133 (static_cast<GPeak&>(obj)).fChi2 = fChi2;
134 (static_cast<GPeak&>(obj)).fNdf = fNdf;
135
136 fBGFit.Copy(((static_cast<GPeak&>(obj)).fBGFit));
137}
138
139bool GPeak::InitParams(TH1* fithist)
140{
141 if(fithist == nullptr) {
142 std::cout << "No histogram is associated yet, no initial guesses made" << std::endl;
143 return false;
144 }
145 // Makes initial guesses at parameters for the fit. Uses the histogram to
146 Double_t xlow = 0.;
147 Double_t xhigh = 0.;
148 GetRange(xlow, xhigh);
149
150 // Int_t bin = fithist->GetXaxis()->FindBin(GetParameter("centroid"));
151 Int_t binlow = fithist->GetXaxis()->FindBin(xlow);
152 Int_t binhigh = fithist->GetXaxis()->FindBin(xhigh);
153
154 Double_t highy = fithist->GetBinContent(binlow);
155 Double_t lowy = fithist->GetBinContent(binhigh);
156 for(int x = 1; x < 5; x++) {
157 highy += fithist->GetBinContent(binlow - x);
158 lowy += fithist->GetBinContent(binhigh + x);
159 }
160 highy = highy / 5.0;
161 lowy = lowy / 5.0;
162
163 // Double_t yhigh = fithist->GetBinContent(binhigh);
164 // Double_t ylow = fithist->GetBinContent(binlow);
165 if(lowy > highy) {
166 std::swap(lowy, highy);
167 }
168
169 double largestx = 0.0;
170 double largesty = 0.0;
171 int i = binlow;
172 for(; i <= binhigh; i++) {
173 if(fithist->GetBinContent(i) > largesty) {
174 largesty = fithist->GetBinContent(i);
175 largestx = fithist->GetXaxis()->GetBinCenter(i);
176 }
177 }
178
179 // - par[0]: height of peak
180 // - par[1]: cent of peak
181 // - par[2]: sigma
182 // - par[3]: R: relative height of skewed gaus to gaus
183 // - par[4]: beta: "skewedness" of the skewed gaussin
184 // - par[5]: step: size of stepfunction step.
185
186 // - par[6]: base bg height.
187
188 // limits.
189 TF1::SetParLimits(0, 0, largesty * 2);
190 TF1::SetParLimits(1, xlow, xhigh);
191 TF1::SetParLimits(2, 0.1, xhigh - xlow);
192 TF1::SetParLimits(3, 0.0, 40);
193 TF1::SetParLimits(4, 0.01, 5);
194 double step = ((highy - lowy) / largesty) * 50;
195
196 // TF1::SetParLimits(5,step-step*.1,step+.1*step);
197 TF1::SetParLimits(5, 0.0, step + step);
198
199 double offset = lowy;
200 TF1::SetParLimits(6, offset - 0.5 * offset, offset + offset);
201
202 // Make initial guesses
203 TF1::SetParameter(0, largesty); // fithist->GetBinContent(bin));
204 TF1::SetParameter(1, largestx); // GetParameter("centroid"));
205 TF1::SetParameter(2, (largestx * .01) / 2.35); // 2,(xhigh-xlow)); //2.0/binWidth); //
206 TF1::SetParameter(3, 5.);
207 TF1::SetParameter(4, 1.);
208 TF1::SetParameter(5, step);
209 TF1::SetParameter(6, offset);
210
211 TF1::SetParError(0, 0.10 * largesty);
212 TF1::SetParError(1, 0.25);
213 TF1::SetParError(2, 0.10 * ((largestx * .01) / 2.35));
214 TF1::SetParError(3, 5);
215 TF1::SetParError(4, 0.5);
216 TF1::SetParError(5, 0.10 * step);
217 TF1::SetParError(6, 0.10 * offset);
218
220 return true;
221}
222
223Bool_t GPeak::Fit(TH1* fithist, Option_t* opt)
224{
225 if(fithist == nullptr) {
226 return false;
227 }
228 TString options = opt;
229 options.ToLower();
230 if(!IsInitialized()) {
231 InitParams(fithist);
232 }
233 TVirtualFitter::SetMaxIterations(100000);
234
235 bool quiet = options.Contains("q");
236 bool verbose = options.Contains("v");
237 bool retryFit = options.Contains("retryfit");
238 options.ReplaceAll("retryfit", "");
239 if(!verbose && !quiet) { options.Append("q"); }
240
241 if(fithist->GetSumw2()->fN != fithist->GetNbinsX() + 2) {
242 fithist->Sumw2();
243 }
244
245 TFitResultPtr fitres = fithist->Fit(this, Form("%sLRS", options.Data()));
246
247 if(verbose) { std::cout << "chi^2/NDF = " << GetChisquare() / static_cast<double>(GetNDF()) << std::endl; }
248
249 if(!fitres.Get()->IsValid()) {
250 if(!quiet) { std::cout << RED << "fit has failed, trying refit... " << RESET_COLOR << std::endl; }
251 fithist->GetListOfFunctions()->Last()->Delete();
252 fitres = fithist->Fit(this, Form("%sLRSME", options.Data()));
253 if(!quiet) {
254 if(fitres.Get()->IsValid()) {
255 std::cout << DGREEN << " refit passed!" << RESET_COLOR << std::endl;
256 } else {
257 std::cout << DRED << " refit also failed :( " << RESET_COLOR << std::endl;
258 }
259 }
260 }
261
262 // check parameter errors
263 if(!TGRSIFunctions::CheckParameterErrors(fitres, options.Data())) {
264 if(retryFit) {
265 // fit again with all parameters released
266 if(!quiet) { std::cout << GREEN << "Re-fitting with released parameters (without any limits):" << RESET_COLOR << std::endl; }
267 for(int i = 0; i < GetNpar(); ++i) {
268 ReleaseParameter(i);
269 }
270 fitres = fithist->Fit(this, Form("%sLRSM", options.Data()));
271 } else {
272 // re-try using minos instead of minuit
273 if(!quiet) { std::cout << YELLOW << "Re-fitting with \"E\" option to get better error estimation using Minos technique." << RESET_COLOR << std::endl; }
274 fitres = fithist->Fit(this, Form("%sLRSME", options.Data()));
275 }
276 }
277 TGRSIFunctions::CheckParameterErrors(fitres, options.Data());
278
279 Double_t xlow = 0.;
280 Double_t xhigh = 0.;
281 TF1::GetRange(xlow, xhigh);
282
283 std::array<double, 5> bgpars;
284 bgpars[0] = TF1::GetParameters()[0];
285 bgpars[1] = TF1::GetParameters()[1];
286 bgpars[2] = TF1::GetParameters()[2];
287 bgpars[3] = TF1::GetParameters()[5];
288 bgpars[4] = TF1::GetParameters()[6];
289
290 fBGFit.SetParameters(bgpars.data());
291
292 fChi2 = GetChisquare();
293 fNdf = GetNDF();
294
295 fArea = Integral(xlow, xhigh) / fithist->GetBinWidth(1);
296 double bgArea = fBGFit.Integral(xlow, xhigh) / fithist->GetBinWidth(1);
297 fArea -= bgArea;
298
299 if(xlow > xhigh) {
300 std::swap(xlow, xhigh);
301 }
302 fSum = fithist->Integral(fithist->GetXaxis()->FindBin(xlow),
303 fithist->GetXaxis()->FindBin(xhigh)); //* fithist->GetBinWidth(1);
304 if(verbose) { std::cout << "sum between markers: " << fSum << std::endl; }
305 fDSum = TMath::Sqrt(fSum);
306 fSum -= bgArea;
307 if(verbose) { std::cout << "sum after subtraction: " << fSum << std::endl; }
308
309 // Make a function that does not include the background
310 // Intgrate the background.
311 // TPeak* tmppeak = new TPeak(*this);
312
313 Double_t range_low = 0.;
314 Double_t range_high = 0.;
315 GetRange(range_low, range_high);
316
317 auto* tmppeak = new GPeak;
318 Copy(*tmppeak);
319 tmppeak->SetParameter("step", 0.0);
320 tmppeak->SetParameter("A", 0.0);
321 tmppeak->SetParameter("B", 0.0);
322 tmppeak->SetParameter("C", 0.0);
323 tmppeak->SetParameter("bg_offset", 0.0);
324 tmppeak->SetRange(range_low, range_high); // This will help get the true area of the gaussian 200 ~ infinity in a gaus
325 tmppeak->SetName("tmppeak");
326
327 // This is where we will do integrals and stuff.
328 TMatrixDSym CovMat = fitres->GetCovarianceMatrix();
329 CovMat(5, 5) = 0.0;
330 CovMat(6, 6) = 0.0;
331 fDArea = (tmppeak->IntegralError(xlow, xhigh, tmppeak->GetParameters(), CovMat.GetMatrixArray())) / fithist->GetBinWidth(1);
332
333 delete tmppeak;
334
335 // always print the results of the fit even if not verbose
336 if(!quiet) { Print(); }
337
338 Copy(*fithist->GetListOfFunctions()->FindObject(GetName()));
339 fithist->GetListOfFunctions()->Add(fBGFit.Clone());
340 fLastFit = this;
341
342 SetParent(nullptr);
343
344 return true;
345}
346
347void GPeak::Clear(Option_t* opt)
348{
349 TString options = opt;
350 // Clear the GPeak including functions and histogram
351 if(options.Contains("all")) {
352 TF1::Clear();
353 }
354 fInitFlag = false;
355 fArea = 0.0;
356 fDArea = 0.0;
357 fSum = 0.0;
358 fDSum = 0.0;
359 fChi2 = 0.0;
360 fNdf = 0.0;
361}
362
363void GPeak::Print(Option_t* opt) const
364{
365 TString options = opt;
366 std::cout << GREEN;
367 std::cout << "Name: " << GetName() << std::endl;
368 std::cout << "Centroid: " << GetParameter("centroid") << " +- " << GetParError(GetParNumber("centroid")) << std::endl;
369 std::cout << "Area: " << fArea << " +- " << fDArea << std::endl;
370 std::cout << "Sum: " << fSum << " +- " << fDSum << std::endl;
371 std::cout << "FWHM: " << GetFWHM() << " +- " << GetFWHMErr() << std::endl;
372 std::cout << "Reso: " << GetFWHM() / GetParameter("centroid") * 100. << "%%" << std::endl;
373 std::cout << "Chi^2/NDF: " << fChi2 / fNdf << std::endl;
374 if(options.Contains("all")) {
375 TF1::Print(opt);
376 }
377 std::cout << RESET_COLOR;
378}
379
381{
382 if(hist == nullptr) {
383 return;
384 }
385 if(fChi2 < 0.000000001) {
386 std::cout << "No fit performed" << std::endl;
387 return;
388 }
389 Double_t xlow = 0.;
390 Double_t xhigh = 0.;
391 GetRange(xlow, xhigh);
392 Int_t nbins = hist->GetXaxis()->GetNbins();
393 auto* res = new Double_t[nbins];
394 auto* bin = new Double_t[nbins];
395 Int_t points = 0;
396 for(int i = 1; i <= nbins; i++) {
397 if(hist->GetBinCenter(i) <= xlow || hist->GetBinCenter(i) >= xhigh) {
398 continue;
399 }
400 res[points] = (hist->GetBinContent(i) - Eval(hist->GetBinCenter(i))) + GetParameter("Height") / 2;
401 bin[points] = hist->GetBinCenter(i);
402 points++;
403 }
404 new GCanvas();
405 auto* residuals = new TGraph(points, bin, res);
406 residuals->Draw("*AC");
407 delete[] res;
408 delete[] bin;
409}
#define DRED
Definition Globals.h:18
#define DGREEN
Definition Globals.h:17
#define RED
Definition Globals.h:9
#define YELLOW
Definition Globals.h:7
#define GREEN
Definition Globals.h:8
#define RESET_COLOR
Definition Globals.h:5
TH1D * hist
Definition UserFillObj.h:3
Definition GPeak.h:11
GPeak()
Definition GPeak.cxx:88
void Copy(TObject &) const override
Definition GPeak.cxx:125
double fDArea
Definition GPeak.h:72
Bool_t IsInitialized() const
Definition GPeak.h:78
Double_t GetFWHM() const
Definition GPeak.h:39
void SetInitialized(Bool_t flag=true)
Definition GPeak.h:79
bool fInitFlag
Definition GPeak.h:80
double fArea
Definition GPeak.h:71
TF1 fBGFit
Definition GPeak.h:84
void Clear(Option_t *opt="") override
Definition GPeak.cxx:347
double fSum
Definition GPeak.h:73
Double_t GetFWHMErr() const
Definition GPeak.h:40
void DrawResiduals(TH1 *) const
Definition GPeak.cxx:380
void Print(Option_t *opt="") const override
Definition GPeak.cxx:363
bool Fit(TH1 *, Option_t *opt="")
Definition GPeak.cxx:223
static GPeak * fLastFit
Definition GPeak.h:82
double fNdf
Definition GPeak.h:76
double fChi2
Definition GPeak.h:75
bool InitParams(TH1 *fithist=nullptr)
Definition GPeak.cxx:139
void InitNames()
Definition GPeak.cxx:114
double fDSum
Definition GPeak.h:74
Double_t StepBG(Double_t *dim, Double_t *par)
bool CheckParameterErrors(const TFitResultPtr &fitres, std::string opt="")