// @(#)root/roostats:$Id$
// Author: Kyle Cranmer    June 2010
/*************************************************************************
 * Copyright (C) 1995-2008, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOSTATS_MaxLikelihoodEstimateTestStat
#define ROOSTATS_MaxLikelihoodEstimateTestStat

//_________________________________________________
/*
BEGIN_HTML
<p>
MaxLikelihoodEstimateTestStat: TestStatistic that returns maximum likelihood estimate of a specified parameter.
</p>
END_HTML
*/
//

#ifndef ROOT_Rtypes
#include "Rtypes.h"
#endif

#ifndef ROO_NLL_VAR
#include "RooNLLVar.h"
#endif

#include "RooFitResult.h"
#include "RooStats/TestStatistic.h"
#include "RooAbsPdf.h"
#include "RooRealVar.h"
#include "RooMinimizer.h"
#include "Math/MinimizerOptions.h"
#include "RooStats/RooStatsUtils.h"



namespace RooStats {

class MaxLikelihoodEstimateTestStat: public TestStatistic {

   public:

   //__________________________________
   MaxLikelihoodEstimateTestStat() :
   fPdf(NULL),fParameter(NULL), fUpperLimit(true)
   {
     // constructor
     //      fPdf = pdf;
     //      fParameter = parameter;

	fMinimizer=::ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str();
	fStrategy=::ROOT::Math::MinimizerOptions::DefaultStrategy();
	fPrintLevel=::ROOT::Math::MinimizerOptions::DefaultPrintLevel();

   }
   //__________________________________
   MaxLikelihoodEstimateTestStat(RooAbsPdf& pdf, RooRealVar& parameter) :
   fPdf(&pdf),fParameter(&parameter), fUpperLimit(true)
   {
      // constructor
      //      fPdf = pdf;
      //      fParameter = parameter;
	fMinimizer=::ROOT::Math::MinimizerOptions::DefaultMinimizerType().c_str();
	fStrategy=::ROOT::Math::MinimizerOptions::DefaultStrategy();
	fPrintLevel=::ROOT::Math::MinimizerOptions::DefaultPrintLevel();

   }

  //______________________________
  virtual Double_t Evaluate(RooAbsData& data, RooArgSet& /*nullPOI*/) {
      
    
    RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
    RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);

    /*
    // this is more straight forward, but produces a lot of messages
    RooFitResult* res = fPdf.fitTo(data, RooFit::CloneData(kFALSE),RooFit::Minos(0),RooFit::Hesse(false), RooFit::Save(1),RooFit::PrintLevel(-1),RooFit::PrintEvalErrors(0));
    RooRealVar* mle = (RooRealVar*) res->floatParsFinal().find(fParameter.GetName());
    double ret = mle->getVal();
    delete res;
    return ret;
    */

    RooArgSet* allParams = fPdf->getParameters(data);
    RooStats::RemoveConstantParameters(allParams);

    // need to call constrain for RooSimultaneous until stripDisconnected problem fixed
    RooAbsReal* nll = fPdf->createNLL(data, RooFit::CloneData(kFALSE),RooFit::Constrain(*allParams),RooFit::ConditionalObservables(fConditionalObs));

    //RooAbsReal* nll = fPdf->createNLL(data, RooFit::CloneData(false));

    // RooAbsReal* profile = nll->createProfile(RooArgSet());
    // profile->getVal();
    // RooArgSet* vars = profile->getVariables();
    // RooMsgService::instance().setGlobalKillBelow(msglevel);
    // double ret = vars->getRealValue(fParameter->GetName());
    // delete vars;
    // delete nll;
    // delete profile;
    // return ret;


     RooMinimizer minim(*nll);
     minim.setStrategy(fStrategy);
     //LM: RooMinimizer.setPrintLevel has +1 offset - so subtruct  here -1
     minim.setPrintLevel(fPrintLevel-1);
     int status = -1;
     //	minim.optimizeConst(true);
     for (int tries = 0, maxtries = 4; tries <= maxtries; ++tries) {
	  //	 status = minim.minimize(fMinimizer, ROOT::Math::MinimizerOptions::DefaultMinimizerAlgo().c_str());
        status = minim.minimize(fMinimizer, "Minimize");
        if (status == 0) {  
           break;
        } else {
           if (tries > 1) {
	      printf("    ----> Doing a re-scan first\n");
	      minim.minimize(fMinimizer,"Scan");
	    }
           if (tries > 2) {
	      printf("    ----> trying with strategy = 1\n");
              minim.setStrategy(1);
           }
        }
     }
     //std::cout << "BEST FIT values " << std::endl;
     //allParams->Print("V");

     RooMsgService::instance().setGlobalKillBelow(msglevel);
     delete nll;

     if (status != 0) return -1; 
     return fParameter->getVal();


  }
  
  virtual const TString GetVarName() const { 
    TString varName = Form("Maximum Likelihood Estimate of %s",fParameter->GetName());
    return varName;
  }

      
  virtual void PValueIsRightTail(bool isright) {  fUpperLimit = isright; }
  virtual bool PValueIsRightTail(void) const { return fUpperLimit; }

   // set the conditional observables which will be used when creating the NLL
   // so the pdf's will not be normalized on the conditional observables when computing the NLL 
   virtual void SetConditionalObservables(const RooArgSet& set) {fConditionalObs.removeAll(); fConditionalObs.add(set);}


   private:
      RooAbsPdf *fPdf;
      RooRealVar *fParameter;
      RooArgSet fConditionalObs;
      bool fUpperLimit;
      TString fMinimizer;
      Int_t fStrategy;
      Int_t fPrintLevel;



   protected:
   ClassDef(MaxLikelihoodEstimateTestStat,2)
};

}


#endif
 MaxLikelihoodEstimateTestStat.h:1
 MaxLikelihoodEstimateTestStat.h:2
 MaxLikelihoodEstimateTestStat.h:3
 MaxLikelihoodEstimateTestStat.h:4
 MaxLikelihoodEstimateTestStat.h:5
 MaxLikelihoodEstimateTestStat.h:6
 MaxLikelihoodEstimateTestStat.h:7
 MaxLikelihoodEstimateTestStat.h:8
 MaxLikelihoodEstimateTestStat.h:9
 MaxLikelihoodEstimateTestStat.h:10
 MaxLikelihoodEstimateTestStat.h:11
 MaxLikelihoodEstimateTestStat.h:12
 MaxLikelihoodEstimateTestStat.h:13
 MaxLikelihoodEstimateTestStat.h:14
 MaxLikelihoodEstimateTestStat.h:15
 MaxLikelihoodEstimateTestStat.h:16
 MaxLikelihoodEstimateTestStat.h:17
 MaxLikelihoodEstimateTestStat.h:18
 MaxLikelihoodEstimateTestStat.h:19
 MaxLikelihoodEstimateTestStat.h:20
 MaxLikelihoodEstimateTestStat.h:21
 MaxLikelihoodEstimateTestStat.h:22
 MaxLikelihoodEstimateTestStat.h:23
 MaxLikelihoodEstimateTestStat.h:24
 MaxLikelihoodEstimateTestStat.h:25
 MaxLikelihoodEstimateTestStat.h:26
 MaxLikelihoodEstimateTestStat.h:27
 MaxLikelihoodEstimateTestStat.h:28
 MaxLikelihoodEstimateTestStat.h:29
 MaxLikelihoodEstimateTestStat.h:30
 MaxLikelihoodEstimateTestStat.h:31
 MaxLikelihoodEstimateTestStat.h:32
 MaxLikelihoodEstimateTestStat.h:33
 MaxLikelihoodEstimateTestStat.h:34
 MaxLikelihoodEstimateTestStat.h:35
 MaxLikelihoodEstimateTestStat.h:36
 MaxLikelihoodEstimateTestStat.h:37
 MaxLikelihoodEstimateTestStat.h:38
 MaxLikelihoodEstimateTestStat.h:39
 MaxLikelihoodEstimateTestStat.h:40
 MaxLikelihoodEstimateTestStat.h:41
 MaxLikelihoodEstimateTestStat.h:42
 MaxLikelihoodEstimateTestStat.h:43
 MaxLikelihoodEstimateTestStat.h:44
 MaxLikelihoodEstimateTestStat.h:45
 MaxLikelihoodEstimateTestStat.h:46
 MaxLikelihoodEstimateTestStat.h:47
 MaxLikelihoodEstimateTestStat.h:48
 MaxLikelihoodEstimateTestStat.h:49
 MaxLikelihoodEstimateTestStat.h:50
 MaxLikelihoodEstimateTestStat.h:51
 MaxLikelihoodEstimateTestStat.h:52
 MaxLikelihoodEstimateTestStat.h:53
 MaxLikelihoodEstimateTestStat.h:54
 MaxLikelihoodEstimateTestStat.h:55
 MaxLikelihoodEstimateTestStat.h:56
 MaxLikelihoodEstimateTestStat.h:57
 MaxLikelihoodEstimateTestStat.h:58
 MaxLikelihoodEstimateTestStat.h:59
 MaxLikelihoodEstimateTestStat.h:60
 MaxLikelihoodEstimateTestStat.h:61
 MaxLikelihoodEstimateTestStat.h:62
 MaxLikelihoodEstimateTestStat.h:63
 MaxLikelihoodEstimateTestStat.h:64
 MaxLikelihoodEstimateTestStat.h:65
 MaxLikelihoodEstimateTestStat.h:66
 MaxLikelihoodEstimateTestStat.h:67
 MaxLikelihoodEstimateTestStat.h:68
 MaxLikelihoodEstimateTestStat.h:69
 MaxLikelihoodEstimateTestStat.h:70
 MaxLikelihoodEstimateTestStat.h:71
 MaxLikelihoodEstimateTestStat.h:72
 MaxLikelihoodEstimateTestStat.h:73
 MaxLikelihoodEstimateTestStat.h:74
 MaxLikelihoodEstimateTestStat.h:75
 MaxLikelihoodEstimateTestStat.h:76
 MaxLikelihoodEstimateTestStat.h:77
 MaxLikelihoodEstimateTestStat.h:78
 MaxLikelihoodEstimateTestStat.h:79
 MaxLikelihoodEstimateTestStat.h:80
 MaxLikelihoodEstimateTestStat.h:81
 MaxLikelihoodEstimateTestStat.h:82
 MaxLikelihoodEstimateTestStat.h:83
 MaxLikelihoodEstimateTestStat.h:84
 MaxLikelihoodEstimateTestStat.h:85
 MaxLikelihoodEstimateTestStat.h:86
 MaxLikelihoodEstimateTestStat.h:87
 MaxLikelihoodEstimateTestStat.h:88
 MaxLikelihoodEstimateTestStat.h:89
 MaxLikelihoodEstimateTestStat.h:90
 MaxLikelihoodEstimateTestStat.h:91
 MaxLikelihoodEstimateTestStat.h:92
 MaxLikelihoodEstimateTestStat.h:93
 MaxLikelihoodEstimateTestStat.h:94
 MaxLikelihoodEstimateTestStat.h:95
 MaxLikelihoodEstimateTestStat.h:96
 MaxLikelihoodEstimateTestStat.h:97
 MaxLikelihoodEstimateTestStat.h:98
 MaxLikelihoodEstimateTestStat.h:99
 MaxLikelihoodEstimateTestStat.h:100
 MaxLikelihoodEstimateTestStat.h:101
 MaxLikelihoodEstimateTestStat.h:102
 MaxLikelihoodEstimateTestStat.h:103
 MaxLikelihoodEstimateTestStat.h:104
 MaxLikelihoodEstimateTestStat.h:105
 MaxLikelihoodEstimateTestStat.h:106
 MaxLikelihoodEstimateTestStat.h:107
 MaxLikelihoodEstimateTestStat.h:108
 MaxLikelihoodEstimateTestStat.h:109
 MaxLikelihoodEstimateTestStat.h:110
 MaxLikelihoodEstimateTestStat.h:111
 MaxLikelihoodEstimateTestStat.h:112
 MaxLikelihoodEstimateTestStat.h:113
 MaxLikelihoodEstimateTestStat.h:114
 MaxLikelihoodEstimateTestStat.h:115
 MaxLikelihoodEstimateTestStat.h:116
 MaxLikelihoodEstimateTestStat.h:117
 MaxLikelihoodEstimateTestStat.h:118
 MaxLikelihoodEstimateTestStat.h:119
 MaxLikelihoodEstimateTestStat.h:120
 MaxLikelihoodEstimateTestStat.h:121
 MaxLikelihoodEstimateTestStat.h:122
 MaxLikelihoodEstimateTestStat.h:123
 MaxLikelihoodEstimateTestStat.h:124
 MaxLikelihoodEstimateTestStat.h:125
 MaxLikelihoodEstimateTestStat.h:126
 MaxLikelihoodEstimateTestStat.h:127
 MaxLikelihoodEstimateTestStat.h:128
 MaxLikelihoodEstimateTestStat.h:129
 MaxLikelihoodEstimateTestStat.h:130
 MaxLikelihoodEstimateTestStat.h:131
 MaxLikelihoodEstimateTestStat.h:132
 MaxLikelihoodEstimateTestStat.h:133
 MaxLikelihoodEstimateTestStat.h:134
 MaxLikelihoodEstimateTestStat.h:135
 MaxLikelihoodEstimateTestStat.h:136
 MaxLikelihoodEstimateTestStat.h:137
 MaxLikelihoodEstimateTestStat.h:138
 MaxLikelihoodEstimateTestStat.h:139
 MaxLikelihoodEstimateTestStat.h:140
 MaxLikelihoodEstimateTestStat.h:141
 MaxLikelihoodEstimateTestStat.h:142
 MaxLikelihoodEstimateTestStat.h:143
 MaxLikelihoodEstimateTestStat.h:144
 MaxLikelihoodEstimateTestStat.h:145
 MaxLikelihoodEstimateTestStat.h:146
 MaxLikelihoodEstimateTestStat.h:147
 MaxLikelihoodEstimateTestStat.h:148
 MaxLikelihoodEstimateTestStat.h:149
 MaxLikelihoodEstimateTestStat.h:150
 MaxLikelihoodEstimateTestStat.h:151
 MaxLikelihoodEstimateTestStat.h:152
 MaxLikelihoodEstimateTestStat.h:153
 MaxLikelihoodEstimateTestStat.h:154
 MaxLikelihoodEstimateTestStat.h:155
 MaxLikelihoodEstimateTestStat.h:156
 MaxLikelihoodEstimateTestStat.h:157
 MaxLikelihoodEstimateTestStat.h:158
 MaxLikelihoodEstimateTestStat.h:159
 MaxLikelihoodEstimateTestStat.h:160
 MaxLikelihoodEstimateTestStat.h:161
 MaxLikelihoodEstimateTestStat.h:162
 MaxLikelihoodEstimateTestStat.h:163
 MaxLikelihoodEstimateTestStat.h:164
 MaxLikelihoodEstimateTestStat.h:165
 MaxLikelihoodEstimateTestStat.h:166
 MaxLikelihoodEstimateTestStat.h:167
 MaxLikelihoodEstimateTestStat.h:168
 MaxLikelihoodEstimateTestStat.h:169
 MaxLikelihoodEstimateTestStat.h:170
 MaxLikelihoodEstimateTestStat.h:171
 MaxLikelihoodEstimateTestStat.h:172
 MaxLikelihoodEstimateTestStat.h:173
 MaxLikelihoodEstimateTestStat.h:174
 MaxLikelihoodEstimateTestStat.h:175