source: trunk/MagicSoft/Mars/mfbase/MFEventSelector2.cc@ 5670

Last change on this file since 5670 was 5667, checked in by domingo, 20 years ago
*** empty log message ***
File size: 18.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, 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 "MProgressBar.h" //
119#include "MEvtLoop.h" // MEvtLoop
120#include "MTaskList.h" // MTaskList
121#include "MBinning.h" // MBinning
122#include "MContinue.h" //
123#include "MFillH.h" // MFillH
124#include "MParList.h" // MParList
125#include "MStatusDisplay.h" // MStatusDisplay
126
127#include "MLog.h"
128#include "MLogManip.h"
129
130ClassImp(MFEventSelector2);
131
132using namespace std;
133
134const TString MFEventSelector2::gsDefName = "MFEventSelector2";
135const TString MFEventSelector2::gsDefTitle = "Filter to select events with a given distribution";
136
137// --------------------------------------------------------------------------
138//
139// Constructor. Takes a reference to an MH3 which gives you
140// 1) The nominal distribution. The distribution is renormalized, so
141// that the absolute values do not matter. To crop the distribution
142// to a nominal value of total events use SetNumMax
143// 2) The parameters histogrammed in MH3 are those on which the
144// event selector will work, eg
145// MH3 hist("MMcEvt.fTelescopeTheta", "MMcEvt.fEnergy");
146// Would result in a redistribution of Theta and Energy.
147// 3) Rules are also accepted in the argument of MH3, for instance:
148// MH3 hist("MMcEvt.fTelescopeTheta");
149// would result in redistributing Theta, while
150// MH3 hist("cos(MMcEvt.fTelescopeTheta)");
151// would result in redistributing cos(Theta).
152//
153// If the reference distribution doesn't contain entries (GetEntries()==0)
154// the original distribution will be used as the nominal distribution;
155// note that also in this case a dummy nominal distribution has to be
156// provided in the first argument (the dummy distribution defines the
157// variable(s) of interest, their binnings and their requested ranges;
158// events outside these ranges won't be accepted).
159//
160MFEventSelector2::MFEventSelector2(MH3 &hist, const char *name, const char *title)
161: fHistOrig(NULL), fHistNom(&hist), fHistRes(NULL),
162 fDataX(hist.GetRule('x')), fDataY(hist.GetRule('y')),
163 fDataZ(hist.GetRule('z')), fNumMax(-1), fHistIsProbability(kFALSE),
164 fUseOrigDist(kTRUE)
165{
166 fName = name ? (TString)name : gsDefName;
167 fTitle = title ? (TString)title : gsDefTitle;
168
169 // name of filter to be applied when determining the original distribution
170 // for all data on the input file
171 fFilterName = "FilterSelector2";
172}
173
174// --------------------------------------------------------------------------
175//
176// Delete fHistRes if instatiated
177//
178MFEventSelector2::~MFEventSelector2()
179{
180 if (fHistRes)
181 delete fHistRes;
182}
183
184//---------------------------------------------------------------------------
185//
186// Recreate a MH3 from fHistNom used as a template. Copy the Binning
187// from fHistNom to the new histogram, and return a pointer to the TH1
188// base class of the MH3.
189//
190TH1 &MFEventSelector2::InitHistogram(MH3* &hist)
191{
192 // if fHistRes is already allocated delete it first
193 if (hist)
194 delete hist;
195
196 // duplicate the fHistNom histogram
197 hist = (MH3*)fHistNom->New();
198
199 // copy binning from one histogram to the other one
200 MH::SetBinning(&hist->GetHist(), &fHistNom->GetHist());
201
202 return hist->GetHist();
203}
204
205// --------------------------------------------------------------------------
206//
207// Try to read the present distribution from the file. Therefore the
208// Reading task of the present loop is used in a new eventloop.
209//
210Bool_t MFEventSelector2::ReadDistribution(MRead &read, MFilter *filter)
211{
212 if (read.GetEntries() > kMaxUInt) // FIXME: LONG_MAX ???
213 {
214 *fLog << err << "kIntMax exceeded." << endl;
215 return kFALSE;
216 }
217
218 *fLog << inf << underline << endl;
219 *fLog << "MFEventSelector2::ReadDistribution:" << endl;
220 *fLog << "**********************" << endl;
221 *fLog << " - Start of eventloop to generate the original distribution..."
222 << endl;
223
224 if (filter != NULL)
225 {
226 *fLog << " filter used : " << filter->GetName()
227 << endl;
228 }
229
230
231 MEvtLoop run("ReadDistribution");
232 //MProgressBar bar;
233 //run.SetProgressBar(&bar);
234
235 MParList plist;
236 MTaskList tlist;
237 plist.AddToList(&tlist);
238 run.SetParList(&plist);
239
240 MBinning binsx("BinningMH3X");
241 MBinning binsy("BinningMH3Y");
242 MBinning binsz("BinningMH3Z");
243 binsx.SetEdges(fHistNom->GetHist(), 'x');
244 binsy.SetEdges(fHistNom->GetHist(), 'y');
245 binsz.SetEdges(fHistNom->GetHist(), 'z');
246 plist.AddToList(&binsx);
247 plist.AddToList(&binsy);
248 plist.AddToList(&binsz);
249
250 MFillH fill(fHistOrig);
251 fill.SetName("FillHistOrig");
252 fill.SetBit(MFillH::kDoNotDisplay);
253 tlist.AddToList(&read);
254
255 MContinue contfilter(filter);
256 if (filter != NULL)
257 {
258 contfilter.SetName("ContFilter");
259 tlist.AddToList(&contfilter);
260 }
261
262 tlist.AddToList(&fill);
263 run.SetDisplay(fDisplay);
264 if (!run.Eventloop())
265 {
266 *fLog << err << dbginf
267 << "Evtloop in MFEventSelector2::ReadDistribution failed."
268 << endl;
269 return kFALSE;
270 }
271
272 tlist.PrintStatistics(0, kTRUE);
273
274 *fLog << inf;
275 *fLog << "MFEventSelector2::ReadDistribution:" << endl;
276 *fLog << " - Original distribution has "
277 << fHistOrig->GetHist().GetEntries() << " entries." << endl;
278 *fLog << " - End of eventloop to generate the original distribution."
279 << endl;
280 *fLog << "**********************" << endl;
281
282 return read.Rewind();
283}
284
285// --------------------------------------------------------------------------
286//
287// After reading the histograms the arrays used for the random event
288// selection are created. If a MStatusDisplay is set the histograms are
289// displayed there.
290//
291void MFEventSelector2::PrepareHistograms()
292{
293 TH1 &ho = fHistOrig->GetHist();
294
295 //-------------------
296 // if requested
297 // set the nominal distribution equal to the original distribution
298
299 const Bool_t fUseOrigDist = fHistNom->GetHist().GetEntries()==0;
300 TH1 *hnp = fUseOrigDist ? (TH1*)(fHistOrig->GetHist()).Clone() :
301 &fHistNom->GetHist();
302
303 TH1 &hn = *hnp;
304 //--------------------
305
306 // normalize to number of counts in primary distribution
307 hn.Scale(1./hn.Integral());
308
309 MH3 *h3 = NULL;
310 TH1 &hist = InitHistogram(h3);
311
312 hist.Divide(&hn, &ho);
313 hist.Scale(1./hist.GetMaximum());
314
315 if (fCanvas)
316 {
317 fCanvas->Clear();
318 fCanvas->Divide(2,2);
319
320 fCanvas->cd(1);
321 gPad->SetBorderMode(0);
322 hn.DrawCopy();
323
324 fCanvas->cd(2);
325 gPad->SetBorderMode(0);
326 ho.DrawCopy();
327 }
328 hn.Multiply(&ho, &hist);
329 hn.SetTitle("Resulting Nominal Distribution");
330
331 if (fNumMax>0)
332 {
333 *fLog << inf;
334 *fLog << "MFEventSelector2::PrepareHistograms:" << endl;
335 *fLog << " - requested number of events = " << fNumMax << endl;
336 *fLog << " - maximum number of events possible = " << hn.Integral() << endl;
337
338 if (fNumMax > hn.Integral())
339 {
340 *fLog << warn << "WARNING - Requested no.of events (" << fNumMax;
341 *fLog << ") is too high... reduced to " << hn.Integral() << endl;
342 }
343 else
344 hn.Scale(fNumMax/hn.Integral());
345 }
346
347 hn.SetEntries(hn.Integral()+0.5);
348 if (fCanvas)
349 {
350 fCanvas->cd(3);
351 gPad->SetBorderMode(0);
352 hn.DrawCopy();
353
354 fCanvas->cd(4);
355 gPad->SetBorderMode(0);
356 fHistRes->Draw();
357 }
358 delete h3;
359
360 const Int_t num = fHistRes->GetNbins();
361 fIs.Set(num);
362 fNom.Set(num);
363 for (int i=0; i<num; i++)
364 {
365 fIs[i] = (Long_t)(ho.GetBinContent(i+1)+0.5);
366 fNom[i] = (Long_t)(hn.GetBinContent(i+1)+0.5);
367 }
368
369 if (fUseOrigDist)
370 delete hnp;
371}
372
373// --------------------------------------------------------------------------
374//
375// PreProcess the data rules extracted from the MH3 nominal distribution
376//
377Bool_t MFEventSelector2::PreProcessData(MParList *parlist)
378{
379 switch (fHistNom->GetDimension())
380 {
381 case 3:
382 if (!fDataZ.PreProcess(parlist))
383 {
384 *fLog << err << "Preprocessing of rule for z-axis failed... abort." << endl;
385 return kFALSE;
386 }
387 // FALLTHROUGH!
388 case 2:
389 if (!fDataY.PreProcess(parlist))
390 {
391 *fLog << err << "Preprocessing of rule for y-axis failed... abort." << endl;
392 return kFALSE;
393 }
394 // FALLTHROUGH!
395 case 1:
396 if (!fDataX.PreProcess(parlist))
397 {
398 *fLog << err << "Preprocessing of rule for x-axis failed... abort." << endl;
399 return kFALSE;
400 }
401 }
402 return kTRUE;
403}
404
405// --------------------------------------------------------------------------
406//
407// PreProcess the filter. Means:
408// 1) Preprocess the rules
409// 2) Read The present distribution from the file.
410// 3) Initialize the histogram for the resulting distribution
411// 4) Prepare the random selection
412// 5) Repreprocess the reading and filter task.
413//
414Int_t MFEventSelector2::PreProcess(MParList *parlist)
415{
416 memset(fCounter, 0, sizeof(fCounter));
417
418 MTaskList *tasklist = (MTaskList*)parlist->FindObject("MTaskList");
419 if (!tasklist)
420 {
421 *fLog << err << "MTaskList not found... abort." << endl;
422 return kFALSE;
423 }
424
425 if (!PreProcessData(parlist))
426 return kFALSE;
427
428 fHistNom->SetTitle(fHistIsProbability ? "ProbabilityDistribution" :
429 "Users Nominal Distribution");
430
431 if (fHistIsProbability)
432 return kTRUE;
433
434 InitHistogram(fHistOrig);
435 InitHistogram(fHistRes);
436
437 fHistOrig->SetTitle("Primary Distribution");
438 fHistRes->SetTitle("Resulting Distribution");
439
440 // Initialize online display if requested
441 fCanvas = fDisplay ? &fDisplay->AddTab(GetName()) : NULL;
442 if (fCanvas)
443 fHistOrig->Draw();
444
445 // Generate primary distribution
446 MRead *read = (MRead*)tasklist->FindObject("MRead");
447 if (!read)
448 {
449 *fLog << err << "MRead not found... abort." << endl;
450 return kFALSE;
451 }
452
453 MFilter *filter = (MFilter*)tasklist->FindObject(fFilterName);
454 if (!filter)
455 {
456 *fLog << inf
457 << "No filter will be used when making the original distribution"
458 << endl;
459 filter = NULL;
460 }
461
462
463 if (!ReadDistribution(*read, filter))
464 return kFALSE;
465
466
467 // Prepare histograms and arrays for selection
468 PrepareHistograms();
469
470 *fLog << "MFEventSelector2::PreProcess; call PreProcess() for read and filter object again"
471 << endl;
472 Int_t rcr = read->CallPreProcess(parlist);
473 Int_t rcf = filter->CallPreProcess(parlist);
474
475 *fLog << "rcr, rcf = " << rcr << ", " << rcf << endl;
476
477 return rcf*rcr;
478}
479
480// --------------------------------------------------------------------------
481//
482// Part of Process(). Select() at the end checks whether a selection should
483// be done or not. Under-/Overflowbins are rejected.
484//
485Bool_t MFEventSelector2::Select(Int_t bin)
486{
487 // under- and overflow bins are not accepted
488 if (bin<0)
489 return kFALSE;
490
491 Bool_t rc = kFALSE;
492
493 if (gRandom->Rndm()*fIs[bin]<=fNom[bin])
494 {
495 // how many events do we still want to read in this bin
496 fNom[bin] -= 1;
497 rc = kTRUE;
498
499 // fill bin (same as Fill(valx, valy, valz))
500 TH1 &h = fHistRes->GetHist();
501 h.AddBinContent(bin+1);
502 h.SetEntries(h.GetEntries()+1);
503 }
504
505 // how many events are still pending to be read
506 fIs[bin] -= 1;
507
508 return rc;
509}
510
511// --------------------------------------------------------------------------
512//
513Bool_t MFEventSelector2::SelectProb(Int_t ibin) const
514{
515 //
516 // If value is outside histogram range, accept event
517 //
518 return ibin<0 ? kTRUE :
519 fHistNom->GetHist().GetBinContent(ibin) > gRandom->Uniform();
520}
521
522// --------------------------------------------------------------------------
523//
524// fIs[i] contains the distribution of the events still to be read from
525// the file. fNom[i] contains the number of events in each bin which
526// are requested.
527// The events are selected by:
528// gRandom->Rndm()*fIs[bin]<=fNom[bin]
529//
530Int_t MFEventSelector2::Process()
531{
532 // get x,y and z (0 if fData not valid)
533 const Double_t valx=fDataX.GetValue();
534 const Double_t valy=fDataY.GetValue();
535 const Double_t valz=fDataZ.GetValue();
536
537 // don't except the event if it is outside the axis range
538 // of the requested distribution
539 const Int_t ibin = fHistNom->FindFixBin(valx, valy, valz)-1;
540 if (!fHistIsProbability)
541 {
542 if (ibin < 0)
543 {
544 fResult = kFALSE;
545 fCounter[1] += 1;
546 return kTRUE;
547 }
548 }
549
550 // check whether a selection should be made
551 fResult = fHistIsProbability ? SelectProb(ibin) : Select(ibin);
552 if (!fResult)
553 {
554 fCounter[2] += 1;
555 return kTRUE;
556 }
557
558 fCounter[0] += 1;
559
560 return kTRUE;
561}
562
563// --------------------------------------------------------------------------
564//
565// Update online display if set.
566//
567Int_t MFEventSelector2::PostProcess()
568{
569 //---------------------------------
570
571 if (GetNumExecutions()>0)
572 {
573 *fLog << inf << endl;
574 *fLog << GetDescriptor() << " execution statistics:" << endl;
575 *fLog << dec << setfill(' ');
576
577 *fLog << " " << setw(7) << fCounter[1] << " (" << setw(3)
578 << (int)((Float_t)(fCounter[1]*100)/(Float_t)(GetNumExecutions())+0.5)
579 << "%) Events not selected due to under/over flow" << endl;
580
581 *fLog << " " << setw(7) << fCounter[2] << " (" << setw(3)
582 << (int)((Float_t)(fCounter[2]*100)/(Float_t)(GetNumExecutions())+0.5)
583 << "%) Events not selected due to requested distribution"
584 << endl;
585
586 *fLog << " " << fCounter[0] << " ("
587 << (int)((Float_t)(fCounter[0]*100)/(Float_t)(GetNumExecutions())+0.5)
588 << "%) Events selected" << endl;
589 *fLog << endl;
590 }
591
592 //---------------------------------
593
594 if (fDisplay && fDisplay->HasCanvas(fCanvas))
595 {
596 fCanvas->cd(4);
597 fHistRes->DrawClone("nonew");
598 fCanvas->Modified();
599 fCanvas->Update();
600 }
601
602 return kTRUE;
603}
604
605
606
607
608
609
Note: See TracBrowser for help on using the repository browser.