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

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