/* ======================================================================== *\ ! ! * ! * 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 ! ! Copyright: MAGIC Software Development, 2000-2003 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // // MTask // // // // Base class for all tasks which can perfomed in a tasklist // // For each event processed in the eventloop all the different // // tasks in the tasklist will be processed. // // // // So all tasks must inherit from this baseclass. // // // // The inheritance from MInputStreamID is used to indicate the // // type of event that this task is for. If it is "All" it is executed // // independantly of the actual ID of the task list. // // // // Inside this abstract class, there are three fundamental function: // // // // - PreProcess(): executed before the eventloop starts. Here you // // can initiate different things, open files, etc. // // As an argument this function gets a pointer to the // // parameter list. You can stop the execution by // // returning kFALSE instead of kTRUE. If an error // // occured and you return kFALSE make sure, that // // any action is closed correctly and all newly // // created object are deleted. The PostProcess in // // such a case won't be executed by the Tasklist or // // Eventloop. // // // // - Process(): executed for each event in the eventloop. Do it // // one task after the other (as they occur in the // // tasklist). Only the tasks with a Stream ID // // which matches the actual ID of the tasklist // // are executed. A task can return kFALSE to // // stop the execuition of the tasklist or // // kCONTINUE to skip the pending tasks. If you want // // to stop the eventloop and wants the eventloop to // // return the status 'failed' return kERROR. // // // // - PostProcess(): executed after the eventloop. Here you can close // // output files, start display of the run parameter, // // etc. PostProcess is only executed in case of // // PreProcess was successfull (returned kTRUE) // // // ///////////////////////////////////////////////////////////////////////////// #include "MTask.h" #include #include #include "MLog.h" #include "MLogManip.h" #include "MFilter.h" #include "MGGroupFrame.h" #include "MStatusDisplay.h" ClassImp(MTask); MTask::MTask(const char *name, const char *title) : fFilter(NULL), fIsPreprocessed(kFALSE), fNumExecutions(0) { fName = name ? name : "MTask"; fTitle = title ? title : "Base class for all tasks (dummy task)."; fListOfBranches = new TList; fListOfBranches->SetOwner(); } MTask::~MTask() { delete fListOfBranches; } // -------------------------------------------------------------------------- // // This adds a branch to the list for the auto enabeling schmeme. // This makes it possible for MReadTree to decide which branches // are really needed for the eventloop. Only the necessary branches // are read from disk which speeds up the calculation enormously. // // You can use TRegExp expressions like "*.fEnergy", but the // recommended method is to call this function for exactly all // branches you want to have, eg: // AddToBranchList("MMcTrig.fNumFirstLevel"); // AddToBranchList("MMcTrig;1.fNumFirstLevel"); // AddToBranchList("MMcTrig;2.fNumFirstLevel"); // // We agreed on the convetion, that all branches are stored with // a trailing dot '.' so that always the Master Branch name // (eg. MMcTrig) is part of the branch name. // // Remark: The common place to call AddToBranchList is the // constructor of the derived classes (tasks) // void MTask::AddToBranchList(const char *b) { if (fListOfBranches->FindObject(b)) return; fListOfBranches->Add(new TNamed(b, "")); } // -------------------------------------------------------------------------- // // Using this overloaded member function you may cascade several branches // in acomma seperated list, eg: "MMcEvt.fTheta,MMcEvt.fEnergy" // // For moredetailed information see AddToBranchList(const char *b); // void MTask::AddToBranchList(const TString &str) { TString s = str; while (1) { Int_t fst = s.First(','); if (fst<0) return; AddToBranchList(TString(s(0, fst))); s.Remove(0, fst+1); } } // -------------------------------------------------------------------------- // // Copy constructor. // MTask::MTask(MTask &t) { fFilter = t.fFilter; fListOfBranches->AddAll(t.fListOfBranches); } // -------------------------------------------------------------------------- // // Mapper function for PreProcess. // Sets the preprocessed flag dependend on the return value of PreProcess. // Bool_t MTask::CallPreProcess(MParList *plist) { fNumExecutions = 0; *fLog << all << fName << "... " << flush; if (fDisplay) fDisplay->SetStatusLine2(*this); switch (PreProcess(plist)) { case kFALSE: return kFALSE; case kTRUE: fIsPreprocessed = kTRUE; return kTRUE; case kSKIP: return kSKIP; } *fLog << err << dbginf << "PreProcess of " << GetDescriptor(); *fLog << " returned an unknown value... aborting." << endl; return kFALSE; } // -------------------------------------------------------------------------- // // Mapper function for Process. // Executes Process dependent on the existance of a filter and its possible // return value. // If Process is executed, the execution counter is increased. // Bool_t MTask::CallProcess() { // // Check for the existance of a filter. If a filter is existing // check for its value. If the value is kFALSE don't execute // this task. // const Bool_t exec = fFilter ? fFilter->IsConditionTrue() : kTRUE; if (!exec) return kTRUE; fNumExecutions++; return Process(); } // -------------------------------------------------------------------------- // // Mapper function for PreProcess. // Calls Postprocess dependent on the state of the preprocessed flag, // resets this flag. // Bool_t MTask::CallPostProcess() { if (!fIsPreprocessed) return kTRUE; fIsPreprocessed = kFALSE; *fLog << all << fName << "... " << flush; if (fDisplay) fDisplay->SetStatusLine2(*this); return PostProcess(); } // -------------------------------------------------------------------------- // // This is reinit function // // This function is called asynchronously if the tasks in the tasklist need // reinitialization. This for example happens when the eventloop switches // from one group of events to another one (eg. switching between events // of different runs means reading a new run header and a new run header // may mean that some value must be reinitialized) // // the virtual implementation returns kTRUE // Bool_t MTask::ReInit(MParList *pList) { return kTRUE; } // -------------------------------------------------------------------------- // // This is processed before the eventloop starts // // It is the job of the PreProcess to connect the tasks // with the right container in the parameter list. // // the virtual implementation returns kTRUE // Bool_t MTask::PreProcess(MParList *pList) { return kTRUE; } // -------------------------------------------------------------------------- // // This is processed for every event in the eventloop // // the virtual implementation returns kTRUE // Bool_t MTask::Process() { return kTRUE; } // -------------------------------------------------------------------------- // // This is processed after the eventloop starts // // the virtual implementation returns kTRUE // Bool_t MTask::PostProcess() { return kTRUE; } // -------------------------------------------------------------------------- // // Prints the number of times all the tasks in the list has been. // For convinience the lvl argument results in a number of spaces at the // beginning of the line. So that the structur of a tasklist can be // identified. If a Tasklist or task has filter applied the name of the // filter is printer in <>-brackets behind the number of executions. // Use MTaskList::PrintStatistics without an argument. // void MTask::PrintStatistics(const Int_t lvl, Bool_t title) const { *fLog << all << setw(lvl) << " " << GetDescriptor() << "\t"; *fLog << dec << fNumExecutions; if (fFilter) *fLog << " <" << fFilter->GetName() << ">"; if (title) *fLog << "\t" << fTitle; *fLog << endl; } // -------------------------------------------------------------------------- // // First call MParContainer::SavePrimitive which should stream the primitive // to the output stream. Then, if a filter is set, stream first the filter // and afterwards set the filter for this task. // void MTask::SavePrimitive(ofstream &out, Option_t *o) { MParContainer::SavePrimitive(out); if (!fFilter) return; /* If we don't stream filter which are not in the task list itself (which means: already streamed) we may be able to use SavePrimitive as some kind of validity check for the macros fFilter->SavePrimitive(out); */ out << " " << GetUniqueName() << ".SetFilter(&" << fFilter->GetUniqueName() <<");" << endl; } // -------------------------------------------------------------------------- // // Check whether the class given in the argument overwrites MTask::Process. // This function calls itself recursively. If you want to call it, // leave out the argument. // Bool_t MTask::OverwritesProcess(TClass *cls) const { if (!cls) cls = IsA(); // // Check whether we reached the base class MTask // if (TString(cls->GetName())=="MTask") return kFALSE; // // Check whether the class cls overwrites Process // if (cls->GetMethodAny("Process")) return kTRUE; // // If the class itself doesn't overload it check all it's base classes // TBaseClass *base=NULL; TIter NextBase(cls->GetListOfBases()); while ((base=(TBaseClass*)NextBase())) { if (OverwritesProcess(base->GetClassPointer())) return kTRUE; } return kFALSE; } void MTask::SetDisplay(MStatusDisplay *d) { if (fFilter) fFilter->SetDisplay(d); MParContainer::SetDisplay(d); }