Dynamically generated Branch structs without object

This has come up twice before in root talk without a satisfactory answer each time. I’m going to re-cast the question a bit.

Why does it no seem to be possible to create trees with a branch hierarchy that has a depth greater than 1 without creating a class/object and using the splitlevel mechanism to have root generate the tree structure from that class/object?

Use case: I have a generic data analysis framework that I’m trying to integrate with Root. Users define a set of parameters that imply a hierarchy I’d like to capture in a generated tree. I can analyze those parameters and know, from them, the desired hierarchy. I would like to create a Tree that duplicates that hierarchy but at run time I don’t have an object i can point Root at to do this.

TBranch has a collection of sub-branches. TBranch has constructors that allow you to specify a branch has a parent branch. However, as has been pointed out before:

  1. Actually creating a branch with a parent does very little in the sense that it does not hook the branch into the hierarchy (does not even add it to the parent branch’s subbranch collection.
  2. It’s possible to manually do that addition however TBranch::Fill’s implementation does not iterate over sub-branches filling them… only over leaves. This can be gathered both by code inspection and experiment.
  3. Manually filling the lower level branches and the tree independently does not make the sub branches appear in the resulting tree.
  4. Adding the subbranch to the collection of branches maintained by TTree does result in the subbranch being filled but at the top level of the hierarchy rather than below the parent branch.

So, I’m not asking how to make a branch hierarchy… that can be done using classes/objects that capture that hierarchy… I get that… I’m asking why can’t I duplicate this ‘manually’? What would be needed to accomplish that?

Thanks to root Developers for any answer.

You can, you are only missing a few of the steps (and it is not clear what they are in part because we have not put effort in promoting this use case or even making it ‘easy’ to use :slight_smile: )

Manually filling the lower level branches and the tree independently does not make the sub branches appear in the resulting tree.

You are likely missing a call to TTree::SetEntries.

It’s possible to manually do that addition however TBranch::Fill’s implementation does not iterate over sub-branches filling them… only over leaves. This can be gathered both by code inspection and experiment.

Yes, any branches that does have data in them (a few branch type are ‘empty’ nodes) must have a TLeaf(Element) associated with it. That leaf needs to be added both to the list of leaves of the branch and of the TTree.

Actually creating a branch with a parent does very little in the sense that it does not hook the branch into the hierarchy (does not even add it to the parent branch’s subbranch collection.

Yes, those are intentionally distinct operation (it is easier that way to handle the various cases).

Cheers,
Philippe.

I’m not 100% clear on what I’m missing, Could you provide a simple example?
Say a tree with a top level branch that has a leaf.
Add to that top level branch a sub branch which also has single leaf in a way that this is all seen by the TTree?
How to fill this monstrosity?

Thanks,
Ron

How to fill this monstrosity?

I am a bit confused … What is your goal? … If you want simple and clean, use the ‘usual’ technique. If you need something more complex, you would have to set the branch address via either the constructor or a call to TBranch::SetAddress.

which also has single leaf in a way that this is all seen by the TTree?

Yes for historical reason the TTree has a list of all leaves. Adding your leave to that leaf may or may not be needed depending on the tool(s) you will use to read it back.

My goal, as stated in the OP. I have an existing general purpose online data analysis program into which I’m trying to slide bits and pieces of root. The analysis program has an existing mechanism for defining, describing and extracting parameter values from event sources.
Parameter definitions are made at run time and parameter extraction depends on user written code that acts as a plugin. I’m trying to avoid having any impact on user written code as I do this
Parameters live in some hierarchy such as you might expect e.g.:

Detector 1
   Subsystem1
       Param1
       ...
       Paramn
   Subsystem2
       Param1
       ...
       Paramn
Detector 2
   Subsystem1
       Param1
       Paramn
....

I have code that can take the parameter definitions and reconstruct at run time the hierarchy. I want add to my existing program the ability to create root trees with a matching hierarchy (without user programming) for example:

Tree
   Branch for Detector1
      Branch for subsystem1 - Leaves for param1.. paramn
      Branch for subsystem2 - Leaves for param1..paramn
   Branch for Detector2
      Branch for subsystem1 - leaves for param1..paramn

Etc.
I don’t think I want to get into having my program dynamically write a C++ class which I then have root compile and then dynamically load. So therefore I think I ruled out what you called the ‘clean’ way to do things.

I’ve attached an attempt that I thought captured what you’ve suggested so far. It just tries to make a simple tree hierarchy:

Tree
    Top ->  A leaf in top.
         Subbranch -> A leaf in subbranch

That is what I asked as an example. A tree with a branch that has a leaf and a subbranch with another leaf.

If you run this program, which does some nonsense filling of the branches and then poke a TBrowser at the resulting file, what you see is

Tree
    Top as a leaf 

Where that leaf contains the data filled into the top branch’s leaf. Opening the file from root and Print-ing the tree confirms that this is the structure of the tree:

root [0] TFile::Open("Test.root", "READONLY");
root [1] TheTree->Print()
******************************************************************************
*Tree    :TheTree   : Some Tree                                              *
*Entries :      100 : Total =            3069 bytes  File  Size =       1098 *
*        :          : Tree compression factor =   2.72                       *
******************************************************************************
*Br    0 :Top       : leaf1/D                                                *
*Entries :      100 : Total  Size=       1848 bytes  File Size  =        296 *
*Baskets :        1 : Basket Size=      32000 bytes  Compression=   2.95     *
*............................................................................*

What steps is my little test program missing?

Thanks,
Ron

subtree.cpp (1.84 KB)

I have gotten rumors that my inability to do this is actually due to a long standing bug that has very low priority (as the normal use case is to build classes).

Is this correct?

TBranch* top = pTree->Branch("Top", &leaf1, "leaf1/D");

This type of branch assume/knows it never has any sub-branches … hence the Print output …

One possible way to sorta get the structure you hope for might be

    TBranch* top = pTree->Branch("Top", &leaf1, "leaf1/D");
    TBranch* sub = pTree->Branch("Top.SubBranch", &leaf2, "leaf2/D");

where the link is only semantic (in the name).

So in other words what I want to accomplish is not possible in the way I want/need to accomplish it? Only class/objects can make trees with anything but a flat branch structure?

If so I come back to my original question:: Why not?
If not I come back to my second question: Can you show a simple example that demonstrates how?

Thanks,
Ron

I want/need to accomplish it?

I understand the want part (nicely represent your structure without describing it classes) but I don’t understand the ‘need’ part. I.e. what is being blocked by not having exactly that structure.

what I want to accomplish is not possible

It seems that you are more or so the first to try this kind of custom hierarchy and indeed the inner does not (as far as we have found out so far) support it. (i.e in your example, the data is saved but the tools (like TTree::Print) are not fully aware of it). So the code would need some adaptation to support this case …

There is two other ways to accomplish something similar. One is with friend tree (i.e. move the problem one level up).

    TFile* pFile = new TFile("Test.root", "RECREATE");
    TTree* mTree = new TTree("MasterTree", "Some Tree");
    TTree* d1Tree = new TTree("detector1","Dectector 1 tree");
    mTree->AddFriend(d1Tree):
    d1Tree->Branch("Subsystem1", &leaf1, "leaf1/D");
    d2Tree->Branch("Subsystem2", &leaf2, "leaf2/D");
    etc ....

I don’t think I want to get into having my program dynamically write a C++ class which I then have root compile and then dynamically load.

You can also/instead dynamically write C++ but ‘just’ load it via the interpreter. [Note that this kind of solution is being used in production by some users]

Cheers,
Philippe.

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