1 /**************************************************************************
2 * Copyright(c) 1998-1999, ALICE Experiment at CERN, All rights reserved. *
4 * Author: The ALICE Off-line Project. *
5 * Contributors are mentioned in the code where appropriate. *
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 **************************************************************************/
19 // marian.ivanov@cern.ch
21 // ------------------------------------------------------------------------------------------------
23 // Standard stream (cout) like input for the tree
24 // Run and see TTreeStreamer::Test() - to see TTreeStreamer functionality
25 // ------------------------------------------------------------------------------------------------
27 // -------------------------------------------------------------------------------------------------
29 // Redirect file to different TTreeStreams
30 // Run and see TTreeSRedirector::Test() as an example of TTreeSRedirectorer functionality
35 #include <TDirectory.h>
36 #include <TObjArray.h>
38 #include "TTreeStream.h"
39 // includes for test procedures
43 ClassImp(TTreeDataElement)
45 ClassImp(TTreeSRedirector)
49 void TTreeStream::Test()
53 TFile *ftest = new TFile("teststreamer.root","recreate");
54 if (!ftest) ftest = new TFile("teststreamer.root","new");
56 //create to streems Tree1 and Tree2
57 TTreeStream stream1("Tree1");
58 TTreeStream stream2("Tree2");
63 TObject *po = new TObject;
64 TObject *po2 = new TObject;
65 for (Int_t i=0;i<100000;i++) {
68 po2->SetUniqueID(i*100);
72 // The data layout of stream is defined during first invocation of streamer.
73 // Endl is the trigger which define the end of structure.
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";
80 //3.) just another example - we can fill the same tree with different objects
83 stream2<<f2<<po2<<"\n";
86 //4.) Close the streeamers (Write the streamed tree's to the file) and close the corresponding file.
93 //5.) and now see results in file tteststreamer.root
96 void TTreeSRedirector::Test2()
99 //Example test function to show functionality of TTreeSRedirector
102 //1.)create the redirector associated with file (testredirector.root)
105 TFile* file = new TFile("test.root","recreate");
106 TTreeSRedirector *pmistream= new TTreeSRedirector();
107 TTreeSRedirector &mistream = *pmistream;
111 TObject *po = new TObject;
112 TObject *po2 = new TObject;
113 for (Int_t i=0;i<100000;i++) {
116 po2->SetUniqueID(i*100);
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";
130 //3.) just another example - we can fill the same tree with different objects
132 mistream<<"TreeK"<<f<<po<<"\n";
133 mistream<<"TreeK"<<f2<<po2<<"\n";
136 //4.) write the streamed tree's to the file and close the corresponding file in destructor
141 //5.) and now see results in file testredirector.root
144 void TTreeSRedirector::Test()
147 //Example test function to show functionality of TTreeSRedirector
150 //1.)create the redirector associated with file (testredirector.root)
153 TTreeSRedirector *pmistream= new TTreeSRedirector("testredirector.root");
154 TTreeSRedirector &mistream = *pmistream;
158 TObject *po = new TObject;
159 TObject *po2 = new TObject;
160 for (Int_t i=0;i<100000;i++) {
163 po2->SetUniqueID(i*100);
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";
177 //3.) just another example - we can fill the same tree with different objects
179 mistream<<"TreeK"<<f<<po<<"\n";
180 mistream<<"TreeK"<<f2<<po2<<"\n";
183 //4.) write the streamed tree's to the file and close the corresponding file in destructor
187 //5.) and now see results in file testredirector.root
190 void TTreeSRedirector::UnitTest(){
196 UnitTestSparse(0.01);
199 void TTreeSRedirector::UnitTestSparse(Double_t scale){
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
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<20000; ientry++){
217 TVectorD vecRandom(50);
218 TVectorD vecZerro(50); // zerro vector
219 for (Int_t j=0; j<50; j++) vecRandom[j]=ientry+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;
228 pvecSparse=&vecRandom;
230 (*pcstream)<<"Full"<< // stored all vectors
234 (*pcstream)<<"SparseSkip"<< // fraction of vectors stored
236 "vec.="<<pvecSparse<<
238 (*pcstream)<<"SparseSkip0"<< // fraction with -pointer
240 "vec.="<<pvecSparse0<<
242 (*pcstream)<<"SparseZerro"<< // all vectors filled, franction filled with 0
244 "vec.="<<pvecSparse1<<
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");
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);
265 Int_t outlyersSparseSkip=treeSparseSkip->Draw("1","(vec.fElements-ientry-0.5)>0.5","goff");
266 Int_t outlyersSparseSkip0=treeSparseSkip0->Draw("1","(vec.fElements-ientry-0.5)>0.5","goff");
267 printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tOutlyersSkip\t%d\n",scale,outlyersSparseSkip);
268 printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tOutlyersSkip0\t%d\n",scale,outlyersSparseSkip);
270 Bool_t isOK=(ratio<1.2)&&(outlyersSparseSkip0);
271 printf("#UnitTest:\tTTreeSRedirector::TestSparse(%f)\tisOk\t%d\n",scale,isOK);
274 TTreeSRedirector::TTreeSRedirector(const char *fname,const char * option) :
276 fDirectoryOwner(kTRUE),
284 fDirectory = new TFile(fname,option);
288 fDirectory = gDirectory;
289 fDirectoryOwner = kFALSE;
293 TTreeSRedirector::~TTreeSRedirector()
298 Close(); //write the tree to the selected file
305 void TTreeSRedirector::StoreObject(TObject* object){
309 TDirectory * backup = gDirectory;
312 if (backup) backup->cd();
315 void TTreeSRedirector::SetDirectory(TDirectory *sfile){
317 // Set the external file
318 // In case other file already attached old file is closed before
319 // Redirector will be the owner of file ?
320 if (fDirectory && fDirectoryOwner) {
327 TTreeStream & TTreeSRedirector::operator<<(Int_t id)
330 // return reference to the data layout with given identifier
331 // if not existing - creates new
332 if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
333 TTreeStream *clayout=0;
334 Int_t entries = fDataLayouts->GetEntriesFast();
335 for (Int_t i=0;i<entries;i++){
336 TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
337 if (!layout) continue;
338 if (layout->fId==id) {
344 TDirectory * backup = gDirectory;
347 snprintf(chname,100,"Tree%d",id);
348 clayout = new TTreeStream(chname);
350 fDataLayouts->AddAt(clayout,entries);
351 if (backup) backup->cd();
356 void TTreeSRedirector::SetExternalTree(const char* name, TTree* externalTree)
358 TTreeStream *clayout=(TTreeStream*)fDataLayouts->FindObject(name);
361 TDirectory * backup = gDirectory;
363 clayout = new TTreeStream(name,externalTree);
365 clayout->SetName(name);
366 Int_t entries = fDataLayouts->GetEntriesFast();
367 fDataLayouts->AddAt(clayout,entries);
368 if (backup) backup->cd();
371 // AliError(Form("identifier %s already associated",name));
375 TTreeStream & TTreeSRedirector::operator<<(const char* name)
378 // return reference to the data layout with given identifier
379 // if not existing - creates new
380 if (!fDataLayouts) fDataLayouts = new TObjArray(10000);
381 TTreeStream *clayout=(TTreeStream*)fDataLayouts->FindObject(name);
382 Int_t entries = fDataLayouts->GetEntriesFast();
385 TDirectory * backup = gDirectory;
387 clayout = new TTreeStream(name);
389 clayout->SetName(name);
390 fDataLayouts->AddAt(clayout,entries);
391 if (backup) backup->cd();
399 void TTreeSRedirector::Close(){
402 TDirectory * backup = gDirectory;
405 Int_t entries = fDataLayouts->GetEntriesFast();
406 for (Int_t i=0;i<entries;i++){
407 TTreeStream * layout = (TTreeStream*)fDataLayouts->At(i);
409 if (layout->fTree) layout->fTree->Write(layout->GetName());
415 if (backup) backup->cd();
418 //-------------------------------------------------------------
419 TTreeDataElement:: TTreeDataElement(Char_t type) :
431 TTreeDataElement:: TTreeDataElement(TDataType* type) :
443 TTreeDataElement:: TTreeDataElement(TClass* cl) :
455 //-------------------------------------------------------------------
456 TTreeStream::TTreeStream(const char *treename, TTree* externalTree):
457 TNamed(treename,treename),
470 if (!fTree) fTree = new TTree(treename, treename);
473 TTreeStream::~TTreeStream()
484 void TTreeStream::Close()
487 // Flush data to disk and close
492 Int_t TTreeStream::CheckIn(Char_t type, void *pointer)
495 // Insert object of given type
497 if (!fElements) fElements = new TObjArray(10000);
498 if (fElements->GetSize()<=fCurrentIndex) fElements->Expand(fCurrentIndex*2);
499 TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
501 element = new TTreeDataElement(type);
504 if (fNextName.Length()>0){
505 if (fNextNameCounter==0){
506 snprintf(name,1000,"%s",(const char*)fNextName);
508 if (fNextNameCounter>0){
509 snprintf(name,1000,"%s%d",(const char*)fNextName,fNextNameCounter);
513 snprintf(name,1000,"B%d.",fCurrentIndex);
515 element->SetName(name);
517 element->SetPointer(pointer);
518 fElements->AddAt(element,fCurrentIndex);
520 return 0; //new element added
522 if (element->GetType()!=type){
524 return 1; //mismatched data element
526 element->SetPointer(pointer);
531 Int_t TTreeStream::CheckIn(TObject *pObject){
536 if (pObject) pClass=pObject->IsA();
537 if (!fElements) fElements = new TObjArray(1000);
538 TTreeDataElement* element = (TTreeDataElement*)fElements->At(fCurrentIndex);
540 element = new TTreeDataElement(pClass);
543 if (fNextName.Length()>0){
544 if (fNextNameCounter==0){
545 snprintf(name,1000,"%s",(const char*)fNextName);
547 if (fNextNameCounter>0){
548 snprintf(name,1000,"%s%d",(const char*)fNextName,fNextNameCounter);
552 snprintf(name,1000,"B%d",fCurrentIndex);
554 element->SetName(name);
556 element->SetPointer(pObject);
557 fElements->AddAt(element,fCurrentIndex);
559 return 0; //new element added
561 if (element->fClass==0) {
562 element->fClass=pClass;
564 if (element->fClass!=pClass){
566 return 1; //mismatched data element
569 element->SetPointer(pObject);
574 void TTreeStream::BuildTree(){
578 //if (fTree && fTree->GetEntries()>0) return;
579 if (!fTree) fTree = new TTree(GetName(),GetName());
580 Int_t entries = fElements->GetEntriesFast();
581 if (!fBranches) fBranches = new TObjArray(entries);
583 for (Int_t i=0;i<entries;i++){
585 TTreeDataElement* element = (TTreeDataElement*)fElements->At(i);
586 if (fBranches->At(i)) continue;
588 if (element->GetName()[0]==0){
589 snprintf(bname1,1000,"B%d",i);
592 snprintf(bname1,1000,"%s",element->GetName());
594 if (element->fClass){
595 if (element->fClass->GetBaseClass("TClonesArray")){
596 TBranch * br = fTree->Branch(bname1,element->fClass->GetName(),&(element->fPointer));
597 fBranches->AddAt(br,i);
600 TBranch * br = fTree->Branch(bname1,element->fClass->GetName(),&(element->fPointer));
601 fBranches->AddAt(br,i);
604 if (element->GetType()>0){
606 snprintf(bname2,1000,"B%d/%c",i,element->GetType());
607 TBranch * br = fTree->Branch(bname1,element->fPointer,bname2);
608 fBranches->AddAt(br,i);
613 void TTreeStream::Fill(){
618 Int_t entries=fElements->GetEntriesFast();
619 if (entries>fTree->GetNbranches()) BuildTree();
620 for (Int_t i=0;i<entries;i++){
621 TTreeDataElement* el = (TTreeDataElement*)fElements->At(i);
623 if (!el->GetType()) continue;
624 TBranch * br = (TBranch*)fBranches->At(i);
626 if (el->GetType()) br->SetAddress(el->fPointer);
629 if (fStatus==0) fTree->Fill(); //fill only in case of non conflicts
634 TTreeStream & TTreeStream::Endl()
637 // Perform pseudo endl operation
639 if (fTree->GetNbranches()==0) BuildTree();
647 TTreeStream &TTreeStream::operator<<(const Char_t *name)
656 //if tree was already defined ignore
657 if (fTree->GetEntries()>0) return *this;
658 //check branch name if tree was not
661 for (last=0;;last++){
662 if (name[last]==0) break;
665 if (last>0&&name[last-1]=='='){