]>
Commit | Line | Data |
---|---|---|
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 |