source: branches/AddingGoogleTestEnvironment/mfbase/MFEventSelector2.cc@ 18147

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