#include "THnBase.h"
#include "TAxis.h"
#include "TBrowser.h"
#include "TError.h"
#include "TClass.h"
#include "TF1.h"
#include "TH1D.h"
#include "TH2D.h"
#include "TH3D.h"
#include "THn.h"
#include "THnSparse.h"
#include "TMath.h"
#include "TRandom.h"
#include "TVirtualPad.h"
#include "HFitInterface.h"
#include "Fit/SparseData.h"
#include "Math/MinimizerOptions.h"
#include "Math/WrappedMultiTF1.h"
ClassImp(THnBase);
THnBase::THnBase(const char* name, const char* title, Int_t dim,
const Int_t* nbins, const Double_t* xmin, const Double_t* xmax):
TNamed(name, title), fNdimensions(dim), fAxes(dim), fBrowsables(dim),
fEntries(0), fTsumw(0), fTsumw2(-1.), fTsumwx(dim), fTsumwx2(dim),
fIntegral(0), fIntegralStatus(kNoInt)
{
for (Int_t i = 0; i < fNdimensions; ++i) {
TAxis* axis = new TAxis(nbins[i], xmin ? xmin[i] : 0., xmax ? xmax[i] : 1.);
axis->SetName(TString::Format("axis%d", i));
fAxes.AddAtAndExpand(axis, i);
}
SetTitle(title);
fAxes.SetOwner();
}
THnBase::~THnBase() {
if (fIntegralStatus != kNoInt) delete [] fIntegral;
}
THnBase* THnBase::CloneEmpty(const char* name, const char* title,
const TObjArray* axes, Bool_t keepTargetAxis) const
{
THnBase* ret = (THnBase*)IsA()->New();
Int_t chunkSize = 1024 * 16;
if (InheritsFrom(THnSparse::Class())) {
chunkSize = ((const THnSparse*)this)->GetChunkSize();
}
ret->Init(name, title, axes, keepTargetAxis, chunkSize);
return ret;
}
void THnBase::Init(const char* name, const char* title,
const TObjArray* axes, Bool_t keepTargetAxis,
Int_t chunkSize )
{
SetNameTitle(name, title);
TIter iAxis(axes);
const TAxis* axis = 0;
Int_t pos = 0;
Int_t *nbins = new Int_t[axes->GetEntriesFast()];
while ((axis = (TAxis*)iAxis())) {
TAxis* reqaxis = new TAxis(*axis);
if (!keepTargetAxis && axis->TestBit(TAxis::kAxisRange)) {
Int_t binFirst = axis->GetFirst();
if (binFirst == 0)
binFirst = 1;
Int_t binLast = axis->GetLast();
if (binLast > axis->GetNbins())
binLast = axis->GetNbins();
Int_t nBins = binLast - binFirst + 1;
if (axis->GetXbins()->GetSize()) {
reqaxis->Set(nBins, axis->GetXbins()->GetArray() + binFirst - 1);
} else {
reqaxis->Set(nBins, axis->GetBinLowEdge(binFirst), axis->GetBinUpEdge(binLast));
}
reqaxis->ResetBit(TAxis::kAxisRange);
}
nbins[pos] = reqaxis->GetNbins();
fAxes.AddAtAndExpand(new TAxis(*reqaxis), pos++);
}
fAxes.SetOwner();
fNdimensions = axes->GetEntriesFast();
InitStorage(nbins, chunkSize);
delete [] nbins;
}
TH1* THnBase::CreateHist(const char* name, const char* title,
const TObjArray* axes,
Bool_t keepTargetAxis ) const {
const int ndim = axes->GetSize();
TH1* hist = 0;
if (ndim == 1)
hist = new TH1D(name, title, 1, 0., 1.);
else if (ndim == 2)
hist = new TH2D(name, title, 1, 0., 1., 1, 0., 1.);
else if (ndim == 3)
hist = new TH3D(name, title, 1, 0., 1., 1, 0., 1., 1, 0., 1.);
else {
Error("CreateHist", "Cannot create histogram %s with %d dimensions!", name, ndim);
return 0;
}
TAxis* hax[3] = {hist->GetXaxis(), hist->GetYaxis(), hist->GetZaxis()};
for (Int_t d = 0; d < ndim; ++d) {
TAxis* reqaxis = (TAxis*)(*axes)[d];
hax[d]->SetTitle(reqaxis->GetTitle());
if (!keepTargetAxis && reqaxis->TestBit(TAxis::kAxisRange)) {
Int_t binFirst = reqaxis->GetFirst();
if (binFirst == 0) binFirst = 1;
Int_t binLast = reqaxis->GetLast();
Int_t nBins = binLast - binFirst + 1;
if (reqaxis->GetXbins()->GetSize()) {
hax[d]->Set(nBins, reqaxis->GetXbins()->GetArray() + binFirst - 1);
} else {
hax[d]->Set(nBins, reqaxis->GetBinLowEdge(binFirst), reqaxis->GetBinUpEdge(binLast));
}
} else {
if (reqaxis->GetXbins()->GetSize()) {
hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXbins()->GetArray());
} else {
hax[d]->Set(reqaxis->GetNbins(), reqaxis->GetXmin(), reqaxis->GetXmax());
}
}
}
hist->Rebuild();
return hist;
}
THnBase* THnBase::CreateHnAny(const char* name, const char* title,
const TH1* h, Bool_t sparse, Int_t chunkSize)
{
int ndim = h->GetDimension();
int nbins[3] = {0,0,0};
double minRange[3] = {0.,0.,0.};
double maxRange[3] = {0.,0.,0.};
TAxis* axis[3] = { h->GetXaxis(), h->GetYaxis(), h->GetZaxis() };
for (int i = 0; i < ndim; ++i) {
nbins[i] = axis[i]->GetNbins();
minRange[i] = axis[i]->GetXmin();
maxRange[i] = axis[i]->GetXmax();
}
THnBase* s = 0;
const char* cname( h->ClassName() );
if (cname[0] == 'T' && cname[1] == 'H'
&& cname[2] >= '1' && cname[2] <= '3' && cname[4] == 0) {
#define R__THNBCASE(TAG) \
if (sparse) { \
s = new _NAME2_(THnSparse,TAG)(name, title, ndim, nbins, \
minRange, maxRange, chunkSize); \
} else { \
s = new _NAME2_(THn,TAG)(name, title, ndim, nbins, \
minRange, maxRange); \
} \
break;
switch (cname[3]) {
case 'F': R__THNBCASE(F);
case 'D': R__THNBCASE(D);
case 'I': R__THNBCASE(I);
case 'S': R__THNBCASE(S);
case 'C': R__THNBCASE(C);
}
#undef R__THNBCASE
}
if (!s) {
::Warning("THnSparse::CreateHnAny", "Unknown Type of Histogram");
return 0;
}
for (int i = 0; i < ndim; ++i) {
s->GetAxis(i)->SetTitle(axis[i]->GetTitle());
}
const TArray *array = dynamic_cast<const TArray*>(h);
if (!array) {
::Warning("THnSparse::CreateHnAny", "Unknown Type of Histogram");
return 0;
}
s->Add(h);
return s;
}
THnBase* THnBase::CreateHnAny(const char* name, const char* title,
const THnBase* hn, Bool_t sparse,
Int_t chunkSize )
{
TClass* type = 0;
if (hn->InheritsFrom(THnSparse::Class())) {
if (sparse) type = hn->IsA();
else {
char bintype;
if (hn->InheritsFrom(THnSparseD::Class())) bintype = 'D';
else if (hn->InheritsFrom(THnSparseF::Class())) bintype = 'F';
else if (hn->InheritsFrom(THnSparseL::Class())) bintype = 'L';
else if (hn->InheritsFrom(THnSparseI::Class())) bintype = 'I';
else if (hn->InheritsFrom(THnSparseS::Class())) bintype = 'S';
else if (hn->InheritsFrom(THnSparseC::Class())) bintype = 'C';
else {
hn->Error("CreateHnAny", "Type %s not implemented; please inform the ROOT team!",
hn->IsA()->GetName());
return 0;
}
type = TClass::GetClass(TString::Format("THn%c", bintype));
}
} else if (hn->InheritsFrom(THn::Class())) {
if (!sparse) type = hn->IsA();
else {
char bintype = 0;
if (hn->InheritsFrom(THnD::Class())) bintype = 'D';
else if (hn->InheritsFrom(THnF::Class())) bintype = 'F';
else if (hn->InheritsFrom(THnC::Class())) bintype = 'C';
else if (hn->InheritsFrom(THnS::Class())) bintype = 'S';
else if (hn->InheritsFrom(THnI::Class())) bintype = 'I';
else if (hn->InheritsFrom(THnL::Class())) bintype = 'L';
else if (hn->InheritsFrom(THnL64::Class())) {
hn->Error("CreateHnAny", "Type THnSparse with Long64_t bins is not available!");
return 0;
}
if (bintype) {
type = TClass::GetClass(TString::Format("THnSparse%c", bintype));
}
}
} else {
hn->Error("CreateHnAny", "Unhandled type %s, not deriving from THn nor THnSparse!",
hn->IsA()->GetName());
return 0;
}
if (!type) {
hn->Error("CreateHnAny", "Unhandled type %s, please inform the ROOT team!",
hn->IsA()->GetName());
return 0;
}
THnBase* ret = (THnBase*)type->New();
ret->Init(name, title, hn->GetListOfAxes(),
kFALSE , chunkSize);
ret->Add(hn);
return ret;
}
void THnBase::Add(const TH1* hist, Double_t c )
{
Long64_t nbins = hist->GetNbinsX() + 2;
if (hist->GetDimension() >= 2) nbins *= hist->GetNbinsY() + 2;
if (hist->GetDimension() >= 3) nbins *= hist->GetNbinsZ() + 2;
int x[3] = {0,0,0};
for (int i = 0; i < nbins; ++i) {
double value = hist->GetBinContent(i);
double error = hist->GetBinError(i);
if (!value && !error) continue;
hist->GetBinXYZ(i, x[0], x[1], x[2]);
SetBinContent(x, value * c);
SetBinError(x, error * c);
}
}
TFitResultPtr THnBase::Fit(TF1 *f ,Option_t *option ,Option_t *goption)
{
Foption_t fitOption;
if (!TH1::FitOptionsMake(option,fitOption)) return 0;
fitOption.Nostore = true;
if (!fitOption.Chi2) fitOption.Like = true;
ROOT::Fit::DataRange range(GetNdimensions());
for ( int i = 0; i < GetNdimensions(); ++i ) {
TAxis *axis = GetAxis(i);
range.AddRange(i, axis->GetXmin(), axis->GetXmax());
}
ROOT::Math::MinimizerOptions minOption;
return ROOT::Fit::FitObject(this, f , fitOption , minOption, goption, range);
}
void THnBase::GetRandom(Double_t *rand, Bool_t subBinRandom )
{
if (fIntegralStatus != kValidInt)
ComputeIntegral();
Double_t p = gRandom->Rndm();
Long64_t idx = TMath::BinarySearch(GetNbins() + 1, fIntegral, p);
const Int_t nStaticBins = 40;
Int_t bin[nStaticBins];
Int_t* pBin = bin;
if (GetNdimensions() > nStaticBins) {
pBin = new Int_t[GetNdimensions()];
}
GetBinContent(idx, pBin);
for (Int_t i = 0; i < fNdimensions; i++) {
rand[i] = GetAxis(i)->GetBinCenter(pBin[i]);
if (subBinRandom)
rand[i] += (gRandom->Rndm() - 0.5) * GetAxis(i)->GetBinWidth(pBin[i]);
}
if (pBin != bin) {
delete [] pBin;
}
return;
}
Bool_t THnBase::IsInRange(Int_t *coord) const
{
Int_t min = 0;
Int_t max = 0;
for (Int_t i = 0; i < fNdimensions; ++i) {
TAxis *axis = GetAxis(i);
if (!axis->TestBit(TAxis::kAxisRange)) continue;
min = axis->GetFirst();
max = axis->GetLast();
if (coord[i] < min || coord[i] > max)
return kFALSE;
}
return kTRUE;
}
TObject* THnBase::ProjectionAny(Int_t ndim, const Int_t* dim,
Bool_t wantNDim,
Option_t* option ) const
{
TString name(GetName());
name +="_proj";
for (Int_t d = 0; d < ndim; ++d) {
name += "_";
name += dim[d];
}
TString title(GetTitle());
Ssiz_t posInsert = title.First(';');
if (posInsert == kNPOS) {
title += " projection ";
for (Int_t d = 0; d < ndim; ++d)
title += GetAxis(dim[d])->GetTitle();
} else {
for (Int_t d = ndim - 1; d >= 0; --d) {
title.Insert(posInsert, GetAxis(d)->GetTitle());
if (d)
title.Insert(posInsert, ", ");
}
title.Insert(posInsert, " projection ");
}
TObjArray newaxes(ndim);
for (Int_t d = 0; d < ndim; ++d) {
newaxes.AddAt(GetAxis(dim[d]),d);
}
THnBase* hn = 0;
TH1* hist = 0;
TObject* ret = 0;
Bool_t* hadRange = 0;
Bool_t ignoreTargetRange = (option && (strchr(option, 'A') || strchr(option, 'a')));
Bool_t keepTargetAxis = ignoreTargetRange || (option && (strchr(option, 'O') || strchr(option, 'o')));
if (ignoreTargetRange) {
hadRange = new Bool_t[ndim];
for (Int_t d = 0; d < ndim; ++d){
TAxis *axis = GetAxis(dim[d]);
hadRange[d] = axis->TestBit(TAxis::kAxisRange);
axis->SetBit(TAxis::kAxisRange, kFALSE);
}
}
if (wantNDim)
ret = hn = CloneEmpty(name, title, &newaxes, keepTargetAxis);
else
ret = hist = CreateHist(name, title, &newaxes, keepTargetAxis);
if (keepTargetAxis) {
if (wantNDim) {
for (Int_t d = 0; d < ndim; ++d) {
hn->GetAxis(d)->SetRange(0, 0);
}
} else {
hist->GetXaxis()->SetRange(0, 0);
hist->GetYaxis()->SetRange(0, 0);
hist->GetZaxis()->SetRange(0, 0);
}
}
Bool_t haveErrors = GetCalculateErrors();
Bool_t wantErrors = haveErrors || (option && (strchr(option, 'E') || strchr(option, 'e')));
Int_t* bins = new Int_t[ndim];
Long64_t myLinBin = 0;
THnIter iter(this, kTRUE );
while ((myLinBin = iter.Next()) >= 0) {
Double_t v = GetBinContent(myLinBin);
for (Int_t d = 0; d < ndim; ++d) {
bins[d] = iter.GetCoord(dim[d]);
if (!keepTargetAxis && GetAxis(dim[d])->TestBit(TAxis::kAxisRange)) {
Int_t binOffset = GetAxis(dim[d])->GetFirst();
if (binOffset > 0) --binOffset;
bins[d] -= binOffset;
}
}
Long64_t targetLinBin = -1;
if (!wantNDim) {
if (ndim == 1) targetLinBin = bins[0];
else if (ndim == 2) targetLinBin = hist->GetBin(bins[0], bins[1]);
else if (ndim == 3) targetLinBin = hist->GetBin(bins[0], bins[1], bins[2]);
} else {
targetLinBin = hn->GetBin(bins, kTRUE );
}
if (wantErrors) {
Double_t err2 = 0.;
if (haveErrors) {
err2 = GetBinError2(myLinBin);
} else {
err2 = v;
}
if (wantNDim) {
hn->AddBinError2(targetLinBin, err2);
} else {
Double_t preverr = hist->GetBinError(targetLinBin);
hist->SetBinError(targetLinBin, TMath::Sqrt(preverr * preverr + err2));
}
}
if (wantNDim)
hn->AddBinContent(targetLinBin, v);
else
hist->AddBinContent(targetLinBin, v);
}
delete [] bins;
if (wantNDim) {
hn->SetEntries(fEntries);
} else {
if (!iter.HaveSkippedBin()) {
hist->SetEntries(fEntries);
} else {
hist->ResetStats();
Double_t entries = hist->GetEffectiveEntries();
if (!wantErrors) {
entries = TMath::Floor(entries + 0.5);
}
hist->SetEntries(entries);
}
}
if (hadRange) {
for (Int_t d = 0; d < ndim; ++d)
GetAxis(dim[d])->SetBit(TAxis::kAxisRange, hadRange[d]);
delete [] hadRange;
}
return ret;
}
void THnBase::Scale(Double_t c)
{
Double_t nEntries = GetEntries();
Bool_t haveErrors = GetCalculateErrors();
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next()) >= 0) {
Double_t v = GetBinContent(i);
SetBinContent(i, c * v);
if (haveErrors) {
Double_t err2 = GetBinError2(i);
SetBinError2(i, c * c * err2);
}
}
SetEntries(nEntries);
}
void THnBase::AddInternal(const THnBase* h, Double_t c, Bool_t rebinned)
{
if (fNdimensions != h->GetNdimensions()) {
Warning("RebinnedAdd", "Different number of dimensions, cannot carry out operation on the histograms");
return;
}
if (!GetCalculateErrors() && h->GetCalculateErrors())
Sumw2();
Bool_t haveErrors = GetCalculateErrors();
Double_t* x = 0;
if (rebinned) {
x = new Double_t[fNdimensions];
}
Int_t* coord = new Int_t[fNdimensions];
Long64_t numTargetBins = GetNbins() + h->GetNbins();
Reserve(numTargetBins);
Long64_t i = 0;
THnIter iter(h);
while ((i = iter.Next(coord)) >= 0) {
Double_t v = h->GetBinContent(i);
Long64_t mybinidx = -1;
if (rebinned) {
for (Int_t j = 0; j < fNdimensions; ++j)
x[j] = h->GetAxis(j)->GetBinCenter(coord[j]);
mybinidx = GetBin(x, kTRUE );
} else {
mybinidx = GetBin(coord, kTRUE );
}
if (haveErrors) {
Double_t err2 = h->GetBinError2(i) * c * c;
AddBinError2(mybinidx, err2);
}
AddBinContent(mybinidx, c * v);
}
delete [] coord;
delete [] x;
Double_t nEntries = GetEntries() + c * h->GetEntries();
SetEntries(nEntries);
}
void THnBase::Add(const THnBase* h, Double_t c)
{
if (!CheckConsistency(h, "Add")) return;
AddInternal(h, c, kFALSE);
}
void THnBase::RebinnedAdd(const THnBase* h, Double_t c)
{
AddInternal(h, c, kTRUE);
}
Long64_t THnBase::Merge(TCollection* list)
{
if (!list) return 0;
if (list->IsEmpty()) return (Long64_t)GetEntries();
Long64_t sumNbins = GetNbins();
TIter iter(list);
const TObject* addMeObj = 0;
while ((addMeObj = iter())) {
const THnBase* addMe = dynamic_cast<const THnBase*>(addMeObj);
if (addMe) {
sumNbins += addMe->GetNbins();
}
}
Reserve(sumNbins);
iter.Reset();
while ((addMeObj = iter())) {
const THnBase* addMe = dynamic_cast<const THnBase*>(addMeObj);
if (!addMe)
Error("Merge", "Object named %s is not THnBase! Skipping it.",
addMeObj->GetName());
else
Add(addMe);
}
return (Long64_t)GetEntries();
}
void THnBase::Multiply(const THnBase* h)
{
if(!CheckConsistency(h, "Multiply"))return;
Bool_t wantErrors = kFALSE;
if (GetCalculateErrors() || h->GetCalculateErrors())
wantErrors = kTRUE;
if (wantErrors) Sumw2();
Double_t nEntries = GetEntries();
Int_t* coord = new Int_t[fNdimensions];
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next(coord)) >= 0) {
Double_t v1 = GetBinContent(i);
Long64_t idxh = h->GetBin(coord);
Double_t v2 = 0.;
if (idxh >= 0) v2 = h->GetBinContent(idxh);
SetBinContent(i, v1 * v2);
if (wantErrors) {
Double_t err1 = GetBinError(i) * v2;
Double_t err2 = 0.;
if (idxh >= 0) err2 = h->GetBinError(idxh) * v1;
SetBinError(i, TMath::Sqrt((err2 * err2 + err1 * err1)));
}
}
SetEntries(nEntries);
delete [] coord;
}
void THnBase::Multiply(TF1* f, Double_t c)
{
Int_t* coord = new Int_t[fNdimensions];
Double_t* x = new Double_t[fNdimensions];
Bool_t wantErrors = GetCalculateErrors();
if (wantErrors) Sumw2();
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next(coord)) >= 0) {
Double_t value = GetBinContent(i);
for (Int_t j = 0; j < fNdimensions; ++j)
x[j] = GetAxis(j)->GetBinCenter(coord[j]);
if (!f->IsInside(x))
continue;
TF1::RejectPoint(kFALSE);
Double_t fvalue = f->EvalPar(x, NULL);
SetBinContent(i, c * fvalue * value);
if (wantErrors) {
Double_t error = GetBinError(i);
SetBinError(i, c * fvalue * error);
}
}
delete [] x;
delete [] coord;
}
void THnBase::Divide(const THnBase *h)
{
if (!CheckConsistency(h, "Divide"))return;
Bool_t wantErrors=GetCalculateErrors();
if (!GetCalculateErrors() && h->GetCalculateErrors())
wantErrors=kTRUE;
Double_t nEntries = fEntries;
if (wantErrors) Sumw2();
Bool_t didWarn = kFALSE;
Int_t* coord = new Int_t[fNdimensions];
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next(coord)) >= 0) {
Double_t v1 = GetBinContent(i);
Long64_t hbin = h->GetBin(coord);
Double_t v2 = h->GetBinContent(hbin);
if (!v2) {
v1 = 0.;
v2 = 1.;
if (!didWarn) {
Warning("Divide(h)", "Histogram h has empty bins - division by zero! Setting bin to 0.");
didWarn = kTRUE;
}
}
SetBinContent(i, v1 / v2);
if (wantErrors) {
Double_t err1 = GetBinError(i) * v2;
Double_t err2 = h->GetBinError(hbin) * v1;
Double_t b22 = v2 * v2;
Double_t err = (err1 * err1 + err2 * err2) / (b22 * b22);
SetBinError2(i, err);
}
}
delete [] coord;
SetEntries(nEntries);
}
void THnBase::Divide(const THnBase *h1, const THnBase *h2, Double_t c1, Double_t c2, Option_t *option)
{
TString opt = option;
opt.ToLower();
Bool_t binomial = kFALSE;
if (opt.Contains("b")) binomial = kTRUE;
if (!CheckConsistency(h1, "Divide") || !CheckConsistency(h2, "Divide"))return;
if (!c2) {
Error("Divide","Coefficient of dividing histogram cannot be zero");
return;
}
Reset();
if (!GetCalculateErrors() && (h1->GetCalculateErrors()|| h2->GetCalculateErrors() != 0))
Sumw2();
Long64_t nFilledBins=0;
Int_t* coord = new Int_t[fNdimensions];
memset(coord, 0, sizeof(Int_t) * fNdimensions);
Bool_t didWarn = kFALSE;
Long64_t i = 0;
THnIter iter(h1);
while ((i = iter.Next(coord)) >= 0) {
Double_t v1 = h1->GetBinContent(i);
Long64_t h2bin = h2->GetBin(coord);
Double_t v2 = h2->GetBinContent(h2bin);
if (!v2) {
v1 = 0.;
v2 = 1.;
if (!didWarn) {
Warning("Divide(h1, h2)", "Histogram h2 has empty bins - division by zero! Setting bin to 0.");
didWarn = kTRUE;
}
}
nFilledBins++;
Long64_t myBin = GetBin(coord);
SetBinContent(myBin, c1 * v1 / c2 / v2);
if(GetCalculateErrors()){
Double_t err1 = h1->GetBinError(i);
Double_t err2 = h2->GetBinError(h2bin);
Double_t errSq = 0.;
if (binomial) {
if (v1 != v2) {
Double_t w = v1 / v2;
err2 *= w;
errSq = TMath::Abs( ( (1. - 2.*w) * err1 * err1 + err2 * err2 ) / (v2 * v2) );
}
} else {
c1 *= c1;
c2 *= c2;
Double_t b22 = v2 * v2 * c2;
err1 *= v2;
err2 *= v1;
errSq = c1 * c2 * (err1 * err1 + err2 * err2) / (b22 * b22);
}
SetBinError2(myBin, errSq);
}
}
delete [] coord;
SetFilledBins(nFilledBins);
SetEntries(h1->GetEntries());
}
Bool_t THnBase::CheckConsistency(const THnBase *h, const char *tag) const
{
if (fNdimensions != h->GetNdimensions()) {
Warning(tag, "Different number of dimensions, cannot carry out operation on the histograms");
return kFALSE;
}
for (Int_t dim = 0; dim < fNdimensions; dim++){
if (GetAxis(dim)->GetNbins() != h->GetAxis(dim)->GetNbins()) {
Warning(tag, "Different number of bins on axis %i, cannot carry out operation on the histograms", dim);
return kFALSE;
}
}
return kTRUE;
}
void THnBase::SetBinEdges(Int_t idim, const Double_t* bins)
{
TAxis* axis = (TAxis*) fAxes[idim];
axis->Set(axis->GetNbins(), bins);
}
void THnBase::SetTitle(const char *title)
{
fTitle = title;
fTitle.ReplaceAll("#;",2,"#semicolon",10);
Int_t endHistTitle = fTitle.First(';');
if (endHistTitle >= 0) {
Int_t posTitle = endHistTitle + 1;
Int_t lenTitle = fTitle.Length();
Int_t dim = 0;
while (posTitle > 0 && posTitle < lenTitle && dim < fNdimensions){
Int_t endTitle = fTitle.Index(";", posTitle);
TString axisTitle = fTitle(posTitle, endTitle - posTitle);
axisTitle.ReplaceAll("#semicolon", 10, ";", 1);
GetAxis(dim)->SetTitle(axisTitle);
dim++;
if (endTitle > 0)
posTitle = endTitle + 1;
else
posTitle = -1;
}
fTitle.Remove(endHistTitle, lenTitle - endHistTitle);
}
fTitle.ReplaceAll("#semicolon", 10, ";", 1);
}
THnBase* THnBase::RebinBase(Int_t group) const
{
Int_t* ngroup = new Int_t[GetNdimensions()];
for (Int_t d = 0; d < GetNdimensions(); ++d)
ngroup[d] = group;
THnBase* ret = RebinBase(ngroup);
delete [] ngroup;
return ret;
}
THnBase* THnBase::RebinBase(const Int_t* group) const
{
Int_t ndim = GetNdimensions();
TString name(GetName());
for (Int_t d = 0; d < ndim; ++d)
name += Form("_%d", group[d]);
TString title(GetTitle());
Ssiz_t posInsert = title.First(';');
if (posInsert == kNPOS) {
title += " rebin ";
for (Int_t d = 0; d < ndim; ++d)
title += Form("{%d}", group[d]);
} else {
for (Int_t d = ndim - 1; d >= 0; --d)
title.Insert(posInsert, Form("{%d}", group[d]));
title.Insert(posInsert, " rebin ");
}
TObjArray newaxes(ndim);
newaxes.SetOwner();
for (Int_t d = 0; d < ndim; ++d) {
newaxes.AddAt(new TAxis(*GetAxis(d) ),d);
if (group[d] > 1) {
TAxis* newaxis = (TAxis*) newaxes.At(d);
Int_t newbins = (newaxis->GetNbins() + group[d] - 1) / group[d];
if (newaxis->GetXbins() && newaxis->GetXbins()->GetSize()) {
Double_t *edges = new Double_t[newbins + 1];
for (Int_t i = 0; i < newbins + 1; ++i)
if (group[d] * i <= newaxis->GetNbins())
edges[i] = newaxis->GetXbins()->At(group[d] * i);
else edges[i] = newaxis->GetXmax();
newaxis->Set(newbins, edges);
delete [] edges;
} else {
newaxis->Set(newbins, newaxis->GetXmin(), newaxis->GetXmax());
}
}
}
THnBase* h = CloneEmpty(name.Data(), title.Data(), &newaxes, kTRUE);
Bool_t haveErrors = GetCalculateErrors();
Bool_t wantErrors = haveErrors;
Int_t* bins = new Int_t[ndim];
Int_t* coord = new Int_t[fNdimensions];
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next(coord)) >= 0) {
Double_t v = GetBinContent(i);
for (Int_t d = 0; d < ndim; ++d) {
bins[d] = TMath::CeilNint( (double) coord[d]/group[d] );
}
Long64_t idxh = h->GetBin(bins, kTRUE );
if (wantErrors) {
Double_t err2 = 0.;
if (haveErrors) {
err2 = GetBinError2(i);
} else err2 = v;
h->AddBinError2(idxh, err2);
}
h->AddBinContent(idxh, v);
}
delete [] bins;
delete [] coord;
h->SetEntries(fEntries);
return h;
}
void THnBase::ResetBase(Option_t * )
{
fEntries = 0.;
fTsumw = 0.;
fTsumw2 = -1.;
if (fIntegralStatus != kNoInt) {
delete [] fIntegral;
fIntegralStatus = kNoInt;
}
}
Double_t THnBase::ComputeIntegral()
{
if (fIntegralStatus != kNoInt) {
delete [] fIntegral;
fIntegralStatus = kNoInt;
}
if (GetNbins() == 0) {
Error("ComputeIntegral", "The histogram must have at least one bin.");
return 0.;
}
fIntegral = new Double_t [GetNbins() + 1];
fIntegral[0] = 0.;
Int_t* coord = new Int_t[fNdimensions];
Long64_t i = 0;
THnIter iter(this);
while ((i = iter.Next(coord)) >= 0) {
Double_t v = GetBinContent(i);
bool regularBin = true;
for (Int_t dim = 0; dim < fNdimensions; dim++) {
if (coord[dim] < 1 || coord[dim] > GetAxis(dim)->GetNbins()) {
regularBin = false;
break;
}
}
if (!regularBin) v = 0.;
fIntegral[i + 1] = fIntegral[i] + v;
}
delete [] coord;
if (fIntegral[GetNbins()] == 0.) {
Error("ComputeIntegral", "No hits in regular bins (non over/underflow).");
delete [] fIntegral;
return 0.;
}
for (Long64_t j = 0; j <= GetNbins(); ++j)
fIntegral[j] = fIntegral[j] / fIntegral[GetNbins()];
fIntegralStatus = kValidInt;
return fIntegral[GetNbins()];
}
void THnBase::PrintBin(Long64_t idx, Option_t* options) const
{
Int_t* coord = new Int_t[fNdimensions];
PrintBin(idx, coord, options);
delete [] coord;
}
Bool_t THnBase::PrintBin(Long64_t idx, Int_t* bin, Option_t* options) const
{
Double_t v = -42;
if (idx == -1) {
idx = GetBin(bin);
v = GetBinContent(idx);
} else {
v = GetBinContent(idx, bin);
}
Double_t err = 0.;
if (GetCalculateErrors()) {
if (idx != -1) {
err = GetBinError(idx);
}
}
if (v == 0. && err == 0. && options && strchr(options, '0')) {
return kFALSE;
}
TString coord;
for (Int_t dim = 0; dim < fNdimensions; ++dim) {
coord += bin[dim];
coord += ',';
}
coord.Remove(coord.Length() - 1);
if (GetCalculateErrors()) {
Printf("Bin at (%s) = %g (+/- %g)", coord.Data(), v, err);
} else {
Printf("Bin at (%s) = %g", coord.Data(), v);
}
return kTRUE;
}
void THnBase::PrintEntries(Long64_t from , Long64_t howmany ,
Option_t* options ) const
{
if (from < 0) from = 0;
if (howmany == -1) howmany = GetNbins();
Int_t* bin = new Int_t[fNdimensions];
if (options && (strchr(options, 'x') || strchr(options, 'X'))) {
Int_t* nbins = new Int_t[fNdimensions];
for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
nbins[dim] = GetAxis(dim)->GetNbins();
bin[dim] = from % nbins[dim];
from /= nbins[dim];
}
for (Long64_t i = 0; i < howmany; ++i) {
if (!PrintBin(-1, bin, options))
++howmany;
++bin[fNdimensions - 1];
for (Int_t dim = fNdimensions - 1; dim >= 0; --dim) {
if (bin[dim] >= nbins[dim]) {
bin[dim] = 0;
if (dim > 0) {
++bin[dim - 1];
} else {
howmany = -1;
}
}
}
}
delete [] nbins;
} else {
for (Long64_t i = from; i < from + howmany; ++i) {
if (!PrintBin(i, bin, options))
++howmany;
}
}
delete [] bin;
}
void THnBase::Print(Option_t* options) const
{
Bool_t optAxis = options && (strchr(options, 'A') || (strchr(options, 'a')));
Bool_t optMem = options && (strchr(options, 'M') || (strchr(options, 'm')));
Bool_t optStat = options && (strchr(options, 'S') || (strchr(options, 's')));
Bool_t optContent = options && (strchr(options, 'C') || (strchr(options, 'c')));
Printf("%s (*0x%lx): \"%s\" \"%s\"", IsA()->GetName(), (unsigned long)this, GetName(), GetTitle());
Printf(" %d dimensions, %g entries in %lld filled bins", GetNdimensions(), GetEntries(), GetNbins());
if (optAxis) {
for (Int_t dim = 0; dim < fNdimensions; ++dim) {
TAxis* axis = GetAxis(dim);
Printf(" axis %d \"%s\": %d bins (%g..%g), %s bin sizes", dim,
axis->GetTitle(), axis->GetNbins(), axis->GetXmin(), axis->GetXmax(),
(axis->GetXbins() ? "variable" : "fixed"));
}
}
if (optStat) {
Printf(" %s error calculation", (GetCalculateErrors() ? "with" : "without"));
if (GetCalculateErrors()) {
Printf(" Sum(w)=%g, Sum(w^2)=%g", GetSumw(), GetSumw2());
for (Int_t dim = 0; dim < fNdimensions; ++dim) {
Printf(" axis %d: Sum(w*x)=%g, Sum(w*x^2)=%g", dim, GetSumwx(dim), GetSumwx2(dim));
}
}
}
if (optMem && InheritsFrom(THnSparse::Class())) {
const THnSparse* hsparse = dynamic_cast<const THnSparse*>(this);
Printf(" coordinates stored in %d chunks of %d entries\n %g of bins filled using %g of memory compared to an array",
hsparse->GetNChunks(), hsparse->GetChunkSize(),
hsparse->GetSparseFractionBins(), hsparse->GetSparseFractionMem());
}
if (optContent) {
Printf(" BIN CONTENT:");
PrintEntries(0, -1, options);
}
}
void THnBase::Browse(TBrowser *b)
{
if (fBrowsables.IsEmpty()) {
for (Int_t dim = 0; dim < fNdimensions; ++dim) {
fBrowsables.AddAtAndExpand(new ROOT::THnBaseBrowsable(this, dim), dim);
}
fBrowsables.SetOwner();
}
for (Int_t dim = 0; dim < fNdimensions; ++dim) {
b->Add(fBrowsables[dim]);
}
}
ROOT::THnBaseBinIter::~THnBaseBinIter() {
}
ClassImp(THnIter);
THnIter::~THnIter() {
delete fIter;
}
ClassImp(ROOT::THnBaseBrowsable);
ROOT::THnBaseBrowsable::THnBaseBrowsable(THnBase* hist, Int_t axis):
fHist(hist), fAxis(axis), fProj(0)
{
TString axisName = hist->GetAxis(axis)->GetName();
if (axisName.IsNull()) {
axisName = TString::Format("axis%d", axis);
}
SetNameTitle(axisName,
TString::Format("Projection on %s of %s", axisName.Data(),
hist->IsA()->GetName()).Data());
}
ROOT::THnBaseBrowsable::~THnBaseBrowsable()
{
delete fProj;
}
void ROOT::THnBaseBrowsable::Browse(TBrowser* b)
{
if (!fProj) {
fProj = fHist->Projection(fAxis);
}
fProj->Draw(b ? b->GetDrawOption() : "");
gPad->Update();
}