]> git.uio.no Git - u/mrichter/AliRoot.git/blame - PWGJE/macros/PID/SystematicErrorUtils.h
Merge branch 'feature-movesplit'
[u/mrichter/AliRoot.git] / PWGJE / macros / PID / SystematicErrorUtils.h
CommitLineData
e131b05f 1#include "TF1.h"
2#include "TH1D.h"
3#include "TH2D.h"
4#include "TMath.h"
5
6#include "Math/WrappedTF1.h"
7#include "Math/BrentRootFinder.h"
8//#include "Math/RootFinderAlgorithms.h"
9
10
11//________________________________________________________
12Double_t getWeightedMean(Double_t* x, Double_t* par)
13{
14 // Estimate the weighted mean with the chi^2 method from:
15 // J. Phys A: Math. Gen. 25 (1992) 1967-1979
16
17 const Double_t sysError = x[0];
18 const Int_t nPoints = (Int_t)par[1];
19
20 const Double_t* xMean = &par[2];
21 const Double_t* xSigma = &par[2 + nPoints];
22
23 const Double_t sysError2 = sysError * sysError;
24
25 // Calculate the weighted mean x^
26 Double_t errTot2Inverse = 0;
27 Double_t weightedMean = 0;
28
29 Double_t totErr2OnePoint = 0;
30 for (Int_t i = 0; i < nPoints; i++) {
31 totErr2OnePoint = xSigma[i] * xSigma[i] + sysError2;
32 errTot2Inverse += totErr2OnePoint > 0 ? 1. / totErr2OnePoint : 1e12;
33
34 weightedMean += totErr2OnePoint > 0 ? xMean[i] / totErr2OnePoint : xMean[i] * 1e12;
35 }
36
37 if (errTot2Inverse > 0)
38 weightedMean /= errTot2Inverse;
39 else
40 weightedMean *= 1e12;
41
42 return weightedMean;
43}
44
45
46//________________________________________________________
47Double_t chiSquareEstimateOfSysError(Double_t* x, Double_t* par)
48{
49 // Estimate the systematic error with the chi^2 method from:
50 // J. Phys A: Math. Gen. 25 (1992) 1967-1979
51
52 const Double_t sysError = x[0];
53 const Double_t chi2Expected = par[0];
54 const Int_t nPoints = (Int_t)par[1];
55 const Bool_t ignoreSigmaErrors = (Bool_t)par[2 * nPoints + 2];
56
57 const Double_t* xMean = &par[2];
58 const Double_t* xSigma = &par[2 + nPoints];
59
60 const Double_t sysError2 = sysError * sysError;
61
62 // Calculate the weighted mean x^
63 Double_t weightedMean = getWeightedMean(x, par);
64
65 Double_t totErr2OnePoint = 0;
66 Double_t chi2 = 0;
67 for (Int_t i = 0; i < nPoints; i++) {
68 totErr2OnePoint = xSigma[i] * xSigma[i] + sysError2;
69
70 chi2 += totErr2OnePoint > 0 ? (xMean[i] - weightedMean) * (xMean[i] - weightedMean) / totErr2OnePoint
71 : (xMean[i] - weightedMean) * (xMean[i] - weightedMean) * 1e12;
72 if (!(totErr2OnePoint > 0) && !ignoreSigmaErrors && xMean[i] > 0) {
73 printf("Warning: xSgima2[%d] = %f, but xMean[%d] = %f\n", i, xSigma[i], i, xMean[i]);
74 }
75
76 //printf("%d: xMean %f, xSigma %f, weightedMean %f, errTot2Inverse %f, sysError %f, chi2 - (N - 1) %e\n",
77 // i, xMean[i], xSigma[i], weightedMean, errTot2Inverse, sysError, chi2 - (nPoints - 1));
78 }
79
80 return chi2 - chi2Expected;
81}
82
83
84//________________________________________________________
85Double_t findSystematicError(Int_t nPoints, Double_t* xMean, Double_t* xSigma, Bool_t ignoreSigmaErrors,
86 Double_t minError = 0.0, Double_t maxError = 1.0, Double_t* xMeanResult = 0x0)
87{
88 Bool_t success = kTRUE;
89 Double_t sysError[3] = {999., 999., 999.};
90
91 // Root of function is estimate for systematic error
92 TF1* f = new TF1("findSystematicError", chiSquareEstimateOfSysError, 0, 1, 2 * nPoints + 2 + 1);
93 f->SetParameter(2 * nPoints + 2, ignoreSigmaErrors);
94 f->SetParameter(1, nPoints);
95
96 for (Int_t i = 0; i < nPoints; i++) {
97 f->SetParameter(i + 2, xMean[i]);
98 f->SetParameter(i + (2 + nPoints), ignoreSigmaErrors ? 0. : xSigma[i]);
99 }
100
101 for (Int_t iter = 0; iter < 3; iter++) {
102 // Mean expected chi^2
103 Double_t chi2Percentile = 0.5;
104
105 // Mean expected chi^2 not exactly known - allow for +- 1 sigma change
106 if (iter == 1)
107 chi2Percentile = 0.16;
108 else if (iter == 2)
109 chi2Percentile = 0.84;
110
111
112 f->SetParameter(0, nPoints - 1);
113 //TODO OLD: more accurate, but different from dcommon efinition of sys. error
114 //f->SetParameter(0, TMath::ChisquareQuantile(chi2Percentile, nPoints - 1)); // NDF = nPoints - 1
115
116
117 // Wrap function and use Brent's method to find the root
118 ROOT::Math::WrappedTF1 wf(*f);
119 ROOT::Math::BrentRootFinder brf;
120
121 // In case of particle fractions, error must be within [0, 1], in case of yields the
122 // error should be: 0 <= error <= yield
123 brf.SetFunction(wf, minError, maxError);
124 brf.SetNpx(1000);
125 brf.SetDefaultNSearch(30);
126 Bool_t currSuccess = brf.Solve(1000);
127
128 if (iter == 0 && xMeanResult) {
129 TF1* fMean = new TF1("findMean", getWeightedMean, 0, 1, 2 * nPoints + 2 + 1);
130 fMean->SetParameters(f->GetParameters());
131 *xMeanResult = fMean->Eval(brf.Root());
132 delete fMean;
133 }
134
135 success = success && currSuccess;
136
137 if (currSuccess)
138 sysError[iter] = TMath::Max(0., brf.Root());
139
140 break;//TODO iter > 0 not used
141 }
142
143 delete f;
144
145 // TODO OLD As the final estimate of the systematic error, take the error for the expected chi^2 (iter 0)
146 // and add the sigma of the 3 estimates (i.e. chi^2 varied by +-1sigma around mean)
147 //TODO Double_t sigmaSysErrorEstimates = TMath::RMS(3, sysError);
148
149 Double_t sysErrorEstimateFinal = sysError[0];//TMath::Sqrt(sysError[0] * sysError[0] + sigmaSysErrorEstimates * sigmaSysErrorEstimates);
150
151 if (!success) {
152 printf("Error: Failed to find root!\n");
153 sysErrorEstimateFinal = 999.;
154 }
155
156 return TMath::Max(0., sysErrorEstimateFinal);
157}
158
159
160//________________________________________________________
161Bool_t extractSystematicError(const Int_t nHistos, TH2D** hInput, TH2D* hResults, const Bool_t setMean,
162 const Bool_t addErrorsQuadratically, const Bool_t ignoreSigmaErrors)
163{
164 if (!hInput || !hResults)
165 return kFALSE;
166
167 Double_t meansForFit[nHistos];
168 Double_t sigmasForFit[nHistos];
169
170 const Int_t nBinsX = hResults->GetNbinsX();
171 const Int_t nBinsY = hResults->GetNbinsY();
172
173 for (Int_t binY = 1; binY <= nBinsY; binY++) {
174 for (Int_t binX = 1; binX <= nBinsX; binX++) {
175 Double_t maxMean = -1.;
176 Double_t minMean = -1.;
177 Bool_t minMaxSet = kFALSE;
178
179 for (Int_t j = 0; j < nHistos; j++) {
180 meansForFit[j] = hInput[j]->GetBinContent(binX, binY);
181 sigmasForFit[j] = hInput[j]->GetBinError(binX, binY);
182
183 if (!minMaxSet || meansForFit[j] > maxMean)
184 maxMean = meansForFit[j];
185
186 if (!minMaxSet || meansForFit[j] < minMean)
187 minMean = meansForFit[j];
188
189 minMaxSet = kTRUE;
190 }
191
192 /* Calculate sigma directly
193 Double_t weightedMean = 0.;
194 for (Int_t i = 0; i < nHistos; i++)
195 weightedMean += meansForFit[i];
196
197 weightedMean /= nHistos;
198
199 Double_t sysError = 0;
200 for (Int_t i = 0; i < nHistos; i++) {
201 sysError += (meansForFit[i] - weightedMean) * (meansForFit[i] - weightedMean);
202 }
203
204 sysError /= TMath::ChisquareQuantile(0.5, nHistos - 1);//nHistos - 1;
205
206 sysError = TMath::Sqrt(sysError);
207 */
208
209 Double_t weightedMean = 0;
210 // The root finder needs some given range. For yields, the error should lie within [0, maxMean - minMean]
211 Double_t sysError = findSystematicError(nHistos, meansForFit, sigmasForFit, ignoreSigmaErrors, 0, maxMean - minMean,
212 &weightedMean);
213
214 if (setMean)
215 hResults->SetBinContent(binX, binY, weightedMean);
216
217 if (addErrorsQuadratically) {
218 Double_t currBinError = hResults->GetBinError(binX, binY);
219 hResults->SetBinError(binX, binY, TMath::Sqrt(currBinError * currBinError + sysError * sysError));
220 }
221 else
222 hResults->SetBinError(binX, binY, sysError);
223
224 /*
225 TH1D* h = new TH1D(Form("h_%s", hResults->GetName()), "", TMath::Max(TMath::Ceil(maxMean), 1000.), 0, maxMean);
226 for (Int_t j = 0; j < nHistos; j++)
227 h->Fill(meansForFit[j]);
228
229 new TCanvas();
230 h->Draw();
231 printf("%s: RMS %e, sysError %e, RMS/mean %e, sysError/mean %e\n", h->GetName(), h->GetRMS(), sysError, h->GetRMS()/weightedMean,
232 sysError/weightedMean);
233 */
234 }
235 }
236
237 return kTRUE;
238}