]> git.uio.no Git - u/mrichter/AliRoot.git/blame - CORRFW/AliCFUnfolding.cxx
Analysis code updated
[u/mrichter/AliRoot.git] / CORRFW / AliCFUnfolding.cxx
CommitLineData
c0b10ad4 1/**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3 * *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
6 * *
7 * Permission to use, copy, modify and distribute this software and its *
8 * documentation strictly for non-commercial purposes is hereby granted *
9 * without fee, provided that the above copyright notice appears in all *
10 * copies and that both the copyright notice and this permission notice *
11 * appear in the supporting documentation. The authors make no claims *
12 * about the suitability of this software for any purpose. It is *
13 * provided "as is" without express or implied warranty. *
14 **************************************************************************/
15
7bc6a013 16//---------------------------------------------------------------------//
17// //
18// AliCFUnfolding Class //
19// Class to handle general unfolding procedure //
20// For the moment only bayesian unfolding is supported //
21// The next steps are to add chi2 minimisation and weighting methods //
22// //
23// //
24// //
25// Use : //
26// ------- //
27// The Bayesian unfolding consists of several iterations. //
28// At each iteration, an inverse response matrix is calculated, given //
29// the measured spectrum, the a priori (guessed) spectrum, //
30// the efficiency spectrum and the response matrix. //
c7f196bd 31// //
32// Then at each iteration, the unfolded spectrum is calculated using //
7bc6a013 33// the inverse response : the goal is to get an unfolded spectrum //
34// similar (according to some criterion) to the a priori one. //
35// If the difference is too big, another iteration is performed : //
36// the a priori spectrum is updated to the unfolded one from the //
37// previous iteration, and so on so forth, until the maximum number //
38// of iterations or the similarity criterion is reached. //
39// //
769f5114 40// Chi2 calculation became absolute with the correlated error //
41// calculation. //
42// Errors on the unfolded distribution are not known until the end //
43// Use the convergence criterion instead //
7bc6a013 44// //
45// Currently the user has to define the max. number of iterations //
46// (::SetMaxNumberOfIterations) //
769f5114 47// and //
48// - the chi2 below which the procedure will stop //
49// (::SetMaxChi2 or ::SetMaxChi2PerDOF) (OBSOLETE) //
50// - the convergence criterion below which the procedure will stop //
51// SetMaxConvergencePerDOF(Double_t val); //
52// //
53// Correlated error calculation can be activated by using: //
54// SetUseCorrelatedErrors(Bool_t b) in combination with convergence //
55// criterion //
56// Documentation about correlated error calculation method can be //
57// found in AliCFUnfolding::CalculateCorrelatedErrors() //
58// Author: marta.verweij@cern.ch //
7bc6a013 59// //
60// An optional possibility is to smooth the unfolded spectrum at the //
61// end of each iteration, either using a fit function //
62// (only if #dimensions <=3) //
63// or a simple averaging using the neighbouring bins values. //
64// This is possible calling the function ::UseSmoothing //
65// If no argument is passed to this function, then the second option //
66// is used. //
67// //
c7f196bd 68// IMPORTANT: //
69//----------- //
70// With this approach, the efficiency map must be calculated //
71// with *simulated* values only, otherwise the method won't work. //
72// //
73// ex: efficiency(bin_pt) = number_rec(bin_pt) / number_sim(bin_pt) //
74// //
75// the pt bin "bin_pt" must always be the same in both the efficiency //
76// numerator and denominator. //
77// This is why the efficiency map has to be created by a method //
78// from which both reconstructed and simulated values are accessible //
79// simultaneously. //
80// //
81// //
7bc6a013 82//---------------------------------------------------------------------//
83// Author : renaud.vernet@cern.ch //
84//---------------------------------------------------------------------//
c0b10ad4 85
86
87#include "AliCFUnfolding.h"
88#include "TMath.h"
89#include "TAxis.h"
85b6bda9 90#include "TF1.h"
91#include "TH1D.h"
92#include "TH2D.h"
93#include "TH3D.h"
769f5114 94#include "TRandom3.h"
c0b10ad4 95
96ClassImp(AliCFUnfolding)
97
98//______________________________________________________________
99
100AliCFUnfolding::AliCFUnfolding() :
101 TNamed(),
5a575436 102 fResponseOrig(0x0),
103 fPriorOrig(0x0),
104 fEfficiencyOrig(0x0),
769f5114 105 fMeasuredOrig(0x0),
a9500e70 106 fMaxNumIterations(0),
c0b10ad4 107 fNVariables(0),
c0b10ad4 108 fUseSmoothing(kFALSE),
85b6bda9 109 fSmoothFunction(0x0),
a9500e70 110 fSmoothOption("iremn"),
769f5114 111 fMaxConvergence(0),
a9500e70 112 fNRandomIterations(0),
5a575436 113 fResponse(0x0),
114 fPrior(0x0),
115 fEfficiency(0x0),
116 fMeasured(0x0),
c0b10ad4 117 fInverseResponse(0x0),
118 fMeasuredEstimate(0x0),
119 fConditional(0x0),
c0b10ad4 120 fUnfolded(0x0),
a9500e70 121 fUnfoldedFinal(0x0),
c0b10ad4 122 fCoordinates2N(0x0),
123 fCoordinatesN_M(0x0),
769f5114 124 fCoordinatesN_T(0x0),
5a575436 125 fRandomResponse(0x0),
126 fRandomEfficiency(0x0),
127 fRandomMeasured(0x0),
769f5114 128 fRandom3(0x0),
769f5114 129 fDeltaUnfoldedP(0x0),
a9500e70 130 fDeltaUnfoldedN(0x0),
769f5114 131 fNCalcCorrErrors(0),
132 fRandomSeed(0)
c0b10ad4 133{
134 //
135 // default constructor
136 //
137}
138
139//______________________________________________________________
140
141AliCFUnfolding::AliCFUnfolding(const Char_t* name, const Char_t* title, const Int_t nVar,
a9500e70 142 const THnSparse* response, const THnSparse* efficiency, const THnSparse* measured, const THnSparse* prior ,
143 Double_t maxConvergencePerDOF, UInt_t randomSeed, Int_t maxNumIterations
144 ) :
c0b10ad4 145 TNamed(name,title),
5a575436 146 fResponseOrig((THnSparse*)response->Clone()),
147 fPriorOrig(0x0),
148 fEfficiencyOrig((THnSparse*)efficiency->Clone()),
769f5114 149 fMeasuredOrig((THnSparse*)measured->Clone()),
a9500e70 150 fMaxNumIterations(maxNumIterations),
c0b10ad4 151 fNVariables(nVar),
c0b10ad4 152 fUseSmoothing(kFALSE),
85b6bda9 153 fSmoothFunction(0x0),
a9500e70 154 fSmoothOption("iremn"),
769f5114 155 fMaxConvergence(0),
a9500e70 156 fNRandomIterations(maxNumIterations),
5a575436 157 fResponse((THnSparse*)response->Clone()),
158 fPrior(0x0),
159 fEfficiency((THnSparse*)efficiency->Clone()),
160 fMeasured((THnSparse*)measured->Clone()),
c0b10ad4 161 fInverseResponse(0x0),
162 fMeasuredEstimate(0x0),
163 fConditional(0x0),
c0b10ad4 164 fUnfolded(0x0),
a9500e70 165 fUnfoldedFinal(0x0),
c0b10ad4 166 fCoordinates2N(0x0),
167 fCoordinatesN_M(0x0),
769f5114 168 fCoordinatesN_T(0x0),
5a575436 169 fRandomResponse((THnSparse*)response->Clone()),
170 fRandomEfficiency((THnSparse*)efficiency->Clone()),
171 fRandomMeasured((THnSparse*)measured->Clone()),
769f5114 172 fRandom3(0x0),
769f5114 173 fDeltaUnfoldedP(0x0),
a9500e70 174 fDeltaUnfoldedN(0x0),
769f5114 175 fNCalcCorrErrors(0),
a9500e70 176 fRandomSeed(randomSeed)
c0b10ad4 177{
178 //
179 // named constructor
180 //
181
182 AliInfo(Form("\n\n--------------------------\nCreating an unfolder :\n--------------------------\nresponse matrix has %d dimension(s)",fResponse->GetNdimensions()));
a9500e70 183
c0b10ad4 184 if (!prior) CreateFlatPrior(); // if no prior distribution declared, simply use a flat distribution
185 else {
186 fPrior = (THnSparse*) prior->Clone();
5a575436 187 fPriorOrig = (THnSparse*)fPrior->Clone();
85b6bda9 188 if (fPrior->GetNdimensions() != fNVariables)
189 AliFatal(Form("The prior matrix should have %d dimensions, and it has actually %d",fNVariables,fPrior->GetNdimensions()));
c0b10ad4 190 }
85b6bda9 191
192 if (fEfficiency->GetNdimensions() != fNVariables)
193 AliFatal(Form("The efficiency matrix should have %d dimensions, and it has actually %d",fNVariables,fEfficiency->GetNdimensions()));
194 if (fMeasured->GetNdimensions() != fNVariables)
195 AliFatal(Form("The measured matrix should have %d dimensions, and it has actually %d",fNVariables,fMeasured->GetNdimensions()));
196 if (fResponse->GetNdimensions() != 2*fNVariables)
197 AliFatal(Form("The response matrix should have %d dimensions, and it has actually %d",2*fNVariables,fResponse->GetNdimensions()));
c0b10ad4 198
85b6bda9 199
c0b10ad4 200 for (Int_t iVar=0; iVar<fNVariables; iVar++) {
201 AliInfo(Form("prior matrix has %d bins in dimension %d",fPrior ->GetAxis(iVar)->GetNbins(),iVar));
202 AliInfo(Form("efficiency matrix has %d bins in dimension %d",fEfficiency->GetAxis(iVar)->GetNbins(),iVar));
203 AliInfo(Form("measured matrix has %d bins in dimension %d",fMeasured ->GetAxis(iVar)->GetNbins(),iVar));
204 }
769f5114 205
5a575436 206 fRandomResponse ->SetTitle("Randomized response matrix");
207 fRandomEfficiency->SetTitle("Randomized efficiency");
208 fRandomMeasured ->SetTitle("Randomized measured");
a9500e70 209 SetMaxConvergencePerDOF(maxConvergencePerDOF) ;
c0b10ad4 210 Init();
211}
212
c0b10ad4 213//______________________________________________________________
214
215AliCFUnfolding::~AliCFUnfolding() {
216 //
217 // destructor
218 //
219 if (fResponse) delete fResponse;
220 if (fPrior) delete fPrior;
c0b10ad4 221 if (fEfficiency) delete fEfficiency;
5a575436 222 if (fEfficiencyOrig) delete fEfficiencyOrig;
c0b10ad4 223 if (fMeasured) delete fMeasured;
769f5114 224 if (fMeasuredOrig) delete fMeasuredOrig;
85b6bda9 225 if (fSmoothFunction) delete fSmoothFunction;
5a575436 226 if (fPriorOrig) delete fPriorOrig;
c0b10ad4 227 if (fInverseResponse) delete fInverseResponse;
228 if (fMeasuredEstimate) delete fMeasuredEstimate;
229 if (fConditional) delete fConditional;
a9500e70 230 if (fUnfolded) delete fUnfolded;
231 if (fUnfoldedFinal) delete fUnfoldedFinal;
c0b10ad4 232 if (fCoordinates2N) delete [] fCoordinates2N;
233 if (fCoordinatesN_M) delete [] fCoordinatesN_M;
234 if (fCoordinatesN_T) delete [] fCoordinatesN_T;
5a575436 235 if (fRandomResponse) delete fRandomResponse;
236 if (fRandomEfficiency) delete fRandomEfficiency;
237 if (fRandomMeasured) delete fRandomMeasured;
769f5114 238 if (fRandom3) delete fRandom3;
769f5114 239 if (fDeltaUnfoldedP) delete fDeltaUnfoldedP;
a9500e70 240 if (fDeltaUnfoldedN) delete fDeltaUnfoldedN;
c0b10ad4 241}
242
243//______________________________________________________________
244
245void AliCFUnfolding::Init() {
246 //
247 // initialisation function : creates internal settings
248 //
249
769f5114 250 fRandom3 = new TRandom3(fRandomSeed);
251
c0b10ad4 252 fCoordinates2N = new Int_t[2*fNVariables];
253 fCoordinatesN_M = new Int_t[fNVariables];
254 fCoordinatesN_T = new Int_t[fNVariables];
255
256 // create the matrix of conditional probabilities P(M|T)
a9500e70 257 CreateConditional(); //done only once at initialization
c0b10ad4 258
259 // create the frame of the inverse response matrix
260 fInverseResponse = (THnSparse*) fResponse->Clone();
261 // create the frame of the unfolded spectrum
262 fUnfolded = (THnSparse*) fPrior->Clone();
a9500e70 263 fUnfolded->SetTitle("Unfolded");
c0b10ad4 264 // create the frame of the measurement estimate spectrum
265 fMeasuredEstimate = (THnSparse*) fMeasured->Clone();
a9500e70 266
5a575436 267 // create the frame of the delta profiles
a9500e70 268 fDeltaUnfoldedP = (THnSparse*)fPrior->Clone();
269 fDeltaUnfoldedP->SetTitle("#Delta unfolded");
270 fDeltaUnfoldedP->Reset();
271 fDeltaUnfoldedN = (THnSparse*)fPrior->Clone();
5a575436 272 fDeltaUnfoldedN->SetTitle("");
a9500e70 273 fDeltaUnfoldedN->Reset();
c0b10ad4 274}
275
a9500e70 276
c0b10ad4 277//______________________________________________________________
278
279void AliCFUnfolding::CreateEstMeasured() {
280 //
281 // This function creates a estimate (M) of the reconstructed spectrum
7bc6a013 282 // given the a priori distribution (T), the efficiency (E) and the conditional matrix (COND)
c0b10ad4 283 //
284 // --> P(M) = SUM { P(M|T) * P(T) }
7bc6a013 285 // --> M(i) = SUM_k { COND(i,k) * T(k) * E (k)}
c0b10ad4 286 //
287 // This is needed to calculate the inverse response matrix
288 //
289
290
291 // clean the measured estimate spectrum
85f9f9e1 292 fMeasuredEstimate->Reset();
293
85b6bda9 294 THnSparse* priorTimesEff = (THnSparse*) fPrior->Clone();
295 priorTimesEff->Multiply(fEfficiency);
296
c0b10ad4 297 // fill it
7bc6a013 298 for (Long_t iBin=0; iBin<fConditional->GetNbins(); iBin++) {
c0b10ad4 299 Double_t conditionalValue = fConditional->GetBinContent(iBin,fCoordinates2N);
300 GetCoordinates();
85b6bda9 301 Double_t priorTimesEffValue = priorTimesEff->GetBinContent(fCoordinatesN_T);
85b6bda9 302 Double_t fill = conditionalValue * priorTimesEffValue ;
303
304 if (fill>0.) {
12e419d5 305 fMeasuredEstimate->AddBinContent(fCoordinatesN_M,fill);
769f5114 306 fMeasuredEstimate->SetBinError(fCoordinatesN_M,0.);
85b6bda9 307 }
c0b10ad4 308 }
85b6bda9 309 delete priorTimesEff ;
c0b10ad4 310}
311
312//______________________________________________________________
313
314void AliCFUnfolding::CreateInvResponse() {
315 //
316 // Creates the inverse response matrix (INV) with Bayesian method
317 // : uses the conditional matrix (COND), the prior probabilities (T) and the efficiency map (E)
318 //
319 // --> P(T|M) = P(M|T) * P(T) * eff(T) / SUM { P(M|T) * P(T) }
320 // --> INV(i,j) = COND(i,j) * T(j) * E(j) / SUM_k { COND(i,k) * T(k) }
321 //
322
85b6bda9 323 THnSparse* priorTimesEff = (THnSparse*) fPrior->Clone();
324 priorTimesEff->Multiply(fEfficiency);
325
7bc6a013 326 for (Long_t iBin=0; iBin<fConditional->GetNbins(); iBin++) {
c0b10ad4 327 Double_t conditionalValue = fConditional->GetBinContent(iBin,fCoordinates2N);
328 GetCoordinates();
85b6bda9 329 Double_t estMeasuredValue = fMeasuredEstimate->GetBinContent(fCoordinatesN_M);
85b6bda9 330 Double_t priorTimesEffValue = priorTimesEff ->GetBinContent(fCoordinatesN_T);
85b6bda9 331 Double_t fill = (estMeasuredValue>0. ? conditionalValue * priorTimesEffValue / estMeasuredValue : 0. ) ;
85b6bda9 332 if (fill>0. || fInverseResponse->GetBinContent(fCoordinates2N)>0.) {
333 fInverseResponse->SetBinContent(fCoordinates2N,fill);
769f5114 334 fInverseResponse->SetBinError (fCoordinates2N,0.);
85b6bda9 335 }
336 }
337 delete priorTimesEff ;
c0b10ad4 338}
339
340//______________________________________________________________
341
342void AliCFUnfolding::Unfold() {
343 //
344 // Main routine called by the user :
769f5114 345 // it calculates the unfolded spectrum from the response matrix, measured spectrum and efficiency
346 // several iterations are performed until a reasonable chi2 or convergence criterion is reached
c0b10ad4 347 //
348
769f5114 349 Int_t iIterBayes = 0 ;
350 Double_t convergence = 0.;
c0b10ad4 351
352 for (iIterBayes=0; iIterBayes<fMaxNumIterations; iIterBayes++) { // bayes iterations
a9500e70 353
354 CreateEstMeasured(); // create measured estimate from prior
355 CreateInvResponse(); // create inverse response from prior
356 CreateUnfolded(); // create unfoled spectrum from measured and inverse response
357
358 convergence = GetConvergence();
359 AliDebug(0,Form("convergence at iteration %d is %e",iIterBayes,convergence));
360
361 if (fMaxConvergence>0. && convergence<fMaxConvergence && fNCalcCorrErrors == 0) {
362 fNRandomIterations = iIterBayes;
363 AliDebug(0,Form("convergence is met at iteration %d",iIterBayes));
c0b10ad4 364 break;
365 }
769f5114 366
85b6bda9 367 if (fUseSmoothing) {
368 if (Smooth()) {
369 AliError("Couldn't smooth the unfolded spectrum!!");
a9500e70 370 if (fNCalcCorrErrors>0) {
371 AliInfo(Form("=======================\nUnfold of randomized distribution finished at iteration %d with convergence %e \n",iIterBayes,convergence));
372 }
373 else {
374 AliInfo(Form("\n\n=======================\nFinish at iteration %d : convergence is %e and you required it to be < %e\n=======================\n\n",iIterBayes,convergence,fMaxConvergence));
769f5114 375 }
85b6bda9 376 return;
377 }
378 }
769f5114 379
a9500e70 380 // update the prior distribution
381 if (fPrior) delete fPrior ;
382 fPrior = (THnSparse*)fUnfolded->Clone() ;
383 fPrior->SetTitle("Prior");
384
385 } // end bayes iteration
386
387 if (fNCalcCorrErrors==0) fUnfoldedFinal = (THnSparse*) fUnfolded->Clone() ;
388
389 //
390 //for (Long_t iBin=0; iBin<fUnfoldedFinal->GetNbins(); iBin++) AliDebug(2,Form("%e\n",fUnfoldedFinal->GetBinError(iBin)));
391 //
392
393 if (fNCalcCorrErrors == 0) {
394 AliInfo("\n================================================\nFinished bayes iteration, now calculating errors...\n================================================\n");
395 fNCalcCorrErrors = 1;
769f5114 396 CalculateCorrelatedErrors();
397 }
398
a9500e70 399 if (fNCalcCorrErrors >1 ) {
400 AliInfo(Form("\n\n=======================\nFinished at iteration %d : convergence is %e and you required it to be < %e\n=======================\n\n",iIterBayes,convergence,fMaxConvergence));
401 }
402 else if(fNCalcCorrErrors>0) {
403 AliInfo(Form("=======================\nUnfolding of randomized distribution finished at iteration %d with convergence %e \n",iIterBayes,convergence));
c0b10ad4 404 }
c0b10ad4 405}
406
407//______________________________________________________________
408
409void AliCFUnfolding::CreateUnfolded() {
410 //
411 // Creates the unfolded (T) spectrum from the measured spectrum (M) and the inverse response matrix (INV)
412 // We have P(T) = SUM { P(T|M) * P(M) }
413 // --> T(i) = SUM_k { INV(i,k) * M(k) }
414 //
415
416
417 // clear the unfolded spectrum
a9500e70 418 // if in the process of error calculation, the random unfolded spectrum is created
419 // otherwise the normal unfolded spectrum is created
420
421 fUnfolded->Reset();
c0b10ad4 422
7bc6a013 423 for (Long_t iBin=0; iBin<fInverseResponse->GetNbins(); iBin++) {
c0b10ad4 424 Double_t invResponseValue = fInverseResponse->GetBinContent(iBin,fCoordinates2N);
425 GetCoordinates();
85b6bda9 426 Double_t effValue = fEfficiency->GetBinContent(fCoordinatesN_T);
85b6bda9 427 Double_t measuredValue = fMeasured ->GetBinContent(fCoordinatesN_M);
85b6bda9 428 Double_t fill = (effValue>0. ? invResponseValue * measuredValue / effValue : 0.) ;
769f5114 429
85b6bda9 430 if (fill>0.) {
a9500e70 431 // set errors to zero
432 // true errors will be filled afterwards
769f5114 433 Double_t err = 0.;
a9500e70 434 fUnfolded->SetBinError (fCoordinatesN_T,err);
435 fUnfolded->AddBinContent(fCoordinatesN_T,fill);
85b6bda9 436 }
c0b10ad4 437 }
438}
769f5114 439
440//______________________________________________________________
441
442void AliCFUnfolding::CalculateCorrelatedErrors() {
443
5a575436 444 // Step 1: Create randomized distribution (fRandomXXXX) of each bin of
a9500e70 445 // the measured spectrum to calculate correlated errors.
446 // Poisson statistics: mean = measured value of bin
769f5114 447 // Step 2: Unfold randomized distribution
a9500e70 448 // Step 3: Store difference of unfolded spectrum from measured distribution and
449 // unfolded distribution from randomized distribution
450 // -> fDeltaUnfoldedP (TProfile with option "S")
769f5114 451 // Step 4: Repeat Step 1-3 several times (fNRandomIterations)
452 // Step 5: The spread of fDeltaUnfoldedP for each bin is the error on the unfolded spectrum of that specific bin
453
769f5114 454
a9500e70 455 //Do fNRandomIterations = bayes iterations performed
456 for (int i=0; i<fNRandomIterations; i++) {
457
458 // reset prior to original one
459 if (fPrior) delete fPrior ;
5a575436 460 fPrior = (THnSparse*) fPriorOrig->Clone();
a9500e70 461
462 // create randomized distribution and stick measured spectrum to it
463 CreateRandomizedDist();
5a575436 464
465 if (fResponse) delete fResponse ;
466 fResponse = (THnSparse*) fRandomResponse->Clone();
467 fResponse->SetTitle("Response");
468
469 if (fEfficiency) delete fEfficiency ;
470 fEfficiency = (THnSparse*) fRandomEfficiency->Clone();
471 fEfficiency->SetTitle("Efficiency");
472
473 if (fMeasured) delete fMeasured ;
474 fMeasured = (THnSparse*) fRandomMeasured->Clone();
a9500e70 475 fMeasured->SetTitle("Measured");
476
5a575436 477 //unfold with randomized distributions
a9500e70 478 Unfold();
479 FillDeltaUnfoldedProfile();
480 }
769f5114 481
a9500e70 482 // Get statistical errors for final unfolded spectrum
483 // ie. spread of each pt bin in fDeltaUnfoldedP
484 Double_t sigma = 0.;
a9500e70 485 for (Long_t iBin=0; iBin<fUnfoldedFinal->GetNbins(); iBin++) {
f21c7024 486 fUnfoldedFinal->GetBinContent(iBin,fCoordinatesN_M);
a9500e70 487 sigma = fDeltaUnfoldedP->GetBinError(fCoordinatesN_M);
488 //AliDebug(2,Form("filling error %e\n",sigma));
489 fUnfoldedFinal->SetBinError(fCoordinatesN_M,sigma);
769f5114 490 }
a9500e70 491
492 // now errors are calculated
493 fNCalcCorrErrors = 2;
769f5114 494}
a9500e70 495
769f5114 496//______________________________________________________________
497void AliCFUnfolding::CreateRandomizedDist() {
498 //
a9500e70 499 // Create randomized dist from original measured distribution
500 // This distribution is created several times, each time with a different random number
769f5114 501 //
502
5a575436 503 for (Long_t iBin=0; iBin<fResponseOrig->GetNbins(); iBin++) {
504 Double_t val = fResponseOrig->GetBinContent(iBin,fCoordinatesN_M); //used as mean
505 Double_t err = fResponseOrig->GetBinError(fCoordinatesN_M); //used as sigma
506 Double_t ran = fRandom3->Gaus(val,err);
507 // random = fRandom3->PoissonD(measuredValue); //doesn't work for normalized spectra, use Gaus (assuming raw counts in bin is large >10)
508 fRandomResponse->SetBinContent(iBin,ran);
509 }
510 for (Long_t iBin=0; iBin<fEfficiencyOrig->GetNbins(); iBin++) {
511 Double_t val = fEfficiencyOrig->GetBinContent(iBin,fCoordinatesN_M); //used as mean
512 Double_t err = fEfficiencyOrig->GetBinError(fCoordinatesN_M); //used as sigma
513 Double_t ran = fRandom3->Gaus(val,err);
514 // random = fRandom3->PoissonD(measuredValue); //doesn't work for normalized spectra, use Gaus (assuming raw counts in bin is large >10)
515 fRandomEfficiency->SetBinContent(iBin,ran);
516 }
517 for (Long_t iBin=0; iBin<fMeasuredOrig->GetNbins(); iBin++) {
518 Double_t val = fMeasuredOrig->GetBinContent(iBin,fCoordinatesN_M); //used as mean
519 Double_t err = fMeasuredOrig->GetBinError(fCoordinatesN_M); //used as sigma
520 Double_t ran = fRandom3->Gaus(val,err);
769f5114 521 // random = fRandom3->PoissonD(measuredValue); //doesn't work for normalized spectra, use Gaus (assuming raw counts in bin is large >10)
5a575436 522 fRandomMeasured->SetBinContent(iBin,ran);
769f5114 523 }
524}
525
526//______________________________________________________________
527void AliCFUnfolding::FillDeltaUnfoldedProfile() {
528 //
a9500e70 529 // Store difference of unfolded spectrum from measured distribution and unfolded spectrum from randomized distribution
530 // The delta profile has been set to a THnSparse to handle N dimension
531 // The THnSparse contains in each bin the mean value and spread of the difference
532 // This function updates the profile wrt to its previous mean and error
533 // The relation between iterations (n+1) and n is as follows :
534 // mean_{n+1} = (n*mean_n + value_{n+1}) / (n+1)
535 // sigma_{n+1} = sqrt { 1/(n+1) * [ n*sigma_n^2 + (n^2+n)*(mean_{n+1}-mean_n)^2 ] } (can this be optimized?)
536
537 for (Long_t iBin=0; iBin<fUnfolded->GetNbins(); iBin++) {
538 Double_t deltaInBin = fUnfoldedFinal->GetBinContent(iBin,fCoordinatesN_M) - fUnfolded->GetBinContent(iBin);
539 Double_t entriesInBin = fDeltaUnfoldedN->GetBinContent(fCoordinatesN_M);
540 //AliDebug(2,Form("%e %e ==> delta = %e\n",fUnfoldedFinal->GetBinContent(iBin,fCoordinatesN_M),fUnfolded->GetBinContent(iBin),deltaInBin));
541
542 Double_t mean_n = fDeltaUnfoldedP->GetBinContent(fCoordinatesN_M) ;
543 Double_t mean_nplus1 = mean_n ;
544 mean_nplus1 *= entriesInBin ;
545 mean_nplus1 += deltaInBin ;
546 mean_nplus1 /= (entriesInBin+1) ;
547
548 Double_t sigma = fDeltaUnfoldedP->GetBinContent(fCoordinatesN_M) ;
549 sigma *= sigma ;
550 sigma *= entriesInBin ;
551 sigma += ( (entriesInBin*entriesInBin+entriesInBin) * TMath::Power(mean_nplus1 - mean_n,2) ) ;
552 sigma /= (entriesInBin+1) ;
553 sigma = TMath::Sqrt(sigma) ;
554
555 //AliDebug(2,Form("sigma = %e\n",sigma));
556
557 fDeltaUnfoldedP->SetBinContent(fCoordinatesN_M,mean_nplus1) ;
558 fDeltaUnfoldedP->SetBinError (fCoordinatesN_M,sigma) ;
559 fDeltaUnfoldedN->SetBinContent(fCoordinatesN_M,entriesInBin+1);
769f5114 560 }
561}
562
85b6bda9 563//______________________________________________________________
564
c0b10ad4 565void AliCFUnfolding::GetCoordinates() {
566 //
567 // assign coordinates in Measured and True spaces (dim=N) from coordinates in global space (dim=2N)
568 //
569 for (Int_t i = 0; i<fNVariables ; i++) {
570 fCoordinatesN_M[i] = fCoordinates2N[i];
571 fCoordinatesN_T[i] = fCoordinates2N[i+fNVariables];
572 }
573}
574
575//______________________________________________________________
576
577void AliCFUnfolding::CreateConditional() {
578 //
579 // creates the conditional probability matrix (R*) holding the P(M|T), given the reponse matrix R
580 //
581 // --> R*(i,j) = R(i,j) / SUM_k{ R(k,j) }
582 //
583
5a575436 584 fConditional = (THnSparse*) fResponse->Clone(); // output of this function
a9500e70 585
85b6bda9 586 Int_t* dim = new Int_t [fNVariables];
587 for (Int_t iDim=0; iDim<fNVariables; iDim++) dim[iDim] = fNVariables+iDim ; //dimensions corresponding to TRUE values (i.e. from N to 2N-1)
a9500e70 588
589 THnSparse* responseInT = fConditional->Projection(fNVariables,dim,"E"); // output denominator :
590 // projection of the response matrix on the TRUE axis
85b6bda9 591 delete [] dim;
769f5114 592
c0b10ad4 593 // fill the conditional probability matrix
7bc6a013 594 for (Long_t iBin=0; iBin<fResponse->GetNbins(); iBin++) {
c0b10ad4 595 Double_t responseValue = fResponse->GetBinContent(iBin,fCoordinates2N);
596 GetCoordinates();
a9500e70 597 Double_t projValue = responseInT->GetBinContent(fCoordinatesN_T);
769f5114 598
85b6bda9 599 Double_t fill = responseValue / projValue ;
600 if (fill>0. || fConditional->GetBinContent(fCoordinates2N)>0.) {
601 fConditional->SetBinContent(fCoordinates2N,fill);
769f5114 602 Double_t err = 0.;
85b6bda9 603 fConditional->SetBinError (fCoordinates2N,err);
604 }
c0b10ad4 605 }
a9500e70 606 delete responseInT ;
c0b10ad4 607}
769f5114 608//______________________________________________________________
609
610Int_t AliCFUnfolding::GetDOF() {
611 //
612 // number of dof = number of bins
613 //
614
615 Int_t nDOF = 1 ;
616 for (Int_t iDim=0; iDim<fNVariables; iDim++) {
617 nDOF *= fPrior->GetAxis(iDim)->GetNbins();
618 }
619 AliDebug(0,Form("Number of degrees of freedom = %d",nDOF));
620 return nDOF;
621}
c0b10ad4 622
623//______________________________________________________________
624
625Double_t AliCFUnfolding::GetChi2() {
626 //
627 // Returns the chi2 between unfolded and a priori spectrum
769f5114 628 // This function became absolute with the correlated error calculation.
629 // Errors on the unfolded distribution are not known until the end
630 // Use the convergence criterion instead
c0b10ad4 631 //
632
769f5114 633 Double_t chi2 = 0. ;
634 Double_t error_unf = 0.;
7bc6a013 635 for (Long_t iBin=0; iBin<fPrior->GetNbins(); iBin++) {
85f9f9e1 636 Double_t priorValue = fPrior->GetBinContent(iBin,fCoordinatesN_T);
769f5114 637 error_unf = fUnfolded->GetBinError(fCoordinatesN_T);
85f9f9e1 638 chi2 += (error_unf > 0. ? TMath::Power((fUnfolded->GetBinContent(fCoordinatesN_T) - priorValue)/error_unf,2) / priorValue : 0.) ;
c0b10ad4 639 }
640 return chi2;
641}
642
643//______________________________________________________________
644
769f5114 645Double_t AliCFUnfolding::GetConvergence() {
646 //
647 // Returns convergence criterion = \sum_t ((U_t^{n-1}-U_t^n)/U_t^{n-1})^2
648 // U is unfolded spectrum, t is the bin, n = current, n-1 = previous
649 //
650 Double_t convergence = 0.;
651 Double_t priorValue = 0.;
652 Double_t currentValue = 0.;
653 for (Long_t iBin=0; iBin < fPrior->GetNbins(); iBin++) {
654 priorValue = fPrior->GetBinContent(iBin,fCoordinatesN_T);
a9500e70 655 currentValue = fUnfolded->GetBinContent(fCoordinatesN_T);
769f5114 656
657 if (priorValue > 0.)
658 convergence += ((priorValue-currentValue)/priorValue)*((priorValue-currentValue)/priorValue);
a9500e70 659 else
769f5114 660 AliWarning(Form("priorValue = %f. Adding 0 to convergence criterion.",priorValue));
769f5114 661 }
662 return convergence;
663}
664
665//______________________________________________________________
666
667void AliCFUnfolding::SetMaxConvergencePerDOF(Double_t val) {
c0b10ad4 668 //
769f5114 669 // Max. convergence criterion per degree of freedom : user setting
670 // convergence criterion = DOF*val; DOF = number of bins
671 // In Jan-Fiete's multiplicity note: Convergence criterion = DOF*0.001^2
c0b10ad4 672 //
673
769f5114 674 Int_t nDOF = GetDOF() ;
675 fMaxConvergence = val * nDOF ;
676 AliInfo(Form("MaxConvergence = %e. Number of degrees of freedom = %d",fMaxConvergence,nDOF));
c0b10ad4 677}
678
679//______________________________________________________________
680
85b6bda9 681Short_t AliCFUnfolding::Smooth() {
c0b10ad4 682 //
683 // Smoothes the unfolded spectrum
85b6bda9 684 //
685 // By default each cell content is replaced by the average with the neighbouring bins (but not diagonally-neighbouring bins)
686 // However, if a specific function fcn has been defined in UseSmoothing(fcn), the unfolded will be fit and updated using fcn
c0b10ad4 687 //
688
85b6bda9 689 if (fSmoothFunction) {
7bc6a013 690 AliDebug(2,Form("Smoothing spectrum with fit function %p",fSmoothFunction));
85b6bda9 691 return SmoothUsingFunction();
692 }
7036630f 693 else return SmoothUsingNeighbours(fUnfolded);
85b6bda9 694}
695
696//______________________________________________________________
697
7036630f 698Short_t AliCFUnfolding::SmoothUsingNeighbours(THnSparse* hist) {
85b6bda9 699 //
700 // Smoothes the unfolded spectrum using neighouring bins
701 //
702
7036630f 703 Int_t const nDimensions = hist->GetNdimensions() ;
704 Int_t* coordinates = new Int_t[nDimensions];
705
706 Int_t* numBins = new Int_t[nDimensions];
707 for (Int_t iVar=0; iVar<nDimensions; iVar++) numBins[iVar] = hist->GetAxis(iVar)->GetNbins();
c0b10ad4 708
7036630f 709 //need a copy because hist will be updated during the loop, and this creates problems
710 THnSparse* copy = (THnSparse*)hist->Clone();
c0b10ad4 711
7bc6a013 712 for (Long_t iBin=0; iBin<copy->GetNbins(); iBin++) { //loop on non-empty bins
7036630f 713 Double_t content = copy->GetBinContent(iBin,coordinates);
7bc6a013 714 Double_t error2 = TMath::Power(copy->GetBinError(iBin),2);
c0b10ad4 715
716 // skip the under/overflow bins...
717 Bool_t isOutside = kFALSE ;
7036630f 718 for (Int_t iVar=0; iVar<nDimensions; iVar++) {
719 if (coordinates[iVar]<1 || coordinates[iVar]>numBins[iVar]) {
c0b10ad4 720 isOutside=kTRUE;
721 break;
722 }
723 }
724 if (isOutside) continue;
725
726 Int_t neighbours = 0; // number of neighbours to average with
727
7036630f 728 for (Int_t iVar=0; iVar<nDimensions; iVar++) {
729 if (coordinates[iVar] > 1) { // must not be on low edge border
730 coordinates[iVar]-- ; //get lower neighbouring bin
731 content += copy->GetBinContent(coordinates);
732 error2 += TMath::Power(copy->GetBinError(coordinates),2);
c0b10ad4 733 neighbours++;
7036630f 734 coordinates[iVar]++ ; //back to initial coordinate
c0b10ad4 735 }
7036630f 736 if (coordinates[iVar] < numBins[iVar]) { // must not be on up edge border
737 coordinates[iVar]++ ; //get upper neighbouring bin
738 content += copy->GetBinContent(coordinates);
739 error2 += TMath::Power(copy->GetBinError(coordinates),2);
c0b10ad4 740 neighbours++;
7036630f 741 coordinates[iVar]-- ; //back to initial coordinate
c0b10ad4 742 }
743 }
85b6bda9 744 // make an average
7036630f 745 hist->SetBinContent(coordinates,content/(1.+neighbours));
746 hist->SetBinError (coordinates,TMath::Sqrt(error2)/(1.+neighbours));
c0b10ad4 747 }
748 delete [] numBins;
7036630f 749 delete [] coordinates ;
c0b10ad4 750 delete copy;
85b6bda9 751 return 0;
c0b10ad4 752}
753
85b6bda9 754//______________________________________________________________
755
756Short_t AliCFUnfolding::SmoothUsingFunction() {
757 //
758 // Fits the unfolded spectrum using the function fSmoothFunction
759 //
760
7bc6a013 761 AliDebug(0,Form("Smooth function is a %s with option \"%s\" and has %d parameters : ",fSmoothFunction->ClassName(),fSmoothOption,fSmoothFunction->GetNpar()));
85b6bda9 762
7bc6a013 763 for (Int_t iPar=0; iPar<fSmoothFunction->GetNpar(); iPar++) AliDebug(0,Form("par[%d]=%e",iPar,fSmoothFunction->GetParameter(iPar)));
764
765 Int_t fitResult = 0;
85b6bda9 766
767 switch (fNVariables) {
7bc6a013 768 case 1 : fitResult = fUnfolded->Projection(0) ->Fit(fSmoothFunction,fSmoothOption); break;
769 case 2 : fitResult = fUnfolded->Projection(1,0) ->Fit(fSmoothFunction,fSmoothOption); break; // (1,0) instead of (0,1) -> TAxis issue
770 case 3 : fitResult = fUnfolded->Projection(0,1,2)->Fit(fSmoothFunction,fSmoothOption); break;
771 default: AliFatal(Form("Cannot handle such fit in %d dimensions",fNVariables)) ; return 1;
772 }
773
774 if (fitResult != 0) {
775 AliWarning(Form("Fit failed with status %d, stopping the loop",fitResult));
776 return 1;
85b6bda9 777 }
778
779 Int_t nDim = fNVariables;
780 Int_t* bins = new Int_t[nDim]; // number of bins for each variable
781 Long_t nBins = 1; // used to calculate the total number of bins in the THnSparse
782
783 for (Int_t iVar=0; iVar<nDim; iVar++) {
784 bins[iVar] = fUnfolded->GetAxis(iVar)->GetNbins();
785 nBins *= bins[iVar];
786 }
787
788 Int_t *bin = new Int_t[nDim]; // bin to fill the THnSparse (holding the bin coordinates)
789 Double_t x[3] = {0,0,0} ; // value in bin center (max dimension is 3 (TF3))
790
791 // loop on the bins and update of fUnfolded
792 // THnSparse::Multiply(TF1*) doesn't exist, so let's do it bin by bin
793 for (Long_t iBin=0; iBin<nBins; iBin++) {
794 Long_t bin_tmp = iBin ;
795 for (Int_t iVar=0; iVar<nDim; iVar++) {
796 bin[iVar] = 1 + bin_tmp % bins[iVar] ;
797 bin_tmp /= bins[iVar] ;
798 x[iVar] = fUnfolded->GetAxis(iVar)->GetBinCenter(bin[iVar]);
799 }
800 Double_t functionValue = fSmoothFunction->Eval(x[0],x[1],x[2]) ;
12e419d5 801 fUnfolded->SetBinError (bin,fUnfolded->GetBinError(bin)*functionValue/fUnfolded->GetBinContent(bin));
85b6bda9 802 fUnfolded->SetBinContent(bin,functionValue);
85b6bda9 803 }
700a1189 804 delete [] bins;
805 delete [] bin ;
85b6bda9 806 return 0;
807}
c0b10ad4 808
809//______________________________________________________________
810
811void AliCFUnfolding::CreateFlatPrior() {
812 //
813 // Creates a flat prior distribution
814 //
815
816 AliInfo("Creating a flat a priori distribution");
817
818 // create the frame of the THnSparse given (for example) the one from the efficiency map
819 fPrior = (THnSparse*) fEfficiency->Clone();
a9500e70 820 fPrior->SetTitle("Prior");
c0b10ad4 821
85b6bda9 822 if (fNVariables != fPrior->GetNdimensions())
823 AliFatal(Form("The prior matrix should have %d dimensions, and it has actually %d",fNVariables,fPrior->GetNdimensions()));
824
c0b10ad4 825 Int_t nDim = fNVariables;
826 Int_t* bins = new Int_t[nDim]; // number of bins for each variable
827 Long_t nBins = 1; // used to calculate the total number of bins in the THnSparse
828
829 for (Int_t iVar=0; iVar<nDim; iVar++) {
830 bins[iVar] = fPrior->GetAxis(iVar)->GetNbins();
831 nBins *= bins[iVar];
832 }
833
834 Int_t *bin = new Int_t[nDim]; // bin to fill the THnSparse (holding the bin coordinates)
835
836 // loop that sets 1 in each bin
837 for (Long_t iBin=0; iBin<nBins; iBin++) {
838 Long_t bin_tmp = iBin ;
839 for (Int_t iVar=0; iVar<nDim; iVar++) {
840 bin[iVar] = 1 + bin_tmp % bins[iVar] ;
841 bin_tmp /= bins[iVar] ;
842 }
843 fPrior->SetBinContent(bin,1.); // put 1 everywhere
85b6bda9 844 fPrior->SetBinError (bin,0.); // put 0 everywhere
c0b10ad4 845 }
846
5a575436 847 fPriorOrig = (THnSparse*)fPrior->Clone();
c0b10ad4 848
849 delete [] bin;
850 delete [] bins;
851}