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

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