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

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