source: trunk/Mars/mbase/MEvtLoop.cc@ 9853

Last change on this file since 9853 was 9497, checked in by tbretz, 15 years ago
*** empty log message ***
File size: 33.5 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@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2003
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 function of the tasks are
41// executed as long as one function returns kSTOP. Only the tasks which
42// are marked as "All" or with a string which matches the MInputStreamID
43// of 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// If you want to display the progress in a gui you can use SetProgressBar
49// and a TGProgressBar or a MProgressBar. If you set a MStatusDisplay
50// using SetDisplay, the Progress bar from this display is used.
51//
52// You can create a macro from a completely setup eventloop by:
53// evtloop.MakeMacro("mymacro.C");
54//
55// You will always need to check the macro, it will not run, but it
56// should have al important information.
57//
58//
59// You can also write all this information to a root file:
60// TFile file("myfile.root");
61// evtloop.Write("MyEvtloopKey");
62//
63// You can afterwards read the information from an open file by:
64// evtloop.Read("MyEvtloopKey");
65//
66// To lookup the information write it to a file using MakeMacro
67//
68//////////////////////////////////////////////////////////////////////////////
69#include "MEvtLoop.h"
70
71#include <time.h> // time_t
72#include <fstream> // ofstream, SavePrimitive
73
74#include <TEnv.h> // TEnv
75#include <TRint.h> // gApplication, TRint::Class()
76#include <TTime.h> // TTime
77#include <TFile.h> // gFile
78#include <TThread.h> // TThread::Self()
79#include <TDatime.h> // TDatime
80#include <TSystem.h> // gSystem
81#include <TStopwatch.h>
82#include <TGProgressBar.h>
83
84#include "MLog.h"
85#include "MLogManip.h"
86
87#include "MString.h"
88#include "MParList.h"
89#include "MTaskList.h"
90#ifdef __MARS__
91#include "MRead.h" // for setting progress bar
92#include "MProgressBar.h" // MProgressBar::GetBar
93#include "MStatusDisplay.h" // MStatusDisplay::GetBar
94#endif
95
96ClassImp(MEvtLoop);
97
98using namespace std;
99
100// --------------------------------------------------------------------------
101//
102// default constructor
103//
104MEvtLoop::MEvtLoop(const char *name) : fParList(NULL), fTaskList(NULL), fProgress(NULL)
105{
106 fName = name;
107
108 gROOT->GetListOfCleanups()->Add(this); // To remove fDisplay
109 SetBit(kMustCleanup);
110
111 *fLog << inf << endl << underline << "Instantiated MEvtLoop (" << name << "), using ROOT v" << ROOT_RELEASE << endl;
112}
113
114// --------------------------------------------------------------------------
115//
116// destructor
117//
118MEvtLoop::~MEvtLoop()
119{
120 if (TestBit(kIsOwner) && fParList)
121 delete fParList;
122}
123
124void MEvtLoop::SetParList(MParList *p)
125{
126 if (!p)
127 return;
128
129 p->SetBit(kMustCleanup);
130 fParList = p;
131}
132
133// --------------------------------------------------------------------------
134//
135// If the evntloop knows its tasklist search for the task there,
136// otherwise return NULL.
137//
138MTask *MEvtLoop::FindTask(const char *name) const
139{
140 return fTaskList ? fTaskList->FindTask(name) : NULL;
141}
142
143// --------------------------------------------------------------------------
144//
145// If the evntloop knows its tasklist search for the task there,
146// otherwise return NULL.
147//
148MTask *MEvtLoop::FindTask(const MTask *obj) const
149{
150 return fTaskList ? fTaskList->FindTask(obj) : NULL;
151}
152
153// --------------------------------------------------------------------------
154//
155// if you set the Eventloop as owner the destructor of the given parameter
156// list is calles by the destructor of MEvtLoop, otherwise not.
157//
158void MEvtLoop::SetOwner(Bool_t enable)
159{
160 enable ? SetBit(kIsOwner) : ResetBit(kIsOwner);
161}
162
163void MEvtLoop::SetProgressBar(TGProgressBar *bar)
164{
165 fProgress = bar;
166 if (fProgress)
167 fProgress->SetBit(kMustCleanup);
168}
169
170#ifdef __MARS__
171// --------------------------------------------------------------------------
172//
173// Specify an existing MProgressBar object. It will display the progress
174// graphically. This will make thing about 1-2% slower.
175//
176void MEvtLoop::SetProgressBar(MProgressBar *bar)
177{
178 SetProgressBar(bar->GetBar());
179}
180#endif
181
182void MEvtLoop::SetDisplay(MStatusDisplay *d)
183{
184 MParContainer::SetDisplay(d);
185 if (!d)
186 fProgress=NULL;
187 else
188 {
189 d->SetBit(kMustCleanup);
190
191 // Get pointer to update Progress bar
192 fProgress = fDisplay->GetBar();
193 }
194
195 if (fParList)
196 fParList->SetDisplay(d);
197}
198
199// --------------------------------------------------------------------------
200//
201// The proprocessing part of the eventloop. Be careful, this is
202// for developers or use in special jobs only!
203//
204Bool_t MEvtLoop::PreProcess()
205{
206 fTaskList = NULL;
207
208 //
209 // check if the needed parameter list is set.
210 //
211 if (!fParList)
212 {
213 *fLog << err << dbginf << "Parlist not initialized." << endl;
214 return kFALSE;
215 }
216
217 //
218 // check for the existance of the specified task list
219 // the default name is "MTaskList"
220 //
221 fTaskList = (MTaskList*)fParList->FindObject("MTaskList");
222 if (!fTaskList)
223 {
224 *fLog << err << dbginf << "Cannot find MTaskList in parameter list." << endl;
225 return kFALSE;
226 }
227
228 if (fLog != &gLog)
229 fParList->SetLogStream(fLog);
230
231#ifdef __MARS__
232 //
233 // Check whether display is still existing
234 //
235 if (fDisplay)
236 {
237 // Lock display to prevent user from deleting it
238 fDisplay->Lock();
239 // Don't display context menus
240 fDisplay->SetNoContextMenu();
241 // Set window and icon name
242 fDisplay->SetWindowName(fName);
243 fDisplay->SetIconName(fName);
244 // Start automatic update
245 fDisplay->StartUpdate();
246 // Cascade display through childs
247 if (!TestBit(kPrivateDisplay))
248 fParList->SetDisplay(fDisplay);
249 }
250#endif
251
252 if (fProgress)
253 fProgress->SetPosition(0);
254
255 //
256 // execute the preprocess of all tasks
257 // connect the different tasks with the right containers in
258 // the parameter list
259 //
260 if (!fTaskList->PreProcess(fParList))
261 {
262 *fLog << err << "Error detected while PreProcessing." << endl;
263 return kFALSE;
264 }
265
266 *fLog << endl;
267
268 return kTRUE;
269}
270
271// --------------------------------------------------------------------------
272//
273// Return the memory currently used by this process (VmSize)
274// which contains shared memory, data memory and private memory.
275//
276UInt_t MEvtLoop::GetMemoryUsage()
277{
278 const TString path = MString::Format("/proc/%d/status", gSystem->GetPid());
279 if (gSystem->AccessPathName(path, kFileExists))
280 return 0;
281
282 return TEnv(path).GetValue("VmSize", 0);
283}
284
285Bool_t MEvtLoop::ProcessGuiEvents(Int_t num)
286{
287 if (gROOT->IsBatch())
288 return kTRUE;
289
290 //
291 // Check status of display
292 //
293 Bool_t rc = kTRUE;
294
295 if (fDisplay)
296 switch (fDisplay->CheckStatus())
297 {
298 case MStatusDisplay::kLoopPause:
299 fDisplay->SetStatusLine1(MString::Format("Paused after %d", num-1));
300 while (fDisplay && fDisplay->CheckStatus()==MStatusDisplay::kLoopPause)
301 {
302 gSystem->ProcessEvents();
303 gSystem->Sleep(1);
304 }
305 // FALLTHROUGH
306 case MStatusDisplay::kLoopStep:
307 if (fDisplay && fDisplay->CheckStatus()==MStatusDisplay::kLoopStep)
308 fDisplay->SetPause();
309 // FALLTHROUGH
310 case MStatusDisplay::kLoopNone:
311 break;
312 case MStatusDisplay::kLoopStop:
313 rc = kFALSE;
314 fDisplay->ClearStatus();
315 break;
316 //
317 // If the display is not on the heap (means: not created
318 // with the new operator) the object is deleted somewhere
319 // else in the code. It is the responsibility of the
320 // application which instantiated the object to make
321 // sure that the correct action is taken. This can be
322 // done by calling MStatusDisplay::CheckStatus()
323 //
324 // Because we are synchronous we can safely delete it here!
325 //
326 // Close means: Close the display but leave analysis running
327 // Exit means: Close the display and stop analysis
328 //
329 case MStatusDisplay::kFileClose:
330 case MStatusDisplay::kFileExit:
331 rc = fDisplay->CheckStatus() == MStatusDisplay::kFileClose;
332
333 if (fDisplay->IsOnHeap())
334 delete fDisplay;
335
336 //
337 // This makes the display really disappear physically on
338 // the screen in case of MStatusDisplay::kFileClose
339 //
340 gSystem->ProcessEvents();
341
342 return rc;
343 default:
344 *fLog << warn << "MEvtloop: fDisplay->CheckStatus() has returned unknown status #" << fDisplay->CheckStatus() << "... cleared." << endl;
345 fDisplay->ClearStatus();
346 break;
347 }
348
349 //
350 // Check System time (don't loose too much time by updating the GUI)
351 //
352
353 // FIXME: Not thread safe (if you have more than one eventloop running)
354 static Int_t start = num;
355 static TTime t1 = gSystem->Now();
356 static TTime t2 = t1;
357
358 //
359 // No update < 20ms
360 //
361 const TTime t0 = gSystem->Now();
362 if (t0-t1 < (TTime)20)
363 return rc;
364 t1 = t0;
365
366 //
367 // Update current speed each 1.5 second
368 //
369 if (fDisplay && t0-t2>(TTime)1500)
370 {
371 const Float_t speed = 1000.*(num-start)/(long int)(t0-t2);
372 TString txt = "Processing...";
373 if (speed>0)
374 {
375 txt += " (";
376 txt += (Int_t)speed;
377 txt += "Evts/s";
378 if (fNumEvents>0 && (Int_t)fNumEvents-num>0)
379 {
380 txt += ", est: ";
381 txt += (int)((fNumEvents-num)/speed/60)+1;
382 txt += "min";
383 }
384 //txt += (int)fmod(entries/(1000.*(num-start)/(long int)(t0-t2)), 60);
385 //txt += "s";
386 txt += ")";
387 }
388 fDisplay->SetStatusLine1(txt);
389 start = num;
390 t2 = t0;
391 }
392
393 //
394 // Set new progress bar position
395 //
396 if (fNumEvents>0 && fProgress)
397 {
398 const Double_t pos = (Double_t)num/fNumEvents;
399 fProgress->SetPosition(pos);
400// if (gROOT->IsBatch())
401// *fLog << all << MString::Format("%.1f", pos) << "%..." << flush;
402 }
403
404 // FIXME: This is a workaround, because TApplication::Run is not
405 // thread safe against ProcessEvents. We assume, that if
406 // we are not in the Main-Thread ProcessEvents() is
407 // called by the TApplication Event Loop...
408 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
409 {
410 //
411 // Handle GUI events (display changes)
412 //
413#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
414 gSystem->ProcessEvents();
415#else
416 if (fDisplay)
417 gSystem->ProcessEvents();
418 else
419 if (fProgress)
420 gClient->ProcessEventsFor(fProgress);
421#endif
422 }
423
424 return rc;
425}
426
427// --------------------------------------------------------------------------
428//
429// The processing part of the eventloop. Be careful, this is
430// for developers or use in special jobs only!
431//
432Int_t MEvtLoop::Process(UInt_t maxcnt)
433{
434 if (!fTaskList)
435 return kFALSE;
436
437 const UInt_t mem0 = GetMemoryUsage();
438
439 //
440 // loop over all events and process all tasks for
441 // each event
442 //
443 *fLog << all <<"Eventloop running (";
444
445 if (maxcnt==0)
446 *fLog << "all";
447 else
448 *fLog << dec << maxcnt;
449
450 *fLog << " events)..." << flush;
451
452 UInt_t entries = kMaxUInt;
453 fNumEvents = 0;
454
455 if (fProgress && !gROOT->IsBatch())
456 {
457 fProgress->Reset();
458 fProgress->SetRange(0, 1);
459
460#ifdef __MARS__
461 MRead *read = (MRead*)fTaskList->FindObject("MRead");
462 if (read && read->GetEntries()>0)
463 entries = read->GetEntries();
464#endif
465
466 if (maxcnt>0)
467 fNumEvents = TMath::Min(maxcnt, entries);
468 else
469 if (entries!=kMaxUInt)
470 fNumEvents = entries;
471 }
472
473 if (fDisplay)
474 {
475 fDisplay->SetStatusLine1("Processing...");
476 fDisplay->SetStatusLine2("");
477 }
478
479 //
480 // start a stopwatch
481 //
482 TStopwatch clock;
483 clock.Start();
484
485 //
486 // This is the MAIN EVENTLOOP which processes the data
487 // if maxcnt==0 the number of processed events is counted
488 // else only maxcnt events are processed
489 //
490 UInt_t numcnts = 0;
491 UInt_t dummy = maxcnt;
492
493 Int_t rc=kTRUE;
494 if (maxcnt==0)
495 // process first and increment if sucessfull
496 while (1)
497 {
498 rc=fTaskList->CallProcess();
499 if (rc!=kTRUE && rc!=kCONTINUE)
500 break;
501
502 numcnts++;
503 if (!ProcessGuiEvents(++dummy))
504 break;
505 }
506 else
507 // check for number and break if unsuccessfull
508 while (dummy--)
509 {
510 rc=fTaskList->CallProcess();
511 if (rc!=kTRUE && rc!=kCONTINUE)
512 break;
513
514 numcnts++;
515 if (!ProcessGuiEvents(maxcnt - dummy))
516 break;
517 }
518
519 //
520 // stop stop-watch, print results
521 //
522 clock.Stop();
523
524 if (fProgress && !gROOT->IsBatch())
525 {
526 //fProgress->SetPosition(maxcnt>0 ? TMath::Min(maxcnt, entries) : entries);
527 fProgress->SetPosition(1);
528
529 // FIXME: This is a workaround, because TApplication::Run is not
530 // thread safe against ProcessEvents. We assume, that if
531 // we are not in the Main-Thread ProcessEvents() is
532 // called by the TApplication Event Loop...
533 if (!TThread::Self()/*gApplication->InheritsFrom(TRint::Class())*/)
534 {
535#if ROOT_VERSION_CODE < ROOT_VERSION(3,02,06)
536 gSystem->ProcessEvents();
537#else
538 gClient->ProcessEventsFor(fDisplay ? fDisplay->GetBar() : fProgress);
539#endif
540 }
541 }
542
543 *fLog << all << "Ready!" << endl << endl;
544
545 *fLog << dec << endl << "CPU - Time: ";
546 *fLog << clock.CpuTime() << "s" << " for " << numcnts << " Events";
547 if (numcnts>0)
548 *fLog << " --> " << numcnts/clock.CpuTime() << " Events/s";
549 *fLog << endl << "Real - Time: ";
550 *fLog << clock.RealTime() << "s" << " for " << numcnts << " Events";
551 if (numcnts>0)
552 *fLog << " --> " << numcnts/clock.RealTime() << " Events/s";
553
554
555 const UInt_t mem1 = GetMemoryUsage();
556 if (mem1>mem0)
557 *fLog << endl << "Mem - Loss: " << mem1-mem0 << "kB" << endl;
558
559 *fLog << endl << endl;
560
561 return rc!=kERROR;
562}
563
564// --------------------------------------------------------------------------
565//
566// The postprocessing part of the eventloop. Be careful, this is
567// for developers or use in special jobs only!
568//
569Bool_t MEvtLoop::PostProcess() const
570{
571 //
572 // execute the post process of all tasks
573 //
574 return fTaskList ? fTaskList->PostProcess() : kTRUE;
575}
576
577// --------------------------------------------------------------------------
578//
579// See class description above. Returns kTRUE if PreProcessing,
580// Processing and PostProcessing was successfull.
581// kFALSE is retuned if something was not successfull, eg:
582// PreProcess or PostProcess returned kFALSE
583// process returned kERRR
584//
585// maxcnt==0 means: all events
586// tlist is the name of the task-list to be used. Be carefull, this
587// feature is not finally implemented - it will only work if no
588// task will access the tasklist.
589//
590Bool_t MEvtLoop::Eventloop(UInt_t maxcnt, Statistics_t printstat)
591{
592 *fLog << inf << endl << underline << "Eventloop: " << fName << " started at " << TDatime().AsString() << endl;
593
594 Bool_t rc = PreProcess();
595
596 //
597 // If all Tasks were PreProcesses successfully start Processing.
598 //
599 if (rc)
600 rc = Process(maxcnt);
601
602 //
603 // Now postprocess all tasks. Only successfully preprocessed tasks
604 // are postprocessed. If the Postprocessing of one task fails
605 // return an error.
606 //
607 if (!PostProcess())
608 {
609 *fLog << err << "Error detected while PostProcessing." << endl;
610 rc = kFALSE;
611 }
612
613 //
614 // If Process has ever been called print statistics
615 //
616 if (fTaskList && fTaskList->GetNumExecutions()>0)
617 switch (printstat)
618 {
619 case kNoStatistics:
620 break;
621 case kStdStatistics:
622 fTaskList->PrintStatistics();
623 break;
624 case kFullStatistics:
625 fTaskList->PrintStatistics(0, kTRUE);
626 break;
627 }
628
629 if (!fDisplay)
630 return rc;
631
632 // Set status lines
633 fDisplay->SetStatusLine1(fName);
634 fDisplay->SetStatusLine2(rc ? "Done." : "Error!");
635 // Stop automatic update
636 fDisplay->StopUpdate();
637 // Reallow context menus
638 fDisplay->SetNoContextMenu(kFALSE);
639 // Reallow user to exit window by File menu
640 fDisplay->UnLock();
641
642 //
643 // If postprocessing of all preprocessed tasks was sucefully return rc.
644 // This gives an error in case the preprocessing has failed already.
645 // Otherwise the eventloop is considered: successfully.
646 //
647 return rc;
648}
649
650// --------------------------------------------------------------------------
651//
652// After you setup (or read) an Evtloop you can use MakeMacro() to write
653// the eventloop setup as a macro. The default name is "evtloop.C". The
654// default extension is .C If the extension is not given, .C is added.
655// If the last character in the argument is a '+' the file is not closed.
656// This is usefull if you have an eventloop which runs three times and
657// you want to write one macro. If the first character is a '+' no
658// opening is written, eg:
659//
660// MEvtLoop evtloop;
661// // some setup
662// evtloop.MakeMacro("mymacro+");
663// // replace the tasklist the first time
664// evtloop.MakeMacro("+mymacro+");
665// // replace the tasklist the second time
666// evtloop.MakeMacro("+mymacro");
667//
668void MEvtLoop::MakeMacro(const char *filename)
669{
670 TString name(filename);
671
672 name = name.Strip(TString::kBoth);
673
674 Bool_t open = kTRUE;
675 Bool_t close = kTRUE;
676 if (name[0]=='+')
677 {
678 open = kFALSE;
679 name.Remove(0, 1);
680 name = name.Strip(TString::kBoth);
681 }
682
683 if (name[name.Length()-1]=='+')
684 {
685 close = kFALSE;
686 name.Remove(name.Length()-1, 1);
687 name = name.Strip(TString::kBoth);
688 }
689
690 if (!name.EndsWith(".C"))
691 name += ".C";
692
693 ofstream fout;
694
695 if (!open)
696 {
697 fout.open(name, ios::app);
698 fout << endl;
699 fout << " // ----------------------------------------------------------------------" << endl;
700 fout << endl;
701 }
702 else
703 {
704 fout.open(name);
705
706 time_t t = time(NULL);
707 fout <<
708 "/* ======================================================================== *\\" << endl <<
709 "!" << endl <<
710 "! *" << endl <<
711 "! * This file is part of MARS, the MAGIC Analysis and Reconstruction" << endl <<
712 "! * Software. It is distributed to you in the hope that it can be a useful" << endl <<
713 "! * and timesaving tool in analysing Data of imaging Cerenkov telescopes." << endl <<
714 "! * It is distributed WITHOUT ANY WARRANTY." << endl <<
715 "! *" << endl <<
716 "! * Permission to use, copy, modify and distribute this software and its" << endl <<
717 "! * documentation for any purpose is hereby granted without fee," << endl <<
718 "! * provided that the above copyright notice appear in all copies and" << endl <<
719 "! * that both that copyright notice and this permission notice appear" << endl <<
720 "! * in supporting documentation. It is provided \"as is\" without express" << endl <<
721 "! * or implied warranty." << endl <<
722 "! *" << endl <<
723 "!" << endl <<
724 "!" << endl <<
725 "! Author(s): Thomas Bretz et al. <mailto:tbretz@astro.uni-wuerzburg.de>" << endl <<
726 "!" << endl <<
727 "! Copyright: MAGIC Software Development, 2000-2005" << endl <<
728 "!" << endl <<
729 "!" << endl <<
730 "\\* ======================================================================== */" << endl << endl <<
731 "// ------------------------------------------------------------------------" << endl <<
732 "//" << endl <<
733 "// This macro was automatically created on" << endl<<
734 "// " << ctime(&t) <<
735 "// with the MEvtLoop::MakeMacro tool." << endl <<
736 "//" << endl <<
737 "// ------------------------------------------------------------------------" << endl << endl <<
738 "void " << name(0, name.Length()-2) << "()" << endl <<
739 "{" << endl;
740 }
741
742 SavePrimitive(fout, (TString)"" + (open?"open":"") + (close?"close":""));
743
744 if (!close)
745 return;
746
747 fout << "}" << endl;
748
749 *fLog << inf << "Macro '" << name << "' written." << endl;
750}
751
752// --------------------------------------------------------------------------
753//
754// Implementation of SavePrimitive. Used to write the call to a constructor
755// to a macro. In the original root implementation it is used to write
756// gui elements to a macro-file.
757//
758void MEvtLoop::StreamPrimitive(ostream &out) const
759{
760 out << " MEvtLoop " << GetUniqueName();
761 if (fName!="Evtloop")
762 out << "(\"" << fName << "\")";
763 out << ";" << endl;
764}
765
766// --------------------------------------------------------------------------
767//
768//
769void MEvtLoop::SavePrimitive(ostream &out, Option_t *opt)
770{
771 TString options = opt;
772 options.ToLower();
773
774 if (HasDuplicateNames("MEvtLoop::SavePrimitive"))
775 {
776 out << " // !" << endl;
777 out << " // ! WARNING - Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
778 out << " // ! one object (MParContainer, MTask, ...) with the same name. The created macro" << endl;
779 out << " // ! may need manual intervention before it can be used." << endl;
780 out << " // !" << endl;
781 out << endl;
782 }
783
784 if (!options.Contains("open"))
785 {
786 if (gListOfPrimitives)
787 {
788 *fLog << err << "MEvtLoop::SavePrimitive - Error: old file not closed." << endl;
789 gListOfPrimitives->R__FOR_EACH(TObject, ResetBit)(BIT(15));
790 delete gListOfPrimitives;
791 }
792 gListOfPrimitives = new TList;
793 }
794
795 if (fParList)
796 fParList->SavePrimitive(out);
797
798 MParContainer::SavePrimitive(out);
799
800 if (fParList)
801 out << " " << GetUniqueName() << ".SetParList(&" << fParList->GetUniqueName() << ");" << endl;
802 else
803 out << " // fParList empty..." << endl;
804 out << " if (!" << GetUniqueName() << ".Eventloop())" << endl;
805 out << " return;" << endl;
806
807 if (!options.Contains("close"))
808 return;
809
810 gListOfPrimitives->R__FOR_EACH(TObject, ResetBit)(BIT(15));
811 delete gListOfPrimitives;
812 gListOfPrimitives = 0;
813}
814
815void MEvtLoop::SavePrimitive(ofstream &out, Option_t *o)
816{
817 SavePrimitive(static_cast<ostream&>(out), o);
818}
819
820// --------------------------------------------------------------------------
821//
822// Get a list of all conmtainer names which are somehow part of the
823// eventloop. Chack for duplicate members and print a warning if
824// duplicates are found. Return kTRUE if duplicates are found, otherwise
825// kFALSE;
826//
827Bool_t MEvtLoop::HasDuplicateNames(TObjArray &arr, const TString txt) const
828{
829 arr.Sort();
830
831 TIter Next(&arr);
832 TObject *obj;
833 TString name;
834 Bool_t found = kFALSE;
835 while ((obj=Next()))
836 {
837 if (name==obj->GetName())
838 {
839 if (!found)
840 {
841 *fLog << warn << endl;
842 *fLog << " ! WARNING (" << txt << ")" << endl;
843 *fLog << " ! Your eventloop (MParList, MTaskList, ...) contains more than" << endl;
844 *fLog << " ! one object (MParContainer, MTask, ...) with the same name." << endl;
845 *fLog << " ! Creating a macro from it using MEvtLoop::MakeMacro may create" << endl;
846 *fLog << " ! a macro which needs manual intervention before it can be used." << endl;
847 found = kTRUE;
848 }
849 *fLog << " ! Please rename: " << obj->GetName() << endl;
850 }
851 name = obj->GetName();
852 }
853
854 return found;
855}
856
857// --------------------------------------------------------------------------
858//
859// Get a list of all conmtainer names which are somehow part of the
860// eventloop. Chack for duplicate members and print a warning if
861// duplicates are found. Return kTRUE if duplicates are found, otherwise
862// kFALSE;
863//
864Bool_t MEvtLoop::HasDuplicateNames(const TString txt) const
865{
866 if (!fParList)
867 return kFALSE;
868
869 TObjArray list;
870 list.SetOwner();
871
872 fParList->GetNames(list);
873
874 return HasDuplicateNames(list, txt);
875}
876
877// --------------------------------------------------------------------------
878//
879// Reads a saved eventloop from a file. The default name is "Evtloop".
880// Therefor an open file must exist (See TFile for more information)
881//
882// eg:
883// TFile file("myfile.root", "READ");
884// MEvtLoop evtloop;
885// evtloop.Read();
886// evtloop.MakeMacro("mymacro");
887//
888Int_t MEvtLoop::Read(const char *name)
889{
890 if (!gFile)
891 {
892 *fLog << err << "MEvtloop::Read: No file found. Please create a TFile first." << endl;
893 return 0;
894 }
895
896 if (!gFile->IsOpen())
897 {
898 *fLog << err << "MEvtloop::Read: File not open. Please open the TFile first." << endl;
899 return 0;
900 }
901
902 Int_t n = 0;
903 TObjArray list;
904
905 n += TObject::Read(name);
906
907 if (n==0)
908 {
909 *fLog << err << "MEvtloop::Read: No objects read." << endl;
910 return 0;
911 }
912
913 n += list.Read((TString)name+"_names");
914
915 fParList->SetNames(list);
916
917 HasDuplicateNames(list, "MEvtLoop::Read");
918
919 *fLog << inf << "Eventloop '" << name << "' read from file." << endl;
920
921 return n;
922}
923
924// --------------------------------------------------------------------------
925//
926// If available print the contents of the parameter list.
927//
928void MEvtLoop::Print(Option_t *) const
929{
930 if (fParList)
931 fParList->Print();
932 else
933 *fLog << all << "MEvtloop: No Parameter List available." << endl;
934}
935
936// --------------------------------------------------------------------------
937//
938// Writes a eventloop to a file. The default name is "Evtloop".
939// Therefor an open file must exist (See TFile for more information)
940//
941// eg:
942// TFile file("myfile.root", "RECREATE");
943// MEvtLoop evtloop;
944// evtloop.Write();
945// file.Close();
946//
947Int_t MEvtLoop::Write(const char *name, Int_t option, Int_t bufsize) const
948{
949 if (!gFile)
950 {
951 *fLog << err << "MEvtloop::Write: No file found. Please create a TFile first." << endl;
952 return 0;
953 }
954
955 if (!gFile->IsOpen())
956 {
957 *fLog << err << "MEvtloop::Write: File not open. Please open the TFile first." << endl;
958 return 0;
959 }
960
961 if (!gFile->IsWritable())
962 {
963 *fLog << err << "MEvtloop::Write: File not writable." << endl;
964 return 0;
965 }
966
967 Int_t n = 0;
968
969 TObjArray list;
970 list.SetOwner();
971
972 fParList->GetNames(list);
973
974#if ROOT_VERSION_CODE < ROOT_VERSION(4,02,00)
975 n += const_cast<MEvtLoop*>(this)->TObject::Write(name, option, bufsize);
976#else
977 n += TObject::Write(name, option, bufsize);
978#endif
979
980 if (n==0)
981 {
982 *fLog << err << "MEvtloop::Read: No objects written." << endl;
983 return 0;
984 }
985
986 n += list.Write((TString)name+"_names", kSingleKey);
987
988 HasDuplicateNames(list, "MEvtLoop::Write");
989
990 *fLog << inf << "Eventloop written to file as " << name << "." << endl;
991
992 return n;
993}
994
995// --------------------------------------------------------------------------
996//
997// Read the contents/setup of a parameter container/task from a TEnv
998// instance (steering card/setup file).
999// The key to search for in the file should be of the syntax:
1000// prefix.vname
1001// While vname is a name which is specific for a single setup date
1002// (variable) of this container and prefix is something like:
1003// evtloopname.name
1004// While name is the name of the containers/tasks in the parlist/tasklist
1005//
1006// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
1007// Job4.MImgCleanStd.CleaningLevel2: 2.5
1008//
1009// If this cannot be found the next step is to search for
1010// MImgCleanStd.CleaningLevel1: 3.0
1011// And if this doesn't exist, too, we should search for:
1012// CleaningLevel1: 3.0
1013//
1014//
1015// With the argument prefix you can overwrite the name of the MEvtLoop object
1016// as prefix - use with extreme care! The prifix argument must not end with
1017// a dot!
1018//
1019//
1020// Warning: The programmer is responsible for the names to be unique in
1021// all Mars classes.
1022//
1023Int_t MEvtLoop::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1024{
1025// if (!prefix.IsNull())
1026// *fLog << warn << "WARNING - Second argument in MEvtLoop::ReadEnv has no meaning... ignored." << endl;
1027
1028 if (prefix.IsNull())
1029 prefix = fName;
1030 prefix += ".";
1031
1032 *fLog << inf << "Looking for resources with prefix " << prefix /*TEnv::fRcName << " from " << env.GetRcName()*/ << endl;
1033
1034 fLog->ReadEnv(env, prefix, print);
1035
1036 if (!fParList)
1037 {
1038 *fLog << warn << "WARNING - No parameter list to propagate resources to." << endl;
1039 return kTRUE;
1040 }
1041
1042 if (fParList->ReadEnv(env, prefix, print)==kERROR)
1043 {
1044 *fLog << err << "ERROR - Reading resource file." << endl;
1045 return kFALSE;
1046 }
1047
1048 return kTRUE;
1049}
1050
1051// --------------------------------------------------------------------------
1052//
1053// Calls 'ReadEnv' with a TEnv initialized with the given file name.
1054// If 'config=0' kTRUE is returned.
1055//
1056Bool_t MEvtLoop::ReadEnv(const char *config, Bool_t print)
1057{
1058 if (!config)
1059 return kTRUE;
1060
1061 const Bool_t fileexist = !gSystem->AccessPathName(config, kFileExists);
1062 if (!fileexist)
1063 {
1064 *fLog << warn << "WARNING - resource file '" << config << "' not found... no resources applied." << endl;
1065 return kFALSE;
1066 }
1067
1068 const TEnv env(config);
1069 return ReadEnv(env, "", print);
1070}
1071
1072// --------------------------------------------------------------------------
1073//
1074// Write the contents/setup of a parameter container/task to a TEnv
1075// instance (steering card/setup file).
1076// The key to search for in the file should be of the syntax:
1077// prefix.vname
1078// While vname is a name which is specific for a single setup date
1079// (variable) of this container and prefix is something like:
1080// evtloopname.name
1081// While name is the name of the containers/tasks in the parlist/tasklist
1082//
1083// eg. Job4.MImgCleanStd.CleaningLevel1: 3.0
1084// Job4.MImgCleanStd.CleaningLevel2: 2.5
1085//
1086// If this cannot be found the next step is to search for
1087// MImgCleanStd.CleaningLevel1: 3.0
1088// And if this doesn't exist, too, we should search for:
1089// CleaningLevel1: 3.0
1090//
1091// Warning: The programmer is responsible for the names to be unique in
1092// all Mars classes.
1093//
1094Bool_t MEvtLoop::WriteEnv(TEnv &env, TString prefix, Bool_t print) const
1095{
1096 if (!prefix.IsNull())
1097 *fLog << warn << "WARNING - Second argument in MEvtLoop::WriteEnv has no meaning... ignored." << endl;
1098
1099 prefix = fName;
1100 prefix += ".";
1101
1102 *fLog << inf << "Writing resources with prefix " << prefix /*TEnv::fRcName << " to " << env.GetRcName()*/ << endl;
1103
1104 fLog->WriteEnv(env, prefix, print);
1105
1106 if (!fParList)
1107 {
1108 *fLog << warn << "WARNING - No parameter list to get resources from." << endl;
1109 return kTRUE;
1110 }
1111
1112
1113 if (fParList->WriteEnv(env, prefix, print)!=kTRUE)
1114 {
1115 *fLog << err << "ERROR - Writing resource file." << endl;
1116 return kFALSE;
1117 }
1118
1119 return kTRUE;
1120}
1121
1122void MEvtLoop::RecursiveRemove(TObject *obj)
1123{
1124 // If the tasklist was deleted... remove it
1125 if (obj==fTaskList)
1126 fTaskList = NULL;
1127
1128 // If the parlist was deleted...invalidate par- and tasklist
1129 if (obj==fParList)
1130 {
1131 fParList=NULL;
1132 fTaskList=NULL;
1133 }
1134
1135 // if the progress bar was deleted...remove it
1136 if (obj==fProgress)
1137 fProgress = NULL;
1138
1139 // If it was something else check par- and tasklist
1140 if (fParList)
1141 fParList->RecursiveRemove(obj);
1142 else
1143 if (fTaskList) // Note that the tasklist is included in the parlist
1144 fTaskList->RecursiveRemove(obj);
1145
1146 // Now check for fDisplay and fLog
1147 MParContainer::RecursiveRemove(obj);
1148}
Note: See TracBrowser for help on using the repository browser.