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

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