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

Last change on this file since 5368 was 5366, checked in by moralejo, 20 years ago
*** empty log message ***
File size: 15.4 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//
152
153MFEventSelector2::MFEventSelector2(MH3 &hist, const char *name, const char *title)
154: fHistOrig(NULL), fHistNom(&hist), fHistRes(NULL),
155 fDataX(hist.GetRule('x')), fDataY(hist.GetRule('y')),
156 fDataZ(hist.GetRule('z')), fNumMax(-1)
157{
158 fName = name ? (TString)name : gsDefName;
159 fTitle = title ? (TString)title : gsDefTitle;
160}
161
162// --------------------------------------------------------------------------
163//
164// Delete fHistRes if instatiated
165//
166MFEventSelector2::~MFEventSelector2()
167{
168 if (fHistRes)
169 delete fHistRes;
170}
171
172//---------------------------------------------------------------------------
173//
174// Recreate a MH3 from fHistNom used as a template. Copy the Binning
175// from fHistNom to the new histogram, and return a pointer to the TH1
176// base class of the MH3.
177//
178TH1 &MFEventSelector2::InitHistogram(MH3* &hist)
179{
180 // if fHistRes is already allocated delete it first
181 if (hist)
182 delete hist;
183
184 // duplicate the fHistNom histogram
185 hist = (MH3*)fHistNom->New();
186
187 // copy binning from one histogram to the other one
188 MH::SetBinning(&hist->GetHist(), &fHistNom->GetHist());
189
190 return hist->GetHist();
191}
192
193// --------------------------------------------------------------------------
194//
195// Try to read the present distribution from the file. Therefore the
196// Reading task of the present loop is used in a new eventloop.
197//
198Bool_t MFEventSelector2::ReadDistribution(MRead &read)
199{
200 if (read.GetEntries() > kMaxUInt) // FIXME: LONG_MAX ???
201 {
202 *fLog << err << "kIntMax exceeded." << endl;
203 return kFALSE;
204 }
205
206 *fLog << inf << underline << endl;
207 *fLog << "MFEventSelector2::ReadDistribution:" << endl;
208 *fLog << " - Start of eventloop to generate the original distribution..." << endl;
209
210 MEvtLoop run(GetName());
211 MParList plist;
212 MTaskList tlist;
213 plist.AddToList(&tlist);
214 run.SetParList(&plist);
215
216 MBinning binsx("BinningMH3X");
217 MBinning binsy("BinningMH3Y");
218 MBinning binsz("BinningMH3Z");
219 binsx.SetEdges(fHistNom->GetHist(), 'x');
220 binsy.SetEdges(fHistNom->GetHist(), 'y');
221 binsz.SetEdges(fHistNom->GetHist(), 'z');
222 plist.AddToList(&binsx);
223 plist.AddToList(&binsy);
224 plist.AddToList(&binsz);
225
226 MFillH fill(fHistOrig);
227 fill.SetBit(MFillH::kDoNotDisplay);
228 tlist.AddToList(&read);
229 tlist.AddToList(&fill);
230 run.SetDisplay(fDisplay);
231 if (!run.Eventloop())
232 {
233 *fLog << err << dbginf << "Evtloop in MFEventSelector2::ReadDistribution failed." << endl;
234 return kFALSE;
235 }
236
237 tlist.PrintStatistics();
238
239 *fLog << inf;
240 *fLog << "MFEventSelector2::ReadDistribution:" << endl;
241 *fLog << " - Original distribution has " << fHistOrig->GetHist().GetEntries() << " entries." << endl;
242 *fLog << " - End of eventloop to generate the original distribution." << endl;
243
244 return read.Rewind();
245}
246
247// --------------------------------------------------------------------------
248//
249// After reading the histograms the arrays used for the random event
250// selection are created. If a MStatusDisplay is set the histograms are
251// displayed there.
252//
253void MFEventSelector2::PrepareHistograms()
254{
255 TH1 &ho = fHistOrig->GetHist();
256
257 //-------------------
258 // if requested
259 // set the nominal distribution equal to the original distribution
260
261 const Bool_t useorigdist = fHistNom->GetHist().GetEntries()==0;
262 TH1 *hnp = useorigdist ? (TH1*)(fHistOrig->GetHist()).Clone() : &fHistNom->GetHist();
263
264 TH1 &hn = *hnp;
265 //--------------------
266
267 // normalize to number of counts in primary distribution
268 hn.Scale(1./hn.Integral());
269
270 MH3 *h3 = NULL;
271 TH1 &hist = InitHistogram(h3);
272
273 hist.Divide(&hn, &ho);
274 hist.Scale(1./hist.GetMaximum());
275
276 if (fCanvas)
277 {
278 fCanvas->Clear();
279 fCanvas->Divide(2,2);
280
281 fCanvas->cd(1);
282 gPad->SetBorderMode(0);
283 hn.DrawCopy();
284
285 fCanvas->cd(2);
286 gPad->SetBorderMode(0);
287 ho.DrawCopy();
288 }
289 hn.Multiply(&ho, &hist);
290 hn.SetTitle("Resulting Nominal Distribution");
291
292 if (fNumMax>0)
293 {
294 *fLog << inf;
295 *fLog << "MFEventSelector2::PrepareHistograms:" << endl;
296 *fLog << " - requested number of events = " << fNumMax << endl;
297 *fLog << " - maximum number of events possible = " << hn.Integral() << endl;
298
299 if (fNumMax > hn.Integral())
300 {
301 *fLog << warn << "WARNING - Requested no.of events (" << fNumMax;
302 *fLog << ") is too high... reduced to " << hn.Integral() << endl;
303 }
304 else
305 hn.Scale(fNumMax/hn.Integral());
306 }
307
308 hn.SetEntries(hn.Integral()+0.5);
309 if (fCanvas)
310 {
311 fCanvas->cd(3);
312 gPad->SetBorderMode(0);
313 hn.DrawCopy();
314
315 fCanvas->cd(4);
316 gPad->SetBorderMode(0);
317 fHistRes->Draw();
318 }
319 delete h3;
320
321 const Int_t num = fHistRes->GetNbins();
322 fIs.Set(num);
323 fNom.Set(num);
324 for (int i=0; i<num; i++)
325 {
326 fIs[i] = (Long_t)(ho.GetBinContent(i+1)+0.5);
327 fNom[i] = (Long_t)(hn.GetBinContent(i+1)+0.5);
328 }
329
330 if (useorigdist)
331 delete hnp;
332}
333
334// --------------------------------------------------------------------------
335//
336// PreProcess the data rules extracted from the MH3 nominal distribution
337//
338Bool_t MFEventSelector2::PreProcessData(MParList *parlist)
339{
340 switch (fHistNom->GetDimension())
341 {
342 case 3:
343 if (!fDataZ.PreProcess(parlist))
344 {
345 *fLog << err << "Preprocessing of rule for z-axis failed... abort." << endl;
346 return kFALSE;
347 }
348 // FALLTHROUGH!
349 case 2:
350 if (!fDataY.PreProcess(parlist))
351 {
352 *fLog << err << "Preprocessing of rule for y-axis failed... abort." << endl;
353 return kFALSE;
354 }
355 // FALLTHROUGH!
356 case 1:
357 if (!fDataX.PreProcess(parlist))
358 {
359 *fLog << err << "Preprocessing of rule for x-axis failed... abort." << endl;
360 return kFALSE;
361 }
362 }
363 return kTRUE;
364}
365
366// --------------------------------------------------------------------------
367//
368// PreProcess the filter. Means:
369// 1) Preprocess the rules
370// 2) Read The present distribution from the file.
371// 3) Initialize the histogram for the resulting distribution
372// 4) Prepare the random selection
373// 5) Repreprocess the reading task.
374//
375Int_t MFEventSelector2::PreProcess(MParList *parlist)
376{
377 memset(fCounter, 0, sizeof(fCounter));
378
379 MTaskList *tasklist = (MTaskList*)parlist->FindObject("MTaskList");
380 if (!tasklist)
381 {
382 *fLog << err << "MTaskList not found... abort." << endl;
383 return kFALSE;
384 }
385
386 MRead *read = (MRead*)tasklist->FindObject("MRead");
387 if (!read)
388 {
389 *fLog << err << "MRead not found... abort." << endl;
390 return kFALSE;
391 }
392
393 if (!PreProcessData(parlist))
394 return kFALSE;
395
396 InitHistogram(fHistOrig);
397 InitHistogram(fHistRes);
398
399 fHistNom->SetTitle("Users Nominal Distribution");
400 fHistOrig->SetTitle("Primary Distribution");
401 fHistRes->SetTitle("Resulting Distribution");
402
403 // Initialize online display if requested
404 fCanvas = fDisplay ? &fDisplay->AddTab(GetName()) : NULL;
405 if (fCanvas)
406 fHistOrig->Draw();
407
408 // Generate primary distribution
409 if (!ReadDistribution(*read))
410 return kFALSE;
411
412 // Prepare histograms and arrays for selection
413 PrepareHistograms();
414
415 return read->CallPreProcess(parlist);
416}
417
418// --------------------------------------------------------------------------
419//
420// Part of Process(). Select() at the end checks whether a selection should
421// be done or not. Under-/Overflowbins are rejected.
422//
423Bool_t MFEventSelector2::Select(Int_t bin)
424{
425 // under- and overflow bins are not counted
426 if (bin<0)
427 return kFALSE;
428
429 Bool_t rc = kFALSE;
430
431 if (gRandom->Rndm()*fIs[bin]<=fNom[bin])
432 {
433 // how many events do we still want to read in this bin
434 fNom[bin] -= 1;
435 rc = kTRUE;
436
437 // fill bin (same as Fill(valx, valy, valz))
438 TH1 &h = fHistRes->GetHist();
439 h.AddBinContent(bin+1);
440 h.SetEntries(h.GetEntries()+1);
441 }
442
443 // how many events are still pending to be read
444 fIs[bin] -= 1;
445
446 return rc;
447}
448
449// --------------------------------------------------------------------------
450//
451// fIs[i] contains the distribution of the events still to be read from
452// the file. fNom[i] contains the number of events in each bin which
453// are requested.
454// The events are selected by:
455// gRandom->Rndm()*fIs[bin]<=fNom[bin]
456//
457Int_t MFEventSelector2::Process()
458{
459 // get x,y and z (0 if fData not valid)
460 const Double_t valx=fDataX.GetValue();
461 const Double_t valy=fDataY.GetValue();
462 const Double_t valz=fDataZ.GetValue();
463
464 // Get corresponding bin number and check
465 // whether a selection should be made
466 fResult = Select(fHistNom->FindFixBin(valx, valy, valz)-1);
467
468 fCounter[fResult ? 1 : 0]++;
469
470 return kTRUE;
471}
472
473// --------------------------------------------------------------------------
474//
475// Update online display if set.
476//
477Int_t MFEventSelector2::PostProcess()
478{
479 //---------------------------------
480
481 if (GetNumExecutions()>0)
482 {
483 *fLog << inf << endl;
484 *fLog << GetDescriptor() << " execution statistics:" << endl;
485 *fLog << dec << setfill(' ');
486 *fLog << " " << setw(7) << fCounter[1] << " (" << setw(3)
487 << (int)(fCounter[0]*100/GetNumExecutions())
488 << "%) Events not selected" << endl;
489
490 *fLog << " " << fCounter[0] << " ("
491 << (int)(fCounter[1]*100/GetNumExecutions())
492 << "%) Events selected" << endl;
493 *fLog << endl;
494 }
495
496 //---------------------------------
497
498 if (fDisplay && fDisplay->HasCanvas(fCanvas))
499 {
500 fCanvas->cd(4);
501 fHistRes->DrawClone("nonew");
502 fCanvas->Modified();
503 fCanvas->Update();
504 }
505
506 return kTRUE;
507}
Note: See TracBrowser for help on using the repository browser.