00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #ifndef ROOT_TProfileHelper
00013 #define ROOT_TProfileHelper
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "TH1.h"
00025 #include "TError.h"
00026 #include "TCollection.h"
00027 #include "THashList.h"
00028 #include "TMath.h"
00029
00030 class TProfileHelper {
00031
00032 public:
00033 template <typename T>
00034 static void Add(T* p, const TH1 *h1, const TH1 *h2, Double_t c1, Double_t c2=1);
00035
00036 template <typename T>
00037 static Double_t GetBinEffectiveEntries(T* p, Int_t bin);
00038
00039 template <typename T>
00040 static Long64_t Merge(T* p, TCollection *list);
00041
00042 template <typename T>
00043 static T* RebinAxis(T* p, Double_t x, TAxis *axis);
00044
00045 template <typename T>
00046 static void Scale(T* p, Double_t c1, Option_t * option);
00047
00048 template <typename T>
00049 static void Sumw2(T* p);
00050
00051 template <typename T>
00052 static void LabelsDeflate(T* p, Option_t *);
00053
00054 template <typename T>
00055 static void LabelsInflate(T* p, Option_t *);
00056
00057 template <typename T>
00058 static Double_t GetBinError(T* p, Int_t bin);
00059 };
00060
00061 template <typename T>
00062 void TProfileHelper::Add(T* p, const TH1 *h1, const TH1 *h2, Double_t c1, Double_t c2)
00063 {
00064
00065
00066 T *p1 = (T*)h1;
00067 T *p2 = (T*)h2;
00068
00069
00070 Int_t nx = p->GetNbinsX();
00071 Int_t ny = p->GetNbinsY();
00072 Int_t nz = p->GetNbinsZ();
00073
00074 if ( nx != p1->GetNbinsX() || nx != p2->GetNbinsX() ||
00075 ny != p1->GetNbinsY() || ny != p2->GetNbinsY() ||
00076 nz != p1->GetNbinsZ() || nz != p2->GetNbinsZ() ) {
00077 Error("Add","Attempt to add profiles with different number of bins");
00078 return;
00079 }
00080
00081
00082 Double_t ac1 = TMath::Abs(c1);
00083 Double_t ac2 = TMath::Abs(c2);
00084 p->fEntries = ac1*p1->GetEntries() + ac2*p2->GetEntries();
00085 Double_t s0[TH1::kNstat], s1[TH1::kNstat], s2[TH1::kNstat];
00086 Int_t i;
00087 for (i=0;i<TH1::kNstat;i++) {s0[i] = s1[i] = s2[i] = 0;}
00088 p->GetStats(s0);
00089 p1->GetStats(s1);
00090 p2->GetStats(s2);
00091 for (i=0;i<TH1::kNstat;i++) {
00092 if (i == 1) s0[i] = c1*c1*s1[i] + c2*c2*s2[i];
00093 else s0[i] = ac1*s1[i] + ac2*s2[i];
00094 }
00095 p->PutStats(s0);
00096
00097
00098 Int_t bin;
00099 Double_t *cu1 = p1->GetW(); Double_t *cu2 = p2->GetW();
00100 Double_t *er1 = p1->GetW2(); Double_t *er2 = p2->GetW2();
00101 Double_t *en1 = p1->GetB(); Double_t *en2 = p2->GetB();
00102 Double_t *ew1 = p1->GetB2(); Double_t *ew2 = p2->GetB2();
00103
00104 if (p->fBinSumw2.fN == 0 && (p1->fBinSumw2.fN != 0 || p2->fBinSumw2.fN != 0) ) p->Sumw2();
00105
00106 if (ew1 == 0) ew1 = en1;
00107 if (ew2 == 0) ew2 = en2;
00108 for (bin =0;bin< p->fN;bin++) {
00109 p->fArray[bin] = c1*cu1[bin] + c2*cu2[bin];
00110 p->fSumw2.fArray[bin] = ac1*er1[bin] + ac2*er2[bin];
00111 p->fBinEntries.fArray[bin] = ac1*en1[bin] + ac2*en2[bin];
00112 if (p->fBinSumw2.fN ) p->fBinSumw2.fArray[bin] = ac1*ac1*ew1[bin] + ac2*ac2*ew2[bin];
00113 }
00114 }
00115
00116 template <typename T>
00117 Double_t TProfileHelper::GetBinEffectiveEntries(T* p, Int_t bin)
00118 {
00119
00120
00121
00122
00123
00124
00125
00126
00127 if (p->fBuffer) p->BufferEmpty();
00128
00129 if (bin < 0 || bin >= p->fNcells) return 0;
00130 double sumOfWeights = p->fBinEntries.fArray[bin];
00131 if ( p->fBinSumw2.fN == 0 || p->fBinSumw2.fN != p->fNcells) {
00132
00133 p->fBinSumw2.Set(0);
00134 return sumOfWeights;
00135 }
00136 double sumOfWeightsSquare = p->fBinSumw2.fArray[bin];
00137 return ( sumOfWeightsSquare > 0 ? sumOfWeights * sumOfWeights / sumOfWeightsSquare : 0 );
00138 }
00139
00140 template <typename T>
00141 Long64_t TProfileHelper::Merge(T* p, TCollection *li) {
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155 if (!li) return 0;
00156 if (li->IsEmpty()) return (Int_t) p->GetEntries();
00157
00158 TList inlist;
00159 TH1* hclone = (TH1*)p->Clone("FirstClone");
00160 R__ASSERT(hclone);
00161 p->BufferEmpty(1);
00162 p->Reset();
00163 p->SetEntries(0);
00164 inlist.Add(hclone);
00165 inlist.AddAll(li);
00166
00167 TAxis newXAxis;
00168 TAxis newYAxis;
00169 TAxis newZAxis;
00170 Bool_t initialLimitsFound = kFALSE;
00171 Bool_t same = kTRUE;
00172 Bool_t allHaveLimits = kTRUE;
00173
00174 TIter next(&inlist);
00175 while (TObject *o = next()) {
00176 T* h = dynamic_cast<T*> (o);
00177 if (!h) {
00178 Error("Add","Attempt to add object of class: %s to a %s",
00179 o->ClassName(),p->ClassName());
00180 return -1;
00181 }
00182 Bool_t hasLimits = h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax();
00183 allHaveLimits = allHaveLimits && hasLimits;
00184
00185 if (hasLimits) {
00186 h->BufferEmpty();
00187 if (!initialLimitsFound) {
00188 initialLimitsFound = kTRUE;
00189 newXAxis.Set(h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(),
00190 h->GetXaxis()->GetXmax());
00191 if ( p->GetDimension() >= 2 )
00192 newYAxis.Set(h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(),
00193 h->GetYaxis()->GetXmax());
00194 if ( p->GetDimension() >= 3 )
00195 newZAxis.Set(h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(),
00196 h->GetZaxis()->GetXmax());
00197 }
00198 else {
00199 if (!p->RecomputeAxisLimits(newXAxis, *(h->GetXaxis()))) {
00200 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
00201 "first: (%d, %f, %f), second: (%d, %f, %f)",
00202 newXAxis.GetNbins(), newXAxis.GetXmin(), newXAxis.GetXmax(),
00203 h->GetXaxis()->GetNbins(), h->GetXaxis()->GetXmin(),
00204 h->GetXaxis()->GetXmax());
00205 }
00206 if (p->GetDimension() >= 2 && !p->RecomputeAxisLimits(newYAxis, *(h->GetYaxis()))) {
00207 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
00208 "first: (%d, %f, %f), second: (%d, %f, %f)",
00209 newYAxis.GetNbins(), newYAxis.GetXmin(), newYAxis.GetXmax(),
00210 h->GetYaxis()->GetNbins(), h->GetYaxis()->GetXmin(),
00211 h->GetYaxis()->GetXmax());
00212 }
00213 if (p->GetDimension() >= 3 && !p->RecomputeAxisLimits(newZAxis, *(h->GetZaxis()))) {
00214 Error("Merge", "Cannot merge histograms - limits are inconsistent:\n "
00215 "first: (%d, %f, %f), second: (%d, %f, %f)",
00216 newZAxis.GetNbins(), newZAxis.GetXmin(), newZAxis.GetXmax(),
00217 h->GetZaxis()->GetNbins(), h->GetZaxis()->GetXmin(),
00218 h->GetZaxis()->GetXmax());
00219 }
00220 }
00221 }
00222 }
00223 next.Reset();
00224
00225 same = same && p->SameLimitsAndNBins(newXAxis, *(p->GetXaxis()));
00226 if ( p->GetDimension() >= 2 )
00227 same = same && p->SameLimitsAndNBins(newYAxis, *(p->GetYaxis()));
00228 if ( p->GetDimension() >= 3 )
00229 same = same && p->SameLimitsAndNBins(newZAxis, *(p->GetZaxis()));
00230 if (!same && initialLimitsFound) {
00231 Int_t b[] = { newXAxis.GetNbins(), newYAxis.GetNbins(), newZAxis.GetNbins() };
00232 Double_t v[] = { newXAxis.GetXmin(), newXAxis.GetXmax(),
00233 newYAxis.GetXmin(), newYAxis.GetXmax(),
00234 newZAxis.GetXmin(), newZAxis.GetXmax() };
00235 p->SetBins(b, v);
00236 }
00237
00238 if (!allHaveLimits) {
00239
00240 while (T* h = dynamic_cast<T*> (next())) {
00241 if (h->GetXaxis()->GetXmin() >= h->GetXaxis()->GetXmax() && h->fBuffer) {
00242
00243 Int_t nbentries = (Int_t)h->fBuffer[0];
00244 Double_t v[5];
00245 for (Int_t i = 0; i < nbentries; i++)
00246 if ( p->GetDimension() == 3 ) {
00247 v[0] = h->fBuffer[5*i + 2];
00248 v[1] = h->fBuffer[5*i + 3];
00249 v[2] = h->fBuffer[5*i + 4];
00250 v[3] = h->fBuffer[5*i + 5];
00251 v[4] = h->fBuffer[5*i + 1];
00252 p->Fill(v);
00253 } else if ( p->GetDimension() == 2 ) {
00254 v[0] = h->fBuffer[4*i + 2];
00255 v[1] = h->fBuffer[4*i + 3];
00256 v[2] = h->fBuffer[4*i + 4];
00257 v[3] = h->fBuffer[4*i + 1];
00258 v[4] = 0;
00259 p->Fill(v);
00260 }
00261 else if ( p->GetDimension() == 1 ) {
00262 v[0] = h->fBuffer[3*i + 2];
00263 v[1] = h->fBuffer[3*i + 3];
00264 v[2] = h->fBuffer[3*i + 1];
00265 v[3] = v[4] = 0;
00266 p->Fill(v);
00267 }
00268 }
00269 }
00270 if (!initialLimitsFound)
00271 return (Int_t) p->GetEntries();
00272 next.Reset();
00273 }
00274
00275
00276 Double_t stats[TH1::kNstat], totstats[TH1::kNstat];
00277 for (Int_t i=0;i<TH1::kNstat;i++) {totstats[i] = stats[i] = 0;}
00278 p->GetStats(totstats);
00279 Double_t nentries = p->GetEntries();
00280 Bool_t canRebin=p->TestBit(TH1::kCanRebin);
00281 p->ResetBit(TH1::kCanRebin);
00282
00283 while ( T* h=static_cast<T*>(next()) ) {
00284
00285 if (h->GetXaxis()->GetXmin() < h->GetXaxis()->GetXmax()) {
00286
00287 h->GetStats(stats);
00288 for (Int_t i = 0; i < TH1::kNstat; i++)
00289 totstats[i] += stats[i];
00290 nentries += h->GetEntries();
00291
00292 for ( Int_t hbin = 0; hbin < h->fN; ++hbin ) {
00293 if ((!same) && (h->IsBinUnderflow(hbin) || h->IsBinOverflow(hbin)) ) {
00294 if (h->GetW()[hbin] != 0) {
00295 Error("Merge", "Cannot merge histograms - the histograms have"
00296 " different limits and undeflows/overflows are present."
00297 " The initial histogram is now broken!");
00298 return -1;
00299 }
00300 }
00301 Int_t hbinx, hbiny, hbinz;
00302 h->GetBinXYZ(hbin, hbinx, hbiny, hbinz);
00303 Int_t pbin = p->GetBin( h->fXaxis.FindBin( h->GetXaxis()->GetBinCenter(hbinx) ),
00304 h->fYaxis.FindBin( h->GetYaxis()->GetBinCenter(hbiny) ),
00305 h->fZaxis.FindBin( h->GetZaxis()->GetBinCenter(hbinz) ) );
00306 if ( p->GetDimension() == 1 )
00307
00308
00309
00310
00311 pbin = p->fXaxis.FindBin(h->GetBinCenter(hbin));
00312 p->fArray[pbin] += h->GetW()[hbin];
00313 p->fSumw2.fArray[pbin] += h->GetW2()[hbin];
00314 p->fBinEntries.fArray[pbin] += h->GetB()[hbin];
00315 if (p->fBinSumw2.fN) {
00316 if ( h->GetB2() ) p->fBinSumw2.fArray[pbin] += h->GetB2()[hbin];
00317 else p->fBinSumw2.fArray[pbin] += h->GetB()[hbin];
00318 }
00319 }
00320 }
00321 }
00322 if (canRebin) p->SetBit(TH1::kCanRebin);
00323
00324
00325 p->PutStats(totstats);
00326 p->SetEntries(nentries);
00327 inlist.Remove(hclone);
00328 delete hclone;
00329 return (Long64_t)nentries;
00330 }
00331
00332 template <typename T>
00333 T* TProfileHelper::RebinAxis(T* p, Double_t x, TAxis *axis)
00334 {
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344 if (!p->TestBit(TH1::kCanRebin)) return 0;
00345 if (axis->GetXmin() >= axis->GetXmax()) return 0;
00346 if (axis->GetNbins() <= 0) return 0;
00347
00348 Double_t xmin, xmax;
00349 if (!p->FindNewAxisLimits(axis, x, xmin, xmax))
00350 return 0;
00351
00352
00353 T *hold = (T*)p->Clone();
00354 hold->SetDirectory(0);
00355
00356 axis->SetLimits(xmin,xmax);
00357 if (p->fBinSumw2.fN) hold->Sumw2();
00358
00359 Int_t nbinsx = p->fXaxis.GetNbins();
00360 Int_t nbinsy = p->fYaxis.GetNbins();
00361 Int_t nbinsz = p->fZaxis.GetNbins();
00362
00363
00364 p->Reset("ICE");
00365
00366 Double_t bx,by,bz;
00367 Int_t ix, iy, iz, binx, biny, binz;
00368 for (binz=1;binz<=nbinsz;binz++) {
00369 bz = hold->GetZaxis()->GetBinCenter(binz);
00370 iz = p->fZaxis.FindFixBin(bz);
00371 for (biny=1;biny<=nbinsy;biny++) {
00372 by = hold->GetYaxis()->GetBinCenter(biny);
00373 iy = p->fYaxis.FindFixBin(by);
00374 for (binx=1;binx<=nbinsx;binx++) {
00375 bx = hold->GetXaxis()->GetBinCenter(binx);
00376 ix = p->fXaxis.FindFixBin(bx);
00377
00378 Int_t sourceBin = hold->GetBin(binx,biny,binz);
00379 Int_t destinationBin = p->GetBin(ix,iy,iz);
00380 p->AddBinContent(destinationBin, hold->fArray[sourceBin]);
00381 p->fBinEntries.fArray[destinationBin] += hold->fBinEntries.fArray[sourceBin];
00382 p->fSumw2.fArray[destinationBin] += hold->fSumw2.fArray[sourceBin];
00383 if (p->fBinSumw2.fN) p->fBinSumw2.fArray[destinationBin] += hold->fBinSumw2.fArray[sourceBin];
00384 }
00385 }
00386 }
00387 return hold;
00388 }
00389
00390 template <typename T>
00391 void TProfileHelper::Scale(T* p, Double_t c1, Option_t *)
00392 {
00393 Double_t ac1 = TMath::Abs(c1);
00394
00395
00396 Int_t bin;
00397 Double_t *cu1 = p->GetW();
00398 Double_t *er1 = p->GetW2();
00399 Double_t *en1 = p->GetB();
00400 for (bin=0;bin<p->fN;bin++) {
00401 p->fArray[bin] = c1*cu1[bin];
00402 p->fSumw2.fArray[bin] = ac1*ac1*er1[bin];
00403 p->fBinEntries.fArray[bin] = en1[bin];
00404 }
00405 }
00406
00407 template <typename T>
00408 void TProfileHelper::Sumw2(T* p)
00409 {
00410
00411
00412
00413
00414
00415
00416
00417
00418 if ( p->fBinSumw2.fN == p->fNcells) {
00419 if (!p->fgDefaultSumw2)
00420 Warning("Sumw2","Sum of squares of profile bin weights structure already created");
00421 return;
00422 }
00423
00424 p->fBinSumw2.Set(p->fNcells);
00425
00426
00427 for (Int_t bin=0; bin<p->fNcells; bin++) {
00428 p->fBinSumw2.fArray[bin] = p->fBinEntries.fArray[bin];
00429 }
00430 }
00431
00432 template <typename T>
00433 void TProfileHelper::LabelsDeflate(T* p, Option_t *ax)
00434 {
00435
00436
00437
00438
00439
00440
00441 TAxis *axis = p->GetXaxis();
00442 if (ax[0] == 'y' || ax[0] == 'Y') axis = p->GetYaxis();
00443 if (ax[0] == 'z' || ax[0] == 'Z') axis = p->GetZaxis();
00444 if (!axis) {
00445 Error("LabelsDeflate","Invalid axis option %s",ax);
00446 return;
00447 }
00448 if (!axis->GetLabels()) return;
00449
00450
00451
00452
00453 TIter next(axis->GetLabels());
00454 TObject *obj;
00455 Int_t nbins = 0;
00456 while ((obj = next())) {
00457 Int_t ibin = obj->GetUniqueID();
00458 if (ibin > nbins) nbins = ibin;
00459 }
00460 if (nbins < 1) nbins = 1;
00461 T *hold = (T*)p->Clone();
00462 hold->SetDirectory(0);
00463
00464
00465 Double_t xmin = axis->GetXmin();
00466 Double_t xmax = axis->GetBinUpEdge(nbins);
00467 axis->SetRange(0,0);
00468
00469 axis->Set(nbins,xmin,xmax);
00470 p->SetBinsLength(-1);
00471 p->fBinEntries.Set(p->fN);
00472 p->fSumw2.Set(p->fN);
00473 if (p->fBinSumw2.fN) p->fBinSumw2.Set(p->fN);
00474
00475
00476 p->Reset("ICE");
00477
00478
00479 Int_t bin,binx,biny,binz;
00480 for (bin =0; bin < hold->fN; ++bin)
00481 {
00482 hold->GetBinXYZ(bin, binx, biny, binz);
00483 Int_t ibin = p->GetBin(binx, biny, binz);
00484 p->fArray[ibin] += hold->fArray[bin];
00485 p->fBinEntries.fArray[ibin] += hold->fBinEntries.fArray[bin];
00486 p->fSumw2.fArray[ibin] += hold->fSumw2.fArray[bin];
00487 if (p->fBinSumw2.fN) p->fBinSumw2.fArray[ibin] += hold->fBinSumw2.fArray[bin];
00488 }
00489
00490 delete hold;
00491 }
00492
00493 template <typename T>
00494 void TProfileHelper::LabelsInflate(T* p, Option_t *ax)
00495 {
00496
00497
00498
00499
00500
00501 TAxis *axis = p->GetXaxis();
00502 if (ax[0] == 'y' || ax[0] == 'Y') axis = p->GetYaxis();
00503 T *hold = (T*)p->Clone();
00504 hold->SetDirectory(0);
00505
00506 Int_t nbxold = p->fXaxis.GetNbins();
00507 Int_t nbyold = p->fYaxis.GetNbins();
00508 Int_t nbins = axis->GetNbins();
00509 Double_t xmin = axis->GetXmin();
00510 Double_t xmax = axis->GetXmax();
00511 xmax = xmin + 2*(xmax-xmin);
00512 axis->SetRange(0,0);
00513
00514 nbins *= 2;
00515 axis->Set(nbins,xmin,xmax);
00516
00517 p->SetBinsLength(-1);
00518 Int_t ncells = p->fN;
00519 p->fBinEntries.Set(ncells);
00520 p->fSumw2.Set(ncells);
00521 if (p->fBinSumw2.fN) p->fBinSumw2.Set(ncells);
00522
00523
00524 for (Int_t ibin =0; ibin < p->fN; ibin++)
00525 {
00526 Int_t binx, biny, binz;
00527 p->GetBinXYZ(ibin, binx, biny, binz);
00528 if (binx <= nbxold && biny <= nbyold) {
00529 Int_t bin = hold->GetBin(binx, biny, binz);
00530 p->fArray[ibin] = hold->fArray[bin];
00531 p->fBinEntries.fArray[ibin] = hold->fBinEntries.fArray[bin];
00532 p->fSumw2.fArray[ibin] = hold->fSumw2.fArray[bin];
00533 if (p->fBinSumw2.fN) p->fBinSumw2.fArray[ibin] = hold->fBinSumw2.fArray[bin];
00534 } else {
00535 p->fArray[ibin] = 0;
00536 p->fBinEntries.fArray[ibin] = 0;
00537 p->fSumw2.fArray[ibin] = 0;
00538 if (p->fBinSumw2.fN) p->fBinSumw2.fArray[ibin] = 0;
00539 }
00540 }
00541 delete hold;
00542 }
00543
00544 template <typename T>
00545 Double_t TProfileHelper::GetBinError(T* p, Int_t bin)
00546 {
00547
00548 if (p->fBuffer) p->BufferEmpty();
00549
00550 if (bin < 0 || bin >= p->fNcells) return 0;
00551 Double_t cont = p->fArray[bin];
00552 Double_t sum = p->fBinEntries.fArray[bin];
00553 Double_t err2 = p->fSumw2.fArray[bin];
00554 Double_t neff = p->GetBinEffectiveEntries(bin);
00555 if (sum == 0) return 0;
00556 Double_t contsum = cont/sum;
00557 Double_t eprim2 = TMath::Abs(err2/sum - contsum*contsum);
00558 Double_t eprim = TMath::Sqrt(eprim2);
00559 Double_t test = 1;
00560 if (err2 != 0 && neff < 5) test = eprim2*sum/err2;
00561
00562 if (p->fgApproximate && p->fNcells <=1000404 && (test < 1.e-4 || eprim2 < 1e-6)) {
00563 Double_t scont, ssum, serr2;
00564 scont = ssum = serr2 = 0;
00565 for (Int_t i=1;i<p->fNcells;i++) {
00566 if (p->fSumw2.fArray[i] <= 0) continue;
00567 scont += p->fArray[i];
00568 ssum += p->fBinEntries.fArray[i];
00569 serr2 += p->fSumw2.fArray[i];
00570 }
00571 Double_t scontsum = scont/ssum;
00572 Double_t seprim2 = TMath::Abs(serr2/ssum - scontsum*scontsum);
00573 eprim = 2*TMath::Sqrt(seprim2);
00574 sum = ssum;
00575 }
00576 sum = TMath::Abs(sum);
00577 if (p->fErrorMode == kERRORMEAN) return eprim/TMath::Sqrt(neff);
00578 else if (p->fErrorMode == kERRORSPREAD) return eprim;
00579 else if (p->fErrorMode == kERRORSPREADI) {
00580 if (eprim != 0) return eprim/TMath::Sqrt(neff);
00581 return 1/TMath::Sqrt(12*neff);
00582 }
00583 else if (p->fErrorMode == kERRORSPREADG) {
00584
00585 return 1./TMath::Sqrt(sum);
00586 }
00587 else return eprim;
00588 }
00589
00590 #endif