source: trunk/Mars/mhbase/MFillH.cc @ 19307

Last change on this file since 19307 was 19307, checked in by tbretz, 15 months ago
That is another try to hopefully get something working. Works with root 6 for callisto and star.
File size: 19.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, 07/2001 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20!   Copyright: MAGIC Software Development, 2000-2008
21!
22!
23\* ======================================================================== */
24
25//////////////////////////////////////////////////////////////////////////////
26//
27//  MFillH
28//
29//  This is a common interface (task) to fill mars histograms. Every mars
30//  histogram which is derived from MH can be filled with this task.
31//
32//  There are two options to use:
33//
34//  1) You specifiy the parameter container with which data the
35//     histogram container should be filled, and the histogram container
36//     which has to be filled. This can be done by either specifing the
37//     name of the objects in the parameter list or by specifiing a pointer
38//     to the object. (s. Constructor)
39//
40//  2) You specify the name and/or type of the histogram to become filled.
41//     Any other action imust be taken by the histogram class.
42//
43//  PreProcess: In the preprocessing of this task we setup all pointers
44//              to instances which are needed and call FillSetup of the
45//              histogram class with the parameter list as an argument.
46//
47//  Process: The process function calls the Fill member function of the
48//           histogram class instance (inheriting from MH) with either
49//           a NULL pointer or a pointer to the corresponding container
50//           as an argument.
51//
52// To use a weight for each event filled in a histogram call
53// SetWeight(). You can eithe use the name of a MParameterD container stored
54// in the parameter list or a pointer to it as an argument.
55//
56//
57//  WARNING:
58//   Because MFillH is a generalized task to fill histograms it doesn't
59//   know about which branches from a file are necessary to fill the
60//   histograms. If you are reading data from a file which is directly
61//   filled into a histogram via MFillH, please call either
62//   MReadTree::DisableAutoScheme() or enable the necessary branches by
63//   yourself, using MReadTree::EnableBranch()
64//
65//   Checkout the Warning in MTaskList.
66//
67//  Version 3:
68//  ----------
69//   - added fTitleTab
70//
71//  Version 2:
72//  ----------
73//   - added fNumExcutions
74//
75//
76//  Input Containers:
77//   A parameter container
78//
79//  Output Containers:
80//   A histogram container
81//
82//////////////////////////////////////////////////////////////////////////////
83#include "MFillH.h"
84
85#include <fstream>
86
87#include <TClass.h>
88#include <TCanvas.h>
89
90#include "MDataPhrase.h"
91
92#include "MLog.h"
93#include "MLogManip.h"
94
95#include "MString.h"
96
97#include "MH.h"
98#include "MHArray.h"
99
100#include "MParameters.h"
101
102#include "MParList.h"
103#include "MStatusDisplay.h"
104
105ClassImp(MFillH);
106
107using namespace std;
108
109// --------------------------------------------------------------------------
110//
111// Initializes name and title of the object. It is called by all
112// constructors.
113//
114void MFillH::Init(const char *name, const char *title)
115{
116    fName  = name  ? name  : "MFillH";
117    fTitle = title ? title : "Task to fill Mars histograms";
118
119    fH            = NULL;
120    fParContainer = NULL;
121
122    fIndex  = NULL;
123    fCanvas = NULL;
124
125    fWeight     = NULL;
126    fWeightName = "";
127}
128
129// --------------------------------------------------------------------------
130//
131// Default Constructor. This is to support some root-stuff.
132// Never try to use it yourself!
133//
134MFillH::MFillH()
135{
136    Init(NULL, NULL);
137}
138
139// --------------------------------------------------------------------------
140//
141// Constructor.
142//
143// 1) - par is the name of the parameter container which should be filled into
144//      the histogram
145//    - hist is the name of the histogram container (which must have been
146//      derived from MH)
147//
148//    In this case MH::Fill is called with a pointer to the corresponding
149//    histogram instance.
150//
151// 2) - hist is the name and/or type of the histogram.
152//      1) The name and type is identical, eg: "MHHillas"
153//      2) They are not identical, eg: "MyHistogram [MHHillas]"
154//         This searches for a class instance of MHHillas with the name
155//         "MyHistogram". If it doesn't exist one is created.
156//
157//    In this case PreProcess calls MH::SetupFill with a pointer to the
158//    parameter list and MH::Fill is called with a NULL-pointer.
159//
160MFillH::MFillH(const char *hist, const char *par, const char *name, const char *title)
161{
162    Init(name, title);
163
164    fHName = hist;
165    fParContainerName = par;
166
167    AddToBranchList(Form("%s.*", (const char*)ExtractName(hist)));
168    if (par)
169        AddToBranchList(Form("%s.*", (const char*)ExtractName(par)));
170
171    if (title)
172        return;
173
174    fTitle = Form("Fill %s", fHName.Data());
175    if (fParContainerName.IsNull())
176        return;
177
178    fTitle += Form(" from %s", fParContainerName.Data());
179}
180
181// --------------------------------------------------------------------------
182//
183// Constructor.
184//
185// 1) - par is a pointer to the instance of your parameter container from which
186//      the data should be used to fill the histogram.
187//    - hist is the name of the histogram container (which must have been
188//      derived from MH)
189//
190//    In this case MH::Fill is called with a pointer to the corresponding
191//    histogram instance.
192//
193// 2) - hist is the name and/or type of the histogram.
194//      1) The name and type is identical, eg: "MHHillas"
195//      2) They are not identical, eg: "MyHistogram [MHHillas]"
196//         This searches for a class instance of MHHillas with the name
197//         "MyHistogram". If it doesn't exist one is created. Everything
198//         which is between the first '[' and the last ']' in the string
199//         is used as the histogram type.
200//
201//    In this case PreProcess calls MH::SetupFill with a pointer to the
202//    parameter list and MH::Fill is called with a NULL-pointer.
203//
204//
205MFillH::MFillH(const char *hist, MParContainer *par, const char *name, const char *title)
206{
207    Init(name, title);
208
209    fHName = hist;
210    fParContainer = par;
211    if (par)
212        fParContainerName = par->GetName();
213
214    AddToBranchList(Form("%s.*", (const char*)ExtractName(hist)));
215    if (par)
216        AddToBranchList(Form("%s.*", par->GetName()));
217
218    if (!title)
219        fTitle = Form("Fill %s from %s", fName.Data(), par?par->GetDescriptor().Data():"NULL");
220}
221
222// --------------------------------------------------------------------------
223//
224// Constructor.
225//
226// - par is a pointer to the instance of your parameter container from which
227//   the data should be used to fill the histogram.
228// - hist is a pointer to the instance of your histogram container (which must
229//   have been derived from MH) into which the data should flow
230//
231MFillH::MFillH(MH *hist, const char *par, const char *name, const char *title)
232{
233    Init(name, title);
234
235    fH = hist;
236    if (hist)
237        fHName = hist->GetName();
238    fParContainerName = par;
239
240    if (fH)
241        AddToBranchList(fH->GetDataMember());
242    if (par)
243        AddToBranchList(Form("%s.*", (const char*)ExtractName(par)));
244
245    if (title)
246        return;
247
248    fTitle = Form("Fill %s", hist ? hist->GetDescriptor().Data() : "NULL");
249    if (!par)
250        return;
251
252    fTitle += Form(" from %s", fParContainerName.Data());
253}
254
255// --------------------------------------------------------------------------
256//
257// Constructor.
258//
259// - par is a pointer to the instance of your parameter container from which
260//   the data should be used to fill the histogram.
261// - hist is the name of the histogram container (which must have been
262//   derived from MH)
263//
264MFillH::MFillH(MH *hist, MParContainer *par, const char *name, const char *title)
265{
266    Init(name, title);
267
268    fH = hist;
269    if (hist)
270        fHName = hist->GetName();
271    fParContainer = par;
272    if (par)
273        fParContainerName = par->GetName();
274
275    if (fH)
276        AddToBranchList(fH->GetDataMember());
277    if (par)
278        AddToBranchList(Form("%s.*", par->GetName()));
279
280    if (!title)
281        fTitle = Form("Fill %s from %s",
282                      hist?hist->GetDescriptor().Data():"NULL",
283                      par ? par->GetDescriptor().Data():"NULL");
284}
285
286// --------------------------------------------------------------------------
287//
288// Destructor. Delete fData if existing and kCanDelete is set.
289//
290MFillH::~MFillH()
291{
292    if (fIndex)
293        if (fIndex->TestBit(kCanDelete))
294            delete fIndex;
295}
296
297// --------------------------------------------------------------------------
298//
299// If the histogram to be filles is a MHArray you can specify a 'rule'
300// This rule is used to create an MDataPhrase. The return value of the chain
301// is casted to int. Each int acts as a key. For each (new) key a new
302// histogram is created in the array. (eg for the rule
303// "MRawRunHeader::fRunNumber" you would get one histogram per run-number)
304//
305void MFillH::SetRuleForIdx(const TString rule)
306{
307    fIndex = new MDataPhrase(rule);
308    fIndex->SetBit(kCanDelete);
309}
310
311// --------------------------------------------------------------------------
312//
313// If the histogram to be filles is a MHArray you can specify a MData-object
314// The return value of the object is casted to int. Each int acts as a key.
315// For each (new) key a new histogram is created in the array. (eg for
316// MDataMember("MRawEvtHeader::fRunNumber") you would get one histogram per
317// run-number)
318//
319void MFillH::SetRuleForIdx(MData *data)
320{
321    fIndex = data;
322}
323
324// --------------------------------------------------------------------------
325//
326// Extracts the name of the histogram from the MFillH argument
327//
328TString MFillH::ExtractName(const char *name) const
329{
330    TString type = name;
331
332    const Ssiz_t first = type.First('[');
333    const Ssiz_t last  = type.First(']');
334
335    if (!first || !last || first>=last)
336        return type;
337
338    return type.Remove(first).Strip(TString::kBoth);
339}
340
341// --------------------------------------------------------------------------
342//
343// Extracts the class-name of the histogram from the MFillH argument
344//
345TString MFillH::ExtractClass(const char *name) const
346{
347    TString type = name;
348
349    const Ssiz_t first = type.First('[');
350    const Ssiz_t last  = type.First(']');
351
352    if (!first || !last || first>=last)
353        return type;
354
355    const Ssiz_t length = last-first-1;
356
357    TString strip = fHName(first+1, length);
358    return strip.Strip(TString::kBoth);
359}
360
361// --------------------------------------------------------------------------
362//
363// Use this to set a draw option used when drawing automatically to the
364// status display.
365//
366void MFillH::SetDrawOption(Option_t *option)
367{
368    fDrawOption = option;
369}
370
371// --------------------------------------------------------------------------
372//
373// Creates a new tab in a status display with the name of the MH class,
374// if fDisplay is set and the MH-class overwrites the Draw function
375//
376// If the draw-option contains 'same' (case insensitive) a tab with the
377// same name as the one which would be created is searched and the
378// MH is drawn to this canvas. If it is not found a new tab is created.
379//
380Bool_t MFillH::DrawToDisplay()
381{
382    fCanvas = NULL;
383
384    if (!fDisplay)
385        return kTRUE;
386
387    if (!fH->OverwritesDraw())
388        return kTRUE;
389
390    if (TestBit(kDoNotDisplay))
391        return kTRUE;
392
393    const TString tabname = fNameTab.IsNull() ? fH->GetName() : fNameTab.Data();
394
395    fCanvas = 0;
396    if (fDrawOption.Contains("same", TString::kIgnoreCase))
397    {
398        fCanvas = fDisplay->GetCanvas(tabname);
399        if (!fCanvas)
400            *fLog << warn << "WARNING - 'same' option given, but no tab with name '" << tabname << "' found." << endl;
401    }
402
403    if (!fCanvas)
404    {
405        const TString tabtitle = fTitleTab.IsNull() ? fH->GetTitle() : fTitleTab.Data();
406        fCanvas = &fDisplay->AddTab(tabname, tabtitle);
407    }
408
409    fCanvas->cd();
410    fH->Draw(fDrawOption);
411
412    return kTRUE;
413}
414
415// --------------------------------------------------------------------------
416//
417// Checks the parameter list for the existance of the parameter container. If
418// the name of it was given in the constructor. It checks also for the
419// existance of the histogram container in the parameter list if a name was
420// given. If it is not available it tried to create a histogram container
421// with the same type as the given object name.
422//
423Int_t MFillH::PreProcess(MParList *pList)
424{
425    if (fIndex)
426    {
427        if (!fIndex->PreProcess(pList))
428        {
429            *fLog << all << "PreProcessing of Index rule failed... aborting." << endl;
430            return kFALSE;
431        }
432
433        if (!fIndex->IsValid())
434        {
435            *fLog << all << "Given Index rule invalid... aborting." << endl;
436            return kFALSE;
437        }
438    }
439
440    //
441    // If the user defined the use of a weight: search for it.
442    //
443    if (!fWeight && !fWeightName.IsNull())
444    {
445        fWeight = (MParameterD*)pList->FindObject(fWeightName, "MParameterD");
446
447        if (!fWeight)
448        {
449            *fLog << err << fWeightName << " [MParameterD] not found... aborting." << endl;
450            return kFALSE;
451        }
452    }
453
454    //
455    // Try to get the histogram container with name fHName from list
456    // or create one with this name
457    //
458    if (!fH)
459    {
460        const TString cls  = ExtractClass(fHName);
461        const TString name = ExtractName(fHName);
462
463        TObject *obj=NULL;
464        if (cls==name)
465            obj = pList->FindObject(fHName);
466
467        if (!obj)
468        {
469            /*
470            if (cls==name)
471            *fLog << inf << "Object '" << fHName << "' not found in parlist... creating." << endl;
472            */
473            obj = pList->FindCreateObj(cls, name);
474        }
475
476        if (!obj)
477            return kFALSE;
478
479        //
480        // We were successfull getting it. Check whether it really inherits
481        // from MH, FindCreateObj does only check for inheritance from
482        // 'type'.
483        //
484        TClass *tcls = fIndex ? MHArray::Class() : MH::Class();
485        if (!obj->InheritsFrom(tcls))
486        {
487            *fLog << err << obj->GetName() << " doesn't inherit ";
488            *fLog << "from " << tcls->GetName() << " - cannot be used for MFillH...";
489            *fLog << "aborting." << endl;
490            return kFALSE;
491        }
492
493        fH = (MH*)obj;
494    }
495
496    //
497    // Now we have the histogram container available. Try to Setup Fill.
498    //
499    fH->SetSerialNumber(GetSerialNumber());
500    fH->SetNumExecutions(0);
501    if (!fH->SetupFill(pList))
502    {
503        *fLog << (TestBit(kCanSkip) ? warn : err);
504        *fLog << (TestBit(kCanSkip) ? "WARNING" : "ERROR");
505        *fLog << " - Calling SetupFill for " << fH->GetDescriptor() << "...";
506        *fLog << (TestBit(kCanSkip) ? "skipped." : "aborting.") << endl;
507
508        return TestBit(kCanSkip) ? kSKIP : kFALSE;
509    }
510
511    //
512    // If also a parameter container is already set we are done.
513    //
514    if (fParContainer)
515        return DrawToDisplay();
516
517    //
518    // This case means, that the MH sets up its container to be filled
519    // by itself. Check there if it has something to be filled with!
520    //
521    if (fParContainerName.IsNull())
522    {
523        fParContainer = NULL;
524        return DrawToDisplay();
525    }
526
527    fParContainer = (MParContainer*)pList->FindObject(fParContainerName);
528    if (fParContainer)
529        return DrawToDisplay();
530
531    if (TestBit(kCanSkip))
532    {
533        *fLog << warn << fParContainerName << " [MParContainer] not found... skipped." << endl;
534        return kSKIP;
535    }
536
537    *fLog << err << fParContainerName << " [MParContainer] not found... aborting." << endl;
538    return kFALSE;
539}
540
541// --------------------------------------------------------------------------
542//
543// Call the ReInit function of the contained Histogram
544//
545Bool_t MFillH::ReInit(MParList *pList)
546{
547    return fH->ReInit(pList);
548} 
549
550// --------------------------------------------------------------------------
551//
552// Fills the data from the parameter conatiner into the histogram container
553//
554Int_t MFillH::Process()
555{
556    if (fIndex)
557        ((MHArray*)fH)->SetIndexByKey(fIndex->GetValue());
558    /*
559     const Int_t key = (Int_t)fIndex->GetValue();
560     const Int_t idx = fMapIdx->Add(key);
561     ((MHArray*)fH)->SetIndex(idx);
562     */
563
564//    TVirtualPad *save = gPad;
565//    if (fCanvas)
566//        fCanvas->cd();
567
568    fH->SetNumExecutions(GetNumExecutions());
569    const Int_t rc = fH->Fill(fParContainer, fWeight?fWeight->GetVal():1);
570
571//    if (save && fCanvas)
572//        save->cd();
573    return rc;
574} 
575
576// --------------------------------------------------------------------------
577//
578// Set the ReadyToSave flag of the histogram container, because now all data
579// has been filled into the histogram.
580//
581Int_t MFillH::PostProcess()
582{
583    // Return if fH was never initialized.
584    if (!fH)
585        return kTRUE;
586
587    //
588    // Now all data is in the histogram. Maybe some final action is
589    // necessary.
590    //
591    if (!fH->Finalize())
592    {
593        *fLog << err << "ERROR - Calling Finalize for ";
594        *fLog << fH->GetDescriptor() << "... aborting." << endl;
595        return kFALSE;
596    }
597
598    fH->SetReadyToSave();
599
600    //
601    // Check whether fDisplay has previously been used (fCanvas),
602    // fDisplay is still open and the corresponding Canvas/Tab is
603    // still existing.
604    //
605    if (fDisplay && fDisplay->HasCanvas(fCanvas))
606    {
607        const TString opt(MString::Format("nonew %s", fDrawOption.Data()));
608
609        // Remove the old class from the canvas to avoid that it is deleted
610        fCanvas->GetListOfPrimitives()->Remove(fH);
611
612        // change into canvas
613        fCanvas->cd();
614
615        // Now clear the canvas from everything fH might have added there
616        // (this should be done only if this is not called with 'same')
617        //fCanvas->Clear();           // already in MH::DrawClone()
618
619        // Make sure that TGraphs go to the correct pads
620        //gROOT->SetSelectedPad(0);   // already in MH::DrawClone()
621
622        // Now create a clone and draw it to the canvas
623        fH->DrawClone(opt);
624
625        // Make sure the update is displayed
626        fCanvas->Modified();
627        fCanvas->Update();
628    }
629
630    return kTRUE;
631}
632
633// --------------------------------------------------------------------------
634//
635// Implementation of SavePrimitive. Used to write the call to a constructor
636// to a macro. In the original root implementation it is used to write
637// gui elements to a macro-file.
638//
639void MFillH::StreamPrimitive(ostream &out) const
640{
641    if (fH)
642        fH->SavePrimitive(out);
643
644    if (fParContainer)
645        fParContainer->SavePrimitive(out);
646
647    if (fWeight)
648        fWeight->SavePrimitive(out);
649
650    out << "   MFillH " << GetUniqueName() << "(";
651
652    if (fH)
653        out << "&" << fH->GetUniqueName();
654    else
655        out << "\"" << fHName << "\"";
656
657    if (fParContainer)
658        out << ", &" << fParContainer->GetUniqueName();
659    else
660        if (!fParContainerName.IsNull())
661            out << ", \"" << fParContainerName << "\"";
662
663    out << ");" << endl;
664
665    if (fWeight || !fWeightName.IsNull())
666    {
667        out << "   " << GetUniqueName() << ".SetWeight(";
668        if (fWeight)
669            out << "&" << fWeight->GetUniqueName() << ");" << endl;
670        else
671            if (!fWeightName.IsNull())
672                out << "\"" << fWeightName << "\");" << endl;
673    }
674
675    if (fIndex)
676    {
677        out << "   " << GetUniqueName() << ".SetRuleForIdx(\"";
678        out << fIndex->GetRule() << "\");" << endl;
679    }
680}
Note: See TracBrowser for help on using the repository browser.