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

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