/* ======================================================================== *\ ! ! * ! * 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 12/2000 (tbretz@uni-sw.gwdg.de) ! ! Copyright: MAGIC Software Development, 2000-2001 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // // MReadTree // // // // This tasks opens all branches in a specified tree and creates the // // corresponding parameter containers if not already existing in the // // parameter list. // // // // The Process function reads one events from the tree. To go through the // // events of one tree make sure that the event number is increased from // // outside. It makes also possible to go back by decreasing the number. // // // // If you don't want to start reading the first event you have to call // // MReadTree::SetEventNum after instantiating your MReadTree-object. // // // // To make reading much faster (up to a factor of 10 to 20) you can // // ensure that only the data you are really processing is enabled by // // calling MReadTree::UseLeaf. // // // // Later we'll use TChain::SetNotify to notify MReadTree if the TChain // // starts to read a new file. // // // ///////////////////////////////////////////////////////////////////////////// #include "MReadTree.h" #include #include #include #include #include #include #include "MLog.h" #include "MLogManip.h" #include "MTime.h" #include "MParList.h" ClassImp(MReadTree); // -------------------------------------------------------------------------- // // Default constructor. It creates an TChain instance which represents the // the Tree you want to read and adds the given file (if you gave one). // More files can be added using MReadTree::AddFile. // Also an empty veto list is created. This list is used if you want to // veto (disable or "don't enable") a branch in the tree. // MReadTree::MReadTree(const char *tname, const char *fname, const char *name, const char *title) : fNumEntry(0), fLeafEnabled(kFALSE) { *fName = name ? name : "MReadTree"; *fTitle = title ? title : "Task to loop over all events in one single tree"; fVetoList = new TArrayC; // // open the input stream // fChain = new TChain(tname); if (fname) fChain->Add(fname); } // -------------------------------------------------------------------------- // // Destructor. It deletes the TChain and veto list object // MReadTree::~MReadTree() { // // Delete all the pointers to pointers to the objects where the // branche data gets stored. // TIter Next(fChain->GetStatus()); TChainElement *element = NULL; while ((element=(TChainElement*)Next())) delete (MParContainer**)element->GetBaddress(); // // Delete the chain and the veto list // delete fChain; delete fVetoList; } // -------------------------------------------------------------------------- // // If you want to read the given tree over several files you must add // the files here before PreProcess is called. Be careful: If the tree // doesn't have the same contents (branches) it may confuse your // program (trees which are are not existing in later files are not read // anymore, tree wich are not existing in the first file are never read) // // Name may use the wildcarding notation, eg "xxx*.root" means all files // starting with xxx in the current file system directory. // Int_t MReadTree::AddFile(const char *fname) { // // FIXME! A check is missing whether the file already exists or not. // // // returns the number of file which were added // return fChain->Add(fname); } // -------------------------------------------------------------------------- // // The first time this function is called all leafes/branches are disabled // and the given branch/leaf is enabled. By enabling only the branches you // are processing you can speed up your calculation many times (up to // a factor of 10 or 20) // void MReadTree::UseLeaf(const char *name) { if (!fLeafEnabled) { *fLog << "Leaf choosing method enabled (only enabled leaves are read)." << endl; fChain->SetBranchStatus("*", kFALSE); fLeafEnabled = kTRUE; } fChain->SetBranchStatus(name, kTRUE); } // -------------------------------------------------------------------------- // // The PreProcess loops (till now) over the branches in the given tree. // It checks if the corresponding containers (containers with the same // name than the branch name) are existing in the Parameter Container List. // If not, a container of objec type 'branch-name' is created (everything // after the last semicolon in the branch name is stripped). Only // branches which don't have a veto (see VetoBranch) are enabled If the // object isn't found in the root dictionary (a list of classes known by the // root environment) the branch is skipped and an error message is printed // out. // Bool_t MReadTree::PreProcess(MParList *pList) { // // get number of events in this tree // fNumEntries = (UInt_t)fChain->GetEntries(); if (!fNumEntries) { *fLog << dbginf << "No entries found in chain (file/s)." << endl; return kFALSE; } // // output logging information // *fLog << fNumEntries << " entries found in file(s)." << endl; // // Get all branches of this tree and // create the Iterator to loop over all branches // TIter Next(fChain->GetListOfBranches()); TBranch *branch=NULL; Int_t num=0; // // loop over all tasks for processing // while ( (branch=(TBranch*)Next()) ) { // // Get Name of Branch // const char *name = branch->GetName(); // // Check if enabeling the branch is allowed // if (HasVeto(name)) { *fLog << "Branch " << name << " has veto... skipped." << endl; continue; } // // Create a pointer to the pointer to the object in which the // branch data is stored. The pointers are stored in the TChain // object and we get the pointers from there to delete it. // MParContainer **pcont = new MParContainer*; // // check if object is existing in the list // *pcont=pList->FindCreateObj(name); if (!*pcont) { // // if class is not existing in the (root) environment // we cannot proceed reading this branch // *fLog << dbginf << "Warning: Class '" << name << "' not existing in dictionary. Branch skipped." << endl; continue; } // // here pcont is a pointer the to container in which the data from // the actual branch should be stored - enable branch. // fChain->SetBranchAddress(name, pcont); *fLog << "Branch " << name << " enabled for reading." << endl; num++; } *fLog << "MReadTree will read " << num << " branches." << endl; return kTRUE; } // -------------------------------------------------------------------------- // // The Process-function reads one event from the tree (this contains all // enabled branches) and increases the position in the file by one event. // (Remark: The position can also be set by some member functions // If the end of the file is reached the Eventloop is stopped. // Bool_t MReadTree::Process() { return fChain->GetEntry(fNumEntry++, 0) == 0 ? kFALSE : kTRUE; } // -------------------------------------------------------------------------- // // Get the Event with the current EventNumber fNumEntry // Bool_t MReadTree::GetEvent() { return fChain->GetEntry(fNumEntry) == 0 ? kFALSE : kTRUE; } // -------------------------------------------------------------------------- // // Decrease the number of the event which is read by Process() next // by one or more // Bool_t MReadTree::DecEventNum(UInt_t dec) { //! //! this function makes Process() read the event one (or more) before //! the actual position (event) in the tree //! if (fNumEntry < dec/*+1*/) { *fLog << "MReadTree::SetPrevEvent: WARNING: " << fNumEntry/*-1*/ << "-" << dec << " out of Range." << endl; return kFALSE; } fNumEntry -= dec/*+1*/; return kTRUE; } // -------------------------------------------------------------------------- // // Increase the number of the event which is read by Process() next // by one or more // Bool_t MReadTree::IncEventNum(UInt_t inc) { //! //! this function makes Process() read the next (or more) after //! the actual position (event) in the tree //! (Be careful: IncEventNum() or IncEventNum(1) does not chenge anything //! in the standard behaviour of the task) //! if (fNumEntry+inc/*-1*/ >= fNumEntries) { *fLog << "MReadTree::SkipEvents: WARNING: " << fNumEntry/*-1*/ << "+" << inc << " out of Range." << endl; return kFALSE; } fNumEntry += inc/*-1*/; return kTRUE; } // -------------------------------------------------------------------------- // // this function makes Process() read event number nr next // // Remark: You can use this function after instatiating you MReadTree-object // to set the event number from which you want to start reading. // Bool_t MReadTree::SetEventNum(UInt_t nr) { if (nr>=fNumEntries) { *fLog << "MReadTree::SetEventNum: WARNING: " << nr << " out of Range." << endl; return kFALSE; } fNumEntry = nr; return kTRUE; } // -------------------------------------------------------------------------- // // This function checks if the Branch Name is part of the Veto List. // This means, that the preprocess doesn't enable the branch. // Bool_t MReadTree::HasVeto(const char *name) const { const size_t nlen = strlen(name)+1; char *pos = fVetoList->GetArray(); size_t len = fVetoList->GetSize(); // // now we compare the 'strings' in the list word by word // (string or word in this context means a zero terminated // array of chars // for (;;) { // // Search for the first byte of the name // char *c = (char*)memchr(pos, name[0], len); // // if we don't find the first byte, the list cannot contain 'name' // if (!c) return kFALSE; // // calculate and check how many bytes remains in the list // len -= c-pos; // // if there are not enough bytes to match the query we are done // if (lenGetSize(); const int tsz = strlen(name)+1; fVetoList->Set(sz+tsz); memcpy(fVetoList->GetArray()+sz, name, tsz); }