Logo ROOT  
Reference Guide
 
Loading...
Searching...
No Matches
THnSparse.cxx
Go to the documentation of this file.
1// @(#)root/hist:$Id$
2// Author: Axel Naumann (2007-09-11)
3
4/*************************************************************************
5 * Copyright (C) 1995-2012, Rene Brun and Fons Rademakers. *
6 * All rights reserved. *
7 * *
8 * For the licensing terms see $ROOTSYS/LICENSE. *
9 * For the list of contributors see $ROOTSYS/README/CREDITS. *
10 *************************************************************************/
11
12#include "THnSparse.h"
13
14#include "TAxis.h"
15#include "TClass.h"
16#include "TDataMember.h"
17#include "TDataType.h"
18
19namespace {
20//______________________________________________________________________________
21//
22// THnSparseBinIter iterates over all filled bins of a THnSparse.
23//______________________________________________________________________________
24
25 class THnSparseBinIter: public ROOT::Internal::THnBaseBinIter {
26 public:
27 THnSparseBinIter(Bool_t respectAxisRange, const THnSparse* hist):
28 ROOT::Internal::THnBaseBinIter(respectAxisRange), fHist(hist),
29 fNbins(hist->GetNbins()), fIndex(-1) {
30 // Construct a THnSparseBinIter
31 fCoord = new Int_t[hist->GetNdimensions()];
32 fCoord[0] = -1;
33 }
34 ~THnSparseBinIter() override { delete [] fCoord; }
35
36 Int_t GetCoord(Int_t dim) const override;
37 Long64_t Next(Int_t* coord = nullptr) override;
38
39 private:
40 THnSparseBinIter(const THnSparseBinIter&) = delete; // intentionally unimplemented
41 THnSparseBinIter& operator=(const THnSparseBinIter&) = delete; // intentionally unimplemented
42
43 const THnSparse* fHist;
44 Int_t* fCoord; // coord buffer for fIndex; fCoord[0] == -1 if not yet calculated
45 Long64_t fNbins; // number of bins to iterate over
46 Long64_t fIndex; // current bin index
47 };
48}
49
50Int_t THnSparseBinIter::GetCoord(Int_t dim) const
51{
52 if (fCoord[0] == -1) {
53 fHist->GetBinContent(fIndex, fCoord);
54 }
55 return fCoord[dim];
56}
57
58Long64_t THnSparseBinIter::Next(Int_t* coord /*= 0*/)
59{
60 // Get next bin index (in range if RespectsAxisRange()).
61 // If coords != 0, set it to the index's axis coordinates
62 // (i.e. coord must point to an array of Int_t[fNdimension]
63 if (!fHist) return -1;
64
65 fCoord[0] = -1;
66 Int_t* useCoordBuf = fCoord;
67 if (coord) {
69 coord[0] = -1;
70 }
72 do {
73 ++fIndex;
74 if (fIndex >= fHist->GetNbins()) {
75 fHist = nullptr;
76 return -1;
77 }
78 if (RespectsAxisRange()) {
79 fHist->GetBinContent(fIndex, useCoordBuf);
80 }
81 } while (RespectsAxisRange()
82 && !fHist->IsInRange(useCoordBuf)
83 && (fHaveSkippedBin = kTRUE /* assignment! */));
84
85 if (coord && coord[0] == -1) {
86 if (fCoord[0] == -1) {
87 fHist->GetBinContent(fIndex, coord);
88 } else {
89 memcpy(coord, fCoord, fHist->GetNdimensions() * sizeof(Int_t));
90 }
91 }
92
93 return fIndex;
94}
95
96
97
98/** \class THnSparseCoordCompression
99THnSparseCoordCompression is a class used by THnSparse internally. It
100represents a compacted n-dimensional array of bin coordinates (indices).
101As the total number of bins in each dimension is known by THnSparse, bin
102indices can be compacted to only use the amount of bins needed by the total
103number of bins in each dimension. E.g. for a THnSparse with
104{15, 100, 2, 20, 10, 100} bins per dimension, a bin index will only occupy
10528 bits (4+7+1+5+4+7), i.e. less than a 32bit integer. The tricky part is
106the fast compression and decompression, the platform-independent storage
107(think of endianness: the bits of the number 0x123456 depend on the
108platform), and the hashing needed by THnSparseArrayChunk.
109*/
110
111
113public:
117
119
120 ULong64_t GetHashFromBuffer(const Char_t* buf) const;
121 Int_t GetBufferSize() const { return fCoordBufferSize; }
122 Int_t GetNdimensions() const { return fNdimensions; }
123 void SetCoordFromBuffer(const Char_t* buf_in, Int_t* coord_out) const;
124 ULong64_t SetBufferFromCoord(const Int_t* coord_in, Char_t* buf_out) const;
125
126protected:
128 // return the number of bits allocated by the number "n"
129 Int_t r = (n > 0);
130 while (n/=2) ++r;
131 return r;
132 }
133private:
134 Int_t fNdimensions; // number of dimensions
135 Int_t fCoordBufferSize; // size of coordbuf
136 Int_t *fBitOffsets; //[fNdimensions + 1] bit offset of each axis index
137};
138
139
140//______________________________________________________________________________
141//______________________________________________________________________________
142
143
144////////////////////////////////////////////////////////////////////////////////
145/// Initialize a THnSparseCoordCompression object with "dim" dimensions
146/// and "bins" holding the number of bins for each dimension; it
147/// stores the
148
150 fNdimensions(dim), fCoordBufferSize(0), fBitOffsets(nullptr)
151{
152 fBitOffsets = new Int_t[dim + 1];
153
154 int shift = 0;
155 for (Int_t i = 0; i < dim; ++i) {
156 fBitOffsets[i] = shift;
157 shift += GetNumBits(nbins[i] + 2);
158 }
159 fBitOffsets[dim] = shift;
160 fCoordBufferSize = (shift + 7) / 8;
161}
162
163
164////////////////////////////////////////////////////////////////////////////////
165/// Construct a THnSparseCoordCompression from another one
166
174
175
176////////////////////////////////////////////////////////////////////////////////
177/// Set this to other if different.
178
180{
181 if (&other == this) return *this;
182
183 fNdimensions = other.fNdimensions;
184 fCoordBufferSize = other.fCoordBufferSize;
185 delete [] fBitOffsets;
186 fBitOffsets = new Int_t[fNdimensions + 1];
187 memcpy(fBitOffsets, other.fBitOffsets, sizeof(Int_t) * fNdimensions);
188 return *this;
189}
190
191
192////////////////////////////////////////////////////////////////////////////////
193/// destruct a THnSparseCoordCompression
194
199
200
201////////////////////////////////////////////////////////////////////////////////
202/// Given the compressed coordinate buffer buf_in, calculate ("decompact")
203/// the bin coordinates and return them in coord_out.
204
206 Int_t* coord_out) const
207{
208 for (Int_t i = 0; i < fNdimensions; ++i) {
209 const Int_t offset = fBitOffsets[i] / 8;
210 Int_t shift = fBitOffsets[i] % 8;
211 Int_t nbits = fBitOffsets[i + 1] - fBitOffsets[i];
212 const UChar_t* pbuf = (const UChar_t*) buf_in + offset;
213 coord_out[i] = *pbuf >> shift;
214 Int_t subst = (Int_t) -1;
215 subst = subst << nbits;
216 nbits -= (8 - shift);
217 shift = 8 - shift;
218 for (Int_t n = 0; n * 8 < nbits; ++n) {
219 ++pbuf;
220 coord_out[i] += *pbuf << shift;
221 shift += 8;
222 }
223 coord_out[i] &= ~subst;
224 }
225}
226
227
228////////////////////////////////////////////////////////////////////////////////
229/// Given the cbin coordinates coord_in, calculate ("compact")
230/// the bin coordinates and return them in buf_in.
231/// Return the hash value.
232
234 Char_t* buf_out) const
235{
236 if (fCoordBufferSize <= 8) {
237 ULong64_t l64buf = 0;
238 for (Int_t i = 0; i < fNdimensions; ++i) {
239 l64buf += ((ULong64_t)((UInt_t)coord_in[i])) << fBitOffsets[i];
240 }
241 memcpy(buf_out, &l64buf, sizeof(Long64_t));
242 return l64buf;
243 }
244
245 // else: doesn't fit into a Long64_t:
247 for (Int_t i = 0; i < fNdimensions; ++i) {
248 const Int_t offset = fBitOffsets[i] / 8;
249 const Int_t shift = fBitOffsets[i] % 8;
250 ULong64_t val = coord_in[i];
251
253 *pbuf += 0xff & (val << shift);
254 val = val >> (8 - shift);
255 while (val) {
256 ++pbuf;
257 *pbuf += 0xff & val;
258 val = val >> 8;
259 }
260 }
261
263}
264
265
266////////////////////////////////////////////////////////////////////////////////
267/// Calculate hash from compact bin index.
268
270{
271 // Bins are addressed in two different modes, depending
272 // on whether the compact bin index fits into a Long64_t or not.
273 // If it does, we can use it as a "perfect hash" for the TExMap.
274 // If not we build a hash from the compact bin index, and use that
275 // as the TExMap's hash.
276
277 if (fCoordBufferSize <= 8) {
278 // fits into a Long64_t
279 ULong64_t hash1 = 0;
281 return hash1;
282 }
283
284 // else: doesn't fit into a Long64_t:
285 ULong64_t hash = 5381;
286 const Char_t* str = buf;
287 while (str - buf < fCoordBufferSize) {
288 hash *= 5;
289 hash += *(str++);
290 }
291 return hash;
292}
293
294
295
296
297/** \class THnSparseCompactBinCoord
298THnSparseCompactBinCoord is a class used by THnSparse internally. It
299maps between an n-dimensional array of bin coordinates (indices) and
300its compact version, the THnSparseCoordCompression.
301*/
302
304public:
308 const Char_t* GetBuffer() const { return fCoordBuffer; }
309 ULong64_t GetHash() const { return fHash; }
317 void SetBuffer(const Char_t* buf) {
320 }
321
322private:
323 // intentionally not implemented
325 // intentionally not implemented
327
328private:
329 ULong64_t fHash; // hash for current coordinates; 0 if not calculated
330 Char_t *fCoordBuffer; // compact buffer of coordinates
331 Int_t *fCurrentBin; // current coordinates
332};
333
334
335//______________________________________________________________________________
336//______________________________________________________________________________
337
338
339////////////////////////////////////////////////////////////////////////////////
340/// Initialize a THnSparseCompactBinCoord object with "dim" dimensions
341/// and "bins" holding the number of bins for each dimension.
342
345 fHash(0), fCoordBuffer(nullptr), fCurrentBin(nullptr)
346{
347 fCurrentBin = new Int_t[dim];
348 size_t bufAllocSize = GetBufferSize();
349 if (bufAllocSize < sizeof(Long64_t))
350 bufAllocSize = sizeof(Long64_t);
352}
353
354
355////////////////////////////////////////////////////////////////////////////////
356/// destruct a THnSparseCompactBinCoord
357
363
364/** \class THnSparseArrayChunk
365THnSparseArrayChunk is used internally by THnSparse.
366THnSparse stores its (dynamic size) array of bin coordinates and their
367contents (and possibly errors) in a TObjArray of THnSparseArrayChunk. Each
368of the chunks holds an array of THnSparseCompactBinCoord and the content
369(a TArray*), which is created outside (by the templated derived classes of
370THnSparse) and passed in at construction time.
371*/
372
373
374////////////////////////////////////////////////////////////////////////////////
375/// (Default) initialize a chunk. Takes ownership of cont (~THnSparseArrayChunk deletes it),
376/// and create an ArrayF for errors if "errors" is true.
377
379 fCoordinateAllocationSize(-1), fSingleCoordinateSize(coordsize), fCoordinatesSize(0),
380 fCoordinates(nullptr), fContent(cont),
381 fSumw2(nullptr)
382{
385 if (errors) Sumw2();
386}
387
388////////////////////////////////////////////////////////////////////////////////
389/// Destructor
390
392{
393 delete fContent;
394 delete [] fCoordinates;
395 delete fSumw2;
396}
397
398////////////////////////////////////////////////////////////////////////////////
399/// Create a new bin in this chunk
400
402{
403 // When streaming out only the filled chunk is saved.
404 // When reading back only the memory needed for that filled part gets
405 // allocated. We need to check whether the allowed chunk size is
406 // bigger than the allocated size. If fCoordinateAllocationSize is
407 // set to -1 this chunk has been allocated by the streamer and the
408 // buffer allocation size is defined by [fCoordinatesSize]. In that
409 // case we need to compare fCoordinatesSize to
410 // fSingleCoordinateSize * fContent->GetSize()
411 // to determine whether we need to expand the buffer.
412 if (fCoordinateAllocationSize == -1 && fContent) {
415 // need to re-allocate:
418 delete [] fCoordinates;
420 }
422 }
423
426}
427
428////////////////////////////////////////////////////////////////////////////////
429/// Turn on support of errors
430
432{
433 if (!fSumw2)
434 fSumw2 = new TArrayD(fContent->GetSize());
435 // fill the structure with the current content
436 for (Int_t bin=0; bin < fContent->GetSize(); bin++) {
438 }
439
440}
441
442
443/** \class THnSparse
444 \ingroup Hist
445
446Efficient multidimensional histogram.
447
448Use a THnSparse instead of TH1 / TH2 / TH3 / array for histogramming when
449only a small fraction of bins is filled. A 10-dimensional histogram with 10
450bins per dimension has 10^10 bins; in a naive implementation this will not
451fit in memory. THnSparse only allocates memory for the bins that have
452non-zero bin content instead, drastically reducing both the memory usage
453and the access time.
454
455To construct a THnSparse object you must use one of its templated, derived
456classes:
457- THnSparseD (typedef for THnSparseT<ArrayD>): bin content held by a Double_t,
458- THnSparseF (typedef for THnSparseT<ArrayF>): bin content held by a Float_t,
459- THnSparseL (typedef for THnSparseT<ArrayL64>): bin content held by a Long64_t,
460- THnSparseI (typedef for THnSparseT<ArrayI>): bin content held by an Int_t,
461- THnSparseS (typedef for THnSparseT<ArrayS>): bin content held by a Short_t,
462- THnSparseC (typedef for THnSparseT<ArrayC>): bin content held by a Char_t,
463
464They take name and title, the number of dimensions, and for each dimension
465the number of bins, the minimal, and the maximal value on the dimension's
466axis. A TH2 h("h","h",10, 0., 10., 20, -5., 5.) would correspond to
467
468 Int_t bins[2] = {10, 20};
469 Double_t xmin[2] = {0., -5.};
470 Double_t xmax[2] = {10., 5.};
471 THnSparseD hs("hs", "hs", 2, bins, xmin, xmax);
472
473## Filling
474A THnSparse is filled just like a regular histogram, using
475THnSparse::Fill(x, weight), where x is a n-dimensional Double_t value.
476To take errors into account, Sumw2() must be called before filling the
477histogram.
478
479Bins are allocated as needed; the status of the allocation can be observed
480by GetSparseFractionBins(), GetSparseFractionMem().
481
482## Fast Bin Content Access
483When iterating over a THnSparse one should only look at filled bins to save
484processing time. The number of filled bins is returned by
485THnSparse::GetNbins(); the bin content for each (linear) bin number can
486be retrieved by THnSparse::GetBinContent(linidx, (Int_t*)coord).
487After the call, coord will contain the bin coordinate of each axis for the bin
488with linear index linidx. A possible call would be
489
490 std::cout << hs.GetBinContent(0, coord);
491 std::cout <<" is the content of bin [x = " << coord[0] "
492 << " | y = " << coord[1] << "]" << std::endl;
493
494## Efficiency
495TH1 and TH2 are generally faster than THnSparse for one and two dimensional
496distributions. THnSparse becomes competitive for a sparsely filled TH3
497with large numbers of bins per dimension. The tutorial \ref hist103_THnSparse_hist.C
498shows the turning point. On a AMD64 with 8GB memory, THnSparse "wins"
499starting with a TH3 with 30 bins per dimension. Using a THnSparse for a
500one-dimensional histogram is only reasonable if it has a huge number of bins.
501
502## Projections
503The dimensionality of a THnSparse can be reduced by projecting it to
5041, 2, 3, or n dimensions, which can be represented by a TH1, TH2, TH3, or
505a THnSparse. See the Projection() members. To only project parts of the
506histogram, call
507
508 THnSparse::GetAxis(12)->SetRange(from_bin, to_bin);
509
510## Internal Representation
511An entry for a filled bin consists of its n-dimensional coordinates and
512its bin content. The coordinates are compacted to use as few bits as
513possible; e.g. a histogram with 10 bins in x and 20 bins in y will only
514use 4 bits for the x representation and 5 bits for the y representation.
515This is handled by the internal class THnSparseCompactBinCoord.
516Bin data (content and coordinates) are allocated in chunks of size
517fChunkSize; this parameter can be set when constructing a THnSparse. Each
518chunk is represented by an object of class THnSparseArrayChunk.
519
520Translation from an n-dimensional bin coordinate to the linear index within
521the chunks is done by GetBin(). It creates a hash from the compacted bin
522coordinates (the hash of a bin coordinate is the compacted coordinate itself
523if it takes less than 8 bytes, the size of a Long64_t.
524This hash is used to lookup the linear index in the TExMap member fBins;
525the coordinates of the entry fBins points to is compared to the coordinates
526passed to GetBin(). If they do not match, these two coordinates have the same
527hash - which is extremely unlikely but (for the case where the compact bin
528coordinates are larger than 4 bytes) possible. In this case, fBinsContinued
529contains a chain of linear indexes with the same hash. Iterating through this
530chain and comparing each bin coordinates with the one passed to GetBin() will
531retrieve the matching bin.
532*/
533
534
535
536////////////////////////////////////////////////////////////////////////////////
537/// Construct an empty THnSparse.
538
540 fChunkSize(1024), fFilledBins(0), fCompactCoord(nullptr)
541{
543}
544
545////////////////////////////////////////////////////////////////////////////////
546/// Construct a THnSparse with "dim" dimensions,
547/// with chunksize as the size of the chunks.
548/// "nbins" holds the number of bins for each dimension;
549/// "xmin" and "xmax" the minimal and maximal value for each dimension.
550/// The arrays "xmin" and "xmax" can be NULL; in that case SetBinEdges()
551/// must be called for each dimension.
552
553THnSparse::THnSparse(const char* name, const char* title, Int_t dim,
554 const Int_t* nbins, const Double_t* xmin, const Double_t* xmax,
556 THnBase(name, title, dim, nbins, xmin, xmax),
557 fChunkSize(chunksize), fFilledBins(0), fCompactCoord(nullptr)
558{
561}
562
563////////////////////////////////////////////////////////////////////////////////
564/// Construct a THnSparse with chunksize as the size of the chunks.
565/// "axes" is a vector of TAxis, its size sets the number of dimensions.
566/// This method is convenient for passing the Axes on the fly:
567/// auto h0= new THnSparseI{"h0", "", {{100, -50., 50.}, {50, -1000., 1000.}}};
568
569THnSparse::THnSparse(const char* name, const char* title,
570 const std::vector<TAxis>& axes,
572THnBase(name, title, axes),
573 fChunkSize(chunksize), fFilledBins(0), fCompactCoord(nullptr)
574{
575 const size_t dim=axes.size();
576 auto nbins=new Int_t[dim];
577 for (size_t i=0; i<dim; i++)
578 nbins[i]=axes.at(i).GetNbins();
581 delete[] nbins;
582}
583
584////////////////////////////////////////////////////////////////////////////////
585/// Construct a THnSparse with dim dimensions and unequal binning.
586/// nbins and std::vector xbins are used to describe bin edges for each dimension.
587/// chunksize represents the size of the chunks.
588
589THnSparse::THnSparse(const char *name, const char *title, Int_t dim, const Int_t *nbins,
590 const std::vector<std::vector<double>> &xbins, Int_t chunksize)
591 : THnBase(name, title, dim, nbins, xbins), fChunkSize(chunksize), fFilledBins(0), fCompactCoord(nullptr)
592{
595}
596
597////////////////////////////////////////////////////////////////////////////////
598/// Construct a THnSparse as a copy of "other"
599
601 : THnBase(other),
602 fChunkSize(other.fChunkSize),
603 fFilledBins(other.fFilledBins),
604 fBins(other.fBins),
605 fBinsContinued(other.fBinsContinued),
606 fCompactCoord(nullptr)
607{
608
609 TObjArray *copiedContent = (TObjArray *)other.fBinContent.Clone();
611 copiedContent->SetOwner(kFALSE);
612 delete copiedContent;
614
615 Int_t dim = other.GetNdimensions();
616 std::vector<Int_t> nbins(dim);
617 for (Int_t i = 0; i < dim; i++)
618 nbins[i] = other.GetAxis(i)->GetNbins();
619
621}
622
623/// Destruct a THnSparse
624
628
629////////////////////////////////////////////////////////////////////////////////
630/// Add "v" to the content of bin with index "bin"
631
633{
635 bin %= fChunkSize;
636 v += chunk->fContent->GetAt(bin);
637 return chunk->fContent->SetAt(v, bin);
638}
639
640////////////////////////////////////////////////////////////////////////////////
641/// Create a new chunk of bin content
642
651
652////////////////////////////////////////////////////////////////////////////////
653/// Initialize the storage of a histogram created via Init()
654
660
661////////////////////////////////////////////////////////////////////////////////
662///We have been streamed; set up fBins
663
665{
667 THnSparseArrayChunk* chunk = nullptr;
669 Long64_t idx = 0;
670 if (2 * GetNbins() > fBins.Capacity())
671 fBins.Expand(3 * GetNbins());
672 while ((chunk = (THnSparseArrayChunk*) iChunk())) {
673 const Int_t chunkSize = chunk->GetEntries();
674 Char_t* buf = chunk->fCoordinates;
675 const Int_t singleCoordSize = chunk->fSingleCoordinateSize;
676 const Char_t* endbuf = buf + singleCoordSize * chunkSize;
677 for (; buf < endbuf; buf += singleCoordSize, ++idx) {
678 Long64_t hash = compactCoord.GetHashFromBuffer(buf);
680 if (linidx) {
682 while (nextidx) {
683 // must be a collision, so go to fBinsContinued.
684 linidx = nextidx;
686 }
687 fBinsContinued.Add(linidx, idx + 1);
688 } else {
689 fBins.Add(hash, idx + 1);
690 }
691 }
692 }
693}
694
695////////////////////////////////////////////////////////////////////////////////
696/// Initialize storage for nbins
697
699 if (!fBins.GetSize() && fBinContent.GetSize()) {
700 FillExMap();
701 }
702 if (2 * nbins > fBins.Capacity()) {
703 fBins.Expand(3 * nbins);
704 }
705}
706
707////////////////////////////////////////////////////////////////////////////////
708/// Get the bin index for the n dimensional tuple x,
709/// allocate one if it doesn't exist yet and "allocate" is true.
710
712{
714 Int_t *coord = cc->GetCoord();
715 for (Int_t i = 0; i < fNdimensions; ++i)
716 coord[i] = GetAxis(i)->FindBin(x[i]);
717 cc->UpdateCoord();
718
720}
721
722
723////////////////////////////////////////////////////////////////////////////////
724/// Get the bin index for the n dimensional tuple addressed by "name",
725/// allocate one if it doesn't exist yet and "allocate" is true.
726
727Long64_t THnSparse::GetBin(const char* name[], Bool_t allocate /* = kTRUE */)
728{
730 Int_t *coord = cc->GetCoord();
731 for (Int_t i = 0; i < fNdimensions; ++i)
732 coord[i] = GetAxis(i)->FindBin(name[i]);
733 cc->UpdateCoord();
734
736}
737
738////////////////////////////////////////////////////////////////////////////////
739/// Get the bin index for the n dimensional coordinates coord,
740/// allocate one if it doesn't exist yet and "allocate" is true.
741
747
748////////////////////////////////////////////////////////////////////////////////
749/// Return the content of the filled bin number "idx".
750/// If coord is non-null, it will contain the bin's coordinates for each axis
751/// that correspond to the bin.
752
754{
755 if (idx >= 0) {
757 idx %= fChunkSize;
758 if (chunk && chunk->fContent->GetSize() > idx) {
759 if (coord) {
761 Int_t sizeCompact = cc->GetBufferSize();
762 cc->SetCoordFromBuffer(chunk->fCoordinates + idx * sizeCompact,
763 coord);
764
765 }
766 return chunk->fContent->GetAt(idx);
767 }
768 }
769 if (coord)
770 memset(coord, -1, sizeof(Int_t) * fNdimensions);
771 return 0.;
772}
773
774////////////////////////////////////////////////////////////////////////////////
775/// Get square of the error of bin addressed by linidx as
776/// \f$\sum weight^{2}\f$
777/// If errors are not enabled (via Sumw2() or CalculateErrors())
778/// return contents.
779
781 if (!GetCalculateErrors())
782 return GetBinContent(linidx);
783
784 if (linidx < 0) return 0.;
787 if (!chunk || chunk->fContent->GetSize() < linidx)
788 return 0.;
789
790 return chunk->fSumw2->GetAt(linidx);
791}
792
793
794////////////////////////////////////////////////////////////////////////////////
795/// Return the index for fCurrentBinIndex.
796/// If it doesn't exist then return -1, or allocate a new bin if allocate is set
797
799{
801 ULong64_t hash = cc->GetHash();
802 if (fBinContent.GetSize() && !fBins.GetSize())
803 FillExMap();
805 while (linidx) {
806 // fBins stores index + 1!
808 if (chunk->Matches((linidx - 1) % fChunkSize, cc->GetBuffer()))
809 return linidx - 1; // we store idx+1, 0 is "TExMap: not found"
810
812 if (!nextlinidx) break;
813
815 }
816 if (!allocate) return -1;
817
818 ++fFilledBins;
819
820 // allocate bin in chunk
822 Long64_t newidx = chunk ? ((Long64_t) chunk->GetEntries()) : -1;
823 if (!chunk || newidx == (Long64_t)fChunkSize) {
824 chunk = AddChunk();
825 newidx = 0;
826 }
827 chunk->AddBin(newidx, cc->GetBuffer());
828
829 // store translation between hash and bin
831 if (!linidx) {
832 // fBins didn't find it
833 if (2 * GetNbins() > fBins.Capacity())
834 fBins.Expand(3 * GetNbins());
835 fBins.Add(hash, newidx + 1);
836 } else {
837 // fBins contains one, but it's the wrong one;
838 // add entry to fBinsContinued.
840 }
841 return newidx;
842}
843
844////////////////////////////////////////////////////////////////////////////////
845/// Return THnSparseCompactBinCoord object.
846
848{
849 if (!fCompactCoord) {
850 Int_t *bins = new Int_t[fNdimensions];
851 for (Int_t d = 0; d < fNdimensions; ++d)
852 bins[d] = GetAxis(d)->GetNbins();
853 const_cast<THnSparse*>(this)->fCompactCoord
855 delete [] bins;
856 }
857 return fCompactCoord;
858}
859
860////////////////////////////////////////////////////////////////////////////////
861/// Return the amount of filled bins over all bins
862
864 Double_t nbinsTotal = 1.;
865 for (Int_t d = 0; d < fNdimensions; ++d)
866 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
867 return fFilledBins / nbinsTotal;
868}
869
870////////////////////////////////////////////////////////////////////////////////
871/// Return the amount of used memory over memory that would be used by a
872/// non-sparse n-dimensional histogram. The value is approximate.
873
876 if (fFilledBins) {
878 TDataMember* dm = clArray ? clArray->GetDataMember("fArray") : nullptr;
879 arrayElementSize = dm ? dm->GetDataType()->Size() : 0;
880 }
881 if (!arrayElementSize) {
882 Warning("GetSparseFractionMem", "Cannot determine type of elements!");
883 return -1.;
884 }
885
887 if (fFilledBins && GetChunk(0)->fSumw2)
888 sizePerChunkElement += sizeof(Double_t); /* fSumw2 */
889
890 Double_t size = 0.;
892 size += + 3 * sizeof(Long64_t) * fBins.GetSize() /* TExMap */;
893
894 Double_t nbinsTotal = 1.;
895 for (Int_t d = 0; d < fNdimensions; ++d)
896 nbinsTotal *= GetAxis(d)->GetNbins() + 2;
897
899}
900
901////////////////////////////////////////////////////////////////////////////////
902/// Create an iterator over all filled bins of a THnSparse.
903/// Use THnIter instead.
904
906{
907 return new THnSparseBinIter(respectAxisRange, this);
908}
909
910////////////////////////////////////////////////////////////////////////////////
911/// Set content of bin with index "bin" to "v"
912
919
920////////////////////////////////////////////////////////////////////////////////
921/// Set error of bin with index "bin" to "e", enable errors if needed
922
924{
926 if (!chunk->fSumw2 ) {
927 // if fSumw2 is zero GetCalculateErrors should return false
928 if (GetCalculateErrors()) {
929 Error("SetBinError", "GetCalculateErrors() logic error!");
930 }
931 Sumw2(); // enable error calculation
932 }
933
934 chunk->fSumw2->SetAt(e2, bin % fChunkSize);
935}
936
937////////////////////////////////////////////////////////////////////////////////
938/// Add "e" to error of bin with index "bin", enable errors if needed
939
941{
943 if (!chunk->fSumw2 ) {
944 // if fSumw2 is zero GetCalculateErrors should return false
945 if (GetCalculateErrors()) {
946 Error("SetBinError", "GetCalculateErrors() logic error!");
947 }
948 Sumw2(); // enable error calculation
949 }
950
951 (*chunk->fSumw2)[bin % fChunkSize] += e2;
952}
953
954////////////////////////////////////////////////////////////////////////////////
955/// Enable calculation of errors
956
958{
959 if (GetCalculateErrors()) return;
960
961 fTsumw2 = 0.;
963 THnSparseArrayChunk* chunk = nullptr;
964 while ((chunk = (THnSparseArrayChunk*) iChunk()))
965 chunk->Sumw2();
966}
967
968////////////////////////////////////////////////////////////////////////////////
969/// Clear the histogram
970
972{
973 fFilledBins = 0;
974 fBins.Delete();
978}
979
#define d(i)
Definition RSha256.hxx:102
size_t size(const MatrixT &matrix)
retrieve the size of a square matrix
bool Bool_t
Boolean (0=false, 1=true) (bool)
Definition RtypesCore.h:78
int Int_t
Signed integer 4 bytes (int)
Definition RtypesCore.h:60
char Char_t
Character 1 byte (char)
Definition RtypesCore.h:52
constexpr Bool_t kFALSE
Definition RtypesCore.h:109
double Double_t
Double 8 bytes.
Definition RtypesCore.h:74
long long Long64_t
Portable signed long integer 8 bytes.
Definition RtypesCore.h:84
unsigned long long ULong64_t
Portable unsigned long integer 8 bytes.
Definition RtypesCore.h:85
constexpr Bool_t kTRUE
Definition RtypesCore.h:108
const char Option_t
Option string (const char)
Definition RtypesCore.h:81
ROOT::Detail::TRangeCast< T, true > TRangeDynCast
TRangeDynCast is an adapter class that allows the typed iteration through a TCollection.
Option_t Option_t option
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t Float_t Float_t Int_t Int_t UInt_t UInt_t Rectangle_t Int_t Int_t Window_t TString Int_t GCValues_t GetPrimarySelectionOwner GetDisplay GetScreen GetColormap GetNativeEvent const char const char dpyName wid window const char font_name cursor keysym reg const char only_if_exist regb h Point_t winding char text const char depth char const char Int_t count const char ColorStruct_t color const char Pixmap_t Pixmap_t PictureAttributes_t attr const char char ret_data h unsigned char height h offset
Option_t Option_t TPoint TPoint const char GetTextMagnitude GetFillStyle GetLineColor GetLineWidth GetMarkerStyle GetTextAlign GetTextColor GetTextSize void char Point_t Rectangle_t WindowAttributes_t Float_t r
char name[80]
Definition TGX11.cxx:148
float xmin
float xmax
Iterator over THnBase bins (internal implementation).
Definition THnBase.h:328
Array of doubles (64 bits per element).
Definition TArrayD.h:27
Double_t * fArray
Definition TArrayD.h:30
Abstract array base class.
Definition TArray.h:31
virtual TClass * IsA() const
Definition TArray.h:60
virtual Double_t GetAt(Int_t i) const =0
Int_t GetSize() const
Definition TArray.h:47
virtual Int_t FindBin(Double_t x)
Find bin number corresponding to abscissa x.
Definition TAxis.cxx:293
Int_t GetNbins() const
Definition TAxis.h:127
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition TClass.h:84
virtual void SetOwner(Bool_t enable=kTRUE)
Set whether this collection is the owner (enable==true) of its content.
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
All ROOT classes may have RTTI (run time type identification) support added.
Definition TDataMember.h:31
TDataType * GetDataType() const
Definition TDataMember.h:76
Int_t Size() const
Get size of basic typedef'ed type.
void Expand(Int_t newsize)
Expand the TExMap.
Definition TExMap.cxx:278
Int_t GetSize() const
Definition TExMap.h:71
void Add(ULong64_t hash, Long64_t key, Long64_t value)
Add an (key,value) pair to the table. The key should be unique.
Definition TExMap.cxx:87
Long64_t GetValue(ULong64_t hash, Long64_t key)
Return the value belonging to specified key and hash value.
Definition TExMap.cxx:173
Int_t Capacity() const
Definition TExMap.h:69
void Delete(Option_t *opt="") override
Delete all entries stored in the TExMap.
Definition TExMap.cxx:163
Multidimensional histogram base.
Definition THnBase.h:45
Double_t fEntries
Number of entries, spread over chunks.
Definition THnBase.h:50
Int_t GetNdimensions() const
Definition THnBase.h:145
void ResetBase(Option_t *option="")
Clear the histogram.
Definition THnBase.cxx:1343
Bool_t GetCalculateErrors() const
Definition THnBase.h:146
Double_t fTsumw2
Total sum of weights squared; -1 if no errors are calculated.
Definition THnBase.h:52
TAxis * GetAxis(Int_t dim) const
Definition THnBase.h:135
Int_t fNdimensions
Number of dimensions.
Definition THnBase.h:47
THnSparseArrayChunk is used internally by THnSparse.
~THnSparseArrayChunk() override
Destructor.
TArrayD * fSumw2
Bin errors.
Int_t fCoordinatesSize
Size of the bin coordinate buffer.
Int_t fSingleCoordinateSize
Size of a single bin coordinate.
void Sumw2()
Turn on support of errors.
Char_t * fCoordinates
[fCoordinatesSize] compact bin coordinate buffer
TArray * fContent
Bin content.
void AddBin(Int_t idx, const Char_t *idxbuf)
Create a new bin in this chunk.
Int_t fCoordinateAllocationSize
! Size of the allocated coordinate buffer; -1 means none or fCoordinatesSize
THnSparseCompactBinCoord is a class used by THnSparse internally.
THnSparseCompactBinCoord(Int_t dim, const Int_t *nbins)
Initialize a THnSparseCompactBinCoord object with "dim" dimensions and "bins" holding the number of b...
ULong64_t GetHash() const
const Char_t * GetBuffer() const
~THnSparseCompactBinCoord()
destruct a THnSparseCompactBinCoord
THnSparseCompactBinCoord(const THnSparseCompactBinCoord &)=delete
void SetBuffer(const Char_t *buf)
void SetCoord(const Int_t *coord)
THnSparseCompactBinCoord & operator=(const THnSparseCompactBinCoord &)=delete
THnSparseCoordCompression is a class used by THnSparse internally.
Int_t GetNdimensions() const
Int_t GetNumBits(Int_t n) const
void SetCoordFromBuffer(const Char_t *buf_in, Int_t *coord_out) const
Given the compressed coordinate buffer buf_in, calculate ("decompact") the bin coordinates and return...
ULong64_t SetBufferFromCoord(const Int_t *coord_in, Char_t *buf_out) const
Given the cbin coordinates coord_in, calculate ("compact") the bin coordinates and return them in buf...
Int_t GetBufferSize() const
THnSparseCoordCompression & operator=(const THnSparseCoordCompression &other)
Set this to other if different.
ULong64_t GetHashFromBuffer(const Char_t *buf) const
Calculate hash from compact bin index.
THnSparseCoordCompression(Int_t dim, const Int_t *nbins)
Initialize a THnSparseCoordCompression object with "dim" dimensions and "bins" holding the number of ...
~THnSparseCoordCompression()
destruct a THnSparseCoordCompression
Efficient multidimensional histogram.
Definition THnSparse.h:37
Double_t GetSparseFractionBins() const
Return the amount of filled bins over all bins.
Double_t GetSparseFractionMem() const
Return the amount of used memory over memory that would be used by a non-sparse n-dimensional histogr...
Double_t GetBinContent(Long64_t bin, Int_t *idx=nullptr) const override
Return the content of the filled bin number "idx".
void Reset(Option_t *option="") override
Clear the histogram.
void AddBinError2(Long64_t bin, Double_t e2) override
Add "e" to error of bin with index "bin", enable errors if needed.
THnSparseArrayChunk * GetChunk(Int_t idx) const
Definition THnSparse.h:51
THnSparseCompactBinCoord * fCompactCoord
! Compact coordinate
Definition THnSparse.h:44
Int_t GetChunkSize() const
Definition THnSparse.h:97
void SetBinContent(Long64_t bin, Double_t v) override
Set content of bin with index "bin" to "v".
Long64_t fFilledBins
Number of filled bins.
Definition THnSparse.h:40
Long64_t GetBin(const Int_t *idx) const override
Definition THnSparse.h:105
void AddBinContent(Long64_t bin, Double_t v=1.) override
Add "v" to the content of bin with index "bin".
TObjArray fBinContent
Array of THnSparseArrayChunk.
Definition THnSparse.h:41
THnSparseCompactBinCoord * GetCompactCoord() const
Return THnSparseCompactBinCoord object.
void InitStorage(Int_t *nbins, Int_t chunkSize) override
Initialize the storage of a histogram created via Init()
Double_t GetBinError2(Long64_t linidx) const override
Get square of the error of bin addressed by linidx as If errors are not enabled (via Sumw2() or Calc...
THnSparse()
Construct an empty THnSparse.
THnSparseArrayChunk * AddChunk()
Create a new chunk of bin content.
virtual TArray * GenerateArray() const =0
void SetBinError2(Long64_t bin, Double_t e2) override
Set error of bin with index "bin" to "e", enable errors if needed.
void FillExMap()
We have been streamed; set up fBins.
~THnSparse() override
Destruct a THnSparse.
TExMap fBins
! Filled bins
Definition THnSparse.h:42
TExMap fBinsContinued
! Filled bins for non-unique hashes, containing pairs of (bin index 0, bin index 1)
Definition THnSparse.h:43
void Reserve(Long64_t nbins) override
Initialize storage for nbins.
Int_t fChunkSize
Number of entries for each chunk.
Definition THnSparse.h:39
void Sumw2() override
Enable calculation of errors.
Long64_t GetNbins() const override
Definition THnSparse.h:102
ROOT::Internal::THnBaseBinIter * CreateIter(Bool_t respectAxisRange) const override
Create an iterator over all filled bins of a THnSparse.
Long64_t GetBinIndexForCurrentBin(Bool_t allocate)
Return the index for fCurrentBinIndex.
An array of TObjects.
Definition TObjArray.h:31
Int_t GetEntriesFast() const
Definition TObjArray.h:58
TObject * Last() const override
Return the object in the last filled slot. Returns 0 if no entries.
Int_t GetEntries() const override
Return the number of objects in array (i.e.
void Delete(Option_t *option="") override
Remove all objects from the array AND delete all heap based objects.
void AddLast(TObject *obj) override
Add object in the next empty slot in the array.
virtual void Clear(Option_t *="")
Definition TObject.h:127
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition TObject.cxx:1082
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition TObject.cxx:1096
Double_t x[n]
Definition legend1.C:17
const Int_t n
Definition legend1.C:16