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

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