// @(#)root/roostats:$Id$
// 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.             *
 *************************************************************************/

/**
Same purpose as HybridCalculatorOriginal, but different implementation.

This is the "generic" version that works with any TestStatSampler. The
HybridCalculator derives from this class but explicitly uses the
ToyMCSampler as its TestStatSampler.
*/

#include "RooStats/HypoTestCalculatorGeneric.h"
#include "RooStats/ToyMCSampler.h"
#include "RooStats/RatioOfProfiledLikelihoodsTestStat.h"

#include "RooAddPdf.h"

#include "RooRandom.h"


ClassImp(RooStats::HypoTestCalculatorGeneric)

using namespace RooStats;
using namespace std;

//___________________________________
HypoTestCalculatorGeneric::HypoTestCalculatorGeneric(
                                     const RooAbsData &data,
                                     const ModelConfig &altModel,
                                     const ModelConfig &nullModel,
                                     TestStatSampler *sampler
                                     ) :
   fAltModel(&altModel),
   fNullModel(&nullModel),
   fData(&data),
   fTestStatSampler(sampler),
   fDefaultSampler(0),
   fDefaultTestStat(0),
   fAltToysSeed(0)
{
   // Constructor. When test stat sampler is not provided
   // uses ToyMCSampler and RatioOfProfiledLikelihoodsTestStat
   // and nToys = 1000.
   // User can : GetTestStatSampler()->SetNToys( # )
   if(!sampler){
      fDefaultTestStat
         = new RatioOfProfiledLikelihoodsTestStat(*nullModel.GetPdf(),
                                                  *altModel.GetPdf(),
                                                  altModel.GetSnapshot());

      fDefaultSampler = new ToyMCSampler(*fDefaultTestStat, 1000);
      fTestStatSampler = fDefaultSampler;
   }


}

//_____________________________________________________________
void HypoTestCalculatorGeneric::SetupSampler(const ModelConfig& model) const {
   // common setup for both models
   fNullModel->LoadSnapshot();
   fTestStatSampler->SetObservables(*fNullModel->GetObservables());
   fTestStatSampler->SetParametersForTestStat(*fNullModel->GetParametersOfInterest());

   // for this model
   model.LoadSnapshot();
   fTestStatSampler->SetSamplingDistName(model.GetName());
   fTestStatSampler->SetPdf(*model.GetPdf());
   fTestStatSampler->SetNuisanceParameters(*model.GetNuisanceParameters());
   // global observables or nuisanance pdf will be set by the derived classes
   // (e.g. Frequentist or HybridCalculator)
}

//____________________________________________________
HypoTestCalculatorGeneric::~HypoTestCalculatorGeneric()  {
   if(fDefaultSampler)    delete fDefaultSampler;
   if(fDefaultTestStat)   delete fDefaultTestStat;
}

//____________________________________________________
HypoTestResult* HypoTestCalculatorGeneric::GetHypoTest() const {

   // several possibilities:
   // no prior nuisance given and no nuisance parameters: ok
   // no prior nuisance given but nuisance parameters: error
   // prior nuisance given for some nuisance parameters:
   //   - nuisance parameters are constant, so they don't float in test statistic
   //   - nuisance parameters are floating, so they do float in test statistic

   // initial setup
   PreHook();
   const_cast<ModelConfig*>(fNullModel)->GuessObsAndNuisance(*fData);
   const_cast<ModelConfig*>(fAltModel)->GuessObsAndNuisance(*fData);

   const RooArgSet * nullSnapshot = fNullModel->GetSnapshot();
   if(nullSnapshot == NULL) {
      oocoutE((TObject*)0,Generation) << "Null model needs a snapshot. Set using modelconfig->SetSnapshot(poi)." << endl;
      return 0;
   }

   // CheckHook
   if(CheckHook() != 0) {
      oocoutE((TObject*)0,Generation) << "There was an error in CheckHook(). Stop." << endl;
      return 0;
   }

   if (!fTestStatSampler  || !fTestStatSampler->GetTestStatistic() ) { 
      oocoutE((TObject*)0,InputArguments) << "Test Statistic Sampler or Test Statistics not defined. Stop." << endl;
      return 0;
   }

   // get a big list of all variables for convenient switching
   RooArgSet *nullParams = fNullModel->GetPdf()->getParameters(*fData);
   RooArgSet *altParams = fAltModel->GetPdf()->getParameters(*fData);
   // save all parameters so we can set them back to what they were
   RooArgSet *bothParams = fNullModel->GetPdf()->getParameters(*fData);
   bothParams->add(*altParams,false);
   RooArgSet *saveAll = (RooArgSet*) bothParams->snapshot();

   // check whether we have a ToyMCSampler and if so, keep a pointer to it
   ToyMCSampler* toymcs = dynamic_cast<ToyMCSampler*>( fTestStatSampler );


   // evaluate test statistic on data
   RooArgSet nullP(*nullSnapshot);
   double obsTestStat; 
   
   RooArgList* allTS = NULL;
   if( toymcs ) {
      allTS = toymcs->EvaluateAllTestStatistics(*const_cast<RooAbsData*>(fData), nullP);
      if (!allTS) return 0;
      //oocoutP((TObject*)0,Generation) << "All Test Statistics on data: " << endl;
      //allTS->Print("v");
      RooRealVar* firstTS = (RooRealVar*)allTS->at(0);
      obsTestStat = firstTS->getVal();
      if (allTS->getSize()<=1) {
        delete allTS;
        allTS= 0;  // don't save
      }
   }else{
      obsTestStat = fTestStatSampler->EvaluateTestStatistic(*const_cast<RooAbsData*>(fData), nullP);
   }
   oocoutP((TObject*)0,Generation) << "Test Statistic on data: " << obsTestStat << endl;

   // set parameters back ... in case the evaluation of the test statistic
   // modified something (e.g. a nuisance parameter that is not randomized
   // must be set here)
   *bothParams = *saveAll;
   


   // Generate sampling distribution for null
   SetupSampler(*fNullModel);
   RooArgSet paramPointNull(*fNullModel->GetParametersOfInterest());
   if(PreNullHook(&paramPointNull, obsTestStat) != 0) {
      oocoutE((TObject*)0,Generation) << "PreNullHook did not return 0." << endl;
   }
   SamplingDistribution* samp_null = NULL;
   RooDataSet* detOut_null = NULL;
   if(toymcs) {
      detOut_null = toymcs->GetSamplingDistributions(paramPointNull);
      if( detOut_null ) {
        samp_null = new SamplingDistribution( detOut_null->GetName(), detOut_null->GetTitle(), *detOut_null );
        if (detOut_null->get()->getSize()<=1) {
          delete detOut_null;
          detOut_null= 0;
        }
      }
   }else samp_null = fTestStatSampler->GetSamplingDistribution(paramPointNull);

   // set parameters back
   *bothParams = *saveAll;

   // Generate sampling distribution for alternate
   SetupSampler(*fAltModel);
   RooArgSet paramPointAlt(*fAltModel->GetParametersOfInterest());
   if(PreAltHook(&paramPointAlt, obsTestStat) != 0) {
      oocoutE((TObject*)0,Generation) << "PreAltHook did not return 0." << endl;
   }
   SamplingDistribution* samp_alt = NULL;
   RooDataSet* detOut_alt = NULL;
   if(toymcs) {

      // case of re-using same toys for every points
      // set a given seed 
      unsigned int prevSeed = 0;
      if (fAltToysSeed > 0) { 
         prevSeed = RooRandom::integer(std::numeric_limits<unsigned int>::max()-1)+1;  // want to avoid zero value
         RooRandom::randomGenerator()->SetSeed(fAltToysSeed);
      }

      detOut_alt = toymcs->GetSamplingDistributions(paramPointAlt);
      if( detOut_alt ) {
        samp_alt = new SamplingDistribution( detOut_alt->GetName(), detOut_alt->GetTitle(), *detOut_alt );
        if (detOut_alt->get()->getSize()<=1) {
          delete detOut_alt;
          detOut_alt= 0;
        }
      }

      // restore the seed 
      if (prevSeed > 0) { 
         RooRandom::randomGenerator()->SetSeed(prevSeed);
      }

   }else samp_alt = fTestStatSampler->GetSamplingDistribution(paramPointAlt);


   // create result
   string resultname = "HypoTestCalculator_result";
   HypoTestResult* res = new HypoTestResult(resultname.c_str());
   res->SetPValueIsRightTail(fTestStatSampler->GetTestStatistic()->PValueIsRightTail());
   res->SetTestStatisticData(obsTestStat);
   res->SetAltDistribution(samp_alt);
   res->SetNullDistribution(samp_null);
   res->SetAltDetailedOutput( detOut_alt );
   res->SetNullDetailedOutput( detOut_null );
   res->SetAllTestStatisticsData( allTS );

   const RooArgSet *aset = GetFitInfo();
   if (aset != NULL) {
      RooDataSet *dset = new RooDataSet(NULL, NULL, *aset);
      dset->add(*aset);
      res->SetFitInfo( dset );
   }

   *bothParams = *saveAll;
   delete allTS;
   delete bothParams;
   delete saveAll;
   delete altParams;
   delete nullParams;
   delete nullSnapshot;
   PostHook();
   return res;
}

//____________________________________________________
void HypoTestCalculatorGeneric::UseSameAltToys()  {
   // to re-use same toys for alternate hypothesis
   fAltToysSeed = RooRandom::integer(std::numeric_limits<unsigned int>::max()-1)+1;
}
   


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