Writing Custom ROOT Objects from Athena

Introduction

There are two ways to write custom ROOT objects to a seperate file in Athena. The difference methods revolve strictly around the method of generating the ROOT class dictionary - something required by ROOT for I/O.

ROOT requires a to write a complex object out to a tree. The dictionary tells ROOT the members and methods provided by the object and allows it to efficiently write the object out (as a split tree for example). The dictionary is generated by running a program called rootcint or genreflex. This is all very easy to do from the command line. Getting this into the ATLAS cmt build system is a bit more tricky - but once you know the magic incantation is actually very easy - the above tutorials show you how to do it.

Technology Choices

There are several choices you have to make when you start your project. Unfortunately, once you make them it isn't trivial to change them later on in the project (changes to your requirements file as well as, possibly, to all your I/O objects). Below is some general discussion on what to do, a bit of why, and also how to fit in well with the rest of ATLAS. Further, the various issues are not orthogonal yet.

Some of the choices you have to make are predicated on support and bugs in ROOT or in ATLAS. This is, of course, a moving target. This wiki page was written when release 15.2 was out and 15.3 was just being made. Both use ROOT version 5.22. ROOT 5.24 had just been cut by the ROOT team.

Which Dictionary Generation Method Should Be Used?

The two methods to map a class so that the ROOT I/O sub-system understands its layout are rootcint and genreflex. Each method has a parser that looks at your object header and converts that into some code that lays out the class.

  • rootcint has been in existence since the start of the ROOT project and everything in ROOT has been developed against it. So it supports all of the I/O features in ROOT. However, it uses CINT to parse your C++ header. While CINT works well for non-template C++, and for basic STL for C++, it doesn't work well for complex C++ template types.

  • genreflex uses the gcc front-end to parse your header - so it can probably handle everything that gcc can. However, it is relatively new to the ROOT project and is not used internally by the ROOT team - nor, really, anyone outside of CERN. As a result, it dosen't fully support all I/O features. For example, see the ClassDef discussion below.

Internally, ATLAS prefers the use of genreflex. Most of the I/O sub-system is based on this, for example (all the transient/persistent code). For code that is in that style it is quite capable. If you want to use ClassDef's (for example, inherrit from TLorentzVector) then you will run into some limitations in ROOT 5.22's genreflex support. In that case it is best to use rootcint. Rootcint also seems to require less boilerplate code and extra files in the ATLAS build system.

To ClassDef or not to ClassDef

In the old days in order to write out an object in ROOT you had to add a ClassDef macro to it:

class JetInfo {
public:
  int defaultTagValue;
  TLorentzVector v;
private:
  ClassDef(JetInfo,1)
};

This would allow the I/O sub-system access to the various variables in the class as well as the ability to write it out (and split it). It also adds methods that enable the TBrowser object in ROOT.

Modern versions of ROOT, however, do not require this. This is very nice because this means, especially in a very large software project, not every object that you are writing out has to take a direct dependency on ROOT.

There are some speed advantages that come with using ClassDef. ROOT developers claim a 5%-10% I/O speed improvement for classes with ClassDef in them with rootcint. There is no speed improvement when using genreflex.

Internally, ATLAS prefers one not to use ClassDef. The ATLAS software project is huge and already has many interdependencies. Removing the ClassDef macro removes one dependency on ROOT. For a while a rule for the core software packages was no ROOT dependency, btw.

To split or not to split

Splitting your tree is an I/O issue and a usability issue. Think of it like this. You can write out your objects as a blob of binary data, organized in your file as object 1, object 2, object 3, etc. Or you can split the object into its compoents. Take the JetInfo object above, for example. You can write the first 1000 jet's defaultTagValue in one blob, and then next you can write the first of the four components of a TLorentzVector, then the second, third, and forth. Then you can write the second 1000 jet's defaultTagValue, etc.

The advantages to splitting are two fold. If you are only interested in reading in and plotting the defaultTagValue then you only need to read those sections of the file. If you are running at a GRID site that has xrootd this can be a huge savings in network I/O, for example. If you are always going to read in the full event (say, using MakeClass), then you loose this advantage.

Second, ROOT data is compressed before it is written out. Grouping data together that looks a like can improve the compression algorithm's efficency - which should make the resulting ROOT files a bit smaller.

If you choose not to split your tree, then things like MakeClass will no longer work (MakeProxy, however, will continue to work). Further, you can't use a MakeClass generated with a split tree on one that isn't split (the leaf and tree names change!).

Internally, ATLAS has no directly guidelines for this. In general every bit of code leaves the split level setting at the default of 99, which means fully split the tree as much as possible. If you are using rootcint I'd say just leave it like that. If you are using genreflex then you need to think about this a little more if you are including TLorentzVector's in your classes (or any other ClassDef'd object) and are stuck using ROOT 5.22.

-- GordonWatts - 05 Jun 2009

Topic attachments
I Attachment History Action Size Date Who Comment
Unknown file formatcxx CustomObjOutputAlg.cxx r1 manage 2.5 K 2009-06-06 - 16:14 GordonWatts  
Header fileh CustomObjOutputAlg.h r1 manage 0.8 K 2009-06-06 - 16:14 GordonWatts  
PNGpng PlotOfJetPt.png r1 manage 20.3 K 2009-06-06 - 15:05 GordonWatts  
PNGpng TBrowserViewOfJets.png r1 manage 23.5 K 2009-06-06 - 15:11 GordonWatts  
Edit | Attach | Watch | Print version | History: r4 < r3 < r2 < r1 | Backlinks | Raw View | WYSIWYG | More topic actions
Topic revision: r4 - 2009-07-03 - GordonWatts
 
    • Cern Search Icon Cern Search
    • TWiki Search Icon TWiki Search
    • Google Search Icon Google Search

    Main All webs login

This site is powered by the TWiki collaboration platform Powered by PerlCopyright & 2008-2019 by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback