Reading and writing THnSparse to file with variable bin size

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

Hi,

This problem still persists. Is there a known solution?

Best,
Peter

When calling “writeSparse” with “useVarBins = true”, one tries to change the numbers of bins from the initial “{10, 4, 4}” to “{5, 2, 2}” -> I guess this is not allowed (i.e. I guess one can switch from fixed size bins to variable size bins but all 3 numbers of bins must be preserved).

I guess the “x” and “x0” options in THnBase::PrintEntries misbehave (i.e. it’s a bug).

testSparse.cxx (2.6 KB)

That’s now (after only a couple of years…) https://sft.its.cern.ch/jira/browse/ROOT-10705 - thanks for the report!

12y later :wink: