Hello,
I have noticed some bizarre behavior with THnSparse with variable bins. I book and fill these histograms in compiled code, save them in TFiles, and then later use macros to read them, project them, and draw the results. I’m finding that the axes get screwed up when I read them back which leads to bizarre seg faults and glibc memory errors. I managed to write two simple CINT functions which seem to demonstrate the problem.
void writeSparse(bool useVarBins=false, bool draw=false)
{
// Define the fixed bins for initialization
const int nDim = 3;
Int_t nBins[nDim] = {10, 4, 4};
Double_t min[nDim] = {0., 0., 0.};
Double_t max[nDim] = {5., 2., 2.};
TFile* f = new TFile("testSparse.root", "recreate");
THnSparseF* h = new THnSparseF("sparseHist", "sparseHist", nDim, nBins, min, max);
// Set variable bins
if(useVarBins){
const int nVarBins0 = 5;
Double_t varBins0[nVarBins0+1] = {0., 1., 2., 3., 4., 5.};
h->GetAxis(0)->Set(nVarBins0, varBins0);
const int nVarBins1 = 2;
Double_t varBins1[nVarBins1+1] = {0., 0.5, 2.};
h->GetAxis(1)->Set(nVarBins1, varBins1);
const int nVarBins2 = 2;
Double_t varBins2[nVarBins2+1] = {0., 1.5, 2.};
h->GetAxis(2)->Set(nVarBins2, varBins2);
}
// Fill 2 bins
Double_t val1[nDim] = {0, 1, 0};
Double_t val2[nDim] = {3, 0, 1};
h->Fill(val1);
h->Fill(val2);
cout << "printing entries with no options:" << endl;
h->PrintEntries();
cout << "printing entries with 'x':" << endl;
h->PrintEntries(0, -1, "x");
// Draw projections
if(draw){
TCanvas* c0 = new TCanvas("c0", "c0", 500, 500);
h->Projection(0)->Draw();
TCanvas* c1 = new TCanvas("c1", "c1", 500, 500);
h->Projection(1)->Draw();
TCanvas* c2 = new TCanvas("c2", "c2", 500, 500);
h->Projection(2)->Draw();
}
h->Write();
}
void readSparse(bool draw=false)
{
TFile* f = new TFile("testSparse.root");
THnSparseF* h = (THnSparseF*) f->Get("sparseHist");
cout << "printing entries with no options:" << endl;
h->PrintEntries();
cout << "printing entries with 'x':" << endl;
h->PrintEntries(0, -1, "x");
// Draw projections
if(draw){
TCanvas* c0 = new TCanvas("c0", "c0", 500, 500);
h->Projection(0)->Draw();
TCanvas* c1 = new TCanvas("c1", "c1", 500, 500);
h->Projection(1)->Draw();
TCanvas* c2 = new TCanvas("c2", "c2", 500, 500);
h->Projection(2)->Draw();
}
}
Before I get into the main issue with variable bins, note that the PrintEntries function with option ‘x’ does not behave as I’d expect. Printing with no options seems to print the correct non-empty bins, but with the x option I get two unfilled bins printed:
root [1] writeSparse()
printing entries with no options:
Bin at (1,3,1) = 1
Bin at (7,1,3) = 1
printing entries with 'x':
Bin at (0,0,0) = 0
Bin at (0,0,1) = 0
Besides the weird printing mentioned above, using fixed bin sizes works fine. When I read the THnSparse in with readSparse, and project and draw, everything looks normal. However, if I use writeSparse with the variable binning turned on, and then try to read back with readSparse, one immediately sees that the bin printouts have changed:
root [1] writeSparse(true)
printing entries with no options:
Bin at (1,2,1) = 1
Bin at (4,1,1) = 1
printing entries with 'x':
Bin at (0,0,0) = 0
Bin at (0,0,1) = 0
root [2] readSparse()
printing entries with no options:
Bin at (1,4,2) = 1
Bin at (4,2,2) = 1
printing entries with 'x':
Bin at (0,0,0) = 0
Bin at (0,0,1) = 0
Also, if I now use the draw option in readSparse, I get a glibc memory corruption error!
I would appreciate some feedback on this. If it’s a bug, are there any suggested workarounds?
I’m using ROOT version 5.28/00e as bundled with ATLAS software.
Thank you