// @(#)root/roostats:$Id: FrequentistCalculator.cxx 37084 2010-11-29 21:37:13Z moneta $
// Author: Kyle Cranmer, Sven Kreiss   23/05/10
/*************************************************************************
 * 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.             *
 *************************************************************************/

/**
Does a frequentist hypothesis test. Nuisance parameters are fixed to their
MLEs.
*/

#include "RooStats/FrequentistCalculator.h"
#include "RooStats/ToyMCSampler.h"
#include "RooMinimizer.h"
#include "RooMinuit.h"
#include "RooProfileLL.h"


ClassImp(RooStats::FrequentistCalculator)

using namespace RooStats;
using namespace std;

void FrequentistCalculator::PreHook() const {
   if (fFitInfo != NULL) {
      delete fFitInfo;
      fFitInfo = NULL;
   }
   if (fStoreFitInfo) {
      fFitInfo = new RooArgSet();
   }
}

void FrequentistCalculator::PostHook() const {
}

int FrequentistCalculator::PreNullHook(RooArgSet *parameterPoint, double obsTestStat) const {

   // ****** any TestStatSampler ********

   // create profile keeping everything but nuisance parameters fixed
   RooArgSet * allParams = fNullModel->GetPdf()->getParameters(*fData);
   RemoveConstantParameters(allParams);

   // note: making nll or profile class variables can only be done in the constructor
   // as all other hooks are const (which has to be because GetHypoTest is const). However,
   // when setting it only in constructor, they would have to be changed every time SetNullModel
   // or SetAltModel is called. Simply put, converting them into class variables breaks
   // encapsulation.

   bool doProfile = true;
   RooArgSet allButNuisance(*allParams);
   if( fNullModel->GetNuisanceParameters() ) {
      allButNuisance.remove(*fNullModel->GetNuisanceParameters());
      if( fConditionalMLEsNull ) {
         oocoutI((TObject*)0,InputArguments) << "Using given conditional MLEs for Null." << endl;
         *allParams = *fConditionalMLEsNull;
         // LM: fConditionalMLEsNull must be nuisance parameters otherwise an error message will be printed
         allButNuisance.add( *fConditionalMLEsNull );
         if (fNullModel->GetNuisanceParameters()) {
            RooArgSet remain(*fNullModel->GetNuisanceParameters());
            remain.remove(*fConditionalMLEsNull,true,true);
            if( remain.getSize() == 0 ) doProfile = false;
         }
      }
   }else{
      doProfile = false;
   }
   if (doProfile) {
      oocoutI((TObject*)0,InputArguments) << "Profiling conditional MLEs for Null." << endl;
      RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
      RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);

      RooArgSet conditionalObs;
      if (fNullModel->GetConditionalObservables()) conditionalObs.add(*fNullModel->GetConditionalObservables());
      
      RooAbsReal* nll = fNullModel->GetPdf()->createNLL(*const_cast<RooAbsData*>(fData), RooFit::CloneData(kFALSE), RooFit::Constrain(*allParams), 
                                                        RooFit::ConditionalObservables(conditionalObs), RooFit::Offset(RooStats::IsNLLOffset()) );
      RooProfileLL* profile = dynamic_cast<RooProfileLL*>(nll->createProfile(allButNuisance));
      profile->getVal(); // this will do fit and set nuisance parameters to profiled values

      // Hack to extract a RooFitResult
      if (fStoreFitInfo) {
         RooFitResult *result = profile->minimizer()->save();
         RooArgSet * detOutput = DetailedOutputAggregator::GetAsArgSet(result, "fitNull_");
         fFitInfo->addOwned(*detOutput);
         delete detOutput; 
         delete result;
      }
   
      delete profile;
      delete nll;
      RooMsgService::instance().setGlobalKillBelow(msglevel);
   }
   
   // add nuisance parameters to parameter point
   if(fNullModel->GetNuisanceParameters())
      parameterPoint->add(*fNullModel->GetNuisanceParameters());

   delete allParams;



   // ***** ToyMCSampler specific *******

   // check whether TestStatSampler is a ToyMCSampler
   ToyMCSampler *toymcs = dynamic_cast<ToyMCSampler*>(GetTestStatSampler());
   if(toymcs) {
      oocoutI((TObject*)0,InputArguments) << "Using a ToyMCSampler. Now configuring for Null." << endl;

      // variable number of toys
      if(fNToysNull >= 0) toymcs->SetNToys(fNToysNull);

      // set the global observables to be generated by the ToyMCSampler
      toymcs->SetGlobalObservables(*fNullModel->GetGlobalObservables());

      // adaptive sampling
      if(fNToysNullTail) {
         oocoutI((TObject*)0,InputArguments) << "Adaptive Sampling" << endl;
         if(GetTestStatSampler()->GetTestStatistic()->PValueIsRightTail()) {
            toymcs->SetToysRightTail(fNToysNullTail, obsTestStat);
         }else{
            toymcs->SetToysLeftTail(fNToysNullTail, obsTestStat);
         }
      }else{
         toymcs->SetToysBothTails(0, 0, obsTestStat); // disable adaptive sampling
      }

      GetNullModel()->LoadSnapshot();
   }

   return 0;
}


int FrequentistCalculator::PreAltHook(RooArgSet *parameterPoint, double obsTestStat) const {

   // ****** any TestStatSampler ********

   // create profile keeping everything but nuisance parameters fixed
   RooArgSet * allParams = fAltModel->GetPdf()->getParameters(*fData);
   RemoveConstantParameters(allParams);

   bool doProfile = true;
   RooArgSet allButNuisance(*allParams);
   if( fAltModel->GetNuisanceParameters() ) {
      allButNuisance.remove(*fAltModel->GetNuisanceParameters());
      if( fConditionalMLEsAlt ) {
         oocoutI((TObject*)0,InputArguments) << "Using given conditional MLEs for Alt." << endl;
         *allParams = *fConditionalMLEsAlt;
         // LM: fConditionalMLEsAlt must be nuisance parameters otherwise an error message will be printed
         allButNuisance.add( *fConditionalMLEsAlt );
         if (fAltModel->GetNuisanceParameters()) {
            RooArgSet remain(*fAltModel->GetNuisanceParameters());
            remain.remove(*fConditionalMLEsAlt,true,true);
            if( remain.getSize() == 0 ) doProfile = false;
         }
      }
   }else{
      doProfile = false;
   }
   if (doProfile) {
      oocoutI((TObject*)0,InputArguments) << "Profiling conditional MLEs for Alt." << endl;
      RooFit::MsgLevel msglevel = RooMsgService::instance().globalKillBelow();
      RooMsgService::instance().setGlobalKillBelow(RooFit::FATAL);

      RooArgSet conditionalObs;
      if (fAltModel->GetConditionalObservables()) conditionalObs.add(*fAltModel->GetConditionalObservables());
            
      RooAbsReal* nll = fAltModel->GetPdf()->createNLL(*const_cast<RooAbsData*>(fData), RooFit::CloneData(kFALSE), RooFit::Constrain(*allParams),
                                                       RooFit::ConditionalObservables(conditionalObs), RooFit::Offset(RooStats::IsNLLOffset()));

      RooProfileLL* profile = dynamic_cast<RooProfileLL*>(nll->createProfile(allButNuisance));
      profile->getVal(); // this will do fit and set nuisance parameters to profiled values

      // Hack to extract a RooFitResult
      if (fStoreFitInfo) {
         RooFitResult *result = profile->minimizer()->save();
         RooArgSet * detOutput =  DetailedOutputAggregator::GetAsArgSet(result, "fitAlt_");
         fFitInfo->addOwned(*detOutput);
         delete detOutput;
         delete result;
      }
   
      delete profile;
      delete nll;
      RooMsgService::instance().setGlobalKillBelow(msglevel);
   }
   
   // add nuisance parameters to parameter point
   if(fAltModel->GetNuisanceParameters())
      parameterPoint->add(*fAltModel->GetNuisanceParameters());

   delete allParams;




   // ***** ToyMCSampler specific *******

   // check whether TestStatSampler is a ToyMCSampler
   ToyMCSampler *toymcs = dynamic_cast<ToyMCSampler*>(GetTestStatSampler());
   if(toymcs) {
      oocoutI((TObject*)0,InputArguments) << "Using a ToyMCSampler. Now configuring for Alt." << endl;

      // variable number of toys
      if(fNToysAlt >= 0) toymcs->SetNToys(fNToysAlt);

      // set the global observables to be generated by the ToyMCSampler
      toymcs->SetGlobalObservables(*fAltModel->GetGlobalObservables());

      // adaptive sampling
      if(fNToysAltTail) {
         oocoutI((TObject*)0,InputArguments) << "Adaptive Sampling" << endl;
         if(GetTestStatSampler()->GetTestStatistic()->PValueIsRightTail()) {
            toymcs->SetToysLeftTail(fNToysAltTail, obsTestStat);
         }else{
            toymcs->SetToysRightTail(fNToysAltTail, obsTestStat);
         }
      }else{
         toymcs->SetToysBothTails(0, 0, obsTestStat); // disable adaptive sampling
      }

   }

   return 0;
}




 FrequentistCalculator.cxx:1
 FrequentistCalculator.cxx:2
 FrequentistCalculator.cxx:3
 FrequentistCalculator.cxx:4
 FrequentistCalculator.cxx:5
 FrequentistCalculator.cxx:6
 FrequentistCalculator.cxx:7
 FrequentistCalculator.cxx:8
 FrequentistCalculator.cxx:9
 FrequentistCalculator.cxx:10
 FrequentistCalculator.cxx:11
 FrequentistCalculator.cxx:12
 FrequentistCalculator.cxx:13
 FrequentistCalculator.cxx:14
 FrequentistCalculator.cxx:15
 FrequentistCalculator.cxx:16
 FrequentistCalculator.cxx:17
 FrequentistCalculator.cxx:18
 FrequentistCalculator.cxx:19
 FrequentistCalculator.cxx:20
 FrequentistCalculator.cxx:21
 FrequentistCalculator.cxx:22
 FrequentistCalculator.cxx:23
 FrequentistCalculator.cxx:24
 FrequentistCalculator.cxx:25
 FrequentistCalculator.cxx:26
 FrequentistCalculator.cxx:27
 FrequentistCalculator.cxx:28
 FrequentistCalculator.cxx:29
 FrequentistCalculator.cxx:30
 FrequentistCalculator.cxx:31
 FrequentistCalculator.cxx:32
 FrequentistCalculator.cxx:33
 FrequentistCalculator.cxx:34
 FrequentistCalculator.cxx:35
 FrequentistCalculator.cxx:36
 FrequentistCalculator.cxx:37
 FrequentistCalculator.cxx:38
 FrequentistCalculator.cxx:39
 FrequentistCalculator.cxx:40
 FrequentistCalculator.cxx:41
 FrequentistCalculator.cxx:42
 FrequentistCalculator.cxx:43
 FrequentistCalculator.cxx:44
 FrequentistCalculator.cxx:45
 FrequentistCalculator.cxx:46
 FrequentistCalculator.cxx:47
 FrequentistCalculator.cxx:48
 FrequentistCalculator.cxx:49
 FrequentistCalculator.cxx:50
 FrequentistCalculator.cxx:51
 FrequentistCalculator.cxx:52
 FrequentistCalculator.cxx:53
 FrequentistCalculator.cxx:54
 FrequentistCalculator.cxx:55
 FrequentistCalculator.cxx:56
 FrequentistCalculator.cxx:57
 FrequentistCalculator.cxx:58
 FrequentistCalculator.cxx:59
 FrequentistCalculator.cxx:60
 FrequentistCalculator.cxx:61
 FrequentistCalculator.cxx:62
 FrequentistCalculator.cxx:63
 FrequentistCalculator.cxx:64
 FrequentistCalculator.cxx:65
 FrequentistCalculator.cxx:66
 FrequentistCalculator.cxx:67
 FrequentistCalculator.cxx:68
 FrequentistCalculator.cxx:69
 FrequentistCalculator.cxx:70
 FrequentistCalculator.cxx:71
 FrequentistCalculator.cxx:72
 FrequentistCalculator.cxx:73
 FrequentistCalculator.cxx:74
 FrequentistCalculator.cxx:75
 FrequentistCalculator.cxx:76
 FrequentistCalculator.cxx:77
 FrequentistCalculator.cxx:78
 FrequentistCalculator.cxx:79
 FrequentistCalculator.cxx:80
 FrequentistCalculator.cxx:81
 FrequentistCalculator.cxx:82
 FrequentistCalculator.cxx:83
 FrequentistCalculator.cxx:84
 FrequentistCalculator.cxx:85
 FrequentistCalculator.cxx:86
 FrequentistCalculator.cxx:87
 FrequentistCalculator.cxx:88
 FrequentistCalculator.cxx:89
 FrequentistCalculator.cxx:90
 FrequentistCalculator.cxx:91
 FrequentistCalculator.cxx:92
 FrequentistCalculator.cxx:93
 FrequentistCalculator.cxx:94
 FrequentistCalculator.cxx:95
 FrequentistCalculator.cxx:96
 FrequentistCalculator.cxx:97
 FrequentistCalculator.cxx:98
 FrequentistCalculator.cxx:99
 FrequentistCalculator.cxx:100
 FrequentistCalculator.cxx:101
 FrequentistCalculator.cxx:102
 FrequentistCalculator.cxx:103
 FrequentistCalculator.cxx:104
 FrequentistCalculator.cxx:105
 FrequentistCalculator.cxx:106
 FrequentistCalculator.cxx:107
 FrequentistCalculator.cxx:108
 FrequentistCalculator.cxx:109
 FrequentistCalculator.cxx:110
 FrequentistCalculator.cxx:111
 FrequentistCalculator.cxx:112
 FrequentistCalculator.cxx:113
 FrequentistCalculator.cxx:114
 FrequentistCalculator.cxx:115
 FrequentistCalculator.cxx:116
 FrequentistCalculator.cxx:117
 FrequentistCalculator.cxx:118
 FrequentistCalculator.cxx:119
 FrequentistCalculator.cxx:120
 FrequentistCalculator.cxx:121
 FrequentistCalculator.cxx:122
 FrequentistCalculator.cxx:123
 FrequentistCalculator.cxx:124
 FrequentistCalculator.cxx:125
 FrequentistCalculator.cxx:126
 FrequentistCalculator.cxx:127
 FrequentistCalculator.cxx:128
 FrequentistCalculator.cxx:129
 FrequentistCalculator.cxx:130
 FrequentistCalculator.cxx:131
 FrequentistCalculator.cxx:132
 FrequentistCalculator.cxx:133
 FrequentistCalculator.cxx:134
 FrequentistCalculator.cxx:135
 FrequentistCalculator.cxx:136
 FrequentistCalculator.cxx:137
 FrequentistCalculator.cxx:138
 FrequentistCalculator.cxx:139
 FrequentistCalculator.cxx:140
 FrequentistCalculator.cxx:141
 FrequentistCalculator.cxx:142
 FrequentistCalculator.cxx:143
 FrequentistCalculator.cxx:144
 FrequentistCalculator.cxx:145
 FrequentistCalculator.cxx:146
 FrequentistCalculator.cxx:147
 FrequentistCalculator.cxx:148
 FrequentistCalculator.cxx:149
 FrequentistCalculator.cxx:150
 FrequentistCalculator.cxx:151
 FrequentistCalculator.cxx:152
 FrequentistCalculator.cxx:153
 FrequentistCalculator.cxx:154
 FrequentistCalculator.cxx:155
 FrequentistCalculator.cxx:156
 FrequentistCalculator.cxx:157
 FrequentistCalculator.cxx:158
 FrequentistCalculator.cxx:159
 FrequentistCalculator.cxx:160
 FrequentistCalculator.cxx:161
 FrequentistCalculator.cxx:162
 FrequentistCalculator.cxx:163
 FrequentistCalculator.cxx:164
 FrequentistCalculator.cxx:165
 FrequentistCalculator.cxx:166
 FrequentistCalculator.cxx:167
 FrequentistCalculator.cxx:168
 FrequentistCalculator.cxx:169
 FrequentistCalculator.cxx:170
 FrequentistCalculator.cxx:171
 FrequentistCalculator.cxx:172
 FrequentistCalculator.cxx:173
 FrequentistCalculator.cxx:174
 FrequentistCalculator.cxx:175
 FrequentistCalculator.cxx:176
 FrequentistCalculator.cxx:177
 FrequentistCalculator.cxx:178
 FrequentistCalculator.cxx:179
 FrequentistCalculator.cxx:180
 FrequentistCalculator.cxx:181
 FrequentistCalculator.cxx:182
 FrequentistCalculator.cxx:183
 FrequentistCalculator.cxx:184
 FrequentistCalculator.cxx:185
 FrequentistCalculator.cxx:186
 FrequentistCalculator.cxx:187
 FrequentistCalculator.cxx:188
 FrequentistCalculator.cxx:189
 FrequentistCalculator.cxx:190
 FrequentistCalculator.cxx:191
 FrequentistCalculator.cxx:192
 FrequentistCalculator.cxx:193
 FrequentistCalculator.cxx:194
 FrequentistCalculator.cxx:195
 FrequentistCalculator.cxx:196
 FrequentistCalculator.cxx:197
 FrequentistCalculator.cxx:198
 FrequentistCalculator.cxx:199
 FrequentistCalculator.cxx:200
 FrequentistCalculator.cxx:201
 FrequentistCalculator.cxx:202
 FrequentistCalculator.cxx:203
 FrequentistCalculator.cxx:204
 FrequentistCalculator.cxx:205
 FrequentistCalculator.cxx:206
 FrequentistCalculator.cxx:207
 FrequentistCalculator.cxx:208
 FrequentistCalculator.cxx:209
 FrequentistCalculator.cxx:210
 FrequentistCalculator.cxx:211
 FrequentistCalculator.cxx:212
 FrequentistCalculator.cxx:213
 FrequentistCalculator.cxx:214
 FrequentistCalculator.cxx:215
 FrequentistCalculator.cxx:216
 FrequentistCalculator.cxx:217
 FrequentistCalculator.cxx:218
 FrequentistCalculator.cxx:219
 FrequentistCalculator.cxx:220
 FrequentistCalculator.cxx:221
 FrequentistCalculator.cxx:222
 FrequentistCalculator.cxx:223
 FrequentistCalculator.cxx:224
 FrequentistCalculator.cxx:225
 FrequentistCalculator.cxx:226
 FrequentistCalculator.cxx:227
 FrequentistCalculator.cxx:228
 FrequentistCalculator.cxx:229
 FrequentistCalculator.cxx:230
 FrequentistCalculator.cxx:231
 FrequentistCalculator.cxx:232
 FrequentistCalculator.cxx:233
 FrequentistCalculator.cxx:234
 FrequentistCalculator.cxx:235