source: trunk/Mars/mfbase/MFEventSelector2.cc@ 9882

Last change on this file since 9882 was 9851, checked in by tbretz, 14 years ago
Changed MH::SetBinning and similar functions to take references instead of pointers as arguments. For convenience wrappers for the old style functions are provided.
File size: 18.1 KB
Line 
1/* ======================================================================== *\
2! $Name: not supported by cvs2svn $:$Id: MFEventSelector2.cc,v 1.10 2006-10-17 17:15:59 tbretz Exp $
3! --------------------------------------------------------------------------
4!
5! *
6! * This file is part of MARS, the MAGIC Analysis and Reconstruction
7! * Software. It is distributed to you in the hope that it can be a useful
8! * and timesaving tool in analysing Data of imaging Cerenkov telescopes.
9! * It is distributed WITHOUT ANY WARRANTY.
10! *
11! * Permission to use, copy, modify and distribute this software and its
12! * documentation for any purpose is hereby granted without fee,
13! * provided that the above copyright notice appear in all copies and
14! * that both that copyright notice and this permission notice appear
15! * in supporting documentation. It is provided "as is" without express
16! * or implied warranty.
17! *
18!
19!
20! Author(s): Thomas Bretz, 01/2002 <mailto:tbretz@astro.uni-wuerzburg.de>
21! Author(s): Wolfgang Wittek 11/2003 <mailto:wittek@mppmu.mpg.de>
22!
23! Copyright: MAGIC Software Development, 2000-2005
24!
25!
26\* ======================================================================== */
27
28/////////////////////////////////////////////////////////////////////////////
29//
30// MFEventSelector2
31//
32// This is a filter to make a selection of events from a file, according to
33// a certain requested distribution in a given parameter (or combination
34// of parameters). The distribution is passed to the class through a histogram
35// of the relevant parameter(s) contained in an object of type MH3. The filter
36// will return true or false in each event such that the final distribution
37// of the parameter(s) for the events surviving the filter is the desired one.
38// The selection of which events are kept in each bin of the parameter(s) is
39// made at random (obviously the selection probability depends on the
40// values of the parameters, and is dictated by the input histogram).
41//
42// This procedure requires the determination of the original distribution
43// of the given parameters for the total sample of events on the input file.
44// If the event loop contains a filter with name "FilterSelector2", this
45// filter will be applied when determining the original distribution.
46//
47// See Constructor for more instructions and also the example below:
48//
49// --------------------------------------------------------------------
50//
51// void select()
52// {
53// MParList plist;
54// MTaskList tlist;
55//
56// MStatusDisplay *d=new MStatusDisplay;
57//
58// plist.AddToList(&tlist);
59//
60// MReadTree read("Events", "myinputfile.root");
61// read.DisableAutoScheme();
62// // Accelerate execution...
63// // read.EnableBranch("MMcEvt.fTelescopeTheta");
64//
65// // create nominal distribution (theta converted into degrees)
66// MH3 nomdist("r2d(MMcEvt.fTelescopeTheta)");
67// MBinning binsx;
68// binsx.SetEdges(5, 0, 45); // five bins from 0deg to 45deg
69// MH::SetBinning(&nomdist.GetHist(), &binsx);
70//
71// // use this to create a nominal distribution in 2D
72// // MH3 nomdist("r2d(MMcEvt.fTelescopeTheta)", "MMcEvt.fEnergy");
73// // MBinning binsy;
74// // binsy.SetEdgesLog(5, 10, 10000);
75// // MH::SetBinning((TH2*)&nomdist.GetHist(), &binsx, &binsy);
76//
77// // Fill the nominal distribution with whatever you want:
78// for (int i=0; i<nomdist.GetNbins(); i++)
79// nomdist.GetHist().SetBinContent(i, i*i);
80//
81// MFEventSelector2 test(nomdist);
82// test.SetNumMax(9999); // total number of events selected
83// MContinue cont(&test);
84//
85// MEvtLoop run;
86// run.SetDisplay(d);
87// run.SetParList(&plist);
88// tlist.AddToList(&read);
89// tlist.AddToList(&cont);
90//
91// if (!run.Eventloop())
92// return;
93//
94// tlist.PrintStatistics();
95// }
96//
97// --------------------------------------------------------------------
98//
99// The random number is generated using gRandom->Rndm(). You may
100// control this procedure using the global object gRandom.
101//
102// Because of the random numbers this works best for huge samples...
103//
104// Don't try to use this filter for the reading task or as a selector
105// in the reading task: This won't work!
106//
107// Remark: You can also use the filter together with MContinue
108//
109//
110// FIXME: Merge MFEventSelector and MFEventSelector2
111//
112/////////////////////////////////////////////////////////////////////////////
113#include "MFEventSelector2.h"
114
115#include <TRandom.h> // gRandom
116#include <TCanvas.h> // TCanvas
117
118#include "MH3.h" // MH3
119#include "MRead.h" // MRead
120#include "MEvtLoop.h" // MEvtLoop
121#include "MTaskList.h" // MTaskList
122#include "MBinning.h" // MBinning
123#include "MContinue.h" //
124#include "MFillH.h" // MFillH
125#include "MParList.h" // MParList
126#include "MStatusDisplay.h" // MStatusDisplay
127
128#include "MLog.h"
129#include "MLogManip.h"
130
131ClassImp(MFEventSelector2);
132
133using namespace std;
134
135const TString MFEventSelector2::gsDefName = "MFEventSelector2";
136const TString MFEventSelector2::gsDefTitle = "Filter to select events with a given distribution";
137
138// --------------------------------------------------------------------------
139//
140// Constructor. Takes a reference to an MH3 which gives you
141// 1) The nominal distribution. The distribution is renormalized, so
142// that the absolute values do not matter. To crop the distribution
143// to a nominal value of total events use SetNumMax
144// 2) The parameters histogrammed in MH3 are those on which the
145// event selector will work, eg
146// MH3 hist("MMcEvt.fTelescopeTheta", "MMcEvt.fEnergy");
147// Would result in a redistribution of Theta and Energy.
148// 3) Rules are also accepted in the argument of MH3, for instance:
149// MH3 hist("MMcEvt.fTelescopeTheta");
150// would result in redistributing Theta, while
151// MH3 hist("cos(MMcEvt.fTelescopeTheta)");
152// would result in redistributing cos(Theta).
153//
154// If the reference distribution doesn't contain entries (GetEntries()==0)
155// the original distribution will be used as the nominal distribution;
156// note that also in this case a dummy nominal distribution has to be
157// provided in the first argument (the dummy distribution defines the
158// variable(s) of interest, their binnings and their requested ranges;
159// events outside these ranges won't be accepted).
160//
161// Set default name of filter to be applied when determining the original
162// distribution for all data on the input file to "FilterSelector2"
163//
164MFEventSelector2::MFEventSelector2(MH3 &hist, const char *name, const char *title)
165 : fHistOrig(NULL), fHistNom(&hist), fHistRes(NULL),
166 fDataX(hist.GetRule('x')), fDataY(hist.GetRule('y')),
167 fDataZ(hist.GetRule('z')), fNumMax(-1), fCanvas(0),
168 fFilterName("FilterSelector2"), fHistIsProbability(kFALSE),
169 fUseOrigDist(kTRUE)
170{
171 fName = name ? (TString)name : gsDefName;
172 fTitle = title ? (TString)title : gsDefTitle;
173}
174
175// --------------------------------------------------------------------------
176//
177// Delete fHistRes if instatiated
178//
179MFEventSelector2::~MFEventSelector2()
180{
181 if (fHistRes)
182 delete fHistRes;
183}
184
185//---------------------------------------------------------------------------
186//
187// Recreate a MH3 from fHistNom used as a template. Copy the Binning
188// from fHistNom to the new histogram, and return a pointer to the TH1
189// base class of the MH3.
190//
191TH1 &MFEventSelector2::InitHistogram(MH3* &hist)
192{
193 // if fHistRes is already allocated delete it first
194 if (hist)
195 delete hist;
196
197 // duplicate the fHistNom histogram
198 hist = static_cast<MH3*>(fHistNom->New());
199
200 // copy binning from one histogram to the other one
201 MH::SetBinning(hist->GetHist(), fHistNom->GetHist());
202
203 return hist->GetHist();
204}
205
206// --------------------------------------------------------------------------
207//
208// Try to read the present distribution from the file. Therefore the
209// Reading task of the present loop is used in a new eventloop.
210//
211Bool_t MFEventSelector2::ReadDistribution(MRead &read, MFilter *filter)
212{
213 if (read.GetEntries() > kMaxUInt) // FIXME: LONG_MAX ???
214 {
215 *fLog << err << "kIntMax exceeded." << endl;
216 return kFALSE;
217 }
218
219 *fLog << inf;
220 fLog->Separator("MFEventSelector2::ReadDistribution");
221 *fLog << " - Start of eventloop to generate the original distribution..." << endl;
222
223 if (filter != NULL)
224 *fLog << " - filter used: " << filter->GetDescriptor() << endl;
225
226
227 MEvtLoop run("ReadDistribution");
228
229 MParList plist;
230 MTaskList tlist;
231 plist.AddToList(&tlist);
232 run.SetParList(&plist);
233
234 MBinning binsx("BinningMH3X");
235 MBinning binsy("BinningMH3Y");
236 MBinning binsz("BinningMH3Z");
237 binsx.SetEdges(fHistNom->GetHist(), 'x');
238 binsy.SetEdges(fHistNom->GetHist(), 'y');
239 binsz.SetEdges(fHistNom->GetHist(), 'z');
240 plist.AddToList(&binsx);
241 plist.AddToList(&binsy);
242 plist.AddToList(&binsz);
243
244 MFillH fill(fHistOrig);
245 fill.SetName("FillHistOrig");
246 fill.SetBit(MFillH::kDoNotDisplay);
247 tlist.AddToList(&read);
248
249 MContinue contfilter(filter);
250 if (filter != NULL)
251 {
252 contfilter.SetName("ContFilter");
253 tlist.AddToList(&contfilter);
254 }
255
256 tlist.AddToList(&fill);
257 run.SetDisplay(fDisplay);
258 if (!run.Eventloop())
259 {
260 *fLog << err << dbginf << "Evtloop failed... abort." << endl;
261 return kFALSE;
262 }
263
264 tlist.PrintStatistics();
265
266 *fLog << inf;
267 *fLog << "MFEventSelector2::ReadDistribution:" << endl;
268 *fLog << " - Original distribution has " << fHistOrig->GetHist().GetEntries() << " entries." << endl;
269 *fLog << " - End of eventloop to generate the original distribution." << endl;
270 fLog->Separator();
271
272 return read.Rewind();
273}
274
275// --------------------------------------------------------------------------
276//
277// After reading the histograms the arrays used for the random event
278// selection are created. If a MStatusDisplay is set the histograms are
279// displayed there.
280//
281void MFEventSelector2::PrepareHistograms()
282{
283 TH1 &ho = fHistOrig->GetHist();
284
285 //-------------------
286 // if requested
287 // set the nominal distribution equal to the original distribution
288
289 const Bool_t useorigdist = fHistNom->GetHist().GetEntries()==0;
290 TH1 *hnp = useorigdist ? (TH1*)(fHistOrig->GetHist()).Clone() :
291 &fHistNom->GetHist();
292
293 TH1 &hn = *hnp;
294 //--------------------
295
296 // normalize to number of counts in primary distribution
297 hn.Scale(1./hn.Integral());
298
299 MH3 *h3 = NULL;
300 TH1 &hist = InitHistogram(h3);
301
302 hist.Divide(&hn, &ho);
303 hist.Scale(1./hist.GetMaximum());
304
305 if (fCanvas)
306 {
307 fCanvas->Clear();
308 fCanvas->Divide(2,2);
309
310 fCanvas->cd(1);
311 gPad->SetBorderMode(0);
312 hn.DrawCopy();
313
314 fCanvas->cd(2);
315 gPad->SetBorderMode(0);
316 ho.DrawCopy();
317 }
318 hn.Multiply(&ho, &hist);
319 hn.SetTitle("Resulting Nominal Distribution");
320
321 if (fNumMax>0)
322 {
323 *fLog << inf;
324 *fLog << "MFEventSelector2::PrepareHistograms:" << endl;
325 *fLog << " - requested number of events = " << fNumMax << endl;
326 *fLog << " - maximum number of events possible = " << hn.Integral() << endl;
327
328 if (fNumMax > hn.Integral())
329 {
330 *fLog << warn << "WARNING - Requested no.of events (" << fNumMax;
331 *fLog << ") is too high... reduced to " << hn.Integral() << endl;
332 }
333 else
334 hn.Scale(fNumMax/hn.Integral());
335 }
336
337 hn.SetEntries(hn.Integral()+0.5);
338 if (fCanvas)
339 {
340 fCanvas->cd(3);
341 gPad->SetBorderMode(0);
342 hn.DrawCopy();
343
344 fCanvas->cd(4);
345 gPad->SetBorderMode(0);
346 fHistRes->Draw();
347 }
348 delete h3;
349
350 const Int_t num = fHistRes->GetNbins();
351 fIs.Set(num);
352 fNom.Set(num);
353 for (int i=0; i<num; i++)
354 {
355 fIs[i] = (Long_t)(ho.GetBinContent(i+1)+0.5);
356 fNom[i] = (Long_t)(hn.GetBinContent(i+1)+0.5);
357 }
358
359 if (useorigdist)
360 delete hnp;
361}
362
363// --------------------------------------------------------------------------
364//
365// PreProcess the data rules extracted from the MH3 nominal distribution
366//
367Bool_t MFEventSelector2::PreProcessData(MParList *parlist)
368{
369 switch (fHistNom->GetDimension())
370 {
371 case 3:
372 if (!fDataZ.PreProcess(parlist))
373 {
374 *fLog << err << "Preprocessing of rule for z-axis failed... abort." << endl;
375 return kFALSE;
376 }
377 // FALLTHROUGH!
378 case 2:
379 if (!fDataY.PreProcess(parlist))
380 {
381 *fLog << err << "Preprocessing of rule for y-axis failed... abort." << endl;
382 return kFALSE;
383 }
384 // FALLTHROUGH!
385 case 1:
386 if (!fDataX.PreProcess(parlist))
387 {
388 *fLog << err << "Preprocessing of rule for x-axis failed... abort." << endl;
389 return kFALSE;
390 }
391 }
392 return kTRUE;
393}
394
395// --------------------------------------------------------------------------
396//
397// PreProcess the filter. Means:
398// 1) Preprocess the rules
399// 2) Read The present distribution from the file.
400// 3) Initialize the histogram for the resulting distribution
401// 4) Prepare the random selection
402// 5) Repreprocess the reading and filter task.
403//
404Int_t MFEventSelector2::PreProcess(MParList *parlist)
405{
406 memset(fCounter, 0, sizeof(fCounter));
407
408 MTaskList *tasklist = (MTaskList*)parlist->FindObject("MTaskList");
409 if (!tasklist)
410 {
411 *fLog << err << "MTaskList not found... abort." << endl;
412 return kFALSE;
413 }
414
415 if (!PreProcessData(parlist))
416 return kFALSE;
417
418 fHistNom->SetTitle(fHistIsProbability ? "ProbabilityDistribution" :
419 "Users Nominal Distribution");
420
421 if (fHistIsProbability)
422 return kTRUE;
423
424 InitHistogram(fHistOrig);
425 InitHistogram(fHistRes);
426
427 fHistOrig->SetTitle("Primary Distribution");
428 fHistRes->SetTitle("Resulting Distribution");
429
430 // Initialize online display if requested
431 fCanvas = fDisplay ? &fDisplay->AddTab(GetName()) : NULL;
432 if (fCanvas)
433 fHistOrig->Draw();
434
435 // Generate primary distribution
436 MRead *read = (MRead*)tasklist->FindObject("MRead");
437 if (!read)
438 {
439 *fLog << err << "MRead not found in tasklist... abort." << endl;
440 return kFALSE;
441 }
442
443 MFilter *filter = (MFilter*)tasklist->FindObject(fFilterName);
444 if (!filter || !filter->InheritsFrom(MFilter::Class()))
445 {
446 *fLog << inf << "No filter will be used when making the original distribution" << endl;
447 filter = NULL;
448 }
449
450 if (!ReadDistribution(*read, filter))
451 return kFALSE;
452
453 // Prepare histograms and arrays for selection
454 PrepareHistograms();
455
456 *fLog << all << "PreProcess..." << flush;
457
458 if (filter != NULL)
459 {
460 const Int_t rcf = filter->CallPreProcess(parlist);
461 if (rcf!=kTRUE)
462 return rcf;
463 }
464
465 const Int_t rcr = read->CallPreProcess(parlist);
466 return rcr;
467}
468
469// --------------------------------------------------------------------------
470//
471// Part of Process(). Select() at the end checks whether a selection should
472// be done or not. Under-/Overflowbins are rejected.
473//
474Bool_t MFEventSelector2::Select(Int_t bin)
475{
476 // under- and overflow bins are not accepted
477 if (bin<0)
478 return kFALSE;
479
480 Bool_t rc = kFALSE;
481
482 if (gRandom->Rndm()*fIs[bin]<=fNom[bin])
483 {
484 // how many events do we still want to read in this bin
485 fNom[bin]--;
486 rc = kTRUE;
487
488 // fill bin (same as Fill(valx, valy, valz))
489 TH1 &h = fHistRes->GetHist();
490 h.AddBinContent(bin+1);
491 h.SetEntries(h.GetEntries()+1);
492 }
493
494 // how many events are still pending to be read
495 fIs[bin]--;
496
497 return rc;
498}
499
500// --------------------------------------------------------------------------
501//
502Bool_t MFEventSelector2::SelectProb(Int_t ibin) const
503{
504 //
505 // If value is outside histogram range, accept event
506 //
507 return ibin<0 ? kTRUE :
508 fHistNom->GetHist().GetBinContent(ibin+1) > gRandom->Uniform();
509}
510
511// --------------------------------------------------------------------------
512//
513// fIs[i] contains the distribution of the events still to be read from
514// the file. fNom[i] contains the number of events in each bin which
515// are requested.
516// The events are selected by:
517// gRandom->Rndm()*fIs[bin]<=fNom[bin]
518//
519Int_t MFEventSelector2::Process()
520{
521 // get x,y and z (0 if fData not valid)
522 const Double_t valx=fDataX.GetValue();
523 const Double_t valy=fDataY.GetValue();
524 const Double_t valz=fDataZ.GetValue();
525
526 // don't except the event if it is outside the axis range
527 // of the requested distribution
528 const Int_t ibin = fHistNom->FindFixBin(valx, valy, valz)-1;
529 if (!fHistIsProbability)
530 {
531 if (ibin < 0)
532 {
533 fResult = kFALSE;
534 fCounter[1]++;
535 return kTRUE;
536 }
537 }
538
539 // check whether a selection should be made
540 fResult = fHistIsProbability ? SelectProb(ibin) : Select(ibin);
541 if (!fResult)
542 {
543 fCounter[2]++;
544 return kTRUE;
545 }
546
547 fCounter[0]++;
548
549 return kTRUE;
550}
551
552// --------------------------------------------------------------------------
553//
554// Update online display if set.
555//
556Int_t MFEventSelector2::PostProcess()
557{
558 //---------------------------------
559
560 if (GetNumExecutions()>0)
561 {
562 *fLog << inf << endl;
563 *fLog << GetDescriptor() << " execution statistics:" << endl;
564 *fLog << dec << setfill(' ');
565
566 *fLog << " " << setw(7) << fCounter[1] << " (" << setw(3)
567 << (int)((Float_t)(fCounter[1]*100)/(Float_t)(GetNumExecutions())+0.5)
568 << "%) Events not selected due to under/over flow" << endl;
569
570 *fLog << " " << setw(7) << fCounter[2] << " (" << setw(3)
571 << (int)((Float_t)(fCounter[2]*100)/(Float_t)(GetNumExecutions())+0.5)
572 << "%) Events not selected due to requested distribution"
573 << endl;
574
575 *fLog << " " << fCounter[0] << " ("
576 << (int)((Float_t)(fCounter[0]*100)/(Float_t)(GetNumExecutions())+0.5)
577 << "%) Events selected" << endl;
578 *fLog << endl;
579 }
580
581 //---------------------------------
582
583 if (fDisplay && fDisplay->HasCanvas(fCanvas))
584 {
585 fCanvas->cd(4);
586 fHistRes->DrawClone("nonew");
587 fCanvas->Modified();
588 fCanvas->Update();
589 }
590
591 return kTRUE;
592}
593
594
595
596
597
598
Note: See TracBrowser for help on using the repository browser.