00001 #include <iostream>
00002 #include <stdexcept>
00003
00004 using namespace std;
00005
00006 #include "TH2D.h"
00007 #include "TFile.h"
00008
00009 #include "NtupleUtils/NuMMParameters.h"
00010 #include "NtupleUtils/NuMatrixSpectrum.h"
00011 #include "NtupleUtils/NuFCExperiment.h"
00012 #include "NtupleUtils/NuFCFitter.h"
00013 #include "NtupleUtils/NuMMRunFC.h"
00014 #include "NtupleUtils/NuFCConfig.h"
00015
00016
00017 #include "MessageService/MsgService.h"
00018
00019 CVSID("$Id: NuFCFitter.cxx,v 1.11 2009/06/03 12:51:13 nickd Exp $");
00020
00022
00023 NuFCFitter::NuFCFitter(
00024 NuFCExperiment *experiment,
00025 NuMMHelperCPT *helper,
00026 NuMatrixSpectrum *ndNQData,
00027 NuMatrixSpectrum *ndPQData,
00028 const NuMMParameters &trueparams )
00029 : fRun(0),
00030 ffdNQData(0),
00031 ffdPQData(0),
00032 fsystFitter(),
00033 fBestFit(0),
00034 fFineGridSearch(false),
00035 fNegativeDeltaChi(false),
00036 fHighFitPoint(false),
00037 fZeroFitPoint(false),
00038 fArchive(false),
00039 fArchiveFilename("archive.root"),
00040 fTrueParams(trueparams)
00041 {
00042
00043
00044 ffdPQData = new NuMatrixSpectrum(experiment->GetPQSpectrum());
00045 ffdNQData = new NuMatrixSpectrum(experiment->GetNQSpectrum());
00046
00047
00048 fRun = new NuMMRunFC(helper, ndNQData, ndPQData, ffdNQData, ffdPQData);
00049 fRun->PredictNus(false);
00050 fRun->SetMaximumEnergy(49.999);
00051
00052
00053
00054 fsystFitter.push_back(fRun);
00055 fsystFitter.QuietModeOn();
00056 }
00057
00059
00060 NuFCFitter::~NuFCFitter()
00061 {
00062
00063 if (fRun) delete fRun;
00064 fRun = 0;
00065
00066
00067 if (ffdNQData) delete ffdNQData;
00068 if (ffdPQData) delete ffdPQData;
00069 ffdNQData = ffdPQData = 0;
00070
00071
00072 if (fBestFit) delete fBestFit;
00073 fBestFit = 0;
00074 }
00075
00077
00078 Double_t NuFCFitter::Fit(const NuMMParameters &fitParameters)
00079 {
00080
00081 const NuMMParameters mmGrid = CoarseGridSearch(fitParameters);
00082
00083
00084 NuMMParameters mmFit = MinuitFit(mmGrid);
00085
00086 Double_t dchi = DeltaChi(mmFit);
00087
00088
00089 if (dchi < 0) {
00090 if (dchi < -1e-5) {
00091 mmFit = RecoverNegativeDeltaChi(mmFit);
00092 dchi = DeltaChi(mmFit);
00093 } else {
00094
00095 dchi = 0;
00096 }
00097 }
00098
00099
00100 if (fBestFit) delete fBestFit;
00101 fBestFit = new NuMMParameters(mmFit);
00102
00103
00104
00105 ClassifyFitPoint(mmFit);
00106
00107
00108 if (fFineGridSearch || fArchive) {
00109 Archive(fArchiveFilename);
00110 }
00111
00112
00113 DoOutput(mmFit, dchi);
00114
00115 return dchi;
00116 }
00117
00119
00120 void NuFCFitter::DoOutput(const NuMMParameters &mmFit, Double_t deltachi )
00121 {
00122
00123 Double_t fitlike = fsystFitter(mmFit.VectorParameters());
00124 MSG("NuFCFitter", Msg::kInfo)
00125 << " Minimum is dm2bar: " << mmFit.Dm2Bar()
00126 << " sn2bar: " << mmFit.Sn2Bar() << '\n'
00127 << " Fit Likelyhood: " << fitlike << '\n'
00128 << " Delta Chi2: " << deltachi << '\n';
00129
00130
00131 if (fFineGridSearch || fNegativeDeltaChi)
00132 MSG("NuFCFitter", Msg::kInfo) << " Please Log this experiment." << endl;
00133
00134 }
00135
00137
00138 NuMMParameters NuFCFitter::MinuitFit(NuMMParameters mmStart)
00139 {
00140
00141
00142 if (mmStart.Sn2Bar() == 0) {
00143 MSG("NuFCFitter", Msg::kDebug) << " Starting minuit at no-oscillation; shifting to lower limits" << endl;
00144 mmStart.Sn2Bar(fTrueParams.LowerDm2BarLimit());
00145 mmStart.Dm2Bar(fTrueParams.LowerSn2BarLimit());
00146 }
00147
00148
00149 NuFCConfig &cfg = NuFCConfig::GetConfig();
00150 if (cfg.FixedSin()) {
00151 mmStart.FixSn2Bar();
00152 mmStart.Sn2Bar(fTrueParams.Sn2Bar());
00153 }
00154
00155
00156 NuMMParameters mmFit = fsystFitter.Minimise(mmStart);
00157
00158
00159 if (mmFit.MinuitPass())
00160 {
00161
00162 MSG("NuFCFitter", Msg::kInfo)
00163 << " Minuit found: dm2: " << mmFit.Dm2()
00164 << " sn2: " << mmFit.Sn2()
00165 << " dm2bar: " << mmFit.Dm2Bar()
00166 << " sn2bar: " << mmFit.Sn2Bar()
00167 << '\n';
00168 } else {
00169
00170
00171
00172 MSG("NuFCFitter", Msg::kInfo) << " Minuit fit failed." << endl;
00173 MSG("NuFCFitter", Msg::kInfo) << " Searching fine grid around sn2: " << mmStart.Sn2Bar()
00174 << ", dm2: " << mmStart.Dm2Bar() << endl;
00175 NuMMParameters mmFineGrid = FineGridSearch(mmStart);
00176 fFineGridSearch = true;
00177
00178
00179
00180 Double_t minuit_chi = fsystFitter(mmFit.VectorParameters());
00181 Double_t finegrid_chi = fsystFitter(mmFineGrid.VectorParameters());
00182
00183 if (minuit_chi > finegrid_chi) {
00184
00185 mmFit = mmFineGrid;
00186 } else {
00187
00188 MSG("NuFCFitter", Msg::kInfo) << " Failed Minuit fit is better than fine grid, using." << endl;
00189 }
00190
00191 }
00192
00193 return mmFit;
00194 }
00195
00197
00198 NuMMParameters NuFCFitter::CoarseGridSearch(NuMMParameters mmGrid)
00199 {
00200
00201 Int_t gridWidth = 5;
00202 Double_t sinMin = 0.2;
00203 Double_t sinMax = 1.0;
00204
00205 const Int_t gridHeight = 15;
00206
00207
00208
00209 NuFCConfig &cfg = NuFCConfig::GetConfig();
00210 if (cfg.FixedSin()) {
00211 gridWidth = 1;
00212 sinMin = sinMax = fTrueParams.Sn2Bar();
00213 }
00214
00215
00216 TH2D likesurf("likesurf", "likesurf", gridWidth, sinMin, sinMax, gridHeight, 2e-3, 30e-3);
00217 mmGrid = GridSearch(likesurf, mmGrid);
00218
00219
00220 vector<Double_t> bins;
00221 for (Int_t i = -15; i <= -1; i++) {
00222 bins.push_back(pow(10, (Double_t)i/10.0));
00223 }
00224 Int_t bincount = bins.size()-1;
00225 TH2D logsurf("logsurf", "logsurf", gridWidth, sinMin, sinMax, bincount, &(bins.front()));
00226 mmGrid = GridSearch(logsurf, mmGrid, &mmGrid);
00227
00228
00229 MSG("NuFCFitter", Msg::kInfo) << " Coarse grid search found sn2: "
00230 << mmGrid.Sn2Bar() << ", dm: " << mmGrid.Dm2Bar() << '\n';
00231
00232 return mmGrid;
00233 }
00234
00236
00237 NuMMParameters NuFCFitter::FineGridSearch(NuMMParameters mmStart)
00238 {
00239
00240 Double_t gridL, gridR, gridT, gridB;
00241 gridL = gridR = gridT = gridB = -1.0;
00242
00243
00244 Int_t gridWidth = 19;
00245 const Int_t gridHeight = 19;
00246
00247
00248 NuFCConfig &cfg = NuFCConfig::GetConfig();
00249
00250
00251 if (!cfg.FixedSin()) {
00252
00253 gridL = mmStart.Sn2Bar() - 0.2;
00254 gridR = gridL + 0.4;
00255
00256 if (gridL <= fTrueParams.LowerSn2BarLimit()) gridL = fTrueParams.LowerSn2BarLimit();
00257 if (gridR > 1.0) gridR = 1.0;
00258 } else {
00259
00260 gridL = gridR = fTrueParams.Sn2Bar();
00261 gridWidth = 1;
00262 }
00263
00264
00265 gridB = mmStart.Dm2Bar() - 2e-3;
00266 gridT = gridB + 4e-3;
00267
00268 if (gridB <= fTrueParams.LowerDm2BarLimit()) gridB = fTrueParams.LowerSn2BarLimit();
00269
00270 MSG("NuFCFitter", Msg::kInfo)
00271 << " Doing fine grid search on sin = [ "
00272 << gridL << ", " << gridR << " ]\n"
00273 << " dm = [ "
00274 << gridB << ", " << gridT << " ]\n";
00275
00276
00277 if (gridL > gridR || gridT <= gridB) {
00278
00279 throw runtime_error("Negative range in fine grid search");
00280 }
00281
00282
00283
00284
00285 TH2D likesurf("likesurf", "likesurf", gridWidth, gridL, gridR,
00286 gridHeight, gridB, gridT);
00287
00288
00289 NuMMParameters mmGrid = GridSearch(likesurf, mmStart);
00290
00291
00292
00293
00294
00295
00296
00297 MSG("NuFCFitter", Msg::kInfo) << " Fine grid search found sn2: "
00298 << mmGrid.Sn2Bar() << ", dm: " << mmGrid.Dm2Bar() << '\n';
00299
00300
00301 return mmGrid;
00302 }
00303
00305
00306 NuMMParameters NuFCFitter::GridSearch(TH2D &likesurf, NuMMParameters mmGrid, NuMMParameters *Ref)
00307 {
00308 Double_t likelihood = fsystFitter.FillLikelihoodSurfaceBar(likesurf, mmGrid);
00309
00310
00311 Int_t minbinX = 0, minbinY = 0, minbinZ = 0;
00312 likesurf.GetMinimumBin(minbinX, minbinY, minbinZ);
00313 Double_t minsin = likesurf.GetXaxis()->GetBinCenter(minbinX);
00314 Double_t minmass = likesurf.GetYaxis()->GetBinCenter(minbinY);
00315
00316
00317 NuFCConfig &cfg = NuFCConfig::GetConfig();
00318
00319
00320 mmGrid.Dm2Bar(0);
00321
00322 if (cfg.FixedSin()) {
00323 mmGrid.Sn2Bar(fTrueParams.Sn2Bar());
00324 } else {
00325 mmGrid.Sn2Bar(0);
00326 }
00327
00328 Double_t zeropoint = fsystFitter(mmGrid.VectorParameters());
00329 if (zeropoint < likelihood) {
00330
00331 minsin = 0.0;
00332 minmass = 0.0;
00333
00334 if (cfg.FixedSin()) {
00335 minsin = fTrueParams.Sn2Bar();
00336 }
00337 }
00338
00339
00340 if (Ref) {
00341 Double_t refpoint = fsystFitter(Ref->VectorParameters());
00342 if (refpoint < likelihood) {
00343 MSG("NuFCFitter", Msg::kDebug) << " Reference point is lower than grid search" << endl;
00344 minsin = Ref->Sn2Bar();
00345 minmass = Ref->Dm2Bar();
00346 }
00347 }
00348
00349
00350 mmGrid.Sn2Bar(minsin);
00351 mmGrid.Dm2Bar(minmass);
00352
00353 return mmGrid;
00354 }
00355
00357
00358 Double_t NuFCFitter::DeltaChi(const NuMMParameters& bestfit)
00359 {
00360
00361 Double_t fitlike = fsystFitter(bestfit.VectorParameters());
00362
00363 Double_t truelikelihood = 0;
00364
00365
00366
00367
00368
00369 if ( (fTrueParams.Dm2Bar() < fTrueParams.LowerDm2BarLimit()) ||
00370 (fTrueParams.Sn2Bar() < fTrueParams.LowerSn2BarLimit()) ) {
00371 MSG("NuFCFitter", Msg::kDebug) << " True point is lower than fit is allowed." << endl;
00372 NuMMParameters pc(bestfit);
00373 pc.Dm2Bar(fTrueParams.LowerDm2BarLimit());
00374 pc.Sn2Bar(fTrueParams.LowerSn2BarLimit());
00375 truelikelihood = fsystFitter(pc.VectorParameters());
00376 } else {
00377 truelikelihood = fsystFitter(fTrueParams.VectorParameters());
00378 }
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388 return truelikelihood - fitlike;
00389 }
00390
00392
00393
00394 NuMMParameters NuFCFitter::RecoverNegativeDeltaChi (const NuMMParameters& bestfit)
00395 {
00396
00397 fNegativeDeltaChi = true;
00398
00399
00400 Double_t truelike = fsystFitter(fTrueParams.VectorParameters());
00401 Double_t oldlike = fsystFitter(bestfit.VectorParameters());;
00402
00403
00404
00405 NuMMParameters tpcopy(fTrueParams);
00406 NuFCConfig &cfg = NuFCConfig::GetConfig();
00407 if (cfg.FixedSin()) {
00408 tpcopy.FixSn2Bar();
00409 }
00410
00411 NuMMParameters newFit = fsystFitter.Minimise(tpcopy);
00412
00413 MSG("NuFCFitter", Msg::kInfo)
00414 << " Negative delta chi2 likelihood (" << truelike - oldlike
00415 << ") found. Refitting from true (" << truelike << ")" << endl;
00416
00417
00418
00419 if (newFit.MinuitPass())
00420 {
00421 MSG("NuFCFitter", Msg::kInfo) << " Refit passed." << endl;
00422 Double_t newlike = fsystFitter(newFit.VectorParameters());
00423 if (newlike > oldlike) {
00424 MSG("NuFCFitter", Msg::kInfo)
00425 << " New fit point ( dm: " << newFit.Dm2Bar() << ", sn: " << newFit.Sn2Bar() << " )\n"
00426 << " at " << newlike << " is higher than before ( " << oldlike << " )! strange!\n"
00427 << " Returning true fit point, as is lowest we have seen."
00428 << endl;
00429 newFit = fTrueParams;
00430 }
00431 } else {
00432 MSG("NuFCFitter", Msg::kError)
00433 << " Unrecoverable error: Refit on negative deltachi failed."
00434 << endl;
00435 throw logic_error("NuFCFitter Refit on negative deltachi failed.");
00436 }
00437
00438 return newFit;
00439 }
00440
00442
00443 void NuFCFitter::ClassifyFitPoint(const NuMMParameters& mmFit)
00444 {
00445
00446
00447
00448 if (mmFit.Sn2Bar() <= fTrueParams.LowerSn2BarLimit() + 1e-4 ||
00449 mmFit.Dm2Bar() <= fTrueParams.LowerDm2BarLimit() + 1e-6 )
00450 {
00451 MSG("NuFCFitter", Msg::kInfo)
00452 << " Best fit is to no oscillation case\n";
00453 fZeroFitPoint = true;
00454 }
00455
00456
00457
00458 if (mmFit.Dm2Bar() >= 30e-3 - 0.25e-4) {
00459 MSG("NuFCFitter", Msg::kInfo)
00460 << " Best fit is maxing out on dm2bar ("
00461 << mmFit.Dm2Bar() << ")" << endl;
00462 fHighFitPoint = true;
00463 }
00464 }
00465
00467
00468 void NuFCFitter::Archive(std::string filename)
00469 {
00470 MSG("NuFCFitter",Msg::kInfo) << "Disabled all archiving." << endl;
00471 return;
00472
00473 if (!ffdPQData || !ffdNQData) {
00474 MSG("NUFCFitter",Msg::kError) << "No far detector spectrum: Cannot archive" << endl;
00475 return;
00476 }
00477 if (!fBestFit) {
00478 MSG("NuFCFitter", Msg::kError)
00479 << "Error: Trying to archive before fit" << endl;
00480 return;
00481 }
00482
00483 MSG("NuFCFitter", Msg::kInfo)
00484 << " Archiving to file " << filename << "..." << endl;
00485
00486
00487
00488 NuMatrixSpectrum fdSpec(*ffdPQData);
00489
00490
00491 string basename = fdSpec.Spectrum()->GetName();
00492
00493
00494
00495
00496
00497 string surfname = basename + "_surf";
00498 TH2D likesurface(surfname.c_str(), surfname.c_str(), 50, 0, 1, 100, 0, 20e-3);
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512
00513
00514
00515
00516
00517
00518 TFile tf(filename.c_str(), "UPDATE");
00519 fdSpec.Spectrum()->Write();
00520 likesurface.Write();
00521
00522 tf.Close();
00523 }
00524
00526
00527 void NuFCFitter::ShiftHistogram(TH2D &surface, Double_t shift)
00528 {
00529 for (Int_t x = 1; x <= surface.GetNbinsX(); x++)
00530 {
00531 for (Int_t y = 1; y <= surface.GetNbinsY(); y++)
00532 {
00533 Double_t contents = surface.GetBinContent(x, y);
00534 surface.SetBinContent(x, y, contents + shift);
00535 }
00536 }
00537 }