The World’s Largest Online Community for Developers

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

## Space from axes

## Integral limits

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:

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.

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`

.

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