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

Last change on this file since 9195 was 9186, checked in by tbretz, 16 years ago
*** empty log message ***
File size: 35.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, 6/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
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 <TRegexp.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)
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 << " Please start debugging!" << endl;
763 return kFALSE;
764 }
765
766 *fLog << inf << "Open new file " << fname << " (Title=" << title << ", Option=" << opt << ", Compression=" << compr << ")" << endl;
767
768 // Print statistics of old file
769 const TString n = GetFileName();
770 if (!n.IsNull() && n!=TString("/dev/null"))
771 Print();
772
773 if (fOut->IsOpen())
774 fOut->Write();
775
776 // Move all trees from the old file to the new file
777 TObject *obj=0;
778 while ((obj = fOut->GetList()->First()))
779 {
780 // Remove obj from old file (otherwise deleting
781 // the old file will delete the objs)
782 fOut->GetList()->Remove(obj);
783
784 // If this is not a tree do nothing.
785 if (!obj->InheritsFrom(TTree::Class()))
786 continue;
787
788 // process all trees in the old file
789 TTree *t = (TTree*)obj;
790
791 // reset and move to new file (this is done implicitly for all branches)
792 t->Reset();
793 t->SetDirectory(newfile);
794 }
795
796 // Close/delete the old file (keys already written above)
797 delete fOut;
798
799 // Replace current with new file
800 fOut = newfile;
801
802 // Change current directory to new file
803 gFile = fOut;
804
805 return kTRUE;
806}
807
808// --------------------------------------------------------------------------
809//
810// A rule looks like:
811// "outputpath{s/source/destination}"
812//
813// outpath: the output path into which the files are written
814// {s/source/destination} a substitution rule for the filename
815// while source can be a regular expression everything which matches this
816// regular expression (see TRegexp) will be replaced by destination.
817// Warning: The algorithm is recursive you may create endless loops!
818//
819// Example:
820// inputfile: /data/MAGIC/Period016/rootdata/20040621_23210_D_Mkn421_E.root
821// rule: /outpath/{s/_D_/_Y_}
822// outfile: /outpath/20040621_23210_Y_Mkn421_E.root
823//
824// If you need more difficult rules please send me an eMail...
825//
826TString MWriteRootFile::GetNewFileName(const char *inname) const
827{
828 // Remove the path from the filename
829 TString fname(inname);
830 if (fname.Last('/')>=0)
831 fname.Remove(0, fname.Last('/')+1);
832
833 // Make a copy of the rule
834 TString rule(fSplitRule);
835
836 // [characte class], ^ do not, [^{}] do not match { and }, [^{}]+ match at least not one { or }
837 const TRegexp subst0("{s/[^{}/]+/[^{}/]+}");
838
839 TString path;
840 Bool_t first = kTRUE;
841
842 Ssiz_t idx=0;
843 while (1)
844 {
845 // Find a substitution exprsssion
846 Ssiz_t len = 0;
847 idx = subst0.Index(rule, &len);
848 if (idx<0)
849 break;
850
851 // If the first substitution expression is found in the rule
852 // determin the path from everything before
853 if (first)
854 {
855 path=rule(0, idx);
856 first = kFALSE;
857 }
858
859 // Extract a substitution expression
860 TString expr = rule(idx, len);
861 rule.Remove(idx, len);
862
863 expr.Remove(0,3);
864 expr.Remove(expr.Length()-1);
865
866 // In all cases this is well defined (see Regexp)
867 const Ssiz_t pos = expr.First('/');
868
869 // Split substitution rule into source and destination
870 const TString src = expr(0, pos);
871 const TString dest = expr(pos+1, expr.Length());
872
873 // Replace source by destination
874 const TRegexp regexp(src);
875
876 Ssiz_t ichar = 0;
877 while (1) // Replace all occurrences of src by dest
878 {
879 idx = regexp.Index(fname, &len, ichar);
880 if (idx<0)
881 break;
882
883 fname.Replace(idx, len, dest);
884 ichar = idx + dest.Length();
885
886 // In next iteration, we start searching the string fname
887 // right after the last character of the previous substitution
888 // (indicated by ichar). This avoids infinite loops in the case
889 // we want to replace, for instance, "_w" by "_Y_w". Without
890 // the use of ichar, the second string would be replaced by
891 // "_Y_Y_w", and this would never end...
892 }
893 }
894
895 // Check if we have a trailing '/'
896 if (!path.IsNull() && path[path.Length()-1]!='/')
897 path.Append("/");
898
899 //inname.Prepend(path);
900
901 // Create full qualified pathname
902 path += fname;
903 return path;
904}
905
906// --------------------------------------------------------------------------
907//
908// Writes a copy of the TTree t to the currently open file using
909// TTree::CloneTree()
910//
911void MWriteRootFile::CopyTree(TTree &t) const
912{
913 TString out = "Copy of tree ";
914 out += t.GetName();
915 out += " in progress...";
916
917 if (fDisplay)
918 fDisplay->SetStatusLine2(out);
919
920 *fLog << inf << out << flush;
921
922 TTree *clone=t.CloneTree();
923 clone->Write();
924 delete clone;
925
926 *fLog << "done." << endl;
927
928 if (fDisplay)
929 {
930 out += " done.";
931 fDisplay->SetStatusLine2(out);
932 }
933}
934
935// --------------------------------------------------------------------------
936//
937// Make all copies requested from the currently open file into the new
938// file.
939//
940Bool_t MWriteRootFile::MakeCopies(const char *fname) const
941{
942 if (fCopies.GetEntries()==0)
943 return kTRUE;
944
945 TFile *file = dynamic_cast<TFile*>(gROOT->GetListOfFiles()->FindObject(fname));
946 if (!file)
947 {
948 *fLog << err << "ERROR - MakeCopies: File " << fname << " not found in gROOT->GetListOfFiles()... abort." << endl;
949 return kFALSE;
950 }
951
952 TIter Next(&fCopies);
953 TObject *o=0;
954 TTree *t=0;
955
956 fOut->cd();
957 while ((o=Next()))
958 {
959 TTree *gettree = dynamic_cast<TTree*>(file->Get(o->GetName()));
960 if (!gettree)
961 {
962 *fLog << err << "ERROR - MakeCopies: Tree " << o->GetName() << " not found in file " << fname << "... abort." << endl;
963 return kFALSE;
964 }
965
966 gettree->SetBranchStatus(o->GetTitle(), 1);
967
968 // First Execution
969 if (t==gettree)
970 continue;
971
972 // Check if its the first call
973 if (t)
974 CopyTree(*t);
975 t = gettree;
976 }
977
978 if (t)
979 CopyTree(*t);
980
981 return kTRUE;
982}
983
984// --------------------------------------------------------------------------
985//
986// ReInit. If file splitting is not allowed call MWriteFile::ReInit.
987//
988// In other cases get MRead from the TaskList (splitting is switched of if
989// this is impossible).
990//
991// Convert the input- into a new output file-name.
992//
993// Open a new file, change all trees to the new file (calling ChangeFile()),
994// and close the old one.
995//
996// Call MWriteFile::ReInit()
997//
998Bool_t MWriteRootFile::ReInit(MParList *pList)
999{
1000 MRead *read = (MRead*)pList->FindTask("MRead");
1001 if (fSplitRule.IsNull() && fCopies.GetEntries()>0 && fOut)
1002 {
1003 if (!read)
1004 {
1005 *fLog << err;
1006 *fLog << "ERROR: No Task 'MRead' found in the tasklist. This task is" << endl;
1007 *fLog << " necessary to get the filename. Without a filename file" << endl;
1008 *fLog << " AddCopySource cannot be used... abort." << endl;
1009 *fLog << endl;
1010 return kFALSE;
1011 }
1012 if (!MakeCopies(read->GetFullFileName()))
1013 return kFALSE;
1014
1015 }
1016
1017 if (fSplitRule.IsNull() || !(fOut || TestBit(kIsNotOwner)))
1018 return MWriteFile::ReInit(pList);
1019
1020 if (!read)
1021 {
1022 *fLog << warn;
1023 *fLog << "WARNING: No Task 'MRead' found in the tasklist. This task is" << endl;
1024 *fLog << " necessary to get the filename. Without a filename file" << endl;
1025 *fLog << " file splitting is not allowed... disabled!" << endl;
1026 *fLog << endl;
1027 fSplitRule = "";
1028 return kTRUE;
1029 }
1030
1031
1032 const TString oldname = read->GetFullFileName();
1033 const TString newname = GetNewFileName(oldname);
1034 if (!ChangeFile(newname))
1035 return kFALSE;
1036
1037 if (!MakeCopies(oldname))
1038 return kFALSE;
1039
1040 return MWriteFile::ReInit(pList);
1041}
1042
1043// --------------------------------------------------------------------------
1044//
1045// return open state of the root file. If the file is 'memory' kTRUE is
1046// returned.
1047//
1048Bool_t MWriteRootFile::IsFileOpen() const
1049{
1050 if (!fOut)
1051 return kTRUE;
1052
1053 const char *n = fOut->GetName();
1054 return n==0 || *n==0 ? kTRUE : fOut->IsOpen();
1055}
1056
1057// --------------------------------------------------------------------------
1058//
1059// return name of the root-file. If the file is "memory" "<memory>" is
1060// returned.
1061//
1062const char *MWriteRootFile::GetFileName() const
1063{
1064 if (!fOut)
1065 return "<memory>";
1066
1067 const char *n = fOut->GetName();
1068 return n==0 || *n==0 ? "<dummy>" : n;
1069}
1070
1071// --------------------------------------------------------------------------
1072//
1073// cd into file. See TFile::cd(). If the file is "memory" kTRUE is returned.
1074//
1075Bool_t MWriteRootFile::cd(const char *path)
1076{
1077 return fOut ? fOut->cd(path) : kTRUE;
1078}
1079
1080// --------------------------------------------------------------------------
1081//
1082// If the output file is deleted set fOut to NULL.
1083// Call MTask::RecursiveRemove
1084//
1085void MWriteRootFile::RecursiveRemove(TObject *obj)
1086{
1087 if (obj==fOut)
1088 fOut=NULL;
1089
1090 MWriteFile::RecursiveRemove(obj);
1091}
1092
1093// --------------------------------------------------------------------------
1094//
1095// Implementation of SavePrimitive. Used to write the call to a constructor
1096// to a macro. In the original root implementation it is used to write
1097// gui elements to a macro-file.
1098//
1099void MWriteRootFile::StreamPrimitive(ostream &out) const
1100{
1101 out << " MWriteRootFile " << GetUniqueName();
1102 if (fOut)
1103 {
1104 out << "(\"";
1105 out << fOut->GetName() << "\", \"";
1106 out << fOut->GetOption() << "\", \"";
1107 out << fOut->GetTitle() << "\", ";
1108 out << fOut->GetCompressionLevel();
1109 out << ")";
1110 }
1111 out << ";" << endl;
1112
1113 if (fName!=gsDefName)
1114 out << " " << GetUniqueName() << ".SetName(\"" << fName << "\");" << endl;
1115 if (fTitle!=gsDefTitle)
1116 out << " " << GetUniqueName() << ".SetTitle(\"" << fTitle << "\");" << endl;
1117
1118 MRootFileBranch *entry;
1119 TIter Next(&fBranches);
1120 while ((entry=(MRootFileBranch*)Next()))
1121 {
1122 out << " " << GetUniqueName() << ".AddContainer(";
1123
1124 if (entry->GetContainer())
1125 {
1126 entry->GetContainer()->SavePrimitive(out);
1127 out << "&" << entry->GetContainer()->GetUniqueName();
1128 }
1129 else
1130 out << "\"" << entry->GetContName() << "\"";
1131
1132 out << ", \"" << entry->GetName() << "\"";
1133 if (!entry->MustHave())
1134 out << ", kFALSE";
1135
1136 out <<");" << endl;
1137 }
1138}
1139
Note: See TracBrowser for help on using the repository browser.