/* ======================================================================== *\ ! ! * ! * This file is part of MARS, the MAGIC Analysis and Reconstruction ! * Software. It is distributed to you in the hope that it can be a useful ! * and timesaving tool in analysing Data of imaging Cerenkov telescopes. ! * It is distributed WITHOUT ANY WARRANTY. ! * ! * Permission to use, copy, modify and distribute this software and its ! * documentation for any purpose is hereby granted without fee, ! * provided that the above copyright notice appear in all copies and ! * that both that copyright notice and this permission notice appear ! * in supporting documentation. It is provided "as is" without express ! * or implied warranty. ! * ! ! ! Author(s): Thomas Bretz 11/2005 ! ! Copyright: MAGIC Software Development, 2006 ! ! \* ======================================================================== */ ///////////////////////////////////////////////////////////////////////////// // // MJTrainSeparation // //////////////////////////////////////////////////////////////////////////// #include "MJTrainSeparation.h" #include #include #include #include #include #include "MHMatrix.h" #include "MLog.h" #include "MLogManip.h" // tools #include "MMath.h" #include "MDataSet.h" #include "MTFillMatrix.h" #include "MChisqEval.h" #include "MStatusDisplay.h" // eventloop #include "MParList.h" #include "MTaskList.h" #include "MEvtLoop.h" // tasks #include "MReadMarsFile.h" #include "MContinue.h" #include "MFillH.h" #include "MRanForestCalc.h" #include "MParameterCalc.h" // container #include "MMcEvt.hxx" #include "MParameters.h" // histograms #include "MBinning.h" #include "MH3.h" #include "MHHadronness.h" // filter #include "MF.h" #include "MFEventSelector.h" #include "MFilterList.h" ClassImp(MJTrainSeparation); using namespace std; void MJTrainSeparation::DisplayResult(MH3 &h31, MH3 &h32) { TH2 &g = (TH2&)h32.GetHist(); TH2 &h = (TH2&)h31.GetHist(); h.SetMarkerColor(kRed); g.SetMarkerColor(kGreen); const Int_t nx = h.GetNbinsX(); const Int_t ny = h.GetNbinsY(); gROOT->SetSelectedPad(NULL); TGraph gr1; TGraph gr2; for (int x=0; xIntegral(1, y+1); const Float_t b = hx->Integral(1, y+1); const Float_t sig1 = MMath::SignificanceLiMa(s+b, b); const Float_t sig2 = s<1 ? 0 : MMath::SignificanceLiMa(s+b, b)*TMath::Log10(s); if (sig1>max1) { maxy1 = y; max1 = sig1; } if (sig2>max2) { maxy2 = y; max2 = sig2; } } gr1.SetPoint(x, h.GetXaxis()->GetBinCenter(x+1), h.GetYaxis()->GetBinCenter(maxy1+1)); gr2.SetPoint(x, h.GetXaxis()->GetBinCenter(x+1), h.GetYaxis()->GetBinCenter(maxy2+1)); delete hx; delete gx; } fDisplay->AddTab("OptCut"); gPad->SetLogx(); h.DrawCopy(); g.DrawCopy("same"); gr1.SetMarkerStyle(kFullDotMedium); gr1.DrawClone("LP")->SetBit(kCanDelete); gr2.SetLineColor(kBlue); gr2.SetMarkerStyle(kFullDotMedium); gr2.DrawClone("LP")->SetBit(kCanDelete); } /* Bool_t MJSpectrum::InitWeighting(const MDataSet &set, MMcSpectrumWeight &w) const { fLog->Separator("Initialize energy weighting"); if (!CheckEnv(w)) { *fLog << err << "ERROR - Reading resources for MMcSpectrumWeight failed." << endl; return kFALSE; } TChain chain("RunHeaders"); set.AddFilesOn(chain); MMcCorsikaRunHeader *h=0; chain.SetBranchAddress("MMcCorsikaRunHeader.", &h); chain.GetEntry(1); if (!h) { *fLog << err << "ERROR - Couldn't read MMcCorsikaRunHeader from DataSet." << endl; return kFALSE; } if (!w.Set(*h)) { *fLog << err << "ERROR - Initializing MMcSpectrumWeight failed." << endl; return kFALSE; } w.Print(); return kTRUE; } Bool_t MJSpectrum::ReadOrigMCDistribution(const MDataSet &set, TH1 &h, MMcSpectrumWeight &weight) const { // Some debug output fLog->Separator("Compiling original MC distribution"); weight.SetNameMcEvt("MMcEvtBasic"); const TString w(weight.GetFormulaWeights()); weight.SetNameMcEvt(); *fLog << inf << "Using weights: " << w << endl; *fLog << "Please stand by, this may take a while..." << flush; if (fDisplay) fDisplay->SetStatusLine1("Compiling MC distribution..."); // Create chain TChain chain("OriginalMC"); set.AddFilesOn(chain); // Prepare histogram h.Reset(); // Fill histogram from chain h.SetDirectory(gROOT); if (h.InheritsFrom(TH2::Class())) { h.SetNameTitle("ThetaEMC", "Event-Distribution vs Theta and Energy for MC (produced)"); h.SetXTitle("\\Theta [\\circ]"); h.SetYTitle("E [GeV]"); h.SetZTitle("Counts"); chain.Draw("MMcEvtBasic.fEnergy:MMcEvtBasic.fTelescopeTheta*TMath::RadToDeg()>>ThetaEMC", w, "goff"); } else { h.SetNameTitle("ThetaMC", "Event-Distribution vs Theta for MC (produced)"); h.SetXTitle("\\Theta [\\circ]"); h.SetYTitle("Counts"); chain.Draw("MMcEvtBasic.fTelescopeTheta*TMath::RadToDeg()>>ThetaMC", w, "goff"); } h.SetDirectory(0); *fLog << "done." << endl; if (fDisplay) fDisplay->SetStatusLine2("done."); if (h.GetEntries()>0) return kTRUE; *fLog << err << "ERROR - Histogram with original MC distribution empty..." << endl; return h.GetEntries()>0; } */ Bool_t MJTrainSeparation::GetEventsProduced(MDataSet &set, Double_t &num, Double_t &min, Double_t &max) const { TChain chain("OriginalMC"); set.AddFilesOn(chain); min = chain.GetMinimum("MMcEvtBasic.fEnergy"); max = chain.GetMaximum("MMcEvtBasic.fEnergy"); num = chain.GetEntries(); if (num<100) *fLog << err << "ERROR - Less than 100 entries in OriginalMC-Tree of MC-Train-Data found." << endl; return num>=100; } Double_t MJTrainSeparation::GetDataRate(MDataSet &set) const { TChain chain1("Events"); set.AddFilesOff(chain1); const Double_t num = chain1.GetEntries(); if (num<100) { *fLog << err << "ERROR - Less than 100 entries in Events-Tree of Train-Data found." << endl; return -1; } TChain chain("EffectiveOnTime"); set.AddFilesOff(chain); TH1F h; h.SetDirectory(gROOT); h.SetNameTitle("OnTime", "Effective on-time"); chain.Draw("MEffectiveOnTime.fVal>>OnTime", "", "goff"); h.SetDirectory(0); if (h.Integral()<1) { *fLog << err << "ERROR - Less than 1s of effective observation time found in Train-Data." << endl; return -1; } *fLog << inf << "Found " << num << " events in " << h.Integral(); *fLog << "s (" << num/h.Integral() << "Hz)" << endl; return num/h.Integral(); } /* Scale: TF1 fold("old", "x^(-2.6)", emin, emax); TF1 fnew("new", "x^(-4.0)", emin, emax); TF1 q("q", "new/old", emin, emax); Double_t scale = 1./q.GetMaximum(emin, emax); // Anzahl produzierter Events vor MFEnergySlope: Double_t nold = fold.Integral(emin, emax); // Anzahl produzierter Events nach MFEnergySlope: Double_t nnew = fnew.Integral(emin, emax)*scale; class MFSpectrum : MMcSpectrumWeight { Double_t fScale; Bool_t fResult; MFSpectrum::MFSpectrum(const char *name, const char *title) { fName = name ? name : "MMcSpectrumWeight"; fTitle = title ? title : "Task to calculate weights to change the energy spectrum"; Init(fName, fTitle); } Int_t PreProcess(MParList *pList) { Int_t rc = MFSpectrumWeight::PreProcess(pList); if (rc!=kTRUE) return rc; fScale = fEval->GetMaximum(fEnergyMin, fEnergyMax); return kTRUE; } Int_t Process() { const Double_t e = fMcEvt->GetEnergy(); Double_t prob = fFunc->Eval(e)/fScale; const Float_t Nexp = fN0 * pow(energy,fMcSlope-fNewSlope); const Float_t Nrnd = ; fResult = Nexp >= gRandom->Uniform(); } } */ Bool_t MJTrainSeparation::AutoTrain() { Double_t num, min, max; if (!GetEventsProduced(fDataSetTrain, num, min, max)) return kFALSE; *fLog << inf << "Using build-in radius of 300m to calculate collection area!" << endl; // Target spectrum TF1 flx("Flux", "[0]*(x/1000)^(-2.6)", min, max); flx.SetParameter(0, 1e-5); // Number n0 of events this spectrum would produce per s and m^2 const Double_t n0 = flx.Integral(min, max); //[#] // Area produced in MC const Double_t A = TMath::Pi()*300*300; //[mē] // Rate R of events this spectrum would produce per s const Double_t R = n0*A; //[Hz] // Number N of events produced (in trainings sample) const Double_t N = num; //[#] // This correponds to an observation time T [s] const Double_t T = N/R; //[s] // With an average data rate after star of const Double_t r = GetDataRate(fDataSetTrain); //[Hz] // this yields a number of n events to be read for training const Double_t n = r*T; //[#] if (r<0) return kFALSE; *fLog << "Calculated a total Monte Carlo observation time of " << T << "s" << endl; *fLog << "For a data rate of " << r << "Hz this corresponds to " << n << " data events." << endl; fNumTrainOn = (UInt_t)-1; fNumTrainOff = TMath::Nint(n); /* An event rate dependent selection? ---------------------------------- Total average data rate: R Goal number of events: N Number of data events: N0 Rate assigned to single evt: r Selection probability: N/N0 * r/R f := N/N0 * r MF f("f * MEventRate.fRate < rand"); */ return kTRUE; } Bool_t MJTrainSeparation::Train(const char *out) { if (!fDataSetTrain.IsValid()) { *fLog << err << "ERROR - DataSet for training invalid!" << endl; return kFALSE; } if (!fDataSetTest.IsValid()) { *fLog << err << "ERROR - DataSet for testing invalid!" << endl; return kFALSE; } // ----------------------- Auto Train? ---------------------- if (fAutoTrain) if (!AutoTrain()) return kFALSE; // --------------------- Setup files -------------------- MReadMarsFile read1("Events"); MReadMarsFile read2("Events"); MReadMarsFile read3("Events"); MReadMarsFile read4("Events"); read1.DisableAutoScheme(); read2.DisableAutoScheme(); read3.DisableAutoScheme(); read4.DisableAutoScheme(); fDataSetTrain.AddFilesOn(read1); fDataSetTrain.AddFilesOff(read3); fDataSetTest.AddFilesOff(read2); fDataSetTest.AddFilesOn(read4); // ----------------------- Setup RF ---------------------- MHMatrix train("Train"); train.AddColumns(fRules); train.AddColumn("MHadronness.fVal"); // ----------------------- Fill Matrix RF ---------------------- MParameterD had("MHadronness"); MParList plistx; plistx.AddToList(&had); plistx.AddToList(this); MTFillMatrix fill; fill.SetLogStream(fLog); fill.SetDisplay(fDisplay); fill.AddPreCuts(fPreCuts); fill.AddPreCuts(fTrainCuts); // Set classifier for gammas had.SetVal(0); fill.SetName("FillGammas"); fill.SetDestMatrix1(&train, fNumTrainOn); fill.SetReader(&read1); if (!fill.Process(plistx)) return kFALSE; // Set classifier for hadrons had.SetVal(1); fill.SetName("FillBackground"); fill.SetDestMatrix1(&train, fNumTrainOff); fill.SetReader(&read3); if (!fill.Process(plistx)) return kFALSE; // ------------------------ Train RF -------------------------- MRanForestCalc rf; rf.SetNumTrees(fNumTrees); rf.SetNdSize(fNdSize); rf.SetNumTry(fNumTry); rf.SetNumObsoleteVariables(1); rf.SetDebug(fDebug); rf.SetDisplay(fDisplay); rf.SetLogStream(fLog); rf.SetFileName(out); rf.SetNameOutput("MHadronness"); //MBinning b(2, -0.5, 1.5, "BinningHadronness", "lin"); //if (!rf.TrainMultiRF(train, b.GetEdgesD())) // classification // return; //if (!rf.TrainSingleRF(train, b.GetEdgesD())) // classification // return; if (!rf.TrainSingleRF(train)) // regression return kFALSE; //fDisplay = rf.GetDisplay(); // --------------------- Display result ---------------------- gLog.Separator("Test"); MParList plist; MTaskList tlist; plist.AddToList(this); plist.AddToList(&tlist); MMcEvt mcevt; plist.AddToList(&mcevt); // ----- Setup histograms ----- MBinning binsy(100, 0 , 1, "BinningMH3Y", "lin"); MBinning binsx( 50, 10, 100000, "BinningMH3X", "log"); plist.AddToList(&binsx); plist.AddToList(&binsy); MH3 h31("MHillas.fSize", "MHadronness.fVal"); MH3 h32("MHillas.fSize", "MHadronness.fVal"); h31.SetTitle("Background probability vs. Size:Size [phe]:Hadronness"); h32.SetTitle("Background probability vs. Size:Size [phe]:Hadronness"); MHHadronness hist; // ----- Setup tasks ----- MFillH fillh0(&hist, "", "FillHadronness"); MFillH fillh1(&h31); MFillH fillh2(&h32); fillh1.SetNameTab("Background"); fillh2.SetNameTab("Gammas"); fillh0.SetBit(MFillH::kDoNotDisplay); // ----- Setup filter ----- MFilterList precuts; precuts.AddToList(fPreCuts); precuts.AddToList(fTestCuts); MContinue c0(&precuts); c0.SetName("PreCuts"); c0.SetInverted(); MFEventSelector sel; sel.SetNumSelectEvts(fNumTestOn); MContinue c1(&sel); c1.SetInverted(); // ----- Setup tasklist ----- tlist.AddToList(&read2); tlist.AddToList(&c0); tlist.AddToList(&c1); tlist.AddToList(&rf); tlist.AddToList(&fillh0); tlist.AddToList(&fillh1); // ----- Run eventloop on gammas ----- MEvtLoop loop; loop.SetDisplay(fDisplay); loop.SetLogStream(fLog); loop.SetParList(&plist); if (!loop.Eventloop()) return kFALSE; // ----- Setup and run eventloop on background ----- sel.SetNumSelectEvts(fNumTestOff); fillh0.ResetBit(MFillH::kDoNotDisplay); tlist.Replace(&read4); tlist.Replace(&fillh2); if (!loop.Eventloop()) return kFALSE; DisplayResult(h31, h32); if (!WriteDisplay(out)) return kFALSE; return kTRUE; }