Why is hadd `unpacking' my collections?

Dear ROOT experts,

I’m now happily using ROOT v5.18.00 (and I’m pleasantly surprised that it seems to be faster yet again). But why does hadd unpack my collections? When merging identical ROOT files each containing a TClonesArray of TObjStrings, saved with the kSingleKey option, hadd tells me it cannot merge those (fine) but then saves each entry in the target file with an individual key.

Unless I’m overlooking something, this should be easily fixable by adding a kSingleKey option to the Write() call for TCollections, right?

Thanks,
Jeroen

hadd can merge automatically objects like TH1 and TTree, but given the fact that the Merge operation is unspecified for most other classes, hadd will only copy a new cycle of your object (one for each file). That’s the only thing that we can do.
In general objects like TClonesArray are stored in a TTree and not as single objects.

Rene

Hi Rene,

I’m not complaining about the collections not being merged, that’s fine. I also agree that the logical thing to do with unmergeable objects is to store a different cycle for each original.

But, that’s not what’s happening. Let’s look at the below (and attached) sample. Sorry if it has become a bit long. (ROOT v5.18.00 by the way.)

The first step creates two files, each with a TClonesArray of two TObjStrings, stored with kSingleKey.

[code]{
// test_hadd_1.C

gROOT->Reset();

TClonesArray a(“TObjString”);
new(a[0]) TObjString(“one”);
new(a[1]) TObjString(“two”);

TClonesArray b(“TObjString”);
new(b[0]) TObjString(“three”);
new(b[1]) TObjString(“four”);

TFile f_a(“test_hadd_a.root”, “RECREATE”);
a.Write(“merge_this”, TObject::kSingleKey);
f_a.Close();

TFile f_b(“test_hadd_b.root”, “RECREATE”);
b.Write(“merge_this”, TObject::kSingleKey);
f_b.Close();
}[/code]

root -b -q test_hadd_1.C root [0] Processing test_hadd_1.C...

Then we hadd them:

hadd test_hadd_comb.root test_hadd_a.root test_hadd_b.root Target file: test_hadd_comb.root Source file 1: test_hadd_a.root Source file 2: test_hadd_b.root Target path: test_hadd_comb.root:/ Unknown object type, name: TObjStrings title: An array of clone objects

And then we have a look at the hadded file:

[code]{
// test_hadd_2.C

gROOT->Reset();

TFile f(“test_hadd_comb.root”, “READ”);

TIter next(f->GetListOfKeys());
TKey* key = 0;
while (key = (TKey*)next()) {
TObject* obj = key->ReadObj();
std::cout << “Key " << key->GetName() << "'" << " with cycle " << key->GetCycle() << std::endl; std::cout << " points to a " << obj->IsA()->GetName() << " called" << obj->GetName() << “’”
<< " with title `” << obj->GetTitle() << “’”
<< std::endl;
} // while

f.Close();
}[/code]

root -b -q test_hadd_2.C root [0] Processing test_hadd_2.C... Key `merge_this' with cycle 2 points to a TObjString called `two' with title `Collectable string class' Key `merge_this' with cycle 1 points to a TObjString called `one' with title `Collectable string class'

So what it did was unpack the first TClonesArray it saw, store the entries as single TObjStrings and then forget all about the second TClonesArray.

Jeroen
test_hadd_2.C (505 Bytes)
test_hadd_1.C (429 Bytes)

Hi Jeroen,

I have now implemented your suggestion (was a bit more complex to implement that I originally thought). Now when running:

hadd -f test_hadd_comb.root test_hadd_a.root test_hadd_b.root
you will get the messages:

Target file: test_hadd_comb.root Source file 1: test_hadd_a.root Source file 2: test_hadd_b.root Target path: test_hadd_comb.root:/ Cannot merge object type, name: TObjStrings title: An array of clone objects
and when listing the objects in the output file, you see:

[code] root -b test_hadd_comb.root

root [0]
Attaching file test_hadd_comb.root as _file0…
root [1] .ls
TFile** test_hadd_comb.root
TFile* test_hadd_comb.root
KEY: TClonesArray merge_this;2 An array of clone objects
KEY: TClonesArray merge_this;1 An array of clone objects
root [2]
[/code]
Rene

Thanks Rene,

for fixing this. I now see (looking at the new code) that it was not a completely trivial fix either.

Cheers,
Jeroen