Logo ROOT   6.30.04
Reference Guide
 All Namespaces Files Pages
TTreePlayer.cxx
Go to the documentation of this file.
1 // @(#)root/treeplayer:$Id$
2 // Author: Rene Brun 12/01/96
3 
4 /*************************************************************************
5  * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers. *
6  * All rights reserved. *
7  * *
8  * For the licensing terms see $ROOTSYS/LICENSE. *
9  * For the list of contributors see $ROOTSYS/README/CREDITS. *
10  *************************************************************************/
11 
12 /** \class TTreePlayer
13 
14 Implement some of the functionality of the class TTree requiring access to
15 extra libraries (Histogram, display, etc).
16 */
17 
18 #include "TTreePlayer.h"
19 
20 #include <string.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 
24 #include "Riostream.h"
25 #include "TROOT.h"
26 #include "TSystem.h"
27 #include "TFile.h"
28 #include "TEventList.h"
29 #include "TEntryList.h"
30 #include "TBranchObject.h"
31 #include "TBranchElement.h"
32 #include "TStreamerInfo.h"
33 #include "TStreamerElement.h"
34 #include "TLeafObject.h"
35 #include "TLeafF.h"
36 #include "TLeafD.h"
37 #include "TLeafC.h"
38 #include "TLeafB.h"
39 #include "TLeafI.h"
40 #include "TLeafS.h"
41 #include "TMath.h"
42 #include "TH1.h"
43 #include "TH2.h"
44 #include "TH3.h"
45 #include "TPolyMarker.h"
46 #include "TPolyMarker3D.h"
47 #include "TText.h"
48 #include "TDirectory.h"
49 #include "TClonesArray.h"
50 #include "TClass.h"
51 #include "TVirtualPad.h"
52 #include "TProfile.h"
53 #include "TProfile2D.h"
54 #include "TTreeFormula.h"
55 #include "TTreeFormulaManager.h"
56 #include "TStyle.h"
57 #include "Foption.h"
58 #include "TTreeResult.h"
59 #include "TTreeRow.h"
60 #include "TPrincipal.h"
61 #include "TChain.h"
62 #include "TChainElement.h"
63 #include "TF1.h"
64 #include "TVirtualFitter.h"
65 #include "TEnv.h"
66 #include "THLimitsFinder.h"
67 #include "TSelectorDraw.h"
68 #include "TSelectorEntries.h"
69 #include "TPluginManager.h"
70 #include "TObjString.h"
71 #include "TTreeProxyGenerator.h"
72 #include "TTreeReaderGenerator.h"
73 #include "TTreeIndex.h"
74 #include "TChainIndex.h"
75 #include "TRefProxy.h"
76 #include "TRefArrayProxy.h"
77 #include "TVirtualMonitoring.h"
78 #include "TTreeCache.h"
79 #include "TStyle.h"
80 #include "TVirtualMutex.h"
81 
82 #include "HFitInterface.h"
83 #include "Foption.h"
84 #include "Fit/BinData.h"
85 #include "Fit/UnBinData.h"
86 #include "Math/MinimizerOptions.h"
87 
88 
89 
90 R__EXTERN Foption_t Foption;
91 
92 TVirtualFitter *tFitter=0;
93 
94 ClassImp(TTreePlayer);
95 
96 ////////////////////////////////////////////////////////////////////////////////
97 /// Default Tree constructor.
98 
99 TTreePlayer::TTreePlayer()
100 {
101  fTree = 0;
102  fScanFileName = 0;
103  fScanRedirect = kFALSE;
104  fSelectedRows = 0;
105  fDimension = 0;
106  fHistogram = 0;
107  fFormulaList = new TList();
108  fFormulaList->SetOwner(kTRUE);
109  fSelector = new TSelectorDraw();
110  fSelectorFromFile = 0;
111  fSelectorClass = 0;
112  fSelectorUpdate = 0;
113  fInput = new TList();
114  fInput->Add(new TNamed("varexp",""));
115  fInput->Add(new TNamed("selection",""));
116  fSelector->SetInputList(fInput);
117  {
118  R__LOCKGUARD(gROOTMutex);
119  gROOT->GetListOfCleanups()->Add(this);
120  }
121  TClass::GetClass("TRef")->AdoptReferenceProxy(new TRefProxy());
122  TClass::GetClass("TRefArray")->AdoptReferenceProxy(new TRefArrayProxy());
123 }
124 
125 ////////////////////////////////////////////////////////////////////////////////
126 /// Tree destructor.
127 
128 TTreePlayer::~TTreePlayer()
129 {
130  delete fFormulaList;
131  delete fSelector;
132  DeleteSelectorFromFile();
133  fInput->Delete();
134  delete fInput;
135  R__LOCKGUARD(gROOTMutex);
136  gROOT->GetListOfCleanups()->Remove(this);
137 }
138 
139 ////////////////////////////////////////////////////////////////////////////////
140 /// Build the index for the tree (see TTree::BuildIndex)
141 
142 TVirtualIndex *TTreePlayer::BuildIndex(const TTree *T, const char *majorname, const char *minorname)
143 {
144  TVirtualIndex *index;
145  if (dynamic_cast<const TChain*>(T)) {
146  index = new TChainIndex(T, majorname, minorname);
147  if (index->IsZombie()) {
148  delete index;
149  Error("BuildIndex", "Creating a TChainIndex unsuccessful - switching to TTreeIndex");
150  }
151  else
152  return index;
153  }
154  return new TTreeIndex(T,majorname,minorname);
155 }
156 
157 ////////////////////////////////////////////////////////////////////////////////
158 /// Copy a Tree with selection, make a clone of this Tree header, then copy the
159 /// selected entries.
160 ///
161 /// - selection is a standard selection expression (see TTreePlayer::Draw)
162 /// - option is reserved for possible future use
163 /// - nentries is the number of entries to process (default is all)
164 /// - first is the first entry to process (default is 0)
165 ///
166 /// IMPORTANT: The copied tree stays connected with this tree until this tree
167 /// is deleted. In particular, any changes in branch addresses
168 /// in this tree are forwarded to the clone trees. Any changes
169 /// made to the branch addresses of the copied trees are over-ridden
170 /// anytime this tree changes its branch addresses.
171 /// Once this tree is deleted, all the addresses of the copied tree
172 /// are reset to their default values.
173 ///
174 /// The following example illustrates how to copy some events from the Tree
175 /// generated in $ROOTSYS/test/Event
176 /// ~~~{.cpp}
177 /// gSystem->Load("libEvent");
178 /// TFile f("Event.root");
179 /// TTree *T = (TTree*)f.Get("T");
180 /// Event *event = new Event();
181 /// T->SetBranchAddress("event",&event);
182 /// TFile f2("Event2.root","recreate");
183 /// TTree *T2 = T->CopyTree("fNtrack<595");
184 /// T2->Write();
185 /// ~~~
186 
187 TTree *TTreePlayer::CopyTree(const char *selection, Option_t *, Long64_t nentries,
188  Long64_t firstentry)
189 {
190 
191  // we make a copy of the tree header
192  TTree *tree = fTree->CloneTree(0);
193  if (tree == 0) return 0;
194 
195  // The clone should not delete any shared i/o buffers.
196  TObjArray* branches = tree->GetListOfBranches();
197  Int_t nb = branches->GetEntriesFast();
198  for (Int_t i = 0; i < nb; ++i) {
199  TBranch* br = (TBranch*) branches->UncheckedAt(i);
200  if (br->InheritsFrom(TBranchElement::Class())) {
201  ((TBranchElement*) br)->ResetDeleteObject();
202  }
203  }
204 
205  Long64_t entry,entryNumber;
206  nentries = GetEntriesToProcess(firstentry, nentries);
207 
208  // Compile selection expression if there is one
209  TTreeFormula *select = 0; // no need to interfere with fSelect since we
210  // handle the loop explicitly below and can call
211  // UpdateFormulaLeaves ourselves.
212  if (strlen(selection)) {
213  select = new TTreeFormula("Selection",selection,fTree);
214  if (!select || !select->GetNdim()) {
215  delete select;
216  delete tree;
217  return 0;
218  }
219  fFormulaList->Add(select);
220  }
221 
222  //loop on the specified entries
223  Int_t tnumber = -1;
224  for (entry=firstentry;entry<firstentry+nentries;entry++) {
225  entryNumber = fTree->GetEntryNumber(entry);
226  if (entryNumber < 0) break;
227  Long64_t localEntry = fTree->LoadTree(entryNumber);
228  if (localEntry < 0) break;
229  if (tnumber != fTree->GetTreeNumber()) {
230  tnumber = fTree->GetTreeNumber();
231  if (select) select->UpdateFormulaLeaves();
232  }
233  if (select) {
234  Int_t ndata = select->GetNdata();
235  Bool_t keep = kFALSE;
236  for(Int_t current = 0; current<ndata && !keep; current++) {
237  keep |= (select->EvalInstance(current) != 0);
238  }
239  if (!keep) continue;
240  }
241  fTree->GetEntry(entryNumber);
242  tree->Fill();
243  }
244  fFormulaList->Clear();
245  return tree;
246 }
247 
248 ////////////////////////////////////////////////////////////////////////////////
249 /// Delete any selector created by this object.
250 /// The selector has been created using TSelector::GetSelector(file)
251 
252 void TTreePlayer::DeleteSelectorFromFile()
253 {
254  if (fSelectorFromFile && fSelectorClass) {
255  if (fSelectorClass->IsLoaded()) {
256  delete fSelectorFromFile;
257  }
258  }
259  fSelectorFromFile = 0;
260  fSelectorClass = 0;
261 }
262 
263 ////////////////////////////////////////////////////////////////////////////////
264 /// Draw the result of a C++ script.
265 ///
266 /// The macrofilename and optionally cutfilename are assumed to contain
267 /// at least a method with the same name as the file. The method
268 /// should return a value that can be automatically cast to
269 /// respectively a double and a boolean.
270 ///
271 /// Both methods will be executed in a context such that the
272 /// branch names can be used as C++ variables. This is
273 /// accomplished by generating a TTreeProxy (see MakeProxy)
274 /// and including the files in the proper location.
275 ///
276 /// If the branch name can not be used a proper C++ symbol name,
277 /// it will be modified as follow:
278 /// - white spaces are removed
279 /// - if the leading character is not a letter, an underscore is inserted
280 /// - < and > are replace by underscores
281 /// - * is replaced by st
282 /// - & is replaced by rf
283 ///
284 /// If a cutfilename is specified, for each entry, we execute
285 /// ~~~{.cpp}
286 /// if (cutfilename()) htemp->Fill(macrofilename());
287 /// ~~~
288 /// If no cutfilename is specified, for each entry we execute
289 /// ~~~{.cpp}
290 /// htemp(macrofilename());
291 /// ~~~
292 /// The default for the histogram are the same as for
293 /// TTreePlayer::DrawSelect
294 
295 Long64_t TTreePlayer::DrawScript(const char* wrapperPrefix,
296  const char *macrofilename, const char *cutfilename,
297  Option_t *option, Long64_t nentries, Long64_t firstentry)
298 {
299  if (!macrofilename || strlen(macrofilename)==0) return 0;
300 
301  TString aclicMode;
302  TString arguments;
303  TString io;
304  TString realcutname;
305  if (cutfilename && strlen(cutfilename))
306  realcutname = gSystem->SplitAclicMode(cutfilename, aclicMode, arguments, io);
307 
308  // we ignore the aclicMode for the cutfilename!
309  TString realname = gSystem->SplitAclicMode(macrofilename, aclicMode, arguments, io);
310 
311  TString selname = wrapperPrefix;
312 
313  ROOT::Internal::TTreeProxyGenerator gp(fTree,realname,realcutname,selname,option,3);
314 
315  selname = gp.GetFileName();
316  if (aclicMode.Length()==0) {
317  Warning("DrawScript","TTreeProxy does not work in interpreted mode yet. The script will be compiled.");
318  aclicMode = "+";
319  }
320  selname.Append(aclicMode);
321 
322  Info("DrawScript","%s",Form("Will process tree/chain using %s",selname.Data()));
323  Long64_t result = fTree->Process(selname,option,nentries,firstentry);
324  fTree->SetNotify(0);
325 
326  // could delete the file selname+".h"
327  // However this would remove the optimization of avoiding a useless
328  // recompilation if the user ask for the same thing twice!
329 
330  return result;
331 }
332 
333 ////////////////////////////////////////////////////////////////////////////////
334 /// Draw expression varexp for specified entries that matches the selection.
335 /// Returns -1 in case of error or number of selected events in case of success.
336 ///
337 /// See the documentation of TTree::Draw for the complete details.
338 
339 Long64_t TTreePlayer::DrawSelect(const char *varexp0, const char *selection, Option_t *option,Long64_t nentries, Long64_t firstentry)
340 {
341  if (fTree->GetEntriesFriend() == 0) return 0;
342 
343  // Let's see if we have a filename as arguments instead of
344  // a TTreeFormula expression.
345 
346  TString possibleFilename = varexp0;
347  Ssiz_t dot_pos = possibleFilename.Last('.');
348  if ( dot_pos != kNPOS
349  && possibleFilename.Index("Alt$")<0 && possibleFilename.Index("Entries$")<0
350  && possibleFilename.Index("LocalEntries$")<0
351  && possibleFilename.Index("Length$")<0 && possibleFilename.Index("Entry$")<0
352  && possibleFilename.Index("LocalEntry$")<0
353  && possibleFilename.Index("Min$")<0 && possibleFilename.Index("Max$")<0
354  && possibleFilename.Index("MinIf$")<0 && possibleFilename.Index("MaxIf$")<0
355  && possibleFilename.Index("Iteration$")<0 && possibleFilename.Index("Sum$")<0
356  && possibleFilename.Index(">")<0 && possibleFilename.Index("<")<0
357  && gSystem->IsFileInIncludePath(possibleFilename.Data())) {
358 
359  if (selection && strlen(selection) && !gSystem->IsFileInIncludePath(selection)) {
360  Error("DrawSelect",
361  "Drawing using a C++ file currently requires that both the expression and the selection are files\n\t\"%s\" is not a file",
362  selection);
363  return 0;
364  }
365  return DrawScript("generatedSel",varexp0,selection,option,nentries,firstentry);
366 
367  } else {
368  possibleFilename = selection;
369  if (possibleFilename.Index("Alt$")<0 && possibleFilename.Index("Entries$")<0
370  && possibleFilename.Index("LocalEntries$")<0
371  && possibleFilename.Index("Length$")<0 && possibleFilename.Index("Entry$")<0
372  && possibleFilename.Index("LocalEntry$")<0
373  && possibleFilename.Index("Min$")<0 && possibleFilename.Index("Max$")<0
374  && possibleFilename.Index("MinIf$")<0 && possibleFilename.Index("MaxIf$")<0
375  && possibleFilename.Index("Iteration$")<0 && possibleFilename.Index("Sum$")<0
376  && possibleFilename.Index(">")<0 && possibleFilename.Index("<")<0
377  && gSystem->IsFileInIncludePath(possibleFilename.Data())) {
378 
379  Error("DrawSelect",
380  "Drawing using a C++ file currently requires that both the expression and the selection are files\n\t\"%s\" is not a file",
381  varexp0);
382  return 0;
383  }
384  }
385 
386  Long64_t oldEstimate = fTree->GetEstimate();
387  TEventList *evlist = fTree->GetEventList();
388  TEntryList *elist = fTree->GetEntryList();
389  if (evlist && elist){
390  elist->SetBit(kCanDelete, kTRUE);
391  }
392  TNamed *cvarexp = (TNamed*)fInput->FindObject("varexp");
393  TNamed *cselection = (TNamed*)fInput->FindObject("selection");
394  if (cvarexp) cvarexp->SetTitle(varexp0);
395  if (cselection) cselection->SetTitle(selection);
396 
397  TString opt = option;
398  opt.ToLower();
399  Bool_t optpara = kFALSE;
400  Bool_t optcandle = kFALSE;
401  Bool_t optgl5d = kFALSE;
402  Bool_t optnorm = kFALSE;
403  if (opt.Contains("norm")) {optnorm = kTRUE; opt.ReplaceAll("norm",""); opt.ReplaceAll(" ","");}
404  if (opt.Contains("para")) optpara = kTRUE;
405  if (opt.Contains("candle")) optcandle = kTRUE;
406  if (opt.Contains("gl5d")) optgl5d = kTRUE;
407  Bool_t pgl = gStyle->GetCanvasPreferGL();
408  if (optgl5d) {
409  fTree->SetEstimate(fTree->GetEntries());
410  if (!gPad) {
411  if (pgl == kFALSE) gStyle->SetCanvasPreferGL(kTRUE);
412  gROOT->ProcessLineFast("new TCanvas();");
413  }
414  }
415 
416  // Do not process more than fMaxEntryLoop entries
417  if (nentries > fTree->GetMaxEntryLoop()) nentries = fTree->GetMaxEntryLoop();
418 
419  // invoke the selector
420  Long64_t nrows = Process(fSelector,option,nentries,firstentry);
421  fSelectedRows = nrows;
422  fDimension = fSelector->GetDimension();
423 
424  //*-* an Event List
425  if (fDimension <= 0) {
426  fTree->SetEstimate(oldEstimate);
427  if (fSelector->GetCleanElist()) {
428  // We are in the case where the input list was reset!
429  fTree->SetEntryList(elist);
430  delete fSelector->GetObject();
431  }
432  return nrows;
433  }
434 
435  // Draw generated histogram
436  Long64_t drawflag = fSelector->GetDrawFlag();
437  Int_t action = fSelector->GetAction();
438  Bool_t draw = kFALSE;
439  if (!drawflag && !opt.Contains("goff")) draw = kTRUE;
440  if (!optcandle && !optpara) fHistogram = (TH1*)fSelector->GetObject();
441  if (optnorm) {
442  Double_t sumh= fHistogram->GetSumOfWeights();
443  if (sumh != 0) fHistogram->Scale(1./sumh);
444  }
445 
446  if (drawflag) {
447  if (gPad) {
448  if (!opt.Contains("same") && !opt.Contains("goff")) {
449  gPad->DrawFrame(-1.,-1.,1.,1.);
450  TText *text_empty = new TText(0.,0.,"Empty");
451  text_empty->SetTextAlign(22);
452  text_empty->SetTextFont(42);
453  text_empty->SetTextSize(0.1);
454  text_empty->SetTextColor(1);
455  text_empty->Draw();
456  }
457  } else {
458  Warning("DrawSelect", "The selected TTree subset is empty.");
459  }
460  }
461 
462  //*-*- 1-D distribution
463  if (fDimension == 1 && !(optpara||optcandle)) {
464  if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("X");
465  if (draw) fHistogram->Draw(opt.Data());
466 
467  //*-*- 2-D distribution
468  } else if (fDimension == 2 && !(optpara||optcandle)) {
469  if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Y");
470  if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("X");
471  if (action == 4) {
472  if (draw) fHistogram->Draw(opt.Data());
473  } else {
474  Bool_t graph = kFALSE;
475  Int_t l = opt.Length();
476  if (l == 0 || opt == "same") graph = kTRUE;
477  if (opt.Contains("p") || opt.Contains("*") || opt.Contains("l")) graph = kTRUE;
478  if (opt.Contains("surf") || opt.Contains("lego") || opt.Contains("cont")) graph = kFALSE;
479  if (opt.Contains("col") || opt.Contains("hist") || opt.Contains("scat")) graph = kFALSE;
480  if (!graph) {
481  if (draw) fHistogram->Draw(opt.Data());
482  } else {
483  if (fSelector->GetOldHistogram() && draw) fHistogram->Draw(opt.Data());
484  }
485  }
486  //*-*- 3-D distribution
487  } else if (fDimension == 3 && !(optpara||optcandle)) {
488  if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Z");
489  if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("Y");
490  if (fSelector->GetVar3()->IsInteger()) fHistogram->LabelsDeflate("X");
491  if (action == 23) {
492  if (draw) fHistogram->Draw(opt.Data());
493  } else if (action == 33) {
494  if (draw) {
495  if (opt.Contains("z")) fHistogram->Draw("func z");
496  else fHistogram->Draw("func");
497  }
498  } else {
499  Int_t noscat = opt.Length();
500  if (opt.Contains("same")) noscat -= 4;
501  if (noscat) {
502  if (draw) fHistogram->Draw(opt.Data());
503  } else {
504  if (fSelector->GetOldHistogram() && draw) fHistogram->Draw(opt.Data());
505  }
506  }
507  //*-*- 4-D distribution
508  } else if (fDimension == 4 && !(optpara||optcandle)) {
509  if (fSelector->GetVar1()->IsInteger()) fHistogram->LabelsDeflate("Z");
510  if (fSelector->GetVar2()->IsInteger()) fHistogram->LabelsDeflate("Y");
511  if (fSelector->GetVar3()->IsInteger()) fHistogram->LabelsDeflate("X");
512  if (draw) fHistogram->Draw(opt.Data());
513  Int_t ncolors = gStyle->GetNumberOfColors();
514  TObjArray *pms = (TObjArray*)fHistogram->GetListOfFunctions()->FindObject("polymarkers");
515  for (Int_t col=0;col<ncolors;col++) {
516  if (!pms) continue;
517  TPolyMarker3D *pm3d = (TPolyMarker3D*)pms->UncheckedAt(col);
518  if (draw) pm3d->Draw();
519  }
520  //*-*- Parallel Coordinates or Candle chart.
521  } else if (fDimension > 1 && (optpara || optcandle)) {
522  if (draw) {
523  TObject* para = fSelector->GetObject();
524  fTree->Draw(">>enlist",selection,"entrylist",nentries,firstentry);
525  TObject *enlist = gDirectory->FindObject("enlist");
526  gROOT->ProcessLine(Form("TParallelCoord::SetEntryList((TParallelCoord*)0x%lx,(TEntryList*)0x%lx)",
527  (ULong_t)para, (ULong_t)enlist));
528  }
529  //*-*- 5d with gl
530  } else if (fDimension == 5 && optgl5d) {
531  gROOT->ProcessLineFast(Form("(new TGL5DDataSet((TTree *)0x%lx))->Draw(\"%s\");", (ULong_t)fTree, opt.Data()));
532  gStyle->SetCanvasPreferGL(pgl);
533  }
534 
535  if (fHistogram) fHistogram->SetCanExtend(TH1::kNoAxis);
536  return fSelectedRows;
537 }
538 
539 ////////////////////////////////////////////////////////////////////////////////
540 /// Fit a projected item(s) from a Tree.
541 /// Returns -1 in case of error or number of selected events in case of success.
542 ///
543 /// The formula is a TF1 expression.
544 ///
545 /// See TTree::Draw for explanations of the other parameters.
546 ///
547 /// By default the temporary histogram created is called htemp.
548 /// If varexp contains >>hnew , the new histogram created is called hnew
549 /// and it is kept in the current directory.
550 /// Example:
551 /// ~~~{.cpp}
552 /// tree.Fit("pol4","sqrt(x)>>hsqrt","y>0")
553 /// will fit sqrt(x) and save the histogram as "hsqrt" in the current
554 /// directory.
555 /// ~~~
556 ///
557 /// The function returns the status of the histogram fit (see TH1::Fit)
558 /// If no entries were selected, the function returns -1;
559 /// (i.e. fitResult is null if the fit is OK)
560 
561 Int_t TTreePlayer::Fit(const char *formula ,const char *varexp, const char *selection,Option_t *option ,Option_t *goption,Long64_t nentries, Long64_t firstentry)
562 {
563  Int_t nch = option ? strlen(option) + 10 : 10;
564  char *opt = new char[nch];
565  if (option) strlcpy(opt,option,nch-1);
566  else strlcpy(opt,"goff",5);
567 
568  Long64_t nsel = DrawSelect(varexp,selection,opt,nentries,firstentry);
569 
570  delete [] opt;
571  Int_t fitResult = -1;
572 
573  if (fHistogram && nsel > 0) {
574  fitResult = fHistogram->Fit(formula,option,goption);
575  }
576  return fitResult;
577 }
578 
579 ////////////////////////////////////////////////////////////////////////////////
580 /// Return the number of entries matching the selection.
581 /// Return -1 in case of errors.
582 ///
583 /// If the selection uses any arrays or containers, we return the number
584 /// of entries where at least one element match the selection.
585 /// GetEntries is implemented using the selector class TSelectorEntries,
586 /// which can be used directly (see code in TTreePlayer::GetEntries) for
587 /// additional option.
588 /// If SetEventList was used on the TTree or TChain, only that subset
589 /// of entries will be considered.
590 
591 Long64_t TTreePlayer::GetEntries(const char *selection)
592 {
593  TSelectorEntries s(selection);
594  fTree->Process(&s);
595  fTree->SetNotify(0);
596  return s.GetSelectedRows();
597 }
598 
599 ////////////////////////////////////////////////////////////////////////////////
600 /// return the number of entries to be processed
601 /// this function checks that nentries is not bigger than the number
602 /// of entries in the Tree or in the associated TEventlist
603 
604 Long64_t TTreePlayer::GetEntriesToProcess(Long64_t firstentry, Long64_t nentries) const
605 {
606  Long64_t lastentry = firstentry + nentries - 1;
607  if (lastentry > fTree->GetEntriesFriend()-1) {
608  lastentry = fTree->GetEntriesFriend() - 1;
609  nentries = lastentry - firstentry + 1;
610  }
611  //TEventList *elist = fTree->GetEventList();
612  //if (elist && elist->GetN() < nentries) nentries = elist->GetN();
613  TEntryList *elist = fTree->GetEntryList();
614  if (elist && elist->GetN() < nentries) nentries = elist->GetN();
615  return nentries;
616 }
617 
618 ////////////////////////////////////////////////////////////////////////////////
619 /// Return name corresponding to colindex in varexp.
620 ///
621 /// - varexp is a string of names separated by :
622 /// - index is an array with pointers to the start of name[i] in varexp
623 
624 const char *TTreePlayer::GetNameByIndex(TString &varexp, Int_t *index,Int_t colindex)
625 {
626  TTHREAD_TLS_DECL(std::string,column);
627  if (colindex<0 ) return "";
628  Int_t i1,n;
629  i1 = index[colindex] + 1;
630  n = index[colindex+1] - i1;
631  column = varexp(i1,n).Data();
632  // return (const char*)Form((const char*)column);
633  return column.c_str();
634 }
635 
636 ////////////////////////////////////////////////////////////////////////////////
637 /// Return the name of the branch pointer needed by MakeClass/MakeSelector
638 
639 static TString R__GetBranchPointerName(TLeaf *leaf, Bool_t replace = kTRUE)
640 {
641  TLeaf *leafcount = leaf->GetLeafCount();
642  TBranch *branch = leaf->GetBranch();
643 
644  TString branchname( branch->GetName() );
645 
646  if ( branch->GetNleaves() <= 1 ) {
647  if (branch->IsA() != TBranchObject::Class()) {
648  if (!leafcount) {
649  TBranch *mother = branch->GetMother();
650  const char* ltitle = leaf->GetTitle();
651  if (mother && mother!=branch) {
652  branchname = mother->GetName();
653  if (branchname[branchname.Length()-1]!='.') {
654  branchname += ".";
655  }
656  if (strncmp(branchname.Data(),ltitle,branchname.Length())==0) {
657  branchname = "";
658  }
659  } else {
660  branchname = "";
661  }
662  branchname += ltitle;
663  }
664  }
665  }
666  if (replace) {
667  char *bname = (char*)branchname.Data();
668  char *twodim = (char*)strstr(bname,"[");
669  if (twodim) *twodim = 0;
670  while (*bname) {
671  if (*bname == '.') *bname='_';
672  if (*bname == ',') *bname='_';
673  if (*bname == ':') *bname='_';
674  if (*bname == '<') *bname='_';
675  if (*bname == '>') *bname='_';
676  bname++;
677  }
678  }
679  return branchname;
680 }
681 
682 ////////////////////////////////////////////////////////////////////////////////
683 /// Generate skeleton analysis class for this Tree.
684 ///
685 /// The following files are produced: classname.h and classname.C
686 /// If classname is 0, classname will be called "nameoftree.
687 ///
688 /// The generated code in classname.h includes the following:
689 /// - Identification of the original Tree and Input file name
690 /// - Definition of analysis class (data and functions)
691 /// - the following class functions:
692 /// - constructor (connecting by default the Tree file)
693 /// - GetEntry(Long64_t entry)
694 /// - Init(TTree *tree) to initialize a new TTree
695 /// - Show(Long64_t entry) to read and Dump entry
696 ///
697 /// The generated code in classname.C includes only the main
698 /// analysis function Loop.
699 ///
700 /// To use this function:
701 /// - connect your Tree file (eg: TFile f("myfile.root");)
702 /// - T->MakeClass("MyClass");
703 ///
704 /// where T is the name of the Tree in file myfile.root
705 /// and MyClass.h, MyClass.C the name of the files created by this function.
706 /// In a ROOT session, you can do:
707 /// ~~~{.cpp}
708 /// root> .L MyClass.C
709 /// root> MyClass t
710 /// root> t.GetEntry(12); // Fill t data members with entry number 12
711 /// root> t.Show(); // Show values of entry 12
712 /// root> t.Show(16); // Read and show values of entry 16
713 /// root> t.Loop(); // Loop on all entries
714 /// ~~~
715 /// NOTE: Do not use the code generated for one Tree in case of a TChain.
716 /// Maximum dimensions calculated on the basis of one TTree only
717 /// might be too small when processing all the TTrees in one TChain.
718 /// Instead of myTree.MakeClass(.., use myChain.MakeClass(..
719 
720 Int_t TTreePlayer::MakeClass(const char *classname, const char *option)
721 {
722  TString opt = option;
723  opt.ToLower();
724 
725  // Connect output files
726  if (!classname) classname = fTree->GetName();
727 
728  TString thead;
729  thead.Form("%s.h", classname);
730  FILE *fp = fopen(thead, "w");
731  if (!fp) {
732  Error("MakeClass","cannot open output file %s", thead.Data());
733  return 3;
734  }
735  TString tcimp;
736  tcimp.Form("%s.C", classname);
737  FILE *fpc = fopen(tcimp, "w");
738  if (!fpc) {
739  Error("MakeClass","cannot open output file %s", tcimp.Data());
740  fclose(fp);
741  return 3;
742  }
743  TString treefile;
744  if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile()) {
745  treefile = fTree->GetDirectory()->GetFile()->GetName();
746  } else {
747  treefile = "Memory Directory";
748  }
749  // In the case of a chain, the GetDirectory information usually does
750  // pertain to the Chain itself but to the currently loaded tree.
751  // So we can not rely on it.
752  Bool_t ischain = fTree->InheritsFrom(TChain::Class());
753  Bool_t isHbook = fTree->InheritsFrom("THbookTree");
754  if (isHbook)
755  treefile = fTree->GetTitle();
756 
757 //======================Generate classname.h=====================
758  // Print header
759  TObjArray *leaves = fTree->GetListOfLeaves();
760  Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
761  TDatime td;
762  fprintf(fp,"//////////////////////////////////////////////////////////\n");
763  fprintf(fp,"// This class has been automatically generated on\n");
764  fprintf(fp,"// %s by ROOT version %s\n",td.AsString(),gROOT->GetVersion());
765  if (!ischain) {
766  fprintf(fp,"// from TTree %s/%s\n",fTree->GetName(),fTree->GetTitle());
767  fprintf(fp,"// found on file: %s\n",treefile.Data());
768  } else {
769  fprintf(fp,"// from TChain %s/%s\n",fTree->GetName(),fTree->GetTitle());
770  }
771  fprintf(fp,"//////////////////////////////////////////////////////////\n");
772  fprintf(fp,"\n");
773  fprintf(fp,"#ifndef %s_h\n",classname);
774  fprintf(fp,"#define %s_h\n",classname);
775  fprintf(fp,"\n");
776  fprintf(fp,"#include <TROOT.h>\n");
777  fprintf(fp,"#include <TChain.h>\n");
778  fprintf(fp,"#include <TFile.h>\n");
779  if (isHbook) fprintf(fp,"#include <THbookFile.h>\n");
780  if (opt.Contains("selector")) fprintf(fp,"#include <TSelector.h>\n");
781 
782  // See if we can add any #include about the user data.
783  Int_t l;
784  fprintf(fp,"\n// Header file for the classes stored in the TTree if any.\n");
785  TList listOfHeaders;
786  listOfHeaders.SetOwner();
787  for (l=0;l<nleaves;l++) {
788  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
789  TBranch *branch = leaf->GetBranch();
790  TClass *cl = TClass::GetClass(branch->GetClassName());
791  if (cl && cl->IsLoaded() && !listOfHeaders.FindObject(cl->GetName())) {
792  const char *declfile = cl->GetDeclFileName();
793  if (declfile && declfile[0]) {
794  static const char *precstl = "prec_stl/";
795  static const unsigned int precstl_len = strlen(precstl);
796  static const char *rootinclude = "include/";
797  static const unsigned int rootinclude_len = strlen(rootinclude);
798  if (strncmp(declfile,precstl,precstl_len) == 0) {
799  fprintf(fp,"#include <%s>\n",declfile+precstl_len);
800  listOfHeaders.Add(new TNamed(cl->GetName(),declfile+precstl_len));
801  } else if (strncmp(declfile,"/usr/include/",13) == 0) {
802  fprintf(fp,"#include <%s>\n",declfile+strlen("/include/c++/"));
803  listOfHeaders.Add(new TNamed(cl->GetName(),declfile+strlen("/include/c++/")));
804  } else if (strstr(declfile,"/include/c++/") != 0) {
805  fprintf(fp,"#include <%s>\n",declfile+strlen("/include/c++/"));
806  listOfHeaders.Add(new TNamed(cl->GetName(),declfile+strlen("/include/c++/")));
807  } else if (strncmp(declfile,rootinclude,rootinclude_len) == 0) {
808  fprintf(fp,"#include <%s>\n",declfile+rootinclude_len);
809  listOfHeaders.Add(new TNamed(cl->GetName(),declfile+rootinclude_len));
810  } else {
811  fprintf(fp,"#include \"%s\"\n",declfile);
812  listOfHeaders.Add(new TNamed(cl->GetName(),declfile));
813  }
814  }
815  }
816  }
817 
818  // First loop on all leaves to generate dimension declarations
819  Int_t len, lenb;
820  char blen[1024];
821  char *bname;
822  Int_t *leaflen = new Int_t[nleaves];
823  TObjArray *leafs = new TObjArray(nleaves);
824  for (l=0;l<nleaves;l++) {
825  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
826  leafs->AddAt(new TObjString(leaf->GetName()),l);
827  leaflen[l] = leaf->GetMaximum();
828  }
829  if (ischain) {
830  // In case of a chain, one must find the maximum dimension of each leaf
831  // One must be careful and not assume that all Trees in the chain
832  // have the same leaves and in the same order!
833  TChain *chain = (TChain*)fTree;
834  Int_t ntrees = chain->GetNtrees();
835  for (Int_t file=0;file<ntrees;file++) {
836  Long64_t first = chain->GetTreeOffset()[file];
837  chain->LoadTree(first);
838  for (l=0;l<nleaves;l++) {
839  TObjString *obj = (TObjString*)leafs->At(l);
840  TLeaf *leaf = chain->GetLeaf(obj->GetName());
841  if (leaf) {
842  leaflen[l] = TMath::Max(leaflen[l],leaf->GetMaximum());
843  }
844  }
845  }
846  chain->LoadTree(0);
847  }
848 
849  fprintf(fp,"\n");
850  if (opt.Contains("selector")) {
851  fprintf(fp,"class %s : public TSelector {\n",classname);
852  fprintf(fp,"public :\n");
853  fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n");
854  } else {
855  fprintf(fp,"class %s {\n",classname);
856  fprintf(fp,"public :\n");
857  fprintf(fp," TTree *fChain; //!pointer to the analyzed TTree or TChain\n");
858  fprintf(fp," Int_t fCurrent; //!current Tree number in a TChain\n");
859  }
860 
861  fprintf(fp,"\n// Fixed size dimensions of array or collections stored in the TTree if any.\n");
862  leaves = fTree->GetListOfLeaves();
863  for (l=0;l<nleaves;l++) {
864  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
865  strlcpy(blen,leaf->GetName(),sizeof(blen));
866  bname = &blen[0];
867  while (*bname) {
868  if (*bname == '.') *bname='_';
869  if (*bname == ',') *bname='_';
870  if (*bname == ':') *bname='_';
871  if (*bname == '<') *bname='_';
872  if (*bname == '>') *bname='_';
873  bname++;
874  }
875  lenb = strlen(blen);
876  if (blen[lenb-1] == '_') {
877  blen[lenb-1] = 0;
878  len = leaflen[l];
879  if (len <= 0) len = 1;
880  fprintf(fp," static constexpr Int_t kMax%s = %d;\n",blen,len);
881  }
882  }
883  delete [] leaflen;
884  leafs->Delete();
885  delete leafs;
886 
887 // second loop on all leaves to generate type declarations
888  fprintf(fp,"\n // Declaration of leaf types\n");
889  TLeaf *leafcount;
890  TLeafObject *leafobj;
891  TBranchElement *bre=0;
892  const char *headOK = " ";
893  const char *headcom = " //";
894  const char *head;
895  char branchname[1024];
896  char aprefix[1024];
897  TObjArray branches(100);
898  TObjArray mustInit(100);
899  TObjArray mustInitArr(100);
900  mustInitArr.SetOwner(kFALSE);
901  Int_t *leafStatus = new Int_t[nleaves];
902  for (l=0;l<nleaves;l++) {
903  Int_t kmax = 0;
904  head = headOK;
905  leafStatus[l] = 0;
906  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
907  len = leaf->GetLen(); if (len<=0) len = 1;
908  leafcount =leaf->GetLeafCount();
909  TBranch *branch = leaf->GetBranch();
910  branchname[0] = 0;
911  strlcpy(branchname,branch->GetName(),sizeof(branchname));
912  strlcpy(aprefix,branch->GetName(),sizeof(aprefix));
913  if (!branches.FindObject(branch)) branches.Add(branch);
914  else leafStatus[l] = 1;
915  if ( branch->GetNleaves() > 1) {
916  // More than one leaf for the branch we need to distinguish them
917  strlcat(branchname,".",sizeof(branchname));
918  strlcat(branchname,leaf->GetTitle(),sizeof(branchname));
919  if (leafcount) {
920  // remove any dimension in title
921  char *dim = (char*)strstr(branchname,"["); if (dim) dim[0] = 0;
922  }
923  } else {
924  strlcpy(branchname,branch->GetName(),sizeof(branchname));
925  }
926  char *twodim = (char*)strstr(leaf->GetTitle(),"][");
927  bname = branchname;
928  while (*bname) {
929  if (*bname == '.') *bname='_';
930  if (*bname == ',') *bname='_';
931  if (*bname == ':') *bname='_';
932  if (*bname == '<') *bname='_';
933  if (*bname == '>') *bname='_';
934  bname++;
935  }
936  if (branch->IsA() == TBranchObject::Class()) {
937  if (branch->GetListOfBranches()->GetEntriesFast()) {leafStatus[l] = 1; continue;}
938  leafobj = (TLeafObject*)leaf;
939  if (!leafobj->GetClass()) {leafStatus[l] = 1; head = headcom;}
940  fprintf(fp,"%s%-15s *%s;\n",head,leafobj->GetTypeName(), leafobj->GetName());
941  if (leafStatus[l] == 0) mustInit.Add(leafobj);
942  continue;
943  }
944  if (leafcount) {
945  len = leafcount->GetMaximum();
946  if (len<=0) len = 1;
947  strlcpy(blen,leafcount->GetName(),sizeof(blen));
948  bname = &blen[0];
949  while (*bname) {
950  if (*bname == '.') *bname='_';
951  if (*bname == ',') *bname='_';
952  if (*bname == ':') *bname='_';
953  if (*bname == '<') *bname='_';
954  if (*bname == '>') *bname='_';
955  bname++;
956  }
957  lenb = strlen(blen);
958  if (blen[lenb-1] == '_') {blen[lenb-1] = 0; kmax = 1;}
959  else snprintf(blen,sizeof(blen),"%d",len);
960  }
961  if (branch->IsA() == TBranchElement::Class()) {
962  bre = (TBranchElement*)branch;
963  if (bre->GetType() != 3 && bre->GetType() != 4
964  && bre->GetStreamerType() <= 0 && bre->GetListOfBranches()->GetEntriesFast()) {
965  leafStatus[l] = 0;
966  }
967  if (bre->GetType() == 3 || bre->GetType() == 4) {
968  fprintf(fp," %-15s %s_;\n","Int_t", branchname);
969  continue;
970  }
971  if (bre->IsBranchFolder()) {
972  fprintf(fp," %-15s *%s;\n",bre->GetClassName(), branchname);
973  mustInit.Add(bre);
974  continue;
975  } else {
976  if (branch->GetListOfBranches()->GetEntriesFast()) {leafStatus[l] = 1;}
977  }
978  if (bre->GetStreamerType() < 0) {
979  if (branch->GetListOfBranches()->GetEntriesFast()) {
980  fprintf(fp,"%s%-15s *%s;\n",headcom,bre->GetClassName(), branchname);
981  } else {
982  fprintf(fp,"%s%-15s *%s;\n",head,bre->GetClassName(), branchname);
983  mustInit.Add(bre);
984  }
985  continue;
986  }
987  if (bre->GetStreamerType() == 0) {
988  if (!TClass::GetClass(bre->GetClassName())->HasInterpreterInfo()) {leafStatus[l] = 1; head = headcom;}
989  fprintf(fp,"%s%-15s *%s;\n",head,bre->GetClassName(), branchname);
990  if (leafStatus[l] == 0) mustInit.Add(bre);
991  continue;
992  }
993  if (bre->GetStreamerType() > 60) {
994  TClass *cle = TClass::GetClass(bre->GetClassName());
995  if (!cle) {leafStatus[l] = 1; continue;}
996  if (bre->GetStreamerType() == 66) leafStatus[l] = 0;
997  char brename[256];
998  strlcpy(brename,bre->GetName(),255);
999  char *bren = brename;
1000  char *adot = strrchr(bren,'.');
1001  if (adot) bren = adot+1;
1002  char *brack = strchr(bren,'[');
1003  if (brack) *brack = 0;
1004  TStreamerElement *elem = (TStreamerElement*)cle->GetStreamerInfo()->GetElements()->FindObject(bren);
1005  if (elem) {
1006  if (elem->IsA() == TStreamerBase::Class()) {leafStatus[l] = 1; continue;}
1007  if (!TClass::GetClass(elem->GetTypeName())) {leafStatus[l] = 1; continue;}
1008  if (!TClass::GetClass(elem->GetTypeName())->HasInterpreterInfo()) {leafStatus[l] = 1; head = headcom;}
1009  if (leafcount) fprintf(fp,"%s%-15s %s[kMax%s];\n",head,elem->GetTypeName(), branchname,blen);
1010  else fprintf(fp,"%s%-15s %s;\n",head,elem->GetTypeName(), branchname);
1011  } else {
1012  if (!TClass::GetClass(bre->GetClassName())->HasInterpreterInfo()) {leafStatus[l] = 1; head = headcom;}
1013  fprintf(fp,"%s%-15s %s;\n",head,bre->GetClassName(), branchname);
1014  }
1015  continue;
1016  }
1017  }
1018  if (strlen(leaf->GetTypeName()) == 0) {leafStatus[l] = 1; continue;}
1019  if (leafcount) {
1020  //len = leafcount->GetMaximum();
1021  //strlcpy(blen,leafcount->GetName(),sizeof(blen));
1022  //bname = &blen[0];
1023  //while (*bname) {if (*bname == '.') *bname='_'; bname++;}
1024  //lenb = strlen(blen);
1025  //Int_t kmax = 0;
1026  //if (blen[lenb-1] == '_') {blen[lenb-1] = 0; kmax = 1;}
1027  //else sprintf(blen,"%d",len);
1028 
1029  const char *stars = " ";
1030  if (bre && bre->GetBranchCount2()) {
1031  stars = "*";
1032  }
1033  // Dimensions can be in the branchname for a split Object with a fix length C array.
1034  // Theses dimensions HAVE TO be placed after the dimension explicited by leafcount
1035  TString dimensions;
1036  char *dimInName = (char*) strstr(branchname,"[");
1037  if ( twodim || dimInName ) {
1038  if (dimInName) {
1039  dimensions = dimInName;
1040  dimInName[0] = 0; // terminate branchname before the array dimensions.
1041  }
1042  if (twodim) dimensions += (char*)(twodim+1);
1043  }
1044  const char* leafcountName = leafcount->GetName();
1045  char b2len[1024];
1046  if (bre && bre->GetBranchCount2()) {
1047  TLeaf * l2 = (TLeaf*)bre->GetBranchCount2()->GetListOfLeaves()->At(0);
1048  strlcpy(b2len,l2->GetName(),sizeof(b2len));
1049  bname = &b2len[0];
1050  while (*bname) {
1051  if (*bname == '.') *bname='_';
1052  if (*bname == ',') *bname='_';
1053  if (*bname == ':') *bname='_';
1054  if (*bname == '<') *bname='_';
1055  if (*bname == '>') *bname='_';
1056  bname++;
1057  }
1058  leafcountName = b2len;
1059  }
1060  if (dimensions.Length()) {
1061  if (kmax) fprintf(fp," %-14s %s%s[kMax%s]%s; //[%s]\n",leaf->GetTypeName(), stars,
1062  branchname,blen,dimensions.Data(),leafcountName);
1063  else fprintf(fp," %-14s %s%s[%d]%s; //[%s]\n",leaf->GetTypeName(), stars,
1064  branchname,len,dimensions.Data(),leafcountName);
1065  } else {
1066  if (kmax) fprintf(fp," %-14s %s%s[kMax%s]; //[%s]\n",leaf->GetTypeName(), stars, branchname,blen,leafcountName);
1067  else fprintf(fp," %-14s %s%s[%d]; //[%s]\n",leaf->GetTypeName(), stars, branchname,len,leafcountName);
1068  }
1069  if (stars[0]=='*') {
1070  TNamed *n;
1071  if (kmax) n = new TNamed(branchname, Form("kMax%s",blen));
1072  else n = new TNamed(branchname, Form("%d",len));
1073  mustInitArr.Add(n);
1074  }
1075  } else {
1076  if (strstr(branchname,"[")) len = 1;
1077  if (len < 2) fprintf(fp," %-15s %s;\n",leaf->GetTypeName(), branchname);
1078  else {
1079  if (twodim) fprintf(fp," %-15s %s%s;\n",leaf->GetTypeName(), branchname,(char*)strstr(leaf->GetTitle(),"["));
1080  else fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
1081  }
1082  }
1083  }
1084 
1085 // generate list of branches
1086  fprintf(fp,"\n");
1087  fprintf(fp," // List of branches\n");
1088  for (l=0;l<nleaves;l++) {
1089  if (leafStatus[l]) continue;
1090  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
1091  fprintf(fp," TBranch *b_%s; //!\n",R__GetBranchPointerName(leaf).Data());
1092  }
1093 
1094 // generate class member functions prototypes
1095  if (opt.Contains("selector")) {
1096  fprintf(fp,"\n");
1097  fprintf(fp," %s(TTree * /*tree*/ =0) : fChain(0) { }\n",classname) ;
1098  fprintf(fp," virtual ~%s() { }\n",classname);
1099  fprintf(fp," virtual Int_t Version() const { return 2; }\n");
1100  fprintf(fp," virtual void Begin(TTree *tree);\n");
1101  fprintf(fp," virtual void SlaveBegin(TTree *tree);\n");
1102  fprintf(fp," virtual void Init(TTree *tree);\n");
1103  fprintf(fp," virtual Bool_t Notify();\n");
1104  fprintf(fp," virtual Bool_t Process(Long64_t entry);\n");
1105  fprintf(fp," virtual Int_t GetEntry(Long64_t entry, Int_t getall = 0) { return fChain ? fChain->GetTree()->GetEntry(entry, getall) : 0; }\n");
1106  fprintf(fp," virtual void SetOption(const char *option) { fOption = option; }\n");
1107  fprintf(fp," virtual void SetObject(TObject *obj) { fObject = obj; }\n");
1108  fprintf(fp," virtual void SetInputList(TList *input) { fInput = input; }\n");
1109  fprintf(fp," virtual TList *GetOutputList() const { return fOutput; }\n");
1110  fprintf(fp," virtual void SlaveTerminate();\n");
1111  fprintf(fp," virtual void Terminate();\n\n");
1112  fprintf(fp," ClassDef(%s,0);\n",classname);
1113  fprintf(fp,"};\n");
1114  fprintf(fp,"\n");
1115  fprintf(fp,"#endif\n");
1116  fprintf(fp,"\n");
1117  } else {
1118  fprintf(fp,"\n");
1119  fprintf(fp," %s(TTree *tree=0);\n",classname);
1120  fprintf(fp," virtual ~%s();\n",classname);
1121  fprintf(fp," virtual Int_t Cut(Long64_t entry);\n");
1122  fprintf(fp," virtual Int_t GetEntry(Long64_t entry);\n");
1123  fprintf(fp," virtual Long64_t LoadTree(Long64_t entry);\n");
1124  fprintf(fp," virtual void Init(TTree *tree);\n");
1125  fprintf(fp," virtual void Loop();\n");
1126  fprintf(fp," virtual Bool_t Notify();\n");
1127  fprintf(fp," virtual void Show(Long64_t entry = -1);\n");
1128  fprintf(fp,"};\n");
1129  fprintf(fp,"\n");
1130  fprintf(fp,"#endif\n");
1131  fprintf(fp,"\n");
1132  }
1133 // generate code for class constructor
1134  fprintf(fp,"#ifdef %s_cxx\n",classname);
1135  if (!opt.Contains("selector")) {
1136  fprintf(fp,"%s::%s(TTree *tree) : fChain(0) \n",classname,classname);
1137  fprintf(fp,"{\n");
1138  fprintf(fp,"// if parameter tree is not specified (or zero), connect the file\n");
1139  fprintf(fp,"// used to generate this class and read the Tree.\n");
1140  fprintf(fp," if (tree == 0) {\n");
1141  if (ischain) {
1142  fprintf(fp,"\n#ifdef SINGLE_TREE\n");
1143  fprintf(fp," // The following code should be used if you want this class to access\n");
1144  fprintf(fp," // a single tree instead of a chain\n");
1145  }
1146  if (isHbook) {
1147  fprintf(fp," THbookFile *f = (THbookFile*)gROOT->GetListOfBrowsables()->FindObject(\"%s\");\n",
1148  treefile.Data());
1149  fprintf(fp," if (!f) {\n");
1150  fprintf(fp," f = new THbookFile(\"%s\");\n",treefile.Data());
1151  fprintf(fp," }\n");
1152  Int_t hid;
1153  sscanf(fTree->GetName(),"h%d",&hid);
1154  fprintf(fp," tree = (TTree*)f->Get(%d);\n\n",hid);
1155  } else {
1156  fprintf(fp," TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(\"%s\");\n",treefile.Data());
1157  fprintf(fp," if (!f || !f->IsOpen()) {\n");
1158  fprintf(fp," f = new TFile(\"%s\");\n",treefile.Data());
1159  fprintf(fp," }\n");
1160  if (fTree->GetDirectory() != fTree->GetCurrentFile()) {
1161  fprintf(fp," TDirectory * dir = (TDirectory*)f->Get(\"%s\");\n",fTree->GetDirectory()->GetPath());
1162  fprintf(fp," dir->GetObject(\"%s\",tree);\n\n",fTree->GetName());
1163  } else {
1164  fprintf(fp," f->GetObject(\"%s\",tree);\n\n",fTree->GetName());
1165  }
1166  }
1167  if (ischain) {
1168  fprintf(fp,"#else // SINGLE_TREE\n\n");
1169  fprintf(fp," // The following code should be used if you want this class to access a chain\n");
1170  fprintf(fp," // of trees.\n");
1171  fprintf(fp," TChain * chain = new TChain(\"%s\",\"%s\");\n",
1172  fTree->GetName(),fTree->GetTitle());
1173  {
1174  R__LOCKGUARD(gROOTMutex);
1175  TIter next(((TChain*)fTree)->GetListOfFiles());
1176  TChainElement *element;
1177  while ((element = (TChainElement*)next())) {
1178  fprintf(fp," chain->Add(\"%s/%s\");\n",element->GetTitle(),element->GetName());
1179  }
1180  }
1181  fprintf(fp," tree = chain;\n");
1182  fprintf(fp,"#endif // SINGLE_TREE\n\n");
1183  }
1184  fprintf(fp," }\n");
1185  fprintf(fp," Init(tree);\n");
1186  fprintf(fp,"}\n");
1187  fprintf(fp,"\n");
1188  }
1189 
1190 // generate code for class destructor()
1191  if (!opt.Contains("selector")) {
1192  fprintf(fp,"%s::~%s()\n",classname,classname);
1193  fprintf(fp,"{\n");
1194  fprintf(fp," if (!fChain) return;\n");
1195  if (isHbook) {
1196  //fprintf(fp," delete fChain->GetCurrentFile();\n");
1197  } else {
1198  fprintf(fp," delete fChain->GetCurrentFile();\n");
1199  }
1200  fprintf(fp,"}\n");
1201  fprintf(fp,"\n");
1202  }
1203 // generate code for class member function GetEntry()
1204  if (!opt.Contains("selector")) {
1205  fprintf(fp,"Int_t %s::GetEntry(Long64_t entry)\n",classname);
1206  fprintf(fp,"{\n");
1207  fprintf(fp,"// Read contents of entry.\n");
1208 
1209  fprintf(fp," if (!fChain) return 0;\n");
1210  fprintf(fp," return fChain->GetEntry(entry);\n");
1211  fprintf(fp,"}\n");
1212  }
1213 // generate code for class member function LoadTree()
1214  if (!opt.Contains("selector")) {
1215  fprintf(fp,"Long64_t %s::LoadTree(Long64_t entry)\n",classname);
1216  fprintf(fp,"{\n");
1217  fprintf(fp,"// Set the environment to read one entry\n");
1218  fprintf(fp," if (!fChain) return -5;\n");
1219  fprintf(fp," Long64_t centry = fChain->LoadTree(entry);\n");
1220  fprintf(fp," if (centry < 0) return centry;\n");
1221  fprintf(fp," if (fChain->GetTreeNumber() != fCurrent) {\n");
1222  fprintf(fp," fCurrent = fChain->GetTreeNumber();\n");
1223  fprintf(fp," Notify();\n");
1224  fprintf(fp," }\n");
1225  fprintf(fp," return centry;\n");
1226  fprintf(fp,"}\n");
1227  fprintf(fp,"\n");
1228  }
1229 
1230 // generate code for class member function Init(), first pass = get branch pointer
1231  fprintf(fp,"void %s::Init(TTree *tree)\n",classname);
1232  fprintf(fp,"{\n");
1233  fprintf(fp," // The Init() function is called when the selector needs to initialize\n"
1234  " // a new tree or chain. Typically here the branch addresses and branch\n"
1235  " // pointers of the tree will be set.\n"
1236  " // It is normally not necessary to make changes to the generated\n"
1237  " // code, but the routine can be extended by the user if needed.\n"
1238  " // Init() will be called many times when running on PROOF\n"
1239  " // (once per file to be processed).\n\n");
1240  if (mustInit.Last()) {
1241  TIter next(&mustInit);
1242  TObject *obj;
1243  fprintf(fp," // Set object pointer\n");
1244  while( (obj = next()) ) {
1245  if (obj->InheritsFrom(TBranch::Class())) {
1246  strlcpy(branchname,((TBranch*)obj)->GetName(),sizeof(branchname));
1247  } else if (obj->InheritsFrom(TLeaf::Class())) {
1248  strlcpy(branchname,((TLeaf*)obj)->GetName(),sizeof(branchname));
1249  }
1250  branchname[1023]=0;
1251  bname = branchname;
1252  while (*bname) {
1253  if (*bname == '.') *bname='_';
1254  if (*bname == ',') *bname='_';
1255  if (*bname == ':') *bname='_';
1256  if (*bname == '<') *bname='_';
1257  if (*bname == '>') *bname='_';
1258  bname++;
1259  }
1260  fprintf(fp," %s = 0;\n",branchname );
1261  }
1262  }
1263  if (mustInitArr.Last()) {
1264  TIter next(&mustInitArr);
1265  TNamed *info;
1266  fprintf(fp," // Set array pointer\n");
1267  while( (info = (TNamed*)next()) ) {
1268  fprintf(fp," for(int i=0; i<%s; ++i) %s[i] = 0;\n",info->GetTitle(),info->GetName());
1269  }
1270  fprintf(fp,"\n");
1271  }
1272  fprintf(fp," // Set branch addresses and branch pointers\n");
1273  fprintf(fp," if (!tree) return;\n");
1274  fprintf(fp," fChain = tree;\n");
1275  if (!opt.Contains("selector")) fprintf(fp," fCurrent = -1;\n");
1276  fprintf(fp," fChain->SetMakeClass(1);\n");
1277  fprintf(fp,"\n");
1278  for (l=0;l<nleaves;l++) {
1279  if (leafStatus[l]) continue;
1280  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
1281  len = leaf->GetLen();
1282  leafcount =leaf->GetLeafCount();
1283  TBranch *branch = leaf->GetBranch();
1284  strlcpy(aprefix,branch->GetName(),sizeof(aprefix));
1285 
1286  if ( branch->GetNleaves() > 1) {
1287  // More than one leaf for the branch we need to distinguish them
1288  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1289  strlcat(branchname,".",sizeof(branchname));
1290  strlcat(branchname,leaf->GetTitle(),sizeof(branchname));
1291  if (leafcount) {
1292  // remove any dimension in title
1293  char *dim = (char*)strstr(branchname,"["); if (dim) dim[0] = 0;
1294  }
1295  } else {
1296  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1297  if (branch->IsA() == TBranchElement::Class()) {
1298  bre = (TBranchElement*)branch;
1299  if (bre->GetType() == 3 || bre->GetType()==4) strlcat(branchname,"_",sizeof(branchname));
1300  }
1301  }
1302  bname = branchname;
1303  char *brak = strstr(branchname,"["); if (brak) *brak = 0;
1304  char *twodim = (char*)strstr(bname,"["); if (twodim) *twodim = 0;
1305  while (*bname) {
1306  if (*bname == '.') *bname='_';
1307  if (*bname == ',') *bname='_';
1308  if (*bname == ':') *bname='_';
1309  if (*bname == '<') *bname='_';
1310  if (*bname == '>') *bname='_';
1311  bname++;
1312  }
1313  const char *maybedisable = "";
1314  if (branch != fTree->GetBranch(branch->GetName())) {
1315  Error("MakeClass","The branch named %s (full path name: %s) is hidden by another branch of the same name and its data will not be loaded.",branch->GetName(),R__GetBranchPointerName(leaf,kFALSE).Data());
1316  maybedisable = "// ";
1317  }
1318  if (branch->IsA() == TBranchObject::Class()) {
1319  if (branch->GetListOfBranches()->GetEntriesFast()) {
1320  fprintf(fp,"%s fChain->SetBranchAddress(\"%s\",(void*)-1,&b_%s);\n",maybedisable,branch->GetName(),R__GetBranchPointerName(leaf).Data());
1321  continue;
1322  }
1323  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1324  }
1325  if (branch->IsA() == TBranchElement::Class()) {
1326  if (((TBranchElement*)branch)->GetType() == 3) len =1;
1327  if (((TBranchElement*)branch)->GetType() == 4) len =1;
1328  }
1329  if (leafcount) len = leafcount->GetMaximum()+1;
1330  if (len > 1) fprintf(fp,"%s fChain->SetBranchAddress(\"%s\", %s, &b_%s);\n",
1331  maybedisable,branch->GetName(), branchname, R__GetBranchPointerName(leaf).Data());
1332  else fprintf(fp,"%s fChain->SetBranchAddress(\"%s\", &%s, &b_%s);\n",
1333  maybedisable,branch->GetName(), branchname, R__GetBranchPointerName(leaf).Data());
1334  }
1335  //must call Notify in case of MakeClass
1336  if (!opt.Contains("selector")) {
1337  fprintf(fp," Notify();\n");
1338  }
1339 
1340  fprintf(fp,"}\n");
1341  fprintf(fp,"\n");
1342 
1343 // generate code for class member function Notify()
1344  fprintf(fp,"Bool_t %s::Notify()\n",classname);
1345  fprintf(fp,"{\n");
1346  fprintf(fp," // The Notify() function is called when a new file is opened. This\n"
1347  " // can be either for a new TTree in a TChain or when when a new TTree\n"
1348  " // is started when using PROOF. It is normally not necessary to make changes\n"
1349  " // to the generated code, but the routine can be extended by the\n"
1350  " // user if needed. The return value is currently not used.\n\n");
1351  fprintf(fp," return kTRUE;\n");
1352  fprintf(fp,"}\n");
1353  fprintf(fp,"\n");
1354 
1355 // generate code for class member function Show()
1356  if (!opt.Contains("selector")) {
1357  fprintf(fp,"void %s::Show(Long64_t entry)\n",classname);
1358  fprintf(fp,"{\n");
1359  fprintf(fp,"// Print contents of entry.\n");
1360  fprintf(fp,"// If entry is not specified, print current entry\n");
1361 
1362  fprintf(fp," if (!fChain) return;\n");
1363  fprintf(fp," fChain->Show(entry);\n");
1364  fprintf(fp,"}\n");
1365  }
1366 // generate code for class member function Cut()
1367  if (!opt.Contains("selector")) {
1368  fprintf(fp,"Int_t %s::Cut(Long64_t entry)\n",classname);
1369  fprintf(fp,"{\n");
1370  fprintf(fp,"// This function may be called from Loop.\n");
1371  fprintf(fp,"// returns 1 if entry is accepted.\n");
1372  fprintf(fp,"// returns -1 otherwise.\n");
1373 
1374  fprintf(fp," return 1;\n");
1375  fprintf(fp,"}\n");
1376  }
1377  fprintf(fp,"#endif // #ifdef %s_cxx\n",classname);
1378 
1379 //======================Generate classname.C=====================
1380  if (!opt.Contains("selector")) {
1381  // generate code for class member function Loop()
1382  fprintf(fpc,"#define %s_cxx\n",classname);
1383  fprintf(fpc,"#include \"%s\"\n",thead.Data());
1384  fprintf(fpc,"#include <TH2.h>\n");
1385  fprintf(fpc,"#include <TStyle.h>\n");
1386  fprintf(fpc,"#include <TCanvas.h>\n");
1387  fprintf(fpc,"\n");
1388  fprintf(fpc,"void %s::Loop()\n",classname);
1389  fprintf(fpc,"{\n");
1390  fprintf(fpc,"// In a ROOT session, you can do:\n");
1391  fprintf(fpc,"// root> .L %s.C\n",classname);
1392  fprintf(fpc,"// root> %s t\n",classname);
1393  fprintf(fpc,"// root> t.GetEntry(12); // Fill t data members with entry number 12\n");
1394  fprintf(fpc,"// root> t.Show(); // Show values of entry 12\n");
1395  fprintf(fpc,"// root> t.Show(16); // Read and show values of entry 16\n");
1396  fprintf(fpc,"// root> t.Loop(); // Loop on all entries\n");
1397  fprintf(fpc,"//\n");
1398  fprintf(fpc,"\n// This is the loop skeleton where:\n");
1399  fprintf(fpc,"// jentry is the global entry number in the chain\n");
1400  fprintf(fpc,"// ientry is the entry number in the current Tree\n");
1401  fprintf(fpc,"// Note that the argument to GetEntry must be:\n");
1402  fprintf(fpc,"// jentry for TChain::GetEntry\n");
1403  fprintf(fpc,"// ientry for TTree::GetEntry and TBranch::GetEntry\n");
1404  fprintf(fpc,"//\n");
1405  fprintf(fpc,"// To read only selected branches, Insert statements like:\n");
1406  fprintf(fpc,"// METHOD1:\n");
1407  fprintf(fpc,"// fChain->SetBranchStatus(\"*\",0); // disable all branches\n");
1408  fprintf(fpc,"// fChain->SetBranchStatus(\"branchname\",1); // activate branchname\n");
1409  fprintf(fpc,"// METHOD2: replace line\n");
1410  fprintf(fpc,"// fChain->GetEntry(jentry); //read all branches\n");
1411  fprintf(fpc,"//by b_branchname->GetEntry(ientry); //read only this branch\n");
1412  fprintf(fpc," if (fChain == 0) return;\n");
1413  fprintf(fpc,"\n Long64_t nentries = fChain->GetEntriesFast();\n");
1414  fprintf(fpc,"\n Long64_t nbytes = 0, nb = 0;\n");
1415  fprintf(fpc," for (Long64_t jentry=0; jentry<nentries;jentry++) {\n");
1416  fprintf(fpc," Long64_t ientry = LoadTree(jentry);\n");
1417  fprintf(fpc," if (ientry < 0) break;\n");
1418  fprintf(fpc," nb = fChain->GetEntry(jentry); nbytes += nb;\n");
1419  fprintf(fpc," // if (Cut(ientry) < 0) continue;\n");
1420  fprintf(fpc," }\n");
1421  fprintf(fpc,"}\n");
1422  }
1423  if (opt.Contains("selector")) {
1424  // generate usage comments and list of includes
1425  fprintf(fpc,"#define %s_cxx\n",classname);
1426  fprintf(fpc,"// The class definition in %s.h has been generated automatically\n",classname);
1427  fprintf(fpc,"// by the ROOT utility TTree::MakeSelector(). This class is derived\n");
1428  fprintf(fpc,"// from the ROOT class TSelector. For more information on the TSelector\n"
1429  "// framework see $ROOTSYS/README/README.SELECTOR or the ROOT User Manual.\n\n");
1430  fprintf(fpc,"// The following methods are defined in this file:\n");
1431  fprintf(fpc,"// Begin(): called every time a loop on the tree starts,\n");
1432  fprintf(fpc,"// a convenient place to create your histograms.\n");
1433  fprintf(fpc,"// SlaveBegin(): called after Begin(), when on PROOF called only on the\n"
1434  "// slave servers.\n");
1435  fprintf(fpc,"// Process(): called for each event, in this function you decide what\n");
1436  fprintf(fpc,"// to read and fill your histograms.\n");
1437  fprintf(fpc,"// SlaveTerminate: called at the end of the loop on the tree, when on PROOF\n"
1438  "// called only on the slave servers.\n");
1439  fprintf(fpc,"// Terminate(): called at the end of the loop on the tree,\n");
1440  fprintf(fpc,"// a convenient place to draw/fit your histograms.\n");
1441  fprintf(fpc,"//\n");
1442  fprintf(fpc,"// To use this file, try the following session on your Tree T:\n");
1443  fprintf(fpc,"//\n");
1444  fprintf(fpc,"// root> T->Process(\"%s.C\")\n",classname);
1445  fprintf(fpc,"// root> T->Process(\"%s.C\",\"some options\")\n",classname);
1446  fprintf(fpc,"// root> T->Process(\"%s.C+\")\n",classname);
1447  fprintf(fpc,"//\n\n");
1448  fprintf(fpc,"#include \"%s\"\n",thead.Data());
1449  fprintf(fpc,"#include <TH2.h>\n");
1450  fprintf(fpc,"#include <TStyle.h>\n");
1451  fprintf(fpc,"\n");
1452  // generate code for class member function Begin
1453  fprintf(fpc,"\n");
1454  fprintf(fpc,"void %s::Begin(TTree * /*tree*/)\n",classname);
1455  fprintf(fpc,"{\n");
1456  fprintf(fpc," // The Begin() function is called at the start of the query.\n");
1457  fprintf(fpc," // When running with PROOF Begin() is only called on the client.\n");
1458  fprintf(fpc," // The tree argument is deprecated (on PROOF 0 is passed).\n");
1459  fprintf(fpc,"\n");
1460  fprintf(fpc," TString option = GetOption();\n");
1461  fprintf(fpc,"\n");
1462  fprintf(fpc,"}\n");
1463  // generate code for class member function SlaveBegin
1464  fprintf(fpc,"\n");
1465  fprintf(fpc,"void %s::SlaveBegin(TTree * /*tree*/)\n",classname);
1466  fprintf(fpc,"{\n");
1467  fprintf(fpc," // The SlaveBegin() function is called after the Begin() function.\n");
1468  fprintf(fpc," // When running with PROOF SlaveBegin() is called on each slave server.\n");
1469  fprintf(fpc," // The tree argument is deprecated (on PROOF 0 is passed).\n");
1470  fprintf(fpc,"\n");
1471  fprintf(fpc," TString option = GetOption();\n");
1472  fprintf(fpc,"\n");
1473  fprintf(fpc,"}\n");
1474  // generate code for class member function Process
1475  fprintf(fpc,"\n");
1476  fprintf(fpc,"Bool_t %s::Process(Long64_t entry)\n",classname);
1477  fprintf(fpc,"{\n");
1478  fprintf(fpc," // The Process() function is called for each entry in the tree (or possibly\n"
1479  " // keyed object in the case of PROOF) to be processed. The entry argument\n"
1480  " // specifies which entry in the currently loaded tree is to be processed.\n"
1481  " // It can be passed to either %s::GetEntry() or TBranch::GetEntry()\n"
1482  " // to read either all or the required parts of the data. When processing\n"
1483  " // keyed objects with PROOF, the object is already loaded and is available\n"
1484  " // via the fObject pointer.\n"
1485  " //\n"
1486  " // This function should contain the \"body\" of the analysis. It can contain\n"
1487  " // simple or elaborate selection criteria, run algorithms on the data\n"
1488  " // of the event and typically fill histograms.\n"
1489  " //\n"
1490  " // The processing can be stopped by calling Abort().\n"
1491  " //\n"
1492  " // Use fStatus to set the return value of TTree::Process().\n"
1493  " //\n"
1494  " // The return value is currently not used.\n\n", classname);
1495  fprintf(fpc,"\n");
1496  fprintf(fpc," return kTRUE;\n");
1497  fprintf(fpc,"}\n");
1498  // generate code for class member function SlaveTerminate
1499  fprintf(fpc,"\n");
1500  fprintf(fpc,"void %s::SlaveTerminate()\n",classname);
1501  fprintf(fpc,"{\n");
1502  fprintf(fpc," // The SlaveTerminate() function is called after all entries or objects\n"
1503  " // have been processed. When running with PROOF SlaveTerminate() is called\n"
1504  " // on each slave server.");
1505  fprintf(fpc,"\n");
1506  fprintf(fpc,"\n");
1507  fprintf(fpc,"}\n");
1508  // generate code for class member function Terminate
1509  fprintf(fpc,"\n");
1510  fprintf(fpc,"void %s::Terminate()\n",classname);
1511  fprintf(fpc,"{\n");
1512  fprintf(fpc," // The Terminate() function is the last function to be called during\n"
1513  " // a query. It always runs on the client, it can be used to present\n"
1514  " // the results graphically or save the results to file.");
1515  fprintf(fpc,"\n");
1516  fprintf(fpc,"\n");
1517  fprintf(fpc,"}\n");
1518  }
1519  Info("MakeClass","Files: %s and %s generated from TTree: %s",thead.Data(),tcimp.Data(),fTree->GetName());
1520  delete [] leafStatus;
1521  fclose(fp);
1522  fclose(fpc);
1523 
1524  return 0;
1525 }
1526 
1527 
1528 ////////////////////////////////////////////////////////////////////////////////
1529 /// Generate skeleton function for this Tree
1530 ///
1531 /// The function code is written on filename.
1532 /// If filename is 0, filename will be called nameoftree.C
1533 ///
1534 /// The generated code includes the following:
1535 /// - Identification of the original Tree and Input file name
1536 /// - Connection of the Tree file
1537 /// - Declaration of Tree variables
1538 /// - Setting of branches addresses
1539 /// - A skeleton for the entry loop
1540 ///
1541 /// To use this function:
1542 /// - connect your Tree file (eg: TFile f("myfile.root");)
1543 /// - T->MakeCode("anal.C");
1544 /// where T is the name of the Tree in file myfile.root
1545 /// and anal.C the name of the file created by this function.
1546 ///
1547 /// NOTE: Since the implementation of this function, a new and better
1548 /// function TTree::MakeClass() has been developed.
1549 
1550 Int_t TTreePlayer::MakeCode(const char *filename)
1551 {
1552 // Connect output file
1553  TString tfile;
1554  if (filename)
1555  tfile = filename;
1556  else
1557  tfile.Form("%s.C", fTree->GetName());
1558  FILE *fp = fopen(tfile, "w");
1559  if (!fp) {
1560  Error("MakeCode","cannot open output file %s", tfile.Data());
1561  return 3;
1562  }
1563  TString treefile;
1564  if (fTree->GetDirectory() && fTree->GetDirectory()->GetFile()) {
1565  treefile = fTree->GetDirectory()->GetFile()->GetName();
1566  } else {
1567  treefile = "Memory Directory";
1568  }
1569  // In the case of a chain, the GetDirectory information usually does
1570  // pertain to the Chain itself but to the currently loaded tree.
1571  // So we can not rely on it.
1572  Bool_t ischain = fTree->InheritsFrom(TChain::Class());
1573 
1574 // Print header
1575  TObjArray *leaves = fTree->GetListOfLeaves();
1576  Int_t nleaves = leaves ? leaves->GetEntriesFast() : 0;
1577  TDatime td;
1578  fprintf(fp,"{\n");
1579  fprintf(fp,"//////////////////////////////////////////////////////////\n");
1580  fprintf(fp,"// This file has been automatically generated \n");
1581  fprintf(fp,"// (%s by ROOT version%s)\n",td.AsString(),gROOT->GetVersion());
1582  if (!ischain) {
1583  fprintf(fp,"// from TTree %s/%s\n",fTree->GetName(),fTree->GetTitle());
1584  fprintf(fp,"// found on file: %s\n",treefile.Data());
1585  } else {
1586  fprintf(fp,"// from TChain %s/%s\n",fTree->GetName(),fTree->GetTitle());
1587  }
1588  fprintf(fp,"//////////////////////////////////////////////////////////\n");
1589  fprintf(fp,"\n");
1590  fprintf(fp,"\n");
1591 
1592 
1593 // Reset and file connect
1594  fprintf(fp,"//Reset ROOT and connect tree file\n");
1595  fprintf(fp," gROOT->Reset();\n");
1596  if (ischain) {
1597  fprintf(fp,"\n#ifdef SINGLE_TREE\n");
1598  fprintf(fp," // The following code should be used if you want this code to access\n");
1599  fprintf(fp," // a single tree instead of a chain\n");
1600  }
1601  fprintf(fp," TFile *f = (TFile*)gROOT->GetListOfFiles()->FindObject(\"%s\");\n",treefile.Data());
1602  fprintf(fp," if (!f) {\n");
1603  fprintf(fp," f = new TFile(\"%s\");\n",treefile.Data());
1604  fprintf(fp," }\n");
1605  if (fTree->GetDirectory() != fTree->GetCurrentFile()) {
1606  fprintf(fp," TDirectory * dir = (TDirectory*)f->Get(\"%s\");\n",fTree->GetDirectory()->GetPath());
1607  fprintf(fp," dir->GetObject(\"%s\",tree);\n\n",fTree->GetName());
1608  } else {
1609  fprintf(fp," f->GetObject(\"%s\",tree);\n\n",fTree->GetName());
1610  }
1611  if (ischain) {
1612  fprintf(fp,"#else // SINGLE_TREE\n\n");
1613  fprintf(fp," // The following code should be used if you want this code to access a chain\n");
1614  fprintf(fp," // of trees.\n");
1615  fprintf(fp," TChain *%s = new TChain(\"%s\",\"%s\");\n",
1616  fTree->GetName(),fTree->GetName(),fTree->GetTitle());
1617  {
1618  R__LOCKGUARD(gROOTMutex);
1619  TIter next(((TChain*)fTree)->GetListOfFiles());
1620  TChainElement *element;
1621  while ((element = (TChainElement*)next())) {
1622  fprintf(fp," %s->Add(\"%s/%s\");\n",fTree->GetName(),element->GetTitle(),element->GetName());
1623  }
1624  }
1625  fprintf(fp,"#endif // SINGLE_TREE\n\n");
1626  }
1627 
1628 // First loop on all leaves to generate type declarations
1629  fprintf(fp,"//Declaration of leaves types\n");
1630  Int_t len, l;
1631  TLeaf *leafcount;
1632  TLeafObject *leafobj;
1633  char *bname;
1634  const char *headOK = " ";
1635  const char *headcom = " //";
1636  const char *head;
1637  char branchname[1024];
1638  for (l=0;l<nleaves;l++) {
1639  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
1640  len = leaf->GetLen();
1641  leafcount =leaf->GetLeafCount();
1642  TBranch *branch = leaf->GetBranch();
1643  if (branch->GetListOfBranches()->GetEntriesFast() > 0) continue;
1644 
1645  if ( branch->GetNleaves() > 1) {
1646  // More than one leaf for the branch we need to distinguish them
1647  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1648  strlcat(branchname,".",sizeof(branchname));
1649  strlcat(branchname,leaf->GetTitle(),sizeof(branchname));
1650  if (leafcount) {
1651  // remove any dimension in title
1652  char *dim = (char*)strstr(branchname,"[");
1653  if (dim) dim[0] = 0;
1654  }
1655  } else {
1656  if (leafcount) strlcpy(branchname,branch->GetName(),sizeof(branchname));
1657  else strlcpy(branchname,leaf->GetTitle(),sizeof(branchname));
1658  }
1659  char *twodim = (char*)strstr(leaf->GetTitle(),"][");
1660  bname = branchname;
1661  while (*bname) {
1662  if (*bname == '.') *bname='_';
1663  if (*bname == ',') *bname='_';
1664  if (*bname == ':') *bname='_';
1665  if (*bname == '<') *bname='_';
1666  if (*bname == '>') *bname='_';
1667  bname++;
1668  }
1669  if (branch->IsA() == TBranchObject::Class()) {
1670  leafobj = (TLeafObject*)leaf;
1671  if (leafobj->GetClass()) head = headOK;
1672  else head = headcom;
1673  fprintf(fp,"%s%-15s *%s = 0;\n",head,leafobj->GetTypeName(), leafobj->GetName());
1674  continue;
1675  }
1676  if (leafcount) {
1677  len = leafcount->GetMaximum();
1678  // Dimensions can be in the branchname for a split Object with a fix length C array.
1679  // Theses dimensions HAVE TO be placed after the dimension explicited by leafcount
1680  char *dimInName = (char*) strstr(branchname,"[");
1681  TString dimensions;
1682  if ( twodim || dimInName ) {
1683  if (dimInName) {
1684  dimensions = dimInName;
1685  dimInName[0] = 0; // terminate branchname before the array dimensions.
1686  }
1687  if (twodim) dimensions += (char*)(twodim+1);
1688  }
1689  if (dimensions.Length()) {
1690  fprintf(fp," %-15s %s[%d]%s;\n",leaf->GetTypeName(), branchname,len,dimensions.Data());
1691  } else {
1692  fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
1693  }
1694  } else {
1695  if (strstr(branchname,"[")) len = 1;
1696  if (len < 2) fprintf(fp," %-15s %s;\n",leaf->GetTypeName(), branchname);
1697  else fprintf(fp," %-15s %s[%d];\n",leaf->GetTypeName(), branchname,len);
1698  }
1699  }
1700 
1701 // Second loop on all leaves to set the corresponding branch address
1702  fprintf(fp,"\n // Set branch addresses.\n");
1703  for (l=0;l<nleaves;l++) {
1704  TLeaf *leaf = (TLeaf*)leaves->UncheckedAt(l);
1705  len = leaf->GetLen();
1706  leafcount =leaf->GetLeafCount();
1707  TBranch *branch = leaf->GetBranch();
1708 
1709  if ( branch->GetNleaves() > 1) {
1710  // More than one leaf for the branch we need to distinguish them
1711  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1712  strlcat(branchname,".",sizeof(branchname));
1713  strlcat(branchname,leaf->GetTitle(),sizeof(branchname));
1714  if (leafcount) {
1715  // remove any dimension in title
1716  char *dim = (char*)strstr(branchname,"[");
1717  if (dim) dim[0] = 0;
1718  }
1719  } else {
1720  if (leafcount) strlcpy(branchname,branch->GetName(),sizeof(branchname));
1721  else strlcpy(branchname,leaf->GetTitle(),sizeof(branchname));
1722  }
1723  bname = branchname;
1724  while (*bname) {
1725  if (*bname == '.') *bname='_';
1726  if (*bname == ',') *bname='_';
1727  if (*bname == ':') *bname='_';
1728  if (*bname == '<') *bname='_';
1729  if (*bname == '>') *bname='_';
1730  bname++;
1731  }
1732  char *brak = strstr(branchname,"[");
1733  if (brak) *brak = 0;
1734  head = headOK;
1735  if (branch->IsA() == TBranchObject::Class()) {
1736  strlcpy(branchname,branch->GetName(),sizeof(branchname));
1737  leafobj = (TLeafObject*)leaf;
1738  if (!leafobj->GetClass()) head = headcom;
1739  }
1740  if (leafcount) len = leafcount->GetMaximum()+1;
1741  if (len > 1 || brak) fprintf(fp,"%s%s->SetBranchAddress(\"%s\",%s);\n",head,fTree->GetName(),branch->GetName(),branchname);
1742  else fprintf(fp,"%s%s->SetBranchAddress(\"%s\",&%s);\n",head,fTree->GetName(),branch->GetName(),branchname);
1743  }
1744 
1745 //Generate instructions to make the loop on entries
1746  fprintf(fp,"\n// This is the loop skeleton\n");
1747  fprintf(fp,"// To read only selected branches, Insert statements like:\n");
1748  fprintf(fp,"// %s->SetBranchStatus(\"*\",0); // disable all branches\n",fTree->GetName());
1749  fprintf(fp,"// %s->SetBranchStatus(\"branchname\",1); // activate branchname\n",GetName());
1750  fprintf(fp,"\n Long64_t nentries = %s->GetEntries();\n",fTree->GetName());
1751  fprintf(fp,"\n Long64_t nbytes = 0;\n");
1752  fprintf(fp,"// for (Long64_t i=0; i<nentries;i++) {\n");
1753  fprintf(fp,"// nbytes += %s->GetEntry(i);\n",fTree->GetName());
1754  fprintf(fp,"// }\n");
1755  fprintf(fp,"}\n");
1756 
1757  printf("Macro: %s generated from Tree: %s\n",tfile.Data(), fTree->GetName());
1758  fclose(fp);
1759 
1760  return 0;
1761 }
1762 
1763 ////////////////////////////////////////////////////////////////////////////////
1764 /// Generate a skeleton analysis class for this Tree using TBranchProxy.
1765 /// TBranchProxy is the base of a class hierarchy implementing an
1766 /// indirect access to the content of the branches of a TTree.
1767 ///
1768 /// "proxyClassname" is expected to be of the form:
1769 /// ~~~{.cpp}
1770 /// [path/]fileprefix
1771 /// ~~~
1772 /// The skeleton will then be generated in the file:
1773 /// ~~~{.cpp}
1774 /// fileprefix.h
1775 /// ~~~
1776 /// located in the current directory or in 'path/' if it is specified.
1777 /// The class generated will be named 'fileprefix'.
1778 /// If the fileprefix contains a period, the right side of the period
1779 /// will be used as the extension (instead of 'h') and the left side
1780 /// will be used as the classname.
1781 ///
1782 /// "macrofilename" and optionally "cutfilename" are expected to point
1783 /// to source file which will be included in by the generated skeletong.
1784 /// Method of the same name as the file(minus the extension and path)
1785 /// will be called by the generated skeleton's Process method as follow:
1786 /// ~~~{.cpp}
1787 /// [if (cutfilename())] htemp->Fill(macrofilename());
1788 /// ~~~
1789 /// "option" can be used select some of the optional features during
1790 /// the code generation. The possible options are:
1791 /// - nohist : indicates that the generated ProcessFill should not
1792 /// fill the histogram.
1793 ///
1794 /// 'maxUnrolling' controls how deep in the class hierarchy does the
1795 /// system 'unroll' class that are not split. 'unrolling' a class
1796 /// will allow direct access to its data members a class (this
1797 /// emulates the behavior of TTreeFormula).
1798 ///
1799 /// The main features of this skeleton are:
1800 ///
1801 /// * on-demand loading of branches
1802 /// * ability to use the 'branchname' as if it was a data member
1803 /// * protection against array out-of-bound
1804 /// * ability to use the branch data as object (when the user code is available)
1805 ///
1806 /// For example with Event.root, if
1807 /// ~~~{.cpp}
1808 /// Double_t somepx = fTracks.fPx[2];
1809 /// ~~~
1810 /// is executed by one of the method of the skeleton,
1811 /// somepx will be updated with the current value of fPx of the 3rd track.
1812 ///
1813 /// Both macrofilename and the optional cutfilename are expected to be
1814 /// the name of source files which contain at least a free standing
1815 /// function with the signature:
1816 /// ~~~{.cpp}
1817 /// x_t macrofilename(); // i.e function with the same name as the file
1818 /// ~~~
1819 /// and
1820 /// ~~~{.cpp}
1821 /// y_t cutfilename(); // i.e function with the same name as the file
1822 /// ~~~
1823 /// x_t and y_t needs to be types that can convert respectively to a double
1824 /// and a bool (because the skeleton uses:
1825 /// ~~~{.cpp}
1826 /// if (cutfilename()) htemp->Fill(macrofilename());
1827 /// ~~~
1828 /// This 2 functions are run in a context such that the branch names are
1829 /// available as local variables of the correct (read-only) type.
1830 ///
1831 /// Note that if you use the same 'variable' twice, it is more efficient
1832 /// to 'cache' the value. For example
1833 /// ~~~{.cpp}
1834 /// Int_t n = fEventNumber; // Read fEventNumber
1835 /// if (n<10 || n>10) { ... }
1836 /// ~~~
1837 /// is more efficient than
1838 /// ~~~{.cpp}
1839 /// if (fEventNumber<10 || fEventNumber>10)
1840 /// ~~~
1841 /// Access to TClonesArray.
1842 ///
1843 /// If a branch (or member) is a TClonesArray (let's say fTracks), you
1844 /// can access the TClonesArray itself by using ->:
1845 /// ~~~{.cpp}
1846 /// fTracks->GetLast();
1847 /// ~~~
1848 /// However this will load the full TClonesArray object and its content.
1849 /// To quickly read the size of the TClonesArray use (note the dot):
1850 /// ~~~{.cpp}
1851 /// fTracks.GetEntries();
1852 /// ~~~
1853 /// This will read only the size from disk if the TClonesArray has been
1854 /// split.
1855 /// To access the content of the TClonesArray, use the [] operator:
1856 /// ~~~
1857 /// float px = fTracks[i].fPx; // fPx of the i-th track
1858 /// ~~~
1859 /// Warning:
1860 ///
1861 /// The variable actually use for access are 'wrapper' around the
1862 /// real data type (to add autoload for example) and hence getting to
1863 /// the data involves the implicit call to a C++ conversion operator.
1864 /// This conversion is automatic in most case. However it is not invoked
1865 /// in a few cases, in particular in variadic function (like printf).
1866 /// So when using printf you should either explicitly cast the value or
1867 /// use any intermediary variable:
1868 /// ~~~{.cpp}
1869 /// fprintf(stdout,"trs[%d].a = %d\n",i,(int)trs.a[i]);
1870 /// ~~~
1871 /// Also, optionally, the generated selector will also call methods named
1872 /// macrofilename_methodname in each of 6 main selector methods if the method
1873 /// macrofilename_methodname exist (Where macrofilename is stripped of its
1874 /// extension).
1875 ///
1876 /// Concretely, with the script named h1analysisProxy.C,
1877 ///
1878 /// - The method calls the method (if it exist)
1879 /// - Begin -> void h1analysisProxy_Begin(TTree*);
1880 /// - SlaveBegin -> void h1analysisProxy_SlaveBegin(TTree*);
1881 /// - Notify -> Bool_t h1analysisProxy_Notify();
1882 /// - Process -> Bool_t h1analysisProxy_Process(Long64_t);
1883 /// - SlaveTerminate -> void h1analysisProxy_SlaveTerminate();
1884 /// - Terminate -> void h1analysisProxy_Terminate();
1885 ///
1886 /// If a file name macrofilename.h (or .hh, .hpp, .hxx, .hPP, .hXX) exist
1887 /// it is included before the declaration of the proxy class. This can
1888 /// be used in particular to insure that the include files needed by
1889 /// the macro file are properly loaded.
1890 ///
1891 /// The default histogram is accessible via the variable named 'htemp'.
1892 ///
1893 /// If the library of the classes describing the data in the branch is
1894 /// loaded, the skeleton will add the needed `include` statements and
1895 /// give the ability to access the object stored in the branches.
1896 ///
1897 /// To draw px using the file `hsimple.root (generated by the
1898 /// hsimple.C tutorial), we need a file named hsimple.cxx:
1899 ///
1900 /// ~~~{.cpp}
1901 /// double hsimple() {
1902 /// return px;
1903 /// }
1904 /// ~~~
1905 /// MakeProxy can then be used indirectly via the TTree::Draw interface
1906 /// as follow:
1907 /// ~~~{.cpp}
1908 /// new TFile("hsimple.root")
1909 /// ntuple->Draw("hsimple.cxx");
1910 /// ~~~
1911 /// A more complete example is available in the tutorials directory:
1912 /// h1analysisProxy.cxx , h1analysProxy.h and h1analysisProxyCut.C
1913 /// which reimplement the selector found in h1analysis.C
1914 
1915 Int_t TTreePlayer::MakeProxy(const char *proxyClassname,
1916  const char *macrofilename, const char *cutfilename,
1917  const char *option, Int_t maxUnrolling)
1918 {
1919  if (macrofilename==0 || strlen(macrofilename)==0 ) {
1920  // We currently require a file name for the script
1921  Error("MakeProxy","A file name for the user script is required");
1922  return 0;
1923  }
1924 
1925  ROOT::Internal::TTreeProxyGenerator gp(fTree,macrofilename,cutfilename,proxyClassname,option,maxUnrolling);
1926 
1927  return 0;
1928 }
1929 
1930 
1931 ////////////////////////////////////////////////////////////////////////////////
1932 /// Generate skeleton selector class for this tree.
1933 ///
1934 /// The following files are produced: classname.h and classname.C.
1935 /// If classname is 0, the selector will be called "nameoftree".
1936 /// The option can be used to specify the branches that will have a data member.
1937 /// - If option is empty, readers will be generated for each leaf.
1938 /// - If option is "@", readers will be generated for the topmost branches.
1939 /// - Individual branches can also be picked by their name:
1940 /// - "X" generates readers for leaves of X.
1941 /// - "@X" generates a reader for X as a whole.
1942 /// - "@X;Y" generates a reader for X as a whole and also readers for the
1943 /// leaves of Y.
1944 /// - For further examples see the figure below.
1945 ///
1946 /// \image html ttree_makeselector_option_examples.png
1947 ///
1948 /// The generated code in classname.h includes the following:
1949 /// - Identification of the original Tree and Input file name
1950 /// - Definition of selector class (data and functions)
1951 /// - The following class functions:
1952 /// - constructor and destructor
1953 /// - void Begin(TTree *tree)
1954 /// - void SlaveBegin(TTree *tree)
1955 /// - void Init(TTree *tree)
1956 /// - Bool_t Notify()
1957 /// - Bool_t Process(Long64_t entry)
1958 /// - void Terminate()
1959 /// - void SlaveTerminate()
1960 ///
1961 /// The selector derives from TSelector.
1962 /// The generated code in classname.C includes empty functions defined above.
1963 ///
1964 /// To use this function:
1965 /// - connect your Tree file (eg: `TFile f("myfile.root");`)
1966 /// - `T->MakeSelector("myselect");`
1967 /// where `T` is the name of the Tree in file `myfile.root`
1968 /// and `myselect.h`, `myselect.C` the name of the files created by this
1969 /// function.
1970 ///
1971 /// In a ROOT session, you can do:
1972 /// ~~~ {.cpp}
1973 /// root > T->Process("myselect.C")
1974 /// ~~~
1975 Int_t TTreePlayer::MakeReader(const char *classname, Option_t *option)
1976 {
1977  if (!classname) classname = fTree->GetName();
1978 
1979  ROOT::Internal::TTreeReaderGenerator gsr(fTree, classname, option);
1980 
1981  return 0;
1982 }
1983 
1984 
1985 ////////////////////////////////////////////////////////////////////////////////
1986 /// Interface to the Principal Components Analysis class.
1987 ///
1988 /// Create an instance of TPrincipal
1989 /// Fill it with the selected variables
1990 ///
1991 /// - if option "n" is specified, the TPrincipal object is filled with
1992 /// normalized variables.
1993 /// - If option "p" is specified, compute the principal components
1994 /// - If option "p" and "d" print results of analysis
1995 /// - If option "p" and "h" generate standard histograms
1996 /// - If option "p" and "c" generate code of conversion functions
1997 ///
1998 /// return a pointer to the TPrincipal object. It is the user responsibility
1999 /// to delete this object.
2000 ///
2001 /// The option default value is "np"
2002 ///
2003 /// See TTreePlayer::DrawSelect for explanation of the other parameters.
2004 
2005 TPrincipal *TTreePlayer::Principal(const char *varexp, const char *selection, Option_t *option, Long64_t nentries, Long64_t firstentry)
2006 {
2007  TTreeFormula **var;
2008  std::vector<TString> cnames;
2009  TString opt = option;
2010  opt.ToLower();
2011  TPrincipal *principal = 0;
2012  Long64_t entry,entryNumber;
2013  Int_t i,nch;
2014  Int_t ncols = 8; // by default first 8 columns are printed only
2015  TObjArray *leaves = fTree->GetListOfLeaves();
2016  Int_t nleaves = leaves->GetEntriesFast();
2017  if (nleaves < ncols) ncols = nleaves;
2018  nch = varexp ? strlen(varexp) : 0;
2019 
2020  nentries = GetEntriesToProcess(firstentry, nentries);
2021 
2022 //*-*- Compile selection expression if there is one
2023  TTreeFormula *select = 0;
2024  if (strlen(selection)) {
2025  select = new TTreeFormula("Selection",selection,fTree);
2026  if (!select) return principal;
2027  if (!select->GetNdim()) { delete select; return principal; }
2028  fFormulaList->Add(select);
2029  }
2030 //*-*- if varexp is empty, take first 8 columns by default
2031  int allvar = 0;
2032  if (varexp && !strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
2033  if (nch == 0 || allvar) {
2034  for (i=0;i<ncols;i++) {
2035  cnames.push_back( ((TLeaf*)leaves->At(i))->GetName() );
2036  }
2037 //*-*- otherwise select only the specified columns
2038  } else {
2039  ncols = fSelector->SplitNames(varexp,cnames);
2040  }
2041  var = new TTreeFormula* [ncols];
2042  Double_t *xvars = new Double_t[ncols];
2043 
2044 //*-*- Create the TreeFormula objects corresponding to each column
2045  for (i=0;i<ncols;i++) {
2046  var[i] = new TTreeFormula("Var1",cnames[i].Data(),fTree);
2047  fFormulaList->Add(var[i]);
2048  }
2049 
2050 //*-*- Create a TreeFormulaManager to coordinate the formulas
2051  TTreeFormulaManager *manager=0;
2052  if (fFormulaList->LastIndex()>=0) {
2053  manager = new TTreeFormulaManager;
2054  for(i=0;i<=fFormulaList->LastIndex();i++) {
2055  manager->Add((TTreeFormula*)fFormulaList->At(i));
2056  }
2057  manager->Sync();
2058  }
2059 
2060 //*-* Build the TPrincipal object
2061  if (opt.Contains("n")) principal = new TPrincipal(ncols, "n");
2062  else principal = new TPrincipal(ncols);
2063 
2064 //*-*- loop on all selected entries
2065  fSelectedRows = 0;
2066  Int_t tnumber = -1;
2067  for (entry=firstentry;entry<firstentry+nentries;entry++) {
2068  entryNumber = fTree->GetEntryNumber(entry);
2069  if (entryNumber < 0) break;
2070  Long64_t localEntry = fTree->LoadTree(entryNumber);
2071  if (localEntry < 0) break;
2072  if (tnumber != fTree->GetTreeNumber()) {
2073  tnumber = fTree->GetTreeNumber();
2074  if (manager) manager->UpdateFormulaLeaves();
2075  }
2076  int ndata = 1;
2077  if (manager && manager->GetMultiplicity()) {
2078  ndata = manager->GetNdata();
2079  }
2080 
2081  for(int inst=0;inst<ndata;inst++) {
2082  Bool_t loaded = kFALSE;
2083  if (select) {
2084  if (select->EvalInstance(inst) == 0) {
2085  continue;
2086  }
2087  }
2088 
2089  if (inst==0) loaded = kTRUE;
2090  else if (!loaded) {
2091  // EvalInstance(0) always needs to be called so that
2092  // the proper branches are loaded.
2093  for (i=0;i<ncols;i++) {
2094  var[i]->EvalInstance(0);
2095  }
2096  loaded = kTRUE;
2097  }
2098 
2099  for (i=0;i<ncols;i++) {
2100  xvars[i] = var[i]->EvalInstance(inst);
2101  }
2102  principal->AddRow(xvars);
2103  }
2104  }
2105 
2106  //*-* some actions with principal ?
2107  if (opt.Contains("p")) {
2108  principal->MakePrincipals(); // Do the actual analysis
2109  if (opt.Contains("d")) principal->Print();
2110  if (opt.Contains("h")) principal->MakeHistograms();
2111  if (opt.Contains("c")) principal->MakeCode();
2112  }
2113 
2114 //*-*- delete temporary objects
2115  fFormulaList->Clear();
2116  delete [] var;
2117  delete [] xvars;
2118 
2119  return principal;
2120 }
2121 
2122 ////////////////////////////////////////////////////////////////////////////////
2123 /// Process this tree executing the TSelector code in the specified filename.
2124 /// The return value is -1 in case of error and TSelector::GetStatus() in
2125 /// in case of success.
2126 ///
2127 /// The code in filename is loaded (interpreted or compiled, see below),
2128 /// filename must contain a valid class implementation derived from TSelector,
2129 /// where TSelector has the following member functions:
2130 ///
2131 /// - Begin(): called every time a loop on the tree starts,
2132 /// a convenient place to create your histograms.
2133 /// - SlaveBegin(): called after Begin(), when on PROOF called only on the
2134 /// slave servers.
2135 /// - Process(): called for each event, in this function you decide what
2136 /// to read and fill your histograms.
2137 /// - SlaveTerminate: called at the end of the loop on the tree, when on PROOF
2138 /// called only on the slave servers.
2139 /// - Terminate(): called at the end of the loop on the tree,
2140 /// a convenient place to draw/fit your histograms.
2141 ///
2142 /// If filename is of the form file.C, the file will be interpreted.
2143 /// If filename is of the form file.C++, the file file.C will be compiled
2144 /// and dynamically loaded.
2145 ///
2146 /// If filename is of the form file.C+, the file file.C will be compiled
2147 /// and dynamically loaded. At next call, if file.C is older than file.o
2148 /// and file.so, the file.C is not compiled, only file.so is loaded.
2149 ///
2150 /// ### NOTE 1
2151 /// It may be more interesting to invoke directly the other Process function
2152 /// accepting a TSelector* as argument.eg
2153 /// ~~~{.cpp}
2154 /// MySelector *selector = (MySelector*)TSelector::GetSelector(filename);
2155 /// selector->CallSomeFunction(..);
2156 /// mytree.Process(selector,..);
2157 /// ~~~
2158 /// ### NOTE 2
2159 /// One should not call this function twice with the same selector file
2160 /// in the same script. If this is required, proceed as indicated in NOTE1,
2161 /// by getting a pointer to the corresponding TSelector,eg
2162 ///#### workaround 1
2163 /// ~~~{.cpp}
2164 ///void stubs1() {
2165 /// TSelector *selector = TSelector::GetSelector("h1test.C");
2166 /// TFile *f1 = new TFile("stubs_nood_le1.root");
2167 /// TTree *h1 = (TTree*)f1->Get("h1");
2168 /// h1->Process(selector);
2169 /// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
2170 /// TTree *h2 = (TTree*)f2->Get("h1");
2171 /// h2->Process(selector);
2172 ///}
2173 /// ~~~
2174 /// or use ACLIC to compile the selector
2175 ///#### workaround 2
2176 /// ~~~{.cpp}
2177 ///void stubs2() {
2178 /// TFile *f1 = new TFile("stubs_nood_le1.root");
2179 /// TTree *h1 = (TTree*)f1->Get("h1");
2180 /// h1->Process("h1test.C+");
2181 /// TFile *f2 = new TFile("stubs_nood_le1_coarse.root");
2182 /// TTree *h2 = (TTree*)f2->Get("h1");
2183 /// h2->Process("h1test.C+");
2184 ///}
2185 /// ~~~
2186 
2187 Long64_t TTreePlayer::Process(const char *filename,Option_t *option, Long64_t nentries, Long64_t firstentry)
2188 {
2189  DeleteSelectorFromFile(); //delete previous selector if any
2190 
2191  // This might reloads the script and delete your option
2192  // string! so let copy it first:
2193  TString opt(option);
2194  TString file(filename);
2195  TSelector *selector = TSelector::GetSelector(file);
2196  if (!selector) return -1;
2197 
2198  fSelectorFromFile = selector;
2199  fSelectorClass = selector->IsA();
2200 
2201  Long64_t nsel = Process(selector,opt,nentries,firstentry);
2202  return nsel;
2203 }
2204 
2205 ////////////////////////////////////////////////////////////////////////////////
2206 /// Process this tree executing the code in the specified selector.
2207 /// The return value is -1 in case of error and TSelector::GetStatus() in
2208 /// in case of success.
2209 ///
2210 /// The TSelector class has the following member functions:
2211 ///
2212 /// - Begin(): called every time a loop on the tree starts,
2213 /// a convenient place to create your histograms.
2214 /// - SlaveBegin(): called after Begin(), when on PROOF called only on the
2215 /// slave servers.
2216 /// - Process(): called for each event, in this function you decide what
2217 /// to read and fill your histograms.
2218 /// - SlaveTerminate: called at the end of the loop on the tree, when on PROOF
2219 /// called only on the slave servers.
2220 /// - Terminate(): called at the end of the loop on the tree,
2221 /// a convenient place to draw/fit your histograms.
2222 ///
2223 /// If the Tree (Chain) has an associated EventList, the loop is on the nentries
2224 /// of the EventList, starting at firstentry, otherwise the loop is on the
2225 /// specified Tree entries.
2226 
2227 Long64_t TTreePlayer::Process(TSelector *selector,Option_t *option, Long64_t nentries, Long64_t firstentry)
2228 {
2229  nentries = GetEntriesToProcess(firstentry, nentries);
2230 
2231  TDirectory::TContext ctxt;
2232 
2233  fTree->SetNotify(selector);
2234 
2235  selector->SetOption(option);
2236 
2237  selector->Begin(fTree); //<===call user initialization function
2238  selector->SlaveBegin(fTree); //<===call user initialization function
2239  if (selector->Version() >= 2)
2240  selector->Init(fTree);
2241  selector->Notify();
2242 
2243  if (gMonitoringWriter)
2244  gMonitoringWriter->SendProcessingStatus("STARTED",kTRUE);
2245 
2246  Bool_t process = (selector->GetAbort() != TSelector::kAbortProcess &&
2247  (selector->Version() != 0 || selector->GetStatus() != -1)) ? kTRUE : kFALSE;
2248  if (process) {
2249 
2250  Long64_t readbytesatstart = 0;
2251  readbytesatstart = TFile::GetFileBytesRead();
2252 
2253  //set the file cache
2254  TTreeCache *tpf = 0;
2255  TFile *curfile = fTree->GetCurrentFile();
2256  if (curfile && fTree->GetCacheSize() > 0) {
2257  tpf = (TTreeCache*)curfile->GetCacheRead(fTree);
2258  if (tpf)
2259  tpf->SetEntryRange(firstentry,firstentry+nentries);
2260  else {
2261  fTree->SetCacheSize(fTree->GetCacheSize());
2262  tpf = (TTreeCache*)curfile->GetCacheRead(fTree);
2263  if (tpf) tpf->SetEntryRange(firstentry,firstentry+nentries);
2264  }
2265  }
2266 
2267  //Create a timer to get control in the entry loop(s)
2268  TProcessEventTimer *timer = 0;
2269  Int_t interval = fTree->GetTimerInterval();
2270  if (!gROOT->IsBatch() && interval)
2271  timer = new TProcessEventTimer(interval);
2272 
2273  //loop on entries (elist or all entries)
2274  Long64_t entry, entryNumber, localEntry;
2275 
2276  Bool_t useCutFill = selector->Version() == 0;
2277 
2278  // force the first monitoring info
2279  if (gMonitoringWriter)
2280  gMonitoringWriter->SendProcessingProgress(0,0,kTRUE);
2281 
2282  //trying to set the first tree, because in the Draw function
2283  //the tree corresponding to firstentry has already been loaded,
2284  //so it is not set in the entry list
2285  fSelectorUpdate = selector;
2286  UpdateFormulaLeaves();
2287 
2288  for (entry=firstentry;entry<firstentry+nentries;entry++) {
2289  entryNumber = fTree->GetEntryNumber(entry);
2290  if (entryNumber < 0) break;
2291  if (timer && timer->ProcessEvents()) break;
2292  if (gROOT->IsInterrupted()) break;
2293  localEntry = fTree->LoadTree(entryNumber);
2294  if (localEntry < 0) break;
2295  if(useCutFill) {
2296  if (selector->ProcessCut(localEntry))
2297  selector->ProcessFill(localEntry); //<==call user analysis function
2298  } else {
2299  selector->Process(localEntry); //<==call user analysis function
2300  }
2301  if (gMonitoringWriter)
2302  gMonitoringWriter->SendProcessingProgress((entry-firstentry),TFile::GetFileBytesRead()-readbytesatstart,kTRUE);
2303  if (selector->GetAbort() == TSelector::kAbortProcess) break;
2304  if (selector->GetAbort() == TSelector::kAbortFile) {
2305  // Skip to the next file.
2306  entry += fTree->GetTree()->GetEntries() - localEntry;
2307  // Reset the abort status.
2308  selector->ResetAbort();
2309  }
2310  }
2311  delete timer;
2312  //we must reset the cache
2313  {
2314  TFile *curfile2 = fTree->GetCurrentFile();
2315  if (curfile2 && fTree->GetCacheSize() > 0) {
2316  tpf = (TTreeCache*)curfile2->GetCacheRead(fTree);
2317  if (tpf) tpf->SetEntryRange(0,0);
2318  }
2319  }
2320  }
2321 
2322  process = (selector->GetAbort() != TSelector::kAbortProcess &&
2323  (selector->Version() != 0 || selector->GetStatus() != -1)) ? kTRUE : kFALSE;
2324  Long64_t res = (process) ? 0 : -1;
2325  if (process) {
2326  selector->SlaveTerminate(); //<==call user termination function
2327  selector->Terminate(); //<==call user termination function
2328  res = selector->GetStatus();
2329  }
2330  fTree->SetNotify(0); // Detach the selector from the tree.
2331  fSelectorUpdate = 0;
2332  if (gMonitoringWriter)
2333  gMonitoringWriter->SendProcessingStatus("DONE");
2334 
2335  return res;
2336 }
2337 
2338 ////////////////////////////////////////////////////////////////////////////////
2339 /// cleanup pointers in the player pointing to obj
2340 
2341 void TTreePlayer::RecursiveRemove(TObject *obj)
2342 {
2343  if (fHistogram == obj) fHistogram = 0;
2344 }
2345 
2346 ////////////////////////////////////////////////////////////////////////////////
2347 /// Loop on Tree and print entries passing selection. If varexp is 0 (or "")
2348 /// then print only first 8 columns. If varexp = "*" print all columns.
2349 /// Otherwise a columns selection can be made using "var1:var2:var3".
2350 /// The function returns the number of entries passing the selection.
2351 ///
2352 /// By default 50 rows are shown and you are asked for `<CR>`
2353 /// to see the next 50 rows.
2354 ///
2355 /// You can change the default number of rows to be shown before `<CR>`
2356 /// via mytree->SetScanField(maxrows) where maxrows is 50 by default.
2357 /// if maxrows is set to 0 all rows of the Tree are shown.
2358 ///
2359 /// This option is interesting when dumping the contents of a Tree to
2360 /// an ascii file, eg from the command line.
2361 /// ### with ROOT 5
2362 /// ~~~{.cpp}
2363 /// root [0] tree->SetScanField(0);
2364 /// root [1] tree->Scan("*"); >tree.log
2365 /// ~~~
2366 /// ### with ROOT 6
2367 /// ~~~{.cpp}
2368 /// root [0] tree->SetScanField(0);
2369 /// root [1] .> tree.log
2370 /// tree->Scan("*");
2371 /// .>
2372 /// ~~~
2373 /// will create a file tree.log
2374 ///
2375 /// Arrays (within an entry) are printed in their linear forms.
2376 /// If several arrays with multiple dimensions are printed together,
2377 /// they will NOT be synchronized. For example print
2378 /// arr1[4][2] and arr2[2][3] will results in a printing similar to:
2379 /// ~~~{.cpp}
2380 /// ***********************************************
2381 /// * Row * Instance * arr1 * arr2 *
2382 /// ***********************************************
2383 /// * x * 0 * arr1[0][0]* arr2[0][0]*
2384 /// * x * 1 * arr1[0][1]* arr2[0][1]*
2385 /// * x * 2 * arr1[1][0]* arr2[0][2]*
2386 /// * x * 3 * arr1[1][1]* arr2[1][0]*
2387 /// * x * 4 * arr1[2][0]* arr2[1][1]*
2388 /// * x * 5 * arr1[2][1]* arr2[1][2]*
2389 /// * x * 6 * arr1[3][0]* *
2390 /// * x * 7 * arr1[3][1]* *
2391 /// ~~~
2392 /// However, if there is a selection criterion which is an array, then
2393 /// all the formulas will be synchronized with the selection criterion
2394 /// (see TTreePlayer::DrawSelect for more information).
2395 ///
2396 /// The options string can contains the following parameters:
2397 ///
2398 /// - lenmax=dd
2399 /// Where 'dd' is the maximum number of elements per array that should
2400 /// be printed. If 'dd' is 0, all elements are printed (this is the
2401 /// default)
2402 /// - colsize=ss
2403 /// Where 'ss' will be used as the default size for all the column
2404 /// If this options is not specified, the default column size is 9
2405 /// - precision=pp
2406 /// Where 'pp' will be used as the default 'precision' for the
2407 /// printing format.
2408 /// - col=xxx
2409 /// Where 'xxx' is colon (:) delimited list of printing format for
2410 /// each column. The format string should follow the printf format
2411 /// specification. The value given will be prefixed by % and, if no
2412 /// conversion specifier is given, will be suffixed by the letter g.
2413 /// before being passed to fprintf. If no format is specified for a
2414 /// column, the default is used (aka ${colsize}.${precision}g )
2415 ///
2416 /// For example:
2417 /// ~~~{.cpp}
2418 /// tree->Scan("a:b:c","","colsize=30 precision=3 col=::20.10:#x:5ld");
2419 /// ~~~
2420 /// Will print 3 columns, the first 2 columns will be 30 characters long,
2421 /// the third columns will be 20 characters long. The printing format used
2422 /// for the columns (assuming they are numbers) will be respectively:
2423 /// ~~~ {.cpp}
2424 /// %30.3g %30.3g %20.10g %#x %5ld
2425 /// ~~~
2426 
2427 Long64_t TTreePlayer::Scan(const char *varexp, const char *selection,
2428  Option_t * option,
2429  Long64_t nentries, Long64_t firstentry)
2430 {
2431 
2432  TString opt = option;
2433  opt.ToLower();
2434  UInt_t ui;
2435  UInt_t lenmax = 0;
2436  UInt_t colDefaultSize = 9;
2437  UInt_t colPrecision = 9;
2438  std::vector<TString> colFormats;
2439  std::vector<Int_t> colSizes;
2440 
2441  if (opt.Contains("lenmax=")) {
2442  int start = opt.Index("lenmax=");
2443  int numpos = start + strlen("lenmax=");
2444  int numlen = 0;
2445  int len = opt.Length();
2446  while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
2447  TString num = opt(numpos,numlen);
2448  opt.Remove(start,strlen("lenmax")+numlen);
2449 
2450  lenmax = atoi(num.Data());
2451  }
2452  if (opt.Contains("colsize=")) {
2453  int start = opt.Index("colsize=");
2454  int numpos = start + strlen("colsize=");
2455  int numlen = 0;
2456  int len = opt.Length();
2457  while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
2458  TString num = opt(numpos,numlen);
2459  opt.Remove(start,strlen("size")+numlen);
2460 
2461  colDefaultSize = atoi(num.Data());
2462  colPrecision = colDefaultSize;
2463  if (colPrecision>18) colPrecision = 18;
2464  }
2465  if (opt.Contains("precision=")) {
2466  int start = opt.Index("precision=");
2467  int numpos = start + strlen("precision=");
2468  int numlen = 0;
2469  int len = opt.Length();
2470  while( (numpos+numlen<len) && isdigit(opt[numpos+numlen]) ) numlen++;
2471  TString num = opt(numpos,numlen);
2472  opt.Remove(start,strlen("precision")+numlen);
2473 
2474  colPrecision = atoi(num.Data());
2475  }
2476  TString defFormat = Form("%d.%d",colDefaultSize,colPrecision);
2477  if (opt.Contains("col=")) {
2478  int start = opt.Index("col=");
2479  int numpos = start + strlen("col=");
2480  int numlen = 0;
2481  int len = opt.Length();
2482  while( (numpos+numlen<len) &&
2483  (isdigit(opt[numpos+numlen])
2484  || opt[numpos+numlen] == 'c'
2485  || opt[numpos+numlen] == 'd'
2486  || opt[numpos+numlen] == 'i'
2487  || opt[numpos+numlen] == 'o'
2488  || opt[numpos+numlen] == 'x'
2489  || opt[numpos+numlen] == 'X'
2490  || opt[numpos+numlen] == 'u'
2491  || opt[numpos+numlen] == 'f'
2492  || opt[numpos+numlen] == 'e'
2493  || opt[numpos+numlen] == 'E'
2494  || opt[numpos+numlen] == 'g'
2495  || opt[numpos+numlen] == 'G'
2496  || opt[numpos+numlen] == 'l'
2497  || opt[numpos+numlen] == 'L'
2498  || opt[numpos+numlen] == 'h'
2499  || opt[numpos+numlen] == 's'
2500  || opt[numpos+numlen] == '#'
2501  || opt[numpos+numlen]=='.'
2502  || opt[numpos+numlen]==':')) numlen++;
2503  TString flist = opt(numpos,numlen);
2504  opt.Remove(start,strlen("col")+numlen);
2505 
2506  int i = 0;
2507  while(i<flist.Length() && flist[i]==':') {
2508  colFormats.push_back(defFormat);
2509  colSizes.push_back(colDefaultSize);
2510  ++i;
2511  }
2512  for(; i<flist.Length(); ++i) {
2513  int next = flist.Index(":",i);
2514  if (next==i) {
2515  colFormats.push_back(defFormat);
2516  } else if (next==kNPOS) {
2517  colFormats.push_back(flist(i,flist.Length()-i));
2518  i = flist.Length();
2519  } else {
2520  colFormats.push_back(flist(i,next-i));
2521  i = next;
2522  }
2523  UInt_t siz = atoi(colFormats[colFormats.size()-1].Data());
2524  colSizes.push_back( siz ? siz : colDefaultSize );
2525  }
2526  }
2527 
2528  TTreeFormula **var;
2529  std::vector<TString> cnames;
2530  TString onerow;
2531  Long64_t entry,entryNumber;
2532  Int_t i,nch;
2533  UInt_t ncols = 8; // by default first 8 columns are printed only
2534  std::ofstream out;
2535  Int_t lenfile = 0;
2536  char * fname = 0;
2537  if (fScanRedirect) {
2538  fTree->SetScanField(0); // no page break if Scan is redirected
2539  fname = (char *) fScanFileName;
2540  if (!fname) fname = (char*)"";
2541  lenfile = strlen(fname);
2542  if (!lenfile) {
2543  Int_t nch2 = strlen(fTree->GetName());
2544  fname = new char[nch2+10];
2545  strlcpy(fname, fTree->GetName(),nch2+10);
2546  strlcat(fname, "-scan.dat",nch2+10);
2547  }
2548  out.open(fname, std::ios::out);
2549  if (!out.good ()) {
2550  if (!lenfile) delete [] fname;
2551  Error("Scan","Can not open file for redirection");
2552  return 0;
2553  }
2554  }
2555  TObjArray *leaves = fTree->GetListOfLeaves();
2556  if (leaves==0) return 0;
2557  UInt_t nleaves = leaves->GetEntriesFast();
2558  if (nleaves < ncols) ncols = nleaves;
2559  nch = varexp ? strlen(varexp) : 0;
2560 
2561  nentries = GetEntriesToProcess(firstentry, nentries);
2562 
2563 //*-*- Compile selection expression if there is one
2564  TTreeFormula *select = 0;
2565  if (selection && strlen(selection)) {
2566  select = new TTreeFormula("Selection",selection,fTree);
2567  if (!select) return -1;
2568  if (!select->GetNdim()) { delete select; return -1; }
2569  fFormulaList->Add(select);
2570  }
2571 //*-*- if varexp is empty, take first 8 columns by default
2572  int allvar = 0;
2573  if (varexp && !strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
2574  if (nch == 0 || allvar) {
2575  UInt_t ncs = ncols;
2576  ncols = 0;
2577  for (ui=0;ui<ncs;++ui) {
2578  TLeaf *lf = (TLeaf*)leaves->At(ui);
2579  if (lf->GetBranch()->GetListOfBranches()->GetEntries() > 0) continue;
2580  cnames.push_back( lf->GetBranch()->GetMother()->GetName() );
2581  if (cnames[ncols] == lf->GetName() ) {
2582  // Already complete, let move on.
2583  } else if (cnames[ncols][cnames[ncols].Length()-1]=='.') {
2584  cnames[ncols] = lf->GetBranch()->GetName(); // name of branch already include mother's name
2585  } else {
2586  if (lf->GetBranch()->GetMother()->IsA()->InheritsFrom(TBranchElement::Class())) {
2587  TBranchElement *mother = (TBranchElement*)lf->GetBranch()->GetMother();
2588  if (mother->GetType() == 3 || mother->GetType() == 4) {
2589  // The name of the mother branch is embedded in the sub-branch names.
2590  cnames[ncols] = lf->GetBranch()->GetName();
2591  ++ncols;
2592  continue;
2593  }
2594  }
2595  if (!strchr(lf->GetBranch()->GetName() ,'[') ) {
2596  cnames[ncols].Append('.');
2597  cnames[ncols].Append( lf->GetBranch()->GetName() );
2598  }
2599  }
2600  if (strcmp( lf->GetBranch()->GetName(), lf->GetName() ) != 0 ) {
2601  cnames[ncols].Append('.');
2602  cnames[ncols].Append( lf->GetName() );
2603  }
2604  ++ncols;
2605  }
2606 //*-*- otherwise select only the specified columns
2607  } else {
2608 
2609  ncols = fSelector->SplitNames(varexp, cnames);
2610 
2611  }
2612  var = new TTreeFormula* [ncols];
2613 
2614  for(ui=colFormats.size();ui<ncols;++ui) {
2615  colFormats.push_back(defFormat);
2616  colSizes.push_back(colDefaultSize);
2617  }
2618 
2619 //*-*- Create the TreeFormula objects corresponding to each column
2620  for (ui=0;ui<ncols;ui++) {
2621  var[ui] = new TTreeFormula("Var1",cnames[ui].Data(),fTree);
2622  fFormulaList->Add(var[ui]);
2623  }
2624 
2625 //*-*- Create a TreeFormulaManager to coordinate the formulas
2626  TTreeFormulaManager *manager=0;
2627  Bool_t hasArray = kFALSE;
2628  Bool_t forceDim = kFALSE;
2629  if (fFormulaList->LastIndex()>=0) {
2630  if (select) {
2631  if (select->GetManager()->GetMultiplicity() > 0 ) {
2632  manager = new TTreeFormulaManager;
2633  for(i=0;i<=fFormulaList->LastIndex();i++) {
2634  manager->Add((TTreeFormula*)fFormulaList->At(i));
2635  }
2636  manager->Sync();
2637  }
2638  }
2639  for(i=0;i<=fFormulaList->LastIndex();i++) {
2640  TTreeFormula *form = ((TTreeFormula*)fFormulaList->At(i));
2641  switch( form->GetManager()->GetMultiplicity() ) {
2642  case 1:
2643  case 2:
2644  hasArray = kTRUE;
2645  forceDim = kTRUE;
2646  break;
2647  case -1:
2648  forceDim = kTRUE;
2649  break;
2650  case 0:
2651  break;
2652  }
2653 
2654  }
2655  }
2656 
2657 //*-*- Print header
2658  onerow = "***********";
2659  if (hasArray) onerow += "***********";
2660 
2661  for (ui=0;ui<ncols;ui++) {
2662  TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
2663  onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
2664  }
2665  if (fScanRedirect)
2666  out<<onerow.Data()<<"*"<<std::endl;
2667  else
2668  printf("%s*\n",onerow.Data());
2669  onerow = "* Row ";
2670  if (hasArray) onerow += "* Instance ";
2671  for (ui=0;ui<ncols;ui++) {
2672  TString numbFormat = Form("* %%%d.%ds ",colSizes[ui],colSizes[ui]);
2673  onerow += Form(numbFormat.Data(),var[ui]->PrintValue(-1));
2674  }
2675  if (fScanRedirect)
2676  out<<onerow.Data()<<"*"<<std::endl;
2677  else
2678  printf("%s*\n",onerow.Data());
2679  onerow = "***********";
2680  if (hasArray) onerow += "***********";
2681  for (ui=0;ui<ncols;ui++) {
2682  TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
2683  onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
2684  }
2685  if (fScanRedirect)
2686  out<<onerow.Data()<<"*"<<std::endl;
2687  else
2688  printf("%s*\n",onerow.Data());
2689 //*-*- loop on all selected entries
2690  fSelectedRows = 0;
2691  Int_t tnumber = -1;
2692  Bool_t exitloop = kFALSE;
2693  for (entry=firstentry;
2694  entry<(firstentry+nentries) && !exitloop;
2695  entry++) {
2696  entryNumber = fTree->GetEntryNumber(entry);
2697  if (entryNumber < 0) break;
2698  Long64_t localEntry = fTree->LoadTree(entryNumber);
2699  if (localEntry < 0) break;
2700  if (tnumber != fTree->GetTreeNumber()) {
2701  tnumber = fTree->GetTreeNumber();
2702  if (manager) manager->UpdateFormulaLeaves();
2703  else {
2704  for(i=0;i<=fFormulaList->LastIndex();i++) {
2705  ((TTreeFormula*)fFormulaList->At(i))->UpdateFormulaLeaves();
2706  }
2707  }
2708  }
2709 
2710  int ndata = 1;
2711  if (forceDim) {
2712 
2713  if (manager) {
2714 
2715  ndata = manager->GetNdata(kTRUE);
2716 
2717  } else {
2718 
2719  // let's print the max number of column
2720  for (ui=0;ui<ncols;ui++) {
2721  if (ndata < var[ui]->GetNdata() ) {
2722  ndata = var[ui]->GetNdata();
2723  }
2724  }
2725  if (select && select->GetNdata()==0) ndata = 0;
2726  }
2727 
2728  }
2729 
2730  if (lenmax && ndata>(int)lenmax) ndata = lenmax;
2731  Bool_t loaded = kFALSE;
2732  for(int inst=0;inst<ndata;inst++) {
2733  if (select) {
2734  if (select->EvalInstance(inst) == 0) {
2735  continue;
2736  }
2737  }
2738  if (inst==0) loaded = kTRUE;
2739  else if (!loaded) {
2740  // EvalInstance(0) always needs to be called so that
2741  // the proper branches are loaded.
2742  for (ui=0;ui<ncols;ui++) {
2743  var[ui]->EvalInstance(0);
2744  }
2745  loaded = kTRUE;
2746  }
2747  onerow = Form("* %8lld ",entryNumber);
2748  if (hasArray) {
2749  onerow += Form("* %8d ",inst);
2750  }
2751  for (ui=0;ui<ncols;++ui) {
2752  TString numbFormat = Form("* %%%d.%ds ",colSizes[ui],colSizes[ui]);
2753  if (var[ui]->GetNdim()) onerow += Form(numbFormat.Data(),var[ui]->PrintValue(0,inst,colFormats[ui].Data()));
2754  else {
2755  TString emptyForm = Form("* %%%dc ",colSizes[ui]);
2756  onerow += Form(emptyForm.Data(),' ');
2757  }
2758  }
2759  fSelectedRows++;
2760  if (fScanRedirect)
2761  out<<onerow.Data()<<"*"<<std::endl;
2762  else
2763  printf("%s*\n",onerow.Data());
2764  if (fTree->GetScanField() > 0 && fSelectedRows > 0) {
2765  if (fSelectedRows%fTree->GetScanField() == 0) {
2766  fprintf(stderr,"Type <CR> to continue or q to quit ==> ");
2767  int answer, readch;
2768  readch = getchar();
2769  answer = readch;
2770  while (readch != '\n' && readch != EOF) readch = getchar();
2771  if (answer == 'q' || answer == 'Q') {
2772  exitloop = kTRUE;
2773  break;
2774  }
2775  }
2776  }
2777  }
2778  }
2779  onerow = "***********";
2780  if (hasArray) onerow += "***********";
2781  for (ui=0;ui<ncols;ui++) {
2782  TString starFormat = Form("*%%%d.%ds",colSizes[ui]+2,colSizes[ui]+2);
2783  onerow += Form(starFormat.Data(),var[ui]->PrintValue(-2));
2784  }
2785  if (fScanRedirect)
2786  out<<onerow.Data()<<"*"<<std::endl;
2787  else
2788  printf("%s*\n",onerow.Data());
2789  if (select) Printf("==> %lld selected %s", fSelectedRows,
2790  fSelectedRows == 1 ? "entry" : "entries");
2791  if (fScanRedirect) printf("File <%s> created\n", fname);
2792 
2793 //*-*- delete temporary objects
2794  fFormulaList->Clear();
2795  // The TTreeFormulaManager is deleted by the last TTreeFormula.
2796  delete [] var;
2797  return fSelectedRows;
2798 }
2799 
2800 ////////////////////////////////////////////////////////////////////////////////
2801 /// Loop on Tree and return TSQLResult object containing entries passing
2802 /// selection. If varexp is 0 (or "") then print only first 8 columns.
2803 /// If varexp = "*" print all columns. Otherwise a columns selection can
2804 /// be made using "var1:var2:var3". In case of error 0 is returned otherwise
2805 /// a TSQLResult object which must be deleted by the user.
2806 
2807 TSQLResult *TTreePlayer::Query(const char *varexp, const char *selection,
2808  Option_t *, Long64_t nentries, Long64_t firstentry)
2809 {
2810  TTreeFormula **var;
2811  std::vector<TString> cnames;
2812  TString onerow;
2813  Long64_t entry,entryNumber;
2814  Int_t i,nch;
2815  Int_t ncols = 8; // by default first 8 columns are printed only
2816  TObjArray *leaves = fTree->GetListOfLeaves();
2817  Int_t nleaves = leaves->GetEntriesFast();
2818  if (nleaves < ncols) ncols = nleaves;
2819  nch = varexp ? strlen(varexp) : 0;
2820 
2821  nentries = GetEntriesToProcess(firstentry, nentries);
2822 
2823  // compile selection expression if there is one
2824  TTreeFormula *select = 0;
2825  if (strlen(selection)) {
2826  select = new TTreeFormula("Selection",selection,fTree);
2827  if (!select) return 0;
2828  if (!select->GetNdim()) { delete select; return 0; }
2829  fFormulaList->Add(select);
2830  }
2831 
2832  // if varexp is empty, take first 8 columns by default
2833  int allvar = 0;
2834  if (varexp && !strcmp(varexp, "*")) { ncols = nleaves; allvar = 1; }
2835  if (nch == 0 || allvar) {
2836  for (i=0;i<ncols;i++) {
2837  cnames.push_back( ((TLeaf*)leaves->At(i))->GetName() );
2838  }
2839  } else {
2840  // otherwise select only the specified columns
2841  ncols = fSelector->SplitNames(varexp,cnames);
2842  }
2843  var = new TTreeFormula* [ncols];
2844 
2845  // create the TreeFormula objects corresponding to each column
2846  for (i=0;i<ncols;i++) {
2847  var[i] = new TTreeFormula("Var1",cnames[i].Data(),fTree);
2848  fFormulaList->Add(var[i]);
2849  }
2850 
2851  // fill header info into result object
2852  TTreeResult *res = new TTreeResult(ncols);
2853  for (i = 0; i < ncols; i++) {
2854  res->AddField(i, var[i]->PrintValue(-1));
2855  }
2856 
2857  //*-*- Create a TreeFormulaManager to coordinate the formulas
2858  TTreeFormulaManager *manager=0;
2859  if (fFormulaList->LastIndex()>=0) {
2860  manager = new TTreeFormulaManager;
2861  for(i=0;i<=fFormulaList->LastIndex();i++) {
2862  manager->Add((TTreeFormula*)fFormulaList->At(i));
2863  }
2864  manager->Sync();
2865  }
2866 
2867  // loop on all selected entries
2868  const char *aresult;
2869  Int_t len;
2870  char *arow = new char[ncols*50];
2871  fSelectedRows = 0;
2872  Int_t tnumber = -1;
2873  Int_t *fields = new Int_t[ncols];
2874  for (entry=firstentry;entry<firstentry+nentries;entry++) {
2875  entryNumber = fTree->GetEntryNumber(entry);
2876  if (entryNumber < 0) break;
2877  Long64_t localEntry = fTree->LoadTree(entryNumber);
2878  if (localEntry < 0) break;
2879  if (tnumber != fTree->GetTreeNumber()) {
2880  tnumber = fTree->GetTreeNumber();
2881  for (i=0;i<ncols;i++) var[i]->UpdateFormulaLeaves();
2882  }
2883 
2884  Int_t ndata = 1;
2885  if (manager && manager->GetMultiplicity()) {
2886  ndata = manager->GetNdata();
2887  }
2888 
2889  if (select) {
2890  select->GetNdata();
2891  if (select->EvalInstance(0) == 0) continue;
2892  }
2893 
2894  Bool_t loaded = kFALSE;
2895  for(int inst=0;inst<ndata;inst++) {
2896  if (select) {
2897  if (select->EvalInstance(inst) == 0) {
2898  continue;
2899  }
2900  }
2901 
2902  if (inst==0) loaded = kTRUE;
2903  else if (!loaded) {
2904  // EvalInstance(0) always needs to be called so that
2905  // the proper branches are loaded.
2906  for (i=0;i<ncols;i++) {
2907  var[i]->EvalInstance(0);
2908  }
2909  loaded = kTRUE;
2910  }
2911  for (i=0;i<ncols;i++) {
2912  aresult = var[i]->PrintValue(0,inst);
2913  len = strlen(aresult)+1;
2914  if (i == 0) {
2915  memcpy(arow,aresult,len);
2916  fields[i] = len;
2917  } else {
2918  memcpy(arow+fields[i-1],aresult,len);
2919  fields[i] = fields[i-1] + len;
2920  }
2921  }
2922  res->AddRow(new TTreeRow(ncols,fields,arow));
2923  fSelectedRows++;
2924  }
2925  }
2926 
2927  // delete temporary objects
2928  fFormulaList->Clear();
2929  // The TTreeFormulaManager is deleted by the last TTreeFormula.
2930  delete [] fields;
2931  delete [] arow;
2932  delete [] var;
2933 
2934  return res;
2935 }
2936 
2937 ////////////////////////////////////////////////////////////////////////////////
2938 /// Set number of entries to estimate variable limits.
2939 
2940 void TTreePlayer::SetEstimate(Long64_t n)
2941 {
2942  fSelector->SetEstimate(n);
2943 }
2944 
2945 ////////////////////////////////////////////////////////////////////////////////
2946 /// Start the TTreeViewer on this TTree.
2947 ///
2948 /// - ww is the width of the canvas in pixels
2949 /// - wh is the height of the canvas in pixels
2950 
2951 void TTreePlayer::StartViewer(Int_t ww, Int_t wh)
2952 {
2953  if (gROOT->IsBatch()) {
2954  Warning("StartViewer", "viewer cannot run in batch mode");
2955  return;
2956  }
2957 
2958  if (ww || wh) { } // use unused variables
2959  TPluginHandler *h;
2960  if ((h = gROOT->GetPluginManager()->FindHandler("TVirtualTreeViewer"))) {
2961  if (h->LoadPlugin() == -1)
2962  return;
2963  h->ExecPlugin(1,fTree);
2964  }
2965 }
2966 
2967 ////////////////////////////////////////////////////////////////////////////////
2968 /// Unbinned fit of one or more variable(s) from a Tree.
2969 ///
2970 /// funcname is a TF1 function.
2971 ///
2972 /// See TTree::Draw for explanations of the other parameters.
2973 ///
2974 /// Fit the variable varexp using the function funcname using the
2975 /// selection cuts given by selection.
2976 ///
2977 /// The list of fit options is given in parameter option.
2978 ///
2979 /// - option = "Q" Quiet mode (minimum printing)
2980 /// - option = "V" Verbose mode (default is between Q and V)
2981 /// - option = "E" Perform better Errors estimation using Minos technique
2982 /// - option = "M" More. Improve fit results
2983 /// - option = "D" Draw the projected histogram with the fitted function
2984 /// normalized to the number of selected rows
2985 /// and multiplied by the bin width
2986 ///
2987 /// You can specify boundary limits for some or all parameters via
2988 /// ~~~{.cpp}
2989 /// func->SetParLimits(p_number, parmin, parmax);
2990 /// ~~~
2991 /// if parmin>=parmax, the parameter is fixed
2992 ///
2993 /// Note that you are not forced to fix the limits for all parameters.
2994 /// For example, if you fit a function with 6 parameters, you can do:
2995 /// ~~~{.cpp}
2996 /// func->SetParameters(0,3.1,1.e-6,0.1,-8,100);
2997 /// func->SetParLimits(4,-10,-4);
2998 /// func->SetParLimits(5, 1,1);
2999 /// ~~~
3000 /// With this setup, parameters 0->3 can vary freely
3001 /// - Parameter 4 has boundaries [-10,-4] with initial value -8
3002 /// - Parameter 5 is fixed to 100.
3003 ///
3004 /// For the fit to be meaningful, the function must be self-normalized.
3005 ///
3006 /// i.e. It must have the same integral regardless of the parameter
3007 /// settings. Otherwise the fit will effectively just maximize the
3008 /// area.
3009 ///
3010 /// It is mandatory to have a normalization variable
3011 /// which is fixed for the fit. e.g.
3012 /// ~~~{.cpp}
3013 /// TF1* f1 = new TF1("f1", "gaus(0)/sqrt(2*3.14159)/[2]", 0, 5);
3014 /// f1->SetParameters(1, 3.1, 0.01);
3015 /// f1->SetParLimits(0, 1, 1); // fix the normalization parameter to 1
3016 /// data->UnbinnedFit("f1", "jpsimass", "jpsipt>3.0");
3017 /// ~~~
3018 ///
3019 /// 1, 2 and 3 Dimensional fits are supported.
3020 /// See also TTree::Fit
3021 ///
3022 /// ### Return status
3023 ///
3024 /// The function return the status of the fit in the following form
3025 /// ~~~{.cpp}
3026 /// fitResult = migradResult + 10*minosResult + 100*hesseResult + 1000*improveResult
3027 /// ~~~
3028 /// - The fitResult is 0 is the fit is OK.
3029 /// - The fitResult is negative in case of an error not connected with the fit.
3030 /// - The number of entries used in the fit can be obtained via
3031 /// ~~~{.cpp}
3032 /// mytree.GetSelectedRows();
3033 /// ~~~
3034 /// - If the number of selected entries is null the function returns -1
3035 ///
3036 /// new implementation using new Fitter classes
3037 
3038 Int_t TTreePlayer::UnbinnedFit(const char *funcname ,const char *varexp, const char *selection,Option_t *option ,Long64_t nentries, Long64_t firstentry)
3039 {
3040  // function is given by name, find it in gROOT
3041  TF1* fitfunc = (TF1*)gROOT->GetFunction(funcname);
3042  if (!fitfunc) { Error("UnbinnedFit", "Unknown function: %s",funcname); return 0; }
3043 
3044  Int_t npar = fitfunc->GetNpar();
3045  if (npar <=0) { Error("UnbinnedFit", "Illegal number of parameters = %d",npar); return 0; }
3046 
3047  // Spin through the data to select out the events of interest
3048  // Make sure that the arrays V1,etc are created large enough to accommodate
3049  // all entries
3050  Long64_t oldEstimate = fTree->GetEstimate();
3051  Long64_t nent = fTree->GetEntriesFriend();
3052  fTree->SetEstimate(TMath::Min(nent,nentries));
3053 
3054  // build FitOptions
3055  TString opt = option;
3056  opt.ToUpper();
3057  Foption_t fitOption;
3058  if (opt.Contains("Q")) fitOption.Quiet = 1;
3059  if (opt.Contains("V")){fitOption.Verbose = 1; fitOption.Quiet = 0;}
3060  if (opt.Contains("E")) fitOption.Errors = 1;
3061  if (opt.Contains("M")) fitOption.More = 1;
3062  if (!opt.Contains("D")) fitOption.Nograph = 1; // what about 0
3063  // could add range and automatic normalization of functions and gradient
3064 
3065  TString drawOpt = "goff";
3066  if (!fitOption.Nograph) drawOpt = "";
3067  Long64_t nsel = DrawSelect(varexp, selection,drawOpt, nentries, firstentry);
3068 
3069  if (!fitOption.Nograph && GetSelectedRows() <= 0 && GetDimension() > 4) {
3070  Info("UnbinnedFit","Ignore option D with more than 4 variables");
3071  nsel = DrawSelect(varexp, selection,"goff", nentries, firstentry);
3072  }
3073 
3074  //if no selected entries return
3075  Long64_t nrows = GetSelectedRows();
3076 
3077  if (nrows <= 0) {
3078  Error("UnbinnedFit", "Cannot fit: no entries selected");
3079  return -1;
3080  }
3081 
3082  // Check that function has same dimension as number of variables
3083  Int_t ndim = GetDimension();
3084  // do not check with TF1::GetNdim() since it returns 1 for TF1 classes created with
3085  // a C function with larger dimension
3086 
3087 
3088  // use pointer stored in the tree (not copy the data in)
3089  std::vector<double *> vlist(ndim);
3090  for (int i = 0; i < ndim; ++i)
3091  vlist[i] = fSelector->GetVal(i);
3092 
3093  // fill the fit data object
3094  // the object will be then managed by the fitted classes - however it will be invalid when the
3095  // data pointers (given by fSelector->GetVal() ) wil be invalidated
3096  ROOT::Fit::UnBinData * fitdata = new ROOT::Fit::UnBinData(nrows, ndim, vlist.begin());
3097 
3098 
3099 
3100  ROOT::Math::MinimizerOptions minOption;
3101  TFitResultPtr ret = ROOT::Fit::UnBinFit(fitdata,fitfunc, fitOption, minOption);
3102 
3103  //reset estimate
3104  fTree->SetEstimate(oldEstimate);
3105 
3106  //if option "D" is specified, draw the projected histogram
3107  //with the fitted function normalized to the number of selected rows
3108  //and multiplied by the bin width
3109  if (!fitOption.Nograph && fHistogram) {
3110  if (fHistogram->GetDimension() < 2) {
3111  TH1 *hf = (TH1*)fHistogram->Clone("unbinnedFit");
3112  hf->SetLineWidth(3);
3113  hf->Reset();
3114  Int_t nbins = fHistogram->GetXaxis()->GetNbins();
3115  Double_t norm = ((Double_t)nsel)*fHistogram->GetXaxis()->GetBinWidth(1);
3116  for (Int_t bin=1;bin<=nbins;bin++) {
3117  Double_t func = norm*fitfunc->Eval(hf->GetBinCenter(bin));
3118  hf->SetBinContent(bin,func);
3119  }
3120  fHistogram->GetListOfFunctions()->Add(hf,"lsame");
3121  }
3122  fHistogram->Draw();
3123  }
3124 
3125 
3126  return int(ret);
3127 
3128 }
3129 
3130 ////////////////////////////////////////////////////////////////////////////////
3131 /// this function is called by TChain::LoadTree when a new Tree is loaded.
3132 /// Because Trees in a TChain may have a different list of leaves, one
3133 /// must update the leaves numbers in the TTreeFormula used by the TreePlayer.
3134 
3135 void TTreePlayer::UpdateFormulaLeaves()
3136 {
3137  if (fSelector) fSelector->Notify();
3138  if (fSelectorUpdate){
3139  //If the selector is writing into a TEntryList, the entry list's
3140  //sublists need to be changed according to the loaded tree
3141  if (fSelector==fSelectorUpdate) {
3142  //FIXME: should be more consistent with selector from file
3143  TObject *obj = fSelector->GetObject();
3144  if (obj){
3145  if (fSelector->GetObject()->InheritsFrom(TEntryList::Class())){
3146  ((TEntryList*)fSelector->GetObject())->SetTree(fTree->GetTree());
3147  }
3148  }
3149  }
3150  if (fSelectorFromFile==fSelectorUpdate) {
3151  TIter next(fSelectorFromFile->GetOutputList());
3152  TEntryList *elist=0;
3153  while ((elist=(TEntryList*)next())){
3154  if (elist->InheritsFrom(TEntryList::Class())){
3155  elist->SetTree(fTree->GetTree());
3156  }
3157  }
3158  }
3159  }
3160 
3161  if (fFormulaList->GetSize()) {
3162  TObjLink *lnk = fFormulaList->FirstLink();
3163  while (lnk) {
3164  lnk->GetObject()->Notify();
3165  lnk = lnk->Next();
3166  }
3167  }
3168 }