The World’s Largest Online Community for Developers
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:
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
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.
Thanks for that, let me explain the different things:
If you want to register an integral over the whole PDF, you would not need to access
tagflav, since you integrate over them.
In case you have a partial integral, you can access them through
x, which acts as the argument in the
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 a
Space that is defined in terms of
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
lower_full = ((zfit.Space.ANY_LOWER, zfit.Space.ANY_LOWER),) upper_full = ((zfit.Space.ANY_UPPER, zfit.Space.ANY_UPPER),) integral_full_limits = zfit.Space.from_axes(axes=(0, 1), limits=(lower_full, upper_full))