source: branches/AddingGoogleTestEnvironment/mhbase/MFillH.cc@ 19882

Last change on this file since 19882 was 17125, checked in by tbretz, 11 years ago
Secured PostProcess agianst never initialized fH, add the fH Clone to the pad directly ourselves.
File size: 19.2 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 // fCanvas->cd();
609 // fCanvas->Clear();
610
611 // Remove the old class to prevent clashes calling
612 // Paint-functions when the display is updated
613 fCanvas->GetListOfPrimitives()->Remove(fH);
614 fCanvas->GetListOfPrimitives()->Add(fH->Clone(), opt);
615 fCanvas->Modified();
616 fCanvas->Update();
617 }
618
619 return kTRUE;
620}
621
622// --------------------------------------------------------------------------
623//
624// Implementation of SavePrimitive. Used to write the call to a constructor
625// to a macro. In the original root implementation it is used to write
626// gui elements to a macro-file.
627//
628void MFillH::StreamPrimitive(ostream &out) const
629{
630 if (fH)
631 fH->SavePrimitive(out);
632
633 if (fParContainer)
634 fParContainer->SavePrimitive(out);
635
636 if (fWeight)
637 fWeight->SavePrimitive(out);
638
639 out << " MFillH " << GetUniqueName() << "(";
640
641 if (fH)
642 out << "&" << fH->GetUniqueName();
643 else
644 out << "\"" << fHName << "\"";
645
646 if (fParContainer)
647 out << ", &" << fParContainer->GetUniqueName();
648 else
649 if (!fParContainerName.IsNull())
650 out << ", \"" << fParContainerName << "\"";
651
652 out << ");" << endl;
653
654 if (fWeight || !fWeightName.IsNull())
655 {
656 out << " " << GetUniqueName() << ".SetWeight(";
657 if (fWeight)
658 out << "&" << fWeight->GetUniqueName() << ");" << endl;
659 else
660 if (!fWeightName.IsNull())
661 out << "\"" << fWeightName << "\");" << endl;
662 }
663
664 if (fIndex)
665 {
666 out << " " << GetUniqueName() << ".SetRuleForIdx(\"";
667 out << fIndex->GetRule() << "\");" << endl;
668 }
669}
Note: See TracBrowser for help on using the repository browser.