source: trunk/MagicSoft/Mars/mfileio/MWriteRootFile.cc@ 3440

Last change on this file since 3440 was 3336, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 16.9 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz, 6/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2003
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26// //
27// MWriteRootFile //
28// //
29// This is a writer to store several containers to a root file. //
30// The containers are added with AddContainer. //
31// To understand how it works, see base class MWriteFile //
32// //
33// Warning: Checkout the Warning in MTaskList. //
34// //
35/////////////////////////////////////////////////////////////////////////////
36#include "MWriteRootFile.h"
37
38#include <fstream>
39
40#include <TFile.h>
41#include <TTree.h>
42
43#include "MLog.h"
44#include "MLogManip.h"
45
46#include "MParList.h"
47
48ClassImp(MRootFileBranch);
49ClassImp(MWriteRootFile);
50
51using namespace std;
52
53static const TString gsDefName = "MWriteRootFile";
54static const TString gsDefTitle = "Task which writes a root-output file";
55
56// --------------------------------------------------------------------------
57//
58// Default constructor. It is there to support some root stuff.
59// Don't use it.
60//
61MWriteRootFile::MWriteRootFile() : fOut(NULL)
62{
63 fName = gsDefName;
64 fTitle = gsDefTitle;
65
66 fBranches.SetOwner();
67}
68
69// --------------------------------------------------------------------------
70//
71// Specify the name of the root file. You can also give an option ("UPDATE"
72// and "RECREATE" would make sense only) as well as the file title and
73// compression factor. To a more detaild description of the options see
74// TFile.
75//
76MWriteRootFile::MWriteRootFile(const char *fname,
77 const Option_t *opt,
78 const char *ftitle,
79 const Int_t comp,
80 const char *name,
81 const char *title)
82{
83 fName = name ? name : gsDefName.Data();
84 fTitle = title ? title : gsDefTitle.Data();
85
86 //
87 // Set the Arrays the owner of its entries. This means, that the
88 // destructor of the arrays will delete all its entries.
89 //
90 fBranches.SetOwner();
91
92 //
93 // Believing the root user guide, TTree instanced are owned by the
94 // directory (file) in which they are. This means we don't have to
95 // care about their destruction.
96 //
97 //fTrees.SetOwner();
98
99 TString str(fname);
100 if (!str.EndsWith(".root", TString::kIgnoreCase))
101 str += ".root";
102
103 //
104 // Open the rootfile
105 //
106 fOut = new TFile(str, opt, ftitle, comp);
107}
108
109// --------------------------------------------------------------------------
110//
111// Prints some statistics about the file to the screen. And closes the file
112// properly.
113//
114MWriteRootFile::~MWriteRootFile()
115{
116 //
117 // Print some statistics to the looging out.
118 //
119 Print();
120
121 //
122 // If the file is still open (no error) write the keys. This is necessary
123 // for appearance of the all trees and branches.
124 //
125 if (IsFileOpen())
126 fOut->Write();
127
128 //
129 // Delete the file. This'll also close the file (if open)
130 //
131 delete fOut;
132
133 //
134 // Remark:
135 // - Trees are automatically deleted by the the file
136 // (unless file.SetDirectory(0) was called)
137 // - Branches are automatically deleted by the tree destructor
138 //
139
140 *fLog << inf << "Output File closed and object deleted." << endl;
141}
142
143// --------------------------------------------------------------------------
144//
145// Prints all trees with the actually number of written entries to log-out.
146//
147void MWriteRootFile::Print(Option_t *) const
148{
149 *fLog << all << underline << "File: " << GetFileName() << endl;
150
151 if (fTrees.GetEntries()==0)
152 {
153 *fLog << " No contents." << endl;
154 return;
155 }
156
157 TObject *obj;
158 TIter NextBranch(&fBranches);
159 while ((obj=NextBranch()))
160 {
161 MRootFileBranch *b = (MRootFileBranch*)obj;
162
163 if (!b->GetTree() || b->GetTree()->TestBit(kIsNewTree))
164 continue;
165
166 TBranch *branch = b->GetBranch();
167
168 TString name = b->GetTree()->GetName();
169 name += '.';
170 name += branch->GetName();
171
172 *fLog << " " << name.Strip(TString::kTrailing, '.') << ": \t" << branch->GetEntries() << " entries." << endl;
173 }
174
175 TTree *t = NULL;
176 TIter NextTree(&fTrees);
177 while ((t=(TTree*)NextTree()))
178 if (t->TestBit(kIsNewTree))
179 *fLog << " " << t->GetName() << ": \t" << t->GetEntries() << " entries." << endl;
180 *fLog << endl;
181}
182
183// --------------------------------------------------------------------------
184//
185// Add a new Container to list of containers which should be written to the
186// file. Give the name of the container which will identify the container
187// in the parameterlist. tname is the name of the tree to which the
188// container should be written (Remark: one tree can hold more than one
189// container). The default is the same name as the container name.
190// You can slso specify a title for the tree. This is only
191// used the first time this tree in 'mentioned'. As default the title
192// is the name of the tree.
193//
194void MWriteRootFile::AddContainer(const char *cname, const char *tname, Bool_t must)
195{
196 //
197 // create a new entry in the list of branches to write and
198 // add the entry to the list.
199 //
200 MRootFileBranch *entry = new MRootFileBranch(cname, tname, must);
201 fBranches.AddLast(entry);
202
203 if (tname && tname[0])
204 AddToBranchList(Form("%s.%s", cname, tname));
205}
206
207// --------------------------------------------------------------------------
208//
209// Add a new Container to list of containers which should be written to the
210// file. Give the pointer to the container. tname is the name of the tree to
211// which the container should be written (Remark: one tree can hold more than
212// one container). The default is the same name as the container name.
213// You can slso specify a title for the tree. This is only
214// used the first time this tree in 'mentioned'. As default the title
215// is the name of the tree.
216//
217void MWriteRootFile::AddContainer(MParContainer *cont, const char *tname,
218 Bool_t must)
219{
220 //
221 // create a new entry in the list of branches to write and
222 // add the entry to the list.
223 //
224 MRootFileBranch *entry = new MRootFileBranch(cont, tname, must);
225 fBranches.AddLast(entry);
226}
227
228// --------------------------------------------------------------------------
229//
230// Add a new Container to list of containers which should be written to the
231// file. Give the pointer to the container. tname is the name of the tree to
232// which the container should be written (Remark: one tree can hold more than
233// one container). The default is the same name as the container name.
234// You can slso specify a title for the tree. This is only
235// used the first time this tree in 'mentioned'. As default the title
236// is the name of the tree.
237//
238Bool_t MWriteRootFile::GetContainer(MParList *pList)
239{
240 //
241 // loop over all branches which are 'marked' as branches to get written.
242 //
243 MRootFileBranch *entry;
244
245 TIter Next(&fBranches);
246 while ((entry=(MRootFileBranch*)Next()))
247 {
248 //
249 // Get the pointer to the container. If the pointer is NULL it seems,
250 // that the user identified the container by name.
251 //
252 MParContainer *cont = entry->GetContainer();
253 if (!cont)
254 {
255 //
256 // Get the name and try to find a container with this name
257 // in the parameter list.
258 //
259 const char *cname = entry->GetContName();
260 cont = (MParContainer*)pList->FindObject(cname);
261 if (!cont)
262 {
263 //
264 // No corresponding container is found
265 //
266 if (entry->MustHave())
267 {
268 *fLog << err << "Cannot find parameter container '" << cname << "'." << endl;
269 return kFALSE;
270 }
271
272 *fLog << inf << "Unnecessary parameter container '" << cname << "' not found..." << endl;
273 delete fBranches.Remove(entry);
274 continue;
275 }
276
277 //
278 // The container is found. Put the pointer into the entry.
279 //
280 entry->SetContainer(cont);
281 }
282
283 //
284 // Get container name, tree name and tree title of this entry.
285 //
286 const char *cname = cont->GetName();
287 const char *tname = entry->GetName();
288 const TString ttitle(Form("Tree containing %s", cont->GetDescriptor()));
289
290 //
291 // if the tree name is NULL this idetifies it to use the default:
292 // the container name.
293 //
294 if (tname[0] == '\0')
295 tname = cname;
296
297 //
298 // Check if the tree is already existing (part of the file)
299 //
300 TTree *tree = (TTree*)fOut->Get(tname);
301 if (!tree)
302 {
303 //
304 // if the tree doesn't exist create a new tree. Use the tree
305 // name as title if title is NULL.
306 // And add the tree to the list of trees
307 //
308 TDirectory *save = gDirectory;
309 fOut->cd();
310
311 tree = new TTree(tname, ttitle);
312 fTrees.AddLast(tree);
313
314 //
315 // If the tree does not already exist in the file mark this
316 // tree as a branch created by MWriteRootFile
317 //
318 tree->SetBit(kIsNewTree);
319
320 gDirectory = save;
321
322 *fLog << inf << "Tree " << tname << " created." << endl;
323 }
324
325 //
326 // In case the file is opened as 'UPDATE' the tree may still not
327 // be in the list. Because it neither was created previously,
328 // nor this time, so the corresponding entries is marked as a
329 // single branch to be filled. --> Add it to the list of trees.
330 //
331 if (!fTrees.FindObject(tree))
332 fTrees.AddLast(tree);
333
334 //
335 // Now we have a valid tree. Search the list of trees for this tree
336 // Add a pointer to the entry in the tree list to this branch-entry
337 //
338 entry->SetTree(tree);
339
340 TString branchname(cname);
341 branchname.Append(".");
342
343 //
344 // Try to get the branch from the file.
345 // If the branch already exists the user specified one branch twice.
346 //
347 TBranch *branch = tree->GetBranch(branchname);
348 if (branch)
349 {
350 *fLog << inf << "Branch '" << cname << "' already existing... updating." << endl;
351 branch->SetAddress(entry->GetAddress());
352 }
353 else
354 {
355 //
356 // Create a new branch in the actual tree. The branch has the name
357 // container name. The type of the container is given by the
358 // ClassName entry in the container. The Address is the address of a
359 // pointer to the container (gotten from the branch entry). As
360 // Basket size we specify a (more or less) common default value.
361 // The containers should be written in Splitlevel=1
362 //
363 *fLog << inf << "Creating Branch " << cname << " of " << cont->ClassName();
364 *fLog << " in tree " << tree->GetName() << "... " << flush;
365
366 branch = tree->Branch(branchname, cont->ClassName(), entry->GetAddress());
367 //
368 // If the branch couldn't be created we have a problem.
369 //
370 if (!branch)
371 {
372 *fLog << endl;
373 *fLog << err << "Unable to create branch '" << cname << "'." << endl;
374 return kFALSE;
375 }
376
377 *fLog << "done." << endl;
378 }
379
380 //
381 // Tell the entry also which branch belongs to it (this is necessary
382 // for branches belonging to already existing tree, UPDATE-mode)
383 //
384 entry->SetBranch(branch);
385 }
386 return kTRUE;
387}
388
389// --------------------------------------------------------------------------
390//
391// Checks all given containers (branch entries) for the write flag.
392// If the write flag is set the corresponding Tree is marked to get filled.
393// All Trees which are marked to be filled are filled with all their
394// branches.
395// In case of a file opened in 'UPDATE' mode, single branches can be
396// filled, too. WARNING - for the moment there is no check whether
397// you filled the correct number of events into the branch, so that
398// each of the other branches in the tree has the correct corresponding
399// number of new entries in the new branch!
400// Be carefull: If only one container (corresponding to a branch) of a tree
401// has the write flag, all containers in this tree are filled!
402//
403Bool_t MWriteRootFile::CheckAndWrite() const
404{
405 TObject *obj;
406
407 //
408 // Loop over all branch entries
409 //
410 TIter NextBranch(&fBranches);
411 while ((obj=NextBranch()))
412 {
413 MRootFileBranch *b = (MRootFileBranch*)obj;
414
415 //
416 // Check for the Write flag
417 //
418 if (!b->GetContainer()->IsReadyToSave())
419 continue;
420
421 //
422 // If the write flag of the branch entry is set, set the write flag of
423 // the corresponding tree entry.
424 //
425 if (b->GetTree()->TestBit(kIsNewTree))
426 b->GetTree()->SetBit(kFillTree);
427 else
428 {
429 if (!b->GetBranch()->Fill())
430 {
431 *fLog << err << "ERROR - Zero bytes written to branch '" << b->GetBranch()->GetName() << "'... abort." << endl;
432 return kFALSE;
433 }
434 }
435 }
436
437 //
438 // Loop over all tree entries
439 //
440 TIter NextTree(&fTrees);
441 while ((obj=NextTree()))
442 {
443 TTree *t = (TTree*)obj;
444
445 //
446 // Check the write flag of the tree
447 //
448 if (!t->TestBit(kFillTree))
449 continue;
450
451 //
452 // If the write flag is set, fill the tree (with the corresponding
453 // branches/containers), delete the write flag and increase the number
454 // of written/filled entries.
455 //
456 t->ResetBit(kFillTree);
457 if (!t->Fill())
458 {
459 *fLog << err << "ERROR - Zero bytes written to tree '" << t->GetName() << "'... abort." << endl;
460 return kFALSE;
461 }
462 }
463 return kTRUE;
464}
465
466// --------------------------------------------------------------------------
467//
468// return open state of the root file.
469//
470Bool_t MWriteRootFile::IsFileOpen() const
471{
472 return fOut->IsOpen();
473}
474
475// --------------------------------------------------------------------------
476//
477// return name of the root-file
478//
479const char *MWriteRootFile::GetFileName() const
480{
481 return fOut->GetName();
482}
483
484// --------------------------------------------------------------------------
485//
486// Implementation of SavePrimitive. Used to write the call to a constructor
487// to a macro. In the original root implementation it is used to write
488// gui elements to a macro-file.
489//
490void MWriteRootFile::StreamPrimitive(ofstream &out) const
491{
492 out << " MWriteRootFile " << GetUniqueName() << "(\"";
493 out << fOut->GetName() << "\", \"";
494 out << fOut->GetOption() << "\", \"";
495 out << fOut->GetTitle() << "\", ";
496 out << fOut->GetCompressionLevel();
497
498 if (fName!=gsDefName || fTitle!=gsDefTitle)
499 {
500 out << ", \"" << fName << "\"";
501 if (fTitle!=gsDefTitle)
502 out << ", \"" << fTitle << "\"";
503 }
504 out << ");" << endl;
505
506
507 MRootFileBranch *entry;
508 TIter Next(&fBranches);
509 while ((entry=(MRootFileBranch*)Next()))
510 {
511 out << " " << GetUniqueName() << ".AddContainer(";
512
513 if (entry->GetContainer())
514 {
515 entry->GetContainer()->SavePrimitive(out);
516 out << "&" << entry->GetContainer()->GetUniqueName();
517 }
518 else
519 out << "\"" << entry->GetContName() << "\"";
520
521 out << ", \"" << entry->GetName() << "\"";
522 if (!entry->MustHave())
523 out << ", kFALSE";
524
525 out <<");" << endl;
526 }
527}
Note: See TracBrowser for help on using the repository browser.