source: trunk/Mars/mfileio/MReadReports.cc @ 10130

Last change on this file since 10130 was 10130, checked in by tbretz, 9 years ago
Fixed a bug in MreadReports which caused the reading to get corrupted as soon as the first event tree was fully read.
File size: 13.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, 11/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20!   Copyright: MAGIC Software Development, 2000-2006
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MReadReports
28//
29// Read from a file events from different trees ordered in time, eg:
30//
31// Having a file with:
32//
33//      Tree1         Tree2         Tree3
34//      ------------  ------------  -----------
35//      (0) MTime[0]
36//                    (0) MTime[1]
37//      (1) MTime[2]
38//      (2) MTime[3]
39//                                  (0) MTime[1]
40//      (3) MTime[4]
41//
42// MReadReports will read the events in the tree in the following order:
43//   <0> (0) from Tree1
44//   <1> (0) from Tree2
45//   <2> (1) from Tree1
46//   <3> (2) from Tree1
47//   <4> (0) from Tree3
48//   <5> (3) from Tree1
49//   ...
50//
51// To tell MReadReports which Trees to read use: MReadReports::AddTree()
52// To schedule a file for reading use MReadReports::AddFile()
53//
54// All calls to AddTree _must_ be before the calls to AddFile!
55//
56// After reading from a tree with the name 'TreeName' the stream id of
57// the main tasklist ('MTaskList' found in MParList in PreProcess) is
58// set to this name. This means that only tasks having this stream id
59// are executed.
60//
61/////////////////////////////////////////////////////////////////////////////
62#include "MReadReports.h"
63
64#include <TChain.h>
65#include <TChainElement.h>
66
67#include "MLog.h"
68#include "MLogManip.h"
69
70#include "MTime.h"
71#include "MParList.h"
72#include "MTaskList.h"
73
74#include "MReadMarsFile.h"
75
76ClassImp(MReadReports);
77
78using namespace std;
79
80// --------------------------------------------------------------------------
81//
82// Default constructor. Set fName and fTitle. Instatiate fTrees and fChains.
83// Call SetOwner for fTrees and fChains
84//
85MReadReports::MReadReports() : fEnableAutoScheme(kFALSE)
86{
87    fName  = "MRead";
88    fTitle = "Reads events and reports from a root file ordered in time";
89
90    fTrees  = new MTaskList("MReadReports");
91    fChains = new TList;
92
93    fTrees->SetOwner();
94    fChains->SetOwner();
95}
96
97// --------------------------------------------------------------------------
98//
99// Destructor, delete everything which was allocated by this task...
100//
101MReadReports::~MReadReports()
102{
103    TObject *o=0;
104    TIter NextC(fChains);
105    while ((o=NextC()))
106        delete *GetTime((TChain*)o);
107
108    delete fTrees;
109    delete fChains;
110}
111
112// --------------------------------------------------------------------------
113//
114// Return the number of entries in all trees.
115//
116UInt_t MReadReports::GetEntries()
117{
118    UInt_t n=0;
119
120    TIter NextT(fTrees->GetList());
121    MReadTree *tree=0;
122    while ((tree=(MReadTree*)NextT()))
123        n += tree->GetEntries();
124
125    return n;
126}
127
128// --------------------------------------------------------------------------
129//
130// In case of a Master Tree GetFileName() of the MReadMarsFile is returned.
131// If no master is available "<MReadReports>" is returned.
132//
133TString MReadReports::GetFullFileName() const
134{
135    if (!TestBit(kHasMaster))
136        return "<MReadReports>";
137
138    TIter NextT(fTrees->GetList());
139    MReadTree *tree=0;
140    while ((tree=(MReadTree*)NextT()))
141        if (tree->InheritsFrom("MReadMarsFile"))
142            return tree->GetFileName();
143
144    return "<n/a>";
145
146}
147
148void MReadReports::AddToBranchList(const char *name)
149{
150    MTask::AddToBranchList(name);
151}
152
153// --------------------------------------------------------------------------
154//
155// Schedule the contents of this tree for reading. As a default the time
156// branch which is used for the ordering is assumed to by "MTime"+tree.
157// If this is not the case you can overwrite the default specifying the
158// name in time.
159//
160// All calls to AddTree _must_ be BEFORE the calls to AddFile!
161//
162// To be done: A flag(?) telling whether the headers can be skipped.
163//
164void MReadReports::AddTree(const char *tree, const char *time, Type_t master)
165{
166    /*
167    if (fTrees->GetNumTasks()>0)
168    {
169        *fLog << warn << "WARNING - AddTree must be called before AddFile... ignored." << endl;
170        *fLog << dbg << fTrees->GetNumTasks() << endl;
171        return kFALSE;
172    }
173    */
174
175    if (master==kMaster && TestBit(kHasMaster))
176    {
177        *fLog << warn << GetDescriptor() << " already has a master tree... ignored." << endl;
178        master = kStandard;
179    }
180
181    MReadTree *t = master==kMaster ? new MReadMarsFile(tree) : new MReadTree(tree);
182    t->SetName(tree);
183    t->SetTitle(time?time:"");
184    if (master==kMaster)
185        SetBit(kHasMaster);
186    if (master==kRequired)
187        t->SetBit(kIsRequired);
188
189    if (!fEnableAutoScheme)
190        t->DisableAutoScheme();
191
192    //FIXME!
193    //t->DisableAutoScheme();
194
195    fTrees->AddToList(t);
196    //    return kTRUE;
197}
198
199MReadTree *MReadReports::GetReader(const char *tree) const
200{
201    return (MReadTree*)fTrees->FindObject(tree);
202}
203
204// --------------------------------------------------------------------------
205//
206// Schedule a file or several files (using widcards) for reading.
207//
208// All calls to AddTree _must_ be BEFORE the calls to AddFile!
209//
210Int_t MReadReports::AddFile(const char *fname, Int_t entries)
211{
212    Int_t n=0;
213
214    TIter NextT(fTrees->GetList());
215    MReadTree *tree=0;
216    while ((tree=(MReadTree*)NextT()))
217        n += tree->AddFile(fname, entries);
218
219    return n;
220}
221
222// --------------------------------------------------------------------------
223//
224// Count the number of required trees and store the number if fNumRequired.
225// Reset the kIsProcessed bit.
226//
227void MReadReports::ForceRequired()
228{
229    fNumRequired = 0;
230
231    TIter Next(fTrees->GetList());
232    TObject *o=0;
233    while ((o=Next()))
234        if (o->TestBit(kIsRequired))
235        {
236            o->ResetBit(kIsProcessed);
237            fNumRequired++;
238        }
239
240    *fLog << dbg << "Number of required trees: " << fNumRequired << endl;
241}
242
243// --------------------------------------------------------------------------
244//
245// Find MTaskList and store a pointer to it in fList.
246// Delete all entries in fChains.
247// Create all chains to read the time in the trees in advance.
248// Enable only the time-branch in this chains.
249// PreProcess fTrees (a MTaskList storing MReadTree tasks for reading)
250//
251Int_t MReadReports::PreProcess(MParList *plist)
252{
253    fChains->Delete();
254
255    Int_t i=0;
256
257    TIter NextT(fTrees->GetList());
258    MReadTree *tree=0;
259    while ((tree=(MReadTree*)NextT()))
260    {
261        if (!((TChain*)tree->fChain)->GetFile())
262        {
263            *fLog << warn << "No files or no tree '" << tree->GetName() << "'... skipped." << endl;
264            fTrees->RemoveFromList(tree);
265            continue;
266        }
267
268        if (tree->GetEntries()==0)
269        {
270            *fLog << warn << "No events in tree '" << tree->GetName() << "'... skipped." << endl;
271            fTrees->RemoveFromList(tree);
272            continue;
273        }
274
275        TString tn(tree->GetTitle());
276        if (tn.IsNull())
277        {
278            tn += "MTime";
279            tn += tree->GetName();
280            tn += ".";
281        }
282
283        TString tn2(tn);
284        tn2 += "*";
285
286        // FIXME: Should be tree->AddToBranchList such that
287        //        each run a new 'table' is created, but
288        //        MRead is searching for MTaskList in the
289        //        parameter list.
290        //AddToBranchList((const char*)tn2);
291
292        //
293        // SetBranchStatus wants to have a pointer to a pointer
294        //
295        MTime **tx = new MTime*;
296        *tx = 0;//new MTime;
297
298        TChain *c=new TChain(tree->GetName());
299
300        c->SetBranchStatus("*", 0);
301        c->SetBranchAddress(tn, tx);
302        c->SetBranchStatus(tn2, 1);
303
304        c->Add((TChain*)tree->fChain);
305        c->GetEntry(0);
306
307        fChains->Add(c);
308
309        i++;
310    }
311
312    if (i==0)
313    {
314        *fLog << err << "Files do not contain any valid tree... abort." << endl;
315        return kFALSE;
316    }
317
318    fPosEntry.Set(i);
319    fPosEntry.Reset();
320
321    // Force that with the next call to Process the required events are read
322    ForceRequired();
323    //fFirstReInit=kTRUE;
324
325    // Preprocess all tasks in fTrees
326    return fTrees->CallPreProcess(plist);
327}
328
329// --------------------------------------------------------------------------
330//
331// If this is not the first ReInit after PreProcess force the required
332// trees to be read first (call FirstRequired())
333//
334/*
335Bool_t MReadReports::ReInit(MParList *plist)
336{
337    if (!fFirstReInit)
338        ForceRequired();
339    fFirstReInit=kFALSE;
340    return kTRUE;
341}
342*/
343
344// --------------------------------------------------------------------------
345//
346// Return the number of the tree which is the next one to be read.
347// The condition for this decision is the time-stamp.
348//
349Int_t MReadReports::FindNextTime()
350{
351    TIter NextC(fChains);
352    TChain *c=0;
353
354    Int_t nmin=0;
355    MTime tmin(**GetTime((TChain*)NextC()));
356
357    Int_t i=0;
358
359    while ((c=(TChain*)NextC()))
360    {
361        MTime &t = **GetTime(c);
362        i++;
363
364        if (t >= tmin)
365            continue;
366
367        tmin = t;
368        nmin = i;
369    }
370    return nmin;
371}
372
373// --------------------------------------------------------------------------
374//
375// Return the number of the tree which is the next one to be read.
376// The condition for this decision kIsRequired but not kIsProcessed is set.
377//
378Int_t MReadReports::FindNextRequired()
379{
380    Int_t n = 0;
381
382    TIter Next(fTrees->GetList());
383    TObject *o=0;
384    while ((o=Next()))
385    {
386        if (o->TestBit(kIsRequired) && !o->TestBit(kIsProcessed))
387        {
388            o->SetBit(kIsProcessed);
389            fNumRequired--;
390            *fLog << dbg << "Reading from tree " << n << " " << o->GetName() << endl;
391            return n;
392        }
393        n++;
394    }
395
396    return -1;
397}
398
399// --------------------------------------------------------------------------
400//
401// Return the MTime corresponding to this TChain...
402//
403MTime** MReadReports::GetTime(TChain *c) const
404{
405    TChainElement *e=(TChainElement*)c->GetStatus()->At(1);
406    return (MTime**)e->GetBaddress();
407}
408
409// --------------------------------------------------------------------------
410//
411// Check which is the next tree to read from. Read an event from this tree.
412// Sets the StreamId accordingly.
413//
414Int_t MReadReports::Process()
415{
416    while (fChains->GetSize())
417    {
418        // Find the next tree to read from checking the time-stamps
419        // of the next events which would be read
420        const Int_t nmin=FindNext();
421        if (nmin<0)
422        {
423            *fLog << err << "MReadReports::Process: ERROR - Determination of next tree failed... abort." << endl;
424            return kERROR;
425        }
426
427        // Read the event from this tree
428        MTask *task = static_cast<MTask*>(fTrees->GetList()->At(nmin));
429        const Int_t rc = task->CallProcess();
430
431        // Read the time-stamp of the next event
432        TChain *chain = static_cast<TChain*>(fChains->At(nmin));
433        const Int_t cnt = chain->GetEntry(++fPosEntry[nmin]);
434
435        // In case there is no further time-stamp of an error reading the
436        // event we remove this time-stamp from the list of time-stamps to
437        // be checked for reading the next events, because there is none.
438        if (cnt<=0 || rc==kFALSE)
439        {
440            *fLog << inf << "Removing chain " << chain->GetName() << " from list" << flush;
441
442            // Find index of chain to be removed
443            const Int_t idx = fChains->IndexOf(chain);
444            *fLog << " (" << idx << ")" << flush;
445
446            delete *GetTime(chain);        // Delete MTime*
447            *fLog << "." << flush;
448            delete fChains->Remove(chain); // Remove chain from TList
449            *fLog << "." << flush;
450
451            // Change array accordingly
452            if (fPosEntry.GetSize()>1)
453            {
454                for (int i=idx; i<fPosEntry.GetSize()-1; i++)
455                    fPosEntry[i] = fPosEntry[i+1];
456                fPosEntry[fPosEntry.GetSize()-1] = 0;
457            }
458
459            // FIXME: Maybe MTaskList should have a member function to
460            //        reorder the tasks?
461
462            // Move this task to the end of the list so that nmin still
463            // corresponds to the correct task in the list.
464            const_cast<TList*>(fTrees->GetList())->Remove(task);
465            *fLog << "." << flush;
466            const_cast<TList*>(fTrees->GetList())->AddLast(task);
467            *fLog << "done." << endl;
468        }
469
470        // If something else than kFALSE (means: stop reading from this
471        // tree) has happened we return the return code of the processing
472        if (rc!=kFALSE)
473            return rc;
474    }
475
476    return kFALSE;
477}
478
479// --------------------------------------------------------------------------
480//
481// PostProcess all MReadTree tasks in fTrees.
482//
483Int_t MReadReports::PostProcess()
484{
485    return fTrees->CallPostProcess();
486}
487
488// --------------------------------------------------------------------------
489//
490// PrintStatistics of this task and of the MReadTree tasks in fTress
491//
492void MReadReports::PrintStatistics(const Int_t lvl, Bool_t title, Double_t time) const
493{
494    MRead::PrintStatistics(lvl, title, time);
495    fTrees->PrintStatistics(lvl+1, title, GetCpuTime());
496}
Note: See TracBrowser for help on using the repository browser.