/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 06/2001 (tbretz@uni-sw.gwdg.de) ! ! Copyright: MAGIC Software Development, 2000-2001 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // // MWriteRootFile // // // // This is a writer to store several containers to a root file. // // The containers are added with AddContainer. // // To understand how it works, see base class MWriteFile // // // ///////////////////////////////////////////////////////////////////////////// #include "MWriteRootFile.h" #include #include #include "MLog.h" #include "MLogManip.h" #include "MParList.h" ClassImp(MWriteRootFile); // -------------------------------------------------------------------------- // // Specify the name of the root file. You can also give an option ("UPDATE" // and "RECREATE" would make sense only) as well as the file title and // compression factor. To a more detaild description of the options see // TFile. // MWriteRootFile::MWriteRootFile(const char *fname, const Option_t *opt, const char *ftitle, const Int_t comp, const char *name, const char *title) { *fName = name ? name : "MWriteRootFile"; *fTitle = title ? title : "Task which writes a root-output file"; // // Set the Arrays the owner of its entries. This means, that the // destructor of the arrays will delete all its entries. // fBranches.SetOwner(); fTrees.SetOwner(); // // Open the rootfile // fOut = new TFile(fname, opt, ftitle, comp); } // -------------------------------------------------------------------------- // // Prints some statistics about the file to the screen. And closes the file // properly. // MWriteRootFile::~MWriteRootFile() { // // Print some statistics to the looging out. // Print(); // // If the file is still open (no error) write the keys. This is necessary // for appearance of the all trees and branches. // if (IsFileOpen()) fOut->Write(); // // Delete the file. This'll also close the file (if open) // delete fOut; } // -------------------------------------------------------------------------- // // Prints all trees with the actually number of written entries to log-out. // void MWriteRootFile::Print(Option_t *) { *fLog << "File: " << GetFileName() << endl; *fLog << "--------------------------------------------------" << endl; MRootFileTree *entry; // // Loop over all tree entries // TObjArrayIter Next(&fTrees); while ((entry=(MRootFileTree*)Next())) { // // Print out the name and the number of actually written entries. // *fLog << entry->GetTree()->GetName() << ": \t"; *fLog << entry->GetNumEntries() << " entries." << endl; } } // -------------------------------------------------------------------------- // // Add a new Container to list of containers which should be written to the // file. Give the name of the container which will identify the container // in the parameterlist. tname is the name of the tree to which the // container should be written (Remark: one tree can hold more than one // container). The default is the same name as the container name. // You can slso specify a title for the tree. This is only // used the first time this tree in 'mentioned'. As default the title // is the name of the tree. // void MWriteRootFile::AddContainer(const char *cname, const char *tname, const char *ttitle) { // // create a new entry in the list of branches to write and // add the entry to the list. // MRootFileBranch *entry = new MRootFileBranch(cname, tname, ttitle); fBranches.AddLast(entry); } // -------------------------------------------------------------------------- // // Add a new Container to list of containers which should be written to the // file. Give the pointer to the container. tname is the name of the tree to // which the container should be written (Remark: one tree can hold more than // one container). The default is the same name as the container name. // You can slso specify a title for the tree. This is only // used the first time this tree in 'mentioned'. As default the title // is the name of the tree. // void MWriteRootFile::AddContainer(MParContainer *cont, const char *tname, const char *ttitle) { // // create a new entry in the list of branches to write and // add the entry to the list. // MRootFileBranch *entry = new MRootFileBranch(cont, tname, ttitle); fBranches.AddLast(entry); } // -------------------------------------------------------------------------- // // Add a new Container to list of containers which should be written to the // file. Give the pointer to the container. tname is the name of the tree to // which the container should be written (Remark: one tree can hold more than // one container). The default is the same name as the container name. // You can slso specify a title for the tree. This is only // used the first time this tree in 'mentioned'. As default the title // is the name of the tree. // Bool_t MWriteRootFile::GetContainer(MParList *pList) { MRootFileBranch *entry; // // // loop over all branches which are 'marked' as branches to get written. TObjArrayIter Next(&fBranches); while ((entry=(MRootFileBranch*)Next())) { // // Get the pointer to the container. If the pointer is NULL it seems, // that the user identified the container by name. // MParContainer *cont = entry->GetContainer(); if (!cont) { // // Get the name and try to find a container with this name // in the parameter list. // const char *cname = entry->GetContName(); cont = (MParContainer*)pList->FindObject(cname); if (!cont) { // // No corresponding container is found // *fLog << dbginf << "Cannot find parameter container '" << cname << "'." << endl; return kFALSE; } // // The container is found. Put the pointer into the entry. // entry->SetContainer(cont); } // // Get container name, tree name and tree title of this entry. // const char *cname = cont->GetName(); const char *tname = entry->GetTreeName(); const char *ttitle = entry->GetTreeTitle(); // // if the tree name is NULL this idetifies it to use the default: // the container name. // if (!tname) tname = cname; // // Check if the tree is already existing (part of the file) // TTree *tree = (TTree*)fOut->Get(tname); if (!tree) { // // if the tree doesn't exist create a new tree. Use the tree // name as title if title is NULL // tree = new TTree(tname, ttitle ? ttitle : tname); // // Create a new entry in the list of trees, which are stored to // the file. Add it to the list. // MRootFileTree *entry = new MRootFileTree(tree); fTrees.AddLast(entry); *fLog << "Created Tree " << tname << "." << endl; } // // Now we have a valid tree. Search the list of trees for this tree // (either it is already there, or we created and add it previously) // Add a pointer to the entry in the tree list to this branch-entry // MRootFileTree *loop; TObjArrayIter NextTree(&fTrees); while ((loop=(MRootFileTree*)NextTree())) { if (loop->GetTree() == tree) entry->SetTree(loop); } // // Try to get the branch from the file. // If the branch already exists the user specified one branch twice. // TBranch *branch = tree->GetBranch(cname); if (branch) { *fLog << dbginf << "Branch '" << cname << "' is already existing." << endl; return kFALSE; } // // Create a new branch in the actual tree. The branch has the name // container name. The type of the container is given by the // ClassName entry in the container. The Address is the address of a // pointer to the container (gotten from the branch entry). As // Basket size we specify a (more or less) common default value. // The containers should be written in Splitlevel=1 // branch = tree->Branch(cname, cont->ClassName(), entry->GetAddress(), 32000, 1); *fLog << "Created Branch " << cname << " of " << cont->ClassName() << "." << endl; // // If the branch couldn't be created we have a problem. // if (!branch) { *fLog << dbginf << "Unable to create branch '" << cname << "'." << endl; return kFALSE; } } return kTRUE; } // -------------------------------------------------------------------------- // // Checks all given containers (branch entries) for the write flag. // If the write flag is set the corresponding Tree is marked to get filled. // All Trees which are marked to be filled are filled with the corresponding // branches. // Be carefull: If only one container (corresponding to a branch) of a tree // has the write flag, all containers in this tree are filled! // void MWriteRootFile::CheckAndWrite() const { TObject *obj; // // Loop over all branch entries // TObjArrayIter NextBranch(&fBranches); while ((obj=NextBranch())) { MRootFileBranch *entry = (MRootFileBranch*)obj; // // Check for the Write flag // if (!entry->GetContainer()->IsReadyToSave()) continue; // // If the write flag of the branch entry is set, set the write flag of // the corresponding tree entry. // entry->GetTree()->SetWriteFlag(); } // // Loop over all tree entries // TObjArrayIter NextTree(&fTrees); while ((obj=NextTree())) { MRootFileTree *entry = (MRootFileTree*)obj; // // Check the write flag of the tree // if (!entry->HasWriteFlag()) continue; // // If the write flag is set, fill the tree (with the corrasponding // branches/containers), delete the write flag and increase the number // of written/filled entries. // entry->GetTree()->Fill(); entry->DelWriteFlag(); (*entry)++; } } // -------------------------------------------------------------------------- // // return open state of the root file. // Bool_t MWriteRootFile::IsFileOpen() const { return fOut->IsOpen(); } // -------------------------------------------------------------------------- // // return name of the root-file // const char *MWriteRootFile::GetFileName() const { return fOut->GetName(); }