/* ======================================================================== *\ ! ! * ! * 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-2001 ! ! \* ======================================================================== */ ////////////////////////////////////////////////////////////////////////////// // // // MEvtLoop // // // // This class is the core of each event processing. // // First you must set the parameter list to use. The parameter list // // must contain the task list (MTaskList) to use. The name of the task // // list can be specified if you call Eventloop. The standard name is // // "MTaskList". The name you specify must match the name of the MTaskList // // object. // // // // If you call Eventloop first all PreProcess functions - with the // // parameter list as an argument - of the tasks in the task list are // // executed. If one of them returns kFALSE then the execution is stopped. // // If the preprocessing was ok. The Process funtion of the tasks are // // as long as one function returns kSTOP. Only the tasks which are marked // // marked as "All" or with a string which matches the MInputStreamID of // // MTaskList are executed. If one tasks returns kCONTINUE the pending // // tasks in the list are skipped and the execution in continued with // // the first one in the list. // // Afterwards the PostProcess functions are executed. // // // // // // Maybe we can add a TProgressMeter sometimes later to be able to show // // the progress graphically... // // // // // // You can create a macro from a completely setup eventloop by: // // evtloop.MakeMacro("mymacro.C"); // // // // You will always need to check the macro, it will not run, but it // // should have al important information. // // // // // // You can also write all this information to a root file: // // TFile file("myfile.root"); // // evtloop.Write("MyEvtloopKey"); // // // // You can afterwards read the information from an open file by: // // evtloop.Read("MyEvtloopKey"); // // // // To lookup the information write it to a file using MakeMacro // // // ////////////////////////////////////////////////////////////////////////////// #include "MEvtLoop.h" #include // time_t #include // ofstream, SavePrimitive #include #include // gFile #include // gSystem #include #include #include "MLog.h" #include "MLogManip.h" #include "MParList.h" #include "MTaskList.h" ClassImp(MEvtLoop); //! //! Maybe we can add a static parameter list to MEvtLoop //! Also we can derive MEvtLoop from MTaskList to have a static tasklist, too //! TList *gListOfPrimitives; // forard declaration in MParContainer.h // -------------------------------------------------------------------------- // // default constructor - emty // MEvtLoop::MEvtLoop() : fParList(NULL), fProgress(NULL) { fName = "Evtloop"; } // -------------------------------------------------------------------------- // // default destructor - emty // MEvtLoop::~MEvtLoop() { if (TestBit(kIsOwner) && fParList) delete fParList; } // -------------------------------------------------------------------------- // // if you set the Eventloop as owner the destructor of the given parameter // list is calles by the destructor of MEvtLoop, otherwise not. // void MEvtLoop::SetOwner(Bool_t enable) { enable ? SetBit(kIsOwner) : ResetBit(kIsOwner); } // -------------------------------------------------------------------------- // // The proprocessing part of the eventloop. Be careful, this is // for developers or use in special jobs only! // Bool_t MEvtLoop::PreProcess(const char *tlist) { // // check if the needed parameter list is set. // if (!fParList) { *fLog << err << dbginf << "Parlist not initialized." << endl; return kFALSE; } // // check for the existance of the specified task list // the default name is "MTaskList" // fTaskList = (MTaskList*)fParList->FindObject(tlist, "MTaskList"); if (!fTaskList) { *fLog << err << dbginf << "Cannot find tasklist '" << tlist << "' in parameter list." << endl; return kFALSE; } if (fLog != &gLog) fParList->SetLogStream(fLog); // // execute the preprocess of all tasks // connect the different tasks with the right containers in // the parameter list // if (!fTaskList->PreProcess(fParList)) { *fLog << err << "Error detected while PreProcessing" << endl; return kFALSE; } *fLog << endl; return kTRUE; } // -------------------------------------------------------------------------- // // The processing part of the eventloop. Be careful, this is // for developers or use in special jobs only! // void MEvtLoop::Process(Int_t maxcnt) const { // // loop over all events and process all tasks for // each event // *fLog << all <<"Eventloop running ("; if (maxcnt<0) *fLog << "all"; else *fLog << dec << maxcnt; *fLog << " events)..." << flush; if (fProgress && maxcnt>0) fProgress->SetRange(0, maxcnt); Int_t dummy = maxcnt<0 ? 0 : maxcnt; // // start a stopwatch // TStopwatch clock; clock.Start(); // // This is the MAIN EVENTLOOP which processes the data // if maxcnt<0 the number of processed events is counted // else only maxcnt events are processed // if (maxcnt<0) // process first and increment if sucessfull if (fProgress) while (fTaskList->Process()) { fProgress->SetPosition(++dummy); #if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06) gSystem->ProcessEvents(); #else gClient->ProcessEventsFor(fProgress); #endif } else while (fTaskList->Process()) dummy++; else // check for number and break if unsuccessfull if (fProgress) while (dummy-- && fTaskList->Process()) { fProgress->SetPosition(maxcnt - dummy); #if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06) gSystem->ProcessEvents(); #else gClient->ProcessEventsFor(fProgress); #endif } else while (dummy-- && fTaskList->Process()); // // stop stop-watch, print results // clock.Stop(); *fLog << all << "Ready!" << endl << endl; *fLog << dec << endl << "CPU - " << "Time: " << clock.CpuTime() << "s" << " for " << (maxcnt<0?dummy:maxcnt) << " Events" << " --> " << (maxcnt<0?dummy:maxcnt)/clock.CpuTime() << " Events/s" << endl; *fLog << "Real - " << "Time: " << clock.RealTime() << "s" << " for " << (maxcnt<0?dummy:maxcnt) << " Events" << " --> " << (maxcnt<0?dummy:maxcnt)/clock.RealTime() << " Events/s" << endl << endl; } // -------------------------------------------------------------------------- // // The postprocessing part of the eventloop. Be careful, this is // for developers or use in special jobs only! // Bool_t MEvtLoop::PostProcess() const { // // execute the post process of all tasks // return fTaskList->PostProcess(); } // -------------------------------------------------------------------------- // // See class description above. // Bool_t MEvtLoop::Eventloop(Int_t maxcnt, const char *tlist) { Bool_t rc = PreProcess(); // // If all Tasks were PreProcesses successfully start Processing. // if (rc) Process(maxcnt); // // Now postprocess all tasks. Only successfully preprocessed tasks are // postprocessed. If the Postprocessing of one task fail return an error. // if (!PostProcess()) return kFALSE; // // If postprocessing of all preprocessed tasks was sucefully return rc. // This gives an error in case the preprocessing has failed already. // Otherwise the eventloop is considered: successfully. // return rc; } // -------------------------------------------------------------------------- // // After you setup (or read) an Evtloop you can use this to write the // eventloop setup as a macro. The default name is "evtloop.C". The default // extension is .C If the extension is not given, .C is added. // I the last character in the argument is a '+' the file is not closed. // This is usefull if you have an eventloop which runs three times and // you want to write one macro. If the first character is a '+' no // opening is written, eg: // // MEvtLoop evtloop; // // some setup // evtloop.MakeMacro("mymacro+"); // // replace the tasklist the first time // evtloop.MakeMacro("+mymacro+"); // // replace the tasklist the second time // evtloop.MakeMacro("+mymacro"); // void MEvtLoop::MakeMacro(const char *filename) { TString name(filename); name = name.Strip(TString::kBoth); Bool_t open = kTRUE; Bool_t close = kTRUE; if (name[0]=='+') { open = kFALSE; name.Remove(0, 1); name = name.Strip(TString::kBoth); } if (name[name.Length()-1]=='+') { close = kFALSE; name.Remove(name.Length()-1, 1); name = name.Strip(TString::kBoth); } if (!name.EndsWith(".C")) name += ".C"; ofstream fout; if (!open) { fout.open(name, ios::app); fout << endl; fout << " // ----------------------------------------------------------------------" << endl; fout << endl; } else { fout.open(name); time_t t = time(NULL); fout << "/* ======================================================================== *\\" << endl << "!" << endl << "! *" << endl << "! * This file is part of MARS, the MAGIC Analysis and Reconstruction" << endl << "! * Software. It is distributed to you in the hope that it can be a useful" << endl << "! * and timesaving tool in analysing Data of imaging Cerenkov telescopes." << endl << "! * It is distributed WITHOUT ANY WARRANTY." << endl << "! *" << endl << "! * Permission to use, copy, modify and distribute this software and its" << endl << "! * documentation for any purpose is hereby granted without fee," << endl << "! * provided that the above copyright notice appear in all copies and" << endl << "! * that both that copyright notice and this permission notice appear" << endl << "! * in supporting documentation. It is provided \"as is\" without express" << endl << "! * or implied warranty." << endl << "! *" << endl << "!" << endl << "!" << endl << "! Author(s): Thomas Bretz et al. " << endl << "!" << endl << "! Copyright: MAGIC Software Development, 2000-2002" << endl << "!" << endl << "!" << endl << "\\* ======================================================================== */" << endl << endl << "// ------------------------------------------------------------------------" << endl << "//" << endl << "// This macro was automatically created on" << endl<< "// " << ctime(&t) << "// with the MEvtLoop::MakeMacro tool." << endl << "//" << endl << "// ------------------------------------------------------------------------" << endl << endl << "void " << name(0, name.Length()-2) << "()" << endl << "{" << endl; } SavePrimitive(fout, (TString)"" + (open?"open":"") + (close?"close":"")); if (!close) return; fout << "}" << endl; *fLog << inf << "Macro '" << name << "' written." << endl; } // -------------------------------------------------------------------------- // // Implementation of SavePrimitive. Used to write the call to a constructor // to a macro. In the original root implementation it is used to write // gui elements to a macro-file. // void MEvtLoop::StreamPrimitive(ofstream &out) const { out << " MEvtLoop " << GetUniqueName() << ";" << endl; } void MEvtLoop::SavePrimitive(ofstream &out, Option_t *opt) { TString options = opt; options.ToLower(); if (HasDuplicateNames("MEvtLoop::SavePrimitive")) { out << " // !" << endl; out << " // ! WARNING - Your eventloop (MParList, MTaskList, ...) contains more than" << endl; out << " // ! one object (MParContainer, MTask, ...) with the same name. The created macro" << endl; out << " // ! may need manual intervention before it can be used." << endl; out << " // !" << endl; out << endl; } if (!options.Contains("open")) { if (gListOfPrimitives) { *fLog << err << "MEvtLoop::SavePrimitive - Error: old file not closed." << endl; gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15)); delete gListOfPrimitives; } gListOfPrimitives = new TList; } if (fParList) fParList->SavePrimitive(out); MParContainer::SavePrimitive(out); if (fParList) out << " " << GetUniqueName() << ".SetParList(&" << fParList->GetUniqueName() << ");" << endl; else out << " // fParList empty..." << endl; out << " if (!" << GetUniqueName() << ".Eventloop())" << endl; out << " return;" << endl; if (!options.Contains("close")) return; gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15)); delete gListOfPrimitives; gListOfPrimitives = 0; } // -------------------------------------------------------------------------- // // Get a list of all conmtainer names which are somehow part of the // eventloop. Chack for duplicate members and print a warning if // duplicates are found. Return kTRUE if duplicates are found, otherwise // kFALSE; // Bool_t MEvtLoop::HasDuplicateNames(TObjArray &arr, const TString txt) const { arr.Sort(); TIter Next(&arr); TObject *obj; TString name; Bool_t found = kFALSE; while ((obj=Next())) { if (name==obj->GetName()) { if (!found) { *fLog << warn << endl; *fLog << " ! WARNING (" << txt << ")" << endl; *fLog << " ! Your eventloop (MParList, MTaskList, ...) contains more than" << endl; *fLog << " ! one object (MParContainer, MTask, ...) with the same name." << endl; *fLog << " ! Creating a macro from it using MEvtLoop::MakeMacro may create" << endl; *fLog << " ! a macro which needs manual intervention before it can be used." << endl; found = kTRUE; } *fLog << " ! Please rename: " << obj->GetName() << endl; } name = obj->GetName(); } return found; } // -------------------------------------------------------------------------- // // Get a list of all conmtainer names which are somehow part of the // eventloop. Chack for duplicate members and print a warning if // duplicates are found. Return kTRUE if duplicates are found, otherwise // kFALSE; // Bool_t MEvtLoop::HasDuplicateNames(const TString txt) const { if (!fParList) return kFALSE; TObjArray list; list.SetOwner(); fParList->GetNames(list); return HasDuplicateNames(list, txt); } // -------------------------------------------------------------------------- // // Reads a saved eventloop from a file. The default name is "Evtloop". // Therefor an open file must exist (See TFile for more information) // // eg: // TFile file("myfile.root", "READ"); // MEvtLoop evtloop; // evtloop.Read(); // evtloop.MakeMacro("mymacro"); // Int_t MEvtLoop::Read(const char *name) { if (!gFile) { *fLog << err << "MEvtloop::Read: No file found. Please create a TFile first." << endl; return 0; } if (!gFile->IsOpen()) { *fLog << err << "MEvtloop::Read: File not open. Please open the TFile first." << endl; return 0; } Int_t n = 0; TObjArray list; n += TObject::Read(name); if (n==0) { *fLog << err << "MEvtloop::Read: No objects read." << endl; return 0; } n += list.Read((TString)name+"_names"); fParList->SetNames(list); HasDuplicateNames(list, "MEvtLoop::Read"); *fLog << inf << "Eventloop '" << name << "' read from file." << endl; return n; } // -------------------------------------------------------------------------- // // If available print the contents of the parameter list. // void MEvtLoop::Print(Option_t *opt) const { if (fParList) fParList->Print(); else *fLog << all << "MEvtloop: No Parameter List available." << endl; } // -------------------------------------------------------------------------- // // Writes a eventloop to a file. The default name is "Evtloop". // Therefor an open file must exist (See TFile for more information) // // eg: // TFile file("myfile.root", "RECREATE"); // MEvtLoop evtloop; // evtloop.Write(); // file.Close(); // Int_t MEvtLoop::Write(const char *name, Int_t option, Int_t bufsize) { if (!gFile) { *fLog << err << "MEvtloop::Write: No file found. Please create a TFile first." << endl; return 0; } if (!gFile->IsOpen()) { *fLog << err << "MEvtloop::Write: File not open. Please open the TFile first." << endl; return 0; } if (!gFile->IsWritable()) { *fLog << err << "MEvtloop::Write: File not writable." << endl; return 0; } Int_t n = 0; TObjArray list; list.SetOwner(); fParList->GetNames(list); n += TObject::Write(name, option, bufsize); if (n==0) { *fLog << err << "MEvtloop::Read: No objects written." << endl; return 0; } n += list.Write((TString)name+"_names", kSingleKey); HasDuplicateNames(list, "MEvtLoop::Write"); *fLog << inf << "Eventloop written to file as " << name << "." << endl; return n; }