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

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