source: trunk/Mars/mtools/MTFillMatrix.cc@ 9969

Last change on this file since 9969 was 9868, checked in by tbretz, 14 years ago
Improved handling of nagative number of events in MTFillMatrix.
File size: 14.3 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, 12/2003 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2005
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MTFillMatrix
28//
29// Use this tool to fill eg trainings and test-matrices, while the matrix
30// to be filled can be a real matrix (MHMatrix) or a file (MWriteRootFile)
31// or both.
32//
33// First create a reference histogram (MH3). For more details see
34// MFEventSelector2 which is used to select events according to the
35// reference histogram.
36//
37// If no reference histogram is available the number of events are
38// randomly choosen from the sample with a probability which fits
39// the total destination number of events.
40//
41// Here is an example of how to choose 1000 events somehow distributed in
42// size from a file.
43// -----------------------------------------------------------------------
44//
45// MH3 ref("MHillas.fSize"); // choose a predefined size distribution
46// // Now setup the distribution
47//
48// MHMatrix matrix1; // create matrix to fill
49// matrix.AddColumn("MHillas.fWidth"); // setup columns of your matrix
50//
51// MReadMarsFile read("myfile.root"); // Setup your 'reader'
52// read.DisableAutoScheme(); // make sure everything is read
53//
54// MTFillMatrix fill(&ref); // setup MTFillMatrix
55// fill.SetNumDestEvents1(1000); // setup number of events to select
56// fill.SetDestMatrix1(&matrix1); // setup destination matrix
57// if (!fill.Process()) // check if everything worked
58// return;
59// fill.WriteMatrix1("myoutput.root"); // write matrix to file
60//
61//
62// To get two matrices instead of one (splitted randomly) you can add
63// the following before calling Process():
64// ------------------------------------------------------------------------
65//
66// MHMatrix matrix2;
67// fill.SetNumDestEvents2(500); // setup number of events to select
68// fill.SetDestMatrix2(&matrix2); // setup destination matrix
69// [...]
70// fill.WriteMatrix2("myoutput2.root");
71//
72//
73// To write both matrices into a single file use:
74// ----------------------------------------------
75//
76// fill.WriteMatrices("myfile.root");
77//
78//
79// Task List execution
80// ----------------------------------------------
81//
82// The tasklist is excuted in the follwowing order:
83// - fReader set by SetReader
84// - fPreTasks in the order as set with the SetPreTask functions
85// - fPreCuts in the order as set with the SetPreCut functions
86// - Selection the event selection
87// - fPostTasks in the order as set with the SetPostTask functions
88// - Fill Matrix
89// - Write output
90//
91/////////////////////////////////////////////////////////////////////////////
92#include "MTFillMatrix.h"
93
94#include <TFile.h>
95#include <TMath.h>
96
97// environment
98#include "MHMatrix.h"
99
100#include "MLog.h"
101#include "MLogManip.h"
102
103// eventloop
104#include "MParList.h"
105#include "MTaskList.h"
106#include "MEvtLoop.h"
107
108// tasks
109#include "MRead.h"
110#include "MFillH.h"
111#include "MContinue.h"
112
113// filters
114#include "MFDataPhrase.h"
115#include "MFilterList.h"
116#include "MFEventSelector.h"
117#include "MFEventSelector2.h"
118
119ClassImp(MTFillMatrix);
120
121using namespace std;
122
123// --------------------------------------------------------------------------
124//
125// Print Size and contained columns.
126// Check whether the number of generated events is compatible with
127// the number of requested events.
128//
129Bool_t MTFillMatrix::CheckResult(MHMatrix *m, Int_t num) const
130{
131 if (!m || num==0)
132 return kTRUE;
133
134 m->Print("SizeCols");
135
136 if (num<0)
137 return kTRUE;
138
139 const Int_t generated = m->GetM().GetNrows();
140 if (TMath::Abs(generated-num) <= TMath::Sqrt(9.0*num))
141 return kTRUE;
142
143 *fLog << warn << "WARNING - No. of generated events (";
144 *fLog << generated << ") incompatible with requested events (";
145 *fLog << num << ") for " << m->GetDescriptor() << endl;
146
147 return kFALSE;
148}
149
150// --------------------------------------------------------------------------
151//
152// Write the given MHMatrix with its name as default name to a
153// file fname.
154//
155Bool_t MTFillMatrix::WriteMatrix(MHMatrix *m, const TString &fname, Int_t i) const
156{
157 if (!m)
158 {
159 *fLog << "ERROR - Unable to write matrix #" << i << " (=NULL)... ignored." << endl;
160 return kFALSE;
161 }
162 if (fname.IsNull())
163 {
164 *fLog << "ERROR - Unable to write matrix, file name empty." << endl;
165 return kFALSE;
166 }
167
168 TFile file(fname, "RECREATE", m->GetTitle());
169 m->Write();
170 return kTRUE;
171}
172
173void MTFillMatrix::Init(const char *name, const char *title)
174{
175 fName = name ? name : "MFillMatrix";
176 fTitle = title ? title : "Tool to fill MHMatrix from file";
177}
178
179MTFillMatrix::MTFillMatrix(const char *name, const char *title)
180: fReference(0), fReader(0), fDestMatrix1(0), fDestMatrix2(0),
181 fNumDestEvents1(0), fNumDestEvents2(0), fNumMaxEvents(0),
182 fWriteFile1(0), fWriteFile2(0)
183{
184 Init(name, title);
185}
186
187// --------------------------------------------------------------------------
188//
189// Constructor. Takes an MH3 as argument. This MH3 is the reference
190// distribution to fill the matrix. More information can be found
191// at MFEventSelector2 which is used to select the events.
192//
193// If no MH3 *ref is given the events are randomly selected from the
194// total sample - this may result in samples which don't have exactly
195// the predefined size, but it is much faster.
196//
197MTFillMatrix::MTFillMatrix(const MH3 *ref, const char *name, const char *title)
198: fReference(0), fReader(0), fDestMatrix1(0), fDestMatrix2(0),
199 fNumDestEvents1(0), fNumDestEvents2(0), fNumMaxEvents(0),
200 fWriteFile1(0), fWriteFile2(0)
201{
202 Init(name, title);
203 if (ref)
204 fReference = (MH3*)ref->Clone();
205}
206
207MTFillMatrix::~MTFillMatrix()
208{
209 if (fReference)
210 delete fReference;
211}
212
213//------------------------------------------------------------------------
214//
215// Function serving AddPreCuts, AddPreTasks and AddPostTasks
216//
217void MTFillMatrix::Add(const TList &src, const TClass *cls, TList &dest)
218{
219 TIter Next(&src);
220 TObject *obj=0;
221 while ((obj=Next()))
222 if (obj->InheritsFrom(cls))
223 dest.Add(obj);
224}
225
226//------------------------------------------------------------------------
227//
228// Add a cut which is used to fill the matrix, eg "MMcEvt.fOartId<1.5"
229// (The rule is applied, nit inverted: The matrix is filled with
230// the events fullfilling the condition)
231//
232void MTFillMatrix::AddPreCut(const char *rule)
233{
234 MFilter *f = new MFDataPhrase(rule);
235 f->SetBit(kCanDelete);
236 AddPreCut(f);
237}
238
239//------------------------------------------------------------------------
240//
241// Add a cut which is used to fill the matrix. If kCanDelete is set
242// MJOptimize takes the ownership.
243//
244void MTFillMatrix::AddPreCut(MFilter *f)
245{
246 fPreCuts.Add(f);
247}
248
249//------------------------------------------------------------------------
250//
251// Add all entries deriving from MFilter from list to PreCuts.
252// The ownership is not affected.
253//
254void MTFillMatrix::AddPreCuts(const TList &list)
255{
256 Add(list, MFilter::Class(), fPreCuts);
257}
258
259//------------------------------------------------------------------------
260//
261// Add a task which is executed before the precuts. If kCanDelete is set
262// MJOptimize takes the ownership.
263//
264void MTFillMatrix::AddPreTask(MTask *t)
265{
266 fPreTasks.Add(t);
267}
268
269//------------------------------------------------------------------------
270//
271// Add all entries deriving from MTask from list to PreTasks.
272// The ownership is not affected.
273//
274void MTFillMatrix::AddPreTasks(const TList &list)
275{
276 Add(list, MTask::Class(), fPreTasks);
277}
278
279//------------------------------------------------------------------------
280//
281// Add a task which is executed after the precuts. If kCanDelete is set
282// MJOptimize takes the ownership.
283//
284void MTFillMatrix::AddPostTask(MTask *t)
285{
286 fPostTasks.Add(t);
287}
288
289//------------------------------------------------------------------------
290//
291// Add all entries deriving from MTask from list to PostTasks.
292// The ownership is not affected.
293//
294void MTFillMatrix::AddPostTasks(const TList &list)
295{
296 Add(list, MTask::Class(), fPostTasks);
297}
298
299// --------------------------------------------------------------------------
300//
301// Fill the matrix (FIXME: Flow diagram missing)
302//
303Bool_t MTFillMatrix::Process(const MParList &parlist)
304{
305 if (!fReader)
306 {
307 *fLog << err << "ERROR - No task to read data was given... abort." << endl;
308 return kFALSE;
309 }
310
311 *fLog << inf;
312 fLog->Separator(GetDescriptor());
313 *fLog << "Fill " << fDestMatrix1->GetDescriptor() << " with ";
314 if (fNumDestEvents1<0)
315 *fLog << "all events";
316 else
317 *fLog << fNumDestEvents1;
318 cout << "." << endl;
319 if (fDestMatrix2)
320 {
321 *fLog << "Fill " << fDestMatrix2->GetDescriptor() << " with ";
322 if (fNumDestEvents2<0)
323 *fLog << "all events";
324 else
325 *fLog << fNumDestEvents2;
326 cout << "." << endl;
327 }
328 *fLog << "Distribution choosen ";
329 if (fReference && fReference->GetHist().GetEntries()>0)
330 *fLog << "from " << fReference->GetDescriptor();
331 else
332 *fLog << "randomly";
333 *fLog << endl;
334
335 //
336 // Create parameter list and task list, add tasklist to parlist
337 //
338 //parlist.Print();
339 MParList plist(parlist);
340 MTaskList tlist;
341 plist.AddToList(&tlist);
342
343 //
344 // A selector to select a given number of events from a sample
345 //
346 // FIXME: Merge MFEventSelector and MFEventSelector2
347 MFilter *selector=0;
348 if (fNumDestEvents1>0 || fNumDestEvents2>0)
349 {
350 if (fReference)
351 {
352 // Case of a reference/nominal distribution
353 // The events must be read before selection
354 MFEventSelector2 *sel = new MFEventSelector2(*fReference);
355 sel->SetNumMax(fNumDestEvents1+fNumDestEvents2);
356 sel->SetInverted();
357
358 selector = sel;
359 }
360 else
361 {
362 // Case of a random distribution
363 // The events can be selected before reading
364 MFEventSelector *sel = new MFEventSelector;
365 sel->SetNumSelectEvts(fNumDestEvents1+fNumDestEvents2);
366 fReader->SetSelector(sel);
367
368 selector = sel;
369 }
370 }
371
372 //
373 // Continue for PreCuts
374 //
375 MFilterList list;
376 list.SetName("PreCuts");
377 if (!list.AddToList(fPreCuts))
378 *fLog << err << "ERROR - Calling MFilterList::AddToList for fPreCuts failed!" << endl;
379
380 MContinue cont0(&list);
381 cont0.SetInverted();
382
383 //
384 // Continue for all events which are not (SetInverted())
385 // selected by the 'selector'
386 //
387 MContinue cont(selector);
388
389 //
390 // Create a filter doing a random split
391 //
392 const Double_t prob = (Double_t)fNumDestEvents1/(fNumDestEvents1+fNumDestEvents2);
393 MFEventSelector split;
394 split.SetSelectionRatio(prob);
395
396 //
397 // Create the logical inverted filter for 'split'
398 //
399 MFilterList invsplit;
400 invsplit.AddToList(&split);
401 invsplit.SetInverted();
402
403 //
404 // The two tasks filling the two matrices
405 //
406 MFillH fill1(fDestMatrix1);
407 MFillH fill2(fDestMatrix2);
408 fill1.SetFilter(&split);
409 fill2.SetFilter(&invsplit);
410
411 // entries in MTaskList
412 tlist.AddToList(fReader); // Read events
413 tlist.AddToList(fPreTasks, 0); // PreTasks
414 if (fPreCuts.GetEntries()>0)
415 tlist.AddToList(&cont0); // PreCuts
416 if (fReference && selector)
417 tlist.AddToList(&cont); // select a sample of events
418 tlist.AddToList(&invsplit); // process invsplit (which implicitly processes split)
419 tlist.AddToList(fPostTasks, 0); // PostTasks
420 if (fDestMatrix1)
421 tlist.AddToList(&fill1); // fill matrix 1
422 if (fDestMatrix2)
423 tlist.AddToList(&fill2); // fill matrix 2
424 if (fWriteFile1)
425 {
426 fWriteFile1->SetFilter(&split);
427 tlist.AddToList(fWriteFile1);
428 }
429 if (fWriteFile2)
430 {
431 fWriteFile2->SetFilter(&invsplit);
432 tlist.AddToList(fWriteFile2);
433 }
434
435 tlist.SetAccelerator(MTask::kAccDontReset|MTask::kAccDontTime);
436
437 //
438 // Execute the eventloop
439 //
440 MEvtLoop evtloop(fName);
441 evtloop.SetParList(&plist);
442 evtloop.SetDisplay(fDisplay);
443 evtloop.SetLogStream(fLog);
444
445 const Bool_t rc = evtloop.Eventloop(fNumMaxEvents);
446
447 if (selector)
448 delete selector;
449
450 if (!rc)
451 {
452 *fLog << err << GetDescriptor() << ": Failed." << endl;
453 return kFALSE;
454 }
455
456 // Check the result of filling...
457 CheckResult(fDestMatrix1, fNumDestEvents1);
458 CheckResult(fDestMatrix2, fNumDestEvents2);
459
460 *fLog << inf << GetDescriptor() << ": Done." << endl;
461 return kTRUE;
462}
463
464// --------------------------------------------------------------------------
465//
466// Write both matrices to a file. Return kFALSE if writing one of them
467// failed or both have the same name.
468//
469Bool_t MTFillMatrix::WriteMatrices(const TString &fname) const
470{
471 if (fDestMatrix1 && fDestMatrix2 &&
472 (TString)fDestMatrix1->GetName()==(TString)fDestMatrix2->GetName())
473 {
474 *fLog << "ERROR - Cannot write matrices (both have the same name)... ignored." << endl;
475 return kFALSE;
476 }
477
478 return WriteMatrix1(fname) && WriteMatrix2(fname);
479}
480
481Int_t MTFillMatrix::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
482{
483 Bool_t rc = kFALSE;
484 if (IsEnvDefined(env, prefix, "NumDestEvents1", print))
485 {
486 rc = kTRUE;
487 SetNumDestEvents1(GetEnvValue(env, prefix, "NumDestEvents1", fNumDestEvents1));
488 }
489 if (IsEnvDefined(env, prefix, "NumDestEvents2", print))
490 {
491 rc = kTRUE;
492 SetNumDestEvents2(GetEnvValue(env, prefix, "NumDestEvents2", fNumDestEvents2));
493 }
494 return rc;
495}
Note: See TracBrowser for help on using the repository browser.