Splitting THnSparse

I have a 7-dimensional THnSparse histogram (hist_7d) and want to be able to split it up into a 2d vector of 5-dimensional THnSparse (hist_5d[i][j]) where the i and j indices correspond to specific bins in the first two axes of hist_7d. To my knowledge I cannot simply project into the other 5 dimensions as it would integrate over all other dimensions, which I don’t want.

I’ve tried brute force looping over all the bins and effectively building brand new THnSparse histograms from this, but I’ve found results to be suspicious and I would love an internal way of splitting up THnSparse histograms like this. Is there a built in functionality for this?

ROOT Version: 6.26.04
Platform: macOS Ventura 13.0
Compiler: g++

See the “Projections” paragraph in the THnSparse class reference.

I’ve looked at the Projections paragraph and the documentation for it for months and if one can use Projections to do what I’m talking about, then I don’t see it. Could you be a bit more specific as to how one could use Projections to do this?

I think you’re referring to the part where it says:

To only project parts of the histogram, call

THnSparse::GetAxis(12)->SetRange(from_bin, to_bin);

right?

It’s not clear to me how to use that or where I would incorporate it.
What I’m familiar with would be

int bins = 5;
int which_bins[5] = {2,3,4,5,6};
for(int j=0; j<hist_7d->GetAxis(0)->GetNbins(); j++){
    for(int k=0; k<hist_7d->GetAxis(1)->GetNbins(); k++){
         hist_5d[j][k]=hist_7d->Projection(bins, which_bins,"E"); 
    }
}

So it’s not clear to me how I would use the prior? Would I do something like

int bins = 5;
int which_bins[5] = {2,3,4,5,6};
for(int j=0; j<hist_7d->GetAxis(0)->GetNbins(); j++){
    for(int k=0; k<hist_7d->GetAxis(1)->GetNbins(); k++){
         hist_6d[k]=hist_7d->GetAxis(1)->SetRange(k+1,k+1); 
         hist_5d[j][k] = hist_6d[k]->GetAxis(0)->SetRange(j+1,j+1);
    }
}

or am I misunderstanding?

Try:

hist_7d->GetAxis(0)->SetRange(j + 1, j + 1);
hist_7d->GetAxis(1)->SetRange(k + 1, k + 1);
hist_5d[j][k] = hist_7d->Projection(bins, which_bins, "E");

I need to run a couple more tests to make sure it’s behaving as intended, but so far it looks like it’s working! To check comprehension: calling this hist_7d->GetAxis(n)->SetRange(j,k) for different n’s, j’s, and k’s would all appropriately switch it to the designated bins and the underlying data and error in hist_7d remains unchanged?
So if I were to do

hist_7d->GetAxis(0)->SetRange(1, 1);
hist_7d->GetAxis(1)->SetRange(2, 2);
hist_5d[1][2] = hist_7d->Projection(bins, which_bins, "E");
hist_7d->GetAxis(0)->SetRange(3,3);
hist_7d->GetAxis(1)->SetRange(4,4);
hist_5d[3][4] = hist_7d->Projection(bins, which_bins, "E");

Then even though they’re sequential, the GetAxis and SetRange resets the expressed range in that axis for hist_7d? And to get it back to “normal” I’d need to call

hist_7d->GetAxis(0)->SetRange(1,hist_7d->GetAxis(0)->GetNbins());
hist_7d->GetAxis(1)->SetRange(1, hist_7d->GetAxis(0)->GetNbins());

yes?

hist_7d->GetAxis(0)->SetRange(); // () or (0, 0)
hist_7d->GetAxis(1)->SetRange(); // () or (0, 0);

BTW. See: TAxis::SetRange