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

Last change on this file since 9254 was 9230, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 34.5 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: Software Development, 2000-2009
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: Look at the Warning in MTaskList.
34//
35// There is a special mode of operation which opens a new file for each new
36// file read by the reading task (opening the new file is initiated by
37// ReInit()) For more details see the corresponding constructor.
38//
39// Memory based trees
40// ------------------
41// It is possible to store the data into memory (TTrees) instead of
42// writing the data into a file. To do this either call the default
43// constructor or specify 'memory' as option in the constructor.
44//
45// Afterwards the tree can be found using
46// gROOT->GetListOfFiles()->FindObject("treename")
47//
48// Currently(!) the tree is not deleted at all! Please make sure to
49// delete it if it is not used anymore - otherwise you could wast a LOT
50// of memory. Please consider that this behaviour might change in the
51// future.
52//
53// Such trees are usefull if you want to use more basic root-tools
54// like TMultiLayerPerceptron or TEventList.
55//
56// If you want to process such memory based Trees using Mars make sure,
57// that you don't need data from the RunHeader tree because you can
58// only use MReadTree but not MReadMarsFile with such a tree.
59//
60/////////////////////////////////////////////////////////////////////////////
61#include "MWriteRootFile.h"
62
63#include <fstream>
64
65#include <TFile.h>
66#include <TTree.h>
67#include <TPRegexp.h>
68
69#include "MLog.h"
70#include "MLogManip.h"
71
72#include "MRead.h"
73#include "MParList.h"
74#include "MStatusDisplay.h"
75
76ClassImp(MRootFileBranch);
77ClassImp(MWriteRootFile);
78
79using namespace std;
80
81const TString MWriteRootFile::gsDefName = "MWriteRootFile";
82const TString MWriteRootFile::gsDefTitle = "Task which writes a root-output file";
83
84void MWriteRootFile::Init(const char *name, const char *title)
85{
86 fName = name ? name : gsDefName.Data();
87 fTitle = title ? title : gsDefTitle.Data();
88
89 //
90 // Set the Arrays the owner of its entries. This means, that the
91 // destructor of the arrays will delete all its entries.
92 //
93 fBranches.SetOwner();
94 fCopies.SetOwner();
95
96 //
97 // Believing the root user guide, TTree instances are owned by the
98 // directory (file) in which they are. This means we don't have to
99 // care about their destruction.
100 //
101 //fTrees.SetOwner();
102
103 gROOT->GetListOfCleanups()->Add(this); // To remove fOut if deleted
104}
105
106// --------------------------------------------------------------------------
107//
108// Try to get the file from gROOT->GetListOfFiles.
109// If it is found fOut is set to it and returned.
110// Otherwise a new file is opened and returned.
111//
112TFile *MWriteRootFile::OpenFile(const char *name, Option_t *option, const char *title, Int_t comp)
113{
114 TFile *file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(name));
115
116 // If the file was not found with its name try its expanded name
117 if (!file)
118 {
119 TString fqp(name);
120 gSystem->ExpandPathName(fqp);
121 file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(fqp));
122 }
123
124 if (!file || TString(name)=="/dev/null")
125 {
126 file = new TFile(name, option, title, comp);
127 if (!file->IsOpen())
128 {
129 delete file;
130 return NULL;
131 }
132
133 file->SetOption(option); // IMPORTANT!
134 file->SetBit(kMustCleanup);
135 ResetBit(kIsNotOwner);
136 return file;
137 }
138
139 fOut = file;
140 fOut->SetBit(kMustCleanup);
141 SetBit(kIsNotOwner);
142
143 *fLog << inf;
144 *fLog << "File '" << name << "' already open... using." << endl;
145 *fLog << "Make sure that you do NOT write to trees which are" << endl;
146 *fLog << "scheduled already by a different MWriteRootFile..." << endl;
147 return fOut;
148}
149
150// --------------------------------------------------------------------------
151//
152// Default constructor. It is there to support some root stuff.
153// Don't use it.
154//
155MWriteRootFile::MWriteRootFile() : fOut(NULL)
156{
157 Init();
158}
159
160// --------------------------------------------------------------------------
161//
162// Use this constructor to run in a special mode.
163//
164// In this mode for each input file a new output file is written. This
165// happens in ReInit.
166//
167// comp: Compression Level (see TFile, TBranch)
168// rule: Rule to create output file name (see GetNewFileName())
169// overwrite: Allow newly created file to overwrite old files ("RECREATE")
170// ftitle: File title stored in the file (see TFile)
171// name, title: Name and title of this object
172//
173MWriteRootFile::MWriteRootFile(const Int_t comp,
174 const char *rule,
175 const Option_t *option,
176 const char *ftitle,
177 const char *name,
178 const char *title) : fSplitRule(rule)
179{
180 Init(name, title);
181
182 //
183 // Open a TFile in dummy mode! This is necessary to be able to create
184 // the trees and branches, which are then (in ReInit) moved to
185 // a valid file. (Stupid workaround - but does a good job)
186 //
187 fOut = OpenFile("/dev/null", option, ftitle, comp);
188}
189
190// --------------------------------------------------------------------------
191//
192// Specify the name of the root file. You can also give an option ("UPDATE"
193// and "RECREATE" would make sense only) as well as the file title and
194// compression factor. To a more detaild description of the options see
195// TFile.
196//
197// To create a memory based TTree use
198// fname = name of TTree
199// option = "memory"
200// Make sure you do not read from a tree with the same name!
201//
202MWriteRootFile::MWriteRootFile(const char *fname,
203 const Option_t *option,
204 const char *ftitle,
205 const Int_t comp,
206 const char *name,
207 const char *title) : fOut(NULL)
208{
209 Init(name, title);
210
211 TString opt(option);
212 opt.ToLower();
213
214 //
215 // Check if we are writing to memory
216 //
217 if (opt.Contains("memory", TString::kIgnoreCase))
218 {
219 fSplitRule = fname;
220 return;
221 }
222
223 //
224 // If no name is given we open the TFile in some kind of dummy mode...
225 //
226 TString str(fname);
227 if (str.IsNull())
228 {
229 fOut = new TFile("/dev/null", "READ", ftitle, comp);
230 fOut->SetBit(kMustCleanup);
231 return;
232 }
233
234 if (!str.EndsWith(".root", TString::kIgnoreCase))
235 str += ".root";
236
237 //
238 // Open the rootfile
239 //
240 fOut = OpenFile(str, opt, ftitle, comp);
241}
242
243// --------------------------------------------------------------------------
244//
245// Prints some statistics about the file to the screen. And closes the file
246// properly.
247//
248void MWriteRootFile::Close()
249{
250 //
251 // Print some statistics to the looging out.
252 //
253 if (fOut && !TestBit(kIsNotOwner))
254 {
255 Print();
256
257 //
258 // If the file is still open (no error) write the keys. This is necessary
259 // for appearance of the all trees and branches.
260 //
261 if (IsFileOpen())
262 fOut->Write();
263
264 //
265 // Delete the file. This'll also close the file (if open)
266 //
267 delete fOut;
268
269 //
270 // Remark:
271 // - Trees are automatically deleted by the the file
272 // (unless file.SetDirectory(0) was called)
273 // - Branches are automatically deleted by the tree destructor
274 //
275 *fLog << inf << "Output File closed and object deleted." << endl;
276 }
277
278 fOut = 0;
279}
280
281// --------------------------------------------------------------------------
282//
283// call Close()
284//
285MWriteRootFile::~MWriteRootFile()
286{
287 Close();
288}
289
290// --------------------------------------------------------------------------
291//
292// Prints all trees with the actually number of written entries to log-out.
293//
294void MWriteRootFile::Print(Option_t *) const
295{
296 if (!fOut)
297 return;
298
299 *fLog << all << underline << "File: " << GetFileName() << dec << endl;
300
301 if (fTrees.GetEntries()==0)
302 {
303 *fLog << " No contents." << endl;
304 return;
305 }
306
307 TObject *obj;
308 TIter NextBranch(&fBranches);
309 while ((obj=NextBranch()))
310 {
311 MRootFileBranch *b = (MRootFileBranch*)obj;
312
313 if (!b->GetTree() || b->GetTree()->TestBit(kIsNewTree))
314 continue;
315
316 TBranch *branch = b->GetBranch();
317
318 TString name = b->GetTree()->GetName();
319 name += '.';
320 name += branch->GetName();
321
322 *fLog << " + " << name.Strip(TString::kTrailing, '.') << ": \t" << (ULong_t)branch->GetEntries() << " entries." << endl;
323 }
324
325 TTree *t = NULL;
326 TIter NextTree(&fTrees);
327 while ((t=(TTree*)NextTree()))
328 if (t->TestBit(kIsNewTree))
329 *fLog << " + " << t->GetName() << ": \t" << (ULong_t)t->GetEntries() << " entries." << endl;
330
331 TIter NextKey(fOut->GetList());
332 while ((obj=NextKey()))
333 {
334 if (!obj->InheritsFrom(TTree::Class()))
335 continue;
336
337 if (fTrees.FindObject(obj) && obj->TestBit(kIsNewTree))
338 continue;
339
340 *fLog << " - " << obj->GetName() << ": \t" << (ULong_t)((TTree*)obj)->GetEntries() << " entries." << endl;
341 }
342 *fLog << endl;
343}
344
345// --------------------------------------------------------------------------
346//
347// Add a new Container to list of containers which should be written to the
348// file. Give the name of the container which will identify the container
349// in the parameterlist. tname is the name of the tree to which the
350// container should be written (Remark: one tree can hold more than one
351// container). The default is the same name as the container name.
352// You can slso specify a title for the tree. This is only
353// used the first time this tree in 'mentioned'. As default the title
354// is the name of the tree.
355//
356void MWriteRootFile::AddContainer(const char *cname, const char *tname, Bool_t must)
357{
358 if (!fOut && !tname)
359 tname = fSplitRule;
360
361 TIter Next(&fBranches);
362 TObject *o=0;
363 while ((o=Next()))
364 if (TString(o->GetName())==TString(tname) && TString(o->GetTitle())==TString(cname))
365 {
366 *fLog << warn;
367 *fLog << "WARNING - Container '" << cname << "' in Tree '" << tname << "' already scheduled... ignored." << endl;
368 return;
369 }
370
371 //
372 // create a new entry in the list of branches to write and
373 // add the entry to the list.
374 //
375 MRootFileBranch *entry = new MRootFileBranch(AddSerialNumber(cname), tname, must);
376 fBranches.AddLast(entry);
377
378 if (tname && tname[0])
379 AddToBranchList(Form("%s.%s", (const char*)AddSerialNumber(cname), tname));
380}
381
382// --------------------------------------------------------------------------
383//
384// Add a new Container to list of containers which should be written to the
385// file. Give the pointer to the container. tname is the name of the tree to
386// which the container should be written (Remark: one tree can hold more than
387// one container). The default is the same name as the container name.
388// You can slso specify a title for the tree. This is only
389// used the first time this tree in 'mentioned'. As default the title
390// is the name of the tree.
391//
392void MWriteRootFile::AddContainer(MParContainer *cont, const char *tname, Bool_t must)
393{
394 if (!fOut && !tname)
395 tname = fSplitRule;
396
397 TIter Next(&fBranches);
398 TObject *o=0;
399 while ((o=Next()))
400 if (TString(o->GetName())==TString(tname) &&
401 static_cast<MRootFileBranch*>(o)->GetContainer()==cont)
402 {
403 *fLog << warn;
404 *fLog << "WARNING - Container " << cont << " in Tree '" << tname << "' already scheduled... ignored." << endl;
405 return;
406 }
407
408 //
409 // create a new entry in the list of branches to write and
410 // add the entry to the list.
411 //
412 MRootFileBranch *entry = new MRootFileBranch(cont, tname, must);
413 fBranches.AddLast(entry);
414}
415
416// --------------------------------------------------------------------------
417//
418// If you want to copy a full tree (or some branches of some trees)
419// completely from one file to another one you can use this
420//
421void MWriteRootFile::AddCopySource(const char *tname, const char *bname)
422{
423 fCopies.Add(new TNamed(tname, bname?bname:"*"));
424 fCopies.Sort();
425}
426
427// --------------------------------------------------------------------------
428//
429// Add a new Container to list of containers which should be written to the
430// file. Give the pointer to the container. tname is the name of the tree to
431// which the container should be written (Remark: one tree can hold more than
432// one container). The default is the same name as the container name.
433// You can slso specify a title for the tree. This is only
434// used the first time this tree in 'mentioned'. As default the title
435// is the name of the tree.
436//
437Bool_t MWriteRootFile::GetContainer(MParList *pList)
438{
439 //
440 // loop over all branches which are 'marked' as branches to get written.
441 //
442 MRootFileBranch *entry;
443
444 TIter Next(&fBranches);
445 while ((entry=(MRootFileBranch*)Next()))
446 {
447 //
448 // Get the pointer to the container. If the pointer is NULL it seems,
449 // that the user identified the container by name.
450 //
451 MParContainer *cont = entry->GetContainer();
452 if (!cont)
453 {
454 //
455 // Get the name and try to find a container with this name
456 // in the parameter list.
457 //
458 const char *cname = entry->GetContName();
459 cont = (MParContainer*)pList->FindObject(cname);
460 if (!cont)
461 {
462 //
463 // No corresponding container is found
464 //
465 if (entry->MustHave())
466 {
467 *fLog << err << "Cannot find parameter container '" << cname << "'." << endl;
468 return kFALSE;
469 }
470
471 *fLog << inf2 << "Unnecessary parameter container '" << cname << "' not found..." << endl;
472 delete fBranches.Remove(entry);
473 continue;
474 }
475
476 //
477 // The container is found. Put the pointer into the entry.
478 //
479 entry->SetContainer(cont);
480 }
481
482 //
483 // Get container name, tree name and tree title of this entry.
484 //
485 const char *cname = cont->GetName();
486 const char *tname = entry->GetName();
487 const TString ttitle(Form("Tree containing %s", cont->GetDescriptor().Data()));
488
489 //
490 // if the tree name is NULL this idetifies it to use the default:
491 // the container name.
492 //
493 if (tname[0] == '\0')
494 tname = cname;
495
496 //
497 // Check if the tree is already existing (part of the file or memory)
498 //
499 TTree *tree = fOut ? (TTree*)fOut->Get(tname) : dynamic_cast<TTree*>(gROOT->FindObject(tname));
500 if (!fOut && tree)
501 {
502 if (tree->GetCurrentFile())
503 {
504 *fLog << err;
505 *fLog << "ERROR - You are trying to write data into a memory stored root tree," << endl;
506 *fLog << " because you either called the default constructor or have" << endl;
507 *fLog << " instantiated MWriteRootFile using the write option 'memory'." << endl;
508 *fLog << " This tree '" << tname << "' is already existing in" << endl;
509 *fLog << " memory (gROOT->FindObject) and is already belonging to a" << endl;
510 *fLog << " file (" << tree->GetCurrentFile()->GetName() << ")." << endl;
511 *fLog << " This can - for example - happen if you are reading from a" << endl;
512 *fLog << " tree with the same name. The easiest solution in this case" << endl;
513 *fLog << " is to change the name of the tree you want to write to." << endl;
514 *fLog << endl;
515 return kFALSE;
516 }
517 *fLog << inf << "Tree '" << tname << "' found already in Memory... using." << endl;
518 }
519
520 if (!tree)
521 {
522 //
523 // if the tree doesn't exist create a new tree. Use the tree
524 // name as title if title is NULL.
525 // And add the tree to the list of trees
526 //
527 TDirectory *save = gDirectory;
528 if (fOut)
529 fOut->cd();
530 else
531 gROOT->cd();
532
533 tree = new TTree(tname, ttitle, fOut ? 99 : 1);
534 fTrees.AddLast(tree);
535
536 //
537 // If the tree does not already exist in the file mark this
538 // tree as a branch created by MWriteRootFile
539 //
540 tree->SetBit(kIsNewTree);
541
542 *fLog << inf << "Tree " << tname << " created in " << gDirectory->GetName() << endl;
543
544 gDirectory = save;
545 }
546
547 //
548 // In case the file is opened as 'UPDATE' the tree may still not
549 // be in the list. Because it neither was created previously,
550 // nor this time, so the corresponding entries is marked as a
551 // single branch to be filled. --> Add it to the list of trees.
552 //
553 if (!fTrees.FindObject(tree))
554 fTrees.AddLast(tree);
555
556 //
557 // Now we have a valid tree. Search the list of trees for this tree
558 // Add a pointer to the entry in the tree list to this branch-entry
559 //
560 entry->SetTree(tree);
561
562 TString branchname(cname);
563 branchname.Append(".");
564
565 //
566 // Try to get the branch from the file.
567 // If the branch already exists the user specified one branch twice.
568 //
569 TBranch *branch = tree->GetBranch(branchname);
570 if (branch)
571 {
572 *fLog << inf << "Branch '" << cname << "' already existing... updating." << endl;
573 branch->SetAddress(entry->GetAddress());
574
575 if (!fSplitRule.IsNull() && fOut)
576 {
577 *fLog << warn << endl;
578 *fLog << "WARNING: You are updating an existing branch. For this case" << endl;
579 *fLog << " file-splitting mode is not allowed... disabled!" << endl;
580 *fLog << endl;
581 fSplitRule = "";
582 }
583 }
584 else
585 {
586 //
587 // Create a new branch in the actual tree. The branch has the name
588 // container name. The type of the container is given by the
589 // ClassName entry in the container. The Address is the address of a
590 // pointer to the container (gotten from the branch entry). As
591 // Basket size we specify a (more or less) common default value.
592 // The containers should be written in Splitlevel=1
593 //
594 *fLog << inf << "Creating Branch '" << cname << "' ";
595 if ((TString)cname!=(TString)cont->ClassName())
596 *fLog << "[" << cont->ClassName() << "] ";
597 *fLog << "in tree " << tree->GetName() << "... " << flush;
598
599 branch = tree->Branch(branchname, cont->ClassName(), entry->GetAddress());
600
601 //
602 // If the branch couldn't be created we have a problem.
603 //
604 if (!branch)
605 {
606 *fLog << endl;
607 *fLog << err << "Unable to create branch '" << cname << "'." << endl;
608 return kFALSE;
609 }
610
611 *fLog << "done." << endl;
612
613 if (!tree->TestBit(kIsNewTree) && !fSplitRule.IsNull())
614 {
615 *fLog << warn << endl;
616 *fLog << "WARNING: You have created a new branch in an existing tree." << endl;
617 *fLog << " For this case file-splitting mode is not allowed... disabled!" << endl;
618 *fLog << endl;
619 fSplitRule= "";
620 }
621 }
622
623 //
624 // Tell the entry also which branch belongs to it (this is necessary
625 // for branches belonging to already existing tree, UPDATE-mode)
626 //
627 entry->SetBranch(branch);
628 }
629
630 return kTRUE;
631}
632
633// --------------------------------------------------------------------------
634//
635// Checks all given containers (branch entries) for the write flag.
636// If the write flag is set the corresponding Tree is marked to get filled.
637// All Trees which are marked to be filled are filled with all their
638// branches.
639// In case of a file opened in 'UPDATE' mode, single branches can be
640// filled, too. WARNING - for the moment there is no check whether
641// you filled the correct number of events into the branch, so that
642// each of the other branches in the tree has the correct corresponding
643// number of new entries in the new branch!
644// Be carefull: If only one container (corresponding to a branch) of a tree
645// has the write flag, all containers in this tree are filled!
646//
647Bool_t MWriteRootFile::CheckAndWrite()
648{
649 TObject *obj;
650
651 //
652 // Loop over all branch entries
653 //
654 TIter NextBranch(&fBranches);
655 while ((obj=NextBranch()))
656 {
657 MRootFileBranch *b = (MRootFileBranch*)obj;
658
659 //
660 // Check for the Write flag
661 //
662 if (!b->GetContainer()->IsReadyToSave())
663 continue;
664
665 //
666 // If the write flag of the branch entry is set, set the write flag of
667 // the corresponding tree entry.
668 //
669 if (b->GetTree()->TestBit(kIsNewTree))
670 b->GetTree()->SetBit(kFillTree);
671 else
672 {
673 if (!b->GetBranch()->Fill())
674 {
675 *fLog << err << "ERROR - Zero bytes written to branch '" << b->GetBranch()->GetName() << "'... abort." << endl;
676 return kFALSE;
677 }
678 }
679 }
680
681 //
682 // Loop over all tree entries
683 //
684 const Int_t n = fTrees.GetEntriesFast();
685
686 for (int idx=0; idx<n; idx++)
687 {
688 TTree *t = (TTree*)fTrees[idx];
689
690 //
691 // Check the write flag of the tree
692 //
693 if (!t->TestBit(kFillTree))
694 continue;
695
696 //
697 // If the write flag is set, fill the tree (with the corresponding
698 // branches/containers), delete the write flag and increase the number
699 // of written/filled entries.
700 //
701 t->ResetBit(kFillTree);
702
703 if (!t->Fill())
704 {
705 *fLog << err << "ERROR - Zero bytes written to tree '" << t->GetName() << "'... abort." << endl;
706 return kFALSE;
707 }
708 }
709
710 //
711 // If we are writing into memory we don't split into seperate files
712 //
713 if (!fOut || TestBit(kIsNotOwner))
714 return kTRUE;
715
716 //
717 // For more information see TTree:ChangeFile()
718 //
719 TTree *t0 = (TTree*)fTrees[0];
720 if (!t0 || fOut==t0->GetCurrentFile())
721 return kTRUE;
722
723 // FIXME: THIS IS EMITTED FOR ALL CONSEQUTIVE EVENTS!
724 *fLog << warn << endl;
725 *fLog << "WARNING - MWriteRootFile: Root's TTree/TFile has opened a new file" << endl;
726 *fLog << " automatically. You can change this behaviour using TTree::SetMaxTreeSize." << endl;
727 *fLog << " You won't be able to read splitted files correctly with MReadMarsFile if" << endl;
728 *fLog << " they have more than one entry in 'RunHeaders' or you try to read more than" << endl;
729 *fLog << " one of such sequences at once." << endl;
730 *fLog << endl;
731
732 return kTRUE;
733}
734
735// --------------------------------------------------------------------------
736//
737// Open a new file with the name fname. Move all trees and branches from the
738// old file to the new file.
739//
740Bool_t MWriteRootFile::ChangeFile(const char *fname)
741{
742 const Int_t compr = fOut ? fOut->GetCompressionLevel() : 0;
743 const TString title = fOut ? fOut->GetTitle() : "";
744 const TString opt = fOut ? fOut->GetOption() : "";
745
746 // Open new file with old setup
747 TFile *newfile = OpenFile(fname, opt, title, compr);
748 if (newfile && newfile==fOut)
749 {
750 *fLog << inf << "Found open file " << fname << "... using." << endl;
751 return kTRUE;
752 }
753 if (!newfile)
754 {
755 *fLog << err << "ERROR - Cannot open new file " << fname << endl;
756 return kFALSE;
757 }
758
759 if (!fOut)
760 {
761 *fLog << err << "ERROR - MWriteRootFile::ChangeFile... something went terribly wrong!" << endl;
762 *fLog << " fname: " << fname << endl;
763 *fLog << " Please start debugging!" << endl;
764 return kFALSE;
765 }
766
767 *fLog << inf << "Open new file " << fname << " (Title=" << title << ", Option=" << opt << ", Compression=" << compr << ")" << endl;
768
769 // Print statistics of old file
770 const TString n = GetFileName();
771 if (!n.IsNull() && n!=TString("/dev/null"))
772 Print();
773
774 if (fOut->IsOpen())
775 fOut->Write();
776
777 // Move all trees from the old file to the new file
778 TObject *obj=0;
779 while ((obj = fOut->GetList()->First()))
780 {
781 // Remove obj from old file (otherwise deleting
782 // the old file will delete the objs)
783 fOut->GetList()->Remove(obj);
784
785 // If this is not a tree do nothing.
786 if (!obj->InheritsFrom(TTree::Class()))
787 continue;
788
789 // process all trees in the old file
790 TTree *t = (TTree*)obj;
791
792 // reset and move to new file (this is done implicitly for all branches)
793 t->Reset();
794 t->SetDirectory(newfile);
795 }
796
797 // Close/delete the old file (keys already written above)
798 delete fOut;
799
800 // Replace current with new file
801 fOut = newfile;
802
803 // Change current directory to new file
804 gFile = fOut;
805
806 return kTRUE;
807}
808
809// --------------------------------------------------------------------------
810//
811// A rule looks like:
812// "s/source/destination/"
813//
814// For more details on regular expression see a proper documentation.
815//
816// Here is an example:
817//
818// Example:
819// inputfile: /data/MAGIC/Period016/rootdata/20040621_23210_D_Mkn421_E.root
820// rule: /([0-9]+_[0-9]+)_D_(.*[.]root)/\\/outpath\\/$1_Y_$2/
821// outfile: /outpath/20040621_23210_Y_Mkn421_E.root
822//
823// Please make sure that all / in your rules are correctly escaped, i.e.
824// in the string stored in memory it must look like \/ and in the string
825// your set in your program it must look \\/.
826//
827TString MWriteRootFile::GetNewFileName(const char *inname) const
828{
829 // Remove the path from the filename
830 TString fname(inname);
831 if (fname.Last('/')>=0)
832 fname.Remove(0, fname.Last('/')+1);
833
834 // Regular expression to split the rule into its contents
835 static const TString sed("s/((\\\\/|[^/])*)/((\\\\/|[^/])*)/([gimosxd]*)");
836
837 // Do splitting
838 TObjArray *subStrL = TPRegexp(sed).MatchS(fSplitRule);
839 if (subStrL->GetEntries()!=6)
840 {
841 *fLog << err << "ERROR - GetNewFileName: Evaluating split rule " << fSplitRule << " failed." << endl;
842 subStrL->Print();
843 delete subStrL;
844 return "";
845 }
846
847 /*const*/ TString reg = (*subStrL)[1]->GetName(); // Regular expression to search for
848 /*const*/ TString tar = (*subStrL)[3]->GetName(); // Regular expression for replacing
849 const TString mod = (*subStrL)[5]->GetName(); // Possible modifiers (e.g. 'a')
850
851 delete subStrL;
852
853 // Unescpae slashes in paths
854 reg.ReplaceAll("\\/", "/");
855 tar.ReplaceAll("\\/", "/");
856
857 // Do substitution
858 const Int_t nrSub = TPRegexp(reg).Substitute(fname, tar, mod);
859 if (nrSub==0)
860 {
861 gLog << err << "ERROR - Substituting due to SplitRule failed." << endl;
862 gLog << " Source FileName: " << fname << endl;
863 gLog << " Search Rexexp: " << reg << endl;
864 gLog << " Replace Rexexp: " << tar << endl;
865 gLog << " Modifiers: " << mod << endl;
866 return "";
867 }
868
869 return fname;
870}
871
872// --------------------------------------------------------------------------
873//
874// Writes a copy of the TTree t to the currently open file using
875// TTree::CloneTree()
876//
877void MWriteRootFile::CopyTree(TTree &t) const
878{
879 TString out = "Copy of tree ";
880 out += t.GetName();
881 out += " in progress...";
882
883 if (fDisplay)
884 fDisplay->SetStatusLine2(out);
885
886 *fLog << inf << out << flush;
887
888 TTree *clone=t.CloneTree();
889 clone->Write();
890 delete clone;
891
892 *fLog << "done." << endl;
893
894 if (fDisplay)
895 {
896 out += " done.";
897 fDisplay->SetStatusLine2(out);
898 }
899}
900
901// --------------------------------------------------------------------------
902//
903// Make all copies requested from the currently open file into the new
904// file.
905//
906Bool_t MWriteRootFile::MakeCopies(const char *fname) const
907{
908 if (fCopies.GetEntries()==0)
909 return kTRUE;
910
911 TFile *file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(fname));
912 if (!file)
913 {
914 *fLog << err << "ERROR - MakeCopies: File " << fname << " not found in gROOT->GetListOfFiles()... abort." << endl;
915 return kFALSE;
916 }
917
918 TIter Next(&fCopies);
919 TObject *o=0;
920 TTree *t=0;
921
922 fOut->cd();
923 while ((o=Next()))
924 {
925 TTree *gettree = dynamic_cast<TTree*>(file->Get(o->GetName()));
926 if (!gettree)
927 {
928 *fLog << err << "ERROR - MakeCopies: Tree " << o->GetName() << " not found in file " << fname << "... abort." << endl;
929 return kFALSE;
930 }
931
932 gettree->SetBranchStatus(o->GetTitle(), 1);
933
934 // First Execution
935 if (t==gettree)
936 continue;
937
938 // Check if its the first call
939 if (t)
940 CopyTree(*t);
941 t = gettree;
942 }
943
944 if (t)
945 CopyTree(*t);
946
947 return kTRUE;
948}
949
950// --------------------------------------------------------------------------
951//
952// ReInit. If file splitting is not allowed call MWriteFile::ReInit.
953//
954// In other cases get MRead from the TaskList (splitting is switched of if
955// this is impossible).
956//
957// Convert the input- into a new output file-name.
958//
959// Open a new file, change all trees to the new file (calling ChangeFile()),
960// and close the old one.
961//
962// Call MWriteFile::ReInit()
963//
964Bool_t MWriteRootFile::ReInit(MParList *pList)
965{
966 MRead *read = (MRead*)pList->FindTask("MRead");
967 if (fSplitRule.IsNull() && fCopies.GetEntries()>0 && fOut)
968 {
969 if (!read)
970 {
971 *fLog << err;
972 *fLog << "ERROR: No Task 'MRead' found in the tasklist. This task is" << endl;
973 *fLog << " necessary to get the filename. Without a filename file" << endl;
974 *fLog << " AddCopySource cannot be used... abort." << endl;
975 *fLog << endl;
976 return kFALSE;
977 }
978 if (!MakeCopies(read->GetFullFileName()))
979 return kFALSE;
980
981 }
982
983 if (fSplitRule.IsNull() || !(fOut || TestBit(kIsNotOwner)))
984 return MWriteFile::ReInit(pList);
985
986 if (!read)
987 {
988 *fLog << warn;
989 *fLog << "WARNING: No Task 'MRead' found in the tasklist. This task is" << endl;
990 *fLog << " necessary to get the filename. Without a filename file" << endl;
991 *fLog << " file splitting is not allowed... disabled!" << endl;
992 *fLog << endl;
993 fSplitRule = "";
994 return kTRUE;
995 }
996
997
998 const TString oldname = read->GetFullFileName();
999 const TString newname = GetNewFileName(oldname);
1000 if (!ChangeFile(newname))
1001 return kFALSE;
1002
1003 if (!MakeCopies(oldname))
1004 return kFALSE;
1005
1006 return MWriteFile::ReInit(pList);
1007}
1008
1009// --------------------------------------------------------------------------
1010//
1011// return open state of the root file. If the file is 'memory' kTRUE is
1012// returned.
1013//
1014Bool_t MWriteRootFile::IsFileOpen() const
1015{
1016 if (!fOut)
1017 return kTRUE;
1018
1019 const char *n = fOut->GetName();
1020 return n==0 || *n==0 ? kTRUE : fOut->IsOpen();
1021}
1022
1023// --------------------------------------------------------------------------
1024//
1025// return name of the root-file. If the file is "memory" "<memory>" is
1026// returned.
1027//
1028const char *MWriteRootFile::GetFileName() const
1029{
1030 if (!fOut)
1031 return "<memory>";
1032
1033 const char *n = fOut->GetName();
1034 return n==0 || *n==0 ? "<dummy>" : n;
1035}
1036
1037// --------------------------------------------------------------------------
1038//
1039// cd into file. See TFile::cd(). If the file is "memory" kTRUE is returned.
1040//
1041Bool_t MWriteRootFile::cd(const char *path)
1042{
1043 return fOut ? fOut->cd(path) : kTRUE;
1044}
1045
1046// --------------------------------------------------------------------------
1047//
1048// If the output file is deleted set fOut to NULL.
1049// Call MTask::RecursiveRemove
1050//
1051void MWriteRootFile::RecursiveRemove(TObject *obj)
1052{
1053 if (obj==fOut)
1054 fOut=NULL;
1055
1056 MWriteFile::RecursiveRemove(obj);
1057}
1058
1059// --------------------------------------------------------------------------
1060//
1061// Implementation of SavePrimitive. Used to write the call to a constructor
1062// to a macro. In the original root implementation it is used to write
1063// gui elements to a macro-file.
1064//
1065void MWriteRootFile::StreamPrimitive(ostream &out) const
1066{
1067 out << " MWriteRootFile " << GetUniqueName();
1068 if (fOut)
1069 {
1070 out << "(\"";
1071 out << fOut->GetName() << "\", \"";
1072 out << fOut->GetOption() << "\", \"";
1073 out << fOut->GetTitle() << "\", ";
1074 out << fOut->GetCompressionLevel();
1075 out << ")";
1076 }
1077 out << ";" << endl;
1078
1079 if (fName!=gsDefName)
1080 out << " " << GetUniqueName() << ".SetName(\"" << fName << "\");" << endl;
1081 if (fTitle!=gsDefTitle)
1082 out << " " << GetUniqueName() << ".SetTitle(\"" << fTitle << "\");" << endl;
1083
1084 MRootFileBranch *entry;
1085 TIter Next(&fBranches);
1086 while ((entry=(MRootFileBranch*)Next()))
1087 {
1088 out << " " << GetUniqueName() << ".AddContainer(";
1089
1090 if (entry->GetContainer())
1091 {
1092 entry->GetContainer()->SavePrimitive(out);
1093 out << "&" << entry->GetContainer()->GetUniqueName();
1094 }
1095 else
1096 out << "\"" << entry->GetContName() << "\"";
1097
1098 out << ", \"" << entry->GetName() << "\"";
1099 if (!entry->MustHave())
1100 out << ", kFALSE";
1101
1102 out <<");" << endl;
1103 }
1104}
1105
Note: See TracBrowser for help on using the repository browser.