Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

NuFCFitter.cxx

Go to the documentation of this file.
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     // Firstly, get copies of the far detector spectrum
00043   //NuMatrixSpectrum *fdNQ = &experiment->GetSpectrum();
00044   ffdPQData = new NuMatrixSpectrum(experiment->GetPQSpectrum());
00045   ffdNQData = new NuMatrixSpectrum(experiment->GetNQSpectrum());
00046   
00047   // Create the run!
00048   fRun = new NuMMRunFC(helper, ndNQData, ndPQData, ffdNQData, ffdPQData);
00049   fRun->PredictNus(false);
00050   fRun->SetMaximumEnergy(49.999);
00051   // fRun->QuietModeOn();
00052   
00053   // Now add this run to the fitter
00054   fsystFitter.push_back(fRun);
00055   fsystFitter.QuietModeOn();
00056 }
00057 
00059 
00060 NuFCFitter::~NuFCFitter()
00061 {
00062   // Delete our run object
00063   if (fRun) delete fRun;
00064   fRun = 0;
00065   
00066   // Delete our copies of the far detector data
00067   if (ffdNQData) delete ffdNQData;
00068   if (ffdPQData) delete ffdPQData;
00069   ffdNQData = ffdPQData = 0;
00070   
00071   // Delete the copy of the best fit point
00072   if (fBestFit) delete fBestFit;
00073   fBestFit = 0;
00074 }
00075 
00077 
00078 Double_t NuFCFitter::Fit(const NuMMParameters &fitParameters)
00079 {
00080   // Start with a coarse grid search, to seed minuit
00081   const NuMMParameters mmGrid = CoarseGridSearch(fitParameters);    
00082 
00083   // Now do a minuit fit
00084   NuMMParameters mmFit = MinuitFit(mmGrid);
00085 
00086   Double_t dchi = DeltaChi(mmFit);
00087 
00088   // If this gave a negative value, rescue it (allow a tiny gap)
00089   if (dchi < 0) {
00090     if (dchi < -1e-5) {
00091       mmFit = RecoverNegativeDeltaChi(mmFit);
00092       dchi = DeltaChi(mmFit);
00093     } else {
00094       // It is below zero, but within error. Set it to zero!
00095       dchi = 0;
00096     }
00097   }
00098 
00099   // Make a copy of the best fit point
00100   if (fBestFit) delete fBestFit;
00101   fBestFit = new NuMMParameters(mmFit);
00102 
00103   // Classify the best fit point i.e. is it zero, high etc
00104   // this is mainly for informational purposes (i.e. the run script)
00105   ClassifyFitPoint(mmFit);
00106 
00107   // Do we want to archive?
00108   if (fFineGridSearch || fArchive) { // || fNegativeDeltaChi
00109     Archive(fArchiveFilename);
00110   }
00111 
00112   // Do the output
00113   DoOutput(mmFit, dchi);
00114   
00115   return dchi;
00116 }
00117 
00119 
00120 void NuFCFitter::DoOutput(const NuMMParameters &mmFit, Double_t deltachi )
00121 {
00122   // Output the fit results
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   // Did we want to ask the control script to log this?
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   // If it is trying to start us at zero, reset to the search minimum
00141   // fTrueParams.LowerDm2BarLimit()) {
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   // Fix the sin, if specified
00149   NuFCConfig &cfg = NuFCConfig::GetConfig();
00150   if (cfg.FixedSin()) {
00151     mmStart.FixSn2Bar();
00152     mmStart.Sn2Bar(fTrueParams.Sn2Bar());
00153   }
00154   
00155   // Now run minuit itself
00156   NuMMParameters mmFit = fsystFitter.Minimise(mmStart);
00157   
00158   // Did minuit succeed?
00159   if (mmFit.MinuitPass())
00160   {
00161     // Tell them what minuit found
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       // Minuit failed to fit. Use a more intensive grid search,
00170       // starting on the minuit starting point (that we get from
00171       // a grid search)
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       // Test the fine grid search against the result from minuit = it could be possible
00179       // that minuit found a 'better' point, even if it failed
00180       Double_t minuit_chi = fsystFitter(mmFit.VectorParameters());
00181       Double_t finegrid_chi = fsystFitter(mmFineGrid.VectorParameters());
00182       
00183       if (minuit_chi > finegrid_chi) {
00184         // The new, fine grid point is better
00185         mmFit = mmFineGrid;
00186       } else {
00187         // The minuit fail point is actually better. Use that.
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   // The width and height of the grid
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   // Check if we are doing one-parameter fit, and if so constrain the grid search
00208   // to one-dimension
00209   NuFCConfig &cfg = NuFCConfig::GetConfig();
00210   if (cfg.FixedSin()) {
00211     gridWidth = 1;
00212     sinMin = sinMax = fTrueParams.Sn2Bar();
00213   }
00214 
00215   // Generate the surface
00216   TH2D likesurf("likesurf", "likesurf", gridWidth, sinMin, sinMax, gridHeight, 2e-3, 30e-3);
00217   mmGrid = GridSearch(likesurf, mmGrid);
00218   
00219   // Now do a log search
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   // Output the minimum
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   // Calculate the location of the fine grid search
00240   Double_t gridL, gridR, gridT, gridB;
00241   gridL = gridR = gridT = gridB = -1.0;
00242   
00243   // The width and height of the grid
00244   Int_t gridWidth = 19;
00245   const Int_t gridHeight = 19;
00246   
00247   // Configuration
00248   NuFCConfig &cfg = NuFCConfig::GetConfig();
00249   
00250   // change behavior if we want a one-parameter fit
00251   if (!cfg.FixedSin()) {
00252       // Go +- 0.2 in sin space
00253     gridL = mmStart.Sn2Bar() - 0.2;
00254     gridR = gridL + 0.4;
00255     // Now limit it to the physical realm
00256     if (gridL <= fTrueParams.LowerSn2BarLimit()) gridL = fTrueParams.LowerSn2BarLimit();
00257     if (gridR > 1.0) gridR = 1.0;
00258   } else {
00259     // One-parameter fit
00260     gridL = gridR = fTrueParams.Sn2Bar();
00261     gridWidth = 1;
00262   }
00263 
00264   // And go +-2e-3 in mass space
00265   gridB = mmStart.Dm2Bar() - 2e-3;
00266   gridT = gridB + 4e-3;
00267   // We only really need to worry about lower limit here
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   // Ensure that we haven't done anything stupid like set low above high
00277   if (gridL > gridR || gridT <= gridB) {
00278 //      cout << "Error: Negative range in fine grid search" << endl;
00279       throw runtime_error("Negative range in fine grid search");
00280   }
00281   
00282   // Make the surface
00283   
00284   // Generate the surface
00285   TH2D likesurf("likesurf", "likesurf", gridWidth, gridL, gridR,
00286     gridHeight, gridB, gridT);
00287     
00288   // And now do a grid search on this
00289   NuMMParameters mmGrid = GridSearch(likesurf, mmStart);
00290   
00291   // Temporarily, archive any fine grid surface
00292   // TFile tf("archives/finegrid.root", "UPDATE");
00293   //   likesurf.Write();
00294   //   tf.Close();
00295   
00296   // Output the minimum
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     // Find the point on this surface that is minimum
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     // Access the configuration
00317     NuFCConfig &cfg = NuFCConfig::GetConfig();
00318 
00319     // Check the zero point, to see if it is lower than anything else on the grid
00320     mmGrid.Dm2Bar(0);
00321     // Different 'zero' point if one parameter
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         // Then the no-oscillation case is the minimum
00331         minsin = 0.0;
00332         minmass = 0.0;
00333         
00334         if (cfg.FixedSin()) {
00335           minsin = fTrueParams.Sn2Bar();
00336         }
00337     }
00338     
00339     // If we have been given a reference point, check to see if this is lower
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     // Set mmPars to the newly found point, then return it
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     // Calculate the two likelihood points
00361     Double_t fitlike = fsystFitter(bestfit.VectorParameters());
00362 
00363     Double_t truelikelihood = 0;  
00364 
00365     // cout << "bfdm: " << bestfit.Dm2Bar() << ", limit = " << fTrueParams.LowerDm2BarLimit() << endl;
00366 
00367     // Don't allow the parameters to go below constrained - this can
00368     // give us an artificially negative delta chi2
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     // fmmPars.Dm2Bar(fmmPars.LowerDm2BarLimit());
00382     //   MAXMSG("NuFCGriPoint", 5, Msg::kInfo) << "Moving true grid point "
00383     //   fmmPars.Sn2Bar(fmmPars.LowerSn2BarLimit());
00384     //   
00385     // Double_t truelikelihood = fsystFitter(fTrueParams.VectorParameters());
00386 
00387     // Return the difference
00388     return truelikelihood - fitlike;
00389 }
00390 
00392 // We have gotten a negative delta chi2. Recover this!    
00393 
00394 NuMMParameters NuFCFitter::RecoverNegativeDeltaChi (const NuMMParameters& bestfit)
00395 {
00396   // Set the failure flag
00397   fNegativeDeltaChi = true;
00398 
00399   // Recalculate the likelihoods
00400   Double_t truelike = fsystFitter(fTrueParams.VectorParameters());
00401   Double_t oldlike = fsystFitter(bestfit.VectorParameters());;
00402 
00403   // Make a copy of the true parameters, to ensure that we do a 1D fit if specified
00404   // (this is assuming we cannot guarantee that the true parameters has the parameter fixed)
00405   NuMMParameters tpcopy(fTrueParams);
00406   NuFCConfig &cfg = NuFCConfig::GetConfig();
00407   if (cfg.FixedSin()) {
00408     tpcopy.FixSn2Bar();
00409   }
00410   // NuMMParameters newFit = fsystFitter.Minimise(fTrueParams);
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   // If this passed, and is lower than our old likelihood, then use it
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   // cout << "    Checking against minimum dm: " << fTrueParams.LowerDm2BarLimit() << ", sn: " << fTrueParams.LowerSn2BarLimit() << endl;
00446  
00447   // Check to see if the fit is to 'zero'
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   // Now check if the best fit is maxing out
00457   // This message is a little out of date, but will do for now
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   // The actual experiment spectrum
00487 //  TH1D fdSpec(*(ffdPQData->Spectrum()));
00488   NuMatrixSpectrum fdSpec(*ffdPQData);
00489 //   // fdSpec.RebinTo4GeV();
00490 //   // Grab the name out of this
00491   string basename = fdSpec.Spectrum()->GetName();
00492 // 
00493 // // No longer do the likelihood surface - it takes too long. Instead just write out the spectrum,
00494 // // and we can regenerate the surface later if we wish
00495 //   
00496   // Now we want the likelihood surfaces. First do the linear portion
00497   string surfname = basename + "_surf";
00498   TH2D likesurface(surfname.c_str(), surfname.c_str(), 50, 0, 1, 100, 0, 20e-3);
00499 //  TH2D likesurface(surfname.c_str(), surfname.c_str(), 100, 0.9, 1, 100, 0.002, 0.003);
00500 //  Double_t minlin = fsystFitter.FillLikelihoodSurfaceBar(likesurface, *fBestFit);
00501 //   
00502 //   // Now do the logarithmic plot
00503 //   vector<Double_t> bins;
00504 //   for (Int_t i = -204; i <= 0; i++) {
00505 //     bins.push_back(pow(10, (Double_t)i/100.0));
00506 //   }
00507 //   Int_t bincount = bins.size()-1;
00508 //   string logname = surfname + "_log";
00509 //   TH2D logsurf(logname.c_str(), logname.c_str(), 50, 0, 1, bincount, &(bins.front()));
00510 //   Double_t minlog = fsystFitter.FillLikelihoodSurfaceBar(logsurf, *fBestFit);
00511 //   
00512 //   // Now, shift both histograms by the minimum
00513 //   Double_t surfmin = minlin < minlog ? minlin : minlog;
00514 //   ShiftHistogram(likesurface, -surfmin);
00515 //   ShiftHistogram(logsurf, -surfmin);
00516   
00517   // Now, write these out!
00518   TFile tf(filename.c_str(), "UPDATE");
00519     fdSpec.Spectrum()->Write();
00520     likesurface.Write();
00521     // logsurf.Write();
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 }

Generated on Mon Feb 15 11:07:13 2010 for loon by  doxygen 1.3.9.1