SetMaxTreeSize and Chain

I’m trying to store 2 branches in a TTree. One is called events, filled every time our detector receives a signal, and one called info with only one leaf. That leaf stores our run info like duration, detector ID, etc. I fill all the events, then when the run is finished I add the info branch and fill one singular RunInfo object. I have to wait until the end because I need the end time. The info branch isn’t made when the events branch is because then calling tree->Fill() would fill up both branches, even when the info leaf hasn’t changed and won’t until I can enter the EndTime. Spamming the tree with duplicates is ugly. This was working fine until I put a MaxTreeSize of 2GB. The files behaved as expected, but an issue arose when making a TChain for analysis.

    TChain *ch;
    TTreeReader *myReader;
    std::string ans;
    std::cout << "Enter the path towards your root file: ";
    std::cin.getline(root_Filename, 128);
     //lets strip the .root off the end so we can get asd.root, asd_1.root, asd_2.root, etc
    std::string fileNoExtension = std::string(root_Filename).substr(0,     std::string(root_Filename).find_last_of("."));
      fileNoExtension+="*";
    ch = new TChain("Detections"); \\selecting the TTree
    ch->Add(fileNoExtension.c_str()); \\adding the base .root file with a * appended to select all _1,_2, etc files swell
    ch->Print();
    myReader = new TTreeReader();
    myReader->SetTree(ch);
   
    RunInfo info; //my class that stores the runtime, detectorID
    // The branch "events" contains Event
    TTreeReaderValue<Event> event(*myReader, "events");
    TTreeReaderValue<RunInfo> cal(*myReader, "info");

    while (myReader->Next()) {
        events.push_back(*event);
        if(events.size()==1){ //only do it once because there's only one leaf
            info = *cal;
        }
    }

However I get an error that the info branch does not exist. I know it’s because if I have 5 files, only the 5th has the branch because it’s not added until the run has completed. Reading a TChain must work by reading each .root and stitching it together, but somehow loses branches that aren’t used in that file.
My hacky fix was to make both branches at the same time and fill them individually:

  TBranch* events = tree->Branch("events",&currEvent);
  TBranch* info = tree->Branch("info", &runInfo);

//in loop
  events->Fill();
  //if the start of a new file
  if(treeFile != tree->GetCurrentFile()){
         treeFile = tree->GetCurrentFile();
         print("Beginning new file. Adding RunInfo");
         info->Fill();
   }

Only issue is the SetMaxTreeSize will only have an effect when tree->Fill() is called. It doesn’t care about branch filling. So this code makes only 1 big file.
Any ideas? Maybe there’s a way to set a max branch size, or maybe a way to have a tree with 2 branches across multiple files but have the second branch empty until the final file?
Any help is appreciated.


ROOT Version: 6.11.02
Platform: OSX 10.11


Hi @mylesb,
as you realized most TTree/TChain features assume that each branch/leaf has the same number of entries.
If I understand correctly, you have a branch “events” with many entries, and one leaf “info” with only one entry.

I think the typical approach would be to store “info” in a different TTree (in the same ROOT file).
Would that do the trick?

Cheers,
Enrico

Hello,
I think the same issue would come up. Because I would have multiple files (orig, orig_1, orig_2, etc) wouldn’t the “info” tree only be saving to one of them (specifically in the last file because I need the finish time). Then when I use the TChain to link the files together, how would I only read from a tree thats in the last file? I’m imagining something like:

    //read events
    std::vector<Event> events;
    TChain *ch;
    TFile *myFile;
    TTreeReader *myReader;
    ch = new TChain("Detections"); \\selecting the TTree
    ch->Add(fileNoExtension.c_str()); \\adding the base .root file with a * appended to select all _1,_2, etc files swell
    ch->Print();
    myReader = new TTreeReader();
    myReader->SetTree(ch);
   
    // The branch "events" contains Event
    TTreeReaderValue<Event> event(*myReader, "events");

    while (myReader->Next()) {
        events.push_back(*event);
    }
    
    //now repeat process, but only on last file for info
    fileNoExtension = //some looping through directory and finding the last orig_x in the series
    myFile = TFile::Open();
    myReader = new TTreeReader("Detection_Info", myFile); //Detection_Info is the new TTree with only 1 leaf
    RunInfo info;
    TTreeReaderValue<RunInfo> cal(*myReader, "info");
    while (myReader->Next()) {
        info = *cal;
    }

While I think this would work, it’s a pretty clunky method. I like that it avoids saving an extra file along with the data files (ex. orig, orig_1, orig_2, …, orig_info), but is a weird hierarchy. Will probably do it this way, but I want to make sure there’s not a cleaner way.

Alternatively, you can of course save the “info” metadata in its own file. That’s what ATLAS’ xAOD format does. That’s false, my bad :smiley:

I can’t think of anything else, but maybe someone with more experience than me will have better advice.

Cheers,
Enrico

I ended up saving with an additional file named *_info.root. It’s not ideal because now that file has to be carried around and isn’t embedded in the data, but it’s not horrible.

How about storing a single (named) TParameter object in the same file in which you have your tree.

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