Plots.C Documentation

(Steve Beale Mar 2004)

(Updated and adapted Camille Belanger-Champagne July 16 2004)

On this page
How do I use this thing?
Great, what does it do (and how)?
The Histograms
Adding NEW histograms
To Create a new histogram class

!! BUG WARNING !!

After compiling LoadPlots.C in root, the first time you run the Loop() function you may get a crash (segmentation violation), but if you quit root, load LoadPlots.C again, it should be fine. The problem has to do with compiling but hasn't been sorted out yet. Also don't run ReInit() after running Loop(true), it will crash (it's fine with just Loop() ).


How do i use this thing?

cd to the root directory of trigsimcert, setup environment and launch root ie:
setup d0tools
setup D0RunII p17.00.00
d0setwa
root
Load and compile Plots.C:
root [0] .x trigsimcert/macros/LoadPlots.C
Make a Plots object with the desired input/output parameters:
root [1] Plots YourPlot("input/file","output/dir")
Run the Loop function to generate the plots
root [2] YourPlot.Loop()
It's a good idea to clear the histograms from memory afterwards
root [3] YourPlot.ReInit();
Or if your finished with this instance of Plots, kill it
root [4] YourPlot.~Plots();
"input/file" should be a text file containing a list of root tuples. If any of the listed files are not found, they are skipped and the macro will just analyze the valid files. "output/dir" should be a path to an existing directory. The reference root file should be here, and a postscript file called plots.ps will be placed here (overwriting any previous plots.ps). If you want to name the postscript file modify the line root[1]:
root [1] Plots YourPlot("input/file","output/dir","psname")

!!Note: to keep the canvas' from poping up, run root as "root -b"!!


back to top


Great, what does it do (and how)?

The quick answer for the impatient:

When you call the Plots constructor the root files are opened and the root trees loaded into a chain (however the reference file is not yet opened). Histograms and trigsimcert objects are created and initialized but nothing else will happen until you call the Loop function. The Loop function opens the reference file, and loops over all events pulling out the trigsimcert objects (that is things like L1Cal, L1Track etc...) These objects are passed to the histogram class objects which handle all the plotting. The resulting histograms are saved in a postscript file (plots.ps in your output directory). The histograms themselves will be plotted against a set of reference data. The loop function can also be used to generate the reference histograms. Just run the loop function as Loop(true), the input file will be taken to be a set of reference data, and the histograms will be put in a root file called Ref.root in the output directory.

The long answer for the detail oriented:

Loading + Compiling:
Running LoadPlots.C within root will load and compile all the necessary files to run the macro.

Constructor:
As mentioned above, the constructor will open the root files. The input file is checked before it is opened, if it doesn't exit or can't be opened for whatever reason, the user is notified of the problem and the constructor will bail out. Similar for the output directory, however instead of trying to open a file, a test file is created (called "test") and will be placed in the directory. If the file can't be created (ie if the directory doesn't exist) the user is notified and the constructor bails. The constructor accepts output directories with or without a '/' at the end. That is "output/dir" and "output/dir/" are both acceptable. By default the working directory is used for output, so the constructor can be called with only an input file. Once the input and output are tested, the input file is opened and read. The input file should be a text file listing root files to analyze. A note for the pathological: don't use a path that is longer than 200 characters, it won't work. It's also not a good idea to have blank lines, they will can cause problems. Each line is interperted as a file name, so a blank line is considered a file. Each 'file' (that is each line) is tested for validity before being accessed and if the file is not found, you'll get a message that says "Could not open $filename". So a blank line shouldn't be a problem, you'll just get error messages saying "Could not open " and the constructor will carry on trying to open the rest of the input files. As the files are opened the root trees are extracted and added to a chain. The trees MUST be labeled as "trigcertTree," so long as they came from trigsimcert, this should always be true.

Initialization (function Init() ):
Once all the input/output is taken care of the initializing function is called (a private function, if you want to reinitialize see the section on ReInit). Here the trigsimcert objects are created (ie L1Cal, etc...) as well as TClonesArray's which will act as branches. Once created the TClonesArrays are initialized to the proper branches from the tree chain. Finally histogram classes are created and initialized via their respective constructors (which make create empty histograms).

Reinitializing (function ReInit() ):
Once you have created a Plots object, you can explicitly reinitialize it. This public function will delete the TClonesArrays and the histograms and then call Init() to recreate them. If you want to run Loop twice on the same Plots object, call this function after the 1st Loop. NOTE calling ReInit() after running the Loop function with 'true' (ie to produce a reference file) will crash. It's beter to just quit root and load it again if you generate a reference.

Loop:
The looping function, it loops over all events in the chain extracting trigsimcert objects. Once an object is extracted it is passed to it's histogram object which fills the histograms for that particular object. Internal loops are used for branches which have more that one object per event (ie electrons, jets etc... that is, most branches). All the histogram classes have a function called Fill(Object) which take an instance of the object it plots. Example: We have an L2Jet histogram object called hl2jet, and we loop over the number of level 2 jets, each time we extract a L2Jet object and call it l2jet, and pass it to the level 2 jet histograms via hl2jet->Fill(l2jet). There is a histogram object for each branch in the chain (tree), and they all call their respective Fill function, even if they don't currently do anything. There is also a DoneEvent fucntion which gets called by every histogram object. This function is used to fill histograms which contain only one entry per event (ie #things/event etc...).

Once the loop is finished, the reference file is opened (with the standard check to make sure it exists), and a post script file is created. Calls to each histogram objects Draw function are made. The Draw function takes the reference file and postscript file as parameters. The drawing of the histograms is discussed below. Once the histograms are drawn, the reference and postscript files are closed and the Loop will return a value of true (and everyone lived happily ever after).

Loop can also be used to generate a reference file by running Loop(true). In this case the input is taken to be a list of reference data. Everything runs the same up to the point where it finishes with looping over events. Now a reference file is created (as opposed to opened) and the histograms are writen to this file. Each histogram object has a Save(file) function. There is no call the the Draw functions and no postscript file is created. Once the save is complete the function returns true.

Histogram Classes (for L1L2, L3 is a little different, see below):
All the histogram classes have the same overall structure. They all start off with a warning to regenerate the reference histograms should you decide to modify any histogram parameters. And just because it's really really important, I'll warn you here too: (however it doesn't look very nice in HTML)

IMPORTANT!!!!
If you change the histogram properties you must regenerate the
reference file 'Ref.root': To do this make a 'Plots' object with the
reference file, and then run Loop(true) ie:

.x macros/LoadPlots.C
Plots anyname("input/file","output/path/dir/");
anyname.Loop(true);

Where 'input/file' is a text file containing the path to the desired
reference root tuple, and Ref.root will be placed in
'output/path/dir/Ref.root'
IF YOU DO NOT REGENERATE THE REFERENCE FILE THE PLOTS WILL NOT WORK

That said, the rest is pretty straight forward. Each histogram has it's dimensions defined at after that cheerful little warning, so it should be easy to redimension them if you want. Each histogram has a constant for the number of bins, and the x axis minimum and maximum. As described in the discussion of the Loop function, there is a Fill, DoneEvent, Draw and Save function common to all histogram classes. These functions are all pretty simple, have a look at the code, they're only dozen or so lines. However I'll mention one execption to Draw. Draw has a third boolean parameter called debug which is defaulted to false, however if called as Draw(ref file,ps file,TRUE), then the canvas for this histogram will not be closed. This can make debugging easier as you don't have to keep refering to the ps file to see the output.

Histogram Classes (for L3):
These classes have the same interface and overall structure, however they are implemented differently. At L3 the number of different plots may be dynamic depending on the number of L3 tools used. The histograms are stored in vectors and created as new tools are found in the loop. Note that if a tool wasn't present in the reference data set, there will be no reference to plot against.

HDraw:
This class is inherited by all the histogram classes. It's a general purpose histogram plotter. Any changes to the format of the histograms can be done here and will be passed on to all the histogram classes. The drawing function is called DrawHisto, and takes a rather long list of arguments:

DrawHisto(TH1F *DATA, bool drawref, TH1F *REF,TLegend *Leg, char *hist_name,char *file_name,bool Gaussian)

DATA is the histogram to to be plotted as data points. If drawref is true, the reference will be plotted. REF is the reference histogram, if drawref is false, this is ignored (but still needs to be something). Leg is an existing legend to which entries will be added. Thus if you like you can pass a legend with enties already added and they will not be overwritten. hist_name and file_name are strings that are used in error notification (to let user know which class + histogram has the problem). The boolean variable Gaussian defaults to false (ie can skip it). If set as true the histogram is 'treated' as a gaussian like distribution (has a peak...), currently all this actually does is has the RMS displayed in the legend.

back to top


The Histograms:

Since all the histograms are plotted by the same function, they will have the same format:

- Data appear as black cross'
- Reference appears as solid red line with a red axis on the right
- The histograms are rescaled to provide a little extra clearance on the top margin.
- Reference is scaled by area
- The Legend will displat the reduced chi^2 (unless it's 0), and the underflow/overflow of the data (if there is any) as well as the root-mean-square of the data and reference (format is 'DataRMS/RefRMS') if the 'Gaussian' variable is true. If the chi^2 value if higher that some parameter (currently set to 3), a red star will appear beside the chi^2.

In determining the reduced chi^2 from the 'full' chi^2, only bins with a non-zero entry in the reference are used. That is, if there are 50 bins in a histogram, but only 40 bins in the reference have non-zero entries then the reduced chi^2 is chi^2 / 40.

Example Plot

back to top


Adding NEW histograms:

There are two ways to do this, the easiest is to simply add another histogram to an existing histogram class. This might be best if the desired histogram makes use of a branch that already has plots. On the other hand, if you've created a new trigsimcert class and want to plot histograms for it you'll have to create a NEW histogram class and then include it in the appropriate places (see below).

To add to an existing histogram class:

This is rather straight forward and can be done by modifying the appropriate histogram class, you won't have to touch any other files. As mentioned before, L1L2 and L3 are handled differently, first we'll go through adding to a L1L2 histogram class.

L1L2:

Open up the desired histogram class source located in macros/HistoFill/ First define the parameters for the histogram (about line 40 or so). Say we want to make a new histogram called NEWHISTO, define:
const Float_t HISTOmax = 10;
const Float_t HISTOmin = 0;
const Int_t HISTObins= 20;
const char HISTOaxis[]="The X axis";

Note that these are GLOBAL constants, they CAN NOT conflict this other histogram classes. By convention the histograms are all names with uppercase letters. Next define the histogram itself in the class declaration:
...
private:
TH1F *NEWHISTO;
...
Now initialize the histogram in the constructor:
NEWHISTO = new TH1F("l2histoclass_NEWHISTO","A TITLE",HISTObins,HISTOmin,HISTOmax);
//Set x axis titles:
NEWHISTO->GetXaxis()->SetTitle(HISTOaxis);NEWHISTO->GetXaxis()->CenterTitle();
Add a delete command in the destructor:
delete NEWHISTO;

Add a Fill command to either the Fill function, or the DoneEvent function (to Fill if there is more than one instance/event, or to DoneEvent if there is only one instance/event). If you use DoneEvent you may need to change the declaration to include the trigsimcert object
ie before: after:
void DoneEvent(); void DoneEvent(L1Cal *l1cal);
Add the fill command as (supstitute the appropriate class + accessor):
NEWHISTO->Fill(l1cal->Et());
Add a Write command to the Save function:
NEWHISTO->Write();
Now Draw the histogram (...using the Draw function...)
Histograms are drawn on canvas' of four plots each, If there are less than four histogram when you add, then you need only select the next pad and draw. If there are already four plots, you will have to clear the canvas after it has been written to the postscript file:
Less than four plots (this example assumes there are three):
After the last plot but before the ps-NewPage() add:
cl1cal->cd(4);
TLegend *Leg4=new TLegend(.75,.75,.99,.99,"");
if(drawref)
{
//DRAW WITH REFERENCE:
TH1F *NEWHISTOref=(TH1F*) ref->Get("l1cal_NEWHISTO");
DrawHisto(NEWHISTO,drawref,NEWHISTOref,Leg1,"NEWHISTO",THISFILE);
}
//DRAW WITHOUT REFERENCE:
else DrawHisto(NEWHISTO,drawref,0,Leg1,"NEWHISTO",THISFILE);
If there is four (or 8 or whatever):
After the canvasname->Update() command:
First turn off the postscript and clear the canvas:
if(post) ps->Off();
canvasname->Clear(); //NOTE: This hasn't yet been tested, you may need to fiddle with it.
canvasname->Divide(2,2);
then draw as above, and repeat the updating of the postscript:
if(post){ ps->On(); ps->NewPage();}
canvasname->Update();
if(!debug) canvasname->Close();
And that's it, you're ready to go.

L3:

Define the histogram parameters as above, but instead of declaring the histogram, declare a vector of histograms:
vector NEWHISTO;
TH1F *NEWHISTO_T; //also need a histogram pointer

No need to add anything to the constructor.
Add a clear command in the destructor:
NEWHISTO.clear();
Do the filling in either the Fill or DoneEvent functions (see above)
Add lines for the new histogram along side the ones already there.
//IN Fill (EVEN IF ONLY 1/EVENT, THIS IS WHERE THE HISTOGRAMS ARE
//CREATED! MUST BE DONE!)
if(index>=0)
{
(NEWHISTO.at(index)).Fill(l3class->Et());
...
}
if(index==-1)
{
//make strings for the labels:
string l_NEWHISTO = "l3class_NEWHISTO"; l_NEWHISTO+=toolname;
...
//make histograms:
NEWHISTO_T=new TH1F(l_NEWHISTO.c_str(),"TITLE",HISTObins,HISTOmin,HISTOmax);
...
//Set X axis labels:
NEWHISTO_T->GetXaxis()->SetTitle(HISTOaxis);NEWHISTO_T->GetXaxis()->CenterTitle();
..
//fill with this entry:
//IF THE IS MORE THAN 1/EVENT, DO THE FILL HERE, OTHERWISE SEE BELOW
NEWHISTO_T->Fill(l3class->accessor());
...
//add to vectors: (Do this even if you haven't filled yet
NEWHISTO.push_back(*NEWHISTO_T);
...
}
...
If there is only 1/event, in the DoneEvent, put:
for(int i=0;i<(int)Tools.size();i++)
{
( NEWHISTO.at(i) ).Fill( something );
...
}
In the Save function add (in the loop):
...
*NEWHISTO_T = NEWHISTO.at(i_tool);
NEWHISTO_T->Write();
...
In Draw:
along with the other string declarations, do one for your histogram:
string l_NEWHISTO ="l3class_NEWHISTO_"; l_NEWHISTO+=toolname;l_NEWHISTO+=";1";
As for L1L2, the drawing is done slightly differently if you have a full canvas, but it's handled the same here, so see above.
To Draw:
cl3class->cd(4);
TLegend *Leg4=new TLegend(.75,.75,.99,.99,"");
if(drawref)
{ TH1F *NEWHISTOref = (TH1F*) ref->Get(l_NEWHISTO.c_str());
//Make sure this tool exists in the reference
if(NEWHISTOref!=0)
{ DrawHisto(&(NEWHISTO.at(i_tool)),drawref,NEWHISTOref,Leg4,"NEWHISTO",THISFILE);}
else
{
DrawHisto(NEWHISTO_T,false,0,Leg3,"NEWHISTO",THISFILE);
cout<<"WARNING: in "< }
}
else
DrawHisto(&(NEWHISTO.at(i_tool)),drawref,0,Leg4,"NEWHISTO",THISFILE);
And that should be it

To Create a new histogram class:

The Best way to do this is just to copy one of the existing classes and modify to suit your needs. Here we'll outline how this is done. We'll make a skeleton histogram class to use a working trigsimcert class. To add plots see the above example of adding plots to an existing class.
1st copy one of the existing histogram classes (make sure you copy an appropriate class, remember L1L2 and L3 are different).

L1L2:
We'll call our new class Hl1new.C (say we copied from Hl1cal.C), and it plots stuff from L1TSCclass. Fix the comments at the top, and change the 1st 'ifndef command:
#ifndef L1TSCCLASS_H_
#include "trigsimcert/L1TSCclass.hpp"
#endif
Change the histogram constants be whatever you want (see the section on adding histograms to existing class). In the class definition change all 'Hl1cal' to 'Hl1new', and change the 'Fill' declaration to use the appropriate class:
void Fill(L1TSCclass *l1tscclass);
Replace the declared histograms as desired. Change the name of the constructor and modify the histogram initialization as desired (see above for details). Change the 'THISFILE' initialization to be the new name of the file. Go through the rest of the functions changing 'Hl1cal' to 'Hl1new' changing histogram names as needed.
In the Draw function:
Change the name of the canvas to something more appropriate (ie 'cl1tscclass'), and change the names of the histograms.
Now refer to the section on adding histograms to existing classes for details on customizing the histograms.
There is one more step, but it's common to both L1L2 and L3, so first we go through the procedure to make a L3 histogram class.
L3:

Similar to above, we'll make a class called Hl3new.C (copied from say Hl3ele.C) which plots stuff from L3TSCclass. Proceed as above, with the exception that instead of histogram declarations we have vectors (change there names as you the histograms) There are also histograms declared which end in '_T', these are used as 'temporary histograms', change their names as well. The rest of the code my look different from L1L2, but the procedure for changing is the same... go through chaning all 'l3ele' to 'l3new' and change the histogram/vector names where ever they appear (just look for anything in uppercase). There are also strings that will need to be changed, they begin with 'l_' and then the histogram name. Change these as needed.

For both L1L2 and L3:

The last step that is common to both L1L2 and L3 is adding the histogram class to the Plots macro. The procedure is the same from both L1L2 and L3 so we'll just work with the L1 example (Hl1new.C):
In Plots.h:
You need to add your class to all those lengthy lists of declarations and initializations etc (they're easy to spot, each is about 25 lines of the same thing). Be consistent in where you add your class. If it's an L1 class group it with the rest of the L1 stuff, and always put it in the same position in the lists.
In Class definition:
1st - add a '#include "HistoFill/Hl1new.C" '
2nd - add a 'L1TSCclass *l1tscclass;'
3rd - add a 'TClonesArray * fl1new;'
4th - add a 'Hl1new *hl1new;'
Nothing in the constructor...
In Init():
5th - add a 'l1tscclass = new L1TSCclass();'
6th - add a 'fl1new = new TClonesArray("L1TSCclass",1);'
//Note on 6: the 1 is the number of objects to start out with.
// ie for l1caltwrs there are 1280 towers, so this value is
// 1280.
7th - add a 'fChain->SetBranchAddress("L1TSCclass",&fl1new);'
//Note on 7: the string is the branch name, and is not always the name
// of the trigsimcert class. Particularly if there are two
// branches that use the same class (ie the L1CalTwr class)
8th - add a 'hl1new = new Hl1new();'
In ReInit():
9th - add a 'delete fl1new;'
10th - add a 'delete hl1new;'
DONE
In Plots.C:
First have your new class get filled (keep the same order as above).
Generally this works by:
for(int j=0;j<(fl1new->GetLast()+1);j++)
{
l1new = dynamic_cast (fl1new->At(j)) ;
hl1new->Fill(l1new);
}
If you know that there is only one instance of this object you can skip the loop.
Be sure to add a 'hl1new->DoneEvent(); ' alone with the rest (even if your DoneEvent function doesn't do anything). add a hl1new->Save(OUT) with the rest and a hl1new->Draw(REF,ps).
DONE
in loadstuff.C:
add the trigsimcert class you used:
#include "trigsimcert/src/L1TSCclass.cpp"
in loadstuff_linkdef.h:
add you trigsimcert class:
#pragma link C++ class L1TSCclass+;
And that's it. Your new histogram class should now be ready to plot!

back to top