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

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