source: trunk/MagicSoft/Mars/mhist/MHMatrix.cc@ 1540

Last change on this file since 1540 was 1524, checked in by tbretz, 22 years ago
*** empty log message ***
File size: 13.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 2002 <mailto:tbretz@astro.uni-wuerzburg.de>
19!
20! Copyright: MAGIC Software Development, 2000-2002
21!
22!
23\* ======================================================================== */
24
25/////////////////////////////////////////////////////////////////////////////
26//
27// MHMatrix
28//
29// This is a histogram container which holds a matrix with one column per
30// data variable. The data variable can be a complex rule (MDataChain).
31// Each event for wich Fill is called (by MFillH) is added as a new
32// row to the matrix.
33//
34// For example:
35// MHMatrix m;
36// m.AddColumn("MHillas.fSize");
37// m.AddColumn("MMcEvt.fImpact/100");
38// m.AddColumn("HillasSource.fDist*MGeomCam.fConvMm2Deg");
39// MFillH fillm(&m);
40// taskliost.AddToList(&fillm);
41// [...]
42// m.Print();
43//
44/////////////////////////////////////////////////////////////////////////////
45#include "MHMatrix.h"
46#include <math.h> // for Alphas
47
48#include <fstream.h>
49
50#include <TList.h>
51#include <TArrayF.h>
52#include <TArrayD.h>
53#include <TArrayI.h>
54
55#include "MLog.h"
56#include "MLogManip.h"
57
58#include "MFillH.h"
59#include "MEvtLoop.h"
60#include "MParList.h"
61#include "MTaskList.h"
62
63#include "MData.h"
64#include "MDataArray.h"
65
66ClassImp(MHMatrix);
67
68const TString MHMatrix::gsDefName = "MHMatrix";
69const TString MHMatrix::gsDefTitle = "Multidimensional Matrix";
70
71// --------------------------------------------------------------------------
72//
73// Default Constructor
74//
75MHMatrix::MHMatrix(const char *name, const char *title)
76 : fNumRow(0), fData(NULL)
77{
78 fName = name ? name : gsDefName.Data();
79 fTitle = title ? title : gsDefTitle.Data();
80}
81
82// --------------------------------------------------------------------------
83//
84// Constructor. Initializes the columns of the matrix with the entries
85// from a MDataArray
86//
87MHMatrix::MHMatrix(MDataArray *mat, const char *name, const char *title)
88 : fNumRow(0), fData(mat)
89{
90 fName = name ? name : gsDefName.Data();
91 fTitle = title ? title : gsDefTitle.Data();
92}
93
94// --------------------------------------------------------------------------
95//
96// Destructor. Does not deleted a user given MDataArray, except IsOwner
97// was called.
98//
99MHMatrix::~MHMatrix()
100{
101 if (TestBit(kIsOwner) && fData)
102 delete fData;
103}
104
105// --------------------------------------------------------------------------
106//
107// Add a new column to the matrix. This can only be done before the first
108// event (row) was filled into the matrix. For the syntax of the rule
109// see MDataChain.
110// Returns the index of the new column, -1 in case of failure.
111// (0, 1, 2, ... for the 1st, 2nd, 3rd, ...)
112//
113Int_t MHMatrix::AddColumn(const char *rule)
114{
115 if (fM.IsValid())
116 {
117 *fLog << warn << "Warning - matrix is already in use. Can't add a new column... skipped." << endl;
118 return -1;
119 }
120
121 if (TestBit(kIsLocked))
122 {
123 *fLog << warn << "Warning - matrix is locked. Can't add new column... skipped." << endl;
124 return -1;
125 }
126
127 if (!fData)
128 {
129 fData = new MDataArray;
130 SetBit(kIsOwner);
131 }
132
133 fData->AddEntry(rule);
134 return fData->GetNumEntries()-1;
135}
136
137void MHMatrix::AddColumns(MDataArray *matrix)
138{
139 if (fM.IsValid())
140 {
141 *fLog << warn << "Warning - matrix is already in use. Can't add new columns... skipped." << endl;
142 return;
143 }
144
145 if (TestBit(kIsLocked))
146 {
147 *fLog << warn << "Warning - matrix is locked. Can't add new columns... skipped." << endl;
148 return;
149 }
150
151 if (fData)
152 *fLog << warn << "Warning - columns already added... replacing." << endl;
153
154 if (fData && TestBit(kIsOwner))
155 {
156 delete fData;
157 ResetBit(kIsOwner);
158 }
159
160 fData = matrix;
161}
162
163// --------------------------------------------------------------------------
164//
165// Checks whether at least one column is available and PreProcesses all
166// data chains.
167//
168Bool_t MHMatrix::SetupFill(const MParList *plist)
169{
170 if (!fData)
171 {
172 *fLog << err << "Error - No Columns initialized... aborting." << endl;
173 return kFALSE;
174 }
175
176 return fData->PreProcess(plist);
177}
178
179// --------------------------------------------------------------------------
180//
181// If the matrix has not enough rows double the number of available rows.
182//
183void MHMatrix::AddRow()
184{
185 fNumRow++;
186
187 if (fM.GetNrows() > fNumRow)
188 return;
189
190 if (!fM.IsValid())
191 {
192 fM.ResizeTo(1, fData->GetNumEntries());
193 return;
194 }
195
196 TMatrix m(fM);
197
198 fM.ResizeTo(fM.GetNrows()*2, fData->GetNumEntries());
199
200 for (int x=0; x<m.GetNcols(); x++)
201 for (int y=0; y<m.GetNrows(); y++)
202 fM(y, x) = m(y, x);
203}
204
205// --------------------------------------------------------------------------
206//
207// Add the values correspoding to the columns to the new row
208//
209Bool_t MHMatrix::Fill(const MParContainer *par)
210{
211 AddRow();
212
213 for (int col=0; col<fData->GetNumEntries(); col++)
214 fM(fNumRow-1, col) = (*fData)(col);
215
216 return kTRUE;
217}
218
219// --------------------------------------------------------------------------
220//
221// Resize the matrix to a number of rows which corresponds to the number of
222// rows which have really been filled with values.
223//
224Bool_t MHMatrix::Finalize()
225{
226 //
227 // It's not a fatal error so we don't need to stop PostProcessing...
228 //
229 if (fData->GetNumEntries()==0 || fNumRow<1)
230 return kTRUE;
231
232 TMatrix m(fM);
233
234 fM.ResizeTo(fNumRow, fData->GetNumEntries());
235
236 for (int x=0; x<fM.GetNcols(); x++)
237 for (int y=0; y<fM.GetNrows(); y++)
238 fM(y, x) = m(y, x);
239
240 return kTRUE;
241}
242/*
243// --------------------------------------------------------------------------
244//
245// Draw clone of histogram. So that the object can be deleted
246// and the histogram is still visible in the canvas.
247// The cloned object are deleted together with the canvas if the canvas is
248// destroyed. If you want to handle destroying the canvas you can get a
249// pointer to it from this function
250//
251TObject *MHMatrix::DrawClone(Option_t *opt) const
252{
253 TCanvas &c = *MH::MakeDefCanvas(fHist);
254
255 //
256 // This is necessary to get the expected bahviour of DrawClone
257 //
258 gROOT->SetSelectedPad(NULL);
259
260 fHist->DrawCopy(opt);
261
262 TString str(opt);
263 if (str.Contains("PROFX", TString::kIgnoreCase) && fDimension==2)
264 {
265 TProfile *p = ((TH2*)fHist)->ProfileX();
266 p->Draw("same");
267 p->SetBit(kCanDelete);
268 }
269 if (str.Contains("PROFY", TString::kIgnoreCase) && fDimension==2)
270 {
271 TProfile *p = ((TH2*)fHist)->ProfileY();
272 p->Draw("same");
273 p->SetBit(kCanDelete);
274 }
275
276 c.Modified();
277 c.Update();
278
279 return &c;
280}
281
282// --------------------------------------------------------------------------
283//
284// Creates a new canvas and draws the histogram into it.
285// Be careful: The histogram belongs to this object and won't get deleted
286// together with the canvas.
287//
288void MHMatrix::Draw(Option_t *opt)
289{
290 if (!gPad)
291 MH::MakeDefCanvas(fHist);
292
293 fHist->Draw(opt);
294
295 TString str(opt);
296 if (str.Contains("PROFX", TString::kIgnoreCase) && fDimension==2)
297 {
298 TProfile *p = ((TH2*)fHist)->ProfileX();
299 p->Draw("same");
300 p->SetBit(kCanDelete);
301 }
302 if (str.Contains("PROFY", TString::kIgnoreCase) && fDimension==2)
303 {
304 TProfile *p = ((TH2*)fHist)->ProfileY();
305 p->Draw("same");
306 p->SetBit(kCanDelete);
307 }
308
309 gPad->Modified();
310 gPad->Update();
311}
312*/
313
314// --------------------------------------------------------------------------
315//
316// Prints the meaning of the columns and the contents of the matrix.
317// Becareful, this can take a long time for matrices with many rows.
318//
319void MHMatrix::Print(Option_t *) const
320{
321 if (fData)
322 fData->Print();
323 else
324 *fLog << all << "Sorry, no column information available." << endl;
325
326 fM.Print();
327}
328
329const TMatrix *MHMatrix::InvertPosDef()
330{
331 TMatrix m(fM);
332
333 const Int_t rows = m.GetNrows();
334 const Int_t cols = m.GetNcols();
335
336 for (int x=0; x<cols; x++)
337 {
338 Double_t avg = 0;
339 for (int y=0; y<rows; y++)
340 avg += fM(y, x);
341
342 avg /= rows;
343
344 for (int y=0; y<rows; y++)
345 m(y, x) -= avg;
346 }
347
348 TMatrix *m2 = new TMatrix(m, TMatrix::kTransposeMult, m);
349
350 Double_t det;
351 m2->Invert(&det);
352 if (det==0)
353 {
354 *fLog << err << "ERROR - MHMatrix::InvertPosDef failed (Matrix is sigular)." << endl;
355 delete m2;
356 return NULL;
357 }
358
359 // m2->Print();
360
361 return m2;
362}
363
364// --------------------------------------------------------------------------
365//
366// Calculated the distance of vector evt from the reference sample
367// represented by the covariance metrix m.
368// - If n<0 the kernel method is applied and
369// sum(epx(-d)/n is returned.
370// - For n>=0 the n nearest neighbors are summed and
371// sqrt(sum(d))/n is returned.
372// - if n==0 all distances are summed
373//
374Double_t MHMatrix::CalcDist(const TMatrix &m, const TVector &evt, Int_t num) const
375{
376 if (num==0) // may later be used for another method
377 {
378 TVector d = evt;
379 d *= m;
380 return sqrt(d*evt);
381 }
382
383 const Int_t rows = fM.GetNrows();
384 const Int_t cols = fM.GetNcols();
385
386 TArrayD dists(rows);
387
388 //
389 // Calculate: v^T * M * v
390 //
391 for (int i=0; i<rows; i++)
392 {
393 TVector col(cols);
394 col = TMatrixRow(fM, i);
395
396 TVector d = evt;
397 d -= col;
398
399 TVector d2 = d;
400 d2 *= m;
401
402 dists[i] = d2*d; // square of distance
403
404 //
405 // This corrects for numerical uncertanties in cases of very
406 // small distances...
407 //
408 if (dists[i]<0)
409 dists[i]=0;
410 }
411
412 TArrayI idx(rows);
413 TMath::Sort(dists.GetSize(), dists.GetArray(), idx.GetArray(), kFALSE);
414
415 const Int_t n = abs(num)<rows ? abs(num) : rows;
416
417 if (num<0)
418 {
419 //
420 // Kernel function sum
421 //
422 const Double_t h = 1;
423
424 Double_t res = 0;
425 for (int i=0; i<n; i++)
426 res += exp(-dists[idx[i]]/h);
427
428 return log(res/n);
429 }
430 else
431 {
432 //
433 // Nearest Neighbor sum
434 //
435 Double_t res = 0;
436 for (int i=0; i<n; i++)
437 res += dists[idx[i]];
438
439 return sqrt(res/n);
440 }
441}
442
443// --------------------------------------------------------------------------
444//
445// Calls calc dist. In the case of the first call the covariance matrix
446// fM2 is calculated.
447// - If n<0 it is divided by (nrows-1)/h while h is the kernel factor.
448//
449Double_t MHMatrix::CalcDist(const TVector &evt, Int_t num)
450{
451 if (!fM2.IsValid())
452 {
453 const TMatrix &m = *InvertPosDef();
454 fM2.ResizeTo(m);
455 fM2 = m;
456 fM2 *= fM.GetNrows()-1;
457 delete &m;
458 }
459
460 return CalcDist(fM2, evt, num);
461}
462
463void MHMatrix::Reassign()
464{
465 TMatrix m = fM;
466 fM.ResizeTo(1,1);
467 fM.ResizeTo(m);
468 fM = m;
469}
470
471void MHMatrix::StreamPrimitive(ofstream &out) const
472{
473 Bool_t data = fData && !TestBit(kIsOwner);
474
475 if (data)
476 {
477 fData->SavePrimitive(out);
478 out << endl;
479 }
480
481 out << " MHMatrix " << GetUniqueName();
482
483 if (data || fName!=gsDefName || fTitle!=gsDefTitle)
484 {
485 out << "(";
486 if (data)
487 out << "&" << fData->GetUniqueName();
488 if (fName!=gsDefName || fTitle!=gsDefTitle)
489 {
490 if (data)
491 out << ", ";
492 out << "\"" << fName << "\"";
493 if (fTitle!=gsDefTitle)
494 out << ", \"" << fTitle << "\"";
495 }
496 }
497 out << ");" << endl;
498
499 if (fData && TestBit(kIsOwner))
500 for (int i=0; i<fData->GetNumEntries(); i++)
501 out << " " << GetUniqueName() << ".AddColumn(\"" << (*fData)[i].GetRule() << "\");" << endl;
502}
503
504const TArrayI MHMatrix::GetIndexOfSortedColumn(Int_t ncol, Bool_t desc) const
505{
506 TMatrixColumn col(fM, ncol);
507
508 const Int_t n = fM.GetNrows();
509
510 TArrayF array(n);
511
512 for (int i=0; i<n; i++)
513 array[i] = col(i);
514
515 TArrayI idx(n);
516 TMath::Sort(n, array.GetArray(), idx.GetArray(), desc);
517
518 return idx;
519}
520
521void MHMatrix::SortMatrixByColumn(Int_t ncol, Bool_t desc)
522{
523 TArrayI idx = GetIndexOfSortedColumn(ncol, desc);
524
525 const Int_t n = fM.GetNrows();
526
527 TMatrix m(n, fM.GetNcols());
528 for (int i=0; i<n; i++)
529 {
530 TVector vold(n);
531 vold = TMatrixRow(fM, idx[i]);
532
533 TMatrixRow rownew(m, i);
534 rownew = vold;
535 }
536
537 fM = m;
538}
539
540Bool_t MHMatrix::Fill(MParList *plist, MTask *read)
541{
542 //
543 // Read data into Matrix
544 //
545 const Bool_t is = plist->IsOwner();
546 plist->SetOwner(kFALSE);
547
548 MTaskList tlist;
549 plist->Replace(&tlist);
550
551 MFillH fillh(this);
552
553 tlist.AddToList(read);
554 tlist.AddToList(&fillh);
555
556 MEvtLoop evtloop;
557 evtloop.SetParList(plist);
558
559 if (!evtloop.Eventloop())
560 return kFALSE;
561
562 plist->Remove(&tlist);
563 plist->SetOwner(is);
564
565 return kTRUE;
566}
Note: See TracBrowser for help on using the repository browser.