00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "THnSparse.h"
00013
00014 #include "TArrayI.h"
00015 #include "TAxis.h"
00016 #include "TClass.h"
00017 #include "TCollection.h"
00018 #include "TDataMember.h"
00019 #include "TDataType.h"
00020 #include "TH1D.h"
00021 #include "TH2D.h"
00022 #include "TH3D.h"
00023 #include "TF1.h"
00024 #include "TInterpreter.h"
00025 #include "TMath.h"
00026 #include "TRandom.h"
00027
00028 #include "TError.h"
00029
00030 #include "HFitInterface.h"
00031 #include "Fit/SparseData.h"
00032 #include "Math/MinimizerOptions.h"
00033 #include "Math/WrappedMultiTF1.h"
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049 class THnSparseCoordCompression {
00050 public:
00051 THnSparseCoordCompression(Int_t dim, const Int_t* nbins);
00052 THnSparseCoordCompression(const THnSparseCoordCompression& other);
00053 ~THnSparseCoordCompression();
00054
00055 ULong64_t GetHashFromBuffer(const Char_t* buf) const;
00056 Int_t GetBufferSize() const { return fCoordBufferSize; }
00057 Int_t GetNdimensions() const { return fNdimensions; }
00058 void SetCoordFromBuffer(const Char_t* buf_in, Int_t* coord_out) const;
00059 ULong64_t SetBufferFromCoord(const Int_t* coord_in, Char_t* buf_out) const;
00060
00061 protected:
00062 Int_t GetNumBits(Int_t n) const {
00063
00064 Int_t r = (n > 0);
00065 while (n/=2) ++r;
00066 return r;
00067 }
00068 private:
00069 Int_t fNdimensions;
00070 Int_t fCoordBufferSize;
00071 Int_t *fBitOffsets;
00072 };
00073
00074
00075
00076
00077
00078
00079
00080 THnSparseCoordCompression::THnSparseCoordCompression(Int_t dim, const Int_t* nbins):
00081 fNdimensions(dim), fCoordBufferSize(0), fBitOffsets(0)
00082 {
00083
00084
00085
00086
00087 fBitOffsets = new Int_t[dim + 1];
00088
00089 int shift = 0;
00090 for (Int_t i = 0; i < dim; ++i) {
00091 fBitOffsets[i] = shift;
00092 shift += GetNumBits(nbins[i] + 2);
00093 }
00094 fBitOffsets[dim] = shift;
00095 fCoordBufferSize = (shift + 7) / 8;
00096 }
00097
00098
00099
00100 THnSparseCoordCompression::THnSparseCoordCompression(const THnSparseCoordCompression& other)
00101 {
00102
00103 fNdimensions = other.fNdimensions;
00104 fCoordBufferSize = other.fCoordBufferSize;
00105 fBitOffsets = new Int_t[fNdimensions + 1];
00106 memcpy(fBitOffsets, other.fBitOffsets, sizeof(Int_t) * fNdimensions);
00107 }
00108
00109
00110
00111 THnSparseCoordCompression::~THnSparseCoordCompression()
00112 {
00113
00114 delete [] fBitOffsets;
00115 }
00116
00117
00118
00119 void THnSparseCoordCompression::SetCoordFromBuffer(const Char_t* buf_in,
00120 Int_t* coord_out) const
00121 {
00122
00123
00124
00125 for (Int_t i = 0; i < fNdimensions; ++i) {
00126 const Int_t offset = fBitOffsets[i] / 8;
00127 Int_t shift = fBitOffsets[i] % 8;
00128 Int_t nbits = fBitOffsets[i + 1] - fBitOffsets[i];
00129 const UChar_t* pbuf = (const UChar_t*) buf_in + offset;
00130 coord_out[i] = *pbuf >> shift;
00131 Int_t subst = (Int_t) -1;
00132 subst = subst << nbits;
00133 nbits -= (8 - shift);
00134 shift = 8 - shift;
00135 for (Int_t n = 0; n * 8 < nbits; ++n) {
00136 ++pbuf;
00137 coord_out[i] += *pbuf << shift;
00138 shift += 8;
00139 }
00140 coord_out[i] &= ~subst;
00141 }
00142 }
00143
00144
00145
00146 ULong64_t THnSparseCoordCompression::SetBufferFromCoord(const Int_t* coord_in,
00147 Char_t* buf_out) const
00148 {
00149
00150
00151
00152
00153 if (fCoordBufferSize <= 8) {
00154 ULong64_t l64buf = 0;
00155 for (Int_t i = 0; i < fNdimensions; ++i) {
00156 l64buf += ((ULong64_t)((UInt_t)coord_in[i])) << fBitOffsets[i];
00157 }
00158 memcpy(buf_out, &l64buf, sizeof(Long64_t));
00159 return l64buf;
00160 }
00161
00162
00163 memset(buf_out, 0, fCoordBufferSize);
00164 for (Int_t i = 0; i < fNdimensions; ++i) {
00165 const Int_t offset = fBitOffsets[i] / 8;
00166 const Int_t shift = fBitOffsets[i] % 8;
00167 ULong64_t val = coord_in[i];
00168
00169 Char_t* pbuf = buf_out + offset;
00170 *pbuf += 0xff & (val << shift);
00171 val = val >> (8 - shift);
00172 while (val) {
00173 ++pbuf;
00174 *pbuf += 0xff & val;
00175 val = val >> 8;
00176 }
00177 }
00178
00179 return GetHashFromBuffer(buf_out);
00180 }
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 ULong64_t THnSparseCoordCompression::GetHashFromBuffer(const Char_t* buf) const
00233 {
00234
00235
00236
00237
00238
00239
00240
00241
00242 if (fCoordBufferSize <= 8) {
00243
00244 ULong64_t hash1 = 0;
00245 memcpy(&hash1, buf, fCoordBufferSize);
00246 return hash1;
00247 }
00248
00249
00250 ULong64_t hash = 5381;
00251 const Char_t* str = buf;
00252 while (str - buf < fCoordBufferSize) {
00253 hash *= 5;
00254 hash += *(str++);
00255 }
00256 return hash;
00257 }
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 class THnSparseCompactBinCoord: public THnSparseCoordCompression {
00270 public:
00271 THnSparseCompactBinCoord(Int_t dim, const Int_t* nbins);
00272 ~THnSparseCompactBinCoord();
00273 Int_t* GetCoord() { return fCurrentBin; }
00274 const Char_t* GetBuffer() const { return fCoordBuffer; }
00275 ULong64_t GetHash() const { return fHash; }
00276 void UpdateCoord() {
00277 fHash = SetBufferFromCoord(fCurrentBin, fCoordBuffer);
00278 }
00279 void SetCoord(const Int_t* coord) {
00280 memcpy(fCurrentBin, coord, sizeof(Int_t) * GetNdimensions());
00281 fHash = SetBufferFromCoord(coord, fCoordBuffer);
00282 }
00283 void SetBuffer(const Char_t* buf) {
00284 memcpy(fCoordBuffer, buf, GetBufferSize());
00285 fHash = GetHashFromBuffer(fCoordBuffer);
00286 }
00287
00288 private:
00289 ULong64_t fHash;
00290 Char_t *fCoordBuffer;
00291 Int_t *fCurrentBin;
00292 };
00293
00294
00295
00296
00297
00298
00299
00300 THnSparseCompactBinCoord::THnSparseCompactBinCoord(Int_t dim, const Int_t* nbins):
00301 THnSparseCoordCompression(dim, nbins),
00302 fHash(0), fCoordBuffer(0), fCurrentBin(0)
00303 {
00304
00305
00306
00307 fCurrentBin = new Int_t[dim];
00308 size_t bufAllocSize = GetBufferSize();
00309 if (bufAllocSize < sizeof(Long64_t))
00310 bufAllocSize = sizeof(Long64_t);
00311 fCoordBuffer = new Char_t[bufAllocSize];
00312 }
00313
00314
00315
00316 THnSparseCompactBinCoord::~THnSparseCompactBinCoord()
00317 {
00318
00319
00320 delete [] fCoordBuffer;
00321 delete [] fCurrentBin;
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336 ClassImp(THnSparseArrayChunk);
00337
00338
00339 THnSparseArrayChunk::THnSparseArrayChunk(Int_t coordsize, bool errors, TArray* cont):
00340 fCoordinateAllocationSize(-1), fSingleCoordinateSize(coordsize), fCoordinatesSize(0),
00341 fCoordinates(0), fContent(cont),
00342 fSumw2(0)
00343 {
00344
00345
00346
00347 fCoordinateAllocationSize = fSingleCoordinateSize * cont->GetSize();
00348 fCoordinates = new Char_t[fCoordinateAllocationSize];
00349 if (errors) Sumw2();
00350 }
00351
00352
00353 THnSparseArrayChunk::~THnSparseArrayChunk()
00354 {
00355
00356 delete fContent;
00357 delete [] fCoordinates;
00358 delete fSumw2;
00359 }
00360
00361
00362 void THnSparseArrayChunk::AddBin(Int_t idx, const Char_t* coordbuf)
00363 {
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375 if (fCoordinateAllocationSize == -1 && fContent) {
00376 Int_t chunksize = fSingleCoordinateSize * fContent->GetSize();
00377 if (fCoordinatesSize < chunksize) {
00378
00379 Char_t *newcoord = new Char_t[chunksize];
00380 memcpy(newcoord, fCoordinates, fCoordinatesSize);
00381 delete [] fCoordinates;
00382 fCoordinates = newcoord;
00383 }
00384 fCoordinateAllocationSize = chunksize;
00385 }
00386
00387 memcpy(fCoordinates + idx * fSingleCoordinateSize, coordbuf, fSingleCoordinateSize);
00388 fCoordinatesSize += fSingleCoordinateSize;
00389 }
00390
00391
00392 void THnSparseArrayChunk::Sumw2()
00393 {
00394
00395 if (!fSumw2)
00396 fSumw2 = new TArrayD(fContent->GetSize());
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 ClassImp(THnSparse);
00491
00492
00493 THnSparse::THnSparse():
00494 fNdimensions(0), fChunkSize(1024), fFilledBins(0), fEntries(0),
00495 fTsumw(0), fTsumw2(-1.), fCompactCoord(0), fIntegral(0), fIntegralStatus(kNoInt)
00496 {
00497
00498 fBinContent.SetOwner();
00499 }
00500
00501
00502 THnSparse::THnSparse(const char* name, const char* title, Int_t dim,
00503 const Int_t* nbins, const Double_t* xmin, const Double_t* xmax,
00504 Int_t chunksize):
00505 TNamed(name, title), fNdimensions(dim), fChunkSize(chunksize), fFilledBins(0),
00506 fAxes(dim), fEntries(0), fTsumw(0), fTsumw2(-1.), fTsumwx(dim), fTsumwx2(dim),
00507 fCompactCoord(0), fIntegral(0), fIntegralStatus(kNoInt)
00508 {
00509
00510
00511
00512
00513
00514
00515
00516 for (Int_t i = 0; i < fNdimensions; ++i) {
00517 TAxis* axis = new TAxis(nbins[i], xmin ? xmin[i] : 0., xmax ? xmax[i] : 1.);
00518 fAxes.AddAtAndExpand(axis, i);
00519 }
00520 SetTitle(title);
00521 fAxes.SetOwner();
00522
00523 fCompactCoord = new THnSparseCompactBinCoord(dim, nbins);
00524 fBinContent.SetOwner();
00525 }
00526
00527
00528 THnSparse::~THnSparse() {
00529
00530
00531 delete fCompactCoord;
00532 if (fIntegralStatus != kNoInt) delete [] fIntegral;
00533 }
00534
00535
00536 void THnSparse::AddBinContent(const Int_t* coord, Double_t v)
00537 {
00538
00539
00540 GetCompactCoord()->SetCoord(coord);
00541 Long64_t bin = GetBinIndexForCurrentBin(kTRUE);
00542 return AddBinContent(bin, v);
00543 }
00544
00545
00546 void THnSparse::AddBinContent(Long64_t bin, Double_t v)
00547 {
00548
00549
00550 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
00551 bin %= fChunkSize;
00552 v += chunk->fContent->GetAt(bin);
00553 return chunk->fContent->SetAt(v, bin);
00554 }
00555
00556
00557 THnSparseArrayChunk* THnSparse::AddChunk()
00558 {
00559
00560 THnSparseArrayChunk* chunk =
00561 new THnSparseArrayChunk(GetCompactCoord()->GetBufferSize(),
00562 GetCalculateErrors(), GenerateArray());
00563 fBinContent.AddLast(chunk);
00564 return chunk;
00565 }
00566
00567
00568 THnSparse* THnSparse::CloneEmpty(const char* name, const char* title,
00569 const TObjArray* axes, Int_t chunksize,
00570 Bool_t keepTargetAxis) const
00571 {
00572
00573
00574
00575
00576
00577 THnSparse* ret = (THnSparse*)IsA()->New();
00578 ret->SetNameTitle(name, title);
00579 ret->fNdimensions = axes->GetEntriesFast();
00580 ret->fChunkSize = chunksize;
00581
00582 TIter iAxis(axes);
00583 const TAxis* axis = 0;
00584 Int_t pos = 0;
00585 Int_t *nbins = new Int_t[axes->GetEntriesFast()];
00586 while ((axis = (TAxis*)iAxis())) {
00587 TAxis* reqaxis = (TAxis*)axis->Clone();
00588 if (!keepTargetAxis && axis->TestBit(TAxis::kAxisRange)) {
00589 Int_t binFirst = axis->GetFirst();
00590 Int_t binLast = axis->GetLast();
00591 Int_t nBins = binLast - binFirst + 1;
00592 if (axis->GetXbins()->GetSize()) {
00593
00594 reqaxis->Set(nBins, axis->GetXbins()->GetArray() + binFirst - 1);
00595 } else {
00596
00597 reqaxis->Set(nBins, axis->GetBinLowEdge(binFirst), axis->GetBinUpEdge(binLast));
00598 }
00599 reqaxis->ResetBit(TAxis::kAxisRange);
00600 }
00601
00602 nbins[pos] = reqaxis->GetNbins();
00603 ret->fAxes.AddAtAndExpand(reqaxis->Clone(), pos++);
00604 }
00605 ret->fAxes.SetOwner();
00606
00607 ret->fCompactCoord = new THnSparseCompactBinCoord(pos, nbins);
00608 delete [] nbins;
00609
00610 return ret;
00611 }
00612
00613
00614 TH1* THnSparse::CreateHist(const char* name, const char* title,
00615 const TObjArray* axes,
00616 Bool_t keepTargetAxis ) const {
00617
00618
00619
00620
00621 const int ndim = axes->GetSize();
00622
00623 TH1* hist = 0;
00624
00625 if (ndim == 1)
00626 hist = new TH1D(name, title, 1, 0., 1.);
00627 else if (ndim == 2)
00628 hist = new TH2D(name, title, 1, 0., 1., 1, 0., 1.);
00629 else if (ndim == 3)
00630 hist = new TH3D(name, title, 1, 0., 1., 1, 0., 1., 1, 0., 1.);
00631 else {
00632 Error("CreateHist", "Cannot create histogram %s with %d dimensions!", name, ndim);
00633 return 0;
00634 }
00635
00636 TAxis* hax[3] = {hist->GetXaxis(), hist->GetYaxis(), hist->GetZaxis()};
00637 for (Int_t d = 0; d < ndim; ++d) {
00638 TAxis* reqaxis = (TAxis*)(*axes)[d];
00639 hax[d]->SetTitle(reqaxis->GetTitle());
00640 if (!keepTargetAxis && reqaxis->TestBit(TAxis::kAxisRange)) {
00641 Int_t binFirst = reqaxis->GetFirst();
00642 if (binFirst == 0) binFirst = 1;
00643 Int_t binLast = reqaxis->GetLast();
00644 Int_t nBins = binLast - binFirst + 1;
00645 if (reqaxis->GetXbins()->GetSize()) {
00646
00647 hax[d]->Set(nBins, reqaxis->GetXbins()->GetArray() + binFirst - 1);
00648 } else {
00649
00650 hax[d]->Set(nBins, reqaxis->GetBinLowEdge(binFirst), reqaxis->GetBinUpEdge(binLast));
00651 }
00652 } else {
00653 if (reqaxis->GetXbins()->GetSize()) {
00654
00655 hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXbins()->GetArray());
00656 } else {
00657
00658 hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXmin(), reqaxis->GetXmax());
00659 }
00660 }
00661 }
00662
00663 hist->Rebuild();
00664
00665 return hist;
00666 }
00667
00668
00669 THnSparse* THnSparse::CreateSparse(const char* name, const char* title,
00670 const TH1* h, Int_t chunkSize)
00671 {
00672
00673
00674
00675 int ndim = h->GetDimension();
00676
00677
00678 int nbins[3] = {0,0,0};
00679 double minRange[3] = {0.,0.,0.};
00680 double maxRange[3] = {0.,0.,0.};
00681 TAxis* axis[3] = { h->GetXaxis(), h->GetYaxis(), h->GetZaxis() };
00682 for (int i = 0; i < ndim; ++i) {
00683 nbins[i] = axis[i]->GetNbins();
00684 minRange[i] = axis[i]->GetXmin();
00685 maxRange[i] = axis[i]->GetXmax();
00686 }
00687
00688
00689
00690
00691
00692 THnSparse* s = 0;
00693 const char* cname( h->ClassName() );
00694 if (cname[0] == 'T' && cname[1] == 'H' && cname[2] >= '1' && cname[2] <= '3' && cname[4] == 0) {
00695 if (cname[3] == 'F') {
00696 s = new THnSparseF(name, title, ndim, nbins, minRange, maxRange, chunkSize);
00697 } else if (cname[3] == 'D') {
00698 s = new THnSparseD(name, title, ndim, nbins, minRange, maxRange, chunkSize);
00699 } else if (cname[3] == 'I') {
00700 s = new THnSparseI(name, title, ndim, nbins, minRange, maxRange, chunkSize);
00701 } else if (cname[3] == 'S') {
00702 s = new THnSparseS(name, title, ndim, nbins, minRange, maxRange, chunkSize);
00703 } else if (cname[3] == 'C') {
00704 s = new THnSparseC(name, title, ndim, nbins, minRange, maxRange, chunkSize);
00705 }
00706 }
00707 if (!s) {
00708 ::Warning("THnSparse::CreateSparse", "Unknown Type of Histogram");
00709 return 0;
00710 }
00711
00712 for (int i = 0; i < ndim; ++i) {
00713 s->GetAxis(i)->SetTitle(axis[i]->GetTitle());
00714 }
00715
00716
00717 const TArray *array = dynamic_cast<const TArray*>(h);
00718 if (!array) {
00719 ::Warning("THnSparse::CreateSparse", "Unknown Type of Histogram");
00720 return 0;
00721 }
00722
00723
00724 for (int i = 0; i < array->GetSize(); ++i) {
00725 double value = h->GetBinContent(i);
00726 double error = h->GetBinError(i);
00727 if (!value && !error) continue;
00728 int x[3] = {0,0,0};
00729 h->GetBinXYZ(i, x[0], x[1], x[2]);
00730 s->SetBinContent(x, value);
00731 s->SetBinError(x, error);
00732 }
00733
00734 return s;
00735 }
00736
00737
00738 void THnSparse::FillExMap()
00739 {
00740
00741 TIter iChunk(&fBinContent);
00742 THnSparseArrayChunk* chunk = 0;
00743 THnSparseCoordCompression compactCoord(*GetCompactCoord());
00744 Long64_t idx = 0;
00745 if (2 * GetNbins() > fBins.Capacity())
00746 fBins.Expand(3 * GetNbins());
00747 while ((chunk = (THnSparseArrayChunk*) iChunk())) {
00748 const Int_t chunkSize = chunk->GetEntries();
00749 Char_t* buf = chunk->fCoordinates;
00750 const Int_t singleCoordSize = chunk->fSingleCoordinateSize;
00751 const Char_t* endbuf = buf + singleCoordSize * chunkSize;
00752 for (; buf < endbuf; buf += singleCoordSize, ++idx) {
00753 Long64_t hash = compactCoord.GetHashFromBuffer(buf);
00754 Long64_t linidx = fBins.GetValue(hash);
00755 if (linidx) {
00756 Long64_t nextidx = linidx;
00757 while (nextidx) {
00758
00759 linidx = nextidx;
00760 nextidx = fBinsContinued.GetValue(linidx);
00761 }
00762 fBinsContinued.Add(linidx, idx + 1);
00763 } else {
00764 fBins.Add(hash, idx + 1);
00765 }
00766 }
00767 }
00768 }
00769
00770
00771 TFitResultPtr THnSparse::Fit(TF1 *f ,Option_t *option ,Option_t *goption)
00772 {
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793 Foption_t fitOption;
00794
00795 if (!TH1::FitOptionsMake(option,fitOption)) return 0;
00796
00797
00798
00799 fitOption.Nostore = true;
00800
00801 if (!fitOption.Chi2) fitOption.Like = true;
00802
00803 ROOT::Fit::DataRange range(GetNdimensions());
00804 for ( int i = 0; i < GetNdimensions(); ++i ) {
00805 TAxis *axis = GetAxis(i);
00806 range.AddRange(i, axis->GetXmin(), axis->GetXmax());
00807 }
00808 ROOT::Math::MinimizerOptions minOption;
00809
00810 return ROOT::Fit::FitObject(this, f , fitOption , minOption, goption, range);
00811 }
00812
00813
00814 Long64_t THnSparse::GetBin(const Double_t* x, Bool_t allocate )
00815 {
00816
00817
00818
00819 THnSparseCompactBinCoord* cc = GetCompactCoord();
00820 Int_t *coord = cc->GetCoord();
00821 for (Int_t i = 0; i < fNdimensions; ++i)
00822 coord[i] = GetAxis(i)->FindBin(x[i]);
00823 cc->UpdateCoord();
00824
00825 return GetBinIndexForCurrentBin(allocate);
00826 }
00827
00828
00829
00830 Long64_t THnSparse::GetBin(const char* name[], Bool_t allocate )
00831 {
00832
00833
00834
00835 THnSparseCompactBinCoord* cc = GetCompactCoord();
00836 Int_t *coord = cc->GetCoord();
00837 for (Int_t i = 0; i < fNdimensions; ++i)
00838 coord[i] = GetAxis(i)->FindBin(name[i]);
00839 cc->UpdateCoord();
00840
00841 return GetBinIndexForCurrentBin(allocate);
00842 }
00843
00844
00845 Long64_t THnSparse::GetBin(const Int_t* coord, Bool_t allocate )
00846 {
00847
00848
00849 GetCompactCoord()->SetCoord(coord);
00850 return GetBinIndexForCurrentBin(allocate);
00851 }
00852
00853
00854 Double_t THnSparse::GetBinContent(const Int_t *coord) const {
00855
00856 GetCompactCoord()->SetCoord(coord);
00857 Long64_t idx = const_cast<THnSparse*>(this)->GetBinIndexForCurrentBin(kFALSE);
00858 if (idx < 0) return 0.;
00859 THnSparseArrayChunk* chunk = GetChunk(idx / fChunkSize);
00860 return chunk->fContent->GetAt(idx % fChunkSize);
00861 }
00862
00863
00864 Double_t THnSparse::GetBinContent(Long64_t idx, Int_t* coord ) const
00865 {
00866
00867
00868
00869
00870 if (idx >= 0) {
00871 THnSparseArrayChunk* chunk = GetChunk(idx / fChunkSize);
00872 idx %= fChunkSize;
00873 if (chunk && chunk->fContent->GetSize() > idx) {
00874 if (coord) {
00875 THnSparseCompactBinCoord* cc = GetCompactCoord();
00876 Int_t sizeCompact = cc->GetBufferSize();
00877 cc->SetCoordFromBuffer(chunk->fCoordinates + idx * sizeCompact,
00878 coord);
00879
00880 }
00881 return chunk->fContent->GetAt(idx);
00882 }
00883 }
00884 if (coord)
00885 memset(coord, -1, sizeof(Int_t) * fNdimensions);
00886 return 0.;
00887 }
00888
00889
00890 Double_t THnSparse::GetBinError(const Int_t *coord) const {
00891
00892
00893
00894
00895
00896
00897 if (!GetCalculateErrors())
00898 return TMath::Sqrt(GetBinContent(coord));
00899
00900 GetCompactCoord()->SetCoord(coord);
00901 Long64_t idx = const_cast<THnSparse*>(this)->GetBinIndexForCurrentBin(kFALSE);
00902 if (idx < 0) return 0.;
00903
00904 THnSparseArrayChunk* chunk = GetChunk(idx / fChunkSize);
00905 return TMath::Sqrt(chunk->fSumw2->GetAt(idx % fChunkSize));
00906 }
00907
00908
00909 Double_t THnSparse::GetBinError(Long64_t linidx) const {
00910
00911
00912
00913
00914
00915
00916 if (!GetCalculateErrors())
00917 return TMath::Sqrt(GetBinContent(linidx));
00918
00919 if (linidx < 0) return 0.;
00920 THnSparseArrayChunk* chunk = GetChunk(linidx / fChunkSize);
00921 linidx %= fChunkSize;
00922 if (!chunk || chunk->fContent->GetSize() < linidx)
00923 return 0.;
00924
00925 return TMath::Sqrt(chunk->fSumw2->GetAt(linidx));
00926 }
00927
00928
00929
00930 Long64_t THnSparse::GetBinIndexForCurrentBin(Bool_t allocate)
00931 {
00932
00933
00934
00935 THnSparseCompactBinCoord* cc = GetCompactCoord();
00936 ULong64_t hash = cc->GetHash();
00937 if (fBinContent.GetSize() && !fBins.GetSize())
00938 FillExMap();
00939 Long64_t linidx = (Long64_t) fBins.GetValue(hash);
00940 while (linidx) {
00941
00942 THnSparseArrayChunk* chunk = GetChunk((linidx - 1)/ fChunkSize);
00943 if (chunk->Matches((linidx - 1) % fChunkSize, cc->GetBuffer()))
00944 return linidx - 1;
00945
00946 Long64_t nextlinidx = fBinsContinued.GetValue(linidx);
00947 if (!nextlinidx) break;
00948
00949 linidx = nextlinidx;
00950 }
00951 if (!allocate) return -1;
00952
00953 ++fFilledBins;
00954
00955
00956 THnSparseArrayChunk *chunk = (THnSparseArrayChunk*) fBinContent.Last();
00957 Long64_t newidx = chunk ? ((Long64_t) chunk->GetEntries()) : -1;
00958 if (!chunk || newidx == (Long64_t)fChunkSize) {
00959 chunk = AddChunk();
00960 newidx = 0;
00961 }
00962 chunk->AddBin(newidx, cc->GetBuffer());
00963
00964
00965 newidx += (fBinContent.GetEntriesFast() - 1) * fChunkSize;
00966 if (!linidx) {
00967
00968 if (2 * GetNbins() > fBins.Capacity())
00969 fBins.Expand(3 * GetNbins());
00970 fBins.Add(hash, newidx + 1);
00971 } else {
00972
00973
00974 fBinsContinued.Add(linidx, newidx + 1);
00975 }
00976 return newidx;
00977 }
00978
00979
00980 THnSparseCompactBinCoord* THnSparse::GetCompactCoord() const
00981 {
00982
00983
00984 if (!fCompactCoord) {
00985 Int_t *bins = new Int_t[fNdimensions];
00986 for (Int_t d = 0; d < fNdimensions; ++d)
00987 bins[d] = GetAxis(d)->GetNbins();
00988 const_cast<THnSparse*>(this)->fCompactCoord
00989 = new THnSparseCompactBinCoord(fNdimensions, bins);
00990 delete [] bins;
00991 }
00992 return fCompactCoord;
00993 }
00994
00995
00996 void THnSparse::GetRandom(Double_t *rand, Bool_t subBinRandom )
00997 {
00998
00999
01000
01001
01002
01003
01004 if (fIntegralStatus != kValidInt)
01005 ComputeIntegral();
01006
01007
01008 Double_t p = gRandom->Rndm();
01009 Long64_t idx = TMath::BinarySearch(GetNbins() + 1, fIntegral, p);
01010 const Int_t nStaticBins = 40;
01011 Int_t bin[nStaticBins];
01012 Int_t* pBin = bin;
01013 if (GetNdimensions() > nStaticBins) {
01014 pBin = new Int_t[GetNdimensions()];
01015 }
01016 GetBinContent(idx, pBin);
01017
01018
01019 for (Int_t i = 0; i < fNdimensions; i++) {
01020 rand[i] = GetAxis(i)->GetBinCenter(pBin[i]);
01021
01022
01023 if (subBinRandom)
01024 rand[i] += (gRandom->Rndm() - 0.5) * GetAxis(i)->GetBinWidth(pBin[i]);
01025 }
01026 if (pBin != bin) {
01027 delete [] pBin;
01028 }
01029
01030 return;
01031 }
01032
01033
01034 Double_t THnSparse::GetSparseFractionBins() const {
01035
01036
01037 Double_t nbinsTotal = 1.;
01038 for (Int_t d = 0; d < fNdimensions; ++d)
01039 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
01040 return fFilledBins / nbinsTotal;
01041 }
01042
01043
01044 Double_t THnSparse::GetSparseFractionMem() const {
01045
01046
01047
01048 Int_t arrayElementSize = 0;
01049 if (fFilledBins) {
01050 TClass* clArray = GetChunk(0)->fContent->IsA();
01051 TDataMember* dm = clArray ? clArray->GetDataMember("fArray") : 0;
01052 arrayElementSize = dm ? dm->GetDataType()->Size() : 0;
01053 }
01054 if (!arrayElementSize) {
01055 Warning("GetSparseFractionMem", "Cannot determine type of elements!");
01056 return -1.;
01057 }
01058
01059 Double_t sizePerChunkElement = arrayElementSize + GetCompactCoord()->GetBufferSize();
01060 if (fFilledBins && GetChunk(0)->fSumw2)
01061 sizePerChunkElement += sizeof(Double_t);
01062
01063 Double_t size = 0.;
01064 size += fBinContent.GetEntries() * (GetChunkSize() * sizePerChunkElement + sizeof(THnSparseArrayChunk));
01065 size += + 3 * sizeof(Long64_t) * fBins.GetSize() ;
01066
01067 Double_t nbinsTotal = 1.;
01068 for (Int_t d = 0; d < fNdimensions; ++d)
01069 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
01070
01071 return size / nbinsTotal / arrayElementSize;
01072 }
01073
01074
01075 Bool_t THnSparse::IsInRange(Int_t *coord) const
01076 {
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086 Int_t min = 0;
01087 Int_t max = 0;
01088 for (Int_t i = 0; i < fNdimensions; ++i) {
01089 TAxis *axis = GetAxis(i);
01090 if (!axis->TestBit(TAxis::kAxisRange)) continue;
01091 min = axis->GetFirst();
01092 max = axis->GetLast();
01093 if (min == 0 && max == 0) {
01094
01095
01096
01097 min = 1;
01098 max = axis->GetNbins();
01099 }
01100 if (coord[i] < min || coord[i] > max)
01101 return kFALSE;
01102 }
01103 return kTRUE;
01104 }
01105
01106
01107 TH1D* THnSparse::Projection(Int_t xDim, Option_t* option ) const
01108 {
01109
01110
01111
01112
01113
01114
01115
01116
01117 return (TH1D*) ProjectionAny(1, &xDim, false, option);
01118 }
01119
01120
01121 TH2D* THnSparse::Projection(Int_t yDim, Int_t xDim, Option_t* option ) const
01122 {
01123
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133 const Int_t dim[2] = {xDim, yDim};
01134 return (TH2D*) ProjectionAny(2, dim, false, option);
01135 }
01136
01137
01138 TH3D* THnSparse::Projection(Int_t xDim, Int_t yDim, Int_t zDim,
01139 Option_t* option ) const
01140 {
01141
01142
01143
01144
01145
01146
01147
01148
01149 const Int_t dim[3] = {xDim, yDim, zDim};
01150 return (TH3D*) ProjectionAny(3, dim, false, option);
01151 }
01152
01153
01154 THnSparse* THnSparse::Projection(Int_t ndim, const Int_t* dim,
01155 Option_t* option ) const
01156 {
01157
01158
01159
01160
01161
01162
01163
01164
01165 return (THnSparse*) ProjectionAny(ndim, dim, true, option);
01166 }
01167
01168
01169
01170 TObject* THnSparse::ProjectionAny(Int_t ndim, const Int_t* dim,
01171 Bool_t wantSparse, Option_t* option ) const
01172 {
01173
01174
01175
01176
01177
01178
01179
01180
01181 TString name(GetName());
01182 name +="_proj";
01183
01184 for (Int_t d = 0; d < ndim; ++d) {
01185 name += "_";
01186 name += dim[d];
01187 }
01188
01189 TString title(GetTitle());
01190 Ssiz_t posInsert = title.First(';');
01191 if (posInsert == kNPOS) {
01192 title += " projection ";
01193 for (Int_t d = 0; d < ndim; ++d)
01194 title += GetAxis(dim[d])->GetTitle();
01195 } else {
01196 for (Int_t d = ndim - 1; d >= 0; --d) {
01197 title.Insert(posInsert, GetAxis(d)->GetTitle());
01198 if (d)
01199 title.Insert(posInsert, ", ");
01200 }
01201 title.Insert(posInsert, " projection ");
01202 }
01203
01204 TObjArray newaxes(ndim);
01205 for (Int_t d = 0; d < ndim; ++d) {
01206 newaxes.AddAt(GetAxis(dim[d]),d);
01207 }
01208
01209 THnSparse* sparse = 0;
01210 TH1* hist = 0;
01211 TObject* ret = 0;
01212
01213 Bool_t* hadRange = 0;
01214 Bool_t ignoreTargetRange = (option && (strchr(option, 'A') || strchr(option, 'a')));
01215 Bool_t keepTargetAxis = ignoreTargetRange || (option && (strchr(option, 'O') || strchr(option, 'o')));
01216 if (ignoreTargetRange) {
01217 hadRange = new Bool_t[ndim];
01218 for (Int_t d = 0; d < ndim; ++d){
01219 TAxis *axis = GetAxis(dim[d]);
01220 hadRange[d] = axis->TestBit(TAxis::kAxisRange);
01221 axis->SetBit(TAxis::kAxisRange, kFALSE);
01222 }
01223 }
01224
01225 if (wantSparse)
01226 ret = sparse = CloneEmpty(name, title, &newaxes, fChunkSize, keepTargetAxis);
01227 else
01228 ret = hist = CreateHist(name, title, &newaxes, keepTargetAxis);
01229
01230 if (keepTargetAxis) {
01231
01232 if (wantSparse) {
01233 for (Int_t d = 0; d < ndim; ++d) {
01234 sparse->GetAxis(d)->SetRange(0, 0);
01235 }
01236 } else {
01237 hist->GetXaxis()->SetRange(0, 0);
01238 hist->GetYaxis()->SetRange(0, 0);
01239 hist->GetZaxis()->SetRange(0, 0);
01240 }
01241 }
01242
01243 Bool_t haveErrors = GetCalculateErrors();
01244 Bool_t wantErrors = (option && (strchr(option, 'E') || strchr(option, 'e'))) || haveErrors;
01245
01246 Int_t* bins = new Int_t[ndim];
01247 Int_t linbin = 0;
01248 Int_t* coord = new Int_t[fNdimensions];
01249 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01250
01251 Double_t err = 0.;
01252 Double_t preverr = 0.;
01253 Double_t v = 0.;
01254
01255 for (Long64_t i = 0; i < GetNbins(); ++i) {
01256 v = GetBinContent(i, coord);
01257
01258 if (!IsInRange(coord)) continue;
01259
01260 for (Int_t d = 0; d < ndim; ++d) {
01261 bins[d] = coord[dim[d]];
01262 if (!keepTargetAxis && GetAxis(dim[d])->TestBit(TAxis::kAxisRange)) {
01263 bins[d] -= GetAxis(dim[d])->GetFirst() - 1;
01264 }
01265 }
01266
01267 if (!wantSparse) {
01268 if (ndim == 1) linbin = bins[0];
01269 else if (ndim == 2) linbin = hist->GetBin(bins[0], bins[1]);
01270 else if (ndim == 3) linbin = hist->GetBin(bins[0], bins[1], bins[2]);
01271 }
01272
01273 if (wantErrors) {
01274 if (haveErrors) {
01275 err = GetBinError(i);
01276 err *= err;
01277 } else err = v;
01278 if (wantSparse) {
01279 preverr = sparse->GetBinError(bins);
01280 sparse->SetBinError(bins, TMath::Sqrt(preverr * preverr + err));
01281 } else {
01282 preverr = hist->GetBinError(linbin);
01283 hist->SetBinError(linbin, TMath::Sqrt(preverr * preverr + err));
01284 }
01285 }
01286
01287
01288 if (wantSparse)
01289 sparse->AddBinContent(bins, v);
01290 else
01291 hist->AddBinContent(linbin, v);
01292 }
01293
01294 delete [] bins;
01295 delete [] coord;
01296
01297 if (wantSparse)
01298
01299 sparse->SetEntries(fEntries);
01300 else
01301
01302
01303 hist->ResetStats();
01304
01305 if (hadRange) {
01306
01307 for (Int_t d = 0; d < ndim; ++d)
01308 GetAxis(dim[d])->SetBit(TAxis::kAxisRange, hadRange[d]);
01309
01310 delete [] hadRange;
01311 }
01312
01313 return ret;
01314 }
01315
01316
01317 void THnSparse::Scale(Double_t c)
01318 {
01319
01320
01321
01322
01323
01324 Double_t nEntries = GetEntries();
01325
01326 Bool_t haveErrors = GetCalculateErrors();
01327 for (Long64_t i = 0; i < GetNbins(); ++i) {
01328
01329 Double_t v = GetBinContent(i);
01330 SetBinContent(i, c * v);
01331 if (haveErrors) {
01332 Double_t err = GetBinError(i);
01333 SetBinError(i, c * err);
01334 }
01335 }
01336 SetEntries(nEntries);
01337 }
01338
01339
01340 void THnSparse::AddInternal(const THnSparse* h, Double_t c, Bool_t rebinned)
01341 {
01342
01343
01344
01345 if (fNdimensions != h->GetNdimensions()) {
01346 Warning("RebinnedAdd", "Different number of dimensions, cannot carry out operation on the histograms");
01347 return;
01348 }
01349
01350
01351 if (!GetCalculateErrors() && h->GetCalculateErrors())
01352 Sumw2();
01353 Bool_t haveErrors = GetCalculateErrors();
01354
01355
01356 Int_t* coord = new Int_t[fNdimensions];
01357 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01358 Double_t* x = 0;
01359 if (rebinned) {
01360 x = new Double_t[fNdimensions];
01361 }
01362
01363 if (!fBins.GetSize() && fBinContent.GetSize()) {
01364 FillExMap();
01365 }
01366
01367
01368 Long64_t numTargetBins = GetNbins() + h->GetNbins();
01369 if (2 * numTargetBins > fBins.Capacity()) {
01370 fBins.Expand(3 * numTargetBins);
01371 }
01372
01373
01374 for (Long64_t i = 0; i < h->GetNbins(); ++i) {
01375
01376 Double_t v = h->GetBinContent(i, coord);
01377
01378 Long64_t binidx = -1;
01379 if (rebinned) {
01380
01381 for (Int_t j = 0; j < fNdimensions; ++j)
01382 x[j] = h->GetAxis(j)->GetBinCenter(coord[j]);
01383
01384 binidx = GetBin(x);
01385 } else {
01386 binidx = GetBin(coord);
01387 }
01388
01389 if (haveErrors) {
01390 Double_t err1 = GetBinError(binidx);
01391 Double_t err2 = h->GetBinError(i) * c;
01392 SetBinError(binidx, TMath::Sqrt(err1 * err1 + err2 * err2));
01393 }
01394
01395 AddBinContent(binidx, c * v);
01396 }
01397
01398
01399 delete [] coord;
01400 delete [] x;
01401
01402 Double_t nEntries = GetEntries() + c * h->GetEntries();
01403 SetEntries(nEntries);
01404 }
01405
01406
01407 void THnSparse::Add(const THnSparse* h, Double_t c)
01408 {
01409
01410
01411
01412
01413
01414
01415 if (!CheckConsistency(h, "Add")) return;
01416
01417 AddInternal(h, c, kFALSE);
01418 }
01419
01420
01421 void THnSparse::RebinnedAdd(const THnSparse* h, Double_t c)
01422 {
01423
01424
01425
01426
01427
01428
01429
01430 AddInternal(h, c, kTRUE);
01431 }
01432
01433
01434
01435 Long64_t THnSparse::Merge(TCollection* list)
01436 {
01437
01438
01439
01440 if (!list) return 0;
01441 if (list->IsEmpty()) return (Long64_t)GetEntries();
01442
01443 Long64_t sumNbins = GetNbins();
01444 TIter iter(list);
01445 const TObject* addMeObj = 0;
01446 while ((addMeObj = iter())) {
01447 const THnSparse* addMe = dynamic_cast<const THnSparse*>(addMeObj);
01448 if (addMe) {
01449 sumNbins += addMe->GetNbins();
01450 }
01451 }
01452 if (!fBins.GetSize() && fBinContent.GetSize()) {
01453 FillExMap();
01454 }
01455 if (2 * sumNbins > fBins.Capacity()) {
01456 fBins.Expand(3 * sumNbins);
01457 }
01458
01459 iter.Reset();
01460 while ((addMeObj = iter())) {
01461 const THnSparse* addMe = dynamic_cast<const THnSparse*>(addMeObj);
01462 if (!addMe)
01463 Error("Merge", "Object named %s is not THnSpase! Skipping it.",
01464 addMeObj->GetName());
01465 else
01466 Add(addMe);
01467 }
01468 return (Long64_t)GetEntries();
01469 }
01470
01471
01472
01473 void THnSparse::Multiply(const THnSparse* h)
01474 {
01475
01476
01477
01478
01479
01480
01481 if(!CheckConsistency(h, "Multiply"))return;
01482
01483
01484 Bool_t wantErrors = kFALSE;
01485 if (GetCalculateErrors() || h->GetCalculateErrors())
01486 wantErrors = kTRUE;
01487
01488 if (wantErrors) Sumw2();
01489
01490 Double_t nEntries = GetEntries();
01491
01492 Int_t* coord = new Int_t[fNdimensions];
01493 for (Long64_t i = 0; i < GetNbins(); ++i) {
01494
01495 Double_t v1 = GetBinContent(i, coord);
01496
01497 Double_t v2 = h->GetBinContent(coord);
01498 SetBinContent(coord, v1 * v2);;
01499 if (wantErrors) {
01500 Double_t err1 = GetBinError(coord) * v2;
01501 Double_t err2 = h->GetBinError(coord) * v1;
01502 SetBinError(coord,TMath::Sqrt((err2 * err2 + err1 * err1)));
01503 }
01504 }
01505 SetEntries(nEntries);
01506
01507 delete [] coord;
01508 }
01509
01510
01511 void THnSparse::Multiply(TF1* f, Double_t c)
01512 {
01513
01514
01515
01516
01517
01518
01519
01520
01521 Int_t* coord = new Int_t[fNdimensions];
01522 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01523 Double_t* points = new Double_t[fNdimensions];
01524
01525
01526 Bool_t wantErrors = GetCalculateErrors();
01527 if (wantErrors) Sumw2();
01528
01529 ULong64_t nEntries = GetNbins();
01530 for (ULong64_t i = 0; i < nEntries; ++i) {
01531 Double_t value = GetBinContent(i, coord);
01532
01533
01534 for (Int_t j = 0; j < fNdimensions; ++j)
01535 points[j] = GetAxis(j)->GetBinCenter(coord[j]);
01536
01537 if (!f->IsInside(points))
01538 continue;
01539 TF1::RejectPoint(kFALSE);
01540
01541
01542 Double_t fvalue = f->EvalPar(points, NULL);
01543
01544 SetBinContent(coord, c * fvalue * value);
01545 if (wantErrors) {
01546 Double_t error(GetBinError(i));
01547 SetBinError(coord, c * fvalue * error);
01548 }
01549 }
01550
01551 delete [] points;
01552 delete [] coord;
01553 }
01554
01555
01556 void THnSparse::Divide(const THnSparse *h)
01557 {
01558
01559
01560
01561
01562
01563
01564
01565 if (!CheckConsistency(h, "Divide"))return;
01566
01567
01568 Bool_t wantErrors=GetCalculateErrors();
01569 if (!GetCalculateErrors() && h->GetCalculateErrors())
01570 wantErrors=kTRUE;
01571
01572
01573 Double_t nEntries = fEntries;
01574
01575 if (wantErrors) Sumw2();
01576 Bool_t didWarn = kFALSE;
01577
01578
01579 Int_t* coord = new Int_t[fNdimensions];
01580 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01581 Double_t err = 0.;
01582 Double_t b22 = 0.;
01583 for (Long64_t i = 0; i < GetNbins(); ++i) {
01584
01585 Double_t v1 = GetBinContent(i, coord);
01586
01587 Double_t v2 = h->GetBinContent(coord);
01588 if (!v2) {
01589 v1 = 0.;
01590 v2 = 1.;
01591 if (!didWarn) {
01592 Warning("Divide(h)", "Histogram h has empty bins - division by zero! Setting bin to 0.");
01593 didWarn = kTRUE;
01594 }
01595 }
01596 SetBinContent(coord, v1 / v2);
01597 if (wantErrors) {
01598 Double_t err1 = GetBinError(coord) * v2;
01599 Double_t err2 = h->GetBinError(coord) * v1;
01600 b22 = v2 * v2;
01601 err = (err1 * err1 + err2 * err2) / (b22 * b22);
01602 SetBinError(coord, TMath::Sqrt(err));
01603 }
01604 }
01605 delete [] coord;
01606 SetEntries(nEntries);
01607 }
01608
01609
01610 void THnSparse::Divide(const THnSparse *h1, const THnSparse *h2, Double_t c1, Double_t c2, Option_t *option)
01611 {
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621 TString opt = option;
01622 opt.ToLower();
01623 Bool_t binomial = kFALSE;
01624 if (opt.Contains("b")) binomial = kTRUE;
01625
01626
01627 if (!CheckConsistency(h1, "Divide") || !CheckConsistency(h2, "Divide"))return;
01628 if (!c2) {
01629 Error("Divide","Coefficient of dividing histogram cannot be zero");
01630 return;
01631 }
01632
01633 Reset();
01634
01635
01636 if (!GetCalculateErrors() && (h1->GetCalculateErrors()|| h2->GetCalculateErrors() != 0))
01637 Sumw2();
01638
01639
01640 Long64_t nFilledBins=0;
01641
01642
01643
01644 Int_t* coord = new Int_t[fNdimensions];
01645 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01646 Float_t w = 0.;
01647 Float_t err = 0.;
01648 Float_t b22 = 0.;
01649 Bool_t didWarn = kFALSE;
01650
01651 for (Long64_t i = 0; i < h1->GetNbins(); ++i) {
01652
01653 Double_t v1 = h1->GetBinContent(i, coord);
01654
01655 Double_t v2 = h2->GetBinContent(coord);
01656 if (!v2) {
01657 v1 = 0.;
01658 v2 = 1.;
01659 if (!didWarn) {
01660 Warning("Divide(h1, h2)", "Histogram h2 has empty bins - division by zero! Setting bin to 0.");
01661 didWarn = kTRUE;
01662 }
01663 }
01664 nFilledBins++;
01665 SetBinContent(coord, c1 * v1 / c2 / v2);
01666 if(GetCalculateErrors()){
01667 Double_t err1=h1->GetBinError(coord);
01668 Double_t err2=h2->GetBinError(coord);
01669 if (binomial) {
01670 if (v1 != v2) {
01671 w = v1 / v2;
01672 err2 *= w;
01673 err = TMath::Abs( ( (1. - 2.*w) * err1 * err1 + err2 * err2 ) / (v2 * v2) );
01674 } else {
01675 err = 0;
01676 }
01677 } else {
01678 c1 *= c1;
01679 c2 *= c2;
01680 b22 = v2 * v2 * c2;
01681 err1 *= v2;
01682 err2 *= v1;
01683 err = c1 * c2 * (err1 * err1 + err2 * err2) / (b22 * b22);
01684 }
01685 SetBinError(coord,TMath::Sqrt(err));
01686 }
01687 }
01688
01689 delete [] coord;
01690 fFilledBins = nFilledBins;
01691
01692
01693 SetEntries(h1->GetEntries());
01694 }
01695
01696
01697 Bool_t THnSparse::CheckConsistency(const THnSparse *h, const char *tag) const
01698 {
01699
01700
01701 if (fNdimensions!=h->GetNdimensions()) {
01702 Warning(tag,"Different number of dimensions, cannot carry out operation on the histograms");
01703 return kFALSE;
01704 }
01705 for (Int_t dim = 0; dim < fNdimensions; dim++){
01706 if (GetAxis(dim)->GetNbins()!=h->GetAxis(dim)->GetNbins()) {
01707 Warning(tag,"Different number of bins on axis %i, cannot carry out operation on the histograms", dim);
01708 return kFALSE;
01709 }
01710 }
01711 return kTRUE;
01712 }
01713
01714
01715 void THnSparse::SetBinEdges(Int_t idim, const Double_t* bins)
01716 {
01717
01718
01719 TAxis* axis = (TAxis*) fAxes[idim];
01720 axis->Set(axis->GetNbins(), bins);
01721 }
01722
01723
01724 void THnSparse::SetBinContent(const Int_t* coord, Double_t v)
01725 {
01726
01727
01728 GetCompactCoord()->SetCoord(coord);
01729 Long_t bin = GetBinIndexForCurrentBin(kTRUE);
01730 SetBinContent(bin, v);
01731 }
01732
01733
01734 void THnSparse::SetBinContent(Long64_t bin, Double_t v)
01735 {
01736
01737
01738 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
01739 chunk->fContent->SetAt(v, bin % fChunkSize);
01740 ++fEntries;
01741 }
01742
01743
01744 void THnSparse::SetBinError(const Int_t* coord, Double_t e)
01745 {
01746
01747
01748 GetCompactCoord()->SetCoord(coord);
01749 Long_t bin = GetBinIndexForCurrentBin(kTRUE);
01750 SetBinError(bin, e);
01751 }
01752
01753
01754 void THnSparse::SetBinError(Long64_t bin, Double_t e)
01755 {
01756
01757
01758 THnSparseArrayChunk* chunk = GetChunk(bin / fChunkSize);
01759 if (!chunk->fSumw2 ) {
01760
01761 if (GetCalculateErrors()) {
01762 Error("SetBinError", "GetCalculateErrors() logic error!");
01763 }
01764 Sumw2();
01765 }
01766
01767 chunk->fSumw2->SetAt(e * e, bin % fChunkSize);
01768 }
01769
01770
01771 void THnSparse::Sumw2()
01772 {
01773
01774
01775 if (GetCalculateErrors()) return;
01776
01777 fTsumw2 = 0.;
01778 TIter iChunk(&fBinContent);
01779 THnSparseArrayChunk* chunk = 0;
01780 while ((chunk = (THnSparseArrayChunk*) iChunk()))
01781 chunk->Sumw2();
01782 }
01783
01784
01785 THnSparse* THnSparse::Rebin(Int_t group) const
01786 {
01787
01788
01789
01790
01791
01792 Int_t* ngroup = new Int_t[GetNdimensions()];
01793 for (Int_t d = 0; d < GetNdimensions(); ++d)
01794 ngroup[d] = group;
01795 THnSparse* ret = Rebin(ngroup);
01796 delete [] ngroup;
01797 return ret;
01798 }
01799
01800
01801 void THnSparse::SetTitle(const char *title)
01802 {
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812 fTitle = title;
01813 fTitle.ReplaceAll("#;",2,"#semicolon",10);
01814
01815 Int_t endHistTitle = fTitle.First(';');
01816 if (endHistTitle >= 0) {
01817
01818 Int_t posTitle = endHistTitle + 1;
01819 Int_t lenTitle = fTitle.Length();
01820 Int_t dim = 0;
01821 while (posTitle > 0 && posTitle < lenTitle && dim < fNdimensions){
01822 Int_t endTitle = fTitle.Index(";", posTitle);
01823 TString axisTitle = fTitle(posTitle, endTitle - posTitle);
01824 axisTitle.ReplaceAll("#semicolon", 10, ";", 1);
01825 GetAxis(dim)->SetTitle(axisTitle);
01826 dim++;
01827 if (endTitle > 0)
01828 posTitle = endTitle + 1;
01829 else
01830 posTitle = -1;
01831 }
01832
01833 fTitle.Remove(endHistTitle, lenTitle - endHistTitle);
01834 }
01835
01836 fTitle.ReplaceAll("#semicolon", 10, ";", 1);
01837
01838 }
01839
01840 THnSparse* THnSparse::Rebin(const Int_t* group) const
01841 {
01842
01843
01844
01845
01846
01847 Int_t ndim = GetNdimensions();
01848 TString name(GetName());
01849 for (Int_t d = 0; d < ndim; ++d)
01850 name += Form("_%d", group[d]);
01851
01852
01853 TString title(GetTitle());
01854 Ssiz_t posInsert = title.First(';');
01855 if (posInsert == kNPOS) {
01856 title += " rebin ";
01857 for (Int_t d = 0; d < ndim; ++d)
01858 title += Form("{%d}", group[d]);
01859 } else {
01860 for (Int_t d = ndim - 1; d >= 0; --d)
01861 title.Insert(posInsert, Form("{%d}", group[d]));
01862 title.Insert(posInsert, " rebin ");
01863 }
01864
01865 TObjArray newaxes(ndim);
01866 newaxes.SetOwner();
01867 for (Int_t d = 0; d < ndim; ++d) {
01868 newaxes.AddAt(GetAxis(d)->Clone(),d);
01869 if (group[d] > 1) {
01870 TAxis* newaxis = (TAxis*) newaxes.At(d);
01871 Int_t newbins = (newaxis->GetNbins() + group[d] - 1) / group[d];
01872 if (newaxis->GetXbins() && newaxis->GetXbins()->GetSize()) {
01873
01874 Double_t *edges = new Double_t[newbins + 1];
01875 for (Int_t i = 0; i < newbins + 1; ++i)
01876 if (group[d] * i <= newaxis->GetNbins())
01877 edges[i] = newaxis->GetXbins()->At(group[d] * i);
01878 else edges[i] = newaxis->GetXmax();
01879 newaxis->Set(newbins, edges);
01880 delete [] edges;
01881 } else {
01882 newaxis->Set(newbins, newaxis->GetXmin(), newaxis->GetXmax());
01883 }
01884 }
01885 }
01886
01887 THnSparse* h = CloneEmpty(name.Data(), title.Data(), &newaxes, fChunkSize, kTRUE);
01888 Bool_t haveErrors = GetCalculateErrors();
01889 Bool_t wantErrors = haveErrors;
01890
01891 Int_t* bins = new Int_t[ndim];
01892 Int_t* coord = new Int_t[fNdimensions];
01893 memset(coord, 0, sizeof(Int_t) * fNdimensions);
01894 Double_t err = 0.;
01895 Double_t preverr = 0.;
01896 Double_t v = 0.;
01897
01898 for (Long64_t i = 0; i < GetNbins(); ++i) {
01899 v = GetBinContent(i, coord);
01900 for (Int_t d = 0; d < ndim; ++d)
01901 bins[d] = TMath::CeilNint( (double) coord[d]/group[d] );
01902
01903 if (wantErrors) {
01904 if (haveErrors) {
01905 err = GetBinError(i);
01906 err *= err;
01907 } else err = v;
01908 preverr = h->GetBinError(bins);
01909 h->SetBinError(bins, TMath::Sqrt(preverr * preverr + err));
01910 }
01911
01912
01913 h->AddBinContent(bins, v);
01914 }
01915
01916 delete [] bins;
01917 delete [] coord;
01918
01919 h->SetEntries(fEntries);
01920
01921 return h;
01922
01923 }
01924
01925
01926 void THnSparse::Reset(Option_t * )
01927 {
01928
01929 fFilledBins = 0;
01930 fEntries = 0.;
01931 fTsumw = 0.;
01932 fTsumw2 = -1.;
01933 fBins.Delete();
01934 fBinsContinued.Clear();
01935 fBinContent.Delete();
01936 if (fIntegralStatus != kNoInt) {
01937 delete [] fIntegral;
01938 fIntegralStatus = kNoInt;
01939 }
01940 }
01941
01942
01943 Double_t THnSparse::ComputeIntegral()
01944 {
01945
01946
01947
01948 if (fIntegralStatus != kNoInt) {
01949 delete [] fIntegral;
01950 fIntegralStatus = kNoInt;
01951 }
01952
01953
01954 if (GetNbins() == 0) {
01955 Error("ComputeIntegral", "The histogram must have at least one bin.");
01956 return 0.;
01957 }
01958
01959
01960 fIntegral = new Double_t [GetNbins() + 1];
01961 fIntegral[0] = 0.;
01962
01963
01964 Int_t* coord = new Int_t[fNdimensions];
01965 for (Long64_t i = 0; i < GetNbins(); ++i) {
01966 Double_t v = GetBinContent(i, coord);
01967
01968
01969 bool regularBin = true;
01970 for (Int_t dim = 0; dim < fNdimensions; dim++)
01971 if (coord[dim] < 1 || coord[dim] > GetAxis(dim)->GetNbins()) {
01972 regularBin = false;
01973 break;
01974 }
01975
01976
01977 if (!regularBin) v = 0.;
01978
01979 fIntegral[i + 1] = fIntegral[i] + v;
01980 }
01981 delete [] coord;
01982
01983
01984 if (fIntegral[GetNbins()] == 0.) {
01985 Error("ComputeIntegral", "No hits in regular bins (non over/underflow).");
01986 delete [] fIntegral;
01987 return 0.;
01988 }
01989
01990
01991 for (Long64_t i = 0; i <= GetNbins(); ++i)
01992 fIntegral[i] = fIntegral[i] / fIntegral[GetNbins()];
01993
01994
01995 fIntegralStatus = kValidInt;
01996 return fIntegral[GetNbins()];
01997 }
01998
01999
02000 void THnSparse::PrintBin(Long64_t idx, Option_t* options) const
02001 {
02002
02003
02004 Int_t* coord = new Int_t[fNdimensions];
02005 PrintBin(idx, coord, options);
02006 delete [] coord;
02007 }
02008
02009
02010 Bool_t THnSparse::PrintBin(Long64_t idx, Int_t* bin, Option_t* options) const
02011 {
02012
02013
02014
02015
02016
02017
02018 Double_t v = -42;
02019 if (idx == -1) {
02020 idx = const_cast<THnSparse*>(this)->GetBin(bin, kFALSE);
02021 v = GetBinContent(idx);
02022 } else {
02023 v = GetBinContent(idx, bin);
02024 }
02025
02026 if (options && strchr(options, '0') && v == 0.) {
02027 if (GetCalculateErrors()) {
02028 if (GetBinError(idx) == 0.) {
02029
02030 return kFALSE;
02031 }
02032 } else {
02033
02034 return kFALSE;
02035 }
02036 }
02037
02038 TString coord;
02039 for (Int_t dim = 0; dim < fNdimensions; ++dim) {
02040 coord += bin[dim];
02041 coord += ',';
02042 }
02043 coord.Remove(coord.Length() - 1);
02044
02045 if (GetCalculateErrors()) {
02046 Double_t err = 0.;
02047 if (idx != -1) {
02048 err = GetBinError(idx);
02049 }
02050 Printf("Bin at (%s) = %g (+/- %g)", coord.Data(), v, err);
02051 } else {
02052 Printf("Bin at (%s) = %g", coord.Data(), v);
02053 }
02054
02055 return kTRUE;
02056 }
02057
02058
02059 void THnSparse::PrintEntries(Long64_t from , Long64_t howmany ,
02060 Option_t* options ) const
02061 {
02062
02063
02064
02065
02066
02067 if (from < 0) from = 0;
02068 if (howmany == -1) howmany = GetNbins();
02069
02070 Int_t* bin = new Int_t[fNdimensions];
02071
02072 if (options && (strchr(options, 'x') || strchr(options, 'X'))) {
02073 Int_t* nbins = new Int_t[fNdimensions];
02074 for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
02075 nbins[dim] = GetAxis(dim)->GetNbins();
02076 bin[dim] = from % nbins[dim];
02077 from /= nbins[dim];
02078 }
02079
02080 for (Long64_t i = 0; i < howmany; ++i) {
02081 if (!PrintBin(-1, bin, options))
02082 ++howmany;
02083
02084 ++bin[fNdimensions - 1];
02085 for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
02086 if (bin[dim] >= nbins[dim]) {
02087 bin[dim] = 0;
02088 if (dim > 0) {
02089 ++bin[dim - 1];
02090 } else {
02091 howmany = -1;
02092 }
02093 }
02094 }
02095 }
02096 delete [] nbins;
02097 } else {
02098 for (Long64_t i = from; i < from + howmany; ++i) {
02099 if (!PrintBin(i, bin, options))
02100 ++howmany;
02101 }
02102 }
02103 delete [] bin;
02104 }
02105
02106
02107 void THnSparse::Print(Option_t* options) const
02108 {
02109
02110
02111
02112
02113
02114
02115
02116 Bool_t optAxis = options && (strchr(options, 'A') || (strchr(options, 'a')));
02117 Bool_t optMem = options && (strchr(options, 'M') || (strchr(options, 'm')));
02118 Bool_t optStat = options && (strchr(options, 'S') || (strchr(options, 's')));
02119 Bool_t optContent = options && (strchr(options, 'C') || (strchr(options, 'c')));
02120
02121 Printf("%s (*0x%lx): \"%s\" \"%s\"", IsA()->GetName(), (unsigned long)this, GetName(), GetTitle());
02122 Printf(" %d dimensions, %g entries in %lld filled bins", GetNdimensions(), GetEntries(), GetNbins());
02123
02124 if (optAxis) {
02125 for (Int_t dim = 0; dim < fNdimensions; ++dim) {
02126 TAxis* axis = GetAxis(dim);
02127 Printf(" axis %d \"%s\": %d bins (%g..%g), %s bin sizes", dim,
02128 axis->GetTitle(), axis->GetNbins(), axis->GetXmin(), axis->GetXmax(),
02129 (axis->GetXbins() ? "variable" : "fixed"));
02130 }
02131 }
02132
02133 if (optStat) {
02134 Printf(" %s error calculation", (GetCalculateErrors() ? "with" : "without"));
02135 if (GetCalculateErrors()) {
02136 Printf(" Sum(w)=%g, Sum(w^2)=%g", GetSumw(), GetSumw2());
02137 for (Int_t dim = 0; dim < fNdimensions; ++dim) {
02138 Printf(" axis %d: Sum(w*x)=%g, Sum(w*x^2)=%g", dim, GetSumwx(dim), GetSumwx2(dim));
02139 }
02140 }
02141 }
02142
02143 if (optMem) {
02144 Printf(" coordinates stored in %d chunks of %d entries\n %g of bins filled using %g of memory compared to an array",
02145 GetNChunks(), GetChunkSize(), GetSparseFractionBins(), GetSparseFractionMem());
02146 }
02147
02148 if (optContent) {
02149 Printf(" BIN CONTENT:");
02150 PrintEntries(0, -1, options);
02151 }
02152 }
02153