"TypeError: compute_integral() got multiple values for argument 'limits'" using register_analytic_integral

35 Views Asked by At

I defined my own ZFit pdf using something like:

class AngularPDFWithAcceptance(zfit.pdf.BasePDF):
    def __init__(self, ctl_name, ctk_name, phi_name, params, name):
        from math import pi
        ctl = zfit.Space(ctl_name, limits=(-1.0, 1.0))
        ctk = zfit.Space(ctk_name, limits=(-1.0, 1.0))
        phi = zfit.Space(phi_name, limits=(-pi, pi))
        obs = ctl*ctk*phi
        super().__init__(obs=obs, params=params, name=name)
        integral_full_limits = zfit.Space(axes=self.axes, limits = self.space.limits)
        self.register_analytic_integral( self.compute_integral_full_limits, integral_full_limits )
    ...
     def compute_integral_full_limits(limits, params, model):
        # this is the integral over 8pi
        ...
        return normalization

When creating the PDF I get an error

...
  File "/data/bfys/wouterh/miniconda3/envs/bd2ksteeEnv/lib/python3.8/site-packages/zfit/core/integration.py", line 606, in __call__
    return self.integrate(*args, **kwargs)
  File "/data/bfys/wouterh/miniconda3/envs/bd2ksteeEnv/lib/python3.8/site-packages/zfit/core/space.py", line 2777, in new_func
    return func(*args, **kwargs)
TypeError: compute_integral() got multiple values for argument 'limits'

Can anybody tell what I do wrong ? Thanks in advance ...

1

There are 1 best solutions below

0
On

Problem

The issue here arises since the integral registration is done in the init for the instance, but it is actually a class method and should be registered with the class, not on an instance (details on the technicality of the error below).

Solution

So the example should look like:

class AngularPDFWithAcceptance(zfit.pdf.BasePDF):
    def __init__(self, ctl_name, ctk_name, phi_name, params, name):
        from math import pi
        ctl = zfit.Space(ctl_name, limits=(-1.0, 1.0))
        ctk = zfit.Space(ctk_name, limits=(-1.0, 1.0))
        phi = zfit.Space(phi_name, limits=(-pi, pi))
        obs = ctl*ctk*phi
        super().__init__(obs=obs, params=params, name=name)
    ...
 def compute_integral_full_limits(limits, params, model):
    # this is the integral over 8pi
    ...
    return normalization

# the following code is duplicated, one could refactor it, i.e. into a class method/attribute
from math import pi
ctl = zfit.Space(ctl_name, limits=(-1.0, 1.0))
ctk = zfit.Space(ctk_name, limits=(-1.0, 1.0))
phi = zfit.Space(phi_name, limits=(-pi, pi))
obs = ctl*ctk*phi
integral_full_limits = zfit.Space(axes=self.axes, limits = self.space.limits)  AngularPDFWithAcceptance.register_analytic_integral(compute_integral_full_limits, integral_full_limits)

Explanation

The problem is that compute_integral_full_limits is an (instance) method. As such, it will take as the first (hidden) argument self automatically. However, since the registration function is a classmethod, it somehow messes up somewhere the signature, i.e. does not provide the self automatically as the first argument. Therefore, most likely, limits are given as the first as well as the second argument somehow