# LaVOZs

The World’s Largest Online Community for Developers

'; zfit - Accessing PDF variables when registering analytic integral - LavOzs.Com

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` and `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 `_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 a `Space` that is defined in terms of `axes`.

## 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

``````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))
``````