source: trunk/MagicSoft/Mars/mtools/MTFillMatrix.cc@ 8006

Last change on this file since 8006 was 7687, checked in by tbretz, 19 years ago
*** empty log message ***
File size: 13.1 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#include "MTFillMatrix.h"
80
81#include <TFile.h>
82
83// environment
84#include "MHMatrix.h"
85
86#include "MLog.h"
87#include "MLogManip.h"
88
89// eventloop
90#include "MParList.h"
91#include "MTaskList.h"
92#include "MEvtLoop.h"
93
94// tasks
95#include "MRead.h"
96#include "MFillH.h"
97#include "MContinue.h"
98
99// filters
100#include "MF.h"
101#include "MFilterList.h"
102#include "MFEventSelector.h"
103#include "MFEventSelector2.h"
104
105ClassImp(MTFillMatrix);
106
107using namespace std;
108
109// --------------------------------------------------------------------------
110//
111// Print Size and contained columns.
112// Check whether the number of generated events is compatible with
113// the number of requested events.
114//
115Bool_t MTFillMatrix::CheckResult(MHMatrix *m, Int_t num) const
116{
117 if (!m || num==0)
118 return kTRUE;
119
120 m->Print("SizeCols");
121
122 const Int_t generated = m->GetM().GetNrows();
123 if (TMath::Abs(generated-num) <= TMath::Sqrt(9.0*num))
124 return kTRUE;
125
126 *fLog << warn << "WARNING - No. of generated events (";
127 *fLog << generated << ") incompatible with requested events (";
128 *fLog << num << ") for " << m->GetDescriptor() << endl;
129
130 return kFALSE;
131}
132
133// --------------------------------------------------------------------------
134//
135// Write the given MHMatrix with its name as default name to a
136// file fname.
137//
138Bool_t MTFillMatrix::WriteMatrix(MHMatrix *m, const TString &fname, Int_t i) const
139{
140 if (!m)
141 {
142 *fLog << "ERROR - Unable to write matrix #" << i << " (=NULL)... ignored." << endl;
143 return kFALSE;
144 }
145 if (fname.IsNull())
146 {
147 *fLog << "ERROR - Unable to write matrix, file name empty." << endl;
148 return kFALSE;
149 }
150
151 TFile file(fname, "RECREATE", m->GetTitle());
152 m->Write();
153 return kTRUE;
154}
155
156// --------------------------------------------------------------------------
157//
158// Constructor. Takes an MH3 as argument. This MH3 is the reference
159// distribution to fill the matrix. More information can be found
160// at MFEventSelector2 which is used to select the events.
161//
162// If no MH3 *ref is given the events are randomly selected from the
163// total sample - this may result in samples which don't have exactly
164// the predefined size, but it is much faster.
165//
166MTFillMatrix::MTFillMatrix(const MH3 *ref)
167: fReference(0), fReader(0), fDestMatrix1(0), fDestMatrix2(0),
168 fNumDestEvents1(0), fNumDestEvents2(0), fWriteFile1(0), fWriteFile2(0)
169{
170 fName = "MFillMatrix";
171 fTitle = "Tool to fill MHMatrix from file";
172
173 if (ref)
174 fReference = (MH3*)ref->Clone();
175}
176
177MTFillMatrix::~MTFillMatrix()
178{
179 if (fReference)
180 delete fReference;
181}
182
183//------------------------------------------------------------------------
184//
185// Function serving AddPreCuts, AddPreTasks and AddPostTasks
186//
187void MTFillMatrix::Add(const TList &src, const TClass *cls, TList &dest)
188{
189 TIter Next(&src);
190 TObject *obj=0;
191 while ((obj=Next()))
192 if (obj->InheritsFrom(cls))
193 dest.Add(obj);
194}
195
196//------------------------------------------------------------------------
197//
198// Add a cut which is used to fill the matrix, eg "MMcEvt.fOartId<1.5"
199// (The rule is applied, nit inverted: The matrix is filled with
200// the events fullfilling the condition)
201//
202void MTFillMatrix::AddPreCut(const char *rule)
203{
204 MFilter *f = new MF(rule);
205 f->SetBit(kCanDelete);
206 AddPreCut(f);
207}
208
209//------------------------------------------------------------------------
210//
211// Add a cut which is used to fill the matrix. If kCanDelete is set
212// MJOptimize takes the ownership.
213//
214void MTFillMatrix::AddPreCut(MFilter *f)
215{
216 fPreCuts.Add(f);
217}
218
219//------------------------------------------------------------------------
220//
221// Add all entries deriving from MFilter from list to PreCuts.
222// The ownership is not affected.
223//
224void MTFillMatrix::AddPreCuts(const TList &list)
225{
226 Add(list, MFilter::Class(), fPreCuts);
227}
228
229//------------------------------------------------------------------------
230//
231// Add a task which is executed before the precuts. If kCanDelete is set
232// MJOptimize takes the ownership.
233//
234void MTFillMatrix::AddPreTask(MTask *t)
235{
236 fPreTasks.Add(t);
237}
238
239//------------------------------------------------------------------------
240//
241// Add all entries deriving from MTask from list to PreTasks.
242// The ownership is not affected.
243//
244void MTFillMatrix::AddPreTasks(const TList &list)
245{
246 Add(list, MTask::Class(), fPreTasks);
247}
248
249//------------------------------------------------------------------------
250//
251// Add a task which is executed after the precuts. If kCanDelete is set
252// MJOptimize takes the ownership.
253//
254void MTFillMatrix::AddPostTask(MTask *t)
255{
256 fPostTasks.Add(t);
257}
258
259//------------------------------------------------------------------------
260//
261// Add all entries deriving from MTask from list to PostTasks.
262// The ownership is not affected.
263//
264void MTFillMatrix::AddPostTasks(const TList &list)
265{
266 Add(list, MTask::Class(), fPostTasks);
267}
268
269// --------------------------------------------------------------------------
270//
271// Fill the matrix (FIXME: Flow diagram missing)
272//
273Bool_t MTFillMatrix::Process(const MParList &parlist)
274{
275 if (!fReader)
276 {
277 *fLog << err << "ERROR - No task to read data was given... abort." << endl;
278 return kFALSE;
279 }
280
281 *fLog << inf;
282 fLog->Separator(GetDescriptor());
283 *fLog << "Fill " << fDestMatrix1->GetDescriptor() << " with " << fNumDestEvents1 << endl;
284 if (fDestMatrix2)
285 *fLog << "Fill " << fDestMatrix2->GetDescriptor() << " with " << fNumDestEvents2 << endl;
286 *fLog << "Distribution choosen ";
287 if (fReference && fReference->GetHist().GetEntries()>0)
288 *fLog << "from " << fReference->GetDescriptor();
289 else
290 *fLog << "randomly";
291 *fLog << endl;
292
293 //
294 // Create parameter list and task list, add tasklist to parlist
295 //
296 parlist.Print();
297 MParList plist(parlist);
298 MTaskList tlist;
299 plist.AddToList(&tlist);
300
301 //
302 // A selector to select a given number of events from a sample
303 //
304 // FIXME: Merge MFEventSelector and MFEventSelector2
305 MFilter *selector=0;
306 if (fNumDestEvents1>0 || fNumDestEvents2>0)
307 {
308 if (fReference)
309 {
310 // Case of a reference/nominal distribution
311 // The events must be read before selection
312 MFEventSelector2 *sel = new MFEventSelector2(*fReference);
313 sel->SetNumMax(fNumDestEvents1+fNumDestEvents2);
314 sel->SetInverted();
315
316 selector = sel;
317 }
318 else
319 {
320 // Case of a random distribution
321 // The events can be selected before reading
322 MFEventSelector *sel = new MFEventSelector;
323 sel->SetNumSelectEvts(fNumDestEvents1+fNumDestEvents2);
324 fReader->SetSelector(sel);
325
326 selector = sel;
327 }
328 }
329
330 //
331 // Continue for PreCuts
332 //
333 MFilterList list;
334 list.SetName("PreCuts");
335 if (!list.AddToList(fPreCuts))
336 *fLog << err << "ERROR - Calling MFilterList::AddToList for fPreCuts failed!" << endl;
337
338 MContinue cont0(&list);
339 cont0.SetInverted();
340
341 //
342 // Continue for all events which are not (SetInverted())
343 // selected by the 'selector'
344 //
345 MContinue cont(selector);
346
347 //
348 // Create a filter doing a random split
349 //
350 const Double_t prob = (Double_t)fNumDestEvents1/(fNumDestEvents1+fNumDestEvents2);
351 MFEventSelector split;
352 split.SetSelectionRatio(prob);
353
354 //
355 // Create the logical inverted filter for 'split'
356 //
357 MFilterList invsplit;
358 invsplit.AddToList(&split);
359 invsplit.SetInverted();
360
361 //
362 // The two tasks filling the two matrices
363 //
364 MFillH fill1(fDestMatrix1);
365 MFillH fill2(fDestMatrix2);
366 fill1.SetFilter(&split);
367 fill2.SetFilter(&invsplit);
368
369 // entries in MTaskList
370 tlist.AddToList(fReader); // Read events
371 tlist.AddToList(fPreTasks); // PreTasks
372 if (fPreCuts.GetEntries()>0)
373 tlist.AddToList(&cont0); // PreCuts
374 if (fReference && selector)
375 tlist.AddToList(&cont); // select a sample of events
376 tlist.AddToList(&invsplit); // process invsplit (which implicitly processes split)
377 tlist.AddToList(fPostTasks); // PostTasks
378 if (fDestMatrix1)
379 tlist.AddToList(&fill1); // fill matrix 1
380 if (fDestMatrix2)
381 tlist.AddToList(&fill2); // fill matrix 2
382 if (fWriteFile1)
383 {
384 fWriteFile1->SetFilter(&split);
385 tlist.AddToList(fWriteFile1);
386 }
387 if (fWriteFile2)
388 {
389 fWriteFile2->SetFilter(&invsplit);
390 tlist.AddToList(fWriteFile2);
391 }
392
393 tlist.SetAccelerator(MTask::kAccDontReset|MTask::kAccDontTime);
394
395 //
396 // Execute the eventloop
397 //
398 MEvtLoop evtloop(fName);
399 evtloop.SetParList(&plist);
400 evtloop.SetDisplay(fDisplay);
401 evtloop.SetLogStream(fLog);
402
403 const Bool_t rc = evtloop.Eventloop();
404
405 if (selector)
406 delete selector;
407
408 if (!rc)
409 {
410 *fLog << err << GetDescriptor() << ": Failed." << endl;
411 return kFALSE;
412 }
413
414 // Check the result of filling...
415 CheckResult(fDestMatrix1, fNumDestEvents1);
416 CheckResult(fDestMatrix2, fNumDestEvents2);
417
418 *fLog << inf << GetDescriptor() << ": Done." << endl;
419 return kTRUE;
420}
421
422// --------------------------------------------------------------------------
423//
424// Write both matrices to a file. Return kFALSE if writing one of them
425// failed or both have the same name.
426//
427Bool_t MTFillMatrix::WriteMatrices(const TString &fname) const
428{
429 if (fDestMatrix1 && fDestMatrix2 &&
430 (TString)fDestMatrix1->GetName()==(TString)fDestMatrix2->GetName())
431 {
432 *fLog << "ERROR - Cannot write matrices (both have the same name)... ignored." << endl;
433 return kFALSE;
434 }
435
436 return WriteMatrix1(fname) && WriteMatrix2(fname);
437}
438
439Int_t MTFillMatrix::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
440{
441 Bool_t rc = kFALSE;
442 if (IsEnvDefined(env, prefix, "NumDestEvents1", print))
443 {
444 rc = kTRUE;
445 SetNumDestEvents1(GetEnvValue(env, prefix, "NumDestEvents1", fNumDestEvents1));
446 }
447 if (IsEnvDefined(env, prefix, "NumDestEvents2", print))
448 {
449 rc = kTRUE;
450 SetNumDestEvents2(GetEnvValue(env, prefix, "NumDestEvents2", fNumDestEvents2));
451 }
452 return rc;
453}
Note: See TracBrowser for help on using the repository browser.