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

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