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

Last change on this file since 9875 was 9315, checked in by tbretz, 16 years ago
*** empty log message ***
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 //
584 // Now all data is in the histogram. Maybe some final action is
585 // necessary.
586 //
587 if (!fH->Finalize())
588 {
589 *fLog << err << "ERROR - Calling Finalize for ";
590 *fLog << fH->GetDescriptor() << "... aborting." << endl;
591 return kFALSE;
592 }
593
594 fH->SetReadyToSave();
595
596 //
597 // Check whether fDisplay has previously been used (fCanvas),
598 // fDisplay is still open and the corresponding Canvas/Tab is
599 // still existing.
600 //
601 if (fDisplay && fDisplay->HasCanvas(fCanvas))
602 {
603 const TString opt(MString::Format("nonew %s", fDrawOption.Data()));
604 fCanvas->cd();
605 // Remove the old class to prevent clashes calling
606 // Paint-functions when the display is updated
607 fCanvas->GetListOfPrimitives()->Remove(fH);
608 // DrawClone also takes care of calling gPad->Clear()
609 fH->DrawClone(opt);
610 fCanvas->Modified();
611 fCanvas->Update();
612 }
613
614 return kTRUE;
615}
616
617// --------------------------------------------------------------------------
618//
619// Implementation of SavePrimitive. Used to write the call to a constructor
620// to a macro. In the original root implementation it is used to write
621// gui elements to a macro-file.
622//
623void MFillH::StreamPrimitive(ostream &out) const
624{
625 if (fH)
626 fH->SavePrimitive(out);
627
628 if (fParContainer)
629 fParContainer->SavePrimitive(out);
630
631 if (fWeight)
632 fWeight->SavePrimitive(out);
633
634 out << " MFillH " << GetUniqueName() << "(";
635
636 if (fH)
637 out << "&" << fH->GetUniqueName();
638 else
639 out << "\"" << fHName << "\"";
640
641 if (fParContainer)
642 out << ", &" << fParContainer->GetUniqueName();
643 else
644 if (!fParContainerName.IsNull())
645 out << ", \"" << fParContainerName << "\"";
646
647 out << ");" << endl;
648
649 if (fWeight || !fWeightName.IsNull())
650 {
651 out << " " << GetUniqueName() << ".SetWeight(";
652 if (fWeight)
653 out << "&" << fWeight->GetUniqueName() << ");" << endl;
654 else
655 if (!fWeightName.IsNull())
656 out << "\"" << fWeightName << "\");" << endl;
657 }
658
659 if (fIndex)
660 {
661 out << " " << GetUniqueName() << ".SetRuleForIdx(\"";
662 out << fIndex->GetRule() << "\");" << endl;
663 }
664}
Note: See TracBrowser for help on using the repository browser.