]>
Commit | Line | Data |
---|---|---|
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 | //________________________________________________________ | |
12 | Double_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 | //________________________________________________________ | |
47 | Double_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 | //________________________________________________________ | |
85 | Double_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 | //________________________________________________________ | |
161 | Bool_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 | } |