Create New TMBTree Object

 
Home Research Classes

Introduction

Sometimes the TMBTree doesn't have all the information in it that you want. Adding a new branch to the resulting root tuple isn't very difficult -- though it is the type of task with lots of little things that have to be done correctly.

The TMBTree is made up of root TTree branches. Each branch contains a certain type of object (like a TMBGlob for the global event info) or a TClonesArray of an object (like a TMBJets object). Root I/O allows the actual object to be written to the TTree, and for the program using the root object to fluf it up again. The MakeTMBTreeClasses_so.C file builds the shared object library that root uses to read these objects.

The TMBTree is made by the program TMBAnalyze_x, which is built in the cvs package tmb_analyze. For each TMBTree object, there is a maker. For example -- for TMBGlob there is a TMBGlobMaker object. The TMBTree objects are all located in the tmb_tree cvs package by convention. Most of the makers can be found in the tmb_tree_maker package, though some are spread around in other packages.

By convention all TMBTree objects are put in the tmb_tree package, and all makers are put in other packages. This is because the Maker objects often link with things from the D0 infrastructure software -- a bad thing for the actual root objects.

What Goes Where

There is one global design decision to make when you create your new TMB Object. Will there be only a single object in each event (like the TMBGlob object) or will there by many (like a TMBJet object)?

  • If there will be many you will be creating a TTree branch that contains a TClonesArray of the objects.
  • If there will be a single one, you'll create only one such object for the TTree branch.

The TMBTree object should contain only the bare minimum of information that you wish to store in the TMBTree. For example, a series of floats: px, py, pz or similar. No D0 data structures should be stored in this object. You may have getter and setter methods to access these variables, or you may make the variables public so that is not required. The getter and setters can, of course, contain code that will make it easy for the user (especially the analysis user) to use the data. Above all, keep it simple. The TMBTree object doesn't really participate in the making process other than as a container.

The TMBTreeMaker object can store whatever it likes -- it is only built and running during the time the TMBAnalyze_x program is running. If you need to store a reference to a data chunk for some reason, that is fine. The TMBTreeMaker's job is to convert the D0 Chunk data into your TMBTree objects.

There are several important coding steps to getting a Maker up and running:

  1. In the constructor you should create a TClonesArray or your object and store it in the _Fruits inherited instance variable. You will never delete this object. This sounds funny, but you won't. You'll just reset it (or clear it) between events. This is because root tracks the address of this variable. The other thing you'll do in the constructor is set the Branch Name that root will write this to.
  2. The next important thing is the Make method. This method is passed an edm event, and is responsible for converting that data into your TMBTree objects.
  3. Finally, the Clear method will be called between events. In this method you should reset anything that needs reset. Be sure to call the inherited Clear method -- that will, in the end, call the Clear method on the _Fruits instance variable, which will reset the TClonesArray, or your object (if you've implemented the overloaded Clear method).

That is it!

Step-by-Step

I created a small script to help me generate these TMBTree objects and Maker files -- there is enough boiler plate code that you can easily go wrong. The process isn't totally smooth, as I'm only just learning it myself.

Setup Work Environment

  1. Create a new local release. I did most of my work in p15.02.00, but your favorite will probably be just fine.
  2. Add the tmb_tree and tmb_tree_maker packages to the release.
  3. Add the /d0mino/gwatts/scripts/new_tmb to your PATH.
  4. Don't forget to do a d0setwa!

To Add A TMBTree Object

  1. Choose a name. Start the name with TMB. For example, TMBL1CTT.
  2. cd into the tmb_tree_maker package -- top level -- and run the script make_tmb_obj <name>.  This will create template TMBTree object and maker files. Unfortunately, it will put both the TMBTree object and Maker in the tmb_tree_maker package (wrote script before I knew better). So...
  3. Move your TMBL1CTT.cpp, _t.cpp, .hpp, and _linkdef.h files from the tmb_tree_maker package into the tmb_tree package. Remove the TMBL1CTT line from the COMPONENTS file in the tmb_tree_maker package and add it to the tmb_tree package's COMPONENTS file. You will also have to fix up include paths in the maker files.
  4. Next you have to instantiate your object in the framework package. In the tmb_tree_maker src directory edit the file TMBCorePkg.cpp  -- it instantiates each maker. Add yours to the end, following the pattern there (and you'll have to add an instance variable to the .hpp file too).
  5. At this point you should be able to build everything.
  6. Next, add the instance variables you wish to save to the TMBL1CTT object's definition. Add any getters or setters you like.
  7. Next, get the constructor for the TMBL1CTTMaker correct. If you are going to have lots of objects and want to store them in a TClonesArray, you can leave it as is -- the template code assumes this. If you want only a single object, modify the _Fruits line to look like "_Fruits=new TMBL1CTT();"
  8. If your object is only a single one per event, make sure to change the Clear method so it doesn't call the TMBMaker::Clear inherited method -- that will end up deleting your object. Instead, call _Fruits->Clear() directly, or otherwise reset your _Fruit to prepare it for the next event.
  9. In the Make method, add code to extract the information you need. Use the supplied addTMBL1CTT routine to add a new object if you need an array. Otherwise just typecast _Fruits to your object type for a single object.
  10. Compile, build, and run on a small sample. You should be able to open the resulting tmb_tree.root file in root and see all of your objects instance variables.

Processing the root Tree

The code modifications to process the root tree are pretty simple. You should already have the basic up and running.

  1. If not there already, copy down from the macros directory a TMBTreeClasses.C and TMBTreeClasses_linkdef.h, and MakeTMBTreeClasses.C file.
  2. Edit these files and add the appropriate lines for your new class (it will be obvious what to do when you look at these guys).
    • If your new class is in a package/directory other than tmb_tree/src and tmb_tree/tmb_tree, you'll need to add the include path to the MakeTMBTreeClasses.C file.
  3. run root -q -l MakeTMBTreeClasses_so.C to make sure everything compiles.
  4. If you modify the TMBTree_bu.h file that is in the macros subdirectory, you can add the new branch. Follow the pattern of something like a TMBGlob for a single object, or TMBJet for data stored in a TClonesArray.
  5. Add code to the Loop() method of TMBTree_bu.C and see it work!

Examples

The best way to see how it is done is to look at something that already works!

If you want to look at some advanced coding check out the bcjet objects and their makers.

Gotchas

I have been nailed by and spent an inordinate amount of time on:

  • If your TMBTree object contains a pointer to any other object, make sure that you zero out that pointer in all constructors. This will cause all sorts of weird behavior during read-back!
  • Do not delete the _Fruits object. Bad things will happen.
  • If you are creating a single object, make sure you don't call TMBMaker::Clear in your Maker's clear method. This will wind up deleting your _Fruit, and that would be rotten. Instead, call _Fruits->Clear() on your own (or otherwise clean up and prep for the next event).