]> git.uio.no Git - u/mrichter/AliRoot.git/blame_incremental - STEER/STEERBase/TTreeStream.cxx
Update master to aliroot
[u/mrichter/AliRoot.git] / STEER / STEERBase / TTreeStream.cxx
... / ...
CommitLineData
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
43ClassImp(TTreeDataElement)
44ClassImp(TTreeStream)
45ClassImp(TTreeSRedirector)
46
47
48
49void 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
96void 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
144void 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
190void 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
199void 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
293TTreeSRedirector::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
312TTreeSRedirector::~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}
324void TTreeSRedirector::StoreObject(TObject* object){
325 //
326 //
327 //
328 TDirectory * backup = gDirectory;
329 fDirectory->cd();
330 object->Write();
331 if (backup) backup->cd();
332}
333
334void 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
346TTreeStream & 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
375void 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
394TTreeStream & 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
418void 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//-------------------------------------------------------------
438TTreeDataElement:: TTreeDataElement(Char_t type) :
439 TNamed(),
440 fType(type),
441 fDType(0),
442 fClass(0),
443 fPointer(0)
444{
445 //
446 //
447 //
448}
449
450TTreeDataElement:: TTreeDataElement(TDataType* type) :
451 TNamed(),
452 fType(0),
453 fDType(type),
454 fClass(0),
455 fPointer(0)
456{
457 //
458 //
459 //
460}
461
462TTreeDataElement:: TTreeDataElement(TClass* cl) :
463 TNamed(),
464 fType(0),
465 fDType(0),
466 fClass(cl),
467 fPointer(0)
468{
469 //
470 //
471 //
472}
473
474//-------------------------------------------------------------------
475TTreeStream::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
492TTreeStream::~TTreeStream()
493{
494 //
495 // Class dtor
496 //
497 fElements->Delete();
498 fBranches->Clear();
499 delete fElements;
500 delete fBranches;
501}
502
503void TTreeStream::Close()
504{
505 //
506 // Flush data to disk and close
507 //
508 fTree->Write();
509}
510
511Int_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
550Int_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
593void 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
653void 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
674TTreeStream & 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
687TTreeStream &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