/* ======================================================================== *\ ! ! * ! * 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, 11/2003 ! ! Copyright: MAGIC Software Development, 2000-2003 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // MReadReports // // Read from a file events from different trees ordered in time, eg: // // Having a file with: // // Tree1 Tree2 Tree3 // ------------ ------------ ----------- // (0) MTime[0] // (0) MTime[1] // (1) MTime[2] // (2) MTime[3] // (0) MTime[1] // (3) MTime[4] // // MReadReports will read the events in the tree in the following order: // <0> (0) from Tree1 // <1> (0) from Tree2 // <2> (1) from Tree1 // <3> (2) from Tree1 // <4> (0) from Tree3 // <5> (3) from Tree1 // ... // // To tell MReadReports which Trees to read use: MReadReports::AddTree() // To schedule a file for reading use MReadReports::AddFile() // // All calls to AddTree _must_ be before the calls to AddFile! // // After reading from a tree with the name 'TreeName' the stream id of // the main tasklist ('MTaskList' found in MParList in PreProcess) is // set to this name. This means that only tasks having this stream id // are executed. // ///////////////////////////////////////////////////////////////////////////// #include "MReadReports.h" #include #include #include "MLog.h" #include "MLogManip.h" #include "MTime.h" #include "MParList.h" #include "MTaskList.h" #include "MReadMarsFile.h" ClassImp(MReadReports); using namespace std; // -------------------------------------------------------------------------- // // Default constructor. Set fName and fTitle. Instatiate fTrees and fChains. // Call SetOwner for fTrees and fChains // MReadReports::MReadReports() : fEnableAutoScheme(kFALSE) { fName = "MRead"; fTitle = "Reads events and reports from a root file ordered in time"; fTrees = new MTaskList("MReadReports"); fChains = new TList; fTrees->SetOwner(); fChains->SetOwner(); } // -------------------------------------------------------------------------- // // Destructor, delete everything which was allocated by this task... // MReadReports::~MReadReports() { TObject *o=0; TIter NextC(fChains); while ((o=NextC())) { delete *GetTime((TChain*)o); delete GetTime((TChain*)o); } delete fTrees; delete fChains; } // -------------------------------------------------------------------------- // // Return the number of entries in all trees. // UInt_t MReadReports::GetEntries() { UInt_t n=0; TIter NextT(fTrees->GetList()); MReadTree *tree=0; while ((tree=(MReadTree*)NextT())) n += tree->GetEntries(); return n; } // -------------------------------------------------------------------------- // // In case of a Master Tree GetFileName() of the MReadMarsFile is returned. // If no master is available "" is returned. // TString MReadReports::GetFileName() const { if (!TestBit(kHasMaster)) return ""; TIter NextT(fTrees->GetList()); MReadTree *tree=0; while ((tree=(MReadTree*)NextT())) if (tree->InheritsFrom("MReadMarsFile")) return tree->GetFileName(); return ""; } void MReadReports::AddToBranchList(const char *name) { MTask::AddToBranchList(name); } // -------------------------------------------------------------------------- // // Schedule the contents of this tree for reading. As a default the time // branch which is used for the ordering is assumed to by "MTime"+tree. // If this is not the case you can overwrite the default specifying the // name in time. // // All calls to AddTree _must_ be BEFORE the calls to AddFile! // // To be done: A flag(?) telling whether the headers can be skipped. // void MReadReports::AddTree(const char *tree, const char *time, Bool_t master) { /* if (fTrees->GetNumTasks()>0) { *fLog << warn << "WARNING - AddTree must be called before AddFile... ignored." << endl; *fLog << dbg << fTrees->GetNumTasks() << endl; return kFALSE; } */ if (master && TestBit(kHasMaster)) { *fLog << warn << GetDescriptor() << " already has a master tree... ignored." << endl; master = kFALSE; } MReadTree *t = master ? new MReadMarsFile(tree) : new MReadTree(tree); t->SetName(tree); t->SetTitle(time?time:""); if (master) SetBit(kHasMaster); if (!fEnableAutoScheme) t->DisableAutoScheme(); //FIXME! //t->DisableAutoScheme(); fTrees->AddToList(t); // return kTRUE; } // -------------------------------------------------------------------------- // // Schedule a file or several files (using widcards) for reading. // // All calls to AddTree _must_ be BEFORE the calls to AddFile! // Int_t MReadReports::AddFile(const char *fname, Int_t entries) { Int_t n=0; TIter NextT(fTrees->GetList()); MReadTree *tree=0; while ((tree=(MReadTree*)NextT())) n += tree->AddFile(fname, entries); return n; } // -------------------------------------------------------------------------- // // Find MTaskList and store a pointer to it in fList. // Delete all entries in fChains. // Create all chains to read the time in the trees in advance. // Enable only the time-branch in this chains. // PreProcess fTrees (a MTaskList storing MReadTree tasks for reading) // Int_t MReadReports::PreProcess(MParList *plist) { fList = (MTask*)plist->FindObject("MTaskList"); fChains->Delete(); Int_t i=0; TIter NextT(fTrees->GetList()); MReadTree *tree=0; while ((tree=(MReadTree*)NextT())) { if (!((TChain*)tree->fChain)->GetFile()) { *fLog << warn << "No files or no tree '" << tree->GetName() << "'... skipped." << endl; fTrees->RemoveFromList(tree); continue; } if (tree->GetEntries()==0) { *fLog << warn << "No events in tree '" << tree->GetName() << "'... skipped." << endl; fTrees->RemoveFromList(tree); continue; } TString tn(tree->GetTitle()); if (tn.IsNull()) { tn += "MTime"; tn += tree->GetName(); tn += "."; } TString tn2(tn); tn2 += "*"; // FIXME: Should be tree->AddToBranchList such that // each run a new 'table' is created, but // MRead is searching for MTaskList in the // parameter list. //AddToBranchList((const char*)tn2); // // SetBranchStatus wants to have a pointer to a pointer // MTime **tx = new MTime*; *tx = new MTime; TChain *c=new TChain(tree->GetName()); c->SetBranchStatus("*", 0); c->SetBranchAddress(tn, tx); tn+="*"; c->SetBranchStatus(tn, 1); c->Add((TChain*)tree->fChain); c->GetEntry(0); fChains->Add(c); i++; } if (i==0) { *fLog << err << "Files do not contain any valid tree... abort." << endl; return kFALSE; } fPosEntry.Set(i); return fTrees->CallPreProcess(plist); } // -------------------------------------------------------------------------- // // Return the MTime corresponding to this TChain... // MTime** MReadReports::GetTime(TChain *c) const { TChainElement *e=(TChainElement*)c->GetStatus()->At(1); return (MTime**)e->GetBaddress(); } // -------------------------------------------------------------------------- // // Do not use if fChains->GetSize()==0 !!! // Int_t MReadReports::FindNextTime() { Int_t i=0; TIter NextC(fChains); TChain *c=0; Int_t nmin=0; MTime tmin(**GetTime((TChain*)NextC())); while ((c=(TChain*)NextC())) { MTime &t = **GetTime(c); i++; if (t >= tmin) continue; tmin = t; nmin = i; } return nmin; } /* Bool_t MReadReports::Notify() { Bool_t same = kTRUE; for (int i=1; iGetTreeNumber(); Bool_t read=kFALSE; if (fPosTree[nmin] != tn) { fPosTree[nmin] = tn; read = kTRUE; } if (!same || !read) return kTRUE; *fLog << dbg << "Read Run Headers!" << endl; return kTRUE; } */ // -------------------------------------------------------------------------- // // Check which is the next tree to read from. Read an event from this tree. // Sets the StreamId accordingly. // Int_t MReadReports::Process() { while (fChains->GetSize()) { const Int_t nmin=FindNextTime(); TChain *chain = (TChain*)fChains->At(nmin); MTask *task = (MTask*)fTrees->GetList()->At(nmin); //Int_t before = chain->GetTreeNumber(); if (chain->GetEntry(++fPosEntry[nmin])>0) { const Int_t rc = task->CallProcess(); if (rc) { fList->SetStreamId(task->GetName()); return rc; } } *fLog << dbg << "Removing chain " << chain->GetName() << " from list." << endl; delete *GetTime(chain); // Delete MTime* delete GetTime(chain); // Delete MTime-instance delete fChains->Remove(chain); // Remove chain from TList // FIXME: Maybe MTaskList should have a member function to // reorder the tasks? // Move this task to the end of the list so that nmin still // corresponds to the correct task in the list. const_cast(fTrees->GetList())->Remove(task); const_cast(fTrees->GetList())->AddLast(task); } return kFALSE; } // -------------------------------------------------------------------------- // // PostProcess all MReadTree tasks in fTrees. // Int_t MReadReports::PostProcess() { return fTrees->CallPostProcess(); } // -------------------------------------------------------------------------- // // PrintStatistics of this task and of the MReadTree tasks in fTress // void MReadReports::PrintStatistics(const Int_t lvl, Bool_t title, Double_t time) const { MRead::PrintStatistics(lvl, title, time); fTrees->PrintStatistics(lvl, title, GetCpuTime()); }