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

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