Tree with multi-branches

Hello
I just wanted to double check about the functionality of trees when adding data to different branches or the same one.
Consider:

  //MODE 1: multiple branches
  dataTree->Branch("charge", &charge);
  dataTree->Branch("mass", &mass);
  dataTree->Branch("posX", &posX);
  dataTree->Branch("posY", &posY);
  dataTree->Branch("localTime", &localTime);
  dataTree->Branch("kinE", &kinE);

Against

//CASE 2: Multiple leaves
dataTree->Branch("mybranch", &charge, "charge/I, mass, posX, posY, localTime, kinE/D");

[Q1] These trees will have a different internal structure so I understand from the class reference. Any advantages/disadvantages?

In my specific case, I am looking at a event that produces two signals that goes into two detectors (For simplicity). Each signal has a potential to produce multiple hits. [Q2:] In my scenario, would it be more convenient to create a branch for EACH detector using the MODE 2?

[Q3:] Last question, is there a smart/proper way to keep up with alignment in ttrees? For example, in one event, detector 1 has one hit and detector 2 has 5 hits. I am thinking either to pad detector1’s extra fields with zeros (creating redundancy) or aligning events during the data processing stage. Any suggestions? Could I avoid padding by filling each branch independently and then when i read the trees, I will have to ensure alignment of events, say, by using an eventID field in each branch?

Thank you,

I implemented successfully both modes so far. I was able to retrieve and plot data using MODE 1 via TreeViewer from a TBrowser object. However, when I try MODE2, the TBrowser doesn’t allow me to expand my branches so I have no access to the leaves. I wonder why when using MODE2 I cannot use the TBroswer to browse my data. Does anything to do with the splitlevel?

Thanks,

Hi,

Indeed the TBrowser (and also the TTreeViewer) do not support access to more than one leave in a ‘leaflist’ branch (as opposed to the case where the Branch is created via an object).

[quote][Q1] These trees will have a different internal structure so I understand from the class reference. Any advantages/disadvantages? [/quote]The first approach (one leaf per branch) will let you (if needed) read the content of each leaves separate, saving in reading and unstreaming time.

[quote][Q3:] Last question, is there a smart/proper way to keep up with alignment in ttrees? For example, in one event, detector 1 has one hit and detector 2 has 5 hits.[/quote]The recommendation is to have one entry per event but (when needed) more than one value per entry. This can be achieved by using a vector of values rather than a single value.

[quote]Could I avoid padding by filling each branch independently and then when i read the trees, I will have to ensure alignment of events, say, by using an eventID field in each branch?[/quote]If you were going in that direction, the best would be to have one TTree per detector.

[quote] [Q2:] In my scenario, would it be more convenient to create a branch for EACH detector using the MODE 2? [/quote]The better alternative would probably to have object describing each detector and create one (split) branch for each detector using those objects (and to support the multiple hit, the object would likely contains vector).

Cheers,
Philippe

I am trying to implement a Tree per detector. Should I have a TFile object for each tree?

  1. I create a file
  2. Then I created three trees (I am assuming they get assigned to the same TFIle)
    Note: I am doing this in my geant4 code
  3. I have pointers to the three branches using TBranch* objects
  4. I fill each TBranch when I see it convenient
    At the end, when I try to write on the file, I get a seg fault.

Can I write different branches at different rates? For example, my alpha ranch only collects single hits per event while my gamma branch could collect multiple hits? (Each hit = one fill) Then I will be filling my gamma branch first and I will be calling the gammaBranch-fill() function more often.

In most examples I see tree->fill() being called but for me it is not convenient since I am writing more gamma hits.
Am I doing something wrong here?

Thanks,
Chris

Hi,

[quote]Can I write different branches at different rates? [/quote]You can, but it is strongly discouraged (in the same TTree) as most tools assume balanced TTree.

[quote] but for me it is not convenient since I am writing more gamma hits. [/quote]Why? I thought you now had as many TTree as top level branches (i.e. 3 of each). What would be the difference?

[quote]At the end, when I try to write on the file, I get a seg fault. [/quote]Not enough information to guess. One thing though is seems you did not call TTree::Fill nor TTree::SetEntries … the TTree essentially thinks they are empty (however this should not lead to a crash).

Cheers,
Philippe.

[quote=“pcanal”]Hi,

[quote]Can I write different branches at different rates? [/quote]You can, but it is strongly discouraged (in the same TTree) as most tools assume balanced TTree.

[quote] but for me it is not convenient since I am writing more gamma hits. [/quote]Why? I thought you now had as many TTree as top level branches (i.e. 3 of each). What would be the difference?

[quote]At the end, when I try to write on the file, I get a seg fault. [/quote]Not enough information to guess. One thing though is seems you did not call TTree::Fill nor TTree::SetEntries … the TTree essentially thinks they are empty (however this should not lead to a crash).

Cheers,
Philippe.[/quote]

Sorry I was not clear about my second point. Ok, when I fill hits at different rates, I meant to say I will be saving more gamma hits than alpha hits. If I have one tree for a gamma and another for the alpha, I will be calling gammatree->fill() more often than alphaTree(). The trees will have different sizes and event alignment would happen when I analyze the data. I think now I have this concept clear.

The problem is that I was trying to outsmart the system (overcomplexify). I am using a single three, I have created three branches and I am calling each TBranch::Fill() function. As I understand from your posting, I could do that except I have to call first TTree::SetEntries (?). I am afraid if I call ttree->fill() it will fill redundant data in my alpha detector. That is why I am thinking this way. Maybe I should stop thinking about having only one TTree object but define three instead.

Another thing I can remember is that I am using a RunID to keep event alignment and I am using that same variable when I am defining each branch:

TBranch *aDet=dataTree->Branch("alphaBranch", &runID,"runID/I,...");
TBranch *gDet=dataTree->Branch("gammaBranch", &runID,"runID/I,...");  //OK to share addresses?

(...)  //Process events and fill tree

//dataTree->Fill();
//INSTEAD
for loop (alpha events){
   aDet->Fill();   //Usually 1 hit
}
for loop (gamma events){
   gDet->Fill();  //Usually more than 1 hit
}   

dataFile.Write(); //a TFile object...

About the segmentation fault, I am thinking it is the way I am saving the TTree since the gamma branch gets filled more often than the alpha and then at the end I saved the data when I called the TFile::Write() function. Now, this is my assumption. I will check my code again and do a more careful inspection and I could try creating a small script to reproduce the problem.

Thank you very much for your comments,
C.

[quote]The problem is that I was trying to outsmart the system (overcomplexify).[/quote]Please don’t :slight_smile:. If the branch are going to be unbalanced, create 3 different TTree, however wise you end up with 4 different value (number of entries in each branches and in the TTree) and the last one (number of entries in the TTree) is meaningless … but ALL the rest of the ROOT code assumes it is the most important … (If for some reason that I don’t understand, you really need this configuration, I am afraid you will have to investigate why it fails).

[quote]//OK to share addresses?[/quote]Maybe or maybe not … It is technically doable but might lead to each confusion.

Cheers,
Philippe.

Thank you very much for your comments. I got everything working now. I was able to test the memory assignation, as to be able to assign the same values to different TTrees, However, I noticed I am using my abstract class to read the values later on for analysis which I am forced to defined those values as separate members, unique to each detector. It makes sense now…

The segmentation fault was completely unrelated to the three assignation. Lesson of the day: Never implement two changes at once… I still need to learn that one!

C.