Hi all.
So, I have a rather complicated problem. I’ve figured out what I need to do in order to work around this problem, but I wanted to share this information with you, and find out if this is a bug, an unintended consequence of the design of ROOT memory/file handling, or if there’s something fundamentally wrong with my code/understanding.
I have an event class (KHLAEvent) that is saved to an output TFile, with the KHLAEvent as the top-level branch. Within this event class there are two TClonesArrays – one holds objects KSingleBoloSubRecord and another holds objects KSambaSubRecord. Within KSingleBoloSubRecord there is a TRef that should point to the appropriate KSambaSubRecord within the event.
I wrote an assignment operator for my KHLAEvent class for the purpose of merging two separate files (**). I want to be able to do something like this:
TFile *fout = new TFile(“out.root”,“recreate”);
TFile *fin1 = new TFile(“input1.root”);
TFile *fin1 = new TFile(“input2.root”);
//set up the branches for KHLAEvent *eout, *ein1, *ein2
//start looping through all entries input1 and input2 and then
if(some condition){
*eout = *ein1;
TreeOut->Fill()
}
else {
*eout = *ein2;
TreeOut->Fill()
}
//write and then close the file.
The assignment operator KHLAEvent::operator= had to be a bit special in order to create a new KSambaSubRecord for each KSingleBoloSubRecord that had a pointer set in its TRef (I have yet to deal with the special case where more than one KSingleBoloSubRecords point to the same KSambaSubRecord, but never mind that.)
The above “code” wouldn’t work – the wrong KSambaSubRecord was copied to the event – unless I explicitly made sure to change the current working directory to the TFile that holds the event I want to copy and then call TTree::GetEntry(currentEntryNumber) before calling the assignment operator. This looks something like this:
TFile *fout = new TFile(“out.root”,“recreate”);
TFile *fin1 = new TFile(“input1.root”);
TFile *fin1 = new TFile(“input2.root”);
//set up the branches for KHLAEvent *eout, *ein1, *ein2
//start looping through all entries input1 and input2 and then
theCurrentEntryFile1; //retain this value
theCurrentEntryFile2; //retain this value
if(some condition){
fin1->cd();
tree_in1->GetEntry(theCurrentEntryFile1);
*eout = *ein1;
TreeOut->Fill()
}
else {
fin2->cd();
tree_in2->GetEntry(theCurrentEntryFile2);
*eout = *ein2;
TreeOut->Fill()
}
//write and then close the file.
In this case, it works, meaning that the correct KSambaSubRecord was properly copied to my *eout event and written to my TreeOut.
I have attached a fully working example. Just compile it, and then run bin/fillEventTest to see what I’m talking about. fillEventTest.cxx is currently written to produce the problem. Uncomment lines 162, 163, 173, 174, 186, 187, 199, 200 to make it work properly. The difference in the output to stdout can be seen in the final TTree::Scan call – but you’ll have to read all of the output to know what its doing.
You’ll have to read through fillEventTest.cxx to get the best idea of what this is doing. But I think the code is readable enough. Or, maybe somebody already knows why I have to call the TFile::cd() and reload the entry without needing to look at my example.
Thanks a lot for your help.
Adam Cox
(**) - We don’t have a guaranteed index variable that would allow me to use the standard TChain/TTree::Merge routines.
trefExample.zip (139 KB)