示例#1
0
 def test_invalid_method(self):
     with pytest.raises(ValueError, match='Unknown solver "xfail"'):
         find_roots(
             self.f,
             lower_bound=self.lower_bound,
             upper_bound=self.upper_bound,
             method="xfail",
         )
示例#2
0
    def containment_radius(self, containment_fraction):
        """Containment angle for a given containment fraction.

        Parameters
        ----------
        containment_fraction : `~numpy.ndarray`
            Containment fraction

        Returns
        -------
        containment_radius : `~numpy.ndarray`
            Containment radius
        """
        rad_max = 1e3

        def f(rad):
            # positive if theta too large
            return self.containment_fraction(rad * u.deg) - containment_fraction

        roots, res = find_roots(f, lower_bound=0, upper_bound=rad_max, nbin=1)
        if np.isnan(roots[0]) or np.allclose(roots[0], rad_max):
            rad = np.inf
        else:
            rad = roots[0]
        return rad * u.deg
示例#3
0
    def _confidence(self, dataset, n_sigma, result, positive):
        stat_best = result["stat"]
        norm = result["norm"]
        norm_err = result["norm_err"]

        def ts_diff(x):
            return (stat_best + n_sigma**2) - dataset.stat_sum(x)

        if positive:
            min_norm = norm
            max_norm = norm + 1e2 * norm_err
            factor = 1
        else:
            min_norm = norm - 1e2 * norm_err
            max_norm = norm
            factor = -1

        with warnings.catch_warnings():
            warnings.simplefilter("ignore")
            roots, res = find_roots(
                ts_diff,
                [min_norm],
                [max_norm],
                nbin=1,
                maxiter=self.max_niter,
                rtol=self.rtol,
            )
            # Where the root finding fails NaN is set as norm
            return (roots[0] - norm) * factor
示例#4
0
    def compute_upper_limit(self, n_sigma=3):
        """Compute upper limit on the signal.

        Searches the signal value for which the test statistics is n_sigma**2 away from the maximum
        or from 0 if the measured excess is negative.

        Parameters
        ----------
        n_sigma : float
            Confidence level of the upper limit expressed in number of sigma. Default is 3.
        """

        ul = np.zeros_like(self.n_on, dtype="float")

        min_range = self.n_sig
        max_range = self.n_sig + 2 * n_sigma * (self.error + 1)
        it = np.nditer(ul, flags=["multi_index"])

        while not it.finished:
            ts_ref = self._stat_fcn(min_range[it.multi_index], 0.0,
                                    it.multi_index)

            roots, res = find_roots(
                self._stat_fcn,
                min_range[it.multi_index],
                max_range[it.multi_index],
                nbin=1,
                args=(ts_ref + n_sigma**2, it.multi_index),
            )
            ul[it.multi_index] = roots[0]
            it.iternext()
        return ul
示例#5
0
    def compute_errp(self, n_sigma=1):
        """Compute upward excess uncertainties.

        Searches the signal value for which the test statistics is n_sigma**2 away from the maximum.

        Parameters
        ----------
        n_sigma : float
            Confidence level of the uncertainty expressed in number of sigma. Default is 1.
        """

        errp = np.zeros_like(self.n_on, dtype="float")
        max_range = self.n_sig + 2 * n_sigma * (self.error + 1)

        it = np.nditer(errp, flags=["multi_index"])
        while not it.finished:
            roots, res = find_roots(
                self._stat_fcn,
                self.n_sig[it.multi_index],
                max_range[it.multi_index],
                nbin=1,
                args=(self.stat_max[it.multi_index] + n_sigma**2,
                      it.multi_index),
            )
            errp[it.multi_index] = roots[0]
            it.iternext()

        return errp - self.n_sig
示例#6
0
    def test_methods(self):

        methods = ["brentq", "secant"]
        for method in methods:
            roots, res = find_roots(
                self.f,
                lower_bound=self.lower_bound,
                upper_bound=self.upper_bound,
                method=method,
            )
            assert roots.unit == u.rad
            assert_allclose(2 * roots.value / np.pi,
                            np.array([-5.0, -3.0, -1.0]))
            assert np.all([sol.converged for sol in res])

            roots, res = find_roots(
                self.h,
                lower_bound=self.lower_bound,
                upper_bound=self.upper_bound,
                method=method,
            )
            assert np.isnan(roots[0])
            assert res[0].iterations == 0
示例#7
0
def _confidence_scipy_brentq(parameters,
                             parameter,
                             function,
                             sigma,
                             reoptimize,
                             upper=True,
                             **kwargs):

    ts_diff = TSDifference(function,
                           parameters,
                           parameter,
                           reoptimize,
                           ts_diff=sigma**2)

    lower_bound = parameter.factor
    upper_bound = parameter.factor_max if upper else parameter.factor_min
    if np.isnan(upper_bound):
        # TODO: remove hard coded limits here...
        upper_bound = parameter.factor
        if upper:
            upper_bound += 1e2 * parameter.error / parameter.scale
        else:
            upper_bound -= 1e2 * parameter.error / parameter.scale

    message, success = "Confidence terminated successfully.", True
    kwargs.setdefault("nbin", 1)

    roots, res = find_roots(ts_diff.fcn,
                            lower_bound=lower_bound,
                            upper_bound=upper_bound,
                            **kwargs)
    result = (roots[0], res[0])
    if np.isnan(roots[0]):
        message = (
            "Confidence estimation failed. Try to set the parameter.min/max by hand."
        )
        success = False
    suffix = "errp" if upper else "errn"

    return {
        "nfev_" + suffix: result[1].iterations,
        suffix: np.abs(result[0] - lower_bound),
        "success_" + suffix: success,
        "message_" + suffix: message,
        "stat_null": ts_diff.stat_null,
    }
示例#8
0
def stat_profile_ul_scipy(value_scan,
                          stat_scan,
                          delta_ts=4,
                          interp_scale="sqrt",
                          **kwargs):
    """Compute upper limit of a parameter from a likelihood profile.

    Parameters
    ----------
    value_scan : `~numpy.ndarray`
        Array of parameter values.
    stat_scan : `~numpy.ndarray`
        Array of delta fit statistic values, with respect to the minimum.
    delta_ts : float
        Difference in test statistics for the upper limit.
    interp_scale : {"sqrt", "lin"}
        Interpolation scale applied to the fit statistic profile. If the profile is
        of parabolic shape, a "sqrt" scaling is recommended. In other cases or
        for fine sampled profiles a "lin" can also be used.
    **kwargs : dict
        Keyword arguments passed to `~scipy.optimize.brentq`.

    Returns
    -------
    ul : float
        Upper limit value.
    """

    interp = interpolate_profile(value_scan,
                                 stat_scan,
                                 interp_scale=interp_scale)

    def f(x):
        return interp((x, )) - delta_ts

    idx = np.argmin(stat_scan)
    norm_best_fit = value_scan[idx]
    roots, res = find_roots(f,
                            lower_bound=norm_best_fit,
                            upper_bound=value_scan[-1],
                            nbin=1,
                            **kwargs)
    return roots[0]
示例#9
0
    def n_sig_matching_significance(self, significance):
        """Compute excess matching a given significance.

        This function is the inverse of `significance`.

        Parameters
        ----------
        significance : float
            Significance

        Returns
        -------
        n_sig : `numpy.ndarray`
            Excess
        """

        n_sig = np.zeros_like(self.n_bkg, dtype="float")
        it = np.nditer(n_sig, flags=["multi_index"])

        while not it.finished:
            lower_bound = np.sqrt(self.n_bkg[it.multi_index]) * significance
            # find upper bounds for secant method as in scipy
            eps = 1e-4
            upper_bound = lower_bound * (1 + eps)
            upper_bound += eps if upper_bound >= 0 else -eps
            roots, res = find_roots(
                self._n_sig_matching_significance_fcn,
                lower_bound=lower_bound,
                upper_bound=upper_bound,
                args=(significance, it.multi_index),
                nbin=1,
                method="secant",
            )
            n_sig[it.multi_index] = roots[0]  # return NaN if fail
            it.iternext()
        return n_sig