Saving trees with branches into another tree as branches

I noticed under the TBranch Class Reference there is a friend class “TTreeCloner”. Can this be used somehow? I haven’t found referenceable applications of this class.

Note that TTreeCloner is the implementation of CloneTree …

I will try to rephrase the question in your terminology. Suppose I have two trees T1 and T2 with the same number of entries and having the same branch structure. Let’s call the collective branches of T1 as b1 and T2 as b2. I would like to create an additional tree T3 with two parent branches b3a and b3b. The parent branch b3a would contain a copy of the branches b1, while the parent branch b3b would contain a copy of the branches b2

This is essentially what AddFriend does, without having to copy the data. Why is that not working for you? (i.e what is missing)?

Cheers,
Philippe.

Hello Philippe,

Allow me to share the current implementation of the main function in the macro that I am trying to use. Included are lines commented out from previous attempts.

void refactorPolarityTestsFileA4() {

//  Open original format file and access its trees.
TFile polarityTestsFile("waisPolCutFilesA4/polarityTestsFileA4.root");
TTree * eventTree = (TTree *) polarityTestsFile.Get("eventTree");
TTree * waisPointingTree = (TTree *) polarityTestsFile.Get("waisPointingTree");
TTree * polarityTestsTree = (TTree *) polarityTestsFile.Get("polarityTestsTree");
TTree * deconvPolarityTestsTree = (TTree *) polarityTestsFile.Get("deconvPolarityTestsTree");
TTree * windowedPolarityTestsTree = (TTree *) polarityTestsFile.Get("windowedPolarityTestsTree");
TTree * windowedDeconvPolarityTestsTree = (TTree *) polarityTestsFile.Get("windowedDeconvPolarityTestsTree");

//  Create file to store trees in, then new tree to store 4 trees.
TFile reformattedFile("waisPolCutFilesA4/polarityTestsFileA4reformatted.root", "recreate");
TTree reformattedTree("polarityTestsTree", "TTree storing polarity test results");
TBranch waveformTests, deconvTests, windowedTests, windowedDeconvTests;
reformattedTree.Branch("waveformTests.", & waveformTests);
reformattedTree.Branch("deconvTests.", & deconvTests);
reformattedTree.Branch("windowedTests.", & windowedTests);
reformattedTree.Branch("windowedDeconvTests.", & windowedDeconvTests);

//  Structure the branches of the reformatted tree.

// TBranch waveformBranch[6], deconvBranch[6], windowedBranch[6], windowedDeconvBranch[6];
// polarity waveformStruct[6], deconvStruct[6], windowedStruct[6], windowedDeconvStruct[6];
// addSubbranches(waveformTests, waveformBranch, waveformStruct);
// addSubbranches(deconvTests, deconvBranch, deconvStruct);
// addSubbranches(windowedTests, windowedBranch, windowedStruct);
// addSubbbranches(windowedDeconvTests, windowedDeconvBranch, windowedDeconvStruct);

//  Now, copy the branches.
CollectBranches(polarityTestsTree -> GetListOfBranches(), waveformTests.GetListOfBranches());
reformattedTree.CollectBranches(deconvPolarityTestsTree -> GetListOfBranches(), deconvTests.GetListOfBranches());
reformattedTree.CollectBranches(windowedPolarityTestsTree -> GetListOfBranches(), windowedTests.GetListOfBranches());
reformattedTree.CollectBranches(windowedDeconvPolarityTestsTree -> GetListOfBranches(), windowedDeconvTests.GetListOfBranches());

// waveformTests.GetListOfBranches() -> Add((TObjArray *) polarityTestsTree -> GetListOfBranches() -> Clone());
// deconvTests.GetListOfBranches() -> Add((TObjArray *) deconvPolarityTestsTree -> GetListOfBranches() -> Clone());
// windowedTests.GetListOfBranches() -> Add((TObjArray *) windowedPolarityTestsTree -> GetListOfBranches() -> Clone());
// windowedDeconvTests.GetListOfBranches() -> Add((TObjArray *) windowedDeconvPolarityTestsTree -> GetListOfBranches() -> Clone());
// branchCopy(polarityTestsTree, waveformTests);
// branchCopy(deconvPolarityTestsTree, deconvTests);
// branchCopy(windowedPolarityTestsTree, windowedTests);
// branchCopy(windowedDeconvPolarityTestsTree, windowedDeconvTests);

//  Now, to write to this new tree.

// for (int entryNum = 0; entryNum < waisPointingTree -> GetEntries(); ++entryNum) {
//
// polarityTestsTree -> GetEntry(entryNum);
// deconvPolarityTestsTree -> GetEntry(entryNum);
// windowedPolarityTestsTree -> GetEntry(entryNum);
// windowedDeconvPolarityTestsTree -> GetEntry(entryNum);
//
//// reformattedTree.Fill();
// waveformTests.Fill();
// deconvTests.Fill();
// windowedTests.Fill();
// windowedDeconvTests.Fill();
// }

//  Write to the relevant trees to the reformatted file.
reformattedFile.cd();
eventTree -> CloneTree() -> Write();
waisPointingTree -> CloneTree() -> Write();
reformattedTree.Write();

//  Closing files.
reformattedFile.Close();
polarityTestsFile.Close();

}

Beyond, the ‘how’ you are try to implement this construct/organization, I am trying to understand the why (as so far just replacing all the copy by using AddFriend seem likely to actually do what you need). So could you clarify why AddFriend would not satisfy you need (let you accomplish what you need to do in the end)?

Am I correct in assuming that by “using AddFriend()”, you mean to apply the same set of AddFriend() commands to each of the 4 trees? That does work, but I would like to see an alternative method where I could then use AddFriend() on a single tree with parent branches, rather than having to repeatedly issue the same AddFriend() command to each tree a given branch would correspond to.

Or do you mean to make a tree of friends? I would like to make a standalone restructured copy of the file, like how I try to do in the above, rather than that. The tree of friends would become unusable if the location of friends change, right?

you mean to apply the same set of AddFriend() commands to each of the 4 trees?

No, one of them is likely sufficient.

TFile polarityTestsFile("waisPolCutFilesA4/polarityTestsFileA4.root","UPDATE");
TTree * polarityTestsTree = (TTree *) polarityTestsFile.Get("polarityTestsTree");
polarityTestsTree->AddFriend("deconvPolarityTestsTree");
polarityTestsTree->AddFriend("windowedPolarityTestsTree");
polarityTestsTree->AddFriend("windowedDeconvPolarityTestsTree");
polarityTestsFile.Write();

and from then on use ‘just’ the polarityTestsTree to have all 4 sets of branches.

or maybe even

TFile polarityTestsFile("waisPolCutFilesA4/polarityTestsFileA4.root","UPDATE");
TTree * eventTree = (TTree *) polarityTestsFile.Get("eventTree");
eventTree->AddFriend("waisPointingTree");
eventTree->AddFriend("polarityTestsTree");
eventTree->AddFriend("deconvPolarityTestsTree");
eventTree->AddFriend("windowedPolarityTestsTree");
eventTree->AddFriend("windowedDeconvPolarityTestsTree");
polarityTestsFile.Write();

and from then on use ‘just’ the eventTree.

Cheers,
Philippe.

PS.

TBranch waveformTests, deconvTests, windowedTests, windowedDeconvTests;
reformattedTree.Branch("waveformTests.", & waveformTests);

This would create a Branch containing as data another ‘TBranch’ object (not your data objects).

Thank you Philippe,

I apologize, I seem to be having difficulty in trying to get across what it is that I want to see how to do. It seems like you are proposing a tree of friends, or a tree with friends.

PS.
TBranch waveformTests, deconvTests, windowedTests, windowedDeconvTests;
reformattedTree.Branch(“waveformTests.”, & waveformTests);

This would create a Branch containing as data another ‘TBranch’ object (not your data objects).

I would like to see how to take the branches inside of “polarityTestsTree”, “deconvPolarityTestsTree”, “windowedPolarityTestsTree”, and “windowedDeconvPolarityTestsTree”, and then copy them respectively into the parent branches of “waveformTests”, “deconvTests”, “windowedTests”, and “windowedDeconvTests”. The branches inside of the initial 4 trees contain only leaves, all with the same number of entries.

Best,
John

I understood that but I never grasped why you want it that way (and why Friend don’t help for what you need).

I think “want” and “need” are two different things here. I just want to see an application of the constructor

TBranch::TBranch(TBranch * parent, const char * name, void * address, const char * leaflist, Int_t basketsize = 32000, Int_t compress = -1)

Using AddFriend() in the way that you suggest gets what is needed to be done now, but if the trees were to be ultimately friended together, why not place them together into a single tree in the first place? Part of the problem is that each tree has a collection of branches with the same name, so to do that you would have to rename the branches. To avoid renaming the branches, we should be able to place each tree’s branches into a parent branch. Otherwise, what is the purpose of having the above constructor?

Part of the problem is that each tree has a collection of branches with the same name, so to do that you would have to rename the branches.

With add friend the name of the TTree is implicit part of the branch name, so no need to change the actual branch names.

It is used in the implementation of TBranchClones to implement split of objects. One of the thing we run into when trying to ‘hand-make’ branch hierarchy is that the tools (MakeSelector, TTree::Draw, TBrowser, etc.) tend to assume that there is also an object/class hierarchy. It might be possible to implement what you want but I still don’t have enough information about the ‘why’ you need what you need ( :slight_smile: ) to know whether overcoming those obstacles is the best solution in the long term.

Cheers,
Philippe.

With add friend the name of the TTree is implicit part of the branch name, so no need to change the actual branch names.

Yes, that is characteristic to both between friends in a tree containing samely-named objects and between branches in a tree containing samely-named objects. But this seems to again highlight the philosophy “you have the file as it is now, so whether or not it should been structured that way to begin with, just use friends”. I am trying to broaden my toolkit of methods to use with ROOT data management. Is this not enough of a reason as to why I would like see this particular method? In terms of long term concerns, does it help to know that this file will be standalone and not part of a larger framework?

It is used in the implementation of TBranchClones to implement split of objects.

I have found little in the way of how to implement TBranchClones, although your response here seems to suggest it relates to my problem at hand. Has progress been made in implementing the related topic of “merging laterally two files”, or is the method still to use GetEntry and Fill?

Best,
John

Has progress been made in implementing the related topic of “merging laterally two files”,

Unfortunately no. If/When we do it, we would go for a solution where the original structure (that the set of branch was in a given TTree) would be only ‘visible’ via the new branch names (but this would also require augmenting the existing utilities to understand this).

Doing the way you want ‘a priori’ could be done by creating an empty branch, creating standalone branches, adding them to the list of branch of the parent and adding the leaves to the TTree list of leaves. But somebody else recently tried and did not quite succeed. I.e. for this to work properly, it would require enhancement of (likely) both the TBranch[Element] class and the utilities (TBrowser, MakeSelector or even TTree::Print) to understand correctly the structure.

Cheers,
Philippe.

PS. For TBranchClones you would need to look at https://root.cern.ch/doc/master/TBranchClones_8cxx_source.html and for the use of TBranchClones in ROOT: tree/tree/src/TTree.cxx Source File

Ah, okay. So this seems to be the problem with what I would like to do. Thank you for the feedback. If this is ever implemented, I assume it would be a highlight under the implementing ROOT version’s release page?

Best,
John

Whether or not this works at the moment, could I please see example code of what you mean? How do I create an empty branch in a tree?

See the discussion at Dynamically generated Branch structs without object

1 Like

So following to the linked discussion under Dynamically generated Branch structs without object, I’m wondering if the problem I now face is related.

I have now modified my macro from earlier to include two classes, with one of the classes a “superclass” which includes objects from the other class, and the other class a “subclass” inheriting from TObject. I then add to my tree parent branches referenced to objects from the “superclass”. The resulting structure does indeed nest branches within branches, but I am now having trouble filling the subbraches of these parent branches. After assigning values to the leaves in each subbranch, I first tried Fill() with tree. That didn’t work, so then I tried Fill() for each parent branch. That also didn’t work, so then I tried Fill() on each subbranch. Am I missing something like a SetEntries(), or SetBranchAddress()?

Am I missing something like a SetEntries(), or SetBranchAddress()?

Most likely set branchAddress.

with one of the classes a “superclass” which includes objects from the other class, and the other class a “subclass” inheriting from TObject.

Note that derivation from TObject is not necessary for I/O nor for splitting.

The resulting structure does indeed nest branches within branches, but I am now having trouble filling the subbraches of these parent branches. After assigning values to the leaves in each subbranch, I

Humm … how did you “assign values to the leaves in each subbranch” ?

Cheers,
Philippe.

Sorry for the delay in response.

If using SetBranchAddress(), would I have to do it for both a parent branch and its subbranches?

Without the derivation from TObject, I get a TStreamer-related run time warning which says the subclass objects inside of the superclass won’t be saved (data member won’t be saved). Under the section ROOT I/O Requirements for Classes I get that a class needs a default constructor to store objects with ROOT. Is this not applicable to what I want to do?

To “assign values to the leaves in each subbranch”, I write a function called by the main function which takes the class object associated with a subbranch, then assigns values to it’s member variables.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.