source: tags/Mars-V0.9.4/mfileio/MWriteRootFile.cc

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