6 #include <pybind11/pybind11.h>
7 #include <pybind11/stl.h>
8 #include <pybind11/numpy.h>
14 namespace py = pybind11;
17 std::tuple<py::array_t<M3::float_t>, py::array_t<M3::float_t>>
TH1ToNumpy(
const TH1* hist) {
19 throw std::runtime_error(
"Histogram pointer is null");
22 int nbins = hist->GetNbinsX();
25 py::array_t<M3::float_t> contents(nbins);
26 auto contents_buf = contents.request();
30 py::array_t<M3::float_t> edges(nbins + 1);
31 auto edges_buf = edges.request();
35 for (
int i = 0; i < nbins; ++i) {
36 contents_ptr[i] = hist->GetBinContent(i + 1);
40 for (
int i = 0; i <= nbins; ++i) {
41 edges_ptr[i] = hist->GetBinLowEdge(i + 1);
44 edges_ptr[nbins] = hist->GetBinLowEdge(nbins + 1) + hist->GetBinWidth(nbins + 1);
46 return std::make_tuple(contents, edges);
50 std::tuple<py::array_t<M3::float_t>, py::array_t<M3::float_t>, py::array_t<M3::float_t>>
TH2ToNumpy(
const TH2* hist) {
52 throw std::runtime_error(
"Histogram pointer is null");
55 int nbinsX = hist->GetNbinsX();
56 int nbinsY = hist->GetNbinsY();
59 py::array_t<M3::float_t> contents({nbinsY, nbinsX});
60 auto contents_buf = contents.request();
64 py::array_t<M3::float_t> edgesX(nbinsX + 1);
65 auto edgesX_buf = edgesX.request();
68 py::array_t<M3::float_t> edgesY(nbinsY + 1);
69 auto edgesY_buf = edgesY.request();
74 for (
int iy = 0; iy < nbinsY; ++iy) {
75 for (
int ix = 0; ix < nbinsX; ++ix) {
76 contents_ptr[iy * nbinsX + ix] = hist->GetBinContent(ix + 1, iy + 1);
81 for (
int i = 0; i <= nbinsX; ++i) {
82 edgesX_ptr[i] = hist->GetXaxis()->GetBinLowEdge(i + 1);
84 edgesX_ptr[nbinsX] = hist->GetXaxis()->GetBinLowEdge(nbinsX + 1) +
85 hist->GetXaxis()->GetBinWidth(nbinsX + 1);
88 for (
int i = 0; i <= nbinsY; ++i) {
89 edgesY_ptr[i] = hist->GetYaxis()->GetBinLowEdge(i + 1);
91 edgesY_ptr[nbinsY] = hist->GetYaxis()->GetBinLowEdge(nbinsY + 1) +
92 hist->GetYaxis()->GetBinWidth(nbinsY + 1);
94 return std::make_tuple(contents, edgesX, edgesY);
107 PYBIND11_OVERRIDE_PURE(
116 PYBIND11_OVERRIDE_PURE(
126 PYBIND11_OVERRIDE_PURE(
136 PYBIND11_OVERRIDE_PURE_NAME(
147 PYBIND11_OVERRIDE_PURE_NAME(
150 "get_sample_likelihood",
158 PYBIND11_OVERRIDE_PURE_NAME(
161 "clean_memory_before_fit",
168 PYBIND11_OVERRIDE_PURE(
177 std::string
GetKinVarName(
const int iSample,
const int Dimension)
const override {
178 PYBIND11_OVERRIDE_PURE(
189 PYBIND11_OVERRIDE_PURE(
199 PYBIND11_OVERRIDE_PURE(
208 PYBIND11_OVERRIDE_PURE(
217 PYBIND11_OVERRIDE_PURE(
226 PYBIND11_OVERRIDE_PURE_NAME(
236 const std::string& ProjectionVar_Str,
237 const int kModeToFill = -1,
238 const int kChannelToFill = -1,
239 const int WeightStyle = 0)
override {
241 (void) ProjectionVar_Str;
243 (void) kChannelToFill;
249 const std::string& ProjectionVar_StrX,
250 const std::string& ProjectionVar_StrY,
251 const int kModeToFill = -1,
252 const int kChannelToFill = -1,
253 const int WeightStyle = 0)
override {
255 (void) ProjectionVar_StrX;
256 (void) ProjectionVar_StrY;
258 (void) kChannelToFill;
264 const std::string &ProjectionVar,
265 const std::vector<KinematicCut> &EventSelectionVec = {},
266 const int WeightStyle = 0,
267 const std::vector<KinematicCut> &SubEventSelectionVec = {})
override {
269 (void) ProjectionVar;
270 (void) EventSelectionVec;
272 (void) SubEventSelectionVec;
277 const std::string& ProjectionVarX,
278 const std::string& ProjectionVarY,
279 const std::vector<KinematicCut>& EventSelectionVec = {},
280 const int WeightStyle = 0,
281 const std::vector<KinematicCut>& SubEventSelectionVec = {})
override {
283 (void) ProjectionVarX;
284 (void) ProjectionVarY;
285 (void) EventSelectionVec;
287 (void) SubEventSelectionVec;
291 int GetNDim(
const int Sample)
const override {
292 PYBIND11_OVERRIDE_PURE(
301 const int iChannel)
const override {
302 PYBIND11_OVERRIDE_PURE(
321 PYBIND11_OVERRIDE_PURE_NAME(
324 "add_additional_weight_pointers",
332 PYBIND11_OVERRIDE_PURE(
341 PYBIND11_OVERRIDE_PURE_NAME(
352 PYBIND11_OVERRIDE_PURE_NAME(
363 PYBIND11_OVERRIDE_PURE_NAME(
366 "setup_experiment_MC",
373 PYBIND11_OVERRIDE_PURE_NAME(
383 PYBIND11_OVERRIDE_PURE_NAME(
392 PYBIND11_OVERRIDE_PURE_NAME(
395 "get_event_kinematic_value",
403 PYBIND11_OVERRIDE_PURE_NAME(
406 "get_event_kinematic_value_reference",
414 PYBIND11_OVERRIDE_PURE_NAME(
417 "register_functional_parameters",
426 py::enum_<TestStatistic>(m_samples,
"TestStatistic")
440 "reweight the MC events in this sample. You will need to override this."
446 "Get the sample likelihood at the current point in your model space. You will need to override this."
452 "Set the test statistic that should be used when calculating likelihoods. \n\
453 :param test_stat: The new test statistic to use",
460 "Get the LLH for a bin by comparing the data and MC. The result depends on having previously set the test statistic using :py:meth:`pyMaCh3.samples.SampleHandlerInterface.set_test_stat` \n\
461 :param data: The data content of the bin. \n\
462 :param mc: The mc content of the bin \n\
463 :param w2: The Sum(w_{i}^2) (sum of weights squared) in the bin, which is sigma^2_{MC stats}",
473 py::init<std::string, ParameterHandlerGeneric*>(),
474 "This should never be called directly as SampleHandlerBase is an abstract base class. \n\
475 However when creating a derived class, in the __init__() method, you should call the parent constructor i.e. this one by doing:: \n\
477 \tsuper(<your derived SampleHandler class>, self).__init__(*args) \n\
479 py::arg(
"mc_version"), py::arg(
"xsec_cov"))
485 int Dimension =
self.GetNDim(sample);
490 const TH1 *hist_original =
self.GetMCHist(sample);
493 if (!hist_original) {
494 throw std::runtime_error(
"GetMCHist returned null pointer");
498 TH1D *hist =
static_cast<TH1D*
>(hist_original->Clone(
"cloned_hist"));
500 if (Dimension == 1) {
503 auto edgesY = py::array_t<M3::float_t>();
504 return py::make_tuple(contents, edgesX, edgesY);
505 }
else if (Dimension == 2) {
507 TH2Poly *hist2poly =
dynamic_cast<TH2Poly *
>(hist);
510 throw std::runtime_error(
"pyMaCh3 can't do non-uniform binning for now :(");
514 TH2 *hist2d =
dynamic_cast<TH2 *
>(hist);
516 throw std::runtime_error(
"Failed to cast to TH2");
518 auto [contents, edgesX, edgesY] =
TH2ToNumpy(hist2d);
519 return py::make_tuple(contents, edgesX, edgesY);
524 throw std::invalid_argument(
"Dimension must be 1 or 2");
527 py::return_value_policy::reference_internal,
529 "Get MC histogram as numpy arrays.\n"
530 "For 1D: Returns (contents, edges)\n"
531 "For 2D: Returns (contents, edgesX, edgesY)\n"
532 "where contents is shape (nbinsY, nbinsX) for 2D")
537 const TH1 *hist =
self.GetDataHist(sample);
539 int Dimension =
self.GetNDim(sample);
541 if (Dimension == 1) {
543 const auto [contents, edgesX] =
TH1ToNumpy(hist);
544 const auto edgesY = py::array_t<M3::float_t>();
545 return py::make_tuple(contents, edgesX, edgesY);
546 }
else if (Dimension == 2) {
548 const TH2Poly *hist2poly =
dynamic_cast<const TH2Poly *
>(hist);
551 throw std::runtime_error(
"pyMaCh3 can't do non-uniform binning for now :(");
555 throw std::runtime_error(
"pyMaCh3 can't do non-uniform binning for now :(");
558 const TH2 *hist2d =
dynamic_cast<const TH2 *
>(hist);
560 throw std::runtime_error(
"Failed to cast to TH2");
562 const auto [contents, edgesX, edgesY] =
TH2ToNumpy(hist2d);
563 return py::make_tuple(contents, edgesX, edgesY);
568 throw std::invalid_argument(
"Dimension must be 1 or 2");
571 py::arg(
"Dimension"),
572 "Get Data histogram as numpy arrays.\n"
573 "For 1D: Returns (contents, edges)\n"
574 "For 2D: Returns (contents, edgesX, edgesY)\n"
575 "where contents is shape (nbinsY, nbinsX) for 2D")
580 const TH1 *hist =
self.GetW2Hist(sample);
582 int Dimension =
self.GetNDim(sample);
584 if (Dimension == 1) {
586 const auto [contents, edgesX] =
TH1ToNumpy(hist);
587 const auto edgesY = py::array_t<M3::float_t>();
588 return py::make_tuple(contents, edgesX, edgesY);
589 }
else if (Dimension == 2) {
591 const TH2Poly *hist2poly =
dynamic_cast<const TH2Poly *
>(hist);
594 throw std::runtime_error(
"pyMaCh3 can't do non-uniform binning for now :(");
598 const TH2 *hist2d =
dynamic_cast<const TH2 *
>(hist);
600 throw std::runtime_error(
"Failed to cast to TH2");
602 const auto [contents, edgesX, edgesY] =
TH2ToNumpy(hist2d);
603 return py::make_tuple(contents, edgesX, edgesY);
608 throw std::invalid_argument(
"Dimension must be 1 or 2");
612 "Get W2 histogram as numpy arrays.\n"
613 "For 1D: Returns (contents, edges)\n"
614 "For 2D: Returns (contents, edgesX, edgesY)\n"
615 "where contents is shape (nbinsY, nbinsX) for 2D");
@ kNTestStatistics
Number of test statistics.
@ kPearson
Standard Pearson likelihood .
@ kBarlowBeeston
Barlow-Beeston () following Conway approximation ()
@ kDembinskiAbdelmotteleb
Based on .
@ kPoisson
Standard Poisson likelihood .
As SampleHandlerBase is an abstract base class we have to do some gymnastics to get it to get it into...
void SetupMC() override
Function which translates experiment struct into core struct.
void InititialiseData() override
Function responsible for loading data from file or loading from file.
void CleanMemoryBeforeFit() override
Allow to clean not used memory before fit starts.
void Init() override
Initialise any variables that your experiment specific SampleHandler needs.
int SetupExperimentMC() override
Experiment specific setup, returns the number of events which were loaded.
const double * GetPointerToKinematicParameter(int, int) const override
void SetupSplines() override
initialise your splineXX object and then use InitialiseSplineObject to conviently setup everything up
double ReturnKinematicParameter(int, int) const override
void RegisterFunctionalParameters() override
HH - a experiment-specific function where the maps to actual functions are set up.
void AddAdditionalWeightPointers() override
DB Function to determine which weights apply to which types of samples.
EW: As SampleHandlerBase is an abstract base class we have to do some gymnastics to get it to get it ...
std::string GetKinVarName(const int iSample, const int Dimension) const override
Return Kinematic Variable name for specified sample and dimension for example "Reconstructed_Neutrino...
std::unique_ptr< TH2 > Get2DVarHist(const int iSample, const std::string &ProjectionVarX, const std::string &ProjectionVarY, const std::vector< KinematicCut > &EventSelectionVec={}, const int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={}) override
std::unique_ptr< TH1 > Get1DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_Str, const int kModeToFill=-1, const int kChannelToFill=-1, const int WeightStyle=0) override
std::vector< double > ReturnKinematicParameterBinning(const int Sample, const std::string &KinematicParameter) const override
Return the binning used to draw a kinematic parameter.
TH1 * GetDataHist(const int Sample) override
Get Data histogram.
void CleanMemoryBeforeFit() override
Allow to clean not used memory before fit starts.
std::string GetSampleTitle(const int iSample) const override
double GetSampleLikelihood(const int iSample) const override
int GetNOscChannels(const int iSample) const override
std::string GetName() const override
TH1 * GetMCHist(const int Sample) override
Get MC histogram.
std::string GetFlavourName(const int iSample, const int iChannel) const override
std::unique_ptr< TH1 > Get1DVarHist(const int iSample, const std::string &ProjectionVar, const std::vector< KinematicCut > &EventSelectionVec={}, const int WeightStyle=0, const std::vector< KinematicCut > &SubEventSelectionVec={}) override
int GetNDim(const int Sample) const override
DB Function to differentiate 1D or 2D binning.
std::unique_ptr< TH2 > Get2DVarHistByModeAndChannel(const int iSample, const std::string &ProjectionVar_StrX, const std::string &ProjectionVar_StrY, const int kModeToFill=-1, const int kChannelToFill=-1, const int WeightStyle=0) override
void PrintRates(const bool DataOnly=false) override
Helper function to print rates for the samples with LLH.
double GetLikelihood() const override
TH1 * GetW2Hist(const int Sample) override
Get W2 histogram.
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
SampleHandlerBase(std::string ConfigFileName, ParameterHandlerGeneric *xsec_cov, const std::shared_ptr< OscillationHandler > &OscillatorObj_=nullptr)
Constructor.
Class responsible for handling implementation of samples used in analysis, reweighting and returning ...
virtual double GetLikelihood() const =0
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....
virtual void Reweight()=0
SampleHandlerInterface()
The main constructor.
void SetTestStatistic(TestStatistic testStat)
Set the test statistic to be used when calculating the binned likelihoods.
std::tuple< py::array_t< M3::float_t >, py::array_t< M3::float_t > > TH1ToNumpy(const TH1 *hist)
std::tuple< py::array_t< M3::float_t >, py::array_t< M3::float_t >, py::array_t< M3::float_t > > TH2ToNumpy(const TH2 *hist)
void initSamplesModule(py::module &m_samples)