// @(#)root/treeplayer:$Name: $:$Id: TTreePlayer.cxx,v 1.200 2005/09/03 02:21:32 pcanal Exp $
// Author: Rene Brun 12/01/96
/*************************************************************************
* Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
* All rights reserved. *
* *
* For the licensing terms see $ROOTSYS/LICENSE. *
* For the list of contributors see $ROOTSYS/README/CREDITS. *
*************************************************************************/
//////////////////////////////////////////////////////////////////////////
// //
// TTree //
// //
// a TTree object has a header with a name and a title.
// It consists of a list of independent branches (TBranch). Each branch
// has its own definition and list of buffers. Branch buffers may be
// automatically written to disk or kept in memory until the Tree attribute
// fMaxVirtualSize is reached.
// Variables of one branch are written to the same buffer.
// A branch buffer is automatically compressed if the file compression
// attribute is set (default).
//
// Branches may be written to different files (see TBranch::SetFile).
//
// The ROOT user can decide to make one single branch and serialize one
// object into one single I/O buffer or to make several branches.
// Making one single branch and one single buffer can be the right choice
// when one wants to process only a subset of all entries in the tree.
// (you know for example the list of entry numbers you want to process).
// Making several branches is particularly interesting in the data analysis
// phase, when one wants to histogram some attributes of an object (entry)
// without reading all the attributes.
//
/*
*/
//
//
// ==> TTree *tree = new TTree(name, title, maxvirtualsize)
// Creates a Tree with name and title. Maxvirtualsize is by default 64Mbytes,
// maxvirtualsize = 64000000(default) means: Keeps as many buffers in memory until
// the sum of all buffers is greater than 64 Megabyte. When this happens,
// memory buffers are written to disk and deleted until the size of all
// buffers is again below the threshold.
// maxvirtualsize = 0 means: keep only one buffer in memory.
//
// Various kinds of branches can be added to a tree:
// A - simple structures or list of variables. (may be for C or Fortran structures)
// B - any object (inheriting from TObject). (we expect this option be the most frequent)
// C - a ClonesArray. (a specialized object for collections of same class objects)
//
// ==> Case A
// ======
// TBranch *branch = tree->Branch(branchname,address, leaflist, bufsize)
// * address is the address of the first item of a structure
// * leaflist is the concatenation of all the variable names and types
// separated by a colon character :
// The variable name and the variable type are separated by a slash (/).
// The variable type may be 0,1 or 2 characters. If no type is given,
// the type of the variable is assumed to be the same as the previous
// variable. If the first variable does not have a type, it is assumed
// of type F by default. The list of currently supported types is given below:
// - C : a character string terminated by the 0 character
// - B : an 8 bit signed integer (Char_t)
// - b : an 8 bit unsigned integer (UChar_t)
// - S : a 16 bit signed integer (Short_t)
// - s : a 16 bit unsigned integer (UShort_t)
// - I : a 32 bit signed integer (Int_t)
// - i : a 32 bit unsigned integer (UInt_t)
// - F : a 32 bit floating point (Float_t)
// - D : a 64 bit floating point (Double_t)
//
// ==> Case B
// ======
// TBranch *branch = tree->Branch(branchname,className,object, bufsize, splitlevel)
// object is the address of a pointer to an existing object (derived from TObject).
// if splitlevel=1 (default), this branch will automatically be split
// into subbranches, with one subbranch for each data member or object
// of the object itself. In case the object member is a TClonesArray,
// the mechanism described in case C is applied to this array.
// if splitlevel=0, the object is serialized in the branch buffer.
//
// ==> Case C
// ======
// TBranch *branch = tree->Branch(branchname,clonesarray, bufsize, splitlevel)
// clonesarray is the address of a pointer to a TClonesArray.
// The TClonesArray is a direct access list of objects of the same class.
// For example, if the TClonesArray is an array of TTrack objects,
// this function will create one subbranch for each data member of
// the object TTrack.
//
//
// ==> branch->SetAddress(Void *address)
// In case of dynamic structures changing with each entry for example, one must
// redefine the branch address before filling the branch again.
// This is done via the TBranch::SetAddress member function.
//
// ==> tree->Fill()
// loops on all defined branches and for each branch invokes the Fill function.
//
// See also the class TNtuple (a simple Tree with only one branch)
//
/*
*/
//
// =============================================================================
//______________________________________________________________________________
//*-*-*-*-*-*-*A simple example with histograms and a tree*-*-*-*-*-*-*-*-*-*
//*-* ===========================================
//
// This program creates :
// - a one dimensional histogram
// - a two dimensional histogram
// - a profile histogram
// - a tree
//
// These objects are filled with some random numbers and saved on a file.
//
//-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//
// #include "TFile.h"
// #include "TH1.h"
// #include "TH2.h"
// #include "TProfile.h"
// #include "TRandom.h"
// #include "TTree.h"
//
//
// //______________________________________________________________________________
// main(int argc, char **argv)
// {
// // Create a new ROOT binary machine independent file.
// // Note that this file may contain any kind of ROOT objects, histograms,trees
// // pictures, graphics objects, detector geometries, tracks, events, etc..
// // This file is now becoming the current directory.
// TFile hfile("htree.root","RECREATE","Demo ROOT file with histograms & trees");
//
// // Create some histograms and a profile histogram
// TH1F *hpx = new TH1F("hpx","This is the px distribution",100,-4,4);
// TH2F *hpxpy = new TH2F("hpxpy","py ps px",40,-4,4,40,-4,4);
// TProfile *hprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20);
//
// // Define some simple structures
// typedef struct {Float_t x,y,z;} POINT;
// typedef struct {
// Int_t ntrack,nseg,nvertex;
// UInt_t flag;
// Float_t temperature;
// } EVENTN;
// static POINT point;
// static EVENTN eventn;
//
// // Create a ROOT Tree
// TTree *tree = new TTree("T","An example of ROOT tree with a few branches");
// tree->Branch("point",&point,"x:y:z");
// tree->Branch("eventn",&eventn,"ntrack/I:nseg:nvertex:flag/i:temperature/F");
// tree->Branch("hpx","TH1F",&hpx,128000,0);
//
// Float_t px,py,pz;
// static Float_t p[3];
//
// //--------------------Here we start a loop on 1000 events
// for ( Int_t i=0; i<1000; i++) {
// gRandom->Rannor(px,py);
// pz = px*px + py*py;
// Float_t random = gRandom->::Rndm(1);
//
// // Fill histograms
// hpx->Fill(px);
// hpxpy->Fill(px,py,1);
// hprof->Fill(px,pz,1);
//
// // Fill structures
// p[0] = px;
// p[1] = py;
// p[2] = pz;
// point.x = 10*(random-1);;
// point.y = 5*random;
// point.z = 20*random;
// eventn.ntrack = Int_t(100*random);
// eventn.nseg = Int_t(2*eventn.ntrack);
// eventn.nvertex = 1;
// eventn.flag = Int_t(random+0.5);
// eventn.temperature = 20+random;
//
// // Fill the tree. For each event, save the 2 structures and 3 objects
// // In this simple example, the objects hpx, hprof and hpxpy are slightly
// // different from event to event. We expect a big compression factor!
// tree->Fill();
// }
// //--------------End of the loop
//
// tree->Print();
//
// // Save all objects in this file
// hfile.Write();
//
// // Close the file. Note that this is automatically done when you leave
// // the application.
// hfile.Close();
//
// return 0;
// }
// //
//////////////////////////////////////////////////////////////////////////
#include <string.h>
#include <stdio.h>
#include "snprintf.h"
#include "Riostream.h"
#include "TTreePlayer.h"
#include "TROOT.h"
#include "TSystem.h"
#include "TFile.h"
#include "TEventList.h"
#include "TBranchObject.h"
#include "TBranchElement.h"
#include "TStreamerInfo.h"
#include "TStreamerElement.h"
#include "TLeafObject.h"
#include "TLeafF.h"
#include "TLeafD.h"
#include "TLeafC.h"
#include "TLeafB.h"
#include "TLeafI.h"
#include "TLeafS.h"
#include "TMath.h"
#include "TH2.h"
#include "TH3.h"
#include "TView.h"
#include "TPolyMarker.h"
#include "TPolyMarker3D.h"
#include "TDirectory.h"
#include "TClonesArray.h"
#include "TClass.h"
#include "TVirtualPad.h"
#include "TProfile.h"
#include "TProfile2D.h"
#include "TTreeFormula.h"
#include "TTreeFormulaManager.h"
#include "TStyle.h"
#include "Foption.h"
#include "TTreeResult.h"
#include "TTreeRow.h"
#include "TPrincipal.h"
#include "Api.h"
#include "TChain.h"
#include "TChainElement.h"
#include "TF1.h"
#include "TH1.h"
#include "TVirtualFitter.h"
#include "TEnv.h"
#include "THLimitsFinder.h"
#include "TSelectorDraw.h"
#include "TPluginManager.h"
#include "TObjString.h"
#include "TTreeProxyGenerator.h"
#include "TTreeIndex.h"
#include "TChainIndex.h"
R__EXTERN Foption_t Foption;
R__EXTERN TTree *gTree;
TVirtualFitter *tFitter=0;
extern void TreeUnbinnedFitLikelihood(Int_t &npar, Double_t *gin, Double_t &f, Double_t *u, Int_t flag);
ClassImp(TTreePlayer)
//______________________________________________________________________________
TTreePlayer::TTreePlayer()
{
//*-*-*-*-*-*-*-*-*-*-*Default Tree constructor*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* ========================
fTree = 0;
fScanFileName = 0;
fScanRedirect = kFALSE;
fSelectedRows = 0;
fDimension = 0;
fHistogram = 0;
fFormulaList = new TList();
fFormulaList->SetOwner(kTRUE);
fSelector = new TSelectorDraw();
fSelectorFromFile = 0;
fSelectorClass = 0;
fInput = new TList();
fInput->Add(new TNamed("varexp",""));
fInput->Add(new TNamed("selection",""));
fSelector->SetInputList(fInput);
gROOT->GetListOfCleanups()->Add(this);
}
//______________________________________________________________________________
TTreePlayer::~TTreePlayer()
{
//*-*-*-*-*-*-*-*-*-*-*Tree destructor*-*-*-*-*-*-*-*-*-*-*-*-*-*-*
//*-* =================
delete fFormulaList;
delete fSelector;
DeleteSelectorFromFile();
fInput->Delete();
delete fInput;
gROOT->GetListOfCleanups()->Remove(this);
}
//______________________________________________________________________________
TVirtualIndex *TTreePlayer::BuildIndex(const TTree *T, const char *majorname, const char *minorname)
{
TVirtualIndex *index;
if (dynamic_cast<const TChain*>(T)) {
index = new TChainIndex(T, majorname, minorname);
if (index->IsZombie()) {
delete index;
Error("BuildIndex", "Creating a TChainIndex unsuccessfull - switching to TTreeIndex");
}
else
return index;
}
return new TTreeIndex(T,majorname,minorname);
}
//______________________________________________________________________________
TTree *TTreePlayer::CopyTree(const char *selection, Option_t *, Long64_t nentries,
Long64_t firstentry)
{
// copy a Tree with selection
// make a clone of this Tree header.
// then copy the selected entries
//
// selection is a standard selection expression (see TTreePlayer::Draw)
// option is reserved for possible future use
// nentries is the number of entries to process (default is all)
// first is the first entry to process (default is 0)
//
// IMPORTANT: The copied tree stays connected with this tree until this tree
// is deleted. In particular, any changes in branch addresses
// in this tree are forwarded to the clone trees. Any changes
// made to the branch addresses of the copied trees are over-ridden
// anytime this tree changes its branch addresses.
// Once this tree is deleted, all the addresses of the copied tree
// are reset to their default values.
//
// The following example illustrates how to copy some events from the Tree
// generated in $ROOTSYS/test/Event
//
// gSystem->Load("libEvent");
// TFile f("Event.root");
// TTree *T = (TTree*)f.Get("T");
// Event *event = new Event();
// T->SetBranchAddress("event",&event);
// TFile f2("Event2.root","recreate");
// TTree *T2 = T->CopyTree("fNtrack<595");
// T2->Write();
// we make a copy of the tree header
TTree *tree = fTree->CloneTree(0);
if (tree == 0) return 0;
Long64_t entry,entryNumber;
nentries = GetEntriesToProcess(firstentry, nentries);
// Compile selection expression if there is one
TTreeFormula *select = 0; // no need to interfer with fSelect since we
// handle the loop explicitly below and can call
// UpdateFormulaLeaves ourselves.
if (strlen(selection)) {
select = new TTreeFormula("Selection",selection,fTree);
if (!select || !select->GetNdim()) { delete select; }
fFormulaList->Add(select);
}
//loop on the specified entries
Int_t tnumber = -1;
for (entry=firstentry;entry<firstentry+nentries;entry++) {
entryNumber = fTree->GetEntryNumber(entry);
if (entryNumber < 0) break;
Long64_t localEntry = fTree->LoadTree(entryNumber);
if (localEntry < 0) break;
if (tnumber != fTree->GetTreeNumber()) {
tnumber = fTree->GetTreeNumber();
if (select) select->UpdateFormulaLeaves();
}
if (select) {
Int_t ndata = select->GetNdata();
Bool_t keep = kFALSE;
for(Int_t current = 0; current<ndata && !keep; current++) {
keep |= (select->EvalInstance(current) != 0);
}
if (!keep) continue;
}
fTree->GetEntry(entryNumber);
tree->Fill();
}
fFormulaList->Clear();
return tree;
}
//______________________________________________________________________________
void TTreePlayer::DeleteSelectorFromFile()
{
// Delete any selector created by this object.
// The selector has been created using TSelector::GetSelector(file)
if (fSelectorFromFile && fSelectorClass) {
if (fSelectorClass->IsLoaded()) {
delete fSelectorFromFile;
}
}
fSelectorFromFile = 0;
fSelectorClass = 0;
}
//______________________________________________________________________________
Long64_t TTreePlayer::DrawScript(const char* wrapperPrefix,
const char *macrofilename, const char *cutfilename,
Option_t *option, Long64_t nentries, Long64_t firstentry)
{
// Draw the result of a C++ script
//
// macrofilename and optionally cutfilename are assumed to contain
// at least a method with the same name as the file. The method
// should return a value that can be automatically cast to
// respectively a double and a boolean.
//
// Both methods will be executed in a context such that the
// branch names can be used as C++ variables. This is
// accomplished by generating a TTreeProxy (see MakeProxy)
// and including the files in the proper location.
//
// If the branch name can not be used a proper C++ symbol name,
// it will be modified as follow:
// - white spaces are removed
// - if the leadind character is not a letter, an underscore is inserted
// - < and > are replace by underscores
// - * is replaced by st
// - & is replaced by rf
//
// If a cutfilename is specified, for each entry, we execute
// if (cutfilename()) htemp->Fill(macrofilename());
// If no cutfilename is specified, for each entry we execute
// htemp(macrofilename());
//
// The default for the histogram are the same as for
// TTreePlayer::DrawSelect
if (!macrofilename || strlen(macrofilename)==0) return 0;
TString aclicMode;
TString arguments;
TString io;
TString realcutname;
if (cutfilename && strlen(cutfilename))
realcutname = gSystem->SplitAclicMode(cutfilename, aclicMode, arguments, io);
// we ignore the aclicMode for the cutfilename!
TString realname = gSystem->SplitAclicMode(macrofilename, aclicMode, arguments, io);
TString selname = wrapperPrefix;
TTreeProxyGenerator gp(fTree,realname,realcutname,selname,option,3);
selname = gp.GetFileName();
if (aclicMode.Length()==0) {
Warning("DrawScript","TTreeProxy does not work in interpreted mode yet. The script will to compiled.");
aclicMode = "+";
}
selname.Append(aclicMode);
Info("DrawScript",Form("Will process tree/chain using %s",selname.Data()));
Long64_t result = fTree->Process(selname,option,nentries,firstentry);
// could delete the file selname+".h"
// However this would remove the optimization of avoiding a useless
// recompilation if the user ask for the same thing twice!
return result;
}
//______________________________________________________________________________
Long64_t TTreePlayer::DrawSelect(const char *varexp0, const char *selection, Option_t *option,Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*-*-*-*-*-*Draw expression varexp for specified entries-*-*-*-*-*
//*-* ============================================
//
// varexp is an expression of the general form
// - "e1" produces a 1-d histogram of expression "e1"
// - "e1:e2" produces a 2-d histogram (or profile) of "e1" versus "e2"
// - "e1:e2:e3" produces a 3-d scatter-plot of "e1" versus "e2" versus "e3"
// - "e1:e2:e3:e4" produces a 3-d scatter-plot of "e1" versus "e2" versus "e3"
// and "e4" mapped on the color number.
//
// Example:
// varexp = x simplest case: draw a 1-Dim distribution of column named x
// = sqrt(x) : draw distribution of sqrt(x)
// = x*y/z
// = y:sqrt(x) 2-Dim distribution of y versus sqrt(x)
// = px:py:pz:2.5*E produces a 3-d scatter-plot of px vs py ps pz
// and the color number of each marker will be 2.5*E.
// If the color number is negative it is set to 0.
// If the color number is greater than the current number of colors
// it is set to the highest color number.
// The default number of colors is 50.
// see TStyle::SetPalette for setting a new color palette.
//
// Note that the variables e1, e2 or e3 may contain a selection.
// example, if e1= x*(y<0), the value histogrammed will be x if y<0
// and will be 0 otherwise.
//
// selection is an expression with a combination of the columns.
// In a selection all the C++ operators are authorized.
// The value corresponding to the selection expression is used as a weight
// to fill the histogram.
// If the expression includes only boolean operations, the result
// is 0 or 1. If the result is 0, the histogram is not filled.
// In general, the expression may be of the form:
// value*(boolean expression)
// if boolean expression is true, the histogram is filled with
// a weight = value.
// Examples:
// selection1 = "x<y && sqrt(z)>3.2"
// selection2 = "(x+y)*(sqrt(z)>3.2"
// selection1 returns a weigth = 0 or 1
// selection2 returns a weight = x+y if sqrt(z)>3.2
// returns a weight = 0 otherwise.
//
// option is the drawing option
// see TH1::Draw for the list of all drawing options.
// If option contains the string "goff", no graphics is generated.
//
// nentries is the number of entries to process (default is all)
// first is the first entry to process (default is 0)
//
// Drawing expressions using arrays and array elements
// ===================================================
// Let assumes, a leaf fMatrix, on the branch fEvent, which is a 3 by 3 array,
// or a TClonesArray.
// In a TTree::Draw expression you can now access fMatrix using the following
// syntaxes:
//
// String passed What is used for each entry of the tree
//
// "fMatrix" the 9 elements of fMatrix
// "fMatrix[][]" the 9 elements of fMatrix
// "fMatrix[2][2]" only the elements fMatrix[2][2]
// "fMatrix[1]" the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2]
// "fMatrix[1][]" the 3 elements fMatrix[1][0], fMatrix[1][1] and fMatrix[1][2]
// "fMatrix[][0]" the 3 elements fMatrix[0][0], fMatrix[1][0] and fMatrix[2][0]
//
// "fEvent.fMatrix...." same as "fMatrix..." (unless there is more than one leaf named fMatrix!).
//
// In summary, if a specific index is not specified for a dimension, TTree::Draw
// will loop through all the indices along this dimension. Leaving off the
// last (right most) dimension of specifying then with the two characters '[]'
// is equivalent. For variable size arrays (and TClonesArray) the range
// of the first dimension is recalculated for each entry of the tree.
// You can also specify the index as an expression of any other variables from the
// tree.
//
// TTree::Draw also now properly handling operations involving 2 or more arrays.
//
// Let assume a second matrix fResults[5][2], here are a sample of some
// of the possible combinations, the number of elements they produce and
// the loop used:
//
// expression element(s) Loop
//
// "fMatrix[2][1] - fResults[5][2]" one no loop
// "fMatrix[2][] - fResults[5][2]" three on 2nd dim fMatrix
// "fMatrix[2][] - fResults[5][]" two on both 2nd dimensions
// "fMatrix[][2] - fResults[][1]" three on both 1st dimensions
// "fMatrix[][2] - fResults[][]" six on both 1st and 2nd dimensions of
// fResults
// "fMatrix[][2] - fResults[3][]" two on 1st dim of fMatrix and 2nd of
// fResults (at the same time)
// "fMatrix[][] - fResults[][]" six on 1st dim then on 2nd dim
//
// "fMatrix[][fResult[][]]" 30 on 1st dim of fMatrix then on both
// dimensions of fResults. The value
// if fResults[j][k] is used as the second
// index of fMatrix.
//
// In summary, TTree::Draw loops through all un-specified dimensions. To
// figure out the range of each loop, we match each unspecified dimension
// from left to right (ignoring ALL dimensions for which an index has been
// specified), in the equivalent loop matched dimensions use the same index
// and are restricted to the smallest range (of only the matched dimensions).
// When involving variable arrays, the range can of course be different
// for each entry of the tree.
//
// So the loop equivalent to "fMatrix[][2] - fResults[3][]" is:
//
// for (Int_t i0; i0 < min(3,2); i0++) {
// use the value of (fMatrix[i0][2] - fMatrix[3][i0])
// }
//
// So the loop equivalent to "fMatrix[][2] - fResults[][]" is:
//
// for (Int_t i0; i0 < min(3,5); i0++) {
// for (Int_t i1; i1 < 2; i1++) {
// use the value of (fMatrix[i0][2] - fMatrix[i0][i1])
// }
// }
//
// So the loop equivalent to "fMatrix[][] - fResults[][]" is:
//
// for (Int_t i0; i0 < min(3,5); i0++) {
// for (Int_t i1; i1 < min(3,2); i1++) {
// use the value of (fMatrix[i0][i1] - fResults[i0][i1])
// }
// }
//
// So the loop equivalent to "fMatrix[][fResults[][]]" is:
//
// for (Int_t i0; i0 < 3; i0++) {
// for (Int_t j2; j2 < 5; j2++) {
// for (Int_t j3; j3 < 2; j3++) {
// i1 = fResults[j2][j3];
// use the value of fMatrix[i0][i1]
// }
// }
//
// Saving the result of Draw to an histogram
// =========================================
// By default the temporary histogram created is called htemp.
// One can retrieve a pointer to this histogram with:
// TH1F *htemp = (TH1F*)gPad->GetPrimitive("htemp");
//
// If varexp0 contains >>hnew (following the variable(s) name(s),
// the new histogram created is called hnew and it is kept in the current
// directory (and also the current pad).
// Example:
// tree.Draw("sqrt(x)>>hsqrt","y>0")
// will draw sqrt(x) and save the histogram as "hsqrt" in the current
// directory. To retrieve it do:
// TH1F *hsqrt = (TH1F*)gDirectory->Get("hsqrt");
//
// The binning information is taken from the environment variables
//
// Hist.Binning.?D.?
//
// In addition, the name of the histogram can be followed by up to 9
// numbers between '(' and ')', where the numbers describe the
// following:
//
// 1 - bins in x-direction
// 2 - lower limit in x-direction
// 3 - upper limit in x-direction
// 4-6 same for y-direction
// 7-9 same for z-direction
//
// When a new binning is used the new value will become the default.
// Values can be skipped.
// Example:
// tree.Draw("sqrt(x)>>hsqrt(500,10,20)"
// // plot sqrt(x) between 10 and 20 using 500 bins
// tree.Draw("sqrt(x):sin(y)>>hsqrt(100,10,60,50,.1,.5)"
// // plot sqrt(x) against sin(y)
// // 100 bins in x-direction; lower limit on x-axis is 10; upper limit is 60
// // 50 bins in y-direction; lower limit on y-axis is .1; upper limit is .5
//
// By default, the specified histogram is reset.
// To continue to append data to an existing histogram, use "+" in front
// of the histogram name.
// A '+' in front of the histogram name is ignored, when the name is followed by
// binning information as described in the previous paragraph.
// tree.Draw("sqrt(x)>>+hsqrt","y>0")
// will not reset hsqrt, but will continue filling.
// This works for 1-D, 2-D and 3-D histograms.
//
// Accessing collection objects
// ============================
//
// TTree::Draw default's handling of collections is to assume that any
// request on a collection pertain to it content. For example, if fTracks
// is a collection of Track objects, the following:
// tree->Draw("event.fTracks.fPx");
// will plot the value of fPx for each Track objects inside the collection.
// Also
// tree->Draw("event.fTracks.size()");
// would plot the result of the member function Track::size() for each
// Track object inside the collection.
// To access information about the collection itself, TTree::Draw support
// the '@' notation. If a variable which points to a collection is prefixed
// or postfixed with '@', the next part of the expression will pertain to
// the collection object. For example:
// tree->Draw("event.@fTracks.size()");
// will plot the size of the collection refered to by fTracks (i.e the number
// of Track objects).
//
// Special functions and variables
// ===============================
//
// Entry$: A TTree::Draw formula can use the special variable Entry$
// to access the entry number being read. For example to draw every
// other entry use:
// tree.Draw("myvar","Entry$%2==0");
//
// Entry$ : return the current entry number (== TTree::GetReadEntry())
// Entries$ : return the total number of entries (== TTree::GetEntries())
// Length$ : return the total number of element of this formula for this
// entry (==TTreeFormula::GetNdata())
// Iteration$: return the current iteration over this formula for this
// entry (i.e. varies from 0 to Length$).
//
// Length$(formula): return the total number of element of the formula given as a
// parameter.
// Sum$(formula): return the sum of the value of the elements of the formula given
// as a parameter. For eaxmple the mean for all the elements in
// one entry can be calculated with:
// Sum$(formula)/Length$(formula)
//
// Alt$(primary,alternate) : return the value of "primary" if it is available
// for the current iteration otherwise return the value of "alternate".
// For example, with arr1[3] and arr2[2]
// tree->Draw("arr1+Alt$(arr2,0)");
// will draw arr[0]+arr2[0] ; arr[1]+arr2[1] and arr[1]+0
// Or with a variable size array arr3
// tree->Draw("Alt$(arr3[0],0)+Alt$(arr3[1],0)+Alt$(arr3[2],0)");
// will draw the sum arr3 for the index 0 to min(2,actual_size_of_arr3-1)
// As a comparison
// tree->Draw("arr3[0]+arr3[1]+arr3[2]");
// will draw the sum arr3 for the index 0 to 2 only if the
// actual_size_of_arr3 is greater or equal to 3.
// Note that the array in 'primary' is flatened/linearilized thus using
// Alt$ with multi-dimensional arrays of different dimensions in unlikely
// to yield the expected results. To visualize a bit more what elements
// would be matched by TTree::Draw, TTree::Scan can be used:
// tree->Scan("arr1:Alt$(arr2,0)");
// will print on one line the value of arr1 and (arr2,0) that will be
// matched by
// tree->Draw("arr1-Alt$(arr2,0)");
//
// Drawing a user function accessing the TTree data directly
// =========================================================
//
// If the formula contains a file name, TTree::MakeProxy will be used
// to load and execute this file. In particular it will draw the
// result of a function with the same name as the file. The function
// will be executed in a context where the name of the branches can
// be used as a C++ variable.
//
// For example draw px using the file hsimple.root (generated by the
// hsimple.C tutorial), we need a file named hsimple.cxx:
//
// double hsimple() {
// return px;
// }
//
// MakeProxy can then be used indirectly via the TTree::Draw interface
// as follow:
// new TFile("hsimple.root")
// ntuple->Draw("hsimple.cxx");
//
// A more complete example is available in the tutorials directory:
// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
// which reimplement the selector found in h1analysis.C
//
// The main features of this facility are:
//
// * on-demand loading of branches
// * ability to use the 'branchname' as if it was a data member
// * protection against array out-of-bound
// * ability to use the branch data as object (when the user code is available)
//
// See TTree::MakeProxy for more details.
//
// Making a Profile histogram
// ==========================
// In case of a 2-Dim expression, one can generate a TProfile histogram
// instead of a TH2F histogram by specyfying option=prof or option=profs.
// The option=prof is automatically selected in case of y:x>>pf
// where pf is an existing TProfile histogram.
//
// Making a 2D Profile histogram
// ==========================
// In case of a 3-Dim expression, one can generate a TProfile2D histogram
// instead of a TH3F histogram by specyfying option=prof or option=profs.
// The option=prof is automatically selected in case of z:y:x>>pf
// where pf is an existing TProfile2D histogram.
//
// Saving the result of Draw to a TEventList
// =========================================
// TTree::Draw can be used to fill a TEventList object (list of entry numbers)
// instead of histogramming one variable.
// If varexp0 has the form >>elist , a TEventList object named "elist"
// is created in the current directory. elist will contain the list
// of entry numbers satisfying the current selection.
// Example:
// tree.Draw(">>yplus","y>0")
// will create a TEventList object named "yplus" in the current directory.
// In an interactive session, one can type (after TTree::Draw)
// yplus.Print("all")
// to print the list of entry numbers in the list.
//
// By default, the specified entry list is reset.
// To continue to append data to an existing list, use "+" in front
// of the list name;
// tree.Draw(">>+yplus","y>0")
// will not reset yplus, but will enter the selected entries at the end
// of the existing list.
//
// Using a TEventList as Input
// ===========================
// Once a TEventList object has been generated, it can be used as input
// for TTree::Draw. Use TTree::SetEventList to set the current event list
// Example:
// TEventList *elist = (TEventList*)gDirectory->Get("yplus");
// tree->SetEventList(elist);
// tree->Draw("py");
//
// If arrays are used in the selection critera, the event entered in the
// list are all the event that have at least one element of the array that
// satisfy the selection.
// Example:
// tree.Draw(">>pyplus","fTracks.fPy>0");
// tree->SetEventList(pyplus);
// tree->Draw("fTracks.fPy");
// will draw the fPy of ALL tracks in event with at least one track with
// a positive fPy.
//
// To select only the elements that did match the original selection
// use TEventList::SetReapplyCut.
// Example:
// tree.Draw(">>pyplus","fTracks.fPy>0");
// pyplus->SetReapplyCut(kTRUE);
// tree->SetEventList(pyplus);
// tree->Draw("fTracks.fPy");
// will draw the fPy of only the tracks that have a positive fPy.
//
// Note: Use tree->SetEventList(0) if you do not want use the list as input.
//
// How to obtain more info from TTree::Draw
// ========================================
//
// Once TTree::Draw has been called, it is possible to access useful
// information still stored in the TTree object via the following functions:
// -GetSelectedRows() // return the number of entries accepted by the
// //selection expression. In case where no selection
// //was specified, returns the number of entries processed.
// -GetV1() //returns a pointer to the float array of V1
// -GetV2() //returns a pointer to the float array of V2
// -GetV3() //returns a pointer to the float array of V3
// -GetW() //returns a pointer to the double array of Weights
// //where weight equal the result of the selection expression.
// where V1,V2,V3 correspond to the expressions in
// TTree::Draw("V1:V2:V3",selection);
//
// Example:
// Root > ntuple->Draw("py:px","pz>4");
// Root > TGraph *gr = new TGraph(ntuple->GetSelectedRows(),
// ntuple->GetV2(), ntuple->GetV1());
// Root > gr->Draw("ap"); //draw graph in current pad
// creates a TGraph object with a number of points corresponding to the
// number of entries selected by the expression "pz>4", the x points of the graph
// being the px values of the Tree and the y points the py values.
//
// Important note: By default TTree::Draw creates the arrays obtained
// with GetV1, GetV2, GetV3, GetW with a length corresponding to the
// parameter fEstimate. By default fEstimate=10000 and can be modified
// via TTree::SetEstimate. A possible recipee is to do
// tree->SetEstimate(tree->GetEntries());
// You must call SetEstimate if the expected number of selected rows
// is greater than 10000.
//
// You can use the option "goff" to turn off the graphics output
// of TTree::Draw in the above example.
//
// Automatic interface to TTree::Draw via the TTreeViewer
// ======================================================
//
// A complete graphical interface to this function is implemented
// in the class TTreeViewer.
// To start the TTreeViewer, three possibilities:
// - select TTree context menu item "StartViewer"
// - type the command "TTreeViewer TV(treeName)"
// - execute statement "tree->StartViewer();"
//
if (fTree->GetEntriesFriend() == 0) return 0;
// Let's see if we have a filename as arguments instead of
// a TTreeFormula expression.
TString possibleFilename = varexp0;
Ssiz_t dot_pos = possibleFilename.Last('.');
if ( dot_pos != kNPOS
&& possibleFilename.Index("Alt$")<0 && possibleFilename.Index("Entries$")<0
&& possibleFilename.Index("Length$")<0 && possibleFilename.Index("Entry$")<0
&& possibleFilename.Index("Iteration$")<0
&& gSystem->IsFileInIncludePath(possibleFilename.Data())) {
if (selection && strlen(selection) && !gSystem->IsFileInIncludePath(selection)) {
Error("DrawSelect",
"Drawing using a C++ file currently requires that both the expression and the selection are files\n\t\"%s\" is not a file",
selection);
return 0;
}
return DrawScript("generatedSel",varexp0,selection,option,nentries,firstentry);
} else {
possibleFilename = selection;
if (possibleFilename.Index("Alt$")<0 && possibleFilename.Index("Entries$")<0
&& possibleFilename.Index("Length$")<0 && possibleFilename.Index("Entry$")<0
&& possibleFilename.Index("Iteration$")<0
&& gSystem->IsFileInIncludePath(possibleFilename.Data())) {
Error("DrawSelect",
"Drawing using a C++ file currently requires that both the expression and the selection are files\n\t\"%s\" is not a file",
varexp0);
return 0;
}
}
Long64_t oldEstimate = fTree->GetEstimate();
TEventList *elist = fTree->GetEventList();
TNamed *cvarexp = (TNamed*)fInput->FindObject("varexp");
TNamed *cselection = (TNamed*)fInput->FindObject("selection");
if (cvarexp) cvarexp->SetTitle(varexp0);
if (cselection) cselection->SetTitle(selection);
// Do not process more than fMaxEntryLoop entries
if (nentries > fTree->GetMaxEntryLoop()) nentries = fTree->GetMaxEntryLoop();
// invoke the selector
Long64_t nrows = Process(fSelector,option,nentries,firstentry);
fSelectedRows = nrows;
fDimension = fSelector->GetDimension();
//*-* an Event List
if (fDimension <= 0) {
fTree->SetEstimate(oldEstimate);
if (fSelector->GetCleanElist()) {
// We are in the case where the input list was reset!
fTree->SetEventList(elist);
delete fSelector->GetObject();
}
return nrows;
}
// Draw generated histogram
Int_t drawflag = fSelector->GetDrawFlag();
Int_t action = fSelector->GetAction();
TString opt = option;
opt.ToLower();
Bool_t draw = kFALSE;
if (!drawflag && !opt.Contains("goff")) draw = kTRUE;
fHistogram = (TH1*)fSelector->GetObject();
if (!nrows && drawflag && !opt.Contains("same")) {
if (gPad) gPad->Clear();
return 0;
}
//*-*- 1-D distribution
if (fDimension == 1) {
if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("X");
if (draw) fHistogram->Draw(option);
//*-*- 2-D distribution
} else if (fDimension == 2) {
if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Y");
if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("X");
if (action == 4) {
if (draw) fHistogram->Draw(option);
} else {
Bool_t graph = kFALSE;
Int_t l = opt.Length();
if (l == 0 || opt == "same") graph = kTRUE;
if (opt.Contains("p") || opt.Contains("*") || opt.Contains("l")) graph = kTRUE;
if (opt.Contains("surf") || opt.Contains("lego") || opt.Contains("cont")) graph = kFALSE;
if (opt.Contains("col") || opt.Contains("hist") || opt.Contains("scat")) graph = kFALSE;
if (!graph) {
if (draw) fHistogram->Draw(option);
} else {
if (fSelector->GetOldHistogram() && draw) fHistogram->Draw(option);
}
}
//*-*- 3-D distribution
} else if (fDimension == 3) {
if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Z");
if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("Y");
if (fSelector->GetVar3()->IsInteger()) fHistogram->LabelsDeflate("X");
if (action == 23) {
if (draw) fHistogram->Draw(option);
} else {
Int_t noscat = opt.Length();
if (opt.Contains("same")) noscat -= 4;
if (noscat) {
if (draw) fHistogram->Draw(option);
} else {
if (fSelector->GetOldHistogram() && draw) fHistogram->Draw(option);
}
}
//*-*- 4-D distribution
} else if (fDimension == 4) {
if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Z");
if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("Y");
if (fSelector->GetVar3()->IsInteger()) fHistogram->LabelsDeflate("X");
if (draw) fHistogram->Draw(option);
Int_t ncolors = gStyle->GetNumberOfColors();
TObjArray *pms = (TObjArray*)fHistogram->GetListOfFunctions()->FindObject("polymarkers");
for (Int_t col=0;col<ncolors;col++) {
if (!pms) continue;
TPolyMarker3D *pm3d = (TPolyMarker3D*)pms->UncheckedAt(col);
if (draw) pm3d->Draw();
}
}
return fSelectedRows;
}
//______________________________________________________________________________
Long64_t TTreePlayer::Fit(const char *formula ,const char *varexp, const char *selection,Option_t *option ,Option_t *goption,Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*-*-*-*Fit a projected item(s) from a Tree*-*-*-*-*-*-*-*-*-*
//*-* ======================================
//
// formula is a TF1 expression.
//
// See TTree::Draw for explanations of the other parameters.
//
// By default the temporary histogram created is called htemp.
// If varexp contains >>hnew , the new histogram created is called hnew
// and it is kept in the current directory.
// Example:
// tree.Fit("pol4","sqrt(x)>>hsqrt","y>0")
// will fit sqrt(x) and save the histogram as "hsqrt" in the current
// directory.
//
Int_t nch = strlen(option) + 10;
char *opt = new char[nch];
if (option) sprintf(opt,"%s",option);
else strcpy(opt,"goff");
Long64_t nsel = DrawSelect(varexp,selection,opt,nentries,firstentry);
delete [] opt;
if (fHistogram) {
fHistogram->Fit(formula,option,goption);
}
return nsel;
}
//______________________________________________________________________________
Long64_t TTreePlayer::GetEntriesToProcess(Long64_t firstentry, Long64_t nentries) const
{
// return the number of entries to be processed
// this function checks that nentries is not bigger than the number
// of entries in the Tree or in the associated TEventlist
Long64_t lastentry = firstentry + nentries - 1;
if (lastentry > fTree->GetEntriesFriend()-1) {
lastentry = fTree->GetEntriesFriend() - 1;
nentries = lastentry - firstentry + 1;
}
TEventList *elist = fTree->GetEventList();
if (elist && elist->GetN() < nentries) nentries = elist->GetN();
return nentries;
}
//______________________________________________________________________________
const char *TTreePlayer::GetNameByIndex(TString &varexp, Int_t *index,Int_t colindex)
{
//*-*-*-*-*-*-*-*-*Return name corresponding to colindex in varexp*-*-*-*-*-*
//*-* ===============================================
//
// varexp is a string of names separated by :
// index is an array with pointers to the start of name[i] in varexp
//
Int_t i1,n;
static TString column;
if (colindex<0 ) return "";
i1 = index[colindex] + 1;
n = index[colindex+1] - i1;
column = varexp(i1,n);
// return (const char*)Form((const char*)column);
return column.Data();
}
//______________________________________________________________________________
Int_t TTreePlayer::MakeClass(const char *classname, const char *option)
{
// Generate skeleton analysis class for this Tree
//
// The following files are produced: classname.h and classname.C
// If classname is 0, classname will be called "nameoftree.
//
// The generated code in classname.h includes the following:
// - Identification of the original Tree and Input file name
// - Definition of analysis class (data and functions)
// - the following class functions:
// - constructor (connecting by default the Tree file)
// - GetEntry(Long64_t entry)
// - Init(TTree *tree) to initialize a new TTree
// - Show(Long64_t entry) to read and Dump entry
//
// The generated code in classname.C includes only the main
// analysis function Loop.
//
// To use this function:
// - connect your Tree file (eg: TFile f("myfile.root");)
// - T->MakeClass("MyClass");
// where T is the name of the Tree in file myfile.root
// and MyClass.h, MyClass.C the name of the files created by this function.
// In a ROOT session, you can do:
// root > .L MyClass.C
// root > MyClass t
// root > t.GetEntry(12); // Fill t data members with entry number 12
// root > t.Show(); // Show values of entry 12
// root > t.Show(16); // Read and show values of entry 16
// root > t.Loop(); // Loop on all entries
TString opt = option;
opt.ToLower();
// Connect output files
char *thead = new char[256];
if (!classname) classname = fTree->GetName();
sprintf(thead,"%s.h",classname);
FILE *fp = fopen(thead,"w");
if (!fp) {
printf("Cannot open output file:%s\n",thead);
delete [] thead;
return 3;
}
char *tcimp = new char[256];
sprintf(tcimp,"%s.C",classname);
FILE *fpc = fopen(tcimp,"w");
if (!fpc) {
printf("Cannot open output file:%s\n",tcimp);
delete [] thead;
delete [] tcimp;
return 3;
}
char *treefile = new char[1000];
if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile())
strcpy(treefile,fTree->GetDirectory()->GetFile()->GetName());
else strcpy(treefile,"Memory Directory");
// In the case of a chain, the GetDirectory information usually does
// pertain to the Chain itself but to the currently loaded tree.
// So we can not rely on it.
Bool_t ischain = fTree->InheritsFrom("TChain");
Bool_t isHbook = fTree->InheritsFrom("THbookTree");
if (isHbook) strcpy(treefile,fTree->GetTitle());
//======================Generate classname.h=====================
// Print header
TObjArray *leaves = fTree->GetListOfLeaves();
Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
TDatime td;
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"// This class has been automatically generated on\n");
fprintf(fp,"// %s by ROOT version %s\n",td.AsString(),gROOT->GetVersion());
if (!ischain) {
fprintf(fp,"// from TTree %s/%s\n",fTree->GetName(),fTree->GetTitle());
fprintf(fp,"// found on file: %s\n",treefile);
} else {
fprintf(fp,"// from TChain %s/%s\n",fTree->GetName(),fTree->GetTitle());
}
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"\n");
fprintf(fp,"#ifndef %s_h\n",classname);
fprintf(fp,"#define %s_h\n",classname);
fprintf(fp,"\n");
fprintf(fp,"#include <TROOT.h>\n");
fprintf(fp,"#include <TChain.h>\n");
fprintf(fp,"#include <TFile.h>\n");
if (isHbook) fprintf(fp,"#include <THbookFile.h>\n");
if (opt.Contains("selector")) fprintf(fp,"#include <TSelector.h>\n");
// First loop on all leaves to generate dimension declarations
Int_t len, lenb,l;
char blen[128];
char *bname;
Int_t *leaflen = new Int_t[nleaves];
TObjArray *leafs = new TObjArray(nleaves);
for (l=0;l<nleaves;l++) {
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
leafs->AddAt(new TObjString(leaf->GetName()),l);
leaflen[l] = leaf->GetMaximum();
}
if (ischain) {
// In case of a chain, one must find the maximum dimension of each leaf
// One must be careful and not assume that all Trees in the chain
// have the same leaves and in the same order!
TChain *chain = (TChain*)fTree;
Int_t ntrees = chain->GetNtrees();
for (Int_t file=0;file<ntrees;file++) {
Long64_t first = chain->GetTreeOffset()[file];
chain->LoadTree(first);
for (l=0;l<nleaves;l++) {
TObjString *obj = (TObjString*)leafs->At(l);
TLeaf *leaf = chain->GetLeaf(obj->GetName());
if (leaf) {
leaflen[l] = TMath::Max(leaflen[l],leaf->GetMaximum());
}
}
}
chain->LoadTree(0);
}
leaves = fTree->GetListOfLeaves();
for (l=0;l<nleaves;l++) {
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
strcpy(blen,leaf->GetName());
bname = &blen[0];
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
lenb = strlen(blen);
if (blen[lenb-1] == '_') {
blen[lenb-1] = 0;
len = leaflen[l];
if (len <= 0) len = 1;
fprintf(fp," const Int_t kMax%s = %d;\n",blen,len);
}
}
delete [] leaflen;
leafs->Delete();
delete leafs;
// second loop on all leaves to generate type declarations
fprintf(fp,"\n");
if (opt.Contains("selector")) {
fprintf(fp,"class %s : public TSelector {\n",classname);
fprintf(fp,"public :\n");
fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n");
} else {
fprintf(fp,"class %s {\n",classname);
fprintf(fp,"public :\n");
fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n");
fprintf(fp," Int_t fCurrent; //!current Tree number in a TChain\n");
}
fprintf(fp,"\n // Declaration of leave types\n");
TLeaf *leafcount;
TLeafObject *leafobj;
TBranchElement *bre=0;
const char *headOK = " ";
const char *headcom = " //";
const char *head;
char branchname[128];
char aprefix[128];
TObjArray branches(100);
TObjArray mustInit(100);
Int_t *leafStatus = new Int_t[nleaves];
for (l=0;l<nleaves;l++) {
Int_t kmax = 0;
head = headOK;
leafStatus[l] = 0;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen(); if (len<=0) len = 1;
leafcount =leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
branchname[0] = 0;
strcpy(branchname,branch->GetName());
strcpy(aprefix,branch->GetName());
if (!branches.FindObject(branch)) branches.Add(branch);
else leafStatus[l] = 1;
if ( branch->GetNleaves() > 1) {
// More than one leaf for the branch we need to distinguish them
strcat(branchname,".");
strcat(branchname,leaf->GetTitle());
if (leafcount) {
// remove any dimension in title
char *dim = (char*)strstr(branchname,"["); if (dim) dim[0] = 0;
}
} else {
strcpy(branchname,branch->GetName());
}
char *twodim = (char*)strstr(leaf->GetTitle(),"][");
bname = branchname;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
if (branch->IsA() == TBranchObject::Class()) {
if (branch->GetListOfBranches()->GetEntriesFast()) {leafStatus[l] = 1; continue;}
leafobj = (TLeafObject*)leaf;
if (!leafobj->GetClass()) {leafStatus[l] = 1; head = headcom;}
fprintf(fp,"%s%-15s *%s;\n",head,leafobj->GetTypeName(), leafobj->GetName());
if (leafStatus[l] == 0) mustInit.Add(leafobj);
continue;
}
if (leafcount) {
len = leafcount->GetMaximum();
if (len<=0) len = 1;
strcpy(blen,leafcount->GetName());
bname = &blen[0];
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
lenb = strlen(blen);
if (blen[lenb-1] == '_') {blen[lenb-1] = 0; kmax = 1;}
else sprintf(blen,"%d",len);
}
if (branch->IsA() == TBranchElement::Class()) {
bre = (TBranchElement*)branch;
if (bre->GetType() != 3 && bre->GetType() != 4
&& bre->GetStreamerType() <= 0 && bre->GetListOfBranches()->GetEntriesFast()) {
leafStatus[l] = 0;
}
if (bre->GetType() == 3 || bre->GetType() == 4) {
fprintf(fp," %-15s %s_;\n","Int_t", branchname);
continue;
}
if (bre->IsBranchFolder()) {
fprintf(fp," %-15s *%s;\n",bre->GetClassName(), branchname);
mustInit.Add(bre);
continue;
} else {
if (branch->GetListOfBranches()->GetEntriesFast()) {leafStatus[l] = 1;}
}
if (bre->GetStreamerType() < 0) {
if (branch->GetListOfBranches()->GetEntriesFast()) {
fprintf(fp,"%s%-15s *%s;\n",headcom,bre->GetClassName(), bre->GetName());
} else {
fprintf(fp,"%s%-15s *%s;\n",head,bre->GetClassName(), bre->GetName());
mustInit.Add(bre);
}
continue;
}
if (bre->GetStreamerType() == 0) {
if (!gROOT->GetClass(bre->GetClassName())->GetClassInfo()) {leafStatus[l] = 1; head = headcom;}
fprintf(fp,"%s%-15s *%s;\n",head,bre->GetClassName(), bre->GetName());
if (leafStatus[l] == 0) mustInit.Add(bre);
continue;
}
if (bre->GetStreamerType() > 60) {
TClass *cle = gROOT->GetClass(bre->GetClassName());
if (!cle) {leafStatus[l] = 1; continue;}
if (bre->GetStreamerType() == 66) leafStatus[l] = 0;
char brename[256];
strcpy(brename,bre->GetName());
char *bren = brename;
char *adot = strrchr(bren,'.');
if (adot) bren = adot+1;
char *brack = strchr(bren,'[');
if (brack) *brack = 0;
TStreamerElement *elem = (TStreamerElement*)cle->GetStreamerInfo()->GetElements()->FindObject(bren);
if (elem) {
if (elem->IsA() == TStreamerBase::Class()) {leafStatus[l] = 1; continue;}
if (!gROOT->GetClass(elem->GetTypeName())) {leafStatus[l] = 1; continue;}
if (!gROOT->GetClass(elem->GetTypeName())->GetClassInfo()) {leafStatus[l] = 1; head = headcom;}
if (leafcount) fprintf(fp,"%s%-15s %s[kMax%s];\n",head,elem->GetTypeName(), branchname,blen);
else fprintf(fp,"%s%-15s %s;\n",head,elem->GetTypeName(), branchname);
} else {
if (!gROOT->GetClass(bre->GetClassName())->GetClassInfo()) {leafStatus[l] = 1; head = headcom;}
fprintf(fp,"%s%-15s %s;\n",head,bre->GetClassName(), branchname);
}
continue;
}
}
if (strlen(leaf->GetTypeName()) == 0) {leafStatus[l] = 1; continue;}
if (leafcount) {
//len = leafcount->GetMaximum();
//strcpy(blen,leafcount->GetName());
//bname = &blen[0];
//while (*bname) {if (*bname == '.') *bname='_'; bname++;}
//lenb = strlen(blen);
//Int_t kmax = 0;
//if (blen[lenb-1] == '_') {blen[lenb-1] = 0; kmax = 1;}
//else sprintf(blen,"%d",len);
const char *stars = " ";
if (bre && bre->GetBranchCount2()) {
stars = "*";
}
// Dimensions can be in the branchname for a split Object with a fix length C array.
// Theses dimensions HAVE TO be placed after the dimension explicited by leafcount
char *dimensions = 0;
char *dimInName = (char*) strstr(branchname,"[");
if ( twodim || dimInName ) {
int dimlen = 0;
if (dimInName) dimlen += strlen(dimInName) + 1;
if (twodim) dimlen += strlen(twodim) + 1;
dimensions = new char[dimlen];
if (dimInName) {
strcpy(dimensions,dimInName);
dimInName[0] = 0; // terminate branchname before the array dimensions.
} else dimensions[0] = 0;
if (twodim) strcat(dimensions,(char*)(twodim+1));
}
const char* leafcountName = leafcount->GetName();
char b2len[128];
if (bre && bre->GetBranchCount2()) {
TLeaf * l2 = (TLeaf*)bre->GetBranchCount2()->GetListOfLeaves()->At(0);
strcpy(b2len,l2->GetName());
bname = &b2len[0];
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
leafcountName = b2len;
}
if (dimensions) {
if (kmax) fprintf(fp," %-14s %s%s[kMax%s]%s; //[%s]\n",leaf->GetTypeName(), stars,
branchname,blen,dimensions,leafcountName);
else fprintf(fp," %-14s %s%s[%d]%s; //[%s]\n",leaf->GetTypeName(), stars,
branchname,len,dimensions,leafcountName);
delete dimensions;
} else {
if (kmax) fprintf(fp," %-14s %s%s[kMax%s]; //[%s]\n",leaf->GetTypeName(), stars, branchname,blen,leafcountName);
else fprintf(fp," %-14s %s%s[%d]; //[%s]\n",leaf->GetTypeName(), stars, branchname,len,leafcountName);
}
} else {
if (strstr(branchname,"[")) len = 1;
if (len < 2) fprintf(fp," %-15s %s;\n",leaf->GetTypeName(), branchname);
else {
if (twodim) fprintf(fp," %-15s %s%s;\n",leaf->GetTypeName(), branchname,(char*)strstr(leaf->GetTitle(),"["));
else fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
}
}
}
// generate list of branches
fprintf(fp,"\n");
fprintf(fp," // List of branches\n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
//if (strlen(leaf->GetTypeName()) == 0) continue;
leafcount =leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
strcpy(branchname,branch->GetName());
if ( branch->GetNleaves() <= 1 ) {
// Code duplicated around line 1362
if (branch->IsA() != TBranchObject::Class()) {
if (!leafcount) {
TBranch *mother = branch->GetMother();
const char* ltitle = leaf->GetTitle();
if (mother && mother!=branch) {
strcpy(branchname,mother->GetName());
if (branchname[strlen(branchname)-1]!='.') {
strcat(branchname,".");
}
if (strncmp(branchname,ltitle,strlen(branchname))==0) {
branchname[0] = 0;
}
} else {
branchname[0] = 0;
}
strcat(branchname,ltitle);
}
}
}
bname = branchname;
char *twodim = (char*)strstr(bname,"[");
if (twodim) *twodim = 0;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
fprintf(fp," TBranch *b_%s; //!\n",branchname);
}
// generate class member functions prototypes
if (opt.Contains("selector")) {
fprintf(fp,"\n");
fprintf(fp," %s(TTree *tree=0) { }\n",classname) ;
fprintf(fp," virtual ~%s() { }\n",classname);
fprintf(fp," virtual Int_t Version() const {return 1;}\n");
fprintf(fp," virtual void Begin(TTree *tree);\n");
fprintf(fp," virtual void SlaveBegin(TTree *tree);\n");
fprintf(fp," virtual void Init(TTree *tree);\n");
fprintf(fp," virtual Bool_t Notify();\n");
fprintf(fp," virtual Bool_t Process(Long64_t entry);\n");
fprintf(fp," virtual void SetOption(const char *option) { fOption = option; }\n");
fprintf(fp," virtual void SetObject(TObject *obj) { fObject = obj; }\n");
fprintf(fp," virtual void SetInputList(TList *input) {fInput = input;}\n");
fprintf(fp," virtual TList *GetOutputList() const { return fOutput; }\n");
fprintf(fp," virtual void SlaveTerminate();\n");
fprintf(fp," virtual void Terminate();\n\n");
fprintf(fp," ClassDef(%s,0);\n",classname);
fprintf(fp,"};\n");
fprintf(fp,"\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
} else {
fprintf(fp,"\n");
fprintf(fp," %s(TTree *tree=0);\n",classname);
fprintf(fp," virtual ~%s();\n",classname);
fprintf(fp," virtual Int_t Cut(Long64_t entry);\n");
fprintf(fp," virtual Int_t GetEntry(Long64_t entry);\n");
fprintf(fp," virtual Long64_t LoadTree(Long64_t entry);\n");
fprintf(fp," virtual void Init(TTree *tree);\n");
fprintf(fp," virtual void Loop();\n");
fprintf(fp," virtual Bool_t Notify();\n");
fprintf(fp," virtual void Show(Long64_t entry = -1);\n");
fprintf(fp,"};\n");
fprintf(fp,"\n");
fprintf(fp,"#endif\n");
fprintf(fp,"\n");
}
// generate code for class constructor
fprintf(fp,"#ifdef %s_cxx\n",classname);
if (!opt.Contains("selector")) {
fprintf(fp,"%s::%s(TTree *tree)\n",classname,classname);
fprintf(fp,"{\n");
fprintf(fp,"// if parameter tree is not specified (or zero), connect the file\n");
fprintf(fp,"// used to generate this class and read the Tree.\n");
fprintf(fp," if (tree == 0) {\n");
if (ischain) {
fprintf(fp,"\n#ifdef SINGLE_TREE\n");
fprintf(fp," // The following code should be used if you want this class to access\n");
fprintf(fp," // a single tree instead of a chain\n");
}
if (isHbook) {
fprintf(fp," THbookFile *f = (THbookFile*)gROOT->GetListOfBrowsables()->FindObject(\"%s\");\n",treefile);
fprintf(fp," if (!f) {\n");
fprintf(fp," f = new THbookFile(\"%s\");\n",treefile);
fprintf(fp," }\n");
Int_t hid;
sscanf(fTree->GetName(),"h%d",&hid);
fprintf(fp," tree = (TTree*)f->Get(%d);\n\n",hid);
} else {
fprintf(fp," TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(\"%s\");\n",treefile);
fprintf(fp," if (!f) {\n");
fprintf(fp," f = new TFile(\"%s\");\n",treefile);
if (gDirectory != gFile) {
fprintf(fp," f->cd(\"%s\");\n",gDirectory->GetPath());
}
fprintf(fp," }\n");
fprintf(fp," tree = (TTree*)gDirectory->Get(\"%s\");\n\n",fTree->GetName());
}
if (ischain) {
fprintf(fp,"#else // SINGLE_TREE\n\n");
fprintf(fp," // The following code should be used if you want this class to access a chain\n");
fprintf(fp," // of trees.\n");
fprintf(fp," TChain * chain = new TChain(\"%s\",\"%s\");\n",
fTree->GetName(),fTree->GetTitle());
TIter next(((TChain*)fTree)->GetListOfFiles());
TChainElement *element;
while ((element = (TChainElement*)next())) {
fprintf(fp," chain->Add(\"%s/%s\");\n",element->GetTitle(),element->GetName());
}
fprintf(fp," tree = chain;\n");
fprintf(fp,"#endif // SINGLE_TREE\n\n");
}
fprintf(fp," }\n");
fprintf(fp," Init(tree);\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
}
// generate code for class destructor()
if (!opt.Contains("selector")) {
fprintf(fp,"%s::~%s()\n",classname,classname);
fprintf(fp,"{\n");
fprintf(fp," if (!fChain) return;\n");
if (isHbook) {
//fprintf(fp," delete fChain->GetCurrentFile();\n");
} else {
fprintf(fp," delete fChain->GetCurrentFile();\n");
}
fprintf(fp,"}\n");
fprintf(fp,"\n");
}
// generate code for class member function GetEntry()
if (!opt.Contains("selector")) {
fprintf(fp,"Int_t %s::GetEntry(Long64_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp,"// Read contents of entry.\n");
fprintf(fp," if (!fChain) return 0;\n");
fprintf(fp," return fChain->GetEntry(entry);\n");
fprintf(fp,"}\n");
}
// generate code for class member function LoadTree()
if (!opt.Contains("selector")) {
fprintf(fp,"Long64_t %s::LoadTree(Long64_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp,"// Set the environment to read one entry\n");
fprintf(fp," if (!fChain) return -5;\n");
fprintf(fp," Long64_t centry = fChain->LoadTree(entry);\n");
fprintf(fp," if (centry < 0) return centry;\n");
fprintf(fp," if (fChain->IsA() != TChain::Class()) return centry;\n");
fprintf(fp," TChain *chain = (TChain*)fChain;\n");
fprintf(fp," if (chain->GetTreeNumber() != fCurrent) {\n");
fprintf(fp," fCurrent = chain->GetTreeNumber();\n");
fprintf(fp," Notify();\n");
fprintf(fp," }\n");
fprintf(fp," return centry;\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
}
// generate code for class member function Init(), first pass = get branch pointer
fprintf(fp,"void %s::Init(TTree *tree)\n",classname);
fprintf(fp,"{\n");
fprintf(fp," // The Init() function is called when the selector needs to initialize\n"
" // a new tree or chain. Typically here the branch addresses of the tree\n"
" // will be set. It is normaly not necessary to make changes to the\n"
" // generated code, but the routine can be extended by the user if needed.\n"
" // Init() will be called many times when running with PROOF.\n\n");
if (mustInit.Last()) {
TIter next(&mustInit);
TObject *obj;
fprintf(fp," // Set object pointer\n");
while( (obj = next()) ) {
if (obj->InheritsFrom(TBranch::Class())) {
strcpy(branchname,((TBranch*)obj)->GetName() );
} else if (obj->InheritsFrom(TLeaf::Class())) {
strcpy(branchname,((TLeaf*)obj)->GetName() );
}
bname = branchname;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
fprintf(fp," %s = 0;\n",branchname );
}
}
fprintf(fp," // Set branch addresses\n");
fprintf(fp," if (tree == 0) return;\n");
fprintf(fp," fChain = tree;\n");
if (!opt.Contains("selector")) fprintf(fp," fCurrent = -1;\n");
fprintf(fp," fChain->SetMakeClass(1);\n");
fprintf(fp,"\n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount =leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
strcpy(aprefix,branch->GetName());
if ( branch->GetNleaves() > 1) {
// More than one leaf for the branch we need to distinguish them
strcpy(branchname,branch->GetName());
strcat(branchname,".");
strcat(branchname,leaf->GetTitle());
if (leafcount) {
// remove any dimension in title
char *dim = (char*)strstr(branchname,"["); if (dim) dim[0] = 0;
}
} else {
strcpy(branchname,branch->GetName());
if (branch->IsA() == TBranchElement::Class()) {
bre = (TBranchElement*)branch;
if (bre->GetType() == 3 || bre->GetType()==4) strcat(branchname,"_");
}
}
bname = branchname;
char *brak = strstr(branchname,"["); if (brak) *brak = 0;
char *twodim = (char*)strstr(bname,"["); if (twodim) *twodim = 0;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
if (branch->IsA() == TBranchObject::Class()) {
if (branch->GetListOfBranches()->GetEntriesFast()) {
fprintf(fp," fChain->SetBranchAddress(\"%s\",(void*)-1);\n",branch->GetName());
continue;
}
strcpy(branchname,branch->GetName());
}
if (branch->IsA() == TBranchElement::Class()) {
if (((TBranchElement*)branch)->GetType() == 3) len =1;
if (((TBranchElement*)branch)->GetType() == 4) len =1;
}
if (leafcount) len = leafcount->GetMaximum()+1;
if (len > 1) fprintf(fp," fChain->SetBranchAddress(\"%s\",%s);\n",branch->GetName(),branchname);
else fprintf(fp," fChain->SetBranchAddress(\"%s\",&%s);\n",branch->GetName(),branchname);
}
//must call Notify in case of MakeClass
if (!opt.Contains("selector")) {
fprintf(fp," Notify();\n");
}
fprintf(fp,"}\n");
fprintf(fp,"\n");
// generate code for class member function Notify()
fprintf(fp,"Bool_t %s::Notify()\n",classname);
fprintf(fp,"{\n");
fprintf(fp," // The Notify() function is called when a new file is opened. This\n"
" // can be either for a new TTree in a TChain or when when a new TTree\n"
" // is started when using PROOF. Typically here the branch pointers\n"
" // will be retrieved. It is normaly not necessary to make changes\n"
" // to the generated code, but the routine can be extended by the\n"
" // user if needed.\n\n");
fprintf(fp," // Get branch pointers\n");
for (l=0;l<nleaves;l++) {
if (leafStatus[l]) continue;
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount = leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
strcpy(branchname,branch->GetName());
if ( branch->GetNleaves() <= 1 ) {
// Code duplicated around line 1120
if (branch->IsA() != TBranchObject::Class()) {
if (!leafcount) {
TBranch *mother = branch->GetMother();
const char* ltitle = leaf->GetTitle();
if (mother && mother!=branch) {
strcpy(branchname,mother->GetName());
if (branchname[strlen(branchname)-1]!='.') {
strcat(branchname,".");
}
if (strncmp(branchname,ltitle,strlen(branchname))==0) {
branchname[0] = 0;
}
} else {
branchname[0] = 0;
}
strcat(branchname,ltitle);
}
}
}
bname = branchname;
char *twodim = (char*)strstr(bname,"["); if (twodim) *twodim = 0;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
if (branch->IsA() == TBranchObject::Class()) {
if (branch->GetListOfBranches()->GetEntriesFast()) {
fprintf(fp," b_%s = fChain->GetBranch(\"%s\");\n",branchname,branch->GetName());
continue;
}
strcpy(branchname,branch->GetName());
}
fprintf(fp," b_%s = fChain->GetBranch(\"%s\");\n",branchname,branch->GetName());
}
fprintf(fp,"\n return kTRUE;\n");
fprintf(fp,"}\n");
fprintf(fp,"\n");
// generate code for class member function Show()
if (!opt.Contains("selector")) {
fprintf(fp,"void %s::Show(Long64_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp,"// Print contents of entry.\n");
fprintf(fp,"// If entry is not specified, print current entry\n");
fprintf(fp," if (!fChain) return;\n");
fprintf(fp," fChain->Show(entry);\n");
fprintf(fp,"}\n");
}
// generate code for class member function Cut()
if (!opt.Contains("selector")) {
fprintf(fp,"Int_t %s::Cut(Long64_t entry)\n",classname);
fprintf(fp,"{\n");
fprintf(fp,"// This function may be called from Loop.\n");
fprintf(fp,"// returns 1 if entry is accepted.\n");
fprintf(fp,"// returns -1 otherwise.\n");
fprintf(fp," return 1;\n");
fprintf(fp,"}\n");
}
fprintf(fp,"#endif // #ifdef %s_cxx\n",classname);
//======================Generate classname.C=====================
if (!opt.Contains("selector")) {
// generate code for class member function Loop()
fprintf(fpc,"#define %s_cxx\n",classname);
fprintf(fpc,"#include \"%s\"\n",thead);
fprintf(fpc,"#include <TH2.h>\n");
fprintf(fpc,"#include <TStyle.h>\n");
fprintf(fpc,"#include <TCanvas.h>\n");
fprintf(fpc,"\n");
fprintf(fpc,"void %s::Loop()\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc,"// In a ROOT session, you can do:\n");
fprintf(fpc,"// Root > .L %s.C\n",classname);
fprintf(fpc,"// Root > %s t\n",classname);
fprintf(fpc,"// Root > t.GetEntry(12); // Fill t data members with entry number 12\n");
fprintf(fpc,"// Root > t.Show(); // Show values of entry 12\n");
fprintf(fpc,"// Root > t.Show(16); // Read and show values of entry 16\n");
fprintf(fpc,"// Root > t.Loop(); // Loop on all entries\n");
fprintf(fpc,"//\n");
fprintf(fpc,"\n// This is the loop skeleton where:\n");
fprintf(fpc,"// jentry is the global entry number in the chain\n");
fprintf(fpc,"// ientry is the entry number in the current Tree\n");
fprintf(fpc,"// Note that the argument to GetEntry must be:\n");
fprintf(fpc,"// jentry for TChain::GetEntry\n");
fprintf(fpc,"// ientry for TTree::GetEntry and TBranch::GetEntry\n");
fprintf(fpc,"//\n");
fprintf(fpc,"// To read only selected branches, Insert statements like:\n");
fprintf(fpc,"// METHOD1:\n");
fprintf(fpc,"// fChain->SetBranchStatus(\"*\",0); // disable all branches\n");
fprintf(fpc,"// fChain->SetBranchStatus(\"branchname\",1); // activate branchname\n");
fprintf(fpc,"// METHOD2: replace line\n");
fprintf(fpc,"// fChain->GetEntry(jentry); //read all branches\n");
fprintf(fpc,"//by b_branchname->GetEntry(ientry); //read only this branch\n");
fprintf(fpc," if (fChain == 0) return;\n");
fprintf(fpc,"\n Long64_t nentries = fChain->GetEntriesFast();\n");
fprintf(fpc,"\n Long64_t nbytes = 0, nb = 0;\n");
fprintf(fpc," for (Long64_t jentry=0; jentry<nentries;jentry++) {\n");
fprintf(fpc," Long64_t ientry = LoadTree(jentry);\n");
fprintf(fpc," if (ientry < 0) break;\n");
fprintf(fpc," nb = fChain->GetEntry(jentry); nbytes += nb;\n");
fprintf(fpc," // if (Cut(ientry) < 0) continue;\n");
fprintf(fpc," }\n");
fprintf(fpc,"}\n");
}
if (opt.Contains("selector")) {
// generate usage comments and list of includes
fprintf(fpc,"#define %s_cxx\n",classname);
fprintf(fpc,"// The class definition in %s.h has been generated automatically\n",classname);
fprintf(fpc,"// by the ROOT utility TTree::MakeSelector(). This class is derived\n");
fprintf(fpc,"// from the ROOT class TSelector. For more information on the TSelector\n"
"// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.\n\n");
fprintf(fpc,"// The following methods are defined in this file:\n");
fprintf(fpc,"// Begin(): called everytime a loop on the tree starts,\n");
fprintf(fpc,"// a convenient place to create your histograms.\n");
fprintf(fpc,"// SlaveBegin(): called after Begin(), when on PROOF called only on the\n"
"// slave servers.\n");
fprintf(fpc,"// Process(): called for each event, in this function you decide what\n");
fprintf(fpc,"// to read and fill your histograms.\n");
fprintf(fpc,"// SlaveTerminate: called at the end of the loop on the tree, when on PROOF\n"
"// called only on the slave servers.\n");
fprintf(fpc,"// Terminate(): called at the end of the loop on the tree,\n");
fprintf(fpc,"// a convenient place to draw/fit your histograms.\n");
fprintf(fpc,"//\n");
fprintf(fpc,"// To use this file, try the following session on your Tree T:\n");
fprintf(fpc,"//\n");
fprintf(fpc,"// Root > T->Process(\"%s.C\")\n",classname);
fprintf(fpc,"// Root > T->Process(\"%s.C\",\"some options\")\n",classname);
fprintf(fpc,"// Root > T->Process(\"%s.C+\")\n",classname);
fprintf(fpc,"//\n\n");
fprintf(fpc,"#include \"%s\"\n",thead);
fprintf(fpc,"#include <TH2.h>\n");
fprintf(fpc,"#include <TStyle.h>\n");
fprintf(fpc,"\n");
// generate code for class member function Begin
fprintf(fpc,"\n");
fprintf(fpc,"void %s::Begin(TTree *tree)\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc," // The Begin() function is called at the start of the query.\n");
fprintf(fpc," // When running with PROOF Begin() is only called on the client.\n");
fprintf(fpc," // The tree argument is deprecated (on PROOF 0 is passed).\n");
fprintf(fpc,"\n");
fprintf(fpc," TString option = GetOption();\n");
fprintf(fpc,"\n");
fprintf(fpc,"}\n");
// generate code for class member function SlaveBegin
fprintf(fpc,"\n");
fprintf(fpc,"void %s::SlaveBegin(TTree *tree)\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc," // The SlaveBegin() function is called after the Begin() function.\n");
fprintf(fpc," // When running with PROOF SlaveBegin() is called on each slave server.\n");
fprintf(fpc," // The tree argument is deprecated (on PROOF 0 is passed).\n");
fprintf(fpc,"\n");
fprintf(fpc," Init(tree);\n");
fprintf(fpc,"\n");
fprintf(fpc," TString option = GetOption();\n");
fprintf(fpc,"\n");
fprintf(fpc,"}\n");
// generate code for class member function Process
fprintf(fpc,"\n");
fprintf(fpc,"Bool_t %s::Process(Long64_t entry)\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc," // The Process() function is called for each entry in the tree (or possibly\n"
" // keyed object in the case of PROOF) to be processed. The entry argument\n"
" // specifies which entry in the currently loaded tree is to be processed.\n"
" // It can be passed to either TTree::GetEntry() or TBranch::GetEntry()\n"
" // to read either all or the required parts of the data. When processing\n"
" // keyed objects with PROOF, the object is already loaded and is available\n"
" // via the fObject pointer.\n"
" //\n"
" // This function should contain the \"body\" of the analysis. It can contain\n"
" // simple or elaborate selection criteria, run algorithms on the data\n"
" // of the event and typically fill histograms.\n\n");
fprintf(fpc," // WARNING when a selector is used with a TChain, you must use\n");
fprintf(fpc," // the pointer to the current TTree to call GetEntry(entry).\n");
fprintf(fpc," // The entry is always the local entry number in the current tree.\n");
fprintf(fpc," // Assuming that fChain is the pointer to the TChain being processed,\n");
fprintf(fpc," // use fChain->GetTree()->GetEntry(entry).\n");
fprintf(fpc,"\n");
fprintf(fpc,"\n");
fprintf(fpc," return kTRUE;\n");
fprintf(fpc,"}\n");
// generate code for class member function SlaveTerminate
fprintf(fpc,"\n");
fprintf(fpc,"void %s::SlaveTerminate()\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc," // The SlaveTerminate() function is called after all entries or objects\n"
" // have been processed. When running with PROOF SlaveTerminate() is called\n"
" // on each slave server.");
fprintf(fpc,"\n");
fprintf(fpc,"\n");
fprintf(fpc,"}\n");
// generate code for class member function Terminate
fprintf(fpc,"\n");
fprintf(fpc,"void %s::Terminate()\n",classname);
fprintf(fpc,"{\n");
fprintf(fpc," // The Terminate() function is the last function to be called during\n"
" // a query. It always runs on the client, it can be used to present\n"
" // the results graphically or save the results to file.");
fprintf(fpc,"\n");
fprintf(fpc,"\n");
fprintf(fpc,"}\n");
}
Info("MakeClass","Files: %s and %s generated from TTree: %s",thead,tcimp,fTree->GetName());
delete [] leafStatus;
delete [] thead;
delete [] tcimp;
delete [] treefile;
fclose(fp);
fclose(fpc);
return 0;
}
//______________________________________________________________________________
Int_t TTreePlayer::MakeCode(const char *filename)
{
// Generate skeleton function for this Tree
//
// The function code is written on filename.
// If filename is 0, filename will be called nameoftree.C
//
// The generated code includes the following:
// - Identification of the original Tree and Input file name
// - Connection of the Tree file
// - Declaration of Tree variables
// - Setting of branches addresses
// - A skeleton for the entry loop
//
// To use this function:
// - connect your Tree file (eg: TFile f("myfile.root");)
// - T->MakeCode("anal.C");
// where T is the name of the Tree in file myfile.root
// and anal.C the name of the file created by this function.
//
// NOTE: Since the implementation of this function, a new and better
// function TTree::MakeClass() has been developped.
// Connect output file
char *tfile = new char[1000];
if (filename) strcpy(tfile,filename);
else sprintf(tfile,"%s.C",fTree->GetName());
FILE *fp = fopen(tfile,"w");
if (!fp) {
printf("Cannot open output file:%s\n",tfile);
return 3;
}
char *treefile = new char[1000];
if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile())
strcpy(treefile,fTree->GetDirectory()->GetFile()->GetName());
else strcpy(treefile,"Memory Directory");
// In the case of a chain, the GetDirectory information usually does
// pertain to the Chain itself but to the currently loaded tree.
// So we can not rely on it.
Bool_t ischain = fTree->InheritsFrom("TChain");
// Print header
TObjArray *leaves = fTree->GetListOfLeaves();
Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
TDatime td;
fprintf(fp,"{\n");
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"// This file has been automatically generated \n");
fprintf(fp,"// (%s by ROOT version%s)\n",td.AsString(),gROOT->GetVersion());
if (!ischain) {
fprintf(fp,"// from TTree %s/%s\n",fTree->GetName(),fTree->GetTitle());
fprintf(fp,"// found on file: %s\n",treefile);
} else {
fprintf(fp,"// from TChain %s/%s\n",fTree->GetName(),fTree->GetTitle());
}
fprintf(fp,"//////////////////////////////////////////////////////////\n");
fprintf(fp,"\n");
fprintf(fp,"\n");
// Reset and file connect
fprintf(fp,"//Reset ROOT and connect tree file\n");
fprintf(fp," gROOT->Reset();\n");
if (ischain) {
fprintf(fp,"\n#ifdef SINGLE_TREE\n");
fprintf(fp," // The following code should be used if you want this code to access\n");
fprintf(fp," // a single tree instead of a chain\n");
}
fprintf(fp," TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(\"%s\");\n",treefile);
fprintf(fp," if (!f) {\n");
fprintf(fp," f = new TFile(\"%s\");\n",treefile);
if (gDirectory != gFile) {
fprintf(fp," f->cd(\"%s\");\n",gDirectory->GetPath());
}
fprintf(fp," }\n");
fprintf(fp," TTree *%s = (TTree*)gDirectory->Get(\"%s\");\n\n",fTree->GetName(),fTree->GetName());
if (ischain) {
fprintf(fp,"#else // SINGLE_TREE\n\n");
fprintf(fp," // The following code should be used if you want this code to access a chain\n");
fprintf(fp," // of trees.\n");
fprintf(fp," TChain *%s = new TChain(\"%s\",\"%s\");\n",
fTree->GetName(),fTree->GetName(),fTree->GetTitle());
TIter next(((TChain*)fTree)->GetListOfFiles());
TChainElement *element;
while ((element = (TChainElement*)next())) {
fprintf(fp," %s->Add(\"%s/%s\");\n",fTree->GetName(),element->GetTitle(),element->GetName());
}
fprintf(fp,"#endif // SINGLE_TREE\n\n");
}
// First loop on all leaves to generate type declarations
fprintf(fp,"//Declaration of leaves types\n");
Int_t len, l;
TLeaf *leafcount;
TLeafObject *leafobj;
char *bname;
const char *headOK = " ";
const char *headcom = " //";
const char *head;
char branchname[128];
for (l=0;l<nleaves;l++) {
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount =leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
if (branch->GetListOfBranches()->GetEntriesFast() > 0) continue;
if ( branch->GetNleaves() > 1) {
// More than one leaf for the branch we need to distinguish them
strcpy(branchname,branch->GetName());
strcat(branchname,".");
strcat(branchname,leaf->GetTitle());
if (leafcount) {
// remove any dimension in title
char *dim = (char*)strstr(branchname,"[");
dim[0] = 0;
}
} else {
if (leafcount) strcpy(branchname,branch->GetName());
else strcpy(branchname,leaf->GetTitle());
}
char *twodim = (char*)strstr(leaf->GetTitle(),"][");
bname = branchname;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
if (branch->IsA() == TBranchObject::Class()) {
leafobj = (TLeafObject*)leaf;
if (leafobj->GetClass()) head = headOK;
else head = headcom;
fprintf(fp,"%s%-15s *%s = 0;\n",head,leafobj->GetTypeName(), leafobj->GetName());
continue;
}
if (leafcount) {
len = leafcount->GetMaximum();
// Dimensions can be in the branchname for a split Object with a fix length C array.
// Theses dimensions HAVE TO be placed after the dimension explicited by leafcount
char *dimInName = (char*) strstr(branchname,"[");
char *dimensions = 0;
if ( twodim || dimInName ) {
int dimlen = 0;
if (dimInName) dimlen += strlen(dimInName) + 1;
if (twodim) dimlen += strlen(twodim) + 1;
dimensions = new char[dimlen];
if (dimInName) {
strcpy(dimensions,dimInName);
dimInName[0] = 0; // terminate branchname before the array dimensions.
} else dimensions[0] = 0;
if (twodim) strcat(dimensions,(char*)(twodim+1));
}
if (dimensions) {
fprintf(fp," %-15s %s[%d]%s;\n",leaf->GetTypeName(), branchname,len,dimensions);
delete dimensions;
} else {
fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
}
} else {
if (strstr(branchname,"[")) len = 1;
if (len < 2) fprintf(fp," %-15s %s;\n",leaf->GetTypeName(), branchname);
else fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
}
}
// Second loop on all leaves to set the corresponding branch address
fprintf(fp,"\n // Set branch addresses.\n");
for (l=0;l<nleaves;l++) {
TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
len = leaf->GetLen();
leafcount =leaf->GetLeafCount();
TBranch *branch = leaf->GetBranch();
if ( branch->GetNleaves() > 1) {
// More than one leaf for the branch we need to distinguish them
strcpy(branchname,branch->GetName());
strcat(branchname,".");
strcat(branchname,leaf->GetTitle());
if (leafcount) {
// remove any dimension in title
char *dim = (char*)strstr(branchname,"[");
dim[0] = 0;
}
} else {
if (leafcount) strcpy(branchname,branch->GetName());
else strcpy(branchname,leaf->GetTitle());
}
bname = branchname;
while (*bname) {
if (*bname == '.') *bname='_';
if (*bname == ':') *bname='_';
if (*bname == '<') *bname='_';
if (*bname == '>') *bname='_';
bname++;
}
char *brak = strstr(branchname,"[");
if (brak) *brak = 0;
head = headOK;
if (branch->IsA() == TBranchObject::Class()) {
strcpy(branchname,branch->GetName());
leafobj = (TLeafObject*)leaf;
if (!leafobj->GetClass()) head = headcom;
}
if (leafcount) len = leafcount->GetMaximum()+1;
if (len > 1 || brak) fprintf(fp,"%s%s->SetBranchAddress(\"%s\",%s);\n",head,fTree->GetName(),branch->GetName(),branchname);
else fprintf(fp,"%s%s->SetBranchAddress(\"%s\",&%s);\n",head,fTree->GetName(),branch->GetName(),branchname);
}
//Generate instructions to make the loop on entries
fprintf(fp,"\n// This is the loop skeleton\n");
fprintf(fp,"// To read only selected branches, Insert statements like:\n");
fprintf(fp,"// %s->SetBranchStatus(\"*\",0); // disable all branches\n",fTree->GetName());
fprintf(fp,"// %s->SetBranchStatus(\"branchname\",1); // activate branchname\n",GetName());
fprintf(fp,"\n Long64_t nentries = %s->GetEntries();\n",fTree->GetName());
fprintf(fp,"\n Long64_t nbytes = 0;\n");
fprintf(fp,"// for (Long64_t i=0; i<nentries;i++) {\n");
fprintf(fp,"// nbytes += %s->GetEntry(i);\n",fTree->GetName());
fprintf(fp,"// }\n");
fprintf(fp,"}\n");
printf("Macro: %s generated from Tree: %s\n",tfile,fTree->GetName());
delete [] tfile;
delete [] treefile;
fclose(fp);
return 0;
}
//______________________________________________________________________________
Int_t TTreePlayer::MakeProxy(const char *proxyClassname,
const char *macrofilename, const char *cutfilename,
const char *option, Int_t maxUnrolling)
{
// Generate a skeleton analysis class for this Tree using TBranchProxy.
// TBranchProxy is the base of a class hierarchy implementing an
// indirect access to the content of the branches of a TTree.
//
// "proxyClassname" is expected to be of the form:
// [path/]fileprefix
// The skeleton will then be generated in the file:
// fileprefix.h
// located in the current directory or in 'path/' if it is specified.
// The class generated will be named 'fileprefix'
//
// "macrofilename" and optionally "cutfilename" are expected to point
// to source file which will be included in by the generated skeletong.
// Method of the same name as the file(minus the extension and path)
// will be called by the generated skeleton's Process method as follow:
// [if (cutfilename())] htemp->Fill(macrofilename());
//
// "option" can be used select some of the optional features during
// the code generation. The possible options are:
// nohist : indicates that the generated ProcessFill should not
// fill the histogram.
//
// 'maxUnrolling' controls how deep in the class hierachy does the
// system 'unroll' class that are not split. 'unrolling' a class
// will allow direct access to its data members a class (this
// emulates the behavior of TTreeFormula).
//
// The main features of this skeleton are:
//
// * on-demand loading of branches
// * ability to use the 'branchname' as if it was a data member
// * protection against array out-of-bound
// * ability to use the branch data as object (when the user code is available)
//
// For example with Event.root, if
// Double_t somepx = fTracks.fPx[2];
// is executed by one of the method of the skeleton,
// somepx will updated with the current value of fPx of the 3rd track.
//
// Both macrofilename and the optional cutfilename are expected to be
// the name of source files which contain at least a free standing
// function with the signature:
// x_t macrofilename(); // i.e function with the same name as the file
// and
// y_t cutfilename(); // i.e function with the same name as the file
//
// x_t and y_t needs to be types that can convert respectively to a double
// and a bool (because the skeleton uses:
// if (cutfilename()) htemp->Fill(macrofilename());
//
// This 2 functions are run in a context such that the branch names are
// available as local variables of the correct (read-only) type.
//
// Note that if you use the same 'variable' twice, it is more efficient
// to 'cache' the value. For example
// Int_t n = fEventNumber; // Read fEventNumber
// if (n<10 || n>10) { ... }
// is more efficient than
// if (fEventNumber<10 || fEventNumber>10)
//
// Also, optionally, the generated selector will also call methods named
// macrofilename_methodname in each of 6 main selector methods if the method
// macrofilename_methodname exist (Where macrofilename is stripped of its
// extension).
//
// Concretely, with the script named h1analysisProxy.C,
//
// The method calls the method (if it exist)
// Begin -> h1analysisProxy_Begin
// SlaveBegin -> h1analysisProxy_SlaveBegin
// Notify -> h1analysisProxy_Notify
// Process -> h1analysisProxy_Process
// SlaveTerminate -> h1analysisProxy_SlaveTerminate
// Terminate -> h1analysisProxy_Terminate
//
// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
// it is included before the declaration of the proxy class. This can
// be used in particular to insure that the include files needed by
// the macro file are properly loaded.
//
// The default histogram is accessible via the variable named 'htemp'.
//
// If the library of the classes describing the data in the branch is
// loaded, the skeleton will add the needed #include statements and
// give the ability to access the object stored in the branches.
//
// To draw px using the file hsimple.root (generated by the
// hsimple.C tutorial), we need a file named hsimple.cxx:
//
// double hsimple() {
// return px;
// }
//
// MakeProxy can then be used indirectly via the TTree::Draw interface
// as follow:
// new TFile("hsimple.root")
// ntuple->Draw("hsimple.cxx");
//
// A more complete example is available in the tutorials directory:
// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
// which reimplement the selector found in h1analysis.C
if (macrofilename==0 || strlen(macrofilename)==0 ) {
// We currently require a file name for the script
Error("MakeProxy","A file name for the user script is required");
return 0;
}
TTreeProxyGenerator gp(fTree,macrofilename,cutfilename,proxyClassname,option,maxUnrolling);
return 0;
}
//______________________________________________________________________________
TPrincipal *TTreePlayer::Principal(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*-*-*-*Interface to the Principal Components Analysis class*-*-*
//*-* ====================================================
//
// Create an instance of TPrincipal
// Fill it with the selected variables
// if option "n" is specified, the TPrincipal object is filled with
// normalized variables.
// If option "p" is specified, compute the principal components
// If option "p" and "d" print results of analysis
// If option "p" and "h" generate standard histograms
// If option "p" and "c" generate code of conversion functions
// return a pointer to the TPrincipal object. It is the user responsability
// to delete this object.
// The option default value is "np"
//
// see TTreePlayer::DrawSelect for explanation of the other parameters.
TTreeFormula **var;
TString *cnames;
TString onerow;
TString opt = option;
opt.ToLower();
TPrincipal *principal = 0;
Long64_t entry,entryNumber;
Int_t i,nch;
Int_t *index = 0;
Int_t ncols = 8; // by default first 8 columns are printed only
TObjArray *leaves = fTree->GetListOfLeaves();
Int_t nleaves = leaves->GetEntriesFast();
if (nleaves < ncols) ncols = nleaves;
nch = varexp ? strlen(varexp) : 0;
nentries = GetEntriesToProcess(firstentry, nentries);
//*-*- Compile selection expression if there is one
TTreeFormula *select = 0;
if (strlen(selection)) {
select = new TTreeFormula("Selection",selection,fTree);
if (!select) return principal;
if (!select->GetNdim()) { delete select; return principal; }
fFormulaList->Add(select);
}
//*-*- if varexp is empty, take first 8 columns by default
int allvar = 0;
if (!strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
if (nch == 0 || allvar) {
cnames = new TString[ncols];
for (i=0;i<ncols;i++) {
cnames[i] = ((TLeaf*)leaves->At(i))->GetName();
}
//*-*- otherwise select only the specified columns
} else {
ncols = 1;
onerow = varexp;
for (i=0;i<onerow.Length();i++) if (onerow[i] == ':') ncols++;
cnames = new TString[ncols];
index = new Int_t[ncols+1];
fSelector->MakeIndex(onerow,index);
for (i=0;i<ncols;i++) {
cnames[i] = fSelector->GetNameByIndex(onerow,index,i);
}
}
var = new TTreeFormula* [ncols];
Double_t *xvars = new Double_t[ncols];
//*-*- Create the TreeFormula objects corresponding to each column
for (i=0;i<ncols;i++) {
var[i] = new TTreeFormula("Var1",cnames[i].Data(),fTree);
fFormulaList->Add(var[i]);
}
//*-*- Create a TreeFormulaManager to coordinate the formulas
TTreeFormulaManager *manager=0;
if (fFormulaList->LastIndex()>=0) {
manager = new TTreeFormulaManager;
for(i=0;i<=fFormulaList->LastIndex();i++) {
manager->Add((TTreeFormula*)fFormulaList->At(i));
}
manager->Sync();
}
//*-* Build the TPrincipal object
if (opt.Contains("n")) principal = new TPrincipal(ncols, "n");
else principal = new TPrincipal(ncols);
//*-*- loop on all selected entries
fSelectedRows = 0;
Int_t tnumber = -1;
for (entry=firstentry;entry<firstentry+nentries;entry++) {
entryNumber = fTree->GetEntryNumber(entry);
if (entryNumber < 0) break;
Long64_t localEntry = fTree->LoadTree(entryNumber);
if (localEntry < 0) break;
if (tnumber != fTree->GetTreeNumber()) {
tnumber = fTree->GetTreeNumber();
if (manager) manager->UpdateFormulaLeaves();
}
int ndata = 1;
if (manager && manager->GetMultiplicity()) {
ndata = manager->GetNdata();
}
for(int inst=0;inst<ndata;inst++) {
Bool_t loaded = kFALSE;
if (select) {
if (select->EvalInstance(inst) == 0) {
continue;
}
}
if (inst==0) loaded = kTRUE;
else if (!loaded) {
// EvalInstance(0) always needs to be called so that
// the proper branches are loaded.
for (i=0;i<ncols;i++) {
var[i]->EvalInstance(0);
}
loaded = kTRUE;
}
for (i=0;i<ncols;i++) {
xvars[i] = var[i]->EvalInstance(inst);
}
principal->AddRow(xvars);
}
}
//*-* some actions with principal ?
if (opt.Contains("p")) {
principal->MakePrincipals(); // Do the actual analysis
if (opt.Contains("d")) principal->Print();
if (opt.Contains("h")) principal->MakeHistograms();
if (opt.Contains("c")) principal->MakeCode();
}
//*-*- delete temporary objects
fFormulaList->Clear();
delete [] var;
delete [] cnames;
delete [] index;
delete [] xvars;
return principal;
}
//______________________________________________________________________________
Long64_t TTreePlayer::Process(const char *filename,Option_t *option, Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*-*-*-*Process this tree executing the code in filename*-*-*-*-*
//*-* ================================================
//
// The code in filename is loaded (interpreted or compiled , see below)
// filename must contain a valid class implementation derived from TSelector.
// where TSelector has the following member functions:
//
// void TSelector::Begin(). This function is called before looping on the
// events in the Tree. The user can create his histograms in this function.
//
// Bool_t TSelector::Notify(). This function is called at the first entry
// of a new file in a chain.
//
// Bool_t TSelector::ProcessCut(Long64_t tentry). This function is called
// before processing tentry. It is the user's responsability to read
// the corresponding entry in memory (may be just a partial read).
// The function returns kTRUE if the entry must be processed,
// kFALSE otherwise. tentry is the entry number in the current Tree.
//
// void TSelector::ProcessFill(Long64_t tentry). This function is called for
// all selected events. User fills histograms in this function.
//
// void TSelector::Terminate(). This function is called at the end of
// the loop on all events.
//
// if filename is of the form file.C, the file will be interpreted.
// if filename is of the form file.C++, the file file.C will be compiled
// and dynamically loaded.
// if filename is of the form file.C+, the file file.C will be compiled
// and dynamically loaded. At next call, if file.C is older than file.o
// and file.so, the file.C is not compiled, only file.so is loaded.
//
// NOTE1
// It may be more interesting to invoke directly the other Process function
// accepting a TSelector* as argument.eg
// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
// selector->CallSomeFunction(..);
// mytree.Process(selector,..);
//
// NOTE2
// One should not call this function twice with the same selector file
// in the same script. If this is required, proceed as indicated in NOTE1,
// by getting a pointer to the corresponding TSelector,eg
// workaround 1
// ------------
//void stubs1() {
// TSelector *selector = TSelector::GetSelector("h1test.C");
// TFile *f1 = new TFile("stubs_nood_le1.root");
// TTree *h1 = (TTree*)f1->Get("h1");
// h1->Process(selector);
// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
// TTree *h2 = (TTree*)f2->Get("h1");
// h2->Process(selector);
//}
// or use ACLIC to compile the selector
// workaround 2
// ------------
//void stubs2() {
// TFile *f1 = new TFile("stubs_nood_le1.root");
// TTree *h1 = (TTree*)f1->Get("h1");
// h1->Process("h1test.C+");
// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
// TTree *h2 = (TTree*)f2->Get("h1");
// h2->Process("h1test.C+");
//}
DeleteSelectorFromFile(); //delete previous selector if any
// This might reloads the script and delete your option
// string! so let copy it first:
TString opt(option);
TString file(filename);
TSelector *selector = TSelector::GetSelector(file);
if (!selector) return -1;
fSelectorFromFile = selector;
fSelectorClass = selector->IsA();
Long64_t nsel = Process(selector,opt,nentries,firstentry);
return nsel;
}
//______________________________________________________________________________
Long64_t TTreePlayer::Process(TSelector *selector,Option_t *option, Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*-*-*-*Process this tree executing the code in selector*-*-*-*-*
//*-* ================================================
//
// The TSelector class has the following member functions:
//
// void TSelector::Begin(). This function is called before looping on the
// events in the Tree. The user can create his histograms in this function.
//
// Bool_t TSelector::Notify(). This function is called at the first entry
// of a new file in a chain.
//
// Bool_t TSelector::ProcessCut(Long64_t tentry). This function is called
// before processing tentry. It is the user's responsability to read
// the corresponding entry in memory (may be just a partial read).
// The function returns kTRUE if the entry must be processed,
// kFALSE otherwise. tentry is the entry number in the current Tree.
//
// void TSelector::ProcessFill(Long64_t tentry). This function is called for
// all selected events. User fills histograms in this function.
//
// void TSelector::Terminate(). This function is called at the end of
// the loop on all events.
//
// If the Tree (Chain) has an associated EventList, the loop is on the nentries
// of the EventList, starting at firstentry, otherwise the loop is on the
// specified Tree entries.
nentries = GetEntriesToProcess(firstentry, nentries);
TDirectory *cursav = gDirectory;
fTree->SetNotify(selector);
selector->SetOption(option);
selector->Begin(fTree); //<===call user initialisation function
selector->SlaveBegin(fTree); //<===call user initialisation function
selector->Notify();
if (selector->GetStatus()!=-1) {
//Create a timer to get control in the entry loop(s)
TProcessEventTimer *timer = 0;
Int_t interval = fTree->GetTimerInterval();
if (!gROOT->IsBatch() && interval)
timer = new TProcessEventTimer(interval);
//loop on entries (elist or all entries)
Long_t entry, entryNumber, localEntry;
Bool_t useCutFill = selector->Version() == 0;
for (entry=firstentry;entry<firstentry+nentries;entry++) {
entryNumber = fTree->GetEntryNumber(entry);
if (entryNumber < 0) break;
if (timer && timer->ProcessEvents()) break;
if (gROOT->IsInterrupted()) break;
localEntry = fTree->LoadTree(entryNumber);
if (localEntry < 0) break;
if(useCutFill) {
if (selector->ProcessCut(localEntry))
selector->ProcessFill(localEntry); //<==call user analysis function
} else {
selector->Process(localEntry);
}
}
delete timer;
selector->SlaveTerminate(); //<==call user termination function
selector->Terminate(); //<==call user termination function
}
if (cursav) cursav->cd();
return selector->GetStatus();
}
//______________________________________________________________________________
void TTreePlayer::RecursiveRemove(TObject *obj)
{
// cleanup pointers in the player pointing to obj
if (fHistogram == obj) fHistogram = 0;
}
//______________________________________________________________________________
Long64_t TTreePlayer::Scan(const char *varexp, const char *selection,
Option_t * option,
Long64_t nentries, Long64_t firstentry)
{
// Loop on Tree and print entries passing selection. If varexp is 0 (or "")
// then print only first 8 columns. If varexp = "*" print all columns.
// Otherwise a columns selection can be made using "var1:var2:var3".
// The function returns the number of entries passing the selection.
//
// By default 50 rows are shown and you are asked for <CR>
// to see the next 50 rows.
// You can change the default number of rows to be shown before <CR>
// via mytree->SetScanfield(maxrows) where maxrows is 50 by default.
// if maxrows is set to 0 all rows of the Tree are shown.
// This option is interesting when dumping the contents of a Tree to
// an ascii file, eg from the command line
// tree->SetScanField(0);
// tree->Scan("*"); >tree.log
// will create a file tree.log
//
// Arrays (within an entry) are printed in their linear forms.
// If several arrays with multiple dimensions are printed together,
// they will NOT be synchronized. For example print
// arr1[4][2] and arr2[2][3] will results in a printing similar to:
// ***********************************************
// * Row * Instance * arr1 * arr2 *
// ***********************************************
// * x * 0 * arr1[0][0]* arr2[0][0]*
// * x * 1 * arr1[0][1]* arr2[0][1]*
// * x * 2 * arr1[1][0]* arr2[0][2]*
// * x * 3 * arr1[1][1]* arr2[1][0]*
// * x * 4 * arr1[2][0]* arr2[1][1]*
// * x * 5 * arr1[2][1]* arr2[1][2]*
// * x * 6 * arr1[3][0]* *
// * x * 7 * arr1[3][1]* *
//
// However, if there is a selection criterium which is an array, then
// all the formulas will be synchronized with the selection criterium
// (see TTreePlayer::DrawSelect for more information).
//
// The options string can contains the following parameters:
// lenmax=dd
// Where 'dd' is the maximum number of elements per array that should
// be printed. If 'dd' is 0, all elements are printed (this is the
// default)
// colsize=ss
// Where 'ss' will be used as the default size for all the column
// If this options is not specified, the default column size is 9
// precision=pp
// Where 'pp' will be used as the default 'precision' for the
// printing format.
// col=xxx
// Where 'xxx' is colon (:) delimited list of printing format for
// each column if no format is specified for a column, the default is
// used.
// For example:
// tree->Scan("a:b:c","","colsize=30 precision=3 col=::20.10");
// Will print 3 columns, the first 2 columns will be 30 characters long,
// the third columns will be 20 characters long. The
// for the columns (assuming they are numbers) will be respectively:
// %30.3g %30.3g %20.10g
TString opt = option;
opt.ToLower();
UInt_t ui;
UInt_t lenmax = 0;
UInt_t colDefaultSize = 9;
UInt_t colPrecision = 9;
vector<TString> colFormats;
vector<Int_t> colSizes;
if (opt.Contains("lenmax=")) {
int start = opt.Index("lenmax=");
int numpos = start + strlen("lenmax=");
int numlen = 0;
int len = opt.Length();
while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
TString num = opt(numpos,numlen);
opt.Remove(start,strlen("lenmax")+numlen);
lenmax = atoi(num.Data());
}
if (opt.Contains("colsize=")) {
int start = opt.Index("colsize=");
int numpos = start + strlen("colsize=");
int numlen = 0;
int len = opt.Length();
while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
TString num = opt(numpos,numlen);
opt.Remove(start,strlen("size")+numlen);
colDefaultSize = atoi(num.Data());
colPrecision = colDefaultSize;
if (colPrecision>18) colPrecision = 18;
}
if (opt.Contains("precision=")) {
int start = opt.Index("precision=");
int numpos = start + strlen("precision=");
int numlen = 0;
int len = opt.Length();
while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
TString num = opt(numpos,numlen);
opt.Remove(start,strlen("precision")+numlen);
colPrecision = atoi(num.Data());
}
TString defFormat = Form("%d.%d",colDefaultSize,colPrecision);
if (opt.Contains("col=")) {
int start = opt.Index("col=");
int numpos = start + strlen("col=");
int numlen = 0;
int len = opt.Length();
while( (numpos+numlen<len) &&
(isdigit(opt[numpos+numlen])
|| opt[numpos+numlen]=='.'
|| opt[numpos+numlen]==':')) numlen++;
TString flist = opt(numpos,numlen);
opt.Remove(start,strlen("col")+numlen);
int i = 0;
while(i<flist.Length() && flist[i]==':') {
colFormats.push_back(defFormat);
colSizes.push_back(colDefaultSize);
++i;
}
for(; i<flist.Length(); ++i) {
int next = flist.Index(":",i);
if (next==i) {
colFormats.push_back(defFormat);
} else if (next==kNPOS) {
colFormats.push_back(flist(i,flist.Length()-i));
i = flist.Length();
} else {
colFormats.push_back(flist(i,next-i));
i = next;
}
UInt_t siz = atoi(colFormats[colFormats.size()-1].Data());
colSizes.push_back( siz ? siz : colDefaultSize );
}
}
TTreeFormula **var;
TString *cnames;
TString onerow;
Long64_t entry,entryNumber;
Int_t i,nch;
Int_t *index = 0;
UInt_t ncols = 8; // by default first 8 columns are printed only
ofstream out;
Int_t lenfile = 0;
char * fname = 0;
if (fScanRedirect) {
fTree->SetScanField(0); // no page break if Scan is redirected
fname = (char *) fScanFileName;
if (!fname) fname = (char*)"";
lenfile = strlen(fname);
if (!lenfile) {
Int_t nch = strlen(fTree->GetName());
fname = new char[nch+10];
strcpy(fname, fTree->GetName());
strcat(fname, "-scan.dat");
}
out.open(fname, ios::out
if (!out.good ()) {
if (!lenfile) delete [] fname;
Error("Scan","Can not open file for redirection");
return 0;
}
}
TObjArray *leaves = fTree->GetListOfLeaves();
if (leaves==0) return 0;
UInt_t nleaves = leaves->GetEntriesFast();
if (nleaves < ncols) ncols = nleaves;
nch = varexp ? strlen(varexp) : 0;
nentries = GetEntriesToProcess(firstentry, nentries);
//*-*- Compile selection expression if there is one
TTreeFormula *select = 0;
if (strlen(selection)) {
select = new TTreeFormula("Selection",selection,fTree);
if (!select) return -1;
if (!select->GetNdim()) { delete select; return -1; }
fFormulaList->Add(select);
}
//*-*- if varexp is empty, take first 8 columns by default
int allvar = 0;
if (!strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
if (nch == 0 || allvar) {
cnames = new TString[ncols];
UInt_t ncs = ncols;
ncols = 0;
for (ui=0;ui<ncs;++ui) {
TLeaf *lf = (TLeaf*)leaves->At(ui);
if (lf->GetBranch()->GetListOfBranches()->GetEntries() > 0) continue;
cnames[ncols] = lf->GetName();
ncols++;
}
//*-*- otherwise select only the specified columns
} else {
ncols = 1;
onerow = varexp;
for (i=0;i<onerow.Length();i++) {
if (onerow[i] == ':') {
if (onerow[i+1] == ':') ++i;
else ncols++;
}
}
cnames = new TString[ncols];
index = new Int_t[ncols+1];
fSelector->MakeIndex(onerow,index);
for (ui=0;ui<ncols;ui++) {
cnames[ui] = fSelector->GetNameByIndex(onerow,index,ui);
}
}
var = new TTreeFormula* [ncols];
for(ui=colFormats.size();ui<ncols;++ui) {
colFormats.push_back(defFormat);
colSizes.push_back(colDefaultSize);
}
//*-*- Create the TreeFormula objects corresponding to each column
for (ui=0;ui<ncols;ui++) {
var[ui] = new TTreeFormula("Var1",cnames[ui].Data(),fTree);
fFormulaList->Add(var[ui]);
}
//*-*- Create a TreeFormulaManager to coordinate the formulas
TTreeFormulaManager *manager=0;
Bool_t hasArray = kFALSE;
Bool_t forceDim = kFALSE;
if (fFormulaList->LastIndex()>=0) {
if (select) {
if (select->GetManager()->GetMultiplicity() > 0 ) {
manager = new TTreeFormulaManager;
for(i=0;i<=fFormulaList->LastIndex();i++) {
manager->Add((TTreeFormula*)fFormulaList->At(i));
}
manager->Sync();
}
}
for(i=0;i<=fFormulaList->LastIndex();i++) {
TTreeFormula *form = ((TTreeFormula*)fFormulaList->At(i));
switch( form->GetManager()->GetMultiplicity() ) {
case 1:
case 2:
hasArray = kTRUE;
case -1:
forceDim = kTRUE;
break;
case 0:
break;
}
}
}
//*-*- Print header
onerow = "***********";
if (hasArray) onerow += "***********";
for (ui=0;ui<ncols;ui++) {
TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
}
if (fScanRedirect)
out<<onerow.Data()<<"*"<<endl;
else
printf("%s*\n",onerow.Data());
onerow = "* Row ";
if (hasArray) onerow += "* Instance ";
for (ui=0;ui<ncols;ui++) {
TString numbFormat = Form("* %%%d.%ds ",colSizes[ui],colSizes[ui]);
onerow += Form(numbFormat.Data(),var[ui]->PrintValue(-1));
}
if (fScanRedirect)
out<<onerow.Data()<<"*"<<endl;
else
printf("%s*\n",onerow.Data());
onerow = "***********";
if (hasArray) onerow += "***********";
for (ui=0;ui<ncols;ui++) {
TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
}
if (fScanRedirect)
out<<onerow.Data()<<"*"<<endl;
else
printf("%s*\n",onerow.Data());
//*-*- loop on all selected entries
fSelectedRows = 0;
Int_t tnumber = -1;
Bool_t exitloop = kFALSE;
for (entry=firstentry;
entry<(firstentry+nentries) && !exitloop;
entry++) {
entryNumber = fTree->GetEntryNumber(entry);
if (entryNumber < 0) break;
Long64_t localEntry = fTree->LoadTree(entryNumber);
if (localEntry < 0) break;
if (tnumber != fTree->GetTreeNumber()) {
tnumber = fTree->GetTreeNumber();
if (manager) manager->UpdateFormulaLeaves();
else {
for(i=0;i<=fFormulaList->LastIndex();i++) {
((TTreeFormula*)fFormulaList->At(i))->UpdateFormulaLeaves();
}
}
}
int ndata = 1;
if (forceDim) {
if (manager) {
ndata = manager->GetNdata(kTRUE);
} else {
// let's print the max number of column
for (ui=0;ui<ncols;ui++) {
if (ndata < var[ui]->GetNdata() ) {
ndata = var[ui]->GetNdata();
}
}
if (select && select->GetNdata()==0) ndata = 0;
}
}
if (lenmax && ndata>(int)lenmax) ndata = lenmax;
Bool_t loaded = kFALSE;
for(int inst=0;inst<ndata;inst++) {
if (select) {
if (select->EvalInstance(inst) == 0) {
continue;
}
}
if (inst==0) loaded = kTRUE;
else if (!loaded) {
// EvalInstance(0) always needs to be called so that
// the proper branches are loaded.
for (ui=0;ui<ncols;ui++) {
var[ui]->EvalInstance(0);
}
loaded = kTRUE;
}
onerow = Form("* %8lld ",entryNumber);
if (hasArray) {
onerow += Form("* %8d ",inst);
}
for (ui=0;ui<ncols;++ui) {
TString numbFormat = Form("* %%%d.%ds ",colSizes[ui],colSizes[ui]);
if (var[ui]->GetNdim()) onerow += Form(numbFormat.Data(),var[ui]->PrintValue(0,inst,colFormats[ui].Data()));
else {
TString emptyForm = Form("* %%%dc ",colSizes[ui]);
onerow += Form(emptyForm.Data(),' ');
}
}
fSelectedRows++;
if (fScanRedirect)
out<<onerow.Data()<<"*"<<endl;
else
printf("%s*\n",onerow.Data());
if (fTree->GetScanField() > 0 && fSelectedRows > 0) {
if (fSelectedRows%fTree->GetScanField() == 0) {
fprintf(stderr,"Type <CR> to continue or q to quit ==> ");
int answer, readch;
readch = getchar();
answer = readch;
while (readch != '\n' && readch != EOF) readch = getchar();
if (answer == 'q' || answer == 'Q') {
exitloop = kTRUE;
break;
}
}
}
}
}
onerow = "***********";
if (hasArray) onerow += "***********";
for (ui=0;ui<ncols;ui++) {
TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
}
if (fScanRedirect)
out<<onerow.Data()<<"*"<<endl;
else
printf("%s*\n",onerow.Data());
if (select) Printf("==> %lld selected %s", fSelectedRows,
fSelectedRows == 1 ? "entry" : "entries");
if (fScanRedirect) printf("File <%s> created\n", fname);
//*-*- delete temporary objects
fFormulaList->Clear();
// The TTreeFormulaManager is deleted by the last TTreeFormula.
delete [] var;
delete [] cnames;
delete [] index;
return fSelectedRows;
}
//______________________________________________________________________________
TSQLResult *TTreePlayer::Query(const char *varexp, const char *selection,
Option_t *, Long64_t nentries, Long64_t firstentry)
{
// Loop on Tree and return TSQLResult object containing entries passing
// selection. If varexp is 0 (or "") then print only first 8 columns.
// If varexp = "*" print all columns. Otherwise a columns selection can
// be made using "var1:var2:var3". In case of error 0 is returned otherwise
// a TSQLResult object which must be deleted by the user.
TTreeFormula **var;
TString *cnames;
TString onerow;
Long64_t entry,entryNumber;
Int_t i,nch;
Int_t *index = 0;
Int_t ncols = 8; // by default first 8 columns are printed only
TObjArray *leaves = fTree->GetListOfLeaves();
Int_t nleaves = leaves->GetEntriesFast();
if (nleaves < ncols) ncols = nleaves;
nch = varexp ? strlen(varexp) : 0;
nentries = GetEntriesToProcess(firstentry, nentries);
// compile selection expression if there is one
TTreeFormula *select = 0;
if (strlen(selection)) {
select = new TTreeFormula("Selection",selection,fTree);
if (!select) return 0;
if (!select->GetNdim()) { delete select; return 0; }
fFormulaList->Add(select);
}
// if varexp is empty, take first 8 columns by default
int allvar = 0;
if (!strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
if (nch == 0 || allvar) {
cnames = new TString[ncols];
for (i=0;i<ncols;i++) {
cnames[i] = ((TLeaf*)leaves->At(i))->GetName();
}
} else {
// otherwise select only the specified columns
ncols = 1;
onerow = varexp;
for (i=0;i<onerow.Length();i++) if (onerow[i] == ':') ncols++;
cnames = new TString[ncols];
index = new Int_t[ncols+1];
fSelector->MakeIndex(onerow,index);
for (i=0;i<ncols;i++) {
cnames[i] = fSelector->GetNameByIndex(onerow,index,i);
}
}
var = new TTreeFormula* [ncols];
// create the TreeFormula objects corresponding to each column
for (i=0;i<ncols;i++) {
var[i] = new TTreeFormula("Var1",cnames[i].Data(),fTree);
fFormulaList->Add(var[i]);
}
// fill header info into result object
TTreeResult *res = new TTreeResult(ncols);
for (i = 0; i < ncols; i++) {
res->AddField(i, var[i]->PrintValue(-1));
}
// loop on all selected entries
const char *aresult;
Int_t len;
char *arow = new char[ncols*50];
fSelectedRows = 0;
Int_t tnumber = -1;
Int_t *fields = new Int_t[ncols];
for (entry=firstentry;entry<firstentry+nentries;entry++) {
entryNumber = fTree->GetEntryNumber(entry);
if (entryNumber < 0) break;
Long64_t localEntry = fTree->LoadTree(entryNumber);
if (localEntry < 0) break;
if (tnumber != fTree->GetTreeNumber()) {
tnumber = fTree->GetTreeNumber();
for (i=0;i<ncols;i++) var[i]->UpdateFormulaLeaves();
}
if (select) {
select->GetNdata();
if (select->EvalInstance(0) == 0) continue;
}
for (i=0;i<ncols;i++) {
aresult = var[i]->PrintValue(0);
len = strlen(aresult)+1;
if (i == 0) {
memcpy(arow,aresult,len);
fields[i] = len;
} else {
memcpy(arow+fields[i-1],aresult,len);
fields[i] = fields[i-1] + len;
}
}
res->AddRow(new TTreeRow(ncols,fields,arow));
fSelectedRows++;
}
// delete temporary objects
fFormulaList->Clear();
delete [] fields;
delete [] arow;
delete [] var;
delete [] cnames;
delete [] index;
return res;
}
//_______________________________________________________________________
void TTreePlayer::SetEstimate(Long64_t n)
{
//*-*-*-*-*-*-*-*-*Set number of entries to estimate variable limits*-*-*-*
//*-* ================================================
//
fSelector->SetEstimate(n);
}
//_______________________________________________________________________
void TTreePlayer::StartViewer(Int_t ww, Int_t wh)
{
//*-*-*-*-*-*-*-*-*Start the TTreeViewer on this TTree*-*-*-*-*-*-*-*-*-*
//*-* ===================================
//
// ww is the width of the canvas in pixels
// wh is the height of the canvas in pixels
if (gROOT->IsBatch()) {
Warning("StartViewer", "viewer cannot run in batch mode");
return;
}
#if !defined(R__WIN32) || defined(GDK_WIN32)
if (ww || wh) { } // use unused variables
TPluginHandler *h;
if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualTreeViewer"))) {
if (h->LoadPlugin() == -1)
return;
h->ExecPlugin(1,fTree);
}
#else
//hoping to replace these two lines soon by the general case
gROOT->LoadClass("TTreeViewer","TreeViewer");
gROOT->ProcessLine(Form("new TTreeViewer(\"%s\",\"TreeViewer\",%d,%d);",fTree->GetName(),ww,wh));
#endif
}
//______________________________________________________________________________
void TreeUnbinnedFitLikelihood(Int_t & /*npar*/, Double_t * /*gin*/,
Double_t &r, Double_t *par, Int_t /*flag*/)
{
// The fit function used by the unbinned likelihood fit.
Double_t x[3];
TF1 *fitfunc = (TF1*)tFitter->GetObjectFit();
fitfunc->InitArgs(x,par);
Long64_t n = gTree->GetSelectedRows();
Double_t *data1 = gTree->GetV1();
Double_t *data2 = gTree->GetV2();
Double_t *data3 = gTree->GetV3();
Double_t *weight = gTree->GetW();
Double_t logEpsilon = -230; // protect against negative probabilities
Double_t logL = 0.0, prob;
//printf("n=%lld, data1=%x, weight=%x\n",n,data1,weight);
for(Long64_t i = 0; i < n; i++) {
if (weight[i] <= 0) continue;
x[0] = data1[i];
if (data2) x[1] = data2[i];
if (data3) x[2] = data3[i];
prob = fitfunc->EvalPar(x,par);
//printf("i=%lld, x=%g, w=%g, prob=%g, logL=%g\n",i,x[0],weight[i],prob,logL);
if(prob > 0) logL += TMath::Log(prob) * weight[i];
else logL += logEpsilon * weight[i];
}
r = -2*logL;
}
//______________________________________________________________________________
Long64_t TTreePlayer::UnbinnedFit(const char *funcname ,const char *varexp, const char *selection,Option_t *option ,Long64_t nentries, Long64_t firstentry)
{
//*-*-*-*-*-*Unbinned fit of one or more variable(s) from a Tree*-*-*-*-*-*
//*-* ===================================================
//
// funcname is a TF1 function.
//
// See TTree::Draw for explanations of the other parameters.
//
// Fit the variable varexp using the function funcname using the
// selection cuts given by selection.
//
// The list of fit options is given in parameter option.
// option = "Q" Quiet mode (minimum printing)
// = "V" Verbose mode (default is between Q and V)
// = "E" Perform better Errors estimation using Minos technique
// = "M" More. Improve fit results
// = "D" Draw the projected histogram with the fitted function
// normalized to the number of selected rows
// and multiplied by the bin width
//
// You can specify boundary limits for some or all parameters via
// func->SetParLimits(p_number, parmin, parmax);
// if parmin>=parmax, the parameter is fixed
// Note that you are not forced to fix the limits for all parameters.
// For example, if you fit a function with 6 parameters, you can do:
// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
// func->SetParLimits(4,-10,-4);
// func->SetParLimits(5, 1,1);
// With this setup, parameters 0->3 can vary freely
// Parameter 4 has boundaries [-10,-4] with initial value -8
// Parameter 5 is fixed to 100.
//
// For the fit to be meaningful, the function must be self-normalized.
//
// i.e. It must have the same integral regardless of the parameter
// settings. Otherwise the fit will effectively just maximize the
// area.
//
// It is mandatory to have a normalization variable
// which is fixed for the fit. e.g.
//
// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
// f1->SetParameters(1, 3.1, 0.01);
// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
// //
//
// 1, 2 and 3 Dimensional fits are supported.
// See also TTree::Fit
Int_t npar,nvpar,nparx;
Int_t i;
Double_t par, we, al, bl;
Double_t eplus,eminus,eparab,globcc,amin,edm,errdef,werr;
Double_t arglist[10];
// Set the global fit function so that TreeUnbinnedFitLikelihood can find it.
TF1* fitfunc = (TF1*)gROOT->GetFunction(funcname);
if (!fitfunc) { Error("UnbinnedFit", "Unknown function: %s",funcname); return 0; }
npar = fitfunc->GetNpar();
if (npar <=0) { Error("UnbinnedFit", "Illegal number of parameters = %d",npar); return 0; }
// Spin through the data to select out the events of interest
// Make sure that the arrays V1,etc are created large enough to accomodate
// all entries
Long64_t oldEstimate = fTree->GetEstimate();
Long64_t nent = fTree->GetEntriesFriend();
fTree->SetEstimate(TMath::Min(nent,nentries));
Long64_t nsel = DrawSelect(varexp, selection, "goff", nentries, firstentry);
//printf("fTree=%x, v1=%x,w=%x\n",fTree,GetV1(),GetW());
//if no selected entries return
Long64_t nrows = GetSelectedRows();
if (nrows <= 0) {
Error("UnbinnedFit", "Cannot fit: no entries selected");
return 0;
}
// Check that function has same dimension as number of variables
Int_t ndim = GetDimension();
if (ndim != fitfunc->GetNdim()) {
Error("UnbinnedFit", "Function dimension=%d not equal to expression dimension=%d",fitfunc->GetNdim(),ndim);
return 0;
}
// Create and set up the fitter
gTree = fTree;
//printf("nsel=%lld, data1=%x, weight=%x\n",nsel,GetV1(),GetW());
tFitter = TVirtualFitter::Fitter(fTree);
tFitter->Clear();
tFitter->SetFCN(TreeUnbinnedFitLikelihood);
tFitter->SetObjectFit(fitfunc);
TString opt = option;
opt.ToLower();
// Some initialisations
if (!opt.Contains("v")) {
arglist[0] = -1;
tFitter->ExecuteCommand("SET PRINT", arglist,1);
arglist[0] = 0;
tFitter->ExecuteCommand("SET NOW", arglist,0);
}
// Setup the parameters (#, name, start, step, min, max)
Double_t min, max;
for(i = 0; i < npar; i++) {
fitfunc->GetParLimits(i, min, max);
Double_t we = 0.1*TMath::Abs(max-min);
if (we == 0) we = 0.3*TMath::Abs(fitfunc->GetParameter(i));
if (we == 0) we = 1;
if(min < max) {
tFitter->SetParameter(i, fitfunc->GetParName(i),
fitfunc->GetParameter(i),
we, min, max);
} else {
tFitter->SetParameter(i, fitfunc->GetParName(i),
fitfunc->GetParameter(i),
we, 0, 0);
}
// Check for a fixed parameter
if(max <= min && min > 0.0) {
tFitter->FixParameter(i);
}
} // end for loop through parameters
// Reset Print level
if (opt.Contains("v")) {
arglist[0] = 0;
tFitter->ExecuteCommand("SET PRINT", arglist,1);
}
// Set error criterion
//Note that FCN is multiplied by 2 in the UnbinnedLikelihood function
arglist[0] = 1;
tFitter->ExecuteCommand("SET ERR",arglist,1);
// Now ready for minimization step
arglist[0] = TVirtualFitter::GetMaxIterations();
arglist[1] = 1;
tFitter->ExecuteCommand("MIGRAD", arglist, 2);
if (opt.Contains("m")) {
tFitter->ExecuteCommand("IMPROVE",arglist,0);
}
if (opt.Contains("e")) {
tFitter->ExecuteCommand("HESSE",arglist,0);
tFitter->ExecuteCommand("MINOS",arglist,0);
}
fitfunc->SetNDF(fitfunc->GetNumberFitPoints()-npar);
// Get return status into function
char parName[50];
for (i=0;i<npar;i++) {
tFitter->GetParameter(i,parName, par,we,al,bl);
if (opt.Contains("e")) werr = we;
else {
tFitter->GetErrors(i,eplus,eminus,eparab,globcc);
if (eplus > 0 && eminus < 0) werr = 0.5*(eplus-eminus);
else werr = we;
}
fitfunc->SetParameter(i,par);
fitfunc->SetParError(i,werr);
}
tFitter->GetStats(amin,edm,errdef,nvpar,nparx);
// Print final values of parameters.
if (!opt.Contains("q")) {
amin = 0;
tFitter->PrintResults(1, amin);
}
//reset estimate
fTree->SetEstimate(oldEstimate);
//if option "D" is specified, draw the projected histogram
//with the fitted function normalized to the number of selected rows
//and multiplied by the bin width
if (opt.Contains("d")) {
if (fHistogram->GetDimension() < 2) {
TH1 *hf = (TH1*)fHistogram->Clone("unbinnedFit");
hf->SetLineWidth(3);
hf->Reset();
Int_t nbins = fHistogram->GetXaxis()->GetNbins();
Double_t norm = ((Double_t)nsel)*fHistogram->GetXaxis()->GetBinWidth(1);
for (Int_t bin=1;bin<=nbins;bin++) {
Double_t func = norm*fitfunc->Eval(hf->GetBinCenter(bin));
hf->SetBinContent(bin,func);
}
fHistogram->GetListOfFunctions()->Add(hf,"lsame");
}
fHistogram->Draw();
}
return nsel;
}
//______________________________________________________________________________
void TTreePlayer::UpdateFormulaLeaves()
{
// this function is called by TChain::LoadTree when a new Tree is loaded.
// Because Trees in a TChain may have a different list of leaves, one
// must update the leaves numbers in the TTreeFormula used by the TreePlayer.
if (fSelector) fSelector->Notify();
if (fFormulaList->GetSize()) {
TObjLink *lnk = fFormulaList->FirstLink();
while (lnk) {
lnk->GetObject()->Notify();
lnk = lnk->Next();
}
}
}
ROOT page - Class index - Class Hierarchy - Top of the page
This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.