Firstly, thank you for making a really neat, pythonic tool which can be used as an alternative for RooFit.
I have successfully defined a custom 2D PDF but I am not completely sure on how to register my function's analytic integral:
Analytic integral from WolframAlpha
The PDF is defined as below:
class PdfForDeltaW(zfit.pdf.ZPDF):
"""Pdf to calculate epsilon, w, and delta w, as a function of sig-flav and tag-flav"""
_N_OBS = 2
_PARAMS = "epsilon w delta_w mix_prob".split()
def _unnormalized_pdf(self, x):
"""Calculation of PDF value"""
sigflav, tagflav = zfit.ztf.unstack_x(x)
epsilon = self.params["epsilon"]
w = self.params["w"]
delta_w = self.params["delta_w"]
mix_prob = self.params["mix_prob"]
dilution = 1 - 2 * w
mixing = 1 - 2 * mix_prob
return (
0.5
* epsilon
* (1 - sigflav * tagflav * (sigflav * delta_w + dilution * mixing))
)
From looking at the example on github I am not sure on how I can access the fit observables for use in the calculation (i.e. x, sigflav
and y, tagflav
for my 2D case) in addition to the fit variables which can be accessed through the params
attribute.
In addition, I am not sure how my limits should be defined. I know that both x and y must be in the range [-1, 1]. I think it would be nice to have a bit more clarity on how the zfit.Space.from_axes
function should be used, and how this relates to the analytic integral.
Cheers, Colm
Thanks for that, let me explain the different things:
Fit variables
If you want to register an integral over the whole PDF, you would not need to access
sigflav
andtagflav
, since you integrate over them. In case you have a partial integral, you can access them throughx
, which acts as the argument in the_unnormalized_pdf
case.Space from axes
A
Space
defines your coordinates and the limits/ranges. Usually, as a user of a PDF, this involves observables (like columns of a DataFrame). But if we create a PDF, the observables that it is going to be used with are of course not known, the PDF works "position based", or "axes based". E.g. in your example,sigflav
is on axis 0, whatever the observable will be named that the PDF will be used with. This is why when registering the integral, we need to use aSpace
that is defined in terms ofaxes
.Integral limits
There can be different control over the limits of a PDF. If needed, more fine grained control can be implemented, but currently available is that you can define an integral from a certain point/or anywhere to a certain point/anywhere.
This is useful since you can register several integrals. Maybe you know the general integral, which has a complicated form. But you also know e.g. that the integral from -1 to 1 is exactly 1. So you can register this as well and give it a higher priority. This means that if you integrate over -1 to 1, the simpler one is used, otherwise the more general form.
In your case, you want to register from ANY to ANY, or use as limits ANY_LOWER, ANY_UPPER, like this