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

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