If a branch lives in a friend that is a multi-file TChain and the main object is a plain TTree, GetMinimum/GetMaximum return the min/max over only the friend chain’s currently-loaded file, with no warning. If the main object is itself a (file-aligned) TChain, the same query is correct. Per-entry access reads the friend correctly in all cases — Draw("w","","goff") on the very same TTree returns the true range — so it looks specific to GetMinimum/GetMaximum. Self-contained reproducer below (generates its own files). Not sure if related to TChain::Add(TChain*) leaves GetEntries() reporting a wrong, too-small value
// TTree::GetMinimum / GetMaximum do not scan a friend TChain correctly.
//
// Setup: N data files and N friend files, file-aligned (same entries per file).
// The friend branch "w" lives in disjoint ranges per file:
// file 0 : w in [4,5] (the file a fresh chain has loaded)
// file 1 : w in [0,1] (holds the global MIN)
// file 2 : w in [9,10] (holds the global MAX)
// so the true min/max of "w" over the whole friend is ~0 / ~10.
//
// Observed (ROOT 6.40.00):
// CASE A main is a TChain (file-aligned with the friend)
// -> GetMinimum/GetMaximum = ~0 / ~10 (correct)
// CASE B main is a plain TTree, same friend TChain
// -> GetMinimum/GetMaximum = ~4 / ~5 (only the friend's first file!)
// -> Draw("w") = ~0 / ~10, so the friend values ARE reachable;
// only GetMinimum/GetMaximum are wrong.
//
// Run: root -l -b -q getminimum_friend_chain.C
void getminimum_friend_chain()
{
printf("ROOT version: %s\n\n", gROOT->GetVersion());
TRandom3 rng(1);
const std::string dir = "gmfc_data";
gSystem->Exec(("rm -rf " + dir).c_str());
gSystem->mkdir(dir.c_str(), kTRUE);
const int per = 100, nfiles = 3;
const double lo[nfiles] = {4.0, 0.0, 9.0}; // file 0 holds neither global min nor max
for (int f = 0; f < nfiles; ++f) {
TFile fd((dir + "/data_" + std::to_string(f) + ".root").c_str(), "RECREATE");
TTree td("data", "data"); Double_t x; td.Branch("x", &x);
for (int i = 0; i < per; ++i) { x = rng.Gaus(); td.Fill(); }
td.Write(); fd.Close();
TFile ff((dir + "/friend_" + std::to_string(f) + ".root").c_str(), "RECREATE");
TTree tf("fr", "fr"); Double_t w; tf.Branch("w", &w);
for (int i = 0; i < per; ++i) { w = lo[f] + rng.Uniform(); tf.Fill(); }
tf.Write(); ff.Close();
}
printf("friend \"w\": file0 in [4,5], file1 in [0,1], file2 in [9,10]\n");
printf("TRUE min ~ 0 , TRUE max ~ 10\n\n");
auto friendChain = [&]{
TChain* fr = new TChain("fr");
for (int f = 0; f < nfiles; ++f) fr->Add((dir + "/friend_" + std::to_string(f) + ".root").c_str());
return fr;
};
// CASE A: main is a TChain, file-aligned with the friend chain
{
TChain* m = new TChain("data");
for (int f = 0; f < nfiles; ++f) m->Add((dir + "/data_" + std::to_string(f) + ".root").c_str());
m->AddFriend(friendChain());
printf("CASE A main->IsA() = %-7s : GetMinimum=%g GetMaximum=%g (expect ~0 / ~10)\n",
m->IsA()->GetName(), m->GetMinimum("w"), m->GetMaximum("w"));
}
// CASE B: main is a plain TTree (CopyTree of the friend-less data chain), same friend
{
TChain dc("data");
for (int f = 0; f < nfiles; ++f) dc.Add((dir + "/data_" + std::to_string(f) + ".root").c_str());
TFile* out = new TFile((dir + "/merged.root").c_str(), "RECREATE");
TTree* m = (TTree*)dc.CopyTree(""); // plain TTree
m->AddFriend(friendChain());
printf("CASE B main->IsA() = %-7s : GetMinimum=%g GetMaximum=%g (expect ~0 / ~10)\n",
m->IsA()->GetName(), m->GetMinimum("w"), m->GetMaximum("w"));
m->SetEstimate(m->GetEntries() + 1);
Long64_t n = m->Draw("w", "", "goff");
printf(" Draw(\"w\") : min=%g max=%g (rows=%lld)\n",
TMath::MinElement(n, m->GetV1()), TMath::MaxElement(n, m->GetV1()), n);
out->Close();
}
printf("\n(generated files in ./%s/ ; delete with `rm -rf %s`)\n", dir.c_str(), dir.c_str());
}
output:
ROOT version: 6.40.00
friend “w”: file0 in [4,5], file1 in [0,1], file2 in [9,10]
TRUE min ~ 0 , TRUE max ~ 10CASE A main->IsA() = TChain : GetMinimum=0.00800271 GetMaximum=9.98806 (expect ~0 / ~10)
CASE B main->IsA() = TTree : GetMinimum=4.00287 GetMaximum=4.99732 (expect ~0 / ~10)
Draw(“w”) : min=0.00800271 max=9.98806 (rows=300)(generated files in ./gmfc_data/ ; delete with rm -rf gmfc_data)
ROOT Version: 6.40.00
Platform: Linux (cvmfs)
Compiler: linuxx8664gcc