MaCh3  2.2.3
Reference Guide
Functions
Sample Handler Getters

Functions

virtual M3::int_t SampleHandlerBase::GetNsamples ()
 
virtual std::string SampleHandlerBase::GetTitle () const
 
virtual std::string SampleHandlerBase::GetSampleName (int Sample) const =0
 
virtual double SampleHandlerBase::GetSampleLikelihood (const int isample)
 
MaCh3ModesSampleHandlerBase::GetMaCh3Modes () const
 Return pointer to MaCh3 modes. More...
 
virtual double SampleHandlerBase::GetLikelihood ()=0
 
unsigned int SampleHandlerBase::GetNEvents () const
 
virtual int SampleHandlerBase::GetNOscChannels ()
 
double SampleHandlerBase::GetPoissonLLH (const double data, const double mc) const
 Calculate test statistic for a single bin using Poisson. More...
 
double SampleHandlerBase::GetTestStatLLH (const double data, const double mc, const double w2) const
 Calculate test statistic for a single bin. Calculation depends on setting of fTestStatistic. Data and mc -> 0 cut-offs are defined in M3::LOW_MC_BOUND. More...
 
void SampleHandlerBase::SetTestStatistic (TestStatistic testStat)
 Set the test statistic to be used when calculating the binned likelihoods. More...
 
int SampleHandlerFD::GetNDim () const
 DB Function to differentiate 1D or 2D binning. More...
 
std::string SampleHandlerFD::GetSampleName (int iSample=0) const override
 
std::string SampleHandlerFD::GetTitle () const override
 
std::string SampleHandlerFD::GetXBinVarName () const
 
std::string SampleHandlerFD::GetYBinVarName () const
 
TH1 * SampleHandlerFD::GetMCHist (const int Dimension)
 Get MC histogram. More...
 
TH1 * SampleHandlerFD::GetW2Hist (const int Dimension)
 Get W2 histogram. More...
 
TH1 * SampleHandlerFD::GetDataHist (const int Dimension)
 Get Data histogram. More...
 
int SampleHandlerFD::GetNOscChannels () override
 
std::string SampleHandlerFD::GetFlavourName (const int iChannel)
 
TH1 * SampleHandlerFD::Get1DVarHist (const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec=std::vector< KinematicCut >(), int WeightStyle=0, TAxis *Axis=nullptr, const std::vector< KinematicCut > &SubEventSelectionVec=std::vector< KinematicCut >())
 
void SampleHandlerFD::Fill1DSubEventHist (TH1D *_h1DVar, const std::string &ProjectionVar, const std::vector< KinematicCut > &SubEventSelectionVec=std::vector< KinematicCut >(), int WeightStyle=0)
 
TH1 * SampleHandlerFD::Get1DVarHistByModeAndChannel (const std::string &ProjectionVar_Str, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *Axis=nullptr)
 
TH2 * SampleHandlerFD::Get2DVarHistByModeAndChannel (const std::string &ProjectionVar_StrX, const std::string &ProjectionVar_StrY, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *AxisX=nullptr, TAxis *AxisY=nullptr)
 
TH1 * SampleHandlerFD::GetModeHist1D (int s, int m, int style=0)
 
TH2 * SampleHandlerFD::GetModeHist2D (int s, int m, int style=0)
 
std::vector< TH1 * > SampleHandlerFD::ReturnHistsBySelection1D (std::string KinematicProjection, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *Axis=0)
 
std::vector< TH2 * > SampleHandlerFD::ReturnHistsBySelection2D (std::string KinematicProjectionX, std::string KinematicProjectionY, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *XAxis=0, TAxis *YAxis=0)
 
THStack * SampleHandlerFD::ReturnStackedHistBySelection1D (std::string KinematicProjection, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *Axis=0)
 
TLegend * SampleHandlerFD::ReturnStackHistLegend ()
 
int SampleHandlerFD::ReturnKinematicParameterFromString (const std::string &KinematicStr) const
 ETA function to generically convert a string from xsec cov to a kinematic type. More...
 
std::string SampleHandlerFD::ReturnStringFromKinematicParameter (const int KinematicVariable) const
 ETA function to generically convert a kinematic type from xsec cov to a string. More...
 

Detailed Description

Group of functions to get various parameters, names, and values.

Function Documentation

◆ Fill1DSubEventHist()

void SampleHandlerFD::Fill1DSubEventHist ( TH1D *  _h1DVar,
const std::string &  ProjectionVar,
const std::vector< KinematicCut > &  SubEventSelectionVec = std::vector< KinematicCut >(),
int  WeightStyle = 0 
)

Definition at line 1491 of file SampleHandlerFD.cpp.

1491  {
1492  int ProjectionVar_Int = ReturnKinematicVectorFromString(ProjectionVar_Str);
1493 
1494  //JM Loop over all events
1495  for (unsigned int iEvent = 0; iEvent < GetNEvents(); iEvent++) {
1496  if (IsEventSelected(iEvent)) {
1497  double Weight = GetEventWeight(iEvent);
1498  if (WeightStyle == 1) {
1499  Weight = 1.;
1500  }
1501  std::vector<double> Vec = ReturnKinematicVector(ProjectionVar_Int,iEvent);
1502  size_t nsubevents = Vec.size();
1503  //JM Loop over all subevents in event
1504  for (unsigned int iSubEvent = 0; iSubEvent < nsubevents; iSubEvent++) {
1505  if (IsSubEventSelected(SubEventSelectionVec, iEvent, iSubEvent, nsubevents)) {
1506  double Var = Vec[iSubEvent];
1507  _h1DVar->Fill(Var,Weight);
1508  }
1509  }
1510  }
1511  }
1512 }
bool IsEventSelected(const int iEvent)
DB Function which determines if an event is selected, where Selection double looks like {{ND280Kinema...
M3::float_t GetEventWeight(const int iEntry) const
bool IsSubEventSelected(const std::vector< KinematicCut > &SubEventCuts, const int iEvent, unsigned const int iSubEvent, size_t nsubevents)
JM Function which determines if a subevent is selected.
int ReturnKinematicVectorFromString(const std::string &KinematicStr) const
virtual std::vector< double > ReturnKinematicVector(std::string KinematicParameter, int iEvent)
unsigned int GetNEvents() const

◆ Get1DVarHist()

TH1 * SampleHandlerFD::Get1DVarHist ( const std::string &  ProjectionVar,
const std::vector< KinematicCut > &  EventSelectionVec = std::vector< KinematicCut >(),
int  WeightStyle = 0,
TAxis *  Axis = nullptr,
const std::vector< KinematicCut > &  SubEventSelectionVec = std::vector< KinematicCut >() 
)

Definition at line 1437 of file SampleHandlerFD.cpp.

1438  {
1439  //DB Need to overwrite the Selection member variable so that IsEventSelected function operates correctly.
1440  // Consequently, store the selection cuts already saved in the sample, overwrite the Selection variable, then reset
1441  std::vector< KinematicCut > tmp_Selection = Selection;
1442  std::vector< KinematicCut > SelectionVecToApply;
1443 
1444  //DB Add all the predefined selections to the selection vector which will be applied
1445  for (size_t iSelec=0;iSelec<Selection.size();iSelec++) {
1446  SelectionVecToApply.emplace_back(Selection[iSelec]);
1447  }
1448 
1449  //DB Add all requested cuts from the argument to the selection vector which will be applied
1450  for (size_t iSelec=0;iSelec<EventSelectionVec.size();iSelec++) {
1451  SelectionVecToApply.emplace_back(EventSelectionVec[iSelec]);
1452  }
1453 
1454  //DB Set the member variable to be the cuts to apply
1455  Selection = SelectionVecToApply;
1456 
1457  //DB Define the histogram which will be returned
1458  TH1D* _h1DVar;
1459  if (Axis) {
1460  _h1DVar = new TH1D("","",Axis->GetNbins(),Axis->GetXbins()->GetArray());
1461  } else {
1462  std::vector<double> xBinEdges = ReturnKinematicParameterBinning(ProjectionVar_Str);
1463  _h1DVar = new TH1D("", "", int(xBinEdges.size())-1, xBinEdges.data());
1464  }
1465  _h1DVar->GetXaxis()->SetTitle(ProjectionVar_Str.c_str());
1466 
1467  if (IsSubEventVarString(ProjectionVar_Str)) {
1468  Fill1DSubEventHist(_h1DVar, ProjectionVar_Str, SubEventSelectionVec, WeightStyle);
1469  } else {
1470  //DB Grab the associated enum with the argument string
1471  int ProjectionVar_Int = ReturnKinematicParameterFromString(ProjectionVar_Str);
1472 
1473  //DB Loop over all events
1474  for (unsigned int iEvent = 0; iEvent < GetNEvents(); iEvent++) {
1475  if (IsEventSelected(iEvent)) {
1476  double Weight = GetEventWeight(iEvent);
1477  if (WeightStyle == 1) {
1478  Weight = 1.;
1479  }
1480  double Var = ReturnKinematicParameter(ProjectionVar_Int,iEvent);
1481  _h1DVar->Fill(Var,Weight);
1482  }
1483  }
1484  }
1485  //DB Reset the saved selection
1486  Selection = tmp_Selection;
1487 
1488  return _h1DVar;
1489 }
std::vector< double > ReturnKinematicParameterBinning(const std::string &KinematicParameter)
Return the binning used to draw a kinematic parameter.
std::vector< KinematicCut > Selection
a way to store selection cuts which you may push back in the get1DVar functions most of the time this...
virtual double ReturnKinematicParameter(std::string KinematicParamter, int iEvent)=0
Return the value of an associated kinematic parameter for an event.
bool IsSubEventVarString(const std::string &VarStr)
JM Check if a kinematic parameter string corresponds to a subevent-level variable.
void Fill1DSubEventHist(TH1D *_h1DVar, const std::string &ProjectionVar, const std::vector< KinematicCut > &SubEventSelectionVec=std::vector< KinematicCut >(), int WeightStyle=0)
int ReturnKinematicParameterFromString(const std::string &KinematicStr) const
ETA function to generically convert a string from xsec cov to a kinematic type.

◆ Get1DVarHistByModeAndChannel()

TH1 * SampleHandlerFD::Get1DVarHistByModeAndChannel ( const std::string &  ProjectionVar_Str,
int  kModeToFill = -1,
int  kChannelToFill = -1,
int  WeightStyle = 0,
TAxis *  Axis = nullptr 
)

Definition at line 1728 of file SampleHandlerFD.cpp.

1729  {
1730  bool fChannel;
1731  bool fMode;
1732 
1733  if (kChannelToFill != -1) {
1734  if (kChannelToFill > GetNOscChannels()) {
1735  MACH3LOG_ERROR("Required channel is not available. kChannelToFill should be between 0 and {}", GetNOscChannels());
1736  MACH3LOG_ERROR("kChannelToFill given:{}", kChannelToFill);
1737  MACH3LOG_ERROR("Exiting.");
1738  throw MaCh3Exception(__FILE__, __LINE__);
1739  }
1740  fChannel = true;
1741  } else {
1742  fChannel = false;
1743  }
1744 
1745  if (kModeToFill!=-1) {
1746  if (!(kModeToFill >= 0) && (kModeToFill < Modes->GetNModes())) {
1747  MACH3LOG_ERROR("Required mode is not available. kModeToFill should be between 0 and {}", Modes->GetNModes());
1748  MACH3LOG_ERROR("kModeToFill given:{}", kModeToFill);
1749  MACH3LOG_ERROR("Exiting..");
1750  throw MaCh3Exception(__FILE__, __LINE__);
1751  }
1752  fMode = true;
1753  } else {
1754  fMode = false;
1755  }
1756 
1757  std::vector< KinematicCut > SelectionVec;
1758 
1759  if (fMode) {
1760  KinematicCut SelecMode;
1762  SelecMode.LowerBound = kModeToFill;
1763  SelecMode.UpperBound = kModeToFill+1;
1764  SelectionVec.push_back(SelecMode);
1765  }
1766 
1767  if (fChannel) {
1768  KinematicCut SelecChannel;
1769  SelecChannel.ParamToCutOnIt = ReturnKinematicParameterFromString("OscillationChannel");
1770  SelecChannel.LowerBound = kChannelToFill;
1771  SelecChannel.UpperBound = kChannelToFill+1;
1772  SelectionVec.push_back(SelecChannel);
1773  }
1774 
1775  return Get1DVarHist(ProjectionVar_Str,SelectionVec,WeightStyle,Axis);
1776 }
#define MACH3LOG_ERROR
Definition: MaCh3Logger.h:27
Custom exception class for MaCh3 errors.
std::unique_ptr< MaCh3Modes > Modes
Holds information about used Generator and MaCh3 modes.
TH1 * Get1DVarHist(const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec=std::vector< KinematicCut >(), int WeightStyle=0, TAxis *Axis=nullptr, const std::vector< KinematicCut > &SubEventSelectionVec=std::vector< KinematicCut >())
int GetNOscChannels() override
KS: Small struct used for applying kinematic cuts.
double UpperBound
Upper bound on which we apply cut.
double LowerBound
Lower bound on which we apply cut.
int ParamToCutOnIt
Index or enum value identifying the kinematic variable to cut on.

◆ Get2DVarHistByModeAndChannel()

TH2 * SampleHandlerFD::Get2DVarHistByModeAndChannel ( const std::string &  ProjectionVar_StrX,
const std::string &  ProjectionVar_StrY,
int  kModeToFill = -1,
int  kChannelToFill = -1,
int  WeightStyle = 0,
TAxis *  AxisX = nullptr,
TAxis *  AxisY = nullptr 
)

Definition at line 1778 of file SampleHandlerFD.cpp.

1779  {
1780  bool fChannel;
1781  bool fMode;
1782 
1783  if (kChannelToFill!=-1) {
1784  if (kChannelToFill > GetNOscChannels()) {
1785  MACH3LOG_ERROR("Required channel is not available. kChannelToFill should be between 0 and {}", GetNOscChannels());
1786  MACH3LOG_ERROR("kChannelToFill given:{}", kChannelToFill);
1787  MACH3LOG_ERROR("Exiting.");
1788  throw MaCh3Exception(__FILE__, __LINE__);
1789  }
1790  fChannel = true;
1791  } else {
1792  fChannel = false;
1793  }
1794 
1795  if (kModeToFill!=-1) {
1796  if (!(kModeToFill >= 0) && (kModeToFill < Modes->GetNModes())) {
1797  MACH3LOG_ERROR("Required mode is not available. kModeToFill should be between 0 and {}", Modes->GetNModes());
1798  MACH3LOG_ERROR("kModeToFill given:{}", kModeToFill);
1799  MACH3LOG_ERROR("Exiting..");
1800  throw MaCh3Exception(__FILE__, __LINE__);
1801  }
1802  fMode = true;
1803  } else {
1804  fMode = false;
1805  }
1806 
1807  std::vector< KinematicCut > SelectionVec;
1808 
1809  if (fMode) {
1810  KinematicCut SelecMode;
1812  SelecMode.LowerBound = kModeToFill;
1813  SelecMode.UpperBound = kModeToFill+1;
1814  SelectionVec.push_back(SelecMode);
1815  }
1816 
1817  if (fChannel) {
1818  KinematicCut SelecChannel;
1819  SelecChannel.ParamToCutOnIt = ReturnKinematicParameterFromString("OscillationChannel");
1820  SelecChannel.LowerBound = kChannelToFill;
1821  SelecChannel.UpperBound = kChannelToFill+1;
1822  SelectionVec.push_back(SelecChannel);
1823  }
1824 
1825  return Get2DVarHist(ProjectionVar_StrX,ProjectionVar_StrY,SelectionVec,WeightStyle,AxisX,AxisY);
1826 }
TH2 * Get2DVarHist(const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec=std::vector< KinematicCut >(), int WeightStyle=0, TAxis *AxisX=nullptr, TAxis *AxisY=nullptr, const std::vector< KinematicCut > &SubEventSelectionVec=std::vector< KinematicCut >())

◆ GetDataHist()

TH1 * SampleHandlerFD::GetDataHist ( const int  Dimension)

Get Data histogram.

Definition at line 1049 of file SampleHandlerFD.cpp.

1049  {
1050 // ************************************************
1051  if(Dimension == 1) {
1052  return SampleDetails.dathist;
1053  } else if(Dimension == 2) {
1054  return SampleDetails.dathist2d;
1055  } else{
1056  MACH3LOG_ERROR("Asdking for {} with N Dimension = {}. This is not implemented", __func__, Dimension);
1057  throw MaCh3Exception(__FILE__, __LINE__);
1058  }
1059 }
SampleInfo SampleDetails
Stores info about currently initialised sample.
TH2D * dathist2d
histogram used for plotting storing 2D data distribution
TH1D * dathist
histogram used for plotting storing 1D data distribution

◆ GetFlavourName()

std::string SampleHandlerFD::GetFlavourName ( const int  iChannel)
inline

Definition at line 83 of file SampleHandlerFD.h.

83  {
84  if (iChannel < 0 || iChannel > GetNOscChannels()) {
85  MACH3LOG_ERROR("Invalid Channel Requested: {}", iChannel);
86  throw MaCh3Exception(__FILE__ , __LINE__);
87  }
88  return OscChannels[iChannel].flavourName;
89  }
std::vector< OscChannelInfo > OscChannels
Stores info about oscillation channel for a single sample.

◆ GetLikelihood()

virtual double SampleHandlerBase::GetLikelihood ( )
pure virtual

Implemented in SampleHandlerFD, and PySampleHandlerBase.

◆ GetMaCh3Modes()

MaCh3Modes* SampleHandlerBase::GetMaCh3Modes ( ) const
inline

Return pointer to MaCh3 modes.

Definition at line 53 of file SampleHandlerBase.h.

53 { return Modes.get(); }

◆ GetMCHist()

TH1 * SampleHandlerFD::GetMCHist ( const int  Dimension)

Get MC histogram.

Definition at line 1034 of file SampleHandlerFD.cpp.

1034  {
1035 // ************************************************
1036  FillMCHist(Dimension);
1037 
1038  if(Dimension == 1) {
1039  return SampleDetails._hPDF1D;
1040  } else if(Dimension == 2) {
1041  return SampleDetails._hPDF2D;
1042  } else{
1043  MACH3LOG_ERROR("Asking for {} with N Dimension = {}. This is not implemented", __func__, Dimension);
1044  throw MaCh3Exception(__FILE__, __LINE__);
1045  }
1046 }
void FillMCHist(const int Dimension)
Fill a histogram with the event-level information used in the fit.
TH1D * _hPDF1D
histogram used for plotting storing 1D MC distribution
TH2D * _hPDF2D
histogram used for plotting storing 2D MC distribution

◆ GetModeHist1D()

TH1* SampleHandlerFD::GetModeHist1D ( int  s,
int  m,
int  style = 0 
)
inline

Definition at line 111 of file SampleHandlerFD.h.

111  {
112  return Get1DVarHistByModeAndChannel(GetXBinVarName(),m,s,style);
113  }
std::string GetXBinVarName() const
TH1 * Get1DVarHistByModeAndChannel(const std::string &ProjectionVar_Str, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *Axis=nullptr)

◆ GetModeHist2D()

TH2* SampleHandlerFD::GetModeHist2D ( int  s,
int  m,
int  style = 0 
)
inline

Definition at line 115 of file SampleHandlerFD.h.

115  {
117  }
std::string GetYBinVarName() const
TH2 * Get2DVarHistByModeAndChannel(const std::string &ProjectionVar_StrX, const std::string &ProjectionVar_StrY, int kModeToFill=-1, int kChannelToFill=-1, int WeightStyle=0, TAxis *AxisX=nullptr, TAxis *AxisY=nullptr)

◆ GetNDim()

int SampleHandlerFD::GetNDim ( ) const
inline

DB Function to differentiate 1D or 2D binning.

Definition at line 31 of file SampleHandlerFD.h.

31 { return SampleDetails.nDimensions; }
int nDimensions
Keep track of the dimensions of the sample binning.

◆ GetNEvents()

unsigned int SampleHandlerBase::GetNEvents ( ) const
inline

Definition at line 60 of file SampleHandlerBase.h.

60 {return nEvents;}
unsigned int nEvents
Number of MC events are there.

◆ GetNOscChannels() [1/2]

virtual int SampleHandlerBase::GetNOscChannels ( )
inlinevirtual

Reimplemented in SampleHandlerFD.

Definition at line 62 of file SampleHandlerBase.h.

62 { return 1; }

◆ GetNOscChannels() [2/2]

int SampleHandlerFD::GetNOscChannels ( )
inlineoverridevirtual

Reimplemented from SampleHandlerBase.

Definition at line 80 of file SampleHandlerFD.h.

80 {return static_cast<int>(OscChannels.size());}

◆ GetNsamples()

virtual M3::int_t SampleHandlerBase::GetNsamples ( )
inlinevirtual

Definition at line 40 of file SampleHandlerBase.h.

40 { return nSamples; };
M3::int_t nSamples
Contains how many samples we've got.

◆ GetPoissonLLH()

double SampleHandlerBase::GetPoissonLLH ( const double  data,
const double  mc 
) const

Calculate test statistic for a single bin using Poisson.

Parameters
datais data
mcis mc

Definition at line 18 of file SampleHandlerBase.cpp.

18  {
19 // ***************************************************************************
20  // Return MC if there are no data, returns 0 for data == 0 && mc == 0
21  if ( data == 0 ) return mc;
22 
23  // If there are some data, but the prediction falls below the MC bound => return Poisson LogL for the low MC bound
24  if ( mc < M3::_LOW_MC_BOUND_ ) {
25  if ( data > M3::_LOW_MC_BOUND_ ) return ( M3::_LOW_MC_BOUND_ - data + data * std::log( data/M3::_LOW_MC_BOUND_ ) );
26  else if ( data >= mc ) return 0.;
27  }
28 
29  // Otherwise, just return usual Poisson LogL using Stirling's approximation
30  // http://hyperphysics.phy-astr.gsu.edu/hbase/math/stirling.html
31  return ( mc - data + data * std::log( data / mc ) );
32 }
constexpr static const double _LOW_MC_BOUND_
MC prediction lower bound in bin to identify problematic binning definitions and handle LogL calculat...
Definition: Core.h:76

◆ GetSampleLikelihood()

virtual double SampleHandlerBase::GetSampleLikelihood ( const int  isample)
inlinevirtual

Definition at line 46 of file SampleHandlerBase.h.

46 {(void) isample; return GetLikelihood();};
virtual double GetLikelihood()=0

◆ GetSampleName() [1/2]

std::string SampleHandlerFD::GetSampleName ( int  iSample = 0) const
overridevirtual

Implements SampleHandlerBase.

Definition at line 1273 of file SampleHandlerFD.cpp.

1273  {
1274  //ETA - this is just to suppress a warning for an unused variable
1275  (void)iSample;
1276 
1277  //ETA - extra safety to make sure SampleName is actually set
1278  // probably unnecessary due to the requirement for it to be in the yaml config
1279  if(SampleName.length() == 0){
1280  MACH3LOG_ERROR("No sample name provided");
1281  MACH3LOG_ERROR("Please provide a SampleName in your configuration file: {}", SampleManager->GetFileName());
1282  throw MaCh3Exception(__FILE__, __LINE__);
1283  }
1284  return SampleName;
1285 }
std::unique_ptr< manager > SampleManager
The manager object used to read the sample yaml file.
std::string SampleName
A unique ID for each sample based on which we can define what systematic should be applied.

◆ GetSampleName() [2/2]

virtual std::string SampleHandlerBase::GetSampleName ( int  Sample) const
pure virtual

Implemented in SampleHandlerFD, and PySampleHandlerBase.

◆ GetTestStatLLH()

double SampleHandlerBase::GetTestStatLLH ( const double  data,
const double  mc,
const double  w2 
) const

Calculate test statistic for a single bin. Calculation depends on setting of fTestStatistic. Data and mc -> 0 cut-offs are defined in M3::LOW_MC_BOUND.

Poisson

Standard Poisson log-likelihood (Stirling approximation) [2]

\[ - \log \mathcal{L}_\mathrm{Poisson} = \sum_i N_i^\mathrm{MC} - N_i^\mathrm{data} + N_i^\mathrm{data} \ln \frac{N_i^\mathrm{data}}{N_i^\mathrm{MC}}, \]

Pearson

Standard Pearson likelihood [24] (assumes Gaussian approximation of bin counts):

\[ - \log \mathcal{L}_\mathrm{Pearson} = \sum_i \frac{(N_i^\mathrm{data} - N_i^\mathrm{MC})^2}{2 \, N_i^\mathrm{MC}} \]

Barlow-Beeston

Based on [3] and following Conway approximation ([5]) The generation of MC is a stochastic process, so even identical settings can lead to different outputs (assuming that the seeds of the random number generator are different). This introduces uncertainty in MC distributions, especially in bins with low statistics.

\[ - \log \mathcal{L}_\mathrm{BB} = - \log \mathcal{L}_\mathrm{Poisson} - \log \mathcal{L}_\mathrm{MC_{stat}} = \sum_i \Biggl[ N_i^\mathrm{MC}(\vec{\theta}) - N_i^\mathrm{data} + N_i^\mathrm{data} \ln \frac{N_i^\mathrm{data}}{N_i^\mathrm{MC}(\vec{\theta})} + \frac{(\beta_i - 1)^2}{2 \sigma_{\beta_i}^2} \Biggr], \]

where \(\beta_i\) is a scaling parameter between ideal ("true") and generated MC in a bin ( \(N^\mathrm{true}_{\mathrm{MC},i} = \beta_i N_i^\mathrm{MC}\)), and \(\sigma^2_{\beta_i} = \frac{\sum_i w_i^2}{N_i^\mathrm{MC}}\), with \(\sum_i w_i^2\) being the sum of the squares of weights in bin \(i\). Assuming \(\beta_i\) follows a Gaussian, its mean can be found by solving the quadratic equation derived by Conway:

\[ \beta_i^2 + (N_i^\mathrm{MC} \sigma_{\beta_i}^2 - 1)\beta_i - N_i^\mathrm{data} \sigma_{\beta_i}^2 = 0 \]

Dembinski-Abdelmotteleb

Alternative treatment of MC statistical uncertainty following Hans Dembinski and Ahmed Abdelmotteleb [6]

This approach extends the Barlow-Beeston method. For each bin:

\[ - \log \mathcal{L}_\mathrm{DA} = (N_i^{\mathrm{MC},\prime} - N_i^\mathrm{data} + N_i^\mathrm{data} \ln \frac{N_i^\mathrm{data}}{N_i^{\mathrm{MC},\prime}}) + k \beta - k + k \ln \frac{k}{k \beta} \]

where

\[ k = \frac{(N_i^\mathrm{MC})^2}{\sum_i w_i^2} \]

and

\[ \beta = \frac{N_i^\mathrm{data} + k}{N_i^\mathrm{MC} + k}, \quad N_i^{\mathrm{MC},\prime} = N_i^\mathrm{MC} \cdot \beta \]

IceCube

Alternative likelihood definition described by the IceCube collaboration [1]

\[ - \log \mathcal{L} = - \sum_i \Biggl( a_i \log(b_i) + \log[\Gamma(N_i^{\mathrm{data}}+a_i)] - (N_i^{\mathrm{data}}+a_i)\log(b_i+1) - \log[\Gamma(a_i)] \Biggr), \]

where the auxiliary variables are

\[ a_i = N^{\mathrm{gen}}_{\mathrm{MC},i} \, b_i + 1, \quad b_i = \frac{N^{\mathrm{gen}}_{\mathrm{MC},i}}{\sum_i w_i^2}. \]

Treatment of low data/mc

Implemented fTestStatistic are kPoisson (with Stirling's approx.), kBarlowBeeston (arXiv:1103.0354), kDembinskiAbdelmotteleb (arXiv:2206.12346), kIceCube (arxiv:1901.04645), and kPearson. Test statistics require mc > 0, therefore low mc and data values are treated with cut-offs based on M3::LOW_MC_BOUND = .00001 by default. For kPoisson, kBarlowBeeston, kDembinskiAbdelmotteleb, kPearson: data > LOW_MC_BOUND & mc <= LOW_MC_BOUND: returns GetTestStatLLH(data, LOW_MC_BOUND, w2), with Poisson(data,LOW_MC_BOUND) limit for mc->0, w2->0. mc < data <= LOW_MC_BOUND: returns 0 (as if any data <= LOW_MC_BOUND were effectively consistent with 0 data count), with a limit of 0 for mc->0. data = 0: returns mc (or mc/2. for kPearson), with a limit of 0 for mc->0. For kIceCube: mc < data returns the lower of IceCube(data,mc,w2) and Poisson(data,mc) penalties, with a Poisson(data,LOW_MC_BOUND) limit for mc->0, w2->0.

Parameters
datais data
mcis mc
w2is \(\sum_{i} w_{i}^2\) (sum of weights squared), which is \(\sigma^2_{\text{MC stats}}\)

Definition at line 36 of file SampleHandlerBase.cpp.

36  {
37 // *************************
38  switch (fTestStatistic)
39  {
40  //CW: Not full Barlow-Beeston or what is referred to as "light": we're not introducing any more parameters
41  // Assume the MC has a Gaussian distribution around generated
42  // As in https://arxiv.org/abs/1103.0354 eq 10, 11
43  //CW: Calculate the Barlow-Beeston likelihood contribution from MC statistics
44  // Assumes the beta scaling parameters are Gaussian distributed
45  // Follows arXiv:1103.0354 section 5 and equation 8, 9, 10, 11 on page 4/5
46  // Essentially solves equation 11
47  case (kBarlowBeeston):
48  {
49  // The MC used in the likelihood calculation is allowed to be changed by Barlow Beeston beta parameters
50  double newmc = mc;
51 
52  // If MC falls below the low MC bound, use low MC bound for newmc
53  if ( mc < M3::_LOW_MC_BOUND_ ) {
54  if ( data > M3::_LOW_MC_BOUND_ ) newmc = M3::_LOW_MC_BOUND_;
55  else if ( data >= mc ) return 0.;
56  }
57 
58  // Barlow-Beeston uses fractional uncertainty on MC, so sqrt(sum[w^2])/mc
59  const double fractional = std::sqrt( w2 ) / newmc;
60  // fractional^2 to avoid doing same operation several times
61  const double fractional2 = fractional * fractional;
62  // b in quadratic equation
63  const double temp = newmc * fractional2 - 1;
64  // b^2 - 4ac in quadratic equation
65  const double temp2 = temp * temp + 4 * data * fractional2;
66  if ( temp2 < 0 ) {
67  MACH3LOG_ERROR("Negative square root in Barlow Beeston coefficient calculation!");
68  throw MaCh3Exception(__FILE__ , __LINE__ );
69  }
70  // Solve for the positive beta
71  const double beta = ( -1 * temp + sqrt( temp2 ) ) / 2.;
72 
73  // If there is no data, test-stat shall return only MC*beta
74  double stat = mc * beta;
75  // With data, test-stat shall return LogL for newMC*beta which includes the low MC bound
76  if ( data > 0 ) {
77  newmc *= beta;
78  stat = newmc - data + data * std::log( data / newmc );
79  }
80 
81  // Now, MC stat penalty
82  // The penalty from MC statistics using Conways approach (https://cds.cern.ch/record/1333496?)
83  double penalty = 0;
84  if ( fractional > 0 ) penalty = ( beta - 1 ) * ( beta - 1 ) / ( 2 * fractional2 );
85 
86  // Returns test-stat plus the MC stat penalty
87  return stat+penalty;
88  }
89  break;
90  //KS: Alternative calculation of Barlow-Beeston following Hans Dembinski and Ahmed Abdelmottele arXiv:2206.12346v2
92  {
93  //KS: code follows authors implementation from:
94  //https://github.com/scikit-hep/iminuit/blob/059d06b00cae097ebf340b218b4eb57357111df8/src/iminuit/cost.py#L274-L300
95 
96  // If there is no MC stat error for any reason, return Poisson LogL
97  if ( w2 == 0 ) return GetPoissonLLH(data,mc);
98 
99  // The MC can be changed
100  double newmc = mc;
101 
102  // If MC falls below the low MC bound, use low MC bound for newmc
103  if ( mc < M3::_LOW_MC_BOUND_ ) {
104  if ( data > M3::_LOW_MC_BOUND_ ) newmc = M3::_LOW_MC_BOUND_;
105  else if ( data >= mc ) return 0.;
106  }
107 
108  //the so-called effective count
109  const double k = newmc * newmc / w2;
110  //Calculate beta which is scaling factor between true and generated MC
111  const double beta = ( data + k ) / ( newmc + k );
112 
113  newmc *= beta;
114 
115  // And penalise the movement in beta relative the mc uncertainty
116  const double penalty = k * beta - k + k * std::log( k / ( k * beta ) );
117 
118  // If there are no data, this shall return newmc
119  double stat = newmc;
120  // All likelihood calculations may use the bare Poisson likelihood, so calculate here
121  // Only if there are some data
122  if ( data > 0 ) stat = newmc - data + data * std::log( data / newmc );
123 
124  // Return the statistical contribution and penalty
125  return stat+penalty;
126  }
127  break;
128  //CW: Also try the IceCube likelihood
129  // It does not modify the MC content
130  // https://arxiv.org/abs/1901.04645
131  // Argüelles, C.A., Schneider, A. & Yuan, T. J. High Energ. Phys. (2019) 2019: 30. https://doi.org/10.1007/JHEP06(2019)030
132  // We essentially construct eq 3.16 and take the logarithm
133  // in eq 3.16, mu is MC, sigma2 is w2, k is data
134  case (kIceCube):
135  {
136  // IceCube low MC bound is implemented to return Poisson(data, _LOW_MC_BOUND_)
137  // up until the IceCube(data, mc) test-statistic is less than Poisson(data, _LOW_MC_BOUND_)
138  // The 0 MC limit is set to Poisson(data, 0.) as there is no way to get a non-diverging and reasonable guess on w2
139 
140  // If there is 0 MC uncertainty (technically also when MC is 0) => Return Poisson(data, mc)
141  if ( w2 == 0 ) return GetPoissonLLH(data,mc);
142 
143  // Auxiliary variables
144  const long double b = mc / w2;
145  const long double a = mc * b + 1;
146 
147  // Use C99's implementation of log of gamma function to not be C++11 dependent
148  const double stat = double( -1 * ( a * logl( b ) + lgammal( data + a ) - lgammal( data + 1 ) - ( ( data + a ) * log1pl( b ) ) - lgammal( a ) ) );
149 
150  // Check whether the stat is more than Poisson-like bound for low mc (mc < data)
151  // TN: I believe this might get some extra optimization
152  if ( mc <= data ) {
153  if ( data <= M3::_LOW_MC_BOUND_ ) return 0.;
154  const double poisson = GetPoissonLLH(data, M3::_LOW_MC_BOUND_);
155  if ( stat > poisson ) return poisson;
156  }
157 
158  // Otherwise, return IceCube test-stat
159  return stat;
160  }
161  break;
162  //KS: Pearson works on assumption that event distribution in each bin is described by a Gaussian which in our case is not fulfilled for all bins, hence use it at your own risk
163  case (kPearson):
164  {
165  //KS: 2 is because this function returns -LLH not -2LLH
166  // With no data return the MC/2.
167  if ( data == 0 ) return mc/2.;
168 
169  // If MC is lower than the low MC bound, return the test-stat at the bound
170  if ( mc < M3::_LOW_MC_BOUND_ ) {
171  if ( data > M3::_LOW_MC_BOUND_ ) return ( data - M3::_LOW_MC_BOUND_ ) * ( data - M3::_LOW_MC_BOUND_ ) / ( 2. * M3::_LOW_MC_BOUND_ );
172  else if ( data >= mc ) return 0.;
173  }
174 
175  // Return the Pearson metric
176  return ( data - mc ) * ( data - mc ) / ( 2 * mc );
177  }
178  break;
179  case (kPoisson):
180  {
181  //Just call GetPoissonLLH which doesn't take in weights
182  //and is a Poisson likelihood comparison.
183  return GetPoissonLLH(data, mc);
184  }
185  break;
187  MACH3LOG_ERROR("kNTestStatistics is not a valid TestStatistic!");
188  throw MaCh3Exception(__FILE__, __LINE__);
189  default:
190  MACH3LOG_ERROR("Couldn't find TestStatistic {} exiting!", static_cast<int>(fTestStatistic));
191  throw MaCh3Exception(__FILE__ , __LINE__ );
192  } // end switch
193 }
@ kNTestStatistics
Number of test statistics.
@ kPearson
Standard Pearson likelihood .
@ kBarlowBeeston
Barlow-Beeston () following Conway approximation ()
@ kIceCube
Based on .
@ kDembinskiAbdelmotteleb
Based on .
@ kPoisson
Standard Poisson likelihood .
TestStatistic fTestStatistic
Test statistic tells what kind of likelihood sample is using.
double GetPoissonLLH(const double data, const double mc) const
Calculate test statistic for a single bin using Poisson.

◆ GetTitle() [1/2]

virtual std::string SampleHandlerBase::GetTitle ( ) const
inlinevirtual

Reimplemented in SampleHandlerFD.

Definition at line 42 of file SampleHandlerBase.h.

42 {return "SampleHandler";};

◆ GetTitle() [2/2]

std::string SampleHandlerFD::GetTitle ( ) const
inlineoverridevirtual

Reimplemented from SampleHandlerBase.

Definition at line 35 of file SampleHandlerFD.h.

35 {return SampleDetails.SampleTitle;}
std::string SampleTitle
the name of this sample e.g."muon-like"

◆ GetW2Hist()

TH1 * SampleHandlerFD::GetW2Hist ( const int  Dimension)

Get W2 histogram.

Definition at line 996 of file SampleHandlerFD.cpp.

996  {
997 // ************************************************
998  if(Dimension == 1) {
999  TH1D* W2Hist = dynamic_cast<TH1D*>(SampleDetails._hPDF1D->Clone((SampleDetails._hPDF1D->GetName() + std::string("_W2")).c_str()));
1000  if (!W2Hist) {
1001  MACH3LOG_ERROR("Failed to cast");
1002  throw MaCh3Exception(__FILE__, __LINE__);
1003  }
1004  W2Hist->Reset();
1005  for (size_t yBin = 0; yBin < Binning.nYBins; ++yBin) {
1006  for (size_t xBin = 0; xBin < Binning.nXBins; ++xBin) {
1007  const int idx = Binning.GetBinSafe(xBin, yBin);
1008  W2Hist->AddBinContent(idx + 1, SampleHandlerFD_array_w2[idx]);
1009  }
1010  }
1011  return W2Hist;
1012  } else if(Dimension == 2) {
1013  TH2D* W2Hist = dynamic_cast<TH2D*>(SampleDetails._hPDF2D->Clone((SampleDetails._hPDF2D->GetName() + std::string("_W2")).c_str()));
1014  if (!W2Hist) {
1015  MACH3LOG_ERROR("Failed to cast");
1016  throw MaCh3Exception(__FILE__, __LINE__);
1017  }
1018  W2Hist->Reset();
1019  for (size_t yBin = 0; yBin < Binning.nYBins; ++yBin) {
1020  for (size_t xBin = 0; xBin < Binning.nXBins; ++xBin) {
1021  const int idx = Binning.GetBinSafe(xBin, yBin);
1022  W2Hist->SetBinContent(static_cast<int>(xBin + 1), static_cast<int>(yBin + 1), SampleHandlerFD_array_w2[idx]);
1023  }
1024  }
1025  return W2Hist;
1026  } else{
1027  MACH3LOG_ERROR("Asking for {} with N Dimension = {}. This is not implemented", __func__, Dimension);
1028  throw MaCh3Exception(__FILE__, __LINE__);
1029  }
1030 }
SampleBinningInfo Binning
KS: This stores binning information, in future could be come vector to store binning for every used s...
double * SampleHandlerFD_array_w2
KS Array used for MC stat.
size_t nXBins
Number of X axis bins in the histogram used for likelihood calculation.
size_t nYBins
Number of Y axis bins in the histogram used for likelihood calculation.
int GetBinSafe(const int xBin, const int yBin) const
Get linear bin index from 2D bin indices with additional checks.

◆ GetXBinVarName()

std::string SampleHandlerFD::GetXBinVarName ( ) const
inline

Definition at line 38 of file SampleHandlerFD.h.

38 {return SampleDetails.XVarStr;}
std::string XVarStr
the strings associated with the variables used for the X binning e.g. "RecoNeutrinoEnergy"

◆ GetYBinVarName()

std::string SampleHandlerFD::GetYBinVarName ( ) const
inline

Definition at line 40 of file SampleHandlerFD.h.

40 {return SampleDetails.YVarStr;}
std::string YVarStr
the strings associated with the variables used for the Y binning e.g. "RecoNeutrinoEnergy"

◆ ReturnHistsBySelection1D()

std::vector< TH1 * > SampleHandlerFD::ReturnHistsBySelection1D ( std::string  KinematicProjection,
int  Selection1,
int  Selection2 = -1,
int  WeightStyle = 0,
TAxis *  Axis = 0 
)

Definition at line 1970 of file SampleHandlerFD.cpp.

1970  {
1971  std::vector<TH1*> hHistList;
1972  std::string legendEntry;
1973 
1974  if (THStackLeg != nullptr) {delete THStackLeg;}
1975  THStackLeg = new TLegend(0.1,0.1,0.9,0.9);
1976 
1977  int iMax = -1;
1978  if (Selection1 == FDPlotType::kModePlot) {
1979  iMax = Modes->GetNModes();
1980  }
1981  if (Selection1 == FDPlotType::kOscChannelPlot) {
1982  iMax = GetNOscChannels();
1983  }
1984  if (iMax == -1) {
1985  MACH3LOG_ERROR("You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
1986  throw MaCh3Exception(__FILE__, __LINE__);
1987  }
1988 
1989  for (int i=0;i<iMax;i++) {
1990  if (Selection1 == FDPlotType::kModePlot) {
1991  hHistList.push_back(Get1DVarHistByModeAndChannel(KinematicProjection,i,Selection2,WeightStyle,XAxis));
1992  THStackLeg->AddEntry(hHistList[i],(Modes->GetMaCh3ModeName(i)+Form(" : (%4.2f)",hHistList[i]->Integral())).c_str(),"f");
1993 
1994  hHistList[i]->SetFillColor(static_cast<Color_t>(Modes->GetMaCh3ModePlotColor(i)));
1995  hHistList[i]->SetLineColor(static_cast<Color_t>(Modes->GetMaCh3ModePlotColor(i)));
1996  }
1997  if (Selection1 == FDPlotType::kOscChannelPlot) {
1998  hHistList.push_back(Get1DVarHistByModeAndChannel(KinematicProjection,Selection2,i,WeightStyle,XAxis));
1999  THStackLeg->AddEntry(hHistList[i],(GetFlavourName(i)+Form(" | %4.2f",hHistList[i]->Integral())).c_str(),"f");
2000  }
2001  }
2002 
2003  return hHistList;
2004 }
TLegend * THStackLeg
DB Miscellaneous Variables.
std::string GetFlavourName(const int iChannel)

◆ ReturnHistsBySelection2D()

std::vector< TH2 * > SampleHandlerFD::ReturnHistsBySelection2D ( std::string  KinematicProjectionX,
std::string  KinematicProjectionY,
int  Selection1,
int  Selection2 = -1,
int  WeightStyle = 0,
TAxis *  XAxis = 0,
TAxis *  YAxis = 0 
)

Definition at line 2006 of file SampleHandlerFD.cpp.

2008  {
2009 // ************************************************
2010  std::vector<TH2*> hHistList;
2011 
2012  int iMax = -1;
2013  if (Selection1 == FDPlotType::kModePlot) {
2014  iMax = Modes->GetNModes();
2015  }
2016  if (Selection1 == FDPlotType::kOscChannelPlot) {
2017  iMax = GetNOscChannels();
2018  }
2019  if (iMax == -1) {
2020  MACH3LOG_ERROR("You've passed me a Selection1 which was not implemented in ReturnHistsBySelection1D. Selection1 and Selection2 are counters for different indexable quantities");
2021  throw MaCh3Exception(__FILE__, __LINE__);
2022  }
2023 
2024  for (int i=0;i<iMax;i++) {
2025  if (Selection1 == FDPlotType::kModePlot) {
2026  hHistList.push_back(Get2DVarHistByModeAndChannel(KinematicProjectionX,KinematicProjectionY,i,Selection2,WeightStyle,XAxis,YAxis));
2027  }
2028  if (Selection1 == FDPlotType::kOscChannelPlot) {
2029  hHistList.push_back(Get2DVarHistByModeAndChannel(KinematicProjectionX,KinematicProjectionY,Selection2,i,WeightStyle,XAxis,YAxis));
2030  }
2031  }
2032 
2033  return hHistList;
2034 }

◆ ReturnKinematicParameterFromString()

int SampleHandlerFD::ReturnKinematicParameterFromString ( const std::string &  KinematicStr) const

ETA function to generically convert a string from xsec cov to a kinematic type.

Definition at line 1627 of file SampleHandlerFD.cpp.

1627  {
1628 // ************************************************
1629  auto it = KinematicParameters->find(KinematicParameterStr);
1630  if (it != KinematicParameters->end()) return it->second;
1631 
1632  MACH3LOG_ERROR("Did not recognise Kinematic Parameter type: {}", KinematicParameterStr);
1633  throw MaCh3Exception(__FILE__, __LINE__);
1634 
1635  return M3::_BAD_INT_;
1636 }
const std::unordered_map< std::string, int > * KinematicParameters
Mapping between string and kinematic enum.
constexpr static const int _BAD_INT_
Default value used for int initialisation.
Definition: Core.h:48

◆ ReturnStackedHistBySelection1D()

THStack * SampleHandlerFD::ReturnStackedHistBySelection1D ( std::string  KinematicProjection,
int  Selection1,
int  Selection2 = -1,
int  WeightStyle = 0,
TAxis *  Axis = 0 
)

Definition at line 2036 of file SampleHandlerFD.cpp.

2036  {
2037  std::vector<TH1*> HistList = ReturnHistsBySelection1D(KinematicProjection, Selection1, Selection2, WeightStyle, XAxis);
2038  THStack* StackHist = new THStack((GetTitle()+"_"+KinematicProjection+"_Stack").c_str(),"");
2039  for (unsigned int i=0;i<HistList.size();i++) {
2040  StackHist->Add(HistList[i]);
2041  }
2042  return StackHist;
2043 }
std::string GetTitle() const override
std::vector< TH1 * > ReturnHistsBySelection1D(std::string KinematicProjection, int Selection1, int Selection2=-1, int WeightStyle=0, TAxis *Axis=0)

◆ ReturnStackHistLegend()

TLegend* SampleHandlerFD::ReturnStackHistLegend ( )
inline

Definition at line 126 of file SampleHandlerFD.h.

126 {return THStackLeg;}

◆ ReturnStringFromKinematicParameter()

std::string SampleHandlerFD::ReturnStringFromKinematicParameter ( const int  KinematicVariable) const

ETA function to generically convert a kinematic type from xsec cov to a string.

Definition at line 1639 of file SampleHandlerFD.cpp.

1639  {
1640 // ************************************************
1641  auto it = ReversedKinematicParameters->find(KinematicParameter);
1642  if (it != ReversedKinematicParameters->end()) {
1643  return it->second;
1644  }
1645 
1646  MACH3LOG_ERROR("Did not recognise Kinematic Parameter type: {}", KinematicParameter);
1647  throw MaCh3Exception(__FILE__, __LINE__);
1648 
1649  return "";
1650 }
const std::unordered_map< int, std::string > * ReversedKinematicParameters
Mapping between kinematic enum and string.

◆ SetTestStatistic()

void SampleHandlerBase::SetTestStatistic ( TestStatistic  testStat)
inline

Set the test statistic to be used when calculating the binned likelihoods.

Parameters
testStatThe test statistic to use.

Definition at line 172 of file SampleHandlerBase.h.

172 { fTestStatistic = testStat; }