MaCh3  2.6.1
Reference Guide
Public Member Functions | Private Member Functions | Private Attributes | List of all members
PredictiveThrower Class Reference

Implementation of Prior/Posterior Predictive and Bayesian p-Value calculations following the approach described in [11] , [12], [14]. More...

#include <Fitters/PredictiveThrower.h>

Inheritance diagram for PredictiveThrower:
[legend]
Collaboration diagram for PredictiveThrower:
[legend]

Public Member Functions

 PredictiveThrower (Manager *const fitMan)
 Constructor. More...
 
virtual ~PredictiveThrower ()
 Destructor. More...
 
void ProduceToys ()
 Produce toys by throwing from MCMC. More...
 
void RunPredictiveAnalysis ()
 Main routine responsible for producing posterior predictive distributions and $p$-value. More...
 
void RunMCMC () override
 This is not used in this class. More...
 
- Public Member Functions inherited from FitterBase
 FitterBase (Manager *const fitMan)
 Constructor. More...
 
virtual ~FitterBase ()
 Destructor for the FitterBase class. More...
 
void AddSampleHandler (SampleHandlerInterface *sample)
 This function adds a sample PDF object to the analysis framework. The sample PDF object will be utilized in fitting procedures or likelihood scans. More...
 
void AddSystObj (ParameterHandlerBase *cov)
 This function adds a Covariance object to the analysis framework. The Covariance object will be utilized in fitting procedures or likelihood scans. More...
 
void DragRace (const int NLaps=100)
 Calculates the required time for each sample or covariance object in a drag race simulation. Inspired by Dan's feature. More...
 
void RunLLHScan ()
 Perform a 1D likelihood scan. More...
 
void RunLLHMap ()
 Perform a general multi-dimensional likelihood scan. More...
 
void GetStepScaleBasedOnLLHScan (const std::string &filename="")
 LLH scan is good first estimate of step scale. More...
 
void Run2DLLHScan ()
 Perform a 2D likelihood scan. More...
 
void RunSigmaVar ()
 Perform a 1D/2D sigma var for all samples. More...
 
virtual void StartFromPreviousFit (const std::string &FitName)
 Allow to start from previous fit/chain. More...
 
std::string GetName () const
 Get name of class. More...
 

Private Member Functions

void SetParamters (std::vector< std::string > &ParameterGroupsNotVaried, std::unordered_set< int > &ParameterOnlyToVary)
 This set some params to prior value this way you can evaluate errors from subset of errors. More...
 
void SetupToyGeneration (std::vector< std::string > &ParameterGroupsNotVaried, std::unordered_set< int > &ParameterOnlyToVary, std::vector< const M3::float_t * > &BoundValuePointer, std::vector< std::pair< double, double >> &ParamBounds)
 Setup useful variables etc before stating toy generation. More...
 
bool LoadToys ()
 Load existing toys. More...
 
void WriteToy (TDirectory *ToyDirectory, TDirectory *Toy_1DDirectory, TDirectory *Toy_2DDirectory, const int iToy)
 Save histograms for a single MCMC Throw/Toy. More...
 
void WriteByModeToys (TDirectory *ByModeDirectory, const int iToy)
 Save mode histograms for a single MCMC Throw/Toy. More...
 
void SetupSampleInformation ()
 Setup sample information. More...
 
std::vector< std::string > GetStoredFancyName (ParameterHandlerBase *Systematics) const
 Get Fancy parameters stored in mcmc chains for passed ParameterHandler. More...
 
std::vector< std::unique_ptr< TH1 > > MakePredictive (const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const std::vector< TDirectory * > &Director, const std::string &suffix, const bool DebugHistograms, const bool WriteHist)
 Produce posterior predictive distribution. More...
 
void Study1DProjections (const std::vector< TDirectory * > &SampleDirectories) const
 Load 1D projections and later produce violin plots for each. More...
 
void StudyByMode1DProjections (const std::vector< TDirectory * > &SampleDirectories) const
 Load 1D projections by mode and produce post pred for each. More...
 
void ProduceSpectra (const std::vector< std::vector< std::vector< std::unique_ptr< TH1D >>>> &Toys, const std::vector< TDirectory * > &Director, const std::string suffix, const bool DoSummary=true) const
 Produce Violin style spectra. More...
 
void MakeFluctuatedHistogram (TH1 *FluctHist, TH1 *PolyHist)
 Make Poisson fluctuation of TH1D hist. More...
 
void PredictiveLLH (const std::vector< std::unique_ptr< TH1 >> &Data_histogram, const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w, const std::vector< TDirectory * > &SampleDir)
 Calculate Posterior Predictive LLH. More...
 
void PosteriorPredictivepValue (const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< TDirectory * > &SampleDir)
 Calculate Posterior Predictive $p$-value Compares observed data to toy datasets generated from: More...
 
void ExtractLLH (TH1 *DatHist, TH1 *MCHist, TH1 *W2Hist, const SampleHandlerInterface *SampleHandler) const
 Calculate the LLH for TH1, set the LLH to title of MCHist. More...
 
double CalcLLH (const double data, const double mc, const double w2, const SampleHandlerInterface *SampleHandler) const
 Calculates the -2LLH (likelihood) for a single sample. More...
 
double CalcLLH (const TH1 *DatHist, const TH1 *MCHist, const TH1 *W2Hist, const SampleHandlerInterface *SampleHandler) const
 Calculates the likelihood (-2LLH) for a single sample; dynamically casts to call the correct GetLLH overload. More...
 
double GetLLH (const TH1D *DatHist, const TH1D *MCHist, const TH1D *W2Hist, const SampleHandlerInterface *SampleHandler) const
 Helper functions to calculate likelihoods using TH1D. More...
 
double GetLLH (const TH2D *DatHist, const TH2D *MCHist, const TH2D *W2Hist, const SampleHandlerInterface *SampleHandler) const
 Helper functions to calculate likelihoods using TH2D. More...
 
double GetLLH (const TH2Poly *DatHist, const TH2Poly *MCHist, const TH2Poly *W2Hist, const SampleHandlerInterface *SampleHandler) const
 Helper functions to calculate likelihoods using TH2Poly. More...
 
void MakeChi2Plots (const std::vector< std::vector< double >> &Chi2_x, const std::string &Chi2_x_title, const std::vector< std::vector< double >> &Chi2_y, const std::string &Chi2_y_title, const std::vector< TDirectory * > &SampleDir, const std::string Title)
 Produce Chi2 plot for a single sample based on which $p$-value is calculated. More...
 
void StudyCorrelations (TDirectory *PredictiveDir, const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const bool DebugHistograms) const
 Study Prior/Posterior correlations between samples etc. More...
 
void StudyInformationCriterion (M3::kInfCrit Criterion, const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
 Information Criterion. More...
 
void StudyBIC (const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
 Study Bayesian Information Criterion (BIC) The BIC is defined as: More...
 
void StudyDIC (const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
 KS: Get the Deviance Information Criterion (DIC) The deviance is defined as: More...
 
void StudyWAIC ()
 KS: Get the Watanabe-Akaike information criterion (WAIC) More...
 
std::string GetBinName (TH1 *hist, const bool uniform, const int Dim, const std::vector< int > &bins) const
 Construct a human-readable label describing a specific analysis bin. More...
 
std::vector< std::unique_ptr< TH1D > > PerBinHistogram (TH1 *hist, const int SampleId, const int Dim, const std::string &suffix) const
 Create per-bin posterior histograms for a given sample. More...
 
void StudyBetaParameters (TDirectory *PredictiveDir)
 Evaluate prior/post predictive distribution for beta parameters (used for evaluating impact MC statistical uncertainty) More...
 
void MakeCutEventRate (TH1D *Histogram, const double DataRate) const
 Make the 1D Event Rate Hist. More...
 
void RateAnalysis (const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const std::vector< TDirectory * > &SampleDirectories) const
 Produce distribution of number of events for each sample. More...
 

Private Attributes

bool FullLLH
 KS: Use Full LLH or only sample contribution based on discussion with Asher we almost always only want the sample likelihood. More...
 
int NModelParams
 KS: Count total number of model parameters which can be used for stuff like BIC. More...
 
bool Is_PriorPredictive
 Whether it is Prior or Posterior predictive. More...
 
int TotalNumberOfSamples
 Number of toys we are generating analysing. More...
 
std::vector< PredictiveSampleSampleInfo
 Handy struct for all sample info. More...
 
int Ntoys
 Number of toys we are generating analysing. More...
 
ParameterHandlerGenericModelSystematic
 Pointer to El Generico. More...
 
std::vector< std::unique_ptr< TH1 > > Data_Hist
 Vector of Data histograms. More...
 
std::vector< std::unique_ptr< TH1 > > MC_Nom_Hist
 Vector of MC histograms. More...
 
std::vector< std::unique_ptr< TH1 > > W2_Nom_Hist
 Vector of W2 histograms. More...
 
std::vector< std::vector< std::unique_ptr< TH1 > > > MC_Hist_Toy
 
std::vector< std::vector< std::unique_ptr< TH1 > > > W2_Hist_Toy
 
std::vector< double > ReweightWeight
 Reweighting factors applied for each toy, by default 1. More...
 
std::vector< double > PenaltyTerm
 Penalty term values for each toy by default 0. More...
 
bool StandardFluctuation
 KS: We have two methods for Poissonian fluctuation. More...
 

Additional Inherited Members

- Protected Member Functions inherited from FitterBase
void ProcessMCMC ()
 Process MCMC output. More...
 
void PrepareOutput ()
 Prepare the output file. More...
 
void SaveOutput ()
 Save output and close files. More...
 
void SanitiseInputs ()
 Remove obsolete memory and make other checks before fit starts. More...
 
void SaveSettings ()
 Save the settings that the MCMC was run with. More...
 
bool GetScanRange (std::map< std::string, std::vector< double >> &scanRanges) const
 YSP: Set up a mapping to store parameters with user-specified ranges, suggested by D. Barrow. More...
 
void GetParameterScanRange (const ParameterHandlerBase *cov, const int i, double &CentralValue, double &lower, double &upper, const int n_points, const std::string &suffix="") const
 Helper function to get parameter scan range, central value. More...
 
bool CheckSkipParameter (const std::vector< std::string > &SkipVector, const std::string &ParamName) const
 KS: Check whether we want to skip parameter using skip vector. More...
 
void CustomRange (const std::string &ParName, const double sigma, double &ParamShiftValue) const
 For comparison with other fitting frameworks (like P-Theta) we usually have to apply different parameter values then usual 1, 3 sigma. More...
 
std::vector< double > CalculateBinEdges (double lowerlimit, double upperlimit, int n_points) const
 
- Protected Attributes inherited from FitterBase
ManagerfitMan
 The manager for configuration handling. More...
 
unsigned int step
 current state More...
 
double logLCurr
 current likelihood More...
 
double logLProp
 proposed likelihood More...
 
double accProb
 current acceptance prob More...
 
int accCount
 counts accepted steps More...
 
unsigned int stepStart
 step start, by default 0 if we start from previous chain then it will be different More...
 
std::vector< double > sample_llh
 store the llh breakdowns More...
 
std::vector< double > syst_llh
 systematic llh breakdowns More...
 
std::vector< SampleHandlerInterface * > samples
 Sample holder. More...
 
unsigned int TotalNSamples
 Total number of samples used, single SampleHandler can store more than one analysis sample! More...
 
std::vector< ParameterHandlerBase * > systematics
 Systematic holder. More...
 
std::unique_ptr< TStopwatch > clock
 tells global time how long fit took More...
 
std::unique_ptr< TStopwatch > stepClock
 tells how long single step/fit iteration took More...
 
double stepTime
 Time of single step. More...
 
std::unique_ptr< TRandom3 > random
 Random number. More...
 
TFile * outputFile
 Output. More...
 
TDirectory * CovFolder
 Output cov folder. More...
 
TDirectory * SampleFolder
 Output sample folder. More...
 
TTree * outTree
 Output tree with posteriors. More...
 
int auto_save
 auto save every N steps More...
 
bool fTestLikelihood
 Necessary for some fitting algorithms like PSO. More...
 
bool FileSaved
 Checks if file saved not repeat some operations. More...
 
bool SettingsSaved
 Checks if setting saved not repeat some operations. More...
 
bool OutputPrepared
 Checks if output prepared not repeat some operations. More...
 
std::string AlgorithmName
 Name of fitting algorithm that is being used. More...
 

Detailed Description

Implementation of Prior/Posterior Predictive and Bayesian p-Value calculations following the approach described in [11] , [12], [14].

For more information, visit the Posterior Predictive page.

Author
Asher Kaboth
Dan Barrow
Ed Atkin
Yashwanth S Prabhu
Kamil Skwarczynski
Patrick Dunne
Clarence Wret

Definition at line 32 of file PredictiveThrower.h.

Constructor & Destructor Documentation

◆ PredictiveThrower()

PredictiveThrower::PredictiveThrower ( Manager *const  fitMan)

Constructor.

Parameters
fitManA pointer to a manager object, which will handle all settings.

Definition at line 10 of file PredictiveThrower.cpp.

10  : FitterBase(man) {
11 // *************************
12  AlgorithmName = "PredictiveThrower";
13  if(!CheckNodeExists(fitMan->raw(), "Predictive")) {
14  MACH3LOG_ERROR("Predictive is missing in your main yaml config");
15  throw MaCh3Exception(__FILE__ , __LINE__ );
16  }
17 
18  StandardFluctuation = GetFromManager<bool>(fitMan->raw()["Predictive"]["StandardFluctuation"], true, __FILE__, __LINE__ );
19 
20  if(StandardFluctuation) MACH3LOG_INFO("Using standard method of statistical fluctuation");
21  else MACH3LOG_INFO("Using alternative method of statistical fluctuation, which is much slower");
22 
23  ModelSystematic = nullptr;
24  // Use the full likelihood for the Prior/Posterior predictive pvalue
25  FullLLH = GetFromManager<bool>(fitMan->raw()["Predictive"]["FullLLH"], false, __FILE__, __LINE__ );
26  NModelParams = 0;
27 
28  Is_PriorPredictive = Get<bool>(fitMan->raw()["Predictive"]["PriorPredictive"], __FILE__, __LINE__);
29  Ntoys = Get<int>(fitMan->raw()["Predictive"]["Ntoy"], __FILE__, __LINE__);
30 
31  if(!Is_PriorPredictive) {
32  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
33  auto outfile = Get<std::string>(fitMan->raw()["General"]["OutputFile"], __FILE__ , __LINE__);
34  if(PosteriorFileName == outfile){
35  MACH3LOG_ERROR("Output file ({}) and posterior files ({}) have same name", outfile, PosteriorFileName);
36  throw MaCh3Exception(__FILE__ , __LINE__ );
37  }
38  }
39 
40  ReweightWeight.resize(Ntoys);
41  PenaltyTerm.resize(Ntoys);
42 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:37
#define MACH3LOG_INFO
Definition: MaCh3Logger.h:35
bool CheckNodeExists(const YAML::Node &node, Args... args)
KS: Wrapper function to call the recursive helper.
Definition: YamlHelper.h:60
FitterBase(Manager *const fitMan)
Constructor.
Definition: FitterBase.cpp:18
std::string AlgorithmName
Name of fitting algorithm that is being used.
Definition: FitterBase.h:177
Manager * fitMan
The manager for configuration handling.
Definition: FitterBase.h:117
Custom exception class used throughout MaCh3.
YAML::Node const & raw() const
Return config.
Definition: Manager.h:47
std::vector< double > PenaltyTerm
Penalty term values for each toy by default 0.
bool FullLLH
KS: Use Full LLH or only sample contribution based on discussion with Asher we almost always only wan...
bool Is_PriorPredictive
Whether it is Prior or Posterior predictive.
int NModelParams
KS: Count total number of model parameters which can be used for stuff like BIC.
int Ntoys
Number of toys we are generating analysing.
bool StandardFluctuation
KS: We have two methods for Poissonian fluctuation.
ParameterHandlerGeneric * ModelSystematic
Pointer to El Generico.
std::vector< double > ReweightWeight
Reweighting factors applied for each toy, by default 1.

◆ ~PredictiveThrower()

PredictiveThrower::~PredictiveThrower ( )
virtual

Destructor.

Definition at line 46 of file PredictiveThrower.cpp.

46  {
47 // *************************
48 }

Member Function Documentation

◆ CalcLLH() [1/2]

double PredictiveThrower::CalcLLH ( const double  data,
const double  mc,
const double  w2,
const SampleHandlerInterface SampleHandler 
) const
private

Calculates the -2LLH (likelihood) for a single sample.

Parameters
dataData value for the sample.
mcMC (Monte Carlo) value for the sample.
w2W2 value for the sample.
SampleHandlerPointer to SampleHandlerInterface providing the LLH test statistic.

Definition at line 1227 of file PredictiveThrower.cpp.

1230  {
1231 // *************************
1232  double llh = SampleHandler->GetTestStatLLH(data, mc, w2);
1233  //KS: do times 2 because banff reports chi2
1234  return 2*llh;
1235 }
double GetTestStatLLH(const double data, const double mc, const double w2) const
Calculate test statistic for a single bin. Calculation depends on setting of fTestStatistic....

◆ CalcLLH() [2/2]

double PredictiveThrower::CalcLLH ( const TH1 *  DatHist,
const TH1 *  MCHist,
const TH1 *  W2Hist,
const SampleHandlerInterface SampleHandler 
) const
private

Calculates the likelihood (-2LLH) for a single sample; dynamically casts to call the correct GetLLH overload.

Parameters
DatHistData histogram with data distribution for a single sample
MCHistMC histogram with MC distribution for a single sample
W2HistW2 histogram with W2 distribution for a single sample
SampleHandlerPointer to SampleHandlerInterface providing LLH test statistic

Definition at line 1238 of file PredictiveThrower.cpp.

1241  {
1242 // *************************
1243  // 1D case
1244  if (auto h1 = dynamic_cast<const TH1D*>(DatHist)) {
1245  return GetLLH(h1,
1246  static_cast<const TH1D*>(MCHist),
1247  static_cast<const TH1D*>(W2Hist),
1248  SampleHandler);
1249  }
1250 
1251  // 2D case
1252  if (auto h2 = dynamic_cast<const TH2D*>(DatHist)) {
1253  return GetLLH(h2,
1254  static_cast<const TH2D*>(MCHist),
1255  static_cast<const TH2D*>(W2Hist),
1256  SampleHandler);
1257  }
1258 
1259  // 2D poly case
1260  if (auto h2p = dynamic_cast<const TH2Poly*>(DatHist)) {
1261  return GetLLH(h2p,
1262  static_cast<const TH2Poly*>(MCHist),
1263  static_cast<const TH2Poly*>(W2Hist),
1264  SampleHandler);
1265  }
1266 
1267  MACH3LOG_ERROR("Unsupported histogram type in {}", __func__);
1268  throw MaCh3Exception(__FILE__ , __LINE__ );
1269 }
double GetLLH(const TH1D *DatHist, const TH1D *MCHist, const TH1D *W2Hist, const SampleHandlerInterface *SampleHandler) const
Helper functions to calculate likelihoods using TH1D.

◆ ExtractLLH()

void PredictiveThrower::ExtractLLH ( TH1 *  DatHist,
TH1 *  MCHist,
TH1 *  W2Hist,
const SampleHandlerInterface SampleHandler 
) const
private

Calculate the LLH for TH1, set the LLH to title of MCHist.

Parameters
DatHistData histogram with data distribution for a single sample
MCHistMC histogram with MC distribution for a single sample
W2HistW2 histogram with W2 distribution for a single sample
SampleHandlerPointer to SampleHandlerInterface providing LLH test statistic

Definition at line 1690 of file PredictiveThrower.cpp.

1690  {
1691 // ****************
1692  const double llh = CalcLLH(DatHist, MCHist, W2Hist, SampleHandler);
1693  std::stringstream ss;
1694  ss << "_2LLH=" << llh;
1695  MCHist->SetTitle((std::string(MCHist->GetTitle())+ss.str()).c_str());
1696  MACH3LOG_INFO("{:<55} {:<10.2f} {:<10.2f} {:<10.2f}", MCHist->GetName(), DatHist->Integral(), MCHist->Integral(), llh);
1697 }
double CalcLLH(const double data, const double mc, const double w2, const SampleHandlerInterface *SampleHandler) const
Calculates the -2LLH (likelihood) for a single sample.

◆ GetBinName()

std::string PredictiveThrower::GetBinName ( TH1 *  hist,
const bool  uniform,
const int  Dim,
const std::vector< int > &  bins 
) const
private

Construct a human-readable label describing a specific analysis bin.

Parameters
histHistogram providing the binning definition.
uniformFlag indicating whether the histogram uses regular axis binning (TH1/TH2) or irregular polygonal binning (e.g. TH2Poly).
DimDimensionality of the original distribution.
binsVector of per-dimension bin indices in analysis coordinates.

Definition at line 973 of file PredictiveThrower.cpp.

976  {
977 // *************************
978  std::string BinName = "";
979  if(Dim == 1) { // True 1D distribution using TH1D
980  const int b = bins[0];
981  const TAxis* ax = hist->GetXaxis();
982  const double low = ax->GetBinLowEdge(b);
983  const double up = ax->GetBinUpEdge(b);
984 
985  BinName = fmt::format("Dim0 ({:g}, {:g})", low, up);
986  } else if (Dim == 2) { // True 2D dsitrubitons
987  if(uniform == true) { //using TH2D
988  const int bx = bins[0];
989  const int by = bins[1];
990  const TAxis* ax = hist->GetXaxis();
991  const TAxis* ay = hist->GetYaxis();
992  BinName = fmt::format("Dim0 ({:g}, {:g}), ", ax->GetBinLowEdge(bx), ax->GetBinUpEdge(bx));
993  BinName += fmt::format("Dim1 ({:g}, {:g})", ay->GetBinLowEdge(by), ay->GetBinUpEdge(by));
994  } else { // using TH2Poly
995  TH2PolyBin* bin = static_cast<TH2PolyBin*>(static_cast<TH2Poly*>(hist)->GetBins()->At(bins[0]-1));
996  // Just make a little fancy name
997  BinName += fmt::format("Dim{} ({:g}, {:g})", 0, bin->GetXMin(), bin->GetXMax());
998  BinName += fmt::format("Dim{} ({:g}, {:g})", 1, bin->GetYMin(), bin->GetYMax());
999  }
1000  } else { // N-dimensional distribution using flatten TH1D
1001  BinName = hist->GetXaxis()->GetBinLabel(bins[0]);
1002  }
1003  return BinName;
1004 }

◆ GetLLH() [1/3]

double PredictiveThrower::GetLLH ( const TH1D *  DatHist,
const TH1D *  MCHist,
const TH1D *  W2Hist,
const SampleHandlerInterface SampleHandler 
) const
private

Helper functions to calculate likelihoods using TH1D.

Parameters
DatHistData histogram with data distribution for a single sample
MCHistMC histogram with MC distribution for a single sample
W2HistW2 histogram with W2 distribution for a single sample
SampleHandlerPointer to SampleHandlerInterface providing LLH test statistic

Definition at line 1272 of file PredictiveThrower.cpp.

1275  {
1276 // *************************
1277  double llh = 0.0;
1278  for (int i = 1; i <= DatHist->GetXaxis()->GetNbins(); ++i)
1279  {
1280  const double data = DatHist->GetBinContent(i);
1281  const double mc = MCHist->GetBinContent(i);
1282  const double w2 = W2Hist->GetBinContent(i);
1283  llh += SampleHandler->GetTestStatLLH(data, mc, w2);
1284  }
1285  //KS: do times 2 because banff reports chi2
1286  return 2*llh;
1287 }

◆ GetLLH() [2/3]

double PredictiveThrower::GetLLH ( const TH2D *  DatHist,
const TH2D *  MCHist,
const TH2D *  W2Hist,
const SampleHandlerInterface SampleHandler 
) const
private

Helper functions to calculate likelihoods using TH2D.

Parameters
DatHistData 2D histogram with data distribution for a single sample
MCHistMC 2D histogram with MC distribution for a single sample
W2HistW2 2D histogram with W2 distribution for a single sample
SampleHandlerPointer to SampleHandlerInterface providing LLH test statistic

Definition at line 1308 of file PredictiveThrower.cpp.

1311  {
1312 // *************************
1313  double llh = 0.0;
1314 
1315  const int nBinsX = DatHist->GetXaxis()->GetNbins();
1316  const int nBinsY = DatHist->GetYaxis()->GetNbins();
1317 
1318  for (int i = 1; i <= nBinsX; ++i)
1319  {
1320  for (int j = 1; j <= nBinsY; ++j)
1321  {
1322  const double data = DatHist->GetBinContent(i, j);
1323  const double mc = MCHist->GetBinContent(i, j);
1324  const double w2 = W2Hist->GetBinContent(i, j);
1325 
1326  llh += SampleHandler->GetTestStatLLH(data, mc, w2);
1327  }
1328  }
1329 
1330  // KS: do times 2 because banff reports chi2
1331  return 2 * llh;
1332 }

◆ GetLLH() [3/3]

double PredictiveThrower::GetLLH ( const TH2Poly *  DatHist,
const TH2Poly *  MCHist,
const TH2Poly *  W2Hist,
const SampleHandlerInterface SampleHandler 
) const
private

Helper functions to calculate likelihoods using TH2Poly.

Parameters
DatHistData 2D poly histogram with data distribution for a single sample
MCHistMC 2D poly histogram with MC distribution for a single sample
W2HistW2 2D poly histogram with W2 distribution for a single sample
SampleHandlerPointer to SampleHandlerInterface providing LLH test statistic

Definition at line 1290 of file PredictiveThrower.cpp.

1293  {
1294 // *************************
1295  double llh = 0.0;
1296  for (int i = 1; i <= DatHist->GetNumberOfBins(); ++i)
1297  {
1298  const double data = DatHist->GetBinContent(i);
1299  const double mc = MCHist->GetBinContent(i);
1300  const double w2 = W2Hist->GetBinContent(i);
1301  llh += SampleHandler->GetTestStatLLH(data, mc, w2);
1302  }
1303  //KS: do times 2 because banff reports chi2
1304  return 2*llh;
1305 }

◆ GetStoredFancyName()

std::vector< std::string > PredictiveThrower::GetStoredFancyName ( ParameterHandlerBase Systematics) const
private

Get Fancy parameters stored in mcmc chains for passed ParameterHandler.

Definition at line 336 of file PredictiveThrower.cpp.

336  {
337 // *************************
338  TDirectory * ogdir = gDirectory;
339 
340  std::vector<std::string> FancyNames;
341  std::string Name = std::string("Config_") + Systematics->GetName();
342  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
343 
344  TFile* file = TFile::Open(PosteriorFileName.c_str(), "READ");
345  TDirectory* CovarianceFolder = file->GetDirectory("CovarianceFolder");
346 
347  TMacro* FoundMacro = static_cast<TMacro*>(CovarianceFolder->Get(Name.c_str()));
348  if(FoundMacro == nullptr) {
349  file->Close();
350  delete file;
351  if(ogdir){ ogdir->cd(); }
352 
353  return FancyNames;
354  }
355  MACH3LOG_DEBUG("Found config for {}", Name);
356  YAML::Node Settings = TMacroToYAML(*FoundMacro);
357 
358  int params = int(Settings["Systematics"].size());
359  FancyNames.resize(params);
360  int iPar = 0;
361  for (auto const &param : Settings["Systematics"]) {
362  FancyNames[iPar] = Get<std::string>(param["Systematic"]["Names"]["FancyName"], __FILE__ , __LINE__);
363  iPar++;
364  }
365  file->Close();
366  delete file;
367  if(ogdir){ ogdir->cd(); }
368  return FancyNames;
369 }
#define MACH3LOG_DEBUG
Definition: MaCh3Logger.h:34
YAML::Node TMacroToYAML(const TMacro &macro)
KS: Convert a ROOT TMacro object to a YAML node.
Definition: YamlHelper.h:152
std::string GetName() const
Get name of covariance.
TFile * Open(const std::string &Name, const std::string &Type, const std::string &File, const int Line)
Opens a ROOT file with the given name and mode.

◆ LoadToys()

bool PredictiveThrower::LoadToys ( )
private

Load existing toys.

Definition at line 243 of file PredictiveThrower.cpp.

243  {
244 // *************************
245  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
246  // Open the ROOT file
247  int originalErrorWarning = gErrorIgnoreLevel;
248  gErrorIgnoreLevel = kFatal;
249  TFile* file = TFile::Open(PosteriorFileName.c_str(), "READ");
250 
251  gErrorIgnoreLevel = originalErrorWarning;
252  TDirectory* ToyDir = nullptr;
253  if (!file || file->IsZombie()) {
254  return false;
255  } else {
256  // Check for the "toys" directory
257  if ((ToyDir = file->GetDirectory("Toys"))) {
258  MACH3LOG_INFO("Found toys in Posterior file will attempt toy reading");
259  } else {
260  file->Close();
261  delete file;
262  return false;
263  }
264  }
265 
266  // Finally get the TTree branch with the penalty vectors for each of the toy throws
267  TTree* PenaltyTree = static_cast<TTree*>(file->Get("ToySummary"));
268  if (!PenaltyTree) {
269  MACH3LOG_WARN("ToySummary TTree not found in file.");
270  file->Close();
271  delete file;
272  return false;
273  }
274 
275  Ntoys = static_cast<int>(PenaltyTree->GetEntries());
276  int ConfigNtoys = Get<int>(fitMan->raw()["Predictive"]["Ntoy"], __FILE__, __LINE__);;
277  if (Ntoys != ConfigNtoys) {
278  MACH3LOG_WARN("Found different number of toys in saved file than asked to run!");
279  MACH3LOG_INFO("Will read _ALL_ toys in the file");
280  MACH3LOG_INFO("Ntoys in file: {}", Ntoys);
281  MACH3LOG_INFO("Ntoys specified: {}", ConfigNtoys);
282  }
283 
284  PenaltyTerm.resize(Ntoys);
285  ReweightWeight.resize(Ntoys);
286 
287  double Penalty = 0, Weight = 1;
288  PenaltyTree->SetBranchAddress("Penalty", &Penalty);
289  PenaltyTree->SetBranchAddress("Weight", &Weight);
290  PenaltyTree->SetBranchAddress("NModelParams", &NModelParams);
291 
292  for (int i = 0; i < Ntoys; ++i) {
293  PenaltyTree->GetEntry(i);
294  if (FullLLH) {
295  PenaltyTerm[i] = Penalty;
296  } else {
297  PenaltyTerm[i] = 0.0;
298  }
299 
300  ReweightWeight[i] = Weight;
301  }
302  // Resize all vectors and get sample names
304 
305  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
306  TH1* DataHist1D = static_cast<TH1*>(ToyDir->Get((SampleInfo[sample].Name + "_data").c_str()));
307  Data_Hist[sample] = M3::Clone(DataHist1D);
308 
309  TH1* MCHist1D = static_cast<TH1*>(ToyDir->Get((SampleInfo[sample].Name + "_mc").c_str()));
310  MC_Nom_Hist[sample] = M3::Clone(MCHist1D);
311 
312  TH1* W2Hist1D = static_cast<TH1*>(ToyDir->Get((SampleInfo[sample].Name + "_w2").c_str()));
313  W2_Nom_Hist[sample] = M3::Clone(W2Hist1D);
314  }
315 
316 
317  for (int iToy = 0; iToy < Ntoys; ++iToy)
318  {
319  if (iToy % 100 == 0) MACH3LOG_INFO(" Loaded toy {}", iToy);
320 
321  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
322  TH1* MCHist1D = static_cast<TH1*>(ToyDir->Get((SampleInfo[sample].Name + "_mc_" + std::to_string(iToy)).c_str()));
323  TH1* W2Hist1D = static_cast<TH1*>(ToyDir->Get((SampleInfo[sample].Name + "_w2_" + std::to_string(iToy)).c_str()));
324 
325  MC_Hist_Toy[sample][iToy] = M3::Clone(MCHist1D);
326  W2_Hist_Toy[sample][iToy] = M3::Clone(W2Hist1D);
327  }
328  }
329 
330  file->Close();
331  delete file;
332  return true;
333 }
#define MACH3LOG_WARN
Definition: MaCh3Logger.h:36
std::vector< std::unique_ptr< TH1 > > W2_Nom_Hist
Vector of W2 histograms.
std::vector< std::vector< std::unique_ptr< TH1 > > > W2_Hist_Toy
void SetupSampleInformation()
Setup sample information.
std::vector< std::unique_ptr< TH1 > > MC_Nom_Hist
Vector of MC histograms.
int TotalNumberOfSamples
Number of toys we are generating analysing.
std::vector< std::unique_ptr< TH1 > > Data_Hist
Vector of Data histograms.
std::vector< std::vector< std::unique_ptr< TH1 > > > MC_Hist_Toy
std::unique_ptr< ObjectType > Clone(const ObjectType *obj, const std::string &name="")
KS: Creates a copy of a ROOT-like object and wraps it in a smart pointer.
KS: Store info about MC sample.
Definition: SampleInfo.h:40

◆ MakeChi2Plots()

void PredictiveThrower::MakeChi2Plots ( const std::vector< std::vector< double >> &  Chi2_x,
const std::string &  Chi2_x_title,
const std::vector< std::vector< double >> &  Chi2_y,
const std::string &  Chi2_y_title,
const std::vector< TDirectory * > &  SampleDir,
const std::string  Title 
)
private

Produce Chi2 plot for a single sample based on which $p$-value is calculated.

Definition at line 1451 of file PredictiveThrower.cpp.

1456  {
1457 // *************************
1458  for (int iSample = 0; iSample < TotalNumberOfSamples+1; ++iSample) {
1459  SampleDir[iSample]->cd();
1460 
1461  // Transpose to extract chi2 values for a given sample across all toys
1462  std::vector<double> chi2_y_sample(Ntoys);
1463  std::vector<double> chi2_x_per_sample(Ntoys);
1464 
1465  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1466  chi2_y_sample[iToy] = Chi2_y[iSample][iToy];
1467  chi2_x_per_sample[iToy] = Chi2_x[iSample][iToy];
1468  }
1469 
1470  const double min_val = std::min(*std::min_element(chi2_y_sample.begin(), chi2_y_sample.end()),
1471  *std::min_element(chi2_x_per_sample.begin(), chi2_x_per_sample.end()));
1472  const double max_val = std::max(*std::max_element(chi2_y_sample.begin(), chi2_y_sample.end()),
1473  *std::max_element(chi2_x_per_sample.begin(), chi2_x_per_sample.end()));
1474 
1475  auto chi2_hist = std::make_unique<TH2D>((SampleInfo[iSample].Name+ Title).c_str(),
1476  (SampleInfo[iSample].Name+ Title).c_str(),
1477  50, min_val, max_val, 50, min_val, max_val);
1478  chi2_hist->SetDirectory(nullptr);
1479  chi2_hist->GetXaxis()->SetTitle(Chi2_x_title.c_str());
1480  chi2_hist->GetYaxis()->SetTitle(Chi2_y_title.c_str());
1481 
1482  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1483  chi2_hist->Fill(chi2_x_per_sample[iToy], chi2_y_sample[iToy]);
1484  }
1485 
1486  Get2DBayesianpValue(chi2_hist.get());
1487  chi2_hist->Write();
1488  }
1489 }
void Get2DBayesianpValue(TH2D *Histogram)
Calculates the 2D Bayesian p-value and generates a visualization.

◆ MakeCutEventRate()

void PredictiveThrower::MakeCutEventRate ( TH1D *  Histogram,
const double  DataRate 
) const
private

Make the 1D Event Rate Hist.

Definition at line 1701 of file PredictiveThrower.cpp.

1701  {
1702 // ****************
1703  // Open the ROOT file
1704  int originalErrorWarning = gErrorIgnoreLevel;
1705  gErrorIgnoreLevel = kFatal;
1706 
1707  // For the event rate histogram add a TLine to the data rate
1708  auto TempLine = std::make_unique<TLine>(DataRate, Histogram->GetMinimum(), DataRate, Histogram->GetMaximum());
1709  TempLine->SetLineColor(kRed);
1710  TempLine->SetLineWidth(2);
1711  // Also fit a Gaussian because why not?
1712  auto Fitter = std::make_unique<TF1>("Fit", "gaus", Histogram->GetBinLowEdge(1), Histogram->GetBinLowEdge(Histogram->GetNbinsX()+1));
1713  Histogram->Fit(Fitter.get(), "RQ");
1714  Fitter->SetLineColor(kRed-5);
1715  // Calculate a p-value
1716  double Above = 0.0;
1717  for (int z = 0; z < Histogram->GetNbinsX(); ++z) {
1718  const double xvalue = Histogram->GetBinCenter(z+1);
1719  if (xvalue >= DataRate) {
1720  Above += Histogram->GetBinContent(z+1);
1721  }
1722  }
1723  const double pvalue = Above/Histogram->Integral();
1724  TLegend Legend(0.4, 0.75, 0.98, 0.90);
1725  Legend.SetFillColor(0);
1726  Legend.SetFillStyle(0);
1727  Legend.SetLineWidth(0);
1728  Legend.SetLineColor(0);
1729  Legend.AddEntry(TempLine.get(), Form("Data, %.0f, p-value=%.2f", DataRate, pvalue), "l");
1730  Legend.AddEntry(Histogram, Form("MC, #mu=%.1f#pm%.1f", Histogram->GetMean(), Histogram->GetRMS()), "l");
1731  Legend.AddEntry(Fitter.get(), Form("Gauss, #mu=%.1f#pm%.1f", Fitter->GetParameter(1), Fitter->GetParameter(2)), "l");
1732  std::string TempTitle = std::string(Histogram->GetName());
1733  TempTitle += "_canv";
1734  TCanvas TempCanvas(TempTitle.c_str(), TempTitle.c_str(), 1024, 1024);
1735  TempCanvas.SetGridx();
1736  TempCanvas.SetGridy();
1737  TempCanvas.SetRightMargin(0.03);
1738  TempCanvas.SetBottomMargin(0.08);
1739  TempCanvas.SetLeftMargin(0.10);
1740  TempCanvas.SetTopMargin(0.06);
1741  TempCanvas.cd();
1742  Histogram->Draw();
1743  TempLine->Draw("same");
1744  Fitter->Draw("same");
1745  Legend.Draw("same");
1746  TempCanvas.Write();
1747  Histogram->Write();
1748  gErrorIgnoreLevel = originalErrorWarning;
1749 }

◆ MakeFluctuatedHistogram()

void PredictiveThrower::MakeFluctuatedHistogram ( TH1 *  FluctHist,
TH1 *  PolyHist 
)
private

Make Poisson fluctuation of TH1D hist.

Parameters
FluctHistHistogram to store fluctuated values (must match Hist type)
HistOriginal histogram to fluctuate

Definition at line 1336 of file PredictiveThrower.cpp.

1336  {
1337 // ****************
1338  // Determine which fluctuation function to call
1339  auto applyFluctuation = [&](auto* f, auto* h) {
1340  if (StandardFluctuation) {
1342  } else {
1344  }
1345  };
1346 
1347  if (Hist->InheritsFrom(TH2Poly::Class())) {
1348  applyFluctuation(static_cast<TH2Poly*>(FluctHist), static_cast<TH2Poly*>(Hist));
1349  }
1350  else if (Hist->InheritsFrom(TH2D::Class())) {
1351  applyFluctuation(static_cast<TH2D*>(FluctHist), static_cast<TH2D*>(Hist));
1352  }
1353  else if (Hist->InheritsFrom(TH1D::Class())) {
1354  applyFluctuation(static_cast<TH1D*>(FluctHist), static_cast<TH1D*>(Hist));
1355  }
1356  else {
1357  MACH3LOG_ERROR("Unsupported histogram type");
1358  throw MaCh3Exception(__FILE__ , __LINE__ );
1359  }
1360 }
void MakeFluctuatedHistogramAlternative(TH1D *FluctHist, TH1D *PolyHist, TRandom3 *rand)
Make Poisson fluctuation of TH1D hist using slow method which is only for cross-check.
void MakeFluctuatedHistogramStandard(TH1D *FluctHist, TH1D *PolyHist, TRandom3 *rand)
Make Poisson fluctuation of TH1D hist using default fast method.
std::unique_ptr< TRandom3 > random
Random number.
Definition: FitterBase.h:153

◆ MakePredictive()

std::vector< std::unique_ptr< TH1 > > PredictiveThrower::MakePredictive ( const std::vector< std::vector< std::unique_ptr< TH1 >>> &  Toys,
const std::vector< TDirectory * > &  Director,
const std::string &  suffix,
const bool  DebugHistograms,
const bool  WriteHist 
)
private

Produce posterior predictive distribution.

  1. Fill histograms, thread safe as all histograms are allocated before and we loop over samples

Definition at line 1064 of file PredictiveThrower.cpp.

1068  {
1069 // *************************
1070  std::vector<std::unique_ptr<TH1>> PostPred(TotalNumberOfSamples);
1071  std::vector<std::vector<std::unique_ptr<TH1D>>> Posterior_hist(TotalNumberOfSamples);
1072  // 1.initialisation
1073  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
1074  const int nDims = SampleInfo[sample].Dimenstion;
1075  const std::string Sample_Name = SampleInfo[sample].Name;
1076  Posterior_hist[sample] = PerBinHistogram(Toys[sample][0].get(), sample, nDims, suffix);
1077  auto PredictiveHist = M3::Clone(Toys[sample][0].get());
1078  // Clear the bin contents
1079  PredictiveHist->Reset();
1080  PredictiveHist->SetName((Sample_Name + "_" + suffix + "_PostPred").c_str());
1081  PredictiveHist->SetTitle((Sample_Name + "_" + suffix + "_PostPred").c_str());
1082  PredictiveHist->SetDirectory(nullptr);
1083  PostPred[sample] = std::move(PredictiveHist);
1084  }
1085 
1087  #ifdef MULTITHREAD
1088  #pragma omp parallel for
1089  #endif
1090  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
1091  const int nDims = SampleInfo[sample].Dimenstion;
1092  auto& hist = Toys[sample][0];
1093  for (size_t iToy = 0; iToy < Toys[sample].size(); ++iToy) {
1094  if(nDims == 2) {
1095  if(std::string(hist->ClassName()) == "TH2Poly") {
1096  for (int i = 1; i <= static_cast<TH2Poly*>(hist.get())->GetNumberOfBins(); ++i) {
1097  double content = Toys[sample][iToy]->GetBinContent(i);
1098  Posterior_hist[sample][i-1]->Fill(content, ReweightWeight[iToy]);
1099  }
1100  } else {
1101  int nbinsx = hist->GetNbinsX();
1102  int nbinsy = hist->GetNbinsY();
1103  for (int iy = 1; iy <= nbinsy; ++iy) {
1104  for (int ix = 1; ix <= nbinsx; ++ix) {
1105  int Bin = (iy-1) * nbinsx + (ix-1);
1106  double content = Toys[sample][iToy]->GetBinContent(ix, iy);
1107  Posterior_hist[sample][Bin]->Fill(content, ReweightWeight[iToy]);
1108  } // end loop over X bins
1109  } // end loop over Y bins
1110  }
1111  } else {
1112  int nbinsx = hist->GetNbinsX();
1113  for (int i = 1; i <= nbinsx; ++i) {
1114  double content = Toys[sample][iToy]->GetBinContent(i);
1115  Posterior_hist[sample][i-1]->Fill(content, ReweightWeight[iToy]);
1116  } // end loop over bins
1117  } // end if over dimensions
1118  } // end loop over toys
1119  } // end loop over samples
1120 
1121  // 3.save
1122  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
1123  const int nDims = SampleInfo[sample].Dimenstion;
1124  auto& hist = Toys[sample][0];
1125  Directory[sample]->cd();
1126  if(nDims == 2) {
1127  if(std::string(hist->ClassName()) == "TH2Poly") {
1128  for (int i = 1; i <= static_cast<TH2Poly*>(hist.get())->GetNumberOfBins(); ++i) {
1129  PostPred[sample]->SetBinContent(i, Posterior_hist[sample][i-1]->GetMean());
1130  // KS: If ROOT below 6.18 one need -1 only for error due to stupid bug...
1131  PostPred[sample]->SetBinError(i, Posterior_hist[sample][i-1]->GetRMS());
1132  if (DebugHistograms) Posterior_hist[sample][i-1]->Write();
1133  } // end loop over poly bins
1134  } else {
1135  int nbinsx = hist->GetNbinsX();
1136  int nbinsy = hist->GetNbinsY();
1137  for (int iy = 1; iy <= nbinsy; ++iy) {
1138  for (int ix = 1; ix <= nbinsx; ++ix) {
1139  int Bin = (iy-1) * nbinsx + (ix-1);
1140  if (DebugHistograms) Posterior_hist[sample][Bin]->Write();
1141  PostPred[sample]->SetBinContent(ix, iy, Posterior_hist[sample][Bin]->GetMean());
1142  PostPred[sample]->SetBinError(ix, iy, Posterior_hist[sample][Bin]->GetRMS());
1143  } // end loop over x
1144  } // end loop over y
1145  }
1146  } else {
1147  int nbinsx = hist->GetNbinsX();
1148  for (int i = 1; i <= nbinsx; ++i) {
1149  PostPred[sample]->SetBinContent(i, Posterior_hist[sample][i-1]->GetMean());
1150  PostPred[sample]->SetBinError(i, Posterior_hist[sample][i-1]->GetRMS());
1151  if (DebugHistograms) Posterior_hist[sample][i-1]->Write();
1152  }
1153  }
1154  if(WriteHist) PostPred[sample]->Write();
1155  } // end loop over samples
1156  return PostPred;
1157 }
std::vector< std::unique_ptr< TH1D > > PerBinHistogram(TH1 *hist, const int SampleId, const int Dim, const std::string &suffix) const
Create per-bin posterior histograms for a given sample.

◆ PerBinHistogram()

std::vector< std::unique_ptr< TH1D > > PredictiveThrower::PerBinHistogram ( TH1 *  hist,
const int  SampleId,
const int  Dim,
const std::string &  suffix 
) const
private

Create per-bin posterior histograms for a given sample.

For each analysis bin of the input histogram, this function allocates a new 1D histogram intended to accumulate the distribution of predicted event counts (e.g. across throws, toys, or posterior evaluations).

The number of output histograms therefore equals the number of physical bins:

  • TH1 → N histograms
  • TH2 → Nx × Ny histograms
  • TH2Poly → one histogram per polygon bin
Parameters
histInput histogram defining the bin structure for this sample.
SampleIdIndex identifying the sample in SampleInfo.
DimDimensionality of the original distribution.
suffixString appended to histogram names (e.g. to distinguish stages).

Definition at line 1007 of file PredictiveThrower.cpp.

1010  {
1011 // *************************
1012  std::vector<std::unique_ptr<TH1D>> PosteriorHistVec;
1013  constexpr int nBins = 100;
1014  const std::string Sample_Name = SampleInfo[SampleId].Name;
1015  if (Dim == 2) {
1016  if(std::string(hist->ClassName()) == "TH2Poly") {
1017  for (int i = 1; i <= static_cast<TH2Poly*>(hist)->GetNumberOfBins(); ++i) {
1018  std::string ProjName = fmt::format("{} {} Bin: {}",
1019  Sample_Name, suffix,
1020  GetBinName(hist, false, Dim, {i}));
1021  // KS: When a histogram is created with an axis lower limit greater or equal to its upper limit ROOT will automatically adjust histogram range
1022  // https://root.cern.ch/doc/master/classTH1.html#auto-bin
1023  auto PosteriorHist = std::make_unique<TH1D>(ProjName.c_str(), ProjName.c_str(), nBins, 1, -1);
1024  PosteriorHist->SetDirectory(nullptr);
1025  PosteriorHist->GetXaxis()->SetTitle("Events");
1026  PosteriorHistVec.push_back(std::move(PosteriorHist));
1027  } //end loop over bin
1028  } else {
1029  int nbinsx = hist->GetNbinsX();
1030  int nbinsy = hist->GetNbinsY();
1031  for (int iy = 1; iy <= nbinsy; ++iy) {
1032  for (int ix = 1; ix <= nbinsx; ++ix) {
1033  std::string ProjName = fmt::format("{} {} Bin: {}",
1034  Sample_Name, suffix,
1035  GetBinName(hist, true, Dim, {ix,iy}));
1036  //KS: When a histogram is created with an axis lower limit greater or equal to its upper limit ROOT will automatically adjust histogram range
1037  // https://root.cern.ch/doc/master/classTH1.html#auto-bin
1038  auto PosteriorHist = std::make_unique<TH1D>(ProjName.c_str(), ProjName.c_str(), nBins, 1, -1);
1039  PosteriorHist->SetDirectory(nullptr);
1040  PosteriorHist->GetXaxis()->SetTitle("Events");
1041  PosteriorHistVec.push_back(std::move(PosteriorHist));
1042  }
1043  }
1044  }
1045  } else {
1046  int nbinsx = hist->GetNbinsX();
1047  PosteriorHistVec.reserve(nbinsx);
1048  for (int i = 1; i <= nbinsx; ++i) {
1049  std::string ProjName = fmt::format("{} {} Bin: {}",
1050  Sample_Name, suffix,
1051  GetBinName(hist, true, Dim, {i}));
1052  //KS: When a histogram is created with an axis lower limit greater or equal to its upper limit ROOT will automatically adjust histogram range
1053  // https://root.cern.ch/doc/master/classTH1.html#auto-bin
1054  auto PosteriorHist = std::make_unique<TH1D>(ProjName.c_str(), ProjName.c_str(), nBins, 1, -1);
1055  PosteriorHist->SetDirectory(nullptr);
1056  PosteriorHist->GetXaxis()->SetTitle("Events");
1057  PosteriorHistVec.push_back(std::move(PosteriorHist));
1058  }
1059  }
1060  return PosteriorHistVec;
1061 }
std::string GetBinName(TH1 *hist, const bool uniform, const int Dim, const std::vector< int > &bins) const
Construct a human-readable label describing a specific analysis bin.

◆ PosteriorPredictivepValue()

void PredictiveThrower::PosteriorPredictivepValue ( const std::vector< std::unique_ptr< TH1 >> &  PostPred_mc,
const std::vector< TDirectory * > &  SampleDir 
)
private

Calculate Posterior Predictive $p$-value Compares observed data to toy datasets generated from:

  • fitted model fluctuations ("Draw")
  • posterior predictive distribution ("Pred")

Computes two discrepancy metrics: • Shape+Rate : bin-by-bin likelihood • Rate-only : total event normalization

TODO This can be multithreaded but be careful for Clone!!!

Definition at line 1363 of file PredictiveThrower.cpp.

1364  {
1365 // *************************
1366  // Step 1: Initialize per-toy accumulators once
1367  // [Sample] [Toys]
1368  auto make_matrix = [&](double init = 0.0) {
1369  return std::vector<std::vector<double>>(
1371  std::vector<double>(Ntoys, init));
1372  };
1373  auto chi2_dat = make_matrix();
1374  auto chi2_mc = make_matrix();
1375  auto chi2_pred = make_matrix();
1376  auto chi2_rate_dat = make_matrix();
1377  auto chi2_rate_mc = make_matrix();
1378  auto chi2_rate_pred = make_matrix();
1379 
1380  // 2. Add penalty terms to global bin
1381  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1382  chi2_dat[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1383  chi2_mc[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1384  chi2_pred[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1385 
1386  chi2_rate_dat[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1387  chi2_rate_mc[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1388  chi2_rate_pred[TotalNumberOfSamples][iToy] = PenaltyTerm[iToy];
1389  }
1390 
1392  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1393  auto SampleHandler = SampleInfo[iSample].SamHandler;
1394  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1395  // Clone histograms to avoid modifying originals
1396  auto DrawFluctHist = M3::Clone(MC_Hist_Toy[iSample][iToy].get());
1397  auto PredFluctHist = M3::Clone(PostPred_mc[iSample].get());
1398 
1399  // Apply fluctuations
1400  MakeFluctuatedHistogram(DrawFluctHist.get(), MC_Hist_Toy[iSample][iToy].get());
1401  MakeFluctuatedHistogram(PredFluctHist.get(), PostPred_mc[iSample].get());
1402 
1403  // I. SHAPE + RATE (bin-by-bin likelihood)
1404  chi2_dat[iSample][iToy] = CalcLLH(Data_Hist[iSample].get(), MC_Hist_Toy[iSample][iToy].get(), W2_Hist_Toy[iSample][iToy].get(), SampleHandler);
1405  chi2_mc[iSample][iToy] = CalcLLH(DrawFluctHist.get(), MC_Hist_Toy[iSample][iToy].get(), W2_Hist_Toy[iSample][iToy].get(), SampleHandler);
1406  chi2_pred[iSample][iToy] = CalcLLH(PredFluctHist.get(), MC_Hist_Toy[iSample][iToy].get(), W2_Hist_Toy[iSample][iToy].get(), SampleHandler);
1407 
1408  // II. RATE-ONLY (total normalization)
1409  chi2_rate_dat[iSample][iToy] = CalcLLH(Data_Hist[iSample]->Integral(), MC_Hist_Toy[iSample][iToy]->Integral(), W2_Hist_Toy[iSample][iToy]->Integral(), SampleHandler);
1410  chi2_rate_mc[iSample][iToy] = CalcLLH(DrawFluctHist->Integral(), MC_Hist_Toy[iSample][iToy]->Integral(), W2_Hist_Toy[iSample][iToy]->Integral(), SampleHandler);
1411  chi2_rate_pred[iSample][iToy] = CalcLLH(PredFluctHist->Integral(), MC_Hist_Toy[iSample][iToy]->Integral(), W2_Hist_Toy[iSample][iToy]->Integral(), SampleHandler);
1412 
1413  // III. accumulate global sums ---
1414  chi2_dat[TotalNumberOfSamples][iToy] += chi2_dat[iSample][iToy];
1415  chi2_mc[TotalNumberOfSamples][iToy] += chi2_mc[iSample][iToy];
1416  chi2_pred[TotalNumberOfSamples][iToy] += chi2_pred[iSample][iToy];
1417 
1418  chi2_rate_dat[TotalNumberOfSamples][iToy] += chi2_rate_dat[iSample][iToy];
1419  chi2_rate_mc[TotalNumberOfSamples][iToy] += chi2_rate_mc[iSample][iToy];
1420  chi2_rate_pred[TotalNumberOfSamples][iToy] += chi2_rate_pred[iSample][iToy];
1421  }
1422  }
1423 
1424  // 4. Produce pValue plots
1425  // Shape+rate posterior predictive checks
1426  MakeChi2Plots(chi2_mc, "-2LLH (Draw Fluc, Draw)", chi2_dat, "-2LLH (Data, Draw)", SampleDir, "_drawfluc_draw");
1427  MakeChi2Plots(chi2_pred, "-2LLH (Pred Fluc, Draw)", chi2_dat, "-2LLH (Data, Draw)", SampleDir, "_predfluc_draw");
1428 
1429  // Rate-only posterior predictive checks
1430  MakeChi2Plots(chi2_rate_mc, "-2LLH (Rate Draw Fluc, Draw)", chi2_rate_dat, "-2LLH (Rate Data, Draw)", SampleDir, "_rate_drawfluc_draw");
1431  MakeChi2Plots(chi2_rate_pred, "-2LLH (Rate Pred Fluc, Draw)", chi2_rate_dat, "-2LLH (Rate Data, Draw)", SampleDir, "_rate_predfluc_draw");
1432 }
void MakeChi2Plots(const std::vector< std::vector< double >> &Chi2_x, const std::string &Chi2_x_title, const std::vector< std::vector< double >> &Chi2_y, const std::string &Chi2_y_title, const std::vector< TDirectory * > &SampleDir, const std::string Title)
Produce Chi2 plot for a single sample based on which $p$-value is calculated.
void MakeFluctuatedHistogram(TH1 *FluctHist, TH1 *PolyHist)
Make Poisson fluctuation of TH1D hist.

◆ PredictiveLLH()

void PredictiveThrower::PredictiveLLH ( const std::vector< std::unique_ptr< TH1 >> &  Data_histogram,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_mc,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_w,
const std::vector< TDirectory * > &  SampleDir 
)
private

Calculate Posterior Predictive LLH.

Definition at line 1435 of file PredictiveThrower.cpp.

1438  {
1439 // *************************
1440  MACH3LOG_INFO("{:<55} {:<10} {:<10} {:<10}", "Sample", "DataInt", "MCInt", "-2LLH");
1441  MACH3LOG_INFO("{:-<55} {:-<10} {:-<10} {:-<10}", "", "", "", "");
1442  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1443  SampleDir[iSample]->cd();
1444  ExtractLLH(Data_histogram[iSample].get(), PostPred_mc[iSample].get(), PostPred_w[iSample].get(), SampleInfo[iSample].SamHandler);
1445  PostPred_mc[iSample]->Write();
1446  }
1447 }
void ExtractLLH(TH1 *DatHist, TH1 *MCHist, TH1 *W2Hist, const SampleHandlerInterface *SampleHandler) const
Calculate the LLH for TH1, set the LLH to title of MCHist.

◆ ProduceSpectra()

void PredictiveThrower::ProduceSpectra ( const std::vector< std::vector< std::vector< std::unique_ptr< TH1D >>>> &  Toys,
const std::vector< TDirectory * > &  Director,
const std::string  suffix,
const bool  DoSummary = true 
) const
private

Produce Violin style spectra.

Definition at line 879 of file PredictiveThrower.cpp.

882  {
883 // *************************
884  std::vector<std::vector<double>> MaxValue(TotalNumberOfSamples);
885 
886  // 1. Create Max value
887  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
888  const int nDims = SampleInfo[sample].Dimenstion;
889  MaxValue[sample].assign(nDims, 0);
890  }
891 
892  // 2. Find maximum entries over all toys
893  #ifdef MULTITHREAD
894  #pragma omp parallel for
895  #endif
896  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
897  for (int toy = 0; toy < Ntoys; ++toy) {
898  const int nDims = SampleInfo[sample].Dimenstion;
899  for (int dim = 0; dim < nDims; dim++) {
900  double max_val = Toys[sample][toy][dim]->GetMaximum();
901  MaxValue[sample][dim] = std::max(MaxValue[sample][dim], max_val);
902  }
903  }
904  }
905 
906  // 3. Make actual spectra histogram (this is because making ROOT histograms is not save)
907  // And we now have actual max values
908  std::vector<std::vector<std::unique_ptr<TH2D>>> Spectra(TotalNumberOfSamples);
909  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
910  const int nDims = SampleInfo[sample].Dimenstion;
911  Spectra[sample].resize(nDims);
912  for (int dim = 0; dim < nDims; dim++) {
913  // Get MC histogram x-axis binning
914  TH1D* refHist = Toys[sample][0][dim].get();
915 
916  const int n_bins_x = refHist->GetNbinsX();
917  std::vector<double> x_bin_edges(n_bins_x + 1);
918  for (int b = 0; b < n_bins_x; ++b) {
919  x_bin_edges[b] = refHist->GetXaxis()->GetBinLowEdge(b + 1);
920  }
921  x_bin_edges[n_bins_x] = refHist->GetXaxis()->GetBinUpEdge(n_bins_x);
922 
923  constexpr int n_bins_y = 400;
924  constexpr double y_min = 0.0;
925  const double y_max = MaxValue[sample][dim] * 1.05;
926 
927  // Create TH2D with variable binning on x axis
928  Spectra[sample][dim] = std::make_unique<TH2D>(
929  (SampleInfo[sample].Name + "_" + suffix + "_dim" + std::to_string(dim)).c_str(), // name
930  (SampleInfo[sample].Name + "_" + suffix + "_dim" + std::to_string(dim)).c_str(), // title
931  n_bins_x, x_bin_edges.data(), // x axis bins
932  n_bins_y, y_min, y_max // y axis bins
933  );
934 
935  Spectra[sample][dim]->GetXaxis()->SetTitle(refHist->GetXaxis()->GetTitle());
936  Spectra[sample][dim]->GetYaxis()->SetTitle("Events");
937 
938  Spectra[sample][dim]->SetDirectory(nullptr);
939  Spectra[sample][dim]->Sumw2(true);
940  }
941  }
942 
943  // 4. now we can actually fill our projections
944  #ifdef MULTITHREAD
945  #pragma omp parallel for collapse(2)
946  #endif
947  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
948  for (int toy = 0; toy < Ntoys; ++toy) {
949  const int nDims = SampleInfo[sample].Dimenstion;
950  for (int dim = 0; dim < nDims; dim++) {
951  FastViolinFill(Spectra[sample][dim].get(), Toys[sample][toy][dim].get());
952  }
953  }
954  }
955 
956  // 5. Save histograms which is not thread save
957  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
958  SampleDirectories[sample]->cd();
959  const int nDims = SampleInfo[sample].Dimenstion;
960  for (long unsigned int dim = 0; dim < Spectra[sample].size(); dim++) {
961  Spectra[sample][dim]->Write();
962  // For case of 2D make additional histograms
963  if(nDims == 2 && DoSummary) {
964  const std::string name = SampleInfo[sample].Name + "_" + suffix+ "_PostPred_dim" + std::to_string(dim);
965  auto Summary = MakeSummaryFromSpectra(Spectra[sample][dim].get(), name);
966  Summary->Write();
967  }
968  }
969  }
970 }
void FastViolinFill(TH2D *violin, TH1D *hist_1d)
KS: Fill Violin histogram with entry from a toy.
std::unique_ptr< TH1D > MakeSummaryFromSpectra(const TH2D *Spectra, const std::string &name)
Build a 1D posterior-predictive summary from a violin spectrum.

◆ ProduceToys()

void PredictiveThrower::ProduceToys ( )

Produce toys by throwing from MCMC.

KS: Names of parameter groups that will not be varied

KS: Index of parameters that will be varied

this store value of parameters sampled from a chain

Definition at line 476 of file PredictiveThrower.cpp.

476  {
477 // *************************
478  // If we found toys then skip process of making new toys
479  if(LoadToys()) return;
480 
482  std::vector<std::string> ParameterGroupsNotVaried;
484  std::unordered_set<int> ParameterOnlyToVary;
485  // For study where one would like to apply bounds
486  std::vector<const M3::float_t*> BoundValuePointer;
487  std::vector<std::pair<double, double>> ParamBounds;
488 
489  // Setup useful information for toy generation
490  SetupToyGeneration(ParameterGroupsNotVaried, ParameterOnlyToVary,
491  BoundValuePointer, ParamBounds);
492 
493  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
494 
495  MACH3LOG_INFO("Starting {}", __func__);
496 
497  outputFile->cd();
498  double Penalty = 0, Weight = 1.;
499  int Draw = 0;
500 
501  TTree *ToyTree = new TTree("ToySummary", "ToySummary");
502  ToyTree->Branch("Penalty", &Penalty, "Penalty/D");
503  ToyTree->Branch("Weight", &Weight, "Weight/D");
504  ToyTree->Branch("Draw", &Draw, "Draw/I");
505  ToyTree->Branch("NModelParams", &NModelParams, "NModelParams/I");
506 
507  // KS: define branches so we can keep track of what params we are throwing
508  std::vector<double> ParamValues(NModelParams);
509  std::vector<const M3::float_t*> ParampPointers(NModelParams);
510  int ParamCounter = 0;
511  for (size_t iSys = 0; iSys < systematics.size(); iSys++)
512  {
513  for (int iPar = 0; iPar < systematics[iSys]->GetNumParams(); iPar++)
514  {
515  ParampPointers[ParamCounter] = systematics[iSys]->RetPointer(iPar);
516  std::string Name = systematics[iSys]->GetParFancyName(iPar);
517  //CW: Also strip out - signs because it messes up TBranches
518  while (Name.find("-") != std::string::npos) {
519  Name.replace(Name.find("-"), 1, std::string("_"));
520  }
521  ToyTree->Branch(Name.c_str(), &ParamValues[ParamCounter], (Name + "/D").c_str());
522  ParamCounter++;
523  }
524  }
525  TDirectory* ToyDirectory = outputFile->mkdir("Toys");
526  ToyDirectory->cd();
527  int SampleCounter = 0;
528  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
529  {
530  auto* MaCh3Sample = samples[iPDF];
531  for (int SampleIndex = 0; SampleIndex < MaCh3Sample->GetNSamples(); ++SampleIndex)
532  {
533  // Get nominal spectra and event rates
534  const TH1* DataHist = MaCh3Sample->GetDataHist(SampleIndex);
535  Data_Hist[SampleCounter] = M3::Clone(DataHist, MaCh3Sample->GetSampleTitle(SampleIndex) + "_data");
536  Data_Hist[SampleCounter]->Write((MaCh3Sample->GetSampleTitle(SampleIndex) + "_data").c_str());
537 
538  const TH1* MCHist = MaCh3Sample->GetMCHist(SampleIndex);
539  MC_Nom_Hist[SampleCounter] = M3::Clone(MCHist, MaCh3Sample->GetSampleTitle(SampleIndex) + "_mc");
540  MC_Nom_Hist[SampleCounter]->Write((MaCh3Sample->GetSampleTitle(SampleIndex) + "_mc").c_str());
541 
542  const TH1* W2Hist = MaCh3Sample->GetW2Hist(SampleIndex);
543  W2_Nom_Hist[SampleCounter] = M3::Clone(W2Hist, MaCh3Sample->GetSampleTitle(SampleIndex) + "_w2");
544  W2_Nom_Hist[SampleCounter]->Write((MaCh3Sample->GetSampleTitle(SampleIndex) + "_w2").c_str());
545  SampleCounter++;
546  }
547  }
548 
549  TDirectory* Toy_1DDirectory = outputFile->mkdir("Toys_1DHistVar");
550  TDirectory* Toy_2DDirectory = outputFile->mkdir("Toys_2DHistVar");
551  auto doByMode = GetFromManager<bool>(fitMan->raw()["Predictive"]["ByMode"], false, __FILE__, __LINE__);
552  TDirectory* ByModeDirectory = nullptr;
553  if(doByMode) ByModeDirectory = outputFile->mkdir("Toys_ByMode");
554  auto ReweightNames = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["ReweightNames"],
555  {"Weight"}, __FILE__, __LINE__);
556  bool doReweight = false;
557  std::vector<double> reweight_weight(ReweightNames.size(), 1.0);
558 
560  std::vector<std::vector<double>> branch_vals(systematics.size());
561  std::vector<std::vector<std::string>> branch_name(systematics.size());
562 
563  TChain* PosteriorFile = nullptr;
564  unsigned int burn_in = 0;
565  unsigned int maxNsteps = 0;
566  unsigned int Step = 0;
567  if(!Is_PriorPredictive)
568  {
569  PosteriorFile = new TChain("posteriors");
570  PosteriorFile->Add(PosteriorFileName.c_str());
571 
572  PosteriorFile->SetBranchAddress("step", &Step);
573  doReweight = true;
574  for (size_t i = 0; i < ReweightNames.size(); ++i) {
575  const auto& name = ReweightNames[i];
576  if (PosteriorFile->GetBranch(name.c_str())) {
577  PosteriorFile->SetBranchStatus(name.c_str(), true);
578  PosteriorFile->SetBranchAddress(name.c_str(), &reweight_weight[i]);
579  } else {
580  MACH3LOG_WARN("Missing reweight branch '{}' -> disabling ALL reweighting", name);
581  doReweight = false;
582  }
583  }
584 
585  for (size_t s = 0; s < systematics.size(); ++s) {
586  auto fancy_names = GetStoredFancyName(systematics[s]);
587  systematics[s]->MatchMaCh3OutputBranches(PosteriorFile, branch_vals[s], branch_name[s], fancy_names);
588  }
589 
590  //Get the burn-in from the config
591  burn_in = Get<unsigned int>(fitMan->raw()["Predictive"]["BurnInSteps"], __FILE__, __LINE__);
592 
593  //DL: Adding sanity check for chains shorter than burn in
594  maxNsteps = static_cast<unsigned int>(PosteriorFile->GetMaximum("step"));
595  if(burn_in >= maxNsteps)
596  {
597  MACH3LOG_ERROR("You are running on a chain shorter than burn in cut");
598  MACH3LOG_ERROR("Maximal value of nSteps: {}, burn in cut {}", maxNsteps, burn_in);
599  MACH3LOG_ERROR("You will run into infinite loop");
600  MACH3LOG_ERROR("You can make new chain or modify burn in cut");
601  throw MaCh3Exception(__FILE__,__LINE__);
602  }
603  }
604 
605  TStopwatch TempClock;
606  TempClock.Start();
607  for(int i = 0; i < Ntoys; i++)
608  {
609  if(Ntoys >= 10 && i % (Ntoys/10) == 0) {
611  }
612  if(!Is_PriorPredictive){
613  int entry = 0;
614  Step = 0;
615  // KS This allow to set additional bounds like mass ordering
616  bool WithinBounds = false;
617  //YSP: Ensures you get an entry from the mcmc even when burn_in is set to zero (Although not advised :p ).
618  //Take 200k burn in steps, WP: Eb C in 1st peaky
619  // If we have combined chains by hadd need to check the step in the chain
620  // Note, entry is not necessarily same as step due to merged ROOT files, so can't choose entry in the range BurnIn - nEntries :(
621  while(Step < burn_in || !WithinBounds) {
622  entry = random->Integer(static_cast<unsigned int>(PosteriorFile->GetEntries()));
623  PosteriorFile->GetEntry(entry);
624  // KS: This might be bit hacky... but BoundValuePointer refer to values in ParameterHandler
625  // so we need to update them
626  if(BoundValuePointer.size() > 0) {
627  for (size_t s = 0; s < systematics.size(); ++s) {
628  systematics[s]->SetParameters(branch_vals[s]);
629  }
630  }
631  WithinBounds = CheckBounds(BoundValuePointer, ParamBounds);
632  }
633  Draw = entry;
634  }
635  for (size_t s = 0; s < systematics.size(); ++s)
636  {
637  //KS: Below line can help you get prior predictive distributions which are helpful for getting pre and post ND fit spectra
638  //YSP: If not set in the config, the code runs SK Posterior Predictive distributions by default. If true, then the code runs SK prior predictive.
639  if(Is_PriorPredictive) {
640  systematics[s]->ThrowParameters();
641  } else {
642  systematics[s]->SetParameters(branch_vals[s]);
643  }
644  }
645 
646  // This set some params to prior value this way you can evaluate errors from subset of errors
647  SetParamters(ParameterGroupsNotVaried, ParameterOnlyToVary);
648 
649  Penalty = 0;
650  if(FullLLH) {
651  for (size_t s = 0; s < systematics.size(); ++s) {
652  //KS: do times 2 because banff reports chi2
653  Penalty = 2.0 * systematics[s]->GetLikelihood();
654  }
655  }
656 
657  PenaltyTerm[i] = Penalty;
658  Weight = 1.;
659  if(doReweight) {
660  for (size_t iWeight = 0; iWeight < reweight_weight.size(); ++iWeight) {
661  Weight *= reweight_weight[iWeight];
662  }
663  }
664  ReweightWeight[i] = Weight;
665 
666  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++) {
667  samples[iPDF]->Reweight();
668  }
669  // Save histograms to file
670  WriteToy(ToyDirectory, Toy_1DDirectory, Toy_2DDirectory, i);
671  if(doByMode) WriteByModeToys(ByModeDirectory, i);
672 
673  // Fill parameter value so we know throw values
674  for (size_t iPar = 0; iPar < ParamValues.size(); iPar++) {
675  ParamValues[iPar] = *ParampPointers[iPar];
676  }
677 
678  ToyTree->Fill();
679  }//end of toys loop
680  TempClock.Stop();
681 
682  if(PosteriorFile) delete PosteriorFile;
683  ToyDirectory->Close(); delete ToyDirectory;
684  Toy_1DDirectory->Close(); delete Toy_1DDirectory;
685  Toy_2DDirectory->Close(); delete Toy_2DDirectory;
686  if(doByMode){
687  ByModeDirectory->Close();
688  delete ByModeDirectory;
689  }
690 
691  outputFile->cd();
692  ToyTree->Write(); delete ToyTree;
693 
694  MACH3LOG_INFO("{} took {:.2f}s to finish for {} toys", __func__, TempClock.RealTime(), Ntoys);
695 }
bool CheckBounds(const std::vector< const M3::float_t * > &BoundValuePointer, const std::vector< std::pair< double, double >> &ParamBounds)
TFile * outputFile
Output.
Definition: FitterBase.h:156
std::vector< SampleHandlerInterface * > samples
Sample holder.
Definition: FitterBase.h:138
std::vector< ParameterHandlerBase * > systematics
Systematic holder.
Definition: FitterBase.h:143
void WriteToy(TDirectory *ToyDirectory, TDirectory *Toy_1DDirectory, TDirectory *Toy_2DDirectory, const int iToy)
Save histograms for a single MCMC Throw/Toy.
bool LoadToys()
Load existing toys.
void WriteByModeToys(TDirectory *ByModeDirectory, const int iToy)
Save mode histograms for a single MCMC Throw/Toy.
void SetupToyGeneration(std::vector< std::string > &ParameterGroupsNotVaried, std::unordered_set< int > &ParameterOnlyToVary, std::vector< const M3::float_t * > &BoundValuePointer, std::vector< std::pair< double, double >> &ParamBounds)
Setup useful variables etc before stating toy generation.
std::vector< std::string > GetStoredFancyName(ParameterHandlerBase *Systematics) const
Get Fancy parameters stored in mcmc chains for passed ParameterHandler.
void SetParamters(std::vector< std::string > &ParameterGroupsNotVaried, std::unordered_set< int > &ParameterOnlyToVary)
This set some params to prior value this way you can evaluate errors from subset of errors.
void PrintProgressBar(const Long64_t Done, const Long64_t All)
KS: Simply print progress bar.
Definition: Monitor.cpp:229

◆ RateAnalysis()

void PredictiveThrower::RateAnalysis ( const std::vector< std::vector< std::unique_ptr< TH1 >>> &  Toys,
const std::vector< TDirectory * > &  SampleDirectories 
) const
private

Produce distribution of number of events for each sample.

Definition at line 1752 of file PredictiveThrower.cpp.

1753  {
1754 // *************************
1755  std::vector<std::unique_ptr<TH1D>> EventHist(TotalNumberOfSamples+1);
1756  for (int iSample = 0; iSample < TotalNumberOfSamples+1; ++iSample) {
1757  std::string Title = "EventHist: ";
1758  if (iSample == TotalNumberOfSamples) {
1759  Title = "Total";
1760  } else {
1761  Title = SampleInfo[iSample].Name;
1762  }
1763  Title += "_sum";
1764  //KS: When a histogram is created with an axis lower limit greater or equal to its upper limit ROOT will automatically adjust histogram range
1765  // https://root.cern.ch/doc/master/classTH1.html#auto-bin
1766  EventHist[iSample] = std::make_unique<TH1D>(Title.c_str(), Title.c_str(), 100, 1, -1);
1767  EventHist[iSample]->SetDirectory(nullptr);
1768  EventHist[iSample]->GetXaxis()->SetTitle("Total event rate");
1769  EventHist[iSample]->GetYaxis()->SetTitle("Counts");
1770  EventHist[iSample]->SetLineWidth(2);
1771  }
1772 
1773  // First fill per-sample histograms
1774  #ifdef MULTITHREAD
1775  #pragma omp parallel for
1776  #endif
1777  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1778  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1779  double Count = Toys[iSample][iToy]->Integral();
1780  EventHist[iSample]->Fill(Count);
1781  }
1782  }
1783 
1784  // Now fill total histogram properly (per toy)
1785  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1786  double TotalCount = 0.0;
1787  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1788  TotalCount += Toys[iSample][iToy]->Integral();
1789  }
1790  EventHist[TotalNumberOfSamples]->Fill(TotalCount);
1791  }
1792 
1793  double DataRate = 0.0;
1794  std::vector<double> DataRates(TotalNumberOfSamples+1);
1795  #ifdef MULTITHREAD
1796  #pragma omp parallel for reduction(+:DataRate)
1797  #endif
1798  for (int i = 0; i < TotalNumberOfSamples; ++i) {
1799  DataRates[i] = Data_Hist[i]->Integral();
1800  DataRate += DataRates[i];
1801  }
1802  DataRates[TotalNumberOfSamples] = DataRate;
1803 
1804  for (int SampleNum = 0; SampleNum < TotalNumberOfSamples+1; ++SampleNum) {
1805  SampleDirectories[SampleNum]->cd();
1806  //Make fancy event rate histogram
1807  MakeCutEventRate(EventHist[SampleNum].get(), DataRates[SampleNum]);
1808  }
1809 }
void MakeCutEventRate(TH1D *Histogram, const double DataRate) const
Make the 1D Event Rate Hist.

◆ RunMCMC()

void PredictiveThrower::RunMCMC ( )
inlineoverridevirtual

This is not used in this class.

Implements FitterBase.

Definition at line 47 of file PredictiveThrower.h.

47  {
48  MACH3LOG_ERROR("{} is not supported in {}", __func__, GetName());
49  throw MaCh3Exception(__FILE__ , __LINE__ );
50  };
std::string GetName() const
Get name of class.
Definition: FitterBase.h:75

◆ RunPredictiveAnalysis()

void PredictiveThrower::RunPredictiveAnalysis ( )

Main routine responsible for producing posterior predictive distributions and $p$-value.

Definition at line 1161 of file PredictiveThrower.cpp.

1161  {
1162 // *************************
1163  // Remove not useful stuff
1164  SanitiseInputs();
1165 
1166  MACH3LOG_INFO("Starting {}", __func__);
1167  MACH3LOG_WARN("\033[0;31mCurrent Total RAM usage is {:.2f} GB\033[0m", M3::Utils::getValue("VmRSS") / 1048576.0);
1168  MACH3LOG_WARN("\033[0;31mOut of Total available RAM {:.2f} GB\033[0m", M3::Utils::getValue("MemTotal") / 1048576.0);
1169 
1170  TStopwatch TempClock;
1171  TempClock.Start();
1172 
1173  auto DebugHistograms = GetFromManager<bool>(fitMan->raw()["Predictive"]["DebugHistograms"], false, __FILE__, __LINE__);
1174  auto doByMode = GetFromManager<bool>(fitMan->raw()["Predictive"]["ByMode"], false, __FILE__, __LINE__);
1175 
1176  TDirectory* PredictiveDir = outputFile->mkdir("Predictive");
1177  std::vector<TDirectory*> SampleDirectories;
1178  SampleDirectories.resize(TotalNumberOfSamples+1);
1179 
1180  // open directory for every sample
1181  for (int sample = 0; sample < TotalNumberOfSamples+1; ++sample) {
1182  SampleDirectories[sample] = PredictiveDir->mkdir(SampleInfo[sample].Name.c_str());
1183  }
1184 
1185  // Produce Violin style spectra
1186  Study1DProjections(SampleDirectories);
1187  // Produce Post pred by each mode individually
1188  if(doByMode) StudyByMode1DProjections(SampleDirectories);
1189  // Produce posterior predictive distribution for mc
1190  auto PostPred_mc = MakePredictive(MC_Hist_Toy, SampleDirectories, "mc", DebugHistograms, false);
1191  // Produce posterior predictive distribution for w2
1192  auto PostPred_w2 = MakePredictive(W2_Hist_Toy, SampleDirectories, "w2", false, false);
1193  // Calculate Posterior Predictive LLH
1194  PredictiveLLH(Data_Hist, PostPred_mc, PostPred_w2, SampleDirectories);
1195  // Calculate Posterior Predictive $p$-value
1196  PosteriorPredictivepValue(PostPred_mc, SampleDirectories);
1197  // Check how number of events changed
1198  RateAnalysis(MC_Hist_Toy, SampleDirectories);
1199 
1200  // Close directories
1201  for (int sample = 0; sample < TotalNumberOfSamples+1; ++sample) {
1202  SampleDirectories[sample]->Close();
1203  delete SampleDirectories[sample];
1204  }
1205 
1206  auto StudyBeta = GetFromManager<bool>(fitMan->raw()["Predictive"]["StudyBetaParameters"], true, __FILE__, __LINE__);
1207  auto StudyInfoCriterion = GetFromManager<bool>(fitMan->raw()["Predictive"]["StudyInformationCriterion"], true, __FILE__, __LINE__);
1208  auto StudyCorr = GetFromManager<bool>(fitMan->raw()["Predictive"]["StudyCorrelations"], true, __FILE__, __LINE__);
1209 
1210  // Studying information criterion
1211  if(StudyInfoCriterion) StudyInformationCriterion(M3::kWAIC, PostPred_mc, PostPred_w2);
1212  // Study Prior/Posterior correlations between samples etc.
1213  if(StudyCorr) StudyCorrelations(PredictiveDir, MC_Hist_Toy, DebugHistograms);
1214  // Perform beta analysis for mc statical uncertainty
1215  if(StudyBeta) StudyBetaParameters(PredictiveDir);
1216 
1217  PredictiveDir->Close();
1218  delete PredictiveDir;
1219 
1220  outputFile->cd();
1221 
1222  TempClock.Stop();
1223  MACH3LOG_INFO("{} took {:.2f}s to finish for {} toys", __func__, TempClock.RealTime(), Ntoys);
1224 }
void SanitiseInputs()
Remove obsolete memory and make other checks before fit starts.
Definition: FitterBase.cpp:224
void StudyCorrelations(TDirectory *PredictiveDir, const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const bool DebugHistograms) const
Study Prior/Posterior correlations between samples etc.
void PosteriorPredictivepValue(const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< TDirectory * > &SampleDir)
Calculate Posterior Predictive $p$-value Compares observed data to toy datasets generated from:
void StudyInformationCriterion(M3::kInfCrit Criterion, const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
Information Criterion.
void StudyByMode1DProjections(const std::vector< TDirectory * > &SampleDirectories) const
Load 1D projections by mode and produce post pred for each.
void PredictiveLLH(const std::vector< std::unique_ptr< TH1 >> &Data_histogram, const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w, const std::vector< TDirectory * > &SampleDir)
Calculate Posterior Predictive LLH.
void RateAnalysis(const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const std::vector< TDirectory * > &SampleDirectories) const
Produce distribution of number of events for each sample.
void Study1DProjections(const std::vector< TDirectory * > &SampleDirectories) const
Load 1D projections and later produce violin plots for each.
void StudyBetaParameters(TDirectory *PredictiveDir)
Evaluate prior/post predictive distribution for beta parameters (used for evaluating impact MC statis...
std::vector< std::unique_ptr< TH1 > > MakePredictive(const std::vector< std::vector< std::unique_ptr< TH1 >>> &Toys, const std::vector< TDirectory * > &Director, const std::string &suffix, const bool DebugHistograms, const bool WriteHist)
Produce posterior predictive distribution.
int getValue(const std::string &Type)
CW: Get info like RAM.
Definition: Monitor.cpp:252
@ kWAIC
Watanabe-Akaike information criterion.

◆ SetParamters()

void PredictiveThrower::SetParamters ( std::vector< std::string > &  ParameterGroupsNotVaried,
std::unordered_set< int > &  ParameterOnlyToVary 
)
private

This set some params to prior value this way you can evaluate errors from subset of errors.

Have ability to not throw legacy matrices

Alternatively vary only selected params

Definition at line 51 of file PredictiveThrower.cpp.

52  {
53 // *************************
54  // WARNING This should be removed in the future
55  auto DoNotThrowLegacyCov = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["DoNotThrowLegacyCov"], {}, __FILE__, __LINE__);
57  for (size_t i = 0; i < DoNotThrowLegacyCov.size(); ++i) {
58  for (size_t s = 0; s < systematics.size(); ++s) {
59  if (systematics[s]->GetName() == DoNotThrowLegacyCov[i]) {
60  systematics[s]->SetParameters();
61  break;
62  }
63  }
64  }
65 
66  // Set groups to prefit values if they were set to not be varies
67  if(ModelSystematic && ParameterGroupsNotVaried.size() > 0) {
68  ModelSystematic->SetGroupOnlyParameters(ParameterGroupsNotVaried);
69  }
70 
72  if (ModelSystematic && !ParameterOnlyToVary.empty()) {
73  for (int i = 0; i < ModelSystematic->GetNumParams(); ++i) {
74  // KS: If parameter is in map then we are skipping this, otherwise for params that we don't want to vary we simply set it to prior
75  if (ParameterOnlyToVary.find(i) == ParameterOnlyToVary.end()) {
77  }
78  }
79  }
80 }
int GetNumParams() const
Get total number of parameters.
void SetParProp(const int i, const double val)
Set proposed parameter value.
double GetParPreFit(const int i) const
Get prior parameter value.
void SetGroupOnlyParameters(const std::string &Group, const std::vector< double > &Pars={})
KS Function to set to prior parameters of a given group or values from vector.

◆ SetupSampleInformation()

void PredictiveThrower::SetupSampleInformation ( )
private

Setup sample information.

Definition at line 83 of file PredictiveThrower.cpp.

83  {
84 // *************************
86  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++) {
87  TotalNumberOfSamples += samples[iPDF]->GetNSamples();
88  }
89 
95 
97 
98 
99  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
100  MC_Hist_Toy[sample].resize(Ntoys);
101  W2_Hist_Toy[sample].resize(Ntoys);
102  }
103  int counter = 0;
104  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++) {
105  for (int SampleIndex = 0; SampleIndex < samples[iPDF]->GetNSamples(); ++SampleIndex) {
106  SampleInfo[counter].Name = samples[iPDF]->GetSampleTitle(SampleIndex);
107  SampleInfo[counter].LocalId = SampleIndex;
108  SampleInfo[counter].SamHandler = samples[iPDF];
109  SampleInfo[counter].Dimenstion = SampleInfo[counter].SamHandler->GetNDim(SampleIndex);
110  counter++;
111  }
112  }
113  SampleInfo[TotalNumberOfSamples].Name= "Total";
114 }

◆ SetupToyGeneration()

void PredictiveThrower::SetupToyGeneration ( std::vector< std::string > &  ParameterGroupsNotVaried,
std::unordered_set< int > &  ParameterOnlyToVary,
std::vector< const M3::float_t * > &  BoundValuePointer,
std::vector< std::pair< double, double >> &  ParamBounds 
)
private

Setup useful variables etc before stating toy generation.

Let's ask the manager what are the file with covariance matrix

Definition at line 118 of file PredictiveThrower.cpp.

121  {
122 // *************************
123  int counter = 0;
124  for (size_t s = 0; s < systematics.size(); ++s) {
125  auto* MaCh3Params = dynamic_cast<ParameterHandlerGeneric*>(systematics[s]);
126  if(MaCh3Params) {
127  ModelSystematic = MaCh3Params;
128  counter++;
129  }
130  }
131 
133 
134  if(Is_PriorPredictive) {
135  MACH3LOG_INFO("You've chosen to run Prior Predictive Distribution");
136  } else {
137  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
138  //KS: We use MCMCProcessor to get names of covariances that were actually used to produce given chain
139  MCMCProcessor Processor(PosteriorFileName);
140  Processor.Initialise();
141 
142  // For throwing FD predictions from ND-only chain we have to allow having different yaml configs
143  auto AllowDifferentConfigs = GetFromManager<bool>(fitMan->raw()["Predictive"]["AllowDifferentConfigs"], false, __FILE__, __LINE__);
144 
146  YAML::Node ConfigInChain = Processor.GetCovConfig(kXSecPar);
147  if(ModelSystematic) {
148  YAML::Node ConfigNow = ModelSystematic->GetConfig();
149  if (!compareYAMLNodes(ConfigNow, ConfigInChain))
150  {
151  if(AllowDifferentConfigs){
152  MACH3LOG_WARN("Yaml configs used for your ParameterHandler for chain you want sample from ({}) and one currently initialised are different", PosteriorFileName);
153  } else {
154  MACH3LOG_ERROR("Yaml configs used for your ParameterHandler for chain you want sample from ({}) and one currently initialised are different", PosteriorFileName);
155  throw MaCh3Exception(__FILE__ , __LINE__ );
156  }
157  }
158  }
159  }
160  if(counter > 1) {
161  MACH3LOG_ERROR("Found {} ParmaterHandler inheriting from ParameterHandlerGeneric, I can accept at most 1", counter);
162  throw MaCh3Exception(__FILE__, __LINE__);
163  }
164 
165  for (size_t s = 0; s < systematics.size(); ++s) {
166  NModelParams += systematics[s]->GetNumParams();
167  }
168 
169  if (ModelSystematic) {
170  auto ThrowParamGroupOnly = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["ThrowParamGroupOnly"], {}, __FILE__, __LINE__);
171  auto UniqueParamGroup = ModelSystematic->GetUniqueParameterGroups();
172  auto ParameterOnlyToVaryString = GetFromManager<std::vector<std::string>>(fitMan->raw()["Predictive"]["ThrowSingleParams"], {}, __FILE__, __LINE__);
173 
174  if (!ThrowParamGroupOnly.empty() && !ParameterOnlyToVaryString.empty()) {
175  MACH3LOG_ERROR("Can't use ThrowParamGroupOnly and ThrowSingleParams at the same time");
176  throw MaCh3Exception(__FILE__, __LINE__);
177  }
178 
179  if (!ParameterOnlyToVaryString.empty()) {
180  MACH3LOG_INFO("I will throw only: {}", fmt::join(ParameterOnlyToVaryString, ", "));
181  std::vector<int> ParameterVary(ParameterOnlyToVaryString.size());
182 
183  for (size_t i = 0; i < ParameterOnlyToVaryString.size(); ++i) {
184  ParameterVary[i] = ModelSystematic->GetParIndex(ParameterOnlyToVaryString[i]);
185  if (ParameterVary[i] == M3::_BAD_INT_) {
186  MACH3LOG_ERROR("Can't proceed if param {} is missing", ParameterOnlyToVaryString[i]);
187  throw MaCh3Exception(__FILE__, __LINE__);
188  }
189  }
190  ParameterOnlyToVary = std::unordered_set<int>(ParameterVary.begin(), ParameterVary.end());
191  } else {
192  MACH3LOG_INFO("I have following parameter groups: {}", fmt::join(UniqueParamGroup, ", "));
193  if (ThrowParamGroupOnly.empty()) {
194  MACH3LOG_INFO("I will vary all");
195  } else {
196  std::unordered_set<std::string> throwOnlySet(ThrowParamGroupOnly.begin(), ThrowParamGroupOnly.end());
197  ParameterGroupsNotVaried.clear();
198 
199  for (const auto& group : UniqueParamGroup) {
200  if (throwOnlySet.find(group) == throwOnlySet.end()) {
201  ParameterGroupsNotVaried.push_back(group);
202  }
203  }
204 
205  MACH3LOG_INFO("I will vary: {}", fmt::join(ThrowParamGroupOnly, ", "));
206  MACH3LOG_INFO("Exclude: {}", fmt::join(ParameterGroupsNotVaried, ", "));
207  }
208  }
209  }
210 
211  auto paramNode = fitMan->raw()["Predictive"]["ParameterBounds"];
212  for (const auto& p : paramNode) {
213  // Extract name
214  std::string name = p[0].as<std::string>();
215 
216  // Extract bounds: min and max
217  double minVal = p[1][0].as<double>();
218  double maxVal = p[1][1].as<double>();
219  ParamBounds.emplace_back(minVal, maxVal);
220 
221  for (size_t s = 0; s < systematics.size(); ++s) {
222  for(int iPar = 0; iPar < systematics[s]->GetNParameters(); iPar++){
223  if(systematics[s]->GetParFancyName(iPar) == name){
224  BoundValuePointer.push_back(systematics[s]->RetPointer(iPar));
225  break;
226  }
227  }
228  }
229  if(ParamBounds.size() != BoundValuePointer.size()){
230  MACH3LOG_ERROR("Ddin't find paramter {}", name);
231  throw MaCh3Exception(__FILE__,__LINE__);
232  }
233  MACH3LOG_INFO("Parameter: {} with : [{}, {}]", name, minVal, maxVal);
234  }
235  if(Is_PriorPredictive && ParamBounds.size() > 0) {
236  MACH3LOG_ERROR("Additional bounds not supported by prior predictive right now");
237  throw MaCh3Exception(__FILE__,__LINE__);
238  }
239 }
@ kXSecPar
Definition: MCMCProcessor.h:46
bool compareYAMLNodes(const YAML::Node &node1, const YAML::Node &node2, bool Mute=false)
Compare if yaml nodes are identical.
Definition: YamlHelper.h:186
Class responsible for processing MCMC chains, performing diagnostics, generating plots,...
Definition: MCMCProcessor.h:61
int GetParIndex(const std::string &name) const
Get index based on name.
YAML::Node GetConfig() const
Getter to return a copy of the YAML node.
Class responsible for handling of systematic error parameters with different types defined in the con...
std::vector< std::string > GetUniqueParameterGroups() const
KS: Get names of all unique parameter groups.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:55

◆ Study1DProjections()

void PredictiveThrower::Study1DProjections ( const std::vector< TDirectory * > &  SampleDirectories) const
private

Load 1D projections and later produce violin plots for each.

Definition at line 698 of file PredictiveThrower.cpp.

698  {
699 // *************************
700  MACH3LOG_INFO("Starting {}", __func__);
701 
702  TDirectory * ogdir = gDirectory;
703  TDirectory* ToyDir = nullptr;
704 
705  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
706  // Open the ROOT file
707  int originalErrorWarning = gErrorIgnoreLevel;
708  gErrorIgnoreLevel = kFatal;
709  TFile* file = TFile::Open(PosteriorFileName.c_str(), "READ");
710  gErrorIgnoreLevel = originalErrorWarning;
711 
712  if (file == nullptr || file->IsZombie()) {
713  ToyDir = outputFile->GetDirectory("Toys_1DHistVar");
714  } else {
715  ToyDir = file->GetDirectory("Toys_1DHistVar");
716  // If toys not amiable in posterior file this means they must be in output file
717  if(ToyDir == nullptr) {
718  ToyDir = outputFile->GetDirectory("Toys_1DHistVar");
719  }
720  }
721 
722  // [sample], [toy], [dim]
723  std::vector<std::vector<std::vector<std::unique_ptr<TH1D>>>> ProjectionToys(TotalNumberOfSamples);
724  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
725  ProjectionToys[sample].resize(Ntoys);
726  const int nDims = SampleInfo[sample].Dimenstion;
727  for (int iToy = 0; iToy < Ntoys; ++iToy) {
728  ProjectionToys[sample][iToy].resize(nDims);
729  }
730  }
731 
732  for (int iToy = 0; iToy < Ntoys; ++iToy) {
733  if (iToy % 100 == 0) MACH3LOG_INFO(" Loaded Projection toys {}", iToy);
734  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
735  const int nDims = SampleInfo[sample].Dimenstion;
736  for(int iDim = 0; iDim < nDims; iDim ++){
737  std::string ProjectionSuffix = "_1DProj" + std::to_string(iDim) + "_" + std::to_string(iToy);
738  TH1D* MCHist1D = static_cast<TH1D*>(ToyDir->Get((SampleInfo[sample].Name + ProjectionSuffix).c_str()));
739  ProjectionToys[sample][iToy][iDim] = M3::Clone(MCHist1D);
740  }
741  } // end loop over samples
742  } // end loop over toys
743  if(file) { file->Close(); delete file; }
744  if(ogdir){ ogdir->cd(); }
745 
746  ProduceSpectra(ProjectionToys, SampleDirectories, "mc");
747  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
748  const int nDims = SampleInfo[sample].Dimenstion;
749  // KS: We only care about doing projections for 2D, for 1D we have well 1D, for beyond 2D we have flattened TH1D
750  if(nDims == 2){
751  auto hist = Data_Hist[sample].get();
752  SampleDirectories[sample]->cd();
753 
754  std::string nameX = "Data_" + SampleInfo[sample].Name + "_Dim0";
755  std::string nameY = "Data_" + SampleInfo[sample].Name + "_Dim1";
756 
757  if(std::string(hist->ClassName()) == "TH2Poly") {
758  TAxis* xax = ProjectionToys[sample][0][0]->GetXaxis();
759  TAxis* yax = ProjectionToys[sample][0][1]->GetXaxis();
760 
761  std::vector<double> XBinning(xax->GetNbins()+1);
762  std::vector<double> YBinning(yax->GetNbins()+1);
763 
764  for(int i=0;i<=xax->GetNbins();++i)
765  XBinning[i] = xax->GetBinLowEdge(i+1);
766 
767  for(int i=0;i<=yax->GetNbins();++i)
768  YBinning[i] = yax->GetBinLowEdge(i+1);
769 
770  TH1D* ProjectionX = PolyProjectionX(static_cast<TH2Poly*>(hist), nameX.c_str(), XBinning, false);
771  TH1D* ProjectionY = PolyProjectionY(static_cast<TH2Poly*>(hist), nameY.c_str(), YBinning, false);
772 
773  auto x_var = SampleInfo[sample].SamHandler->GetKinVarName(SampleInfo[sample].LocalId, 0);
774  auto y_var = SampleInfo[sample].SamHandler->GetKinVarName(SampleInfo[sample].LocalId, 1);
775  ProjectionX->GetXaxis()->SetTitle(x_var.c_str());
776  ProjectionY->GetXaxis()->SetTitle(y_var.c_str());
777 
778  ProjectionX->SetDirectory(nullptr);
779  ProjectionY->SetDirectory(nullptr);
780 
781  ProjectionX->Write(nameX.c_str());
782  ProjectionY->Write(nameY.c_str());
783 
784  delete ProjectionX;
785  delete ProjectionY;
786  } else { //TH2D
787  TH1D* ProjectionX = static_cast<TH2D*>(hist)->ProjectionX(nameX.c_str());
788  TH1D* ProjectionY = static_cast<TH2D*>(hist)->ProjectionY(nameY.c_str());
789 
790  ProjectionX->SetDirectory(nullptr);
791  ProjectionY->SetDirectory(nullptr);
792 
793  ProjectionX->Write(nameX.c_str());
794  ProjectionY->Write(nameY.c_str());
795  delete ProjectionX;
796  delete ProjectionY;
797  }
798  }
799  }
800 }
TH1D * PolyProjectionX(TObject *poly, const std::string &TempName, const std::vector< double > &xbins, const bool computeErrors)
WP: Poly Projectors.
TH1D * PolyProjectionY(TObject *poly, const std::string &TempName, const std::vector< double > &ybins, const bool computeErrors)
WP: Poly Projectors.
void ProduceSpectra(const std::vector< std::vector< std::vector< std::unique_ptr< TH1D >>>> &Toys, const std::vector< TDirectory * > &Director, const std::string suffix, const bool DoSummary=true) const
Produce Violin style spectra.

◆ StudyBetaParameters()

void PredictiveThrower::StudyBetaParameters ( TDirectory *  PredictiveDir)
private

Evaluate prior/post predictive distribution for beta parameters (used for evaluating impact MC statistical uncertainty)

  1. Initialise Beta histogram
  2. Fill histograms, thread safe as all histograms are allocated before and we loop over samples

ROOT enumerates from 1 while MaCh3 from 0

  1. Write to file

Definition at line 1493 of file PredictiveThrower.cpp.

1493  {
1494 // *************************
1495  bool StudyBeta = GetFromManager<bool>(fitMan->raw()["Predictive"]["StudyBetaParameters"], true, __FILE__, __LINE__ );
1496  if (StudyBeta == false) return;
1497 
1498  MACH3LOG_INFO("Starting {}", __func__);
1499  TDirectory* BetaDir = PredictiveDir->mkdir("BetaParameters");
1500  std::vector<std::vector<std::unique_ptr<TH1D>>> BetaHist(TotalNumberOfSamples);
1501  std::vector<TDirectory *> DirBeta(TotalNumberOfSamples);
1502  // initialise directory for each sample
1503  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
1504  BetaDir->cd();
1505  DirBeta[sample] = BetaDir->mkdir(SampleInfo[sample].Name.c_str());
1506  }
1507 
1509  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1510  const int nDims = SampleInfo[iSample].Dimenstion;
1511  // Use any histogram that defines the binning structure
1512  TH1* RefHist = Data_Hist[iSample].get();
1513  BetaHist[iSample] = PerBinHistogram(RefHist, iSample, nDims, "Beta_Parameter");
1514  // Change x-axis title
1515  for (size_t i = 0; i < BetaHist[iSample].size(); ++i) {
1516  BetaHist[iSample][i]->GetXaxis()->SetTitle("beta parameter");
1517  }
1518  }
1519 
1521  #ifdef MULTITHREAD
1522  #pragma omp parallel for
1523  #endif
1524  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1525  const int nDims = SampleInfo[iSample].Dimenstion;
1526  const auto likelihood = SampleInfo[iSample].SamHandler->GetTestStatistic();
1527  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1528  if (nDims == 2) {
1529  if(std::string(Data_Hist[iSample]->ClassName()) == "TH2Poly") {
1530  for (int i = 1; i <= static_cast<TH2Poly*>(Data_Hist[iSample].get())->GetNumberOfBins(); ++i) {
1531  const double Data = Data_Hist[iSample]->GetBinContent(i);
1532  const double MC = MC_Hist_Toy[iSample][iToy]->GetBinContent(i);
1533  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(i);
1534 
1535  const double BetaParam = GetBetaParameter(Data, MC, w2, likelihood);
1536  BetaHist[iSample][i-1]->Fill(BetaParam, ReweightWeight[iToy]);
1537  } // end loop over poly bins
1538  } else {
1539  const int nX = Data_Hist[iSample]->GetNbinsX();
1540  const int nY = Data_Hist[iSample]->GetNbinsY();
1541  for (int iy = 1; iy <= nY; ++iy) {
1542  for (int ix = 1; ix <= nX; ++ix) {
1543  const int FlatBin = (iy-1) * nX + (ix-1);
1544 
1545  const double Data = Data_Hist[iSample]->GetBinContent(ix, iy);
1546  const double MC = MC_Hist_Toy[iSample][iToy]->GetBinContent(ix, iy);
1547  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(ix, iy);
1548 
1549  const double BetaParam = GetBetaParameter(Data, MC, w2, likelihood);
1550  BetaHist[iSample][FlatBin]->Fill(BetaParam, ReweightWeight[iToy]);
1551  }
1552  } // end loop over x
1553  } // end loop over y
1554  } else {
1555  int nbinsx = Data_Hist[iSample]->GetNbinsX();
1556  for (int ix = 1; ix <= nbinsx; ++ix) {
1558  const double Data = Data_Hist[iSample]->GetBinContent(ix);
1559  const double MC = MC_Hist_Toy[iSample][iToy]->GetBinContent(ix);
1560  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(ix);
1561 
1562  const double BetaParam = GetBetaParameter(Data, MC, w2, likelihood);
1563  BetaHist[iSample][ix-1]->Fill(BetaParam, ReweightWeight[iToy]);
1564  } // end loop over bins
1565  }
1566  } // end loop over toys
1567  } // end loop over samples
1568 
1570  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1571  for (size_t iBin = 0; iBin < BetaHist[iSample].size(); iBin++) {
1572  DirBeta[iSample]->cd();
1573  BetaHist[iSample][iBin]->Write();
1574  }
1575  DirBeta[iSample]->Close();
1576  delete DirBeta[iSample];
1577  }
1578  BetaDir->Close();
1579  delete BetaDir;
1580 
1581  PredictiveDir->cd();
1582 }
double GetBetaParameter(const double data, const double mc, const double w2, const TestStatistic TestStat)
KS: Calculate Beta parameter which will be different based on specified test statistic.

◆ StudyBIC()

void PredictiveThrower::StudyBIC ( const std::vector< std::unique_ptr< TH1 >> &  PostPred_mc,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_w 
)
private

Study Bayesian Information Criterion (BIC) The BIC is defined as:

\[ \mathrm{BIC} = -2 \log L + k \log(n) \]

where:

  • \(L\) is the likelihood evaluated at the fitted model
  • \(k\) is the number of model parameters
  • \(n\) is the number of observations

[13]

Definition at line 1843 of file PredictiveThrower.cpp.

1844  {
1845 // ****************
1846  //make fancy event rate histogram
1847  double DataRate = 0.0;
1848  double BinsRate = 0.0;
1849  double TotalLLH = 0.0;
1850  #ifdef MULTITHREAD
1851  #pragma omp parallel for reduction(+:DataRate, BinsRate, TotalLLH)
1852  #endif
1853  for (int i = 0; i < TotalNumberOfSamples; ++i)
1854  {
1855  auto SampleHandler = SampleInfo[i].SamHandler;
1856  auto* h = Data_Hist[i].get();
1857  DataRate += h->Integral();
1858  if (auto h1 = dynamic_cast<TH1D*>(h)) {
1859  BinsRate += h1->GetNbinsX();
1860  } else if (auto h2 = dynamic_cast<TH2D*>(h)) {
1861  BinsRate += h2->GetNbinsX() * h2->GetNbinsY();
1862  } else if (auto h2poly = dynamic_cast<TH2Poly*>(h)) {
1863  BinsRate += h2poly->GetNumberOfBins();
1864  } else {
1865  MACH3LOG_WARN("Unknown histogram type in DataHist[{}]", i);
1866  }
1867  TotalLLH += CalcLLH(Data_Hist[i].get(), PostPred_mc[i].get(), PostPred_w[i].get(), SampleHandler);
1868  }
1869 
1870  const double EventRateBIC = GetBIC(TotalLLH, DataRate, NModelParams);
1871  const double BinBasedBIC = GetBIC(TotalLLH, BinsRate, NModelParams);
1872  MACH3LOG_INFO("Calculated Bayesian Information Criterion using global number of events: {:.2f}", EventRateBIC);
1873  MACH3LOG_INFO("Calculated Bayesian Information Criterion using global number of bins: {:.2f}", BinBasedBIC);
1874  MACH3LOG_INFO("Additional info: NModelParams: {}, DataRate: {:.2f}, BinsRate: {:.2f}", NModelParams, DataRate, BinsRate);
1875 }
double GetBIC(const double llh, const int data, const int nPars)
Get the Bayesian Information Criterion (BIC) or Schwarz information criterion (also SIC,...

◆ StudyByMode1DProjections()

void PredictiveThrower::StudyByMode1DProjections ( const std::vector< TDirectory * > &  SampleDirectories) const
private

Load 1D projections by mode and produce post pred for each.

Todo:
KS: Here we assume each sample has same modes, this is because ProduceSpectra function, expects vector [sample], [toy], [dim], so we make ProjectionToys with [mode], [sample], [toy], [dim] so we can reuse this functionality

Definition at line 803 of file PredictiveThrower.cpp.

803  {
804 // *************************
805  MACH3LOG_INFO("Starting {}", __func__);
806 
807  TDirectory* ogdir = gDirectory;
808  TDirectory* ToyDir = nullptr;
809 
810  auto PosteriorFileName = Get<std::string>(fitMan->raw()["Predictive"]["PosteriorFile"], __FILE__, __LINE__);
811  // Open the ROOT file
812  int originalErrorWarning = gErrorIgnoreLevel;
813  gErrorIgnoreLevel = kFatal;
814  TFile* file = TFile::Open(PosteriorFileName.c_str(), "READ");
815  gErrorIgnoreLevel = originalErrorWarning;
816 
817  if (file == nullptr || file->IsZombie()) {
818  ToyDir = outputFile->GetDirectory("Toys_ByMode");
819  } else {
820  ToyDir = file->GetDirectory("Toys_ByMode");
821  // If toys not amiable in posterior file this means they must be in output file
822  if(ToyDir == nullptr) {
823  ToyDir = outputFile->GetDirectory("Toys_ByMode");
824  }
825  }
826 
830  auto* mode = SampleInfo[0].SamHandler->GetMaCh3Modes();
831  auto NModes = mode->GetNModes()+1;
832  // [mode], [sample], [toy], [dim]
833  std::vector<std::vector<std::vector<std::vector<std::unique_ptr<TH1D>>>>> ProjectionToys(NModes);
834  for(int iMode = 0; iMode < NModes; iMode++) {
835  ProjectionToys[iMode].resize(TotalNumberOfSamples);
836  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
837  ProjectionToys[iMode][sample].resize(Ntoys);
838  const int nDims = SampleInfo[sample].Dimenstion;
839  for (int iToy = 0; iToy < Ntoys; ++iToy) {
840  ProjectionToys[iMode][sample][iToy].resize(nDims);
841  }
842  }
843  }
844 
845  for (int iToy = 0; iToy < Ntoys; ++iToy) {
846  if (iToy % 100 == 0) MACH3LOG_INFO(" Loaded Projection toys {}", iToy);
847  for(int iMode = 0; iMode < NModes; iMode++) {
848  auto ModeName = mode->GetMaCh3ModeName(iMode);
849  for (int sample = 0; sample < TotalNumberOfSamples; ++sample) {
850  const int nDims = SampleInfo[sample].Dimenstion;
851  for(int iDim = 0; iDim < nDims; iDim ++) {
852  std::string ProjectionSuffix = "_1DProj" + std::to_string(iDim) + "_" + ModeName + "_" + std::to_string(iToy);
853  TH1D* MCHist1D = static_cast<TH1D*>(ToyDir->Get((SampleInfo[sample].Name + ProjectionSuffix).c_str()));
854  ProjectionToys[iMode][sample][iToy][iDim] = M3::Clone(MCHist1D);
855  }
856  }
857  } // end loop over samples
858  } // end loop over toys
859 
860  // ByMode directory
861  std::vector<TDirectory*> ModeDirectory(TotalNumberOfSamples);
862  for(int iSample = 0; iSample < TotalNumberOfSamples; iSample++) {
863  ModeDirectory[iSample] = SampleDirectories[iSample]->mkdir("ByMode");
864  }
865  // Produce By Mode Spectra
866  for(int iMode = 0; iMode < NModes; iMode++) {
867  auto ModeName = mode->GetMaCh3ModeName(iMode);
868  ProduceSpectra(ProjectionToys[iMode], ModeDirectory, ModeName, false);
869  }
870  for(int iSample = 0; iSample < TotalNumberOfSamples; iSample++) {
871  ModeDirectory[iSample]->Close();
872  delete ModeDirectory[iSample];
873  }
874  if(file){file->Close(); delete file;}
875  if(ogdir){ ogdir->cd(); }
876 }

◆ StudyCorrelations()

void PredictiveThrower::StudyCorrelations ( TDirectory *  PredictiveDir,
const std::vector< std::vector< std::unique_ptr< TH1 >>> &  Toys,
const bool  DebugHistograms 
) const
private

Study Prior/Posterior correlations between samples etc.

Definition at line 1586 of file PredictiveThrower.cpp.

1588  {
1589 // ****************
1590  MACH3LOG_INFO("Startin {}", __func__);
1591 
1592  // Make a new directory
1593  TDirectory *CorrDir = PredictiveDir->mkdir("Correlations");
1594  CorrDir->cd();
1595 
1596  std::vector<double> minVals(TotalNumberOfSamples, std::numeric_limits<double>::max());
1597  std::vector<double> maxVals(TotalNumberOfSamples, std::numeric_limits<double>::lowest());
1598  #ifdef MULTITHREAD
1599  #pragma omp parallel for
1600  #endif
1601  for (int i = 0; i < TotalNumberOfSamples; ++i)
1602  {
1603  for (const auto& toyHist : Toys[i])
1604  {
1605  const double val = toyHist->Integral();
1606  if (val < minVals[i]) minVals[i] = val;
1607  if (val > maxVals[i]) maxVals[i] = val;
1608  }
1609  }
1610  auto hSamCorr = std::make_unique<TH2D>("Sample Correlation", "Sample Correlation", TotalNumberOfSamples, 0,
1612  hSamCorr->SetDirectory(nullptr);
1613  hSamCorr->GetZaxis()->SetTitle("Correlation");
1614  hSamCorr->SetMinimum(-1);
1615  hSamCorr->SetMaximum(1);
1616  hSamCorr->GetXaxis()->SetLabelSize(0.015);
1617  hSamCorr->GetYaxis()->SetLabelSize(0.015);
1618  // Loop over the Covariance matrix entries
1619  for (int i = 0; i < TotalNumberOfSamples; ++i) {
1620  hSamCorr->SetBinContent(i+1, i+1, 1.0);
1621  hSamCorr->GetXaxis()->SetBinLabel(i+1, SampleInfo[i].Name.c_str());
1622  for (int j = 0; j < TotalNumberOfSamples; ++j) {
1623  hSamCorr->GetYaxis()->SetBinLabel(j+1, SampleInfo[j].Name.c_str());
1624  }
1625  }
1626 
1627  std::vector<std::vector<std::unique_ptr<TH2D>>> SamCorr(TotalNumberOfSamples);
1628  for (int i = 0; i < TotalNumberOfSamples; ++i)
1629  {
1630  SamCorr[i].resize(TotalNumberOfSamples);
1631  const double Min_i = minVals[i];
1632  const double Max_i = maxVals[i];
1633  for (int j = 0; j < TotalNumberOfSamples; ++j)
1634  {
1635  const double Min_j = minVals[j];
1636  const double Max_j = maxVals[j];
1637  // TH2D to hold the Correlation
1638  std::string name = "SamCorr_" + std::to_string(i) + "_" + std::to_string(j);
1639  SamCorr[i][j] = std::make_unique<TH2D>(name.c_str(), name.c_str(), 70, Min_i, Max_i, 70, Min_j, Max_j);
1640  SamCorr[i][j]->SetDirectory(nullptr);
1641  SamCorr[i][j]->SetMinimum(0);
1642  SamCorr[i][j]->GetXaxis()->SetTitle(SampleInfo[i].Name.c_str());
1643  SamCorr[i][j]->GetYaxis()->SetTitle(SampleInfo[j].Name.c_str());
1644  SamCorr[i][j]->GetZaxis()->SetTitle("Events");
1645  }
1646  }
1647 
1648  // Now we are sure we have the diagonal elements, let's make the off-diagonals
1649  #ifdef MULTITHREAD
1650  #pragma omp parallel for
1651  #endif
1652  for (int i = 0; i < TotalNumberOfSamples; ++i)
1653  {
1654  for (int j = 0; j <= i; ++j)
1655  {
1656  // Skip the diagonal elements which we've already done above
1657  if (j == i) continue;
1658 
1659  for (int iToy = 0; iToy < Ntoys; ++iToy)
1660  {
1661  SamCorr[i][j]->Fill(Toys[i][iToy]->Integral(), Toys[j][iToy]->Integral());
1662  }
1663  SamCorr[i][j]->Smooth();
1664 
1665  // The value of the Covariance
1666  const double corr = SamCorr[i][j]->GetCorrelationFactor();
1667  hSamCorr->SetBinContent(i+1, j+1, corr);
1668  hSamCorr->SetBinContent(j+1, i+1, corr);
1669  }// End j loop
1670  }// End i loop
1671 
1672  hSamCorr->Draw("colz");
1673  hSamCorr->Write("Sample_Corr");
1674 
1675  if(DebugHistograms) {
1676  for (int i = 0; i < TotalNumberOfSamples; ++i){
1677  for (int j = 0; j <= i; ++j) {
1678  // Skip the diagonal elements which we've already done above
1679  if (j == i) continue;
1680  SamCorr[i][j]->Write();
1681  }// End j loop
1682  }// End i loop
1683  } // end if debugHist
1684 
1685  PredictiveDir->cd();
1686 }

◆ StudyDIC()

void PredictiveThrower::StudyDIC ( const std::vector< std::unique_ptr< TH1 >> &  PostPred_mc,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_w 
)
private

KS: Get the Deviance Information Criterion (DIC) The deviance is defined as:

\[ D(\theta) = -2 \log L(\theta) \]

The DIC statistic is then:

\[ \mathrm{DIC} = D(\hat{\theta}) + 2p_D \]

where:

\[ p_D = \bar{D} - D(\hat{\theta}) \]

is the effective number of parameters, and

\[ \bar{D} = E_{\theta|y}[D(\theta)] \]

[33] [35]

Definition at line 1879 of file PredictiveThrower.cpp.

1880  {
1881 // ****************
1882  //The posterior mean of the deviance
1883  double Dbar = 0.;
1884  double TotalLLH = 0.0;
1885 
1886  #ifdef MULTITHREAD
1887  #pragma omp parallel for reduction(+:Dbar)
1888  #endif
1889  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample)
1890  {
1891  auto SampleHandler = SampleInfo[iSample].SamHandler;
1892  TotalLLH += CalcLLH(Data_Hist[iSample].get(), PostPred_mc[iSample].get(), PostPred_w[iSample].get(), SampleHandler);
1893  double LLH_temp = 0.;
1894  for (int iToy = 0; iToy < Ntoys; ++iToy)
1895  {
1896  LLH_temp += CalcLLH(Data_Hist[iSample].get(), MC_Hist_Toy[iSample][iToy].get(), W2_Hist_Toy[iSample][iToy].get(), SampleHandler);
1897  }
1898  Dbar += LLH_temp;
1899  }
1900  Dbar = Dbar / Ntoys;
1901 
1902  // A point estimate of the deviance
1903  const double Dhat = TotalLLH;
1904 
1905  //Effective number of parameters
1906  const double p_D = std::fabs(Dbar - Dhat);
1907 
1908  //Actual test stat
1909  const double DIC_stat = Dhat + 2 * p_D;
1910  MACH3LOG_INFO("Effective number of parameters following DIC formalism is equal to: {:.2f}", p_D);
1911  MACH3LOG_INFO("DIC test statistic = {:.2f}", DIC_stat);
1912 }

◆ StudyInformationCriterion()

void PredictiveThrower::StudyInformationCriterion ( M3::kInfCrit  Criterion,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_mc,
const std::vector< std::unique_ptr< TH1 >> &  PostPred_w 
)
private

Information Criterion.

Definition at line 1813 of file PredictiveThrower.cpp.

1815  {
1816 // ****************
1817  MACH3LOG_INFO("******************************");
1818  switch(Criterion) {
1819  case M3::kInfCrit::kBIC:
1820  // Study Bayesian Information Criterion
1821  StudyBIC(PostPred_mc, PostPred_w);
1822  break;
1823  case M3::kInfCrit::kDIC:
1824  // Study Deviance Information Criterion
1825  StudyDIC(PostPred_mc, PostPred_w);
1826  break;
1827  case M3::kInfCrit::kWAIC:
1828  // Study Watanabe-Akaike information criterion (WAIC)
1829  StudyWAIC();
1830  break;
1832  MACH3LOG_ERROR("kInfCrits is not a valid kInfCrit!");
1833  throw MaCh3Exception(__FILE__, __LINE__);
1834  default:
1835  MACH3LOG_ERROR("UNKNOWN Information Criterion SPECIFIED!");
1836  MACH3LOG_ERROR("You gave {}", static_cast<int>(Criterion));
1837  throw MaCh3Exception(__FILE__ , __LINE__ );
1838  }
1839  MACH3LOG_INFO("******************************");
1840 }
void StudyBIC(const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
Study Bayesian Information Criterion (BIC) The BIC is defined as:
void StudyWAIC()
KS: Get the Watanabe-Akaike information criterion (WAIC)
void StudyDIC(const std::vector< std::unique_ptr< TH1 >> &PostPred_mc, const std::vector< std::unique_ptr< TH1 >> &PostPred_w)
KS: Get the Deviance Information Criterion (DIC) The deviance is defined as:
@ kInfCrits
This only enumerates.
@ kBIC
Bayesian Information Criterion.
@ kDIC
Deviance Information Criterion.

◆ StudyWAIC()

void PredictiveThrower::StudyWAIC ( )
private

KS: Get the Watanabe-Akaike information criterion (WAIC)

WAIC is a fully Bayesian measure of model fit that estimates the predictive accuracy, taking into account the effective number of parameters in the model.

It is defined as:

\[ \text{WAIC} = -2 \left( \text{lppd} - p_\text{WAIC} \right), \]

where

\[ \text{lppd} = \sum_{i=1}^n \log \left( \frac{1}{S} \sum_{s=1}^S p(y_i \mid \theta_s) \right) \]

is the log pointwise predictive density and

\[ p_\text{WAIC} = \sum_{i=1}^n \text{Var}_{s=1,\dots,S} \left[ \log p(y_i \mid \theta_s) \right] \]

is the effective number of parameters (variance of log-likelihood over posterior samples).

[13] [18]

Definition at line 1950 of file PredictiveThrower.cpp.

1950  {
1951 // ****************
1952  // log pointwise predictive density
1953  double lppd = 0.;
1954  // effective number of parameters
1955  double p_WAIC = 0.;
1956 
1957  #ifdef MULTITHREAD
1958  #pragma omp parallel for reduction(+:lppd, p_WAIC)
1959  #endif
1960  for (int iSample = 0; iSample < TotalNumberOfSamples; ++iSample) {
1961  auto SampleHandler = SampleInfo[iSample].SamHandler;
1962  auto* hData = Data_Hist[iSample].get();
1963 
1964  if (auto h2poly = dynamic_cast<TH2Poly*>(hData)) {
1965  // TH2Poly: irregular bins, linear indexing
1966  for (int i = 1; i <= h2poly->GetNumberOfBins(); ++i) {
1967  const double data = Data_Hist[iSample]->GetBinContent(i);
1968  double mean_llh = 0.;
1969  double sum_exp_llh = 0;
1970  double mean_llh_squared = 0.;
1971 
1972  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1973  const double mc = MC_Hist_Toy[iSample][iToy]->GetBinContent(i);
1974  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(i);
1975  // Get the -log-likelihood for this sample and bin
1976  double neg_LLH_temp = SampleHandler->GetTestStatLLH(data, mc, w2);
1977  AccumulateWAICToy(neg_LLH_temp, mean_llh, mean_llh_squared, sum_exp_llh);
1978  }
1979  AccumulateWAICBin(mean_llh, mean_llh_squared, sum_exp_llh, Ntoys, lppd, p_WAIC);
1980  }
1981  } else if (auto h2 = dynamic_cast<TH2D*>(hData)) {
1982  // TH2D: nested loops over X and Y
1983  for (int ix = 1; ix <= h2->GetNbinsX(); ++ix) {
1984  for (int iy = 1; iy <= h2->GetNbinsY(); ++iy) {
1985  const double data = hData->GetBinContent(ix, iy);
1986  double mean_llh = 0.;
1987  double mean_llh_squared = 0.;
1988  double sum_exp_llh = 0.;
1989  for (int iToy = 0; iToy < Ntoys; ++iToy) {
1990  const double mc = MC_Hist_Toy[iSample][iToy]->GetBinContent(ix, iy);
1991  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(ix, iy);
1992  // Get the -log-likelihood for this sample and bin
1993  double neg_LLH_temp = SampleHandler->GetTestStatLLH(data, mc, w2);
1994  AccumulateWAICToy(neg_LLH_temp, mean_llh, mean_llh_squared, sum_exp_llh);
1995  }
1996  AccumulateWAICBin(mean_llh, mean_llh_squared, sum_exp_llh, Ntoys, lppd, p_WAIC);
1997  }
1998  }
1999  } else if (auto h1 = dynamic_cast<TH1D*>(hData)) {
2000  // TH1D: 1D histogram
2001  for (int iBin = 1; iBin <= h1->GetNbinsX(); ++iBin) {
2002  const double data = hData->GetBinContent(iBin);
2003  double mean_llh = 0.;
2004  double mean_llh_squared = 0.;
2005  double sum_exp_llh = 0.;
2006  for (int iToy = 0; iToy < Ntoys; ++iToy) {
2007  const double mc = MC_Hist_Toy[iSample][iToy]->GetBinContent(iBin);
2008  const double w2 = W2_Hist_Toy[iSample][iToy]->GetBinContent(iBin);
2009 
2010  // Get the -log-likelihood for this sample and bin
2011  double neg_LLH_temp = SampleHandler->GetTestStatLLH(data, mc, w2);
2012  AccumulateWAICToy(neg_LLH_temp, mean_llh, mean_llh_squared, sum_exp_llh);
2013  }
2014  AccumulateWAICBin(mean_llh, mean_llh_squared, sum_exp_llh, Ntoys, lppd, p_WAIC);
2015  }
2016  }
2017  }
2018 
2019  // Compute WAIC, see Eq. 13 in Gelman2014
2020  double WAIC = -2 * (lppd - p_WAIC);
2021  MACH3LOG_INFO("Effective number of parameters following WAIC formalism is equal to: {:.2f}", p_WAIC);
2022  MACH3LOG_INFO("WAIC = {:.2f}", WAIC);
2023 }
void AccumulateWAICToy(const double neg_LLH_temp, double &mean_llh, double &mean_llh_squared, double &sum_exp_llh)
void AccumulateWAICBin(double &mean_llh, double &mean_llh_squared, double &sum_exp_llh, const unsigned int Ntoys, double &lppd, double &p_WAIC)

◆ WriteByModeToys()

void PredictiveThrower::WriteByModeToys ( TDirectory *  ByModeDirectory,
const int  iToy 
)
private

Save mode histograms for a single MCMC Throw/Toy.

Definition at line 431 of file PredictiveThrower.cpp.

432  {
433 // *************************
434  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
435  {
436  auto* SampleHandler = samples[iPDF];
437  auto* modes = SampleHandler->GetMaCh3Modes();
438  for (int iSample = 0; iSample < SampleHandler->GetNSamples(); ++iSample)
439  {
440  ByModeDirectory->cd();
441 
442  auto SampleName = SampleHandler->GetSampleTitle(iSample);
443  for (int iMode = 0; iMode < modes->GetNModes()+1; ++iMode) {
444  auto ModeName = modes->GetMaCh3ModeName(iMode);
445  for(int iDim = 0; iDim < SampleHandler->GetNDim(iSample); iDim++) {
446  std::string ProjectionName = SampleHandler->GetKinVarName(iSample, iDim);
447  std::string PlotSuffix = "_1DProj" + std::to_string(iDim) + "_" + ModeName + "_" + std::to_string(iToy);
448 
449  auto hist = SampleHandler->Get1DVarHistByModeAndChannel(iSample, ProjectionName, iMode);
450  hist->SetTitle((SampleName + PlotSuffix).c_str());
451  hist->SetName((SampleName + PlotSuffix).c_str());
452  hist->Write();
453  } // end loop over dimension
454  } // end loop over mode
455  } // end loop over sample
456  } // end loop over sample handler objects
457 }

◆ WriteToy()

void PredictiveThrower::WriteToy ( TDirectory *  ToyDirectory,
TDirectory *  Toy_1DDirectory,
TDirectory *  Toy_2DDirectory,
const int  iToy 
)
private

Save histograms for a single MCMC Throw/Toy.

Definition at line 373 of file PredictiveThrower.cpp.

376  {
377 // *************************
378  int SampleCounter = 0;
379  for (size_t iPDF = 0; iPDF < samples.size(); iPDF++)
380  {
381  auto* SampleHandler = samples[iPDF];
382  for (int iSample = 0; iSample < SampleHandler->GetNSamples(); ++iSample)
383  {
384  ToyDirectory->cd();
385 
386  auto SampleName = SampleHandler->GetSampleTitle(iSample);
387  const TH1* MCHist = SampleHandler->GetMCHist(iSample);
388  MC_Hist_Toy[SampleCounter][iToy] = M3::Clone(MCHist, SampleName + "_mc_" + std::to_string(iToy));
389  MC_Hist_Toy[SampleCounter][iToy]->Write();
390 
391  const TH1* W2Hist = SampleHandler->GetW2Hist(iSample);
392  W2_Hist_Toy[SampleCounter][iToy] = M3::Clone(W2Hist, SampleName + "_w2_" + std::to_string(iToy));
393  W2_Hist_Toy[SampleCounter][iToy]->Write();
394 
395  // now get 1D projection for every dimension
396  Toy_1DDirectory->cd();
397  for(int iDim = 0; iDim < SampleHandler->GetNDim(iSample); iDim++) {
398  std::string ProjectionName = SampleHandler->GetKinVarName(iSample, iDim);
399  std::string ProjectionSuffix = "_1DProj" + std::to_string(iDim) + "_" + std::to_string(iToy);
400 
401  auto hist = SampleHandler->Get1DVarHist(iSample, ProjectionName);
402  hist->SetTitle((SampleName + ProjectionSuffix).c_str());
403  hist->SetName((SampleName + ProjectionSuffix).c_str());
404  hist->Write();
405  }
406 
407  Toy_2DDirectory->cd();
408  // now get 2D projection for every combination
409  for(int iDim1 = 0; iDim1 < SampleHandler->GetNDim(iSample); iDim1++) {
410  for (int iDim2 = iDim1 + 1; iDim2 < SampleHandler->GetNDim(iSample); ++iDim2) {
411  // Get the names for the two dimensions
412  std::string XVarName = SampleHandler->GetKinVarName(iSample, iDim1);
413  std::string YVarName = SampleHandler->GetKinVarName(iSample, iDim2);
414 
415  // Get the 2D histogram for this pair
416  auto hist2D = SampleHandler->Get2DVarHist(iSample, XVarName, YVarName);
417 
418  // Write the histogram
419  std::string suffix2D = "_2DProj_" + std::to_string(iDim1) + "_vs_" + std::to_string(iDim2) + "_" + std::to_string(iToy);
420  hist2D->SetTitle((SampleName + suffix2D).c_str());
421  hist2D->SetName((SampleName + suffix2D).c_str());
422  hist2D->Write();
423  }
424  }
425  SampleCounter++;
426  }
427  }
428 }

Member Data Documentation

◆ Data_Hist

std::vector<std::unique_ptr<TH1> > PredictiveThrower::Data_Hist
private

Vector of Data histograms.

Definition at line 307 of file PredictiveThrower.h.

◆ FullLLH

bool PredictiveThrower::FullLLH
private

KS: Use Full LLH or only sample contribution based on discussion with Asher we almost always only want the sample likelihood.

Definition at line 288 of file PredictiveThrower.h.

◆ Is_PriorPredictive

bool PredictiveThrower::Is_PriorPredictive
private

Whether it is Prior or Posterior predictive.

Definition at line 292 of file PredictiveThrower.h.

◆ MC_Hist_Toy

std::vector<std::vector<std::unique_ptr<TH1> > > PredictiveThrower::MC_Hist_Toy
private

Vector of MC histograms per sample and toy experiment. Indexed as [sample][toy].

Definition at line 315 of file PredictiveThrower.h.

◆ MC_Nom_Hist

std::vector<std::unique_ptr<TH1> > PredictiveThrower::MC_Nom_Hist
private

Vector of MC histograms.

Definition at line 309 of file PredictiveThrower.h.

◆ ModelSystematic

ParameterHandlerGeneric* PredictiveThrower::ModelSystematic
private

Pointer to El Generico.

Definition at line 304 of file PredictiveThrower.h.

◆ NModelParams

int PredictiveThrower::NModelParams
private

KS: Count total number of model parameters which can be used for stuff like BIC.

Definition at line 290 of file PredictiveThrower.h.

◆ Ntoys

int PredictiveThrower::Ntoys
private

Number of toys we are generating analysing.

Definition at line 301 of file PredictiveThrower.h.

◆ PenaltyTerm

std::vector<double> PredictiveThrower::PenaltyTerm
private

Penalty term values for each toy by default 0.

Definition at line 323 of file PredictiveThrower.h.

◆ ReweightWeight

std::vector<double> PredictiveThrower::ReweightWeight
private

Reweighting factors applied for each toy, by default 1.

Definition at line 321 of file PredictiveThrower.h.

◆ SampleInfo

std::vector<PredictiveSample> PredictiveThrower::SampleInfo
private

Handy struct for all sample info.

Definition at line 298 of file PredictiveThrower.h.

◆ StandardFluctuation

bool PredictiveThrower::StandardFluctuation
private

KS: We have two methods for Poissonian fluctuation.

Definition at line 326 of file PredictiveThrower.h.

◆ TotalNumberOfSamples

int PredictiveThrower::TotalNumberOfSamples
private

Number of toys we are generating analysing.

Definition at line 295 of file PredictiveThrower.h.

◆ W2_Hist_Toy

std::vector<std::vector<std::unique_ptr<TH1> > > PredictiveThrower::W2_Hist_Toy
private

Vector of W² histograms per sample and toy experiment. Indexed as [sample][toy]

Definition at line 318 of file PredictiveThrower.h.

◆ W2_Nom_Hist

std::vector<std::unique_ptr<TH1> > PredictiveThrower::W2_Nom_Hist
private

Vector of W2 histograms.

Definition at line 311 of file PredictiveThrower.h.


The documentation for this class was generated from the following files: