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

Last change on this file since 2306 was 2300, checked in by wittek, 23 years ago
*** empty log message ***
File size: 29.0 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! Rudy Boeck 2003 <mailto:
20! Wolfgang Wittek2003 <mailto:wittek@mppmu.mpg.de>
21!
22! Copyright: MAGIC Software Development, 2000-2003
23!
24!
25\* ======================================================================== */
26
27/////////////////////////////////////////////////////////////////////////////
28//
29// MHMatrix
30//
31// This is a histogram container which holds a matrix with one column per
32// data variable. The data variable can be a complex rule (MDataChain).
33// Each event for wich Fill is called (by MFillH) is added as a new
34// row to the matrix.
35//
36// For example:
37// MHMatrix m;
38// m.AddColumn("MHillas.fSize");
39// m.AddColumn("MMcEvt.fImpact/100");
40// m.AddColumn("HillasSource.fDist*MGeomCam.fConvMm2Deg");
41// MFillH fillm(&m);
42// taskliost.AddToList(&fillm);
43// [...]
44// m.Print();
45//
46/////////////////////////////////////////////////////////////////////////////
47#include "MHMatrix.h"
48
49#include <fstream>
50
51#include <TList.h>
52#include <TArrayF.h>
53#include <TArrayD.h>
54#include <TArrayI.h>
55
56#include <TH1.h>
57#include <TCanvas.h>
58#include <TRandom3.h>
59
60#include "MLog.h"
61#include "MLogManip.h"
62
63#include "MFillH.h"
64#include "MEvtLoop.h"
65#include "MParList.h"
66#include "MTaskList.h"
67#include "MProgressBar.h"
68
69#include "MData.h"
70#include "MDataArray.h"
71#include "MFilter.h"
72
73ClassImp(MHMatrix);
74
75using namespace std;
76
77const TString MHMatrix::gsDefName = "MHMatrix";
78const TString MHMatrix::gsDefTitle = "Multidimensional Matrix";
79
80// --------------------------------------------------------------------------
81//
82// Default Constructor
83//
84MHMatrix::MHMatrix(const char *name, const char *title)
85 : fNumRow(0), fData(NULL)
86{
87 fName = name ? name : gsDefName.Data();
88 fTitle = title ? title : gsDefTitle.Data();
89}
90
91// --------------------------------------------------------------------------
92//
93// Default Constructor
94//
95MHMatrix::MHMatrix(const TMatrix &m, const char *name, const char *title)
96 : fNumRow(m.GetNrows()), fM(m), fData(NULL)
97{
98 fName = name ? name : gsDefName.Data();
99 fTitle = title ? title : gsDefTitle.Data();
100}
101
102// --------------------------------------------------------------------------
103//
104// Constructor. Initializes the columns of the matrix with the entries
105// from a MDataArray
106//
107MHMatrix::MHMatrix(MDataArray *mat, const char *name, const char *title)
108 : fNumRow(0), fData(mat)
109{
110 fName = name ? name : gsDefName.Data();
111 fTitle = title ? title : gsDefTitle.Data();
112}
113
114// --------------------------------------------------------------------------
115//
116// Destructor. Does not deleted a user given MDataArray, except IsOwner
117// was called.
118//
119MHMatrix::~MHMatrix()
120{
121 if (TestBit(kIsOwner) && fData)
122 delete fData;
123}
124
125// --------------------------------------------------------------------------
126//
127// Add a new column to the matrix. This can only be done before the first
128// event (row) was filled into the matrix. For the syntax of the rule
129// see MDataChain.
130// Returns the index of the new column, -1 in case of failure.
131// (0, 1, 2, ... for the 1st, 2nd, 3rd, ...)
132//
133Int_t MHMatrix::AddColumn(const char *rule)
134{
135 if (fM.IsValid())
136 {
137 *fLog << warn << "Warning - matrix is already in use. Can't add a new column... skipped." << endl;
138 return -1;
139 }
140
141 if (TestBit(kIsLocked))
142 {
143 *fLog << warn << "Warning - matrix is locked. Can't add new column... skipped." << endl;
144 return -1;
145 }
146
147 if (!fData)
148 {
149 fData = new MDataArray;
150 SetBit(kIsOwner);
151 }
152
153 fData->AddEntry(rule);
154 return fData->GetNumEntries()-1;
155}
156
157// --------------------------------------------------------------------------
158//
159void MHMatrix::AddColumns(MDataArray *matrix)
160{
161 if (fM.IsValid())
162 {
163 *fLog << warn << "Warning - matrix is already in use. Can't add new columns... skipped." << endl;
164 return;
165 }
166
167 if (TestBit(kIsLocked))
168 {
169 *fLog << warn << "Warning - matrix is locked. Can't add new columns... skipped." << endl;
170 return;
171 }
172
173 if (fData)
174 *fLog << warn << "Warning - columns already added... replacing." << endl;
175
176 if (fData && TestBit(kIsOwner))
177 {
178 delete fData;
179 ResetBit(kIsOwner);
180 }
181
182 fData = matrix;
183}
184
185// --------------------------------------------------------------------------
186//
187// Checks whether at least one column is available and PreProcesses all
188// data chains.
189//
190Bool_t MHMatrix::SetupFill(const MParList *plist)
191{
192 if (!fData)
193 {
194 *fLog << err << "Error - No Columns initialized... aborting." << endl;
195 return kFALSE;
196 }
197
198 return fData->PreProcess(plist);
199}
200
201// --------------------------------------------------------------------------
202//
203// If the matrix has not enough rows double the number of available rows.
204//
205void MHMatrix::AddRow()
206{
207 fNumRow++;
208
209 if (fM.GetNrows() > fNumRow)
210 return;
211
212 if (!fM.IsValid())
213 {
214 fM.ResizeTo(1, fData->GetNumEntries());
215 return;
216 }
217
218 TMatrix m(fM);
219
220 fM.ResizeTo(fM.GetNrows()*2, fData->GetNumEntries());
221
222 TVector vold(fM.GetNcols());
223 for (int x=0; x<m.GetNrows(); x++)
224 TMatrixRow(fM, x) = vold = TMatrixRow(m, x);
225}
226
227// --------------------------------------------------------------------------
228//
229// Add the values correspoding to the columns to the new row
230//
231Bool_t MHMatrix::Fill(const MParContainer *par, const Stat_t w)
232{
233 AddRow();
234
235 for (int col=0; col<fData->GetNumEntries(); col++)
236 fM(fNumRow-1, col) = (*fData)(col);
237
238 return kTRUE;
239}
240
241// --------------------------------------------------------------------------
242//
243// Resize the matrix to a number of rows which corresponds to the number of
244// rows which have really been filled with values.
245//
246Bool_t MHMatrix::Finalize()
247{
248 //
249 // It's not a fatal error so we don't need to stop PostProcessing...
250 //
251 if (fData->GetNumEntries()==0 || fNumRow<1)
252 return kTRUE;
253
254 if (fNumRow != fM.GetNrows())
255 {
256 TMatrix m(fM);
257 CopyCrop(fM, m, fNumRow);
258 }
259
260 return kTRUE;
261}
262
263/*
264// --------------------------------------------------------------------------
265//
266// Draw clone of histogram. So that the object can be deleted
267// and the histogram is still visible in the canvas.
268// The cloned object are deleted together with the canvas if the canvas is
269// destroyed. If you want to handle destroying the canvas you can get a
270// pointer to it from this function
271//
272TObject *MHMatrix::DrawClone(Option_t *opt) const
273{
274 TCanvas &c = *MH::MakeDefCanvas(fHist);
275
276 //
277 // This is necessary to get the expected bahviour of DrawClone
278 //
279 gROOT->SetSelectedPad(NULL);
280
281 fHist->DrawCopy(opt);
282
283 TString str(opt);
284 if (str.Contains("PROFX", TString::kIgnoreCase) && fDimension==2)
285 {
286 TProfile *p = ((TH2*)fHist)->ProfileX();
287 p->Draw("same");
288 p->SetBit(kCanDelete);
289 }
290 if (str.Contains("PROFY", TString::kIgnoreCase) && fDimension==2)
291 {
292 TProfile *p = ((TH2*)fHist)->ProfileY();
293 p->Draw("same");
294 p->SetBit(kCanDelete);
295 }
296
297 c.Modified();
298 c.Update();
299
300 return &c;
301}
302
303// --------------------------------------------------------------------------
304//
305// Creates a new canvas and draws the histogram into it.
306// Be careful: The histogram belongs to this object and won't get deleted
307// together with the canvas.
308//
309void MHMatrix::Draw(Option_t *opt)
310{
311 if (!gPad)
312 MH::MakeDefCanvas(fHist);
313
314 fHist->Draw(opt);
315
316 TString str(opt);
317 if (str.Contains("PROFX", TString::kIgnoreCase) && fDimension==2)
318 {
319 TProfile *p = ((TH2*)fHist)->ProfileX();
320 p->Draw("same");
321 p->SetBit(kCanDelete);
322 }
323 if (str.Contains("PROFY", TString::kIgnoreCase) && fDimension==2)
324 {
325 TProfile *p = ((TH2*)fHist)->ProfileY();
326 p->Draw("same");
327 p->SetBit(kCanDelete);
328 }
329
330 gPad->Modified();
331 gPad->Update();
332}
333*/
334
335// --------------------------------------------------------------------------
336//
337// Prints the meaning of the columns and the contents of the matrix.
338// Becareful, this can take a long time for matrices with many rows.
339// Use the option 'size' to print the size of the matrix.
340// Use the option 'cols' to print the culumns
341// Use the option 'data' to print the contents
342//
343void MHMatrix::Print(Option_t *o) const
344{
345 TString str(o);
346
347 *fLog << all << flush;
348
349 if (str.Contains("size", TString::kIgnoreCase))
350 {
351 *fLog << GetDescriptor() << ": NumColumns=" << fM.GetNcols();
352 *fLog << " NumRows=" << fM.GetNrows() << endl;
353 }
354
355 if (!fData && str.Contains("cols", TString::kIgnoreCase))
356 *fLog << "Sorry, no column information available." << endl;
357
358 if (fData && str.Contains("cols", TString::kIgnoreCase))
359 fData->Print();
360
361 if (str.Contains("data", TString::kIgnoreCase))
362 fM.Print();
363}
364
365// --------------------------------------------------------------------------
366//
367const TMatrix *MHMatrix::InvertPosDef()
368{
369 TMatrix m(fM);
370
371 const Int_t rows = m.GetNrows();
372 const Int_t cols = m.GetNcols();
373
374 for (int x=0; x<cols; x++)
375 {
376 Double_t avg = 0;
377 for (int y=0; y<rows; y++)
378 avg += fM(y, x);
379
380 avg /= rows;
381
382 TMatrixColumn(m, x) += -avg;
383 }
384
385 TMatrix *m2 = new TMatrix(m, TMatrix::kTransposeMult, m);
386
387 Double_t det;
388 m2->Invert(&det);
389 if (det==0)
390 {
391 *fLog << err << "ERROR - MHMatrix::InvertPosDef failed (Matrix is singular)." << endl;
392 delete m2;
393 return NULL;
394 }
395
396 // m2->Print();
397
398 return m2;
399}
400
401// --------------------------------------------------------------------------
402//
403// Calculated the distance of vector evt from the reference sample
404// represented by the covariance metrix m.
405// - If n<0 the kernel method is applied and
406// -log(sum(epx(-d/h))/n) is returned.
407// - For n>0 the n nearest neighbors are summed and
408// sqrt(sum(d)/n) is returned.
409// - if n==0 all distances are summed
410//
411Double_t MHMatrix::CalcDist(const TMatrix &m, const TVector &evt, Int_t num) const
412{
413 if (num==0) // may later be used for another method
414 {
415 TVector d = evt;
416 d *= m;
417 return TMath::Sqrt(d*evt);
418 }
419
420 const Int_t rows = fM.GetNrows();
421 const Int_t cols = fM.GetNcols();
422
423 TArrayD dists(rows);
424
425 //
426 // Calculate: v^T * M * v
427 //
428 for (int i=0; i<rows; i++)
429 {
430 TVector col(cols);
431 col = TMatrixRow(fM, i);
432
433 TVector d = evt;
434 d -= col;
435
436 TVector d2 = d;
437 d2 *= m;
438
439 dists[i] = d2*d; // square of distance
440
441 //
442 // This corrects for numerical uncertanties in cases of very
443 // small distances...
444 //
445 if (dists[i]<0)
446 dists[i]=0;
447 }
448
449 TArrayI idx(rows);
450 TMath::Sort(dists.GetSize(), dists.GetArray(), idx.GetArray(), kFALSE);
451
452 Int_t from = 0;
453 Int_t to = TMath::Abs(num)<rows ? TMath::Abs(num) : rows;
454 //
455 // This is a zero-suppression for the case a test- and trainings
456 // sample is identical. This would result in an unwanted leading
457 // zero in the array. To suppress also numerical uncertanties of
458 // zero we cut at 1e-5. Due to Rudy this should be enough. If
459 // you encounter problems we can also use (eg) 1e-25
460 //
461 if (dists[idx[0]]<1e-5)
462 {
463 from++;
464 to ++;
465 if (to>rows)
466 to = rows;
467 }
468
469 if (num<0)
470 {
471 //
472 // Kernel function sum (window size h set according to literature)
473 //
474 const Double_t h = TMath::Power(rows, -1./(cols+4));
475 const Double_t hwin = h*h*2;
476
477 Double_t res = 0;
478 for (int i=from; i<to; i++)
479 res += TMath::Exp(-dists[idx[i]]/hwin);
480
481 return -TMath::Log(res/(to-from));
482 }
483 else
484 {
485 //
486 // Nearest Neighbor sum
487 //
488 Double_t res = 0;
489 for (int i=from; i<to; i++)
490 res += dists[idx[i]];
491
492 return TMath::Sqrt(res/(to-from));
493 }
494}
495
496// --------------------------------------------------------------------------
497//
498// Calls calc dist. In the case of the first call the covariance matrix
499// fM2 is calculated.
500// - If n<0 it is divided by (nrows-1)/h while h is the kernel factor.
501//
502Double_t MHMatrix::CalcDist(const TVector &evt, Int_t num)
503{
504 if (!fM2.IsValid())
505 {
506 if (!fM.IsValid())
507 {
508 *fLog << err << "MHMatrix::CalcDist - ERROR: fM not valid." << endl;
509 return -1;
510 }
511
512 const TMatrix *m = InvertPosDef();
513 if (!m)
514 return -1;
515
516 fM2.ResizeTo(*m);
517 fM2 = *m;
518 fM2 *= fM.GetNrows()-1;
519 delete m;
520 }
521
522 return CalcDist(fM2, evt, num);
523}
524
525// --------------------------------------------------------------------------
526//
527void MHMatrix::Reassign()
528{
529 TMatrix m = fM;
530 fM.ResizeTo(1,1);
531 fM.ResizeTo(m);
532 fM = m;
533}
534
535// --------------------------------------------------------------------------
536//
537// Implementation of SavePrimitive. Used to write the call to a constructor
538// to a macro. In the original root implementation it is used to write
539// gui elements to a macro-file.
540//
541void MHMatrix::StreamPrimitive(ofstream &out) const
542{
543 Bool_t data = fData && !TestBit(kIsOwner);
544
545 if (data)
546 {
547 fData->SavePrimitive(out);
548 out << endl;
549 }
550
551 out << " MHMatrix " << GetUniqueName();
552
553 if (data || fName!=gsDefName || fTitle!=gsDefTitle)
554 {
555 out << "(";
556 if (data)
557 out << "&" << fData->GetUniqueName();
558 if (fName!=gsDefName || fTitle!=gsDefTitle)
559 {
560 if (data)
561 out << ", ";
562 out << "\"" << fName << "\"";
563 if (fTitle!=gsDefTitle)
564 out << ", \"" << fTitle << "\"";
565 }
566 }
567 out << ");" << endl;
568
569 if (fData && TestBit(kIsOwner))
570 for (int i=0; i<fData->GetNumEntries(); i++)
571 out << " " << GetUniqueName() << ".AddColumn(\"" << (*fData)[i].GetRule() << "\");" << endl;
572}
573
574// --------------------------------------------------------------------------
575//
576const TArrayI MHMatrix::GetIndexOfSortedColumn(Int_t ncol, Bool_t desc) const
577{
578 TMatrixColumn col(fM, ncol);
579
580 const Int_t n = fM.GetNrows();
581
582 TArrayF array(n);
583
584 for (int i=0; i<n; i++)
585 array[i] = col(i);
586
587 TArrayI idx(n);
588 TMath::Sort(n, array.GetArray(), idx.GetArray(), desc);
589
590 return idx;
591}
592
593// --------------------------------------------------------------------------
594//
595void MHMatrix::SortMatrixByColumn(Int_t ncol, Bool_t desc)
596{
597 TArrayI idx = GetIndexOfSortedColumn(ncol, desc);
598
599 const Int_t n = fM.GetNrows();
600
601 TMatrix m(n, fM.GetNcols());
602 TVector vold(fM.GetNcols());
603 for (int i=0; i<n; i++)
604 TMatrixRow(m, i) = vold = TMatrixRow(fM, idx[i]);
605
606 fM = m;
607}
608
609// --------------------------------------------------------------------------
610//
611Bool_t MHMatrix::Fill(MParList *plist, MTask *read, MFilter *filter)
612{
613 //
614 // Read data into Matrix
615 //
616 const Bool_t is = plist->IsOwner();
617 plist->SetOwner(kFALSE);
618
619 MTaskList tlist;
620 plist->Replace(&tlist);
621
622 MFillH fillh(this);
623
624 tlist.AddToList(read);
625
626 if (filter)
627 {
628 tlist.AddToList(filter);
629 fillh.SetFilter(filter);
630 }
631
632 tlist.AddToList(&fillh);
633
634 //MProgressBar bar;
635 MEvtLoop evtloop;
636 evtloop.SetParList(plist);
637 evtloop.SetName("EvtLoopMatrix");
638 //evtloop.SetProgressBar(&bar);
639
640
641 if (!evtloop.Eventloop())
642 return kFALSE;
643
644 tlist.PrintStatistics();
645
646 plist->Remove(&tlist);
647 plist->SetOwner(is);
648
649 return kTRUE;
650}
651
652// --------------------------------------------------------------------------
653//
654// Return a comma seperated list of all data members used in the matrix.
655// This is mainly used in MTask::AddToBranchList
656//
657TString MHMatrix::GetDataMember() const
658{
659 return fData ? fData->GetDataMember() : TString("");
660}
661
662// --------------------------------------------------------------------------
663//
664//
665void MHMatrix::ReduceNumberOfRows(UInt_t numrows, const TString opt)
666{
667 UInt_t rows = fM.GetNrows();
668
669 if (rows==numrows)
670 {
671 *fLog << warn << "Matrix has already the correct number of rows..." << endl;
672 return;
673 }
674
675 Float_t ratio = (Float_t)numrows/fM.GetNrows();
676
677 if (ratio>=1)
678 {
679 *fLog << warn << "Matrix cannot be enlarged..." << endl;
680 return;
681 }
682
683 Double_t sum = 0;
684
685 UInt_t oldrow = 0;
686 UInt_t newrow = 0;
687
688 TVector vold(fM.GetNcols());
689 while (oldrow<rows)
690 {
691 sum += ratio;
692
693 if (newrow<=(unsigned int)sum)
694 TMatrixRow(fM, newrow++) = vold = TMatrixRow(fM, oldrow);
695
696 oldrow++;
697 }
698}
699
700// ------------------------------------------------------------------------
701//
702// Used in DefRefMatrix to display the result graphically
703//
704void MHMatrix::DrawDefRefInfo(const TH1 &hth, const TH1 &hthd, const TH1 &thsh, Int_t refcolumn)
705{
706 //
707 // Fill a histogram with the distribution after raduction
708 //
709 TH1F hta;
710 hta.SetDirectory(NULL);
711 hta.SetName("hta");
712 hta.SetTitle("Distribution after reduction");
713 SetBinning(&hta, &hth);
714
715 for (Int_t i=0; i<fM.GetNrows(); i++)
716 hta.Fill(fM(i, refcolumn));
717
718 TCanvas *th1 = MakeDefCanvas(this);
719 th1->Divide(2,2);
720
721 th1->cd(1);
722 ((TH1&)hth).DrawCopy(); // real histogram before
723
724 th1->cd(2);
725 ((TH1&)hta).DrawCopy(); // histogram after
726
727 th1->cd(3);
728 ((TH1&)hthd).DrawCopy(); // correction factors
729
730 th1->cd(4);
731 ((TH1&)thsh).DrawCopy(); // target
732}
733
734// ------------------------------------------------------------------------
735//
736// Resizes th etarget matrix to rows*source.GetNcol() and copies
737// the data from the first (n)rows or the source into the target matrix.
738//
739void MHMatrix::CopyCrop(TMatrix &target, const TMatrix &source, Int_t rows)
740{
741 TVector v(source.GetNcols());
742
743 target.ResizeTo(rows, source.GetNcols());
744 for (Int_t ir=0; ir<rows; ir++)
745 TMatrixRow(target, ir) = v = TMatrixRow(source, ir);
746}
747
748// ------------------------------------------------------------------------
749//
750// Define the reference matrix
751// refcolumn number of the column (starting at 0) containing the variable,
752// for which a target distribution may be given;
753// thsh histogram containing the target distribution of the variable
754// nmaxevts the number of events the reference matrix should have after
755// the renormalization
756// rest a TMatrix conatining the resulting (not choosen)
757// columns of the primary matrix. Maybe NULL if you
758// are not interested in this
759//
760Bool_t MHMatrix::DefRefMatrix(const UInt_t refcolumn, const TH1F &thsh,
761 Int_t nmaxevts, TMatrix *rest)
762{
763 if (!fM.IsValid())
764 {
765 *fLog << err << dbginf << "Matrix not initialized" << endl;
766 return kFALSE;
767 }
768
769 if (thsh.GetMinimum()<0)
770 {
771 *fLog << err << dbginf << "Renormalization not possible: ";
772 *fLog << "Target Distribution has values < 0" << endl;
773 return kFALSE;
774 }
775
776
777 if (nmaxevts>fM.GetNrows())
778 {
779 *fLog << warn << dbginf << "No.requested (" << nmaxevts;
780 *fLog << ") > available events (" << fM.GetNrows() << ")... ";
781 *fLog << "setting equal." << endl;
782 nmaxevts = fM.GetNrows();
783 }
784
785
786 if (nmaxevts<0)
787 {
788 *fLog << err << dbginf << "Number of requested events < 0" << endl;
789 return kFALSE;
790 }
791
792 if (nmaxevts==0)
793 nmaxevts = fM.GetNrows();
794
795 //
796 // refcol is the column number starting at 0; it is >= 0
797 //
798 // number of the column (count from 0) containing
799 // the variable for which the target distribution is given
800 //
801
802 //
803 // Calculate normalization factors
804 //
805 //const int nbins = thsh.GetNbinsX();
806 //const double frombin = thsh.GetBinLowEdge(1);
807 //const double tobin = thsh.GetBinLowEdge(nbins+1);
808 //const double dbin = thsh.GetBinWidth(1);
809
810 const Int_t nrows = fM.GetNrows();
811 const Int_t ncols = fM.GetNcols();
812
813 //
814 // set up the real histogram (distribution before)
815 //
816 //TH1F hth("th", "Distribution before reduction", nbins, frombin, tobin);
817 TH1F hth;
818 hth.SetNameTitle("th", "Distribution before reduction");
819 SetBinning(&hth, &thsh);
820 hth.SetDirectory(NULL);
821 for (Int_t j=0; j<nrows; j++)
822 hth.Fill(fM(j, refcolumn));
823
824 //TH1F hthd("thd", "Correction factors", nbins, frombin, tobin);
825 TH1F hthd;
826 hthd.SetNameTitle("thd", "Correction factors");
827 SetBinning(&hthd, &thsh);
828 hthd.SetDirectory(NULL);
829 hthd.Divide((TH1F*)&thsh, &hth, 1, 1);
830
831 if (hthd.GetMaximum() <= 0)
832 {
833 *fLog << err << dbginf << "Maximum correction factor <= 0... abort." << endl;
834 return kFALSE;
835 }
836
837 //
838 // ===== obtain correction factors (normalization factors)
839 //
840 hthd.Scale(1/hthd.GetMaximum());
841
842 //
843 // get random access
844 //
845 TArrayI ind(nrows);
846 GetRandomArrayI(ind);
847
848 //
849 // define new matrix
850 //
851 Int_t evtcount1 = -1;
852 Int_t evtcount2 = 0;
853
854 TMatrix mnewtmp(nrows, ncols);
855 TMatrix mrest(nrows, ncols);
856
857 TArrayF cumulweight(nrows); // keep track for each bin how many events
858
859 //
860 // Project values in reference column into [0,1]
861 //
862 TVector v(fM.GetNrows());
863 v = TMatrixColumn(fM, refcolumn);
864 //v += -frombin;
865 //v *= 1/dbin;
866
867 //
868 // select events (distribution after renormalization)
869 //
870 Int_t ir;
871 TVector vold(fM.GetNcols());
872 for (ir=0; ir<nrows; ir++)
873 {
874 // const Int_t indref = (Int_t)v(ind[ir]);
875 const Int_t indref = hthd.FindBin(v(ind[ir])) - 1;
876 cumulweight[indref] += hthd.GetBinContent(indref+1);
877 if (cumulweight[indref]<=0.5)
878 {
879 TMatrixRow(mrest, evtcount2++) = vold = TMatrixRow(fM, ind[ir]);
880 continue;
881 }
882
883 cumulweight[indref] -= 1.;
884 if (++evtcount1 >= nmaxevts)
885 break;
886
887 TMatrixRow(mnewtmp, evtcount1) = vold = TMatrixRow(fM, ind[ir]);
888 }
889
890 for (/*empty*/; ir<nrows; ir++)
891 TMatrixRow(mrest, evtcount2++) = vold = TMatrixRow(fM, ind[ir]);
892
893 //
894 // reduce size
895 //
896 // matrix fM having the requested distribution
897 // and the requested number of rows;
898 // this is the matrix to be used in the g/h separation
899 //
900 CopyCrop(fM, mnewtmp, evtcount1);
901 fNumRow = evtcount1;
902
903 if (evtcount1 < nmaxevts)
904 *fLog << warn << "Reference sample contains less events (" << evtcount1 << ") than requested (" << nmaxevts << ")" << endl;
905
906 if (TestBit(kEnableGraphicalOutput))
907 DrawDefRefInfo(hth, hthd, thsh, refcolumn);
908
909 if (rest)
910 CopyCrop(*rest, mrest, evtcount2);
911
912 return kTRUE;
913}
914
915// ------------------------------------------------------------------------
916//
917// Returns a array containing randomly sorted indices
918//
919void MHMatrix::GetRandomArrayI(TArrayI &ind) const
920{
921 const Int_t rows = ind.GetSize();
922
923 TArrayF ranx(rows);
924
925 TRandom3 rnd(0);
926 for (Int_t i=0; i<rows; i++)
927 ranx[i] = rnd.Rndm(i);
928
929 TMath::Sort(rows, ranx.GetArray(), ind.GetArray(), kTRUE);
930}
931
932// ------------------------------------------------------------------------
933//
934// Define the reference matrix
935// nmaxevts maximum number of events in the reference matrix
936// rest a TMatrix conatining the resulting (not choosen)
937// columns of the primary matrix. Maybe NULL if you
938// are not interested in this
939//
940// the target distribution will be set
941// equal to the real distribution; the events in the reference
942// matrix will then be simply a random selection of the events
943// in the original matrix.
944//
945Bool_t MHMatrix::DefRefMatrix(Int_t nmaxevts, TMatrix *rest)
946{
947 if (!fM.IsValid())
948 {
949 *fLog << err << dbginf << "Matrix not initialized" << endl;
950 return kFALSE;
951 }
952
953 if (nmaxevts>fM.GetNrows())
954 {
955 *fLog << dbginf << "No.of requested events (" << nmaxevts
956 << ") exceeds no.of available events (" << fM.GetNrows()
957 << ")" << endl;
958 *fLog << dbginf
959 << " set no.of requested events = no.of available events"
960 << endl;
961 nmaxevts = fM.GetNrows();
962 }
963
964 if (nmaxevts<0)
965 {
966 *fLog << err << dbginf << "Number of requested events < 0" << endl;
967 return kFALSE;
968 }
969
970 if (nmaxevts==0)
971 nmaxevts = fM.GetNrows();
972
973 const Int_t nrows = fM.GetNrows();
974 const Int_t ncols = fM.GetNcols();
975
976 //
977 // get random access
978 //
979 TArrayI ind(nrows);
980 GetRandomArrayI(ind);
981
982 //
983 // define new matrix
984 //
985 Int_t evtcount1 = 0;
986 Int_t evtcount2 = 0;
987
988 TMatrix mnewtmp(nrows, ncols);
989 TMatrix mrest(nrows, ncols);
990
991 //
992 // select events (distribution after renormalization)
993 //
994 TVector vold(fM.GetNcols());
995 for (Int_t ir=0; ir<nmaxevts; ir++)
996 TMatrixRow(mnewtmp, evtcount1++) = vold = TMatrixRow(fM, ind[ir]);
997
998 for (Int_t ir=nmaxevts; ir<nrows; ir++)
999 TMatrixRow(mrest, evtcount2++) = vold = TMatrixRow(fM, ind[ir]);
1000
1001 //
1002 // reduce size
1003 //
1004 // matrix fM having the requested distribution
1005 // and the requested number of rows;
1006 // this is the matrix to be used in the g/h separation
1007 //
1008 CopyCrop(fM, mnewtmp, evtcount1);
1009 fNumRow = evtcount1;
1010
1011 if (evtcount1 < nmaxevts)
1012 *fLog << warn << "The reference sample contains less events (" << evtcount1 << ") than requested (" << nmaxevts << ")" << endl;
1013
1014 if (!rest)
1015 return kTRUE;
1016
1017 CopyCrop(*rest, mrest, evtcount2);
1018
1019 return kTRUE;
1020}
1021
1022// --------------------------------------------------------------------------
1023//
1024// overload TOject member function read
1025// in order to reset the name of the object read
1026//
1027Int_t MHMatrix::Read(const char *name)
1028{
1029 Int_t ret = TObject::Read(name);
1030 SetName(name);
1031
1032 return ret;
1033}
1034
1035// --------------------------------------------------------------------------
1036//
1037// Read the setup from a TEnv:
1038// Column0, Column1, Column2, ..., Column10, ..., Column100, ...
1039//
1040// Searching stops if the first key isn't found in the TEnv. Empty
1041// columns are not allowed
1042//
1043// eg.
1044// MHMatrix.Column0: cos(MMcEvt.fTelescopeTheta)
1045// MHMatrix.Column1: MHillasSrc.fAlpha
1046//
1047Bool_t MHMatrix::ReadEnv(const TEnv &env, TString prefix, Bool_t print)
1048{
1049 if (fM.IsValid())
1050 {
1051 *fLog << err << "ERROR - matrix is already in use. Can't add a new column from TEnv... skipped." << endl;
1052 return kERROR;
1053 }
1054
1055 if (TestBit(kIsLocked))
1056 {
1057 *fLog << err << "ERROR - matrix is locked. Can't add new column from TEnv... skipped." << endl;
1058 return kERROR;
1059 }
1060
1061 //
1062 // Search (beginning with 0) all keys
1063 //
1064 int i=0;
1065 while (1)
1066 {
1067 TString idx = "Column";
1068 idx += i;
1069
1070 // Output if print set to kTRUE
1071 if (!IsEnvDefined(env, prefix, idx, print))
1072 break;
1073
1074 // Try to get the file name
1075 TString name = GetEnvValue(env, prefix, idx, "");
1076 if (name.IsNull())
1077 {
1078 *fLog << warn << prefix+"."+idx << " empty." << endl;
1079 continue;
1080 }
1081
1082 if (i==0)
1083 if (fData)
1084 {
1085 *fLog << inf << "Removing all existing columns in " << GetDescriptor() << endl;
1086 fData->Delete();
1087 }
1088 else
1089 {
1090 fData = new MDataArray;
1091 SetBit(kIsOwner);
1092 }
1093
1094 fData->AddEntry(name);
1095 i++;
1096 }
1097
1098 return i!=0;
1099}
1100
1101// --------------------------------------------------------------------------
1102//
1103// ShuffleEvents. Shuffles the order of the matrix rows.
1104//
1105//
1106void MHMatrix::ShuffleRows(UInt_t seed)
1107{
1108 TRandom rnd(seed);
1109
1110 TVector v(fM.GetNcols());
1111 TVector tmp(fM.GetNcols());
1112 for (Int_t irow = 0; irow<fNumRow; irow++)
1113 {
1114 const Int_t jrow = rnd.Integer(fNumRow);
1115
1116 v = TMatrixRow(fM, irow);
1117 TMatrixRow(fM, irow) = tmp = TMatrixRow(fM, jrow);
1118 TMatrixRow(fM, jrow) = v;
1119 }
1120
1121 *fLog << warn << GetDescriptor() << ": Attention! Matrix rows have been shuffled." << endl;
1122}
1123
1124void MHMatrix::ReduceRows(UInt_t num)
1125{
1126 if ((Int_t)num>=fM.GetNrows())
1127 {
1128 *fLog << warn << GetDescriptor() << ": Warning - " << num << " >= rows=" << fM.GetNrows() << endl;
1129 return;
1130 }
1131
1132 const TMatrix m(fM);
1133 fM.ResizeTo(num, fM.GetNcols());
1134
1135 TVector tmp(fM.GetNcols());
1136 for (UInt_t irow=0; irow<num; irow++)
1137 TMatrixRow(fM, irow) = tmp = TMatrixRow(m, irow);
1138}
Note: See TracBrowser for help on using the repository browser.