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

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