]> git.uio.no Git - u/mrichter/AliRoot.git/blob - STEER/STEERBase/TTreeStream.cxx
Ignore streamer of raw header v3_14.
[u/mrichter/AliRoot.git] / STEER / STEERBase / TTreeStream.cxx
1 /**************************************************************************
2  * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
3  *                                                                        *
4  * Author: The ALICE Off-line Project.                                    *
5  * Contributors are mentioned in the code where appropriate.              *
6  *                                                                        *
7  * Permission to use, copy, modify and distribute this software and its   *
8  * documentation strictly for non-commercial purposes is hereby granted   *
9  * without fee, provided that the above copyright notice appears in all   *
10  * copies and that both the copyright notice and this permission notice   *
11  * appear in the supporting documentation. The authors make no claims     *
12  * about the suitability of this software for any purpose. It is          *
13  * provided "as is" without express or implied warranty.                  *
14  **************************************************************************/
15
16 /* $Id$ */
17
18 //
19 //  marian.ivanov@cern.ch
20 //
21 //  ------------------------------------------------------------------------------------------------
22 //  TTreeStream
23 //  Standard stream (cout) like input for the tree
24 //  Run and see TTreeStreamer::Test() - to see TTreeStreamer functionality
25 //  ------------------------------------------------------------------------------------------------  
26 //
27 //  -------------------------------------------------------------------------------------------------
28 //  TTreeSRedirector
29 //  Redirect file to  different TTreeStreams  
30 //  Run and see   TTreeSRedirector::Test() as an example of TTreeSRedirectorer functionality 
31 // 
32
33 #include <TClass.h>
34 #include <TFile.h>
35 #include <TDirectory.h>
36 #include <TObjArray.h>
37 #include <TTree.h>
38 #include "TTreeStream.h"
39 // includes for test procedures
40 #include "TVectorD.h"
41 #include "TRandom.h"
42
43 ClassImp(TTreeDataElement)
44 ClassImp(TTreeStream)
45 ClassImp(TTreeSRedirector)
46
47
48
49 void TTreeStream::Test()
50 {
51   //
52   // 
53   TFile *ftest = new TFile("teststreamer.root","recreate");
54   if (!ftest) ftest = new TFile("teststreamer.root","new");
55   //
56   //create to streems Tree1 and Tree2
57   TTreeStream stream1("Tree1");
58   TTreeStream stream2("Tree2");
59   //
60   Char_t ch='s';
61   Float_t f=3.;
62   Float_t f2=1;
63   TObject *po  = new TObject;
64   TObject *po2 = new TObject;
65   for (Int_t i=0;i<100000;i++) {
66     f=i*100;
67     po->SetUniqueID(i);
68     po2->SetUniqueID(i*100);
69     ch=i%120;
70     //
71     //    Stream the data
72     //    The data layout of stream is defined during first invocation of streamer.
73     //    Endl is the trigger which define the end of structure.
74     // 
75     //    The name of branch can be specified using strings with = at the the end
76     //    if string is not specified automatic convention is u (sed B0, B1, ...Bn)
77     stream1<<"i="<<i<<"ch="<<ch<<"f="<<f<<"po="<<po<<"\n";
78     f  = 1./(100.1+i);
79     f2 = -f;     
80     //3.) just another example - we can fill the same tree with different objects
81     //
82     stream2<<f<<po<<"\n";
83     stream2<<f2<<po2<<"\n";
84   }
85   //
86   //4.) Close the streeamers (Write the streamed tree's to the file) and close the corresponding file.
87   //
88   stream1.Close();
89   stream2.Close();
90   ftest->Close();
91   delete ftest;
92   //
93   //5.) and now see results  in file tteststreamer.root
94 }
95
96 void TTreeSRedirector::Test2()
97 {
98   //
99   //Example test function to show functionality of TTreeSRedirector
100   //
101   //
102   //1.)create the  redirector associated with file (testredirector.root)
103   //
104   //
105   TFile* file = new TFile("test.root","recreate");
106   TTreeSRedirector *pmistream= new TTreeSRedirector();
107   TTreeSRedirector &mistream = *pmistream;
108   Char_t ch='s';
109   Float_t f=3.;
110   Float_t f2=1;
111   TObject *po  = new TObject;
112   TObject *po2 = new TObject;
113   for (Int_t i=0;i<100000;i++) {
114     f=i*100;
115     po->SetUniqueID(i);
116     po2->SetUniqueID(i*100);
117     ch=i%120;
118     //
119     //2.) create the tree with identifier specified by first argument
120     //                                layout specified by sequence of arguments
121     //                                Tree identifier has to be specified as first argument !!! 
122     //    if the tree and layout was already defined the consistency if layout is checked
123     //                                if the data are consisten fill given tree 
124     //    the name of branch can be specified using strings with = at the the end
125     //    if string is not specified use automatic convention  B0, B1, ...Bn
126     mistream<<"TreeIdentifier"<<"i="<<i<<"ch="<<ch<<"f="<<f<<"po="<<po<<"\n";
127     f  = 1./(100.1+i);
128     f2 = -f; 
129     
130     //3.) just another example - we can fill the same tree with different objects
131     //
132     mistream<<"TreeK"<<f<<po<<"\n";
133     mistream<<"TreeK"<<f2<<po2<<"\n";
134   }
135   //
136   //4.) write the streamed tree's to the file and close the corresponding file in destructor
137   //
138   delete pmistream;
139   delete file;
140   //
141   //5.) and now see results in file testredirector.root 
142 }
143
144 void TTreeSRedirector::Test()
145 {
146   //
147   //Example test function to show functionality of TTreeSRedirector
148   //
149   //
150   //1.)create the  redirector associated with file (testredirector.root)
151   //
152   //
153   TTreeSRedirector *pmistream= new TTreeSRedirector("testredirector.root");
154   TTreeSRedirector &mistream = *pmistream;
155   Char_t ch='s';
156   Float_t f=3.;
157   Float_t f2=1;
158   TObject *po  = new TObject;
159   TObject *po2 = new TObject;
160   for (Int_t i=0;i<100000;i++) {
161     f=i*100;
162     po->SetUniqueID(i);
163     po2->SetUniqueID(i*100);
164     ch=i%120;
165     //
166     //2.) create the tree with identifier specified by first argument
167     //                                layout specified by sequence of arguments
168     //                                Tree identifier has to be specified as first argument !!! 
169     //    if the tree and layout was already defined the consistency if layout is checked
170     //                                if the data are consisten fill given tree 
171     //    the name of branch can be specified using strings with = at the the end
172     //    if string is not specified use automatic convention  B0, B1, ...Bn
173     mistream<<"TreeIdentifier"<<"i="<<i<<"ch="<<ch<<"f="<<f<<"po="<<po<<"\n";
174     f  = 1./(100.1+i);
175     f2 = -f; 
176     
177     //3.) just another example - we can fill the same tree with different objects
178     //
179     mistream<<"TreeK"<<f<<po<<"\n";
180     mistream<<"TreeK"<<f2<<po2<<"\n";
181   }
182   //
183   //4.) write the streamed tree's to the file and close the corresponding file in destructor
184   //
185   delete pmistream;
186   //
187   //5.) and now see results in file testredirector.root 
188 }
189
190 void TTreeSRedirector::UnitTest(Int_t testEntries){
191   //
192   //
193   //
194   UnitTestSparse(0.5,testEntries);
195   UnitTestSparse(0.1,testEntries);
196   UnitTestSparse(0.01,testEntries);
197 }
198
199 void TTreeSRedirector::UnitTestSparse(Double_t scale, Int_t testEntries){
200   //
201   // Unit test for the TTreeSRedirector
202   // 1.) Test TTreeRedirector 
203   //      a.) Fill tree with random vectors
204   //      b.) Fill downscaled version of vectors
205   //      c.) The same skipping first entry
206   // 2.) Check results wtitten to terminale
207   //     a.) Disk consumption 
208   //             skip data should be scale time smaller than full
209   //             zerro replaced  ata should be compresed time smaller than full
210   //     b.) Test invariants
211   // Input parameter scale => downscaling of sprse element 
212   //            
213   if (scale<=0) scale=1;
214   if (scale>1) scale=1;
215   TTreeSRedirector *pcstream = new TTreeSRedirector("testpcstreamSparse.root","recreate");
216   for (Int_t ientry=0; ientry<testEntries; ientry++){
217     TVectorD vecRandom(200);
218     TVectorD vecZerro(200);   // zerro vector
219     for (Int_t j=0; j<200; j++) vecRandom[j]=j+ientry+0.1*gRandom->Rndm();
220     Bool_t isSelected= (gRandom->Rndm()<scale);
221     TVectorD *pvecFull   = &vecRandom;
222     TVectorD *pvecSparse = isSelected ? &vecRandom:0;
223     TVectorD *pvecSparse0 = isSelected ? &vecRandom:0;
224     TVectorD *pvecSparse1 = isSelected ? &vecRandom:&vecZerro;
225
226     if (ientry==0) {
227       pvecSparse0=0;
228       pvecSparse=&vecRandom;
229     }
230     (*pcstream)<<"Full"<<                  // stored all vectors
231       "ientry="<<ientry<<
232       "vec.="<<pvecFull<<                  
233       "\n";
234     (*pcstream)<<"SparseSkip"<<                // fraction of vectors stored
235       "ientry="<<ientry<<
236       "vec.="<<pvecSparse<<                
237       "\n";
238     (*pcstream)<<"SparseSkip0"<<               // fraction with -pointer
239       "ientry="<<ientry<<
240       "vec.="<<pvecSparse0<<
241       "\n";
242     (*pcstream)<<"SparseZerro"<<               // all vectors filled, franction filled with 0
243       "ientry="<<ientry<<
244       "vec.="<<pvecSparse1<<
245       "\n";
246   }
247   delete pcstream;
248   //
249   // 2.) check results
250   //
251   TFile* f = TFile::Open("testpcstreamSparse.root");
252   TTree * treeFull = (TTree*)f->Get("Full");
253   TTree * treeSparseSkip = (TTree*)f->Get("SparseSkip");
254   TTree * treeSparseSkip0 = (TTree*)f->Get("SparseSkip0");
255   TTree * treeSparseZerro = (TTree*)f->Get("SparseZerro");
256   //    a.) data volume
257   //
258   Double_t ratio=(1./scale)*treeSparseSkip->GetZipBytes()/Double_t(treeFull->GetZipBytes());
259   Double_t ratio0=(1./scale)*treeSparseSkip0->GetZipBytes()/Double_t(treeFull->GetZipBytes());
260   Double_t ratio1=(1./scale)*treeSparseZerro->GetZipBytes()/Double_t(treeFull->GetZipBytes());
261   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tRatioSkip\t%f\n",scale,ratio);
262   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tRatioSkip0\t%f\n",scale,ratio0);
263   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tRatioZerro\t%f\n",scale,ratio1);
264   //    b.) Integrity 
265   Int_t outlyersSparseSkip=treeSparseSkip->Draw("1","(vec.fElements-ientry-Iteration$-0.5)>0.5","goff");
266   Int_t outlyersSparseSkip0=treeSparseSkip0->Draw("1","(vec.fElements-ientry-Iteration$-0.5)>0.5","goff");
267   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tOutlyersSkip\t%d\n",scale,outlyersSparseSkip!=0);
268   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tOutlyersSkip0\t%d\n",scale,outlyersSparseSkip0!=0);
269   //    c.) Number of entries
270   //
271   Int_t entries=treeFull->GetEntries();
272   Int_t entries0=treeSparseSkip0->GetEntries();
273   Bool_t  isOKStat =(entries==entries0);
274   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tEntries\t%d\n",scale,isOKStat);
275   //
276   //   d.)Reading test
277   TVectorD *pvecRead   = 0;
278   treeSparseSkip0->SetBranchAddress("vec.",&pvecRead);
279   Bool_t readOK=kTRUE;
280   for (Int_t ientry=0; ientry<testEntries; ientry++){
281     if (!pvecRead) continue;
282     if (pvecRead->GetNrows()==0) continue;
283     if (TMath::Abs((*pvecRead)[0]-ientry)>0.5) readOK=kFALSE;
284   }
285   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tReadOK\t%d\n",scale,readOK);
286   //
287   //   e.)Global test
288   Bool_t isOK=(outlyersSparseSkip0==0)&&isOKStat&&readOK;
289   printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tisOk\t%d\n",scale,isOK);  
290
291 }
292
293 TTreeSRedirector::TTreeSRedirector(const char *fname,const char * option) :
294   fDirectory(NULL),
295   fDirectoryOwner(kTRUE),
296   fDataLayouts(NULL)
297 {
298   //
299   // Constructor
300   //
301   TString name(fname);
302   if (!name.IsNull()){
303     fDirectory = new TFile(fname,option);
304   }
305   else
306   {
307     fDirectory = gDirectory;
308     fDirectoryOwner = kFALSE;
309   }
310 }
311
312 TTreeSRedirector::~TTreeSRedirector()
313 {
314   //
315   // Destructor
316   //
317   Close();       //write the tree to the selected file
318   if (fDirectoryOwner)
319   {
320     fDirectory->Close();
321     delete fDirectory;
322   }
323 }
324 void TTreeSRedirector::StoreObject(TObject* object){
325   //
326   //
327   //
328   TDirectory * backup = gDirectory;
329   fDirectory->cd();
330   object->Write();
331   if (backup) backup->cd();
332 }
333
334 void  TTreeSRedirector::SetDirectory(TDirectory *sfile){
335   //
336   // Set the external file 
337   // In case other file already attached old file is closed before
338   // Redirector will be the owner of file ?
339   if (fDirectory && fDirectoryOwner) {
340     fDirectory->Close();
341     delete fDirectory;
342   }
343   fDirectory=sfile;
344 }
345
346 TTreeStream  & TTreeSRedirector::operator<<(Int_t id)
347 {
348   //
349   // return reference to the data layout with given identifier
350   // if not existing - creates new
351   if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
352   TTreeStream *clayout=0;
353   Int_t entries = fDataLayouts->GetEntriesFast();
354   for (Int_t i=0;i<entries;i++){
355     TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
356     if (!layout) continue;
357     if (layout->fId==id) {
358       clayout = layout;
359       break;
360     }
361   }
362   if (!clayout){
363     TDirectory * backup = gDirectory;
364     fDirectory->cd();
365     char chname[100];
366     snprintf(chname,100,"Tree%d",id);
367     clayout = new TTreeStream(chname);
368     clayout->fId=id;
369     fDataLayouts->AddAt(clayout,entries);
370     if (backup) backup->cd();
371   }
372   return *clayout;
373 }
374
375 void TTreeSRedirector::SetExternalTree(const char* name, TTree* externalTree)
376 {
377   TTreeStream *clayout=(TTreeStream*)fDataLayouts->FindObject(name);
378
379   if (!clayout){
380     TDirectory * backup = gDirectory;
381     fDirectory->cd();
382     clayout = new TTreeStream(name,externalTree);
383     clayout->fId=-1;
384     clayout->SetName(name);
385     Int_t entries = fDataLayouts->GetEntriesFast();
386     fDataLayouts->AddAt(clayout,entries);
387     if (backup) backup->cd();
388   }
389   //else
390   //  AliError(Form("identifier %s already associated",name));
391 }
392
393
394 TTreeStream  & TTreeSRedirector::operator<<(const char* name)
395 {
396   //
397   // return reference to the data layout with given identifier
398   // if not existing - creates new
399   if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
400   TTreeStream *clayout=(TTreeStream*)fDataLayouts->FindObject(name);
401   Int_t entries = fDataLayouts->GetEntriesFast();
402
403   if (!clayout){
404     TDirectory * backup = gDirectory;
405     fDirectory->cd();
406     clayout = new TTreeStream(name);
407     clayout->fId=-1;
408     clayout->SetName(name);
409     fDataLayouts->AddAt(clayout,entries);    
410     if (backup) backup->cd();
411   }
412   return *clayout;
413 }
414
415
416
417
418 void TTreeSRedirector::Close(){
419   //
420   //
421   TDirectory * backup = gDirectory;
422   fDirectory->cd();
423   if (fDataLayouts){
424     Int_t entries = fDataLayouts->GetEntriesFast();
425     for (Int_t i=0;i<entries;i++){
426       TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
427       if (layout){
428         if (layout->fTree) layout->fTree->Write(layout->GetName());
429       }
430     }
431     delete fDataLayouts;
432     fDataLayouts=0;
433   }
434   if (backup) backup->cd();
435 }
436
437 //-------------------------------------------------------------
438 TTreeDataElement:: TTreeDataElement(Char_t type) :
439   TNamed(),
440   fType(type),
441   fDType(0),
442   fClass(0),
443   fPointer(0)
444 {
445   //
446   //
447   //
448 }
449
450 TTreeDataElement:: TTreeDataElement(TDataType* type) :
451   TNamed(),
452   fType(0),
453   fDType(type),
454   fClass(0),
455   fPointer(0)
456 {
457   //
458   //
459   //
460 }
461
462 TTreeDataElement:: TTreeDataElement(TClass* cl) :
463   TNamed(),
464   fType(0),
465   fDType(0),
466   fClass(cl),
467   fPointer(0)
468 {
469   //
470   //
471   //
472 }
473
474 //-------------------------------------------------------------------
475 TTreeStream::TTreeStream(const char *treename, TTree* externalTree):
476   TNamed(treename,treename),
477   fElements(0),
478   fBranches(0),
479   fTree(externalTree),
480   fCurrentIndex(0),
481   fId(0),
482   fNextName(),
483   fNextNameCounter(),
484   fStatus(0)
485 {
486   //
487   // Standard ctor
488   //
489   if (!fTree) fTree = new TTree(treename, treename);
490 }
491
492 TTreeStream::~TTreeStream()
493 {
494   //
495   // Class dtor
496   //
497   fElements->Delete();
498   fBranches->Clear();
499   delete fElements;
500   delete fBranches;
501 }
502
503 void TTreeStream::Close()
504 {
505   //
506   // Flush data to disk and close
507   //
508   fTree->Write();
509 }
510
511 Int_t TTreeStream::CheckIn(Char_t type, void *pointer)
512 {
513   //
514   // Insert object of given type
515   //
516   if (!fElements) fElements = new TObjArray(10000);
517   if (fElements->GetSize()<=fCurrentIndex) fElements->Expand(fCurrentIndex*2);
518   TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
519   if (!element) {
520     element = new TTreeDataElement(type);
521     //
522     char name[1000];
523     if (fNextName.Length()>0){
524       if (fNextNameCounter==0){
525         snprintf(name,1000,"%s",(const char*)fNextName);
526       }
527       if (fNextNameCounter>0){
528         snprintf(name,1000,"%s%d",(const char*)fNextName,fNextNameCounter);
529       }      
530     }
531     else{
532       snprintf(name,1000,"B%d.",fCurrentIndex);
533     }
534     element->SetName(name);
535     //
536     element->SetPointer(pointer);
537     fElements->AddAt(element,fCurrentIndex);
538     fCurrentIndex++;
539     return 0; //new element added
540   }
541   if (element->GetType()!=type){
542     fStatus++;
543     return 1; //mismatched data element
544   }
545   element->SetPointer(pointer);
546   fCurrentIndex++;
547   return 0;
548 }
549
550 Int_t TTreeStream::CheckIn(TObject *pObject){
551   //
552   // Insert TObject
553   //
554   TClass *pClass = 0;
555   if (pObject) pClass=pObject->IsA();
556   if (!fElements) fElements = new TObjArray(1000);
557   TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
558   if (!element) {
559     element = new TTreeDataElement(pClass);
560     //
561     char name[1000];
562     if (fNextName.Length()>0){
563       if (fNextNameCounter==0){
564         snprintf(name,1000,"%s",(const char*)fNextName);
565       }
566       if (fNextNameCounter>0){
567         snprintf(name,1000,"%s%d",(const char*)fNextName,fNextNameCounter);
568       }      
569     }
570     else{
571       snprintf(name,1000,"B%d",fCurrentIndex);
572     }
573     element->SetName(name);
574     
575     element->SetPointer(pObject);
576     fElements->AddAt(element,fCurrentIndex);
577     fCurrentIndex++;
578     return 0; //new element added
579   }
580   if (element->fClass==0) {
581     element->fClass=pClass;
582   }else{
583     if (element->fClass!=pClass && pClass!=0){
584       fStatus++;
585       return 1; //mismatched data element
586     }
587   }
588   element->SetPointer(pObject);
589   fCurrentIndex++;
590   return 0;  
591 }
592
593 void TTreeStream::BuildTree(){
594   //
595   // Build the Tree
596   //
597   //if (fTree && fTree->GetEntries()>0) return;
598   Int_t entriesFilled=0;
599   if (!fTree)  {
600     fTree = new TTree(GetName(),GetName());
601   }else{
602     entriesFilled=fTree->GetEntries();
603   }
604   Int_t entries = fElements->GetEntriesFast();  
605   if (!fBranches) fBranches = new TObjArray(entries);
606   
607   for (Int_t i=0;i<entries;i++){
608     //
609     TTreeDataElement* element = (TTreeDataElement*)fElements->At(i);
610     if (fBranches->At(i)) continue;
611     char bname1[1000];
612     if (element->GetName()[0]==0){
613       snprintf(bname1,1000,"B%d",i);
614     }
615     else{
616       snprintf(bname1,1000,"%s",element->GetName());
617     }
618     if (element->fClass){
619       if (element->fClass->GetBaseClass("TClonesArray")){
620         TBranch * br = fTree->Branch(bname1,element->fClass->GetName(),&(element->fPointer));
621         if (entriesFilled!=0) {
622           br->SetAddress(0);
623           for (Int_t ientry=0; ientry<entriesFilled;ientry++) br->Fill();
624           br->SetAddress(&(element->fPointer));
625         }
626         fBranches->AddAt(br,i);
627       }else
628         {
629           TBranch * br = fTree->Branch(bname1,element->fClass->GetName(),&(element->fPointer));
630           if (entriesFilled!=0) {
631             br->SetAddress(0);
632             for (Int_t ientry=0; ientry<entriesFilled;ientry++) br->Fill();
633             br->SetAddress(&(element->fPointer));
634           }
635           fBranches->AddAt(br,i);
636         }
637     }
638     if (element->GetType()>0){
639       char bname2[1000];
640       snprintf(bname2,1000,"B%d/%c",i,element->GetType());
641       TBranch * br = fTree->Branch(bname1,element->fPointer,bname2);
642       if (entriesFilled!=0) {
643         br->SetAddress(0);
644         for (Int_t ientry=0; ientry<entriesFilled;ientry++) br->Fill();
645         br->SetAddress(element->fPointer);
646       }
647
648       fBranches->AddAt(br,i);
649     }
650   }
651 }
652
653 void TTreeStream::Fill(){
654   //
655   // Fill the tree
656   //
657   if (fTree) { 
658     Int_t entries=fElements->GetEntriesFast();
659     if (entries>fTree->GetNbranches()) BuildTree();
660     for (Int_t i=0;i<entries;i++){    
661       TTreeDataElement* el  = (TTreeDataElement*)fElements->At(i);
662       if (!el) continue;
663       if (!el->GetType()) continue;
664       TBranch      * br  = (TBranch*)fBranches->At(i);
665       if (br &&el){
666         if (el->GetType())  br->SetAddress(el->fPointer);
667       }
668     }
669     if (fStatus==0) fTree->Fill(); //fill only in case of non conflicts
670     fStatus=0;
671   }
672 }
673
674 TTreeStream & TTreeStream::Endl()
675 {
676   //
677   // Perform pseudo endl operation
678   //
679   if (fTree->GetNbranches()==0) BuildTree();
680   Fill();
681   fStatus =0;
682   fCurrentIndex=0;
683   return *this;
684 }
685
686
687 TTreeStream  &TTreeStream::operator<<(const Char_t *name)
688 {
689   //
690   // Endl 
691   //
692   if (name[0]=='\n'){
693     return Endl();
694   }
695   //
696   //if tree was already defined ignore
697   if (fTree->GetEntries()>0) return *this;
698   //check branch name if tree was not 
699   //
700   Int_t last=0;
701   for (last=0;;last++){
702     if (name[last]==0) break;    
703   }
704   
705   if (last>0&&name[last-1]=='='){
706     fNextName = name;
707     fNextName[last-1]=0;
708     fNextNameCounter=0;
709   }
710   return *this;
711 }
712