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

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