source: trunk/MagicSoft/Mars/mbase/MEvtLoop.cc@ 1938

Last change on this file since 1938 was 1902, checked in by tbretz, 21 years ago
*** empty log message ***
File size: 24.2 KB
Line 
1/* ======================================================================== *\
2!
3! *
4! * This file is part of MARS, the MAGIC Analysis and Reconstruction
5! * Software. It is distributed to you in the hope that it can be a useful
6! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
7! * It is distributed WITHOUT ANY WARRANTY.
8! *
9! * Permission to use, copy, modify and distribute this software and its
10! * documentation for any purpose is hereby granted without fee,
11! * provided that the above copyright notice appear in all copies and
12! * that both that copyright notice and this permission notice appear
13! * in supporting documentation. It is provided "as is" without express
14! * or implied warranty.
15! *
16!
17!
18! Author(s): Thomas Bretz 12/2000 <mailto:tbretz@uni-sw.gwdg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2001
21!
22!
23\* ======================================================================== */
24
25
26//////////////////////////////////////////////////////////////////////////////
27// //
28// MEvtLoop //
29// //
30// This class is the core of each event processing. //
31// First you must set the parameter list to use. The parameter list //
32// must contain the task list (MTaskList) to use. The name of the task //
33// list can be specified if you call Eventloop. The standard name is //
34// "MTaskList". The name you specify must match the name of the MTaskList //
35// object. //
36// //
37// If you call Eventloop first all PreProcess functions - with the //
38// parameter list as an argument - of the tasks in the task list are //
39// executed. If one of them returns kFALSE then the execution is stopped. //
40// If the preprocessing was ok. The Process funtion of the tasks are //
41// as long as one function returns kSTOP. Only the tasks which are marked //
42// marked as "All" or with a string which matches the MInputStreamID of //
43// MTaskList are executed. If one tasks returns kCONTINUE the pending //
44// tasks in the list are skipped and the execution in continued with //
45// the first one in the list. //
46// Afterwards the PostProcess functions are executed. //
47// //
48// //
49// Maybe we can add a TProgressMeter sometimes later to be able to show //
50// the progress graphically... //
51// //
52// //
53// You can create a macro from a completely setup eventloop by: //
54// evtloop.MakeMacro("mymacro.C"); //
55// //
56// You will always need to check the macro, it will not run, but it //
57// should have al important information. //
58// //
59// //
60// You can also write all this information to a root file: //
61// TFile file("myfile.root"); //
62// evtloop.Write("MyEvtloopKey"); //
63// //
64// You can afterwards read the information from an open file by: //
65// evtloop.Read("MyEvtloopKey"); //
66// //
67// To lookup the information write it to a file using MakeMacro //
68// //
69//////////////////////////////////////////////////////////////////////////////
70#include "MEvtLoop.h"
71
72#include <time.h> // time_t
73#include <fstream.h> // ofstream, SavePrimitive
74#include <iostream.h>
75
76#include <TFile.h> // gFile
77#include <TSystem.h> // gSystem
78#include <TStopwatch.h>
79#include <TGProgressBar.h>
80
81#include "MLog.h"
82#include "MLogManip.h"
83
84#include "MParList.h"
85#include "MTaskList.h"
86#ifdef __MARS__
87#include "MRead.h" // for setting progress bar
88#include "MProgressBar.h" // MProgressBar::GetBar
89#endif
90
91ClassImp(MEvtLoop);
92
93
94//!
95//! Maybe we can add a static parameter list to MEvtLoop
96//! Also we can derive MEvtLoop from MTaskList to have a static tasklist, too
97//!
98
99TList *gListOfPrimitives; // forard declaration in MParContainer.h
100
101// --------------------------------------------------------------------------
102//
103// default constructor - emty
104//
105MEvtLoop::MEvtLoop(const char *name) : fParList(NULL), fProgress(NULL)
106{
107 fName = name;
108
109 *fLog << inf << "Instantiated MEvtLoop (" << name << "), using ROOT v" << ROOTVER << endl;
110}
111
112// --------------------------------------------------------------------------
113//
114// default destructor - emty
115//
116MEvtLoop::~MEvtLoop()
117{
118 if (TestBit(kIsOwner) && fParList)
119 delete fParList;
120}
121
122// --------------------------------------------------------------------------
123//
124// if you set the Eventloop as owner the destructor of the given parameter
125// list is calles by the destructor of MEvtLoop, otherwise not.
126//
127void MEvtLoop::SetOwner(Bool_t enable)
128{
129 enable ? SetBit(kIsOwner) : ResetBit(kIsOwner);
130}
131
132#ifdef __MARS__
133// --------------------------------------------------------------------------
134//
135// Specify an existing MProgressBar object. It will display the progress
136// graphically. This will make thing about 1-2% slower.
137//
138void MEvtLoop::SetProgressBar(MProgressBar *bar)
139{
140 fProgress = bar->GetBar();
141}
142#endif
143
144// --------------------------------------------------------------------------
145//
146// The proprocessing part of the eventloop. Be careful, this is
147// for developers or use in special jobs only!
148//
149Bool_t MEvtLoop::PreProcess(const char *tlist)
150{
151 //
152 // check if the needed parameter list is set.
153 //
154 if (!fParList)
155 {
156 *fLog << err << dbginf << "Parlist not initialized." << endl;
157 return kFALSE;
158 }
159
160 //
161 // check for the existance of the specified task list
162 // the default name is "MTaskList"
163 //
164 fTaskList = (MTaskList*)fParList->FindObject(tlist, "MTaskList");
165 if (!fTaskList)
166 {
167 *fLog << err << dbginf << "Cannot find tasklist '" << tlist << "' in parameter list." << endl;
168 return kFALSE;
169 }
170
171 if (fLog != &gLog)
172 fParList->SetLogStream(fLog);
173
174 //
175 // execute the preprocess of all tasks
176 // connect the different tasks with the right containers in
177 // the parameter list
178 //
179 if (!fTaskList->PreProcess(fParList))
180 {
181 *fLog << err << "Error detected while PreProcessing" << endl;
182 return kFALSE;
183 }
184
185 *fLog << endl;
186
187 return kTRUE;
188}
189
190// --------------------------------------------------------------------------
191//
192// The processing part of the eventloop. Be careful, this is
193// for developers or use in special jobs only!
194//
195Bool_t MEvtLoop::Process(Int_t maxcnt) const
196{
197 //
198 // loop over all events and process all tasks for
199 // each event
200 //
201 *fLog << all <<"Eventloop running (";
202
203 if (maxcnt<0)
204 *fLog << "all";
205 else
206 *fLog << dec << maxcnt;
207
208 *fLog << " events)..." << flush;
209
210 if (fProgress)
211 {
212 fProgress->Reset();
213
214 Int_t entries = INT_MAX;
215
216#ifdef __MARS__
217 // limits.h
218 MRead *read = (MRead*)fTaskList->FindObject("MRead");
219 if (read && read->GetEntries()>0)
220 entries = read->GetEntries();
221#endif
222
223 if (maxcnt>0)
224 fProgress->SetRange(0, TMath::Min(maxcnt, entries));
225 else
226 if (entries!=INT_MAX)
227 fProgress->SetRange(0, entries);
228 }
229
230 Int_t dummy = maxcnt<0 ? 0 : maxcnt;
231
232 //
233 // start a stopwatch
234 //
235 TStopwatch clock;
236 clock.Start();
237
238 //
239 // This is the MAIN EVENTLOOP which processes the data
240 // if maxcnt<0 the number of processed events is counted
241 // else only maxcnt events are processed
242 //
243 Int_t numcnts = 0;
244
245 Bool_t rc = kTRUE;
246 if (maxcnt<0)
247 // process first and increment if sucessfull
248 if (fProgress)
249 while ((rc=fTaskList->Process())==kTRUE)
250 {
251 fProgress->SetPosition(++dummy);
252#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
253 gSystem->ProcessEvents();
254#else
255 gClient->ProcessEventsFor(fProgress);
256#endif
257 numcnts++;
258 }
259 else
260 while ((rc=fTaskList->Process())==kTRUE) numcnts++;
261 else
262 // check for number and break if unsuccessfull
263 if (fProgress)
264 while (dummy-- && (rc=fTaskList->Process())==kTRUE)
265 {
266 fProgress->SetPosition(maxcnt - dummy);
267#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
268 gSystem->ProcessEvents();
269#else
270 gClient->ProcessEventsFor(fProgress);
271#endif
272 numcnts++;
273 }
274 else
275 while (dummy-- && (rc=fTaskList->Process())==kTRUE) numcnts++;
276
277 //
278 // stop stop-watch, print results
279 //
280 clock.Stop();
281
282 *fLog << all << "Ready!" << endl << endl;
283
284 *fLog << dec << endl << "CPU - "
285 << "Time: " << clock.CpuTime() << "s"
286 << " for " << numcnts << " Events"
287 << " --> " << numcnts/clock.CpuTime() << " Events/s"
288 << endl;
289 *fLog << "Real - "
290 << "Time: " << clock.RealTime() << "s"
291 << " for " << numcnts << " Events"
292 << " --> " << numcnts/clock.RealTime() << " Events/s"
293 << endl << endl;
294
295 return rc!=kERROR;
296}
297
298// --------------------------------------------------------------------------
299//
300// The postprocessing part of the eventloop. Be careful, this is
301// for developers or use in special jobs only!
302//
303Bool_t MEvtLoop::PostProcess() const
304{
305 //
306 // execute the post process of all tasks
307 //
308 return fTaskList->PostProcess();
309}
310
311// --------------------------------------------------------------------------
312//
313// See class description above.
314//
315Bool_t MEvtLoop::Eventloop(Int_t maxcnt, const char *tlist)
316{
317 Bool_t rc = PreProcess();
318
319 //
320 // If all Tasks were PreProcesses successfully start Processing.
321 //
322 if (rc)
323 rc = Process(maxcnt);
324
325 //
326 // Now postprocess all tasks. Only successfully preprocessed tasks are
327 // postprocessed. If the Postprocessing of one task fail return an error.
328 //
329 if (!PostProcess())
330 return kFALSE;
331
332 //
333 // If postprocessing of all preprocessed tasks was sucefully return rc.
334 // This gives an error in case the preprocessing has failed already.
335 // Otherwise the eventloop is considered: successfully.
336 //
337 return rc;
338}
339
340// --------------------------------------------------------------------------
341//
342// After you setup (or read) an Evtloop you can use this to write the
343// eventloop setup as a macro. The default name is "evtloop.C". The default
344// extension is .C If the extension is not given, .C is added.
345// I the last character in the argument is a '+' the file is not closed.
346// This is usefull if you have an eventloop which runs three times and
347// you want to write one macro. If the first character is a '+' no
348// opening is written, eg:
349//
350// MEvtLoop evtloop;
351// // some setup
352// evtloop.MakeMacro("mymacro+");
353// // replace the tasklist the first time
354// evtloop.MakeMacro("+mymacro+");
355// // replace the tasklist the second time
356// evtloop.MakeMacro("+mymacro");
357//
358void MEvtLoop::MakeMacro(const char *filename)
359{
360 TString name(filename);
361
362 name = name.Strip(TString::kBoth);
363
364 Bool_t open = kTRUE;
365 Bool_t close = kTRUE;
366 if (name[0]=='+')
367 {
368 open = kFALSE;
369 name.Remove(0, 1);
370 name = name.Strip(TString::kBoth);
371 }
372
373 if (name[name.Length()-1]=='+')
374 {
375 close = kFALSE;
376 name.Remove(name.Length()-1, 1);
377 name = name.Strip(TString::kBoth);
378 }
379
380 if (!name.EndsWith(".C"))
381 name += ".C";
382
383 ofstream fout;
384
385 if (!open)
386 {
387 fout.open(name, ios::app);
388 fout << endl;
389 fout << " // ----------------------------------------------------------------------" << endl;
390 fout << endl;
391 }
392 else
393 {
394 fout.open(name);
395
396 time_t t = time(NULL);
397 fout <<
398 "/* ======================================================================== *\\" << endl <<
399 "!" << endl <<
400 "! *" << endl <<
401 "! * This file is part of MARS, the MAGIC Analysis and Reconstruction" << endl <<
402 "! * Software. It is distributed to you in the hope that it can be a useful" << endl <<
403 "! * and timesaving tool in analysing Data of imaging Cerenkov telescopes." << endl <<
404 "! * It is distributed WITHOUT ANY WARRANTY." << endl <<
405 "! *" << endl <<
406 "! * Permission to use, copy, modify and distribute this software and its" << endl <<
407 "! * documentation for any purpose is hereby granted without fee," << endl <<
408 "! * provided that the above copyright notice appear in all copies and" << endl <<
409 "! * that both that copyright notice and this permission notice appear" << endl <<
410 "! * in supporting documentation. It is provided \"as is\" without express" << endl <<
411 "! * or implied warranty." << endl <<
412 "! *" << endl <<
413 "!" << endl <<
414 "!" << endl <<
415 "! Author(s): Thomas Bretz et al. <mailto:tbretz@astro.uni-wuerzburg.de>" << endl <<
416 "!" << endl <<
417 "! Copyright: MAGIC Software Development, 2000-2002" << endl <<
418 "!" << endl <<
419 "!" << endl <<
420 "\\* ======================================================================== */" << endl << endl <<
421 "// ------------------------------------------------------------------------" << endl <<
422 "//" << endl <<
423 "// This macro was automatically created on" << endl<<
424 "// " << ctime(&t) <<
425 "// with the MEvtLoop::MakeMacro tool." << endl <<
426 "//" << endl <<
427 "// ------------------------------------------------------------------------" << endl << endl <<
428 "void " << name(0, name.Length()-2) << "()" << endl <<
429 "{" << endl;
430 }
431
432 SavePrimitive(fout, (TString)"" + (open?"open":"") + (close?"close":""));
433
434 if (!close)
435 return;
436
437 fout << "}" << endl;
438
439 *fLog << inf << "Macro '" << name << "' written." << endl;
440}
441
442// --------------------------------------------------------------------------
443//
444// Implementation of SavePrimitive. Used to write the call to a constructor
445// to a macro. In the original root implementation it is used to write
446// gui elements to a macro-file.
447//
448void MEvtLoop::StreamPrimitive(ofstream &out) const
449{
450 out << " MEvtLoop " << GetUniqueName();
451 if (fName!="Evtloop")
452 out << "(\"" << fName << "\")";
453 out << ";" << endl;
454}
455
456// --------------------------------------------------------------------------
457//
458//
459void MEvtLoop::SavePrimitive(ofstream &out, Option_t *opt)
460{
461 TString options = opt;
462 options.ToLower();
463
464 if (HasDuplicateNames("MEvtLoop::SavePrimitive"))
465 {
466 out << " // !" << endl;
467 out << " // ! WARNING - Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
468 out << " // ! one object (MParContainer, MTask, ...) with the same name. The created macro" << endl;
469 out << " // ! may need manual intervention before it can be used." << endl;
470 out << " // !" << endl;
471 out << endl;
472 }
473
474 if (!options.Contains("open"))
475 {
476 if (gListOfPrimitives)
477 {
478 *fLog << err << "MEvtLoop::SavePrimitive - Error: old file not closed." << endl;
479 gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15));
480 delete gListOfPrimitives;
481 }
482 gListOfPrimitives = new TList;
483 }
484
485 if (fParList)
486 fParList->SavePrimitive(out);
487
488 MParContainer::SavePrimitive(out);
489
490 if (fParList)
491 out << " " << GetUniqueName() << ".SetParList(&" << fParList->GetUniqueName() << ");" << endl;
492 else
493 out << " // fParList empty..." << endl;
494 out << " if (!" << GetUniqueName() << ".Eventloop())" << endl;
495 out << " return;" << endl;
496
497 if (!options.Contains("close"))
498 return;
499
500 gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15));
501 delete gListOfPrimitives;
502 gListOfPrimitives = 0;
503}
504
505// --------------------------------------------------------------------------
506//
507// Get a list of all conmtainer names which are somehow part of the
508// eventloop. Chack for duplicate members and print a warning if
509// duplicates are found. Return kTRUE if duplicates are found, otherwise
510// kFALSE;
511//
512Bool_t MEvtLoop::HasDuplicateNames(TObjArray &arr, const TString txt) const
513{
514 arr.Sort();
515
516 TIter Next(&arr);
517 TObject *obj;
518 TString name;
519 Bool_t found = kFALSE;
520 while ((obj=Next()))
521 {
522 if (name==obj->GetName())
523 {
524 if (!found)
525 {
526 *fLog << warn << endl;
527 *fLog << " ! WARNING (" << txt << ")" << endl;
528 *fLog << " ! Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
529 *fLog << " ! one object (MParContainer, MTask, ...) with the same name." << endl;
530 *fLog << " ! Creating a macro from it using MEvtLoop::MakeMacro may create" << endl;
531 *fLog << " ! a macro which needs manual intervention before it can be used." << endl;
532 found = kTRUE;
533 }
534 *fLog << " ! Please rename: " << obj->GetName() << endl;
535 }
536 name = obj->GetName();
537 }
538
539 return found;
540}
541
542// --------------------------------------------------------------------------
543//
544// Get a list of all conmtainer names which are somehow part of the
545// eventloop. Chack for duplicate members and print a warning if
546// duplicates are found. Return kTRUE if duplicates are found, otherwise
547// kFALSE;
548//
549Bool_t MEvtLoop::HasDuplicateNames(const TString txt) const
550{
551 if (!fParList)
552 return kFALSE;
553
554 TObjArray list;
555 list.SetOwner();
556
557 fParList->GetNames(list);
558
559 return HasDuplicateNames(list, txt);
560}
561
562// --------------------------------------------------------------------------
563//
564// Reads a saved eventloop from a file. The default name is "Evtloop".
565// Therefor an open file must exist (See TFile for more information)
566//
567// eg:
568// TFile file("myfile.root", "READ");
569// MEvtLoop evtloop;
570// evtloop.Read();
571// evtloop.MakeMacro("mymacro");
572//
573Int_t MEvtLoop::Read(const char *name)
574{
575 if (!gFile)
576 {
577 *fLog << err << "MEvtloop::Read: No file found. Please create a TFile first." << endl;
578 return 0;
579 }
580
581 if (!gFile->IsOpen())
582 {
583 *fLog << err << "MEvtloop::Read: File not open. Please open the TFile first." << endl;
584 return 0;
585 }
586
587 Int_t n = 0;
588 TObjArray list;
589
590 n += TObject::Read(name);
591
592 if (n==0)
593 {
594 *fLog << err << "MEvtloop::Read: No objects read." << endl;
595 return 0;
596 }
597
598 n += list.Read((TString)name+"_names");
599
600 fParList->SetNames(list);
601
602 HasDuplicateNames(list, "MEvtLoop::Read");
603
604 *fLog << inf << "Eventloop '" << name << "' read from file." << endl;
605
606 return n;
607}
608
609// --------------------------------------------------------------------------
610//
611// If available print the contents of the parameter list.
612//
613void MEvtLoop::Print(Option_t *opt) const
614{
615 if (fParList)
616 fParList->Print();
617 else
618 *fLog << all << "MEvtloop: No Parameter List available." << endl;
619}
620
621// --------------------------------------------------------------------------
622//
623// Writes a eventloop to a file. The default name is "Evtloop".
624// Therefor an open file must exist (See TFile for more information)
625//
626// eg:
627// TFile file("myfile.root", "RECREATE");
628// MEvtLoop evtloop;
629// evtloop.Write();
630// file.Close();
631//
632Int_t MEvtLoop::Write(const char *name, Int_t option, Int_t bufsize)
633{
634 if (!gFile)
635 {
636 *fLog << err << "MEvtloop::Write: No file found. Please create a TFile first." << endl;
637 return 0;
638 }
639
640 if (!gFile->IsOpen())
641 {
642 *fLog << err << "MEvtloop::Write: File not open. Please open the TFile first." << endl;
643 return 0;
644 }
645
646 if (!gFile->IsWritable())
647 {
648 *fLog << err << "MEvtloop::Write: File not writable." << endl;
649 return 0;
650 }
651
652 Int_t n = 0;
653
654 TObjArray list;
655 list.SetOwner();
656
657 fParList->GetNames(list);
658
659 n += TObject::Write(name, option, bufsize);
660
661 if (n==0)
662 {
663 *fLog << err << "MEvtloop::Read: No objects written." << endl;
664 return 0;
665 }
666
667 n += list.Write((TString)name+"_names", kSingleKey);
668
669 HasDuplicateNames(list, "MEvtLoop::Write");
670
671 *fLog << inf << "Eventloop written to file as " << name << "." << endl;
672
673 return n;
674}
675
676// --------------------------------------------------------------------------
677//
678// Read the contents/setup of a parameter container/task from a TEnv
679// instance (steering card/setup file).
680// The key to search for in the file should be of the syntax:
681// prefix.vname
682// While vname is a name which is specific for a single setup date
683// (variable) of this container and prefix is something like:
684// evtloopname.name
685// While name is the name of the containers/tasks in the parlist/tasklist
686//
687// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
688// Job4.MImgCleanStd.CleaningLevel2: 2.5
689//
690// If this cannot be found the next step is to search for
691// MImgCleanStd.CleaningLevel1: 3.0
692// And if this doesn't exist, too, we should search for:
693// CleaningLevel1: 3.0
694//
695// Warning: The programmer is responsible for the names to be unique in
696// all Mars classes.
697//
698Bool_t MEvtLoop::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
699{
700 if (!prefix.IsNull())
701 *fLog << warn << "WARNING - Second argument in MEvtLoop::ReadEnv has no meaning... ignored." << endl;
702
703 prefix = fName;
704 prefix += ".";
705
706 *fLog << inf << "Reading resources for " << prefix /*TEnv::fRcName << " from " << env.GetRcName()*/ << endl;
707
708 if (fParList->ReadEnv(env, prefix, print)==kERROR)
709 {
710 *fLog << err << "ERROR - Reading Environment file." << endl;
711 return kFALSE;
712 }
713
714 return kTRUE;
715}
716
717// --------------------------------------------------------------------------
718//
719// Write the contents/setup of a parameter container/task to a TEnv
720// instance (steering card/setup file).
721// The key to search for in the file should be of the syntax:
722// prefix.vname
723// While vname is a name which is specific for a single setup date
724// (variable) of this container and prefix is something like:
725// evtloopname.name
726// While name is the name of the containers/tasks in the parlist/tasklist
727//
728// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
729// Job4.MImgCleanStd.CleaningLevel2: 2.5
730//
731// If this cannot be found the next step is to search for
732// MImgCleanStd.CleaningLevel1: 3.0
733// And if this doesn't exist, too, we should search for:
734// CleaningLevel1: 3.0
735//
736// Warning: The programmer is responsible for the names to be unique in
737// all Mars classes.
738//
739Bool_t MEvtLoop::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
740{
741 if (!prefix.IsNull())
742 *fLog << warn << "WARNING - Second argument in MEvtLoop::WriteEnv has no meaning... ignored." << endl;
743
744 prefix = fName;
745 prefix += ".";
746
747 *fLog << inf << "Writing resources: " << prefix /*TEnv::fRcName << " to " << env.GetRcName()*/ << endl;
748
749 if (fParList->WriteEnv(env, prefix, print)!=kTRUE)
750 {
751 *fLog << err << "ERROR - Writing Environment file." << endl;
752 return kFALSE;
753 }
754
755 return kTRUE;
756}
Note: See TracBrowser for help on using the repository browser.