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

Last change on this file since 1861 was 1850, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 21.1 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() : fParList(NULL), fProgress(NULL)
106{
107 fName = "Evtloop";
108}
109
110// --------------------------------------------------------------------------
111//
112// default destructor - emty
113//
114MEvtLoop::~MEvtLoop()
115{
116 if (TestBit(kIsOwner) && fParList)
117 delete fParList;
118}
119
120// --------------------------------------------------------------------------
121//
122// if you set the Eventloop as owner the destructor of the given parameter
123// list is calles by the destructor of MEvtLoop, otherwise not.
124//
125void MEvtLoop::SetOwner(Bool_t enable)
126{
127 enable ? SetBit(kIsOwner) : ResetBit(kIsOwner);
128}
129
130#ifdef __MARS__
131// --------------------------------------------------------------------------
132//
133// Specify an existing MProgressBar object. It will display the progress
134// graphically. This will make thing about 1-2% slower.
135//
136void MEvtLoop::SetProgressBar(MProgressBar *bar)
137{
138 fProgress = bar->GetBar();
139}
140#endif
141
142// --------------------------------------------------------------------------
143//
144// The proprocessing part of the eventloop. Be careful, this is
145// for developers or use in special jobs only!
146//
147Bool_t MEvtLoop::PreProcess(const char *tlist)
148{
149 //
150 // check if the needed parameter list is set.
151 //
152 if (!fParList)
153 {
154 *fLog << err << dbginf << "Parlist not initialized." << endl;
155 return kFALSE;
156 }
157
158 //
159 // check for the existance of the specified task list
160 // the default name is "MTaskList"
161 //
162 fTaskList = (MTaskList*)fParList->FindObject(tlist, "MTaskList");
163 if (!fTaskList)
164 {
165 *fLog << err << dbginf << "Cannot find tasklist '" << tlist << "' in parameter list." << endl;
166 return kFALSE;
167 }
168
169 if (fLog != &gLog)
170 fParList->SetLogStream(fLog);
171
172 //
173 // execute the preprocess of all tasks
174 // connect the different tasks with the right containers in
175 // the parameter list
176 //
177 if (!fTaskList->PreProcess(fParList))
178 {
179 *fLog << err << "Error detected while PreProcessing" << endl;
180 return kFALSE;
181 }
182
183 *fLog << endl;
184
185 return kTRUE;
186}
187
188// --------------------------------------------------------------------------
189//
190// The processing part of the eventloop. Be careful, this is
191// for developers or use in special jobs only!
192//
193Bool_t MEvtLoop::Process(Int_t maxcnt) const
194{
195 //
196 // loop over all events and process all tasks for
197 // each event
198 //
199 *fLog << all <<"Eventloop running (";
200
201 if (maxcnt<0)
202 *fLog << "all";
203 else
204 *fLog << dec << maxcnt;
205
206 *fLog << " events)..." << flush;
207
208 if (fProgress)
209 {
210 fProgress->Reset();
211
212 Int_t entries = INT_MAX;
213
214#ifdef __MARS__
215 // limits.h
216 MRead *read = (MRead*)fTaskList->FindObject("MRead");
217 if (read && read->GetEntries()>0)
218 entries = read->GetEntries();
219#endif
220
221 if (maxcnt>0)
222 fProgress->SetRange(0, TMath::Min(maxcnt, entries));
223 else
224 if (entries!=INT_MAX)
225 fProgress->SetRange(0, entries);
226 }
227
228 Int_t dummy = maxcnt<0 ? 0 : maxcnt;
229
230 //
231 // start a stopwatch
232 //
233 TStopwatch clock;
234 clock.Start();
235
236 //
237 // This is the MAIN EVENTLOOP which processes the data
238 // if maxcnt<0 the number of processed events is counted
239 // else only maxcnt events are processed
240 //
241 Int_t numcnts = 0;
242
243 Bool_t rc = kTRUE;
244 if (maxcnt<0)
245 // process first and increment if sucessfull
246 if (fProgress)
247 while ((rc=fTaskList->Process())==kTRUE)
248 {
249 fProgress->SetPosition(++dummy);
250#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
251 gSystem->ProcessEvents();
252#else
253 gClient->ProcessEventsFor(fProgress);
254#endif
255 numcnts++;
256 }
257 else
258 while ((rc=fTaskList->Process())==kTRUE) numcnts++;
259 else
260 // check for number and break if unsuccessfull
261 if (fProgress)
262 while (dummy-- && (rc=fTaskList->Process())==kTRUE)
263 {
264 fProgress->SetPosition(maxcnt - dummy);
265#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
266 gSystem->ProcessEvents();
267#else
268 gClient->ProcessEventsFor(fProgress);
269#endif
270 numcnts++;
271 }
272 else
273 while (dummy-- && (rc=fTaskList->Process())==kTRUE) numcnts++;
274
275 //
276 // stop stop-watch, print results
277 //
278 clock.Stop();
279
280 *fLog << all << "Ready!" << endl << endl;
281
282 *fLog << dec << endl << "CPU - "
283 << "Time: " << clock.CpuTime() << "s"
284 << " for " << numcnts << " Events"
285 << " --> " << numcnts/clock.CpuTime() << " Events/s"
286 << endl;
287 *fLog << "Real - "
288 << "Time: " << clock.RealTime() << "s"
289 << " for " << numcnts << " Events"
290 << " --> " << numcnts/clock.RealTime() << " Events/s"
291 << endl << endl;
292
293 return rc!=kERROR;
294}
295
296// --------------------------------------------------------------------------
297//
298// The postprocessing part of the eventloop. Be careful, this is
299// for developers or use in special jobs only!
300//
301Bool_t MEvtLoop::PostProcess() const
302{
303 //
304 // execute the post process of all tasks
305 //
306 return fTaskList->PostProcess();
307}
308
309// --------------------------------------------------------------------------
310//
311// See class description above.
312//
313Bool_t MEvtLoop::Eventloop(Int_t maxcnt, const char *tlist)
314{
315 Bool_t rc = PreProcess();
316
317 //
318 // If all Tasks were PreProcesses successfully start Processing.
319 //
320 if (rc)
321 rc = Process(maxcnt);
322
323 //
324 // Now postprocess all tasks. Only successfully preprocessed tasks are
325 // postprocessed. If the Postprocessing of one task fail return an error.
326 //
327 if (!PostProcess())
328 return kFALSE;
329
330 //
331 // If postprocessing of all preprocessed tasks was sucefully return rc.
332 // This gives an error in case the preprocessing has failed already.
333 // Otherwise the eventloop is considered: successfully.
334 //
335 return rc;
336}
337
338// --------------------------------------------------------------------------
339//
340// After you setup (or read) an Evtloop you can use this to write the
341// eventloop setup as a macro. The default name is "evtloop.C". The default
342// extension is .C If the extension is not given, .C is added.
343// I the last character in the argument is a '+' the file is not closed.
344// This is usefull if you have an eventloop which runs three times and
345// you want to write one macro. If the first character is a '+' no
346// opening is written, eg:
347//
348// MEvtLoop evtloop;
349// // some setup
350// evtloop.MakeMacro("mymacro+");
351// // replace the tasklist the first time
352// evtloop.MakeMacro("+mymacro+");
353// // replace the tasklist the second time
354// evtloop.MakeMacro("+mymacro");
355//
356void MEvtLoop::MakeMacro(const char *filename)
357{
358 TString name(filename);
359
360 name = name.Strip(TString::kBoth);
361
362 Bool_t open = kTRUE;
363 Bool_t close = kTRUE;
364 if (name[0]=='+')
365 {
366 open = kFALSE;
367 name.Remove(0, 1);
368 name = name.Strip(TString::kBoth);
369 }
370
371 if (name[name.Length()-1]=='+')
372 {
373 close = kFALSE;
374 name.Remove(name.Length()-1, 1);
375 name = name.Strip(TString::kBoth);
376 }
377
378 if (!name.EndsWith(".C"))
379 name += ".C";
380
381 ofstream fout;
382
383 if (!open)
384 {
385 fout.open(name, ios::app);
386 fout << endl;
387 fout << " // ----------------------------------------------------------------------" << endl;
388 fout << endl;
389 }
390 else
391 {
392 fout.open(name);
393
394 time_t t = time(NULL);
395 fout <<
396 "/* ======================================================================== *\\" << endl <<
397 "!" << endl <<
398 "! *" << endl <<
399 "! * This file is part of MARS, the MAGIC Analysis and Reconstruction" << endl <<
400 "! * Software. It is distributed to you in the hope that it can be a useful" << endl <<
401 "! * and timesaving tool in analysing Data of imaging Cerenkov telescopes." << endl <<
402 "! * It is distributed WITHOUT ANY WARRANTY." << endl <<
403 "! *" << endl <<
404 "! * Permission to use, copy, modify and distribute this software and its" << endl <<
405 "! * documentation for any purpose is hereby granted without fee," << endl <<
406 "! * provided that the above copyright notice appear in all copies and" << endl <<
407 "! * that both that copyright notice and this permission notice appear" << endl <<
408 "! * in supporting documentation. It is provided \"as is\" without express" << endl <<
409 "! * or implied warranty." << endl <<
410 "! *" << endl <<
411 "!" << endl <<
412 "!" << endl <<
413 "! Author(s): Thomas Bretz et al. <mailto:tbretz@astro.uni-wuerzburg.de>" << endl <<
414 "!" << endl <<
415 "! Copyright: MAGIC Software Development, 2000-2002" << endl <<
416 "!" << endl <<
417 "!" << endl <<
418 "\\* ======================================================================== */" << endl << endl <<
419 "// ------------------------------------------------------------------------" << endl <<
420 "//" << endl <<
421 "// This macro was automatically created on" << endl<<
422 "// " << ctime(&t) <<
423 "// with the MEvtLoop::MakeMacro tool." << endl <<
424 "//" << endl <<
425 "// ------------------------------------------------------------------------" << endl << endl <<
426 "void " << name(0, name.Length()-2) << "()" << endl <<
427 "{" << endl;
428 }
429
430 SavePrimitive(fout, (TString)"" + (open?"open":"") + (close?"close":""));
431
432 if (!close)
433 return;
434
435 fout << "}" << endl;
436
437 *fLog << inf << "Macro '" << name << "' written." << endl;
438}
439
440// --------------------------------------------------------------------------
441//
442// Implementation of SavePrimitive. Used to write the call to a constructor
443// to a macro. In the original root implementation it is used to write
444// gui elements to a macro-file.
445//
446
447void MEvtLoop::StreamPrimitive(ofstream &out) const
448{
449 out << " MEvtLoop " << GetUniqueName() << ";" << endl;
450}
451
452void MEvtLoop::SavePrimitive(ofstream &out, Option_t *opt)
453{
454 TString options = opt;
455 options.ToLower();
456
457 if (HasDuplicateNames("MEvtLoop::SavePrimitive"))
458 {
459 out << " // !" << endl;
460 out << " // ! WARNING - Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
461 out << " // ! one object (MParContainer, MTask, ...) with the same name. The created macro" << endl;
462 out << " // ! may need manual intervention before it can be used." << endl;
463 out << " // !" << endl;
464 out << endl;
465 }
466
467 if (!options.Contains("open"))
468 {
469 if (gListOfPrimitives)
470 {
471 *fLog << err << "MEvtLoop::SavePrimitive - Error: old file not closed." << endl;
472 gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15));
473 delete gListOfPrimitives;
474 }
475 gListOfPrimitives = new TList;
476 }
477
478 if (fParList)
479 fParList->SavePrimitive(out);
480
481 MParContainer::SavePrimitive(out);
482
483 if (fParList)
484 out << " " << GetUniqueName() << ".SetParList(&" << fParList->GetUniqueName() << ");" << endl;
485 else
486 out << " // fParList empty..." << endl;
487 out << " if (!" << GetUniqueName() << ".Eventloop())" << endl;
488 out << " return;" << endl;
489
490 if (!options.Contains("close"))
491 return;
492
493 gListOfPrimitives->ForEach(TObject, ResetBit)(BIT(15));
494 delete gListOfPrimitives;
495 gListOfPrimitives = 0;
496}
497
498// --------------------------------------------------------------------------
499//
500// Get a list of all conmtainer names which are somehow part of the
501// eventloop. Chack for duplicate members and print a warning if
502// duplicates are found. Return kTRUE if duplicates are found, otherwise
503// kFALSE;
504//
505Bool_t MEvtLoop::HasDuplicateNames(TObjArray &arr, const TString txt) const
506{
507 arr.Sort();
508
509 TIter Next(&arr);
510 TObject *obj;
511 TString name;
512 Bool_t found = kFALSE;
513 while ((obj=Next()))
514 {
515 if (name==obj->GetName())
516 {
517 if (!found)
518 {
519 *fLog << warn << endl;
520 *fLog << " ! WARNING (" << txt << ")" << endl;
521 *fLog << " ! Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
522 *fLog << " ! one object (MParContainer, MTask, ...) with the same name." << endl;
523 *fLog << " ! Creating a macro from it using MEvtLoop::MakeMacro may create" << endl;
524 *fLog << " ! a macro which needs manual intervention before it can be used." << endl;
525 found = kTRUE;
526 }
527 *fLog << " ! Please rename: " << obj->GetName() << endl;
528 }
529 name = obj->GetName();
530 }
531
532 return found;
533}
534
535// --------------------------------------------------------------------------
536//
537// Get a list of all conmtainer names which are somehow part of the
538// eventloop. Chack for duplicate members and print a warning if
539// duplicates are found. Return kTRUE if duplicates are found, otherwise
540// kFALSE;
541//
542Bool_t MEvtLoop::HasDuplicateNames(const TString txt) const
543{
544 if (!fParList)
545 return kFALSE;
546
547 TObjArray list;
548 list.SetOwner();
549
550 fParList->GetNames(list);
551
552 return HasDuplicateNames(list, txt);
553}
554
555// --------------------------------------------------------------------------
556//
557// Reads a saved eventloop from a file. The default name is "Evtloop".
558// Therefor an open file must exist (See TFile for more information)
559//
560// eg:
561// TFile file("myfile.root", "READ");
562// MEvtLoop evtloop;
563// evtloop.Read();
564// evtloop.MakeMacro("mymacro");
565//
566Int_t MEvtLoop::Read(const char *name)
567{
568 if (!gFile)
569 {
570 *fLog << err << "MEvtloop::Read: No file found. Please create a TFile first." << endl;
571 return 0;
572 }
573
574 if (!gFile->IsOpen())
575 {
576 *fLog << err << "MEvtloop::Read: File not open. Please open the TFile first." << endl;
577 return 0;
578 }
579
580 Int_t n = 0;
581 TObjArray list;
582
583 n += TObject::Read(name);
584
585 if (n==0)
586 {
587 *fLog << err << "MEvtloop::Read: No objects read." << endl;
588 return 0;
589 }
590
591 n += list.Read((TString)name+"_names");
592
593 fParList->SetNames(list);
594
595 HasDuplicateNames(list, "MEvtLoop::Read");
596
597 *fLog << inf << "Eventloop '" << name << "' read from file." << endl;
598
599 return n;
600}
601
602// --------------------------------------------------------------------------
603//
604// If available print the contents of the parameter list.
605//
606void MEvtLoop::Print(Option_t *opt) const
607{
608 if (fParList)
609 fParList->Print();
610 else
611 *fLog << all << "MEvtloop: No Parameter List available." << endl;
612}
613
614// --------------------------------------------------------------------------
615//
616// Writes a eventloop to a file. The default name is "Evtloop".
617// Therefor an open file must exist (See TFile for more information)
618//
619// eg:
620// TFile file("myfile.root", "RECREATE");
621// MEvtLoop evtloop;
622// evtloop.Write();
623// file.Close();
624//
625Int_t MEvtLoop::Write(const char *name, Int_t option, Int_t bufsize)
626{
627 if (!gFile)
628 {
629 *fLog << err << "MEvtloop::Write: No file found. Please create a TFile first." << endl;
630 return 0;
631 }
632
633 if (!gFile->IsOpen())
634 {
635 *fLog << err << "MEvtloop::Write: File not open. Please open the TFile first." << endl;
636 return 0;
637 }
638
639 if (!gFile->IsWritable())
640 {
641 *fLog << err << "MEvtloop::Write: File not writable." << endl;
642 return 0;
643 }
644
645 Int_t n = 0;
646
647 TObjArray list;
648 list.SetOwner();
649
650 fParList->GetNames(list);
651
652 n += TObject::Write(name, option, bufsize);
653
654 if (n==0)
655 {
656 *fLog << err << "MEvtloop::Read: No objects written." << endl;
657 return 0;
658 }
659
660 n += list.Write((TString)name+"_names", kSingleKey);
661
662 HasDuplicateNames(list, "MEvtLoop::Write");
663
664 *fLog << inf << "Eventloop written to file as " << name << "." << endl;
665
666 return n;
667}
Note: See TracBrowser for help on using the repository browser.