source: trunk/MagicSoft/Mars/mhbase/MFillH.cc@ 6948

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