Пример #1
0
def Fit0_Jitter(x, y, yerr = None, verbose = True, doPlot = False, \
                    xpred = None):
    k = terms.Matern32Term(log_sigma=0.0, log_rho=0.0)
    if yerr is None:
        wn = np.median(abs(np.diff(y)))
    else:
        wn = np.median(yerr)
    k += terms.JitterTerm(log_sigma=np.log(wn))
    gp = GP(k, mean=1.0)
    gp.compute(x)
    HP_init = gp.get_parameter_vector()
    soln = minimize(NLL0, gp.get_parameter_vector(), jac=True, args=(gp, y))
    gp.set_parameter_vector(soln.x)
    if verbose:
        print 'Initial pars:', HP_init
        print 'Fitted pars:', soln.x
    if xpred is None:
        return soln.x
    mu, var = gp.predict(y, xpred, return_var=True)
    std = np.sqrt(var)
    if doPlot:
        plt.errorbar(x, y, yerr=yerr, fmt=".k", capsize=0)
        plt.plot(xpred, mu, 'C0')
        plt.fill_between(xpred,
                         mu + std,
                         mu - std,
                         color='C0',
                         alpha=0.4,
                         lw=0)
    return soln.x, mu, std
Пример #2
0
def test_log_likelihood(method, seed=42):
    np.random.seed(seed)
    x = np.sort(np.random.rand(10))
    yerr = np.random.uniform(0.1, 0.5, len(x))
    y = np.sin(x)

    kernel = terms.RealTerm(0.1, 0.5)
    gp = GP(kernel, method=method)
    with pytest.raises(RuntimeError):
        gp.log_likelihood(y)

    for term in [(0.6, 0.7, 1.0)]:
        kernel += terms.ComplexTerm(*term)
        gp = GP(kernel, method=method)

        assert gp.computed is False

        with pytest.raises(ValueError):
            gp.compute(np.random.rand(len(x)), yerr)

        gp.compute(x, yerr)
        assert gp.computed is True
        assert gp.dirty is False

        ll = gp.log_likelihood(y)
        K = gp.get_matrix(include_diagonal=True)
        ll0 = -0.5 * np.dot(y, np.linalg.solve(K, y))
        ll0 -= 0.5 * np.linalg.slogdet(K)[1]
        ll0 -= 0.5 * len(x) * np.log(2*np.pi)
        assert np.allclose(ll, ll0)

    # Check that changing the parameters "un-computes" the likelihood.
    gp.set_parameter_vector(gp.get_parameter_vector())
    assert gp.dirty is True
    assert gp.computed is False

    # Check that changing the parameters changes the likelihood.
    gp.compute(x, yerr)
    ll1 = gp.log_likelihood(y)
    params = gp.get_parameter_vector()
    params[0] += 0.1
    gp.set_parameter_vector(params)
    gp.compute(x, yerr)
    ll2 = gp.log_likelihood(y)
    assert not np.allclose(ll1, ll2)

    gp[1] += 0.1
    assert gp.dirty is True
    gp.compute(x, yerr)
    ll3 = gp.log_likelihood(y)
    assert not np.allclose(ll2, ll3)
Пример #3
0
def test_grad_log_likelihood(kernel, seed=42, eps=1.34e-7):
    np.random.seed(seed)
    x = np.sort(np.random.rand(100))
    yerr = np.random.uniform(0.1, 0.5, len(x))
    y = np.sin(x)

    if not terms.HAS_AUTOGRAD:
        gp = GP(kernel)
        gp.compute(x, yerr)
        with pytest.raises(ImportError):
            _, grad = gp.grad_log_likelihood(y)
        return

    for fit_mean in [True, False]:
        gp = GP(kernel, fit_mean=fit_mean)
        gp.compute(x, yerr)
        _, grad = gp.grad_log_likelihood(y)
        grad0 = np.empty_like(grad)

        v = gp.get_parameter_vector()
        for i, pval in enumerate(v):
            v[i] = pval + eps
            gp.set_parameter_vector(v)
            ll = gp.log_likelihood(y)

            v[i] = pval - eps
            gp.set_parameter_vector(v)
            ll -= gp.log_likelihood(y)

            grad0[i] = 0.5 * ll / eps
            v[i] = pval
        assert np.allclose(grad, grad0)
Пример #4
0
def test_build_gp(method, seed=42):
    kernel = terms.RealTerm(0.5, 0.1)
    kernel += terms.ComplexTerm(0.6, 0.7, 1.0)
    gp = GP(kernel, method=method)

    assert gp.vector_size == 5
    p = gp.get_parameter_vector()
    assert np.allclose(p, [0.5, 0.1, 0.6, 0.7, 1.0])

    gp.set_parameter_vector([0.5, 0.8, 0.6, 0.7, 2.0])
    p = gp.get_parameter_vector()
    assert np.allclose(p, [0.5, 0.8, 0.6, 0.7, 2.0])

    with pytest.raises(ValueError):
        gp.set_parameter_vector([0.5, 0.8, -0.6])

    with pytest.raises(ValueError):
        gp.set_parameter_vector("face1")
Пример #5
0
def test_grad_log_likelihood(kernel, with_general, seed=42, eps=1.34e-7):
    np.random.seed(seed)
    x = np.sort(np.random.rand(100))
    yerr = np.random.uniform(0.1, 0.5, len(x))
    y = np.sin(x)

    if with_general:
        U = np.vander(x - np.mean(x), 4).T
        V = U * np.random.rand(4)[:, None]
        A = np.sum(U * V, axis=0) + 1e-8
    else:
        A = np.empty(0)
        U = np.empty((0, 0))
        V = np.empty((0, 0))

    if not terms.HAS_AUTOGRAD:
        gp = GP(kernel)
        gp.compute(x, yerr, A=A, U=U, V=V)
        with pytest.raises(ImportError):
            _, grad = gp.grad_log_likelihood(y)
        return

    for fit_mean in [True, False]:
        gp = GP(kernel, fit_mean=fit_mean)
        gp.compute(x, yerr, A=A, U=U, V=V)
        _, grad = gp.grad_log_likelihood(y)
        grad0 = np.empty_like(grad)

        v = gp.get_parameter_vector()
        for i, pval in enumerate(v):
            v[i] = pval + eps
            gp.set_parameter_vector(v)
            ll = gp.log_likelihood(y)

            v[i] = pval - eps
            gp.set_parameter_vector(v)
            ll -= gp.log_likelihood(y)

            grad0[i] = 0.5 * ll / eps
            v[i] = pval
        assert np.allclose(grad, grad0)
Пример #6
0
    def __call__(self, period: Optional[float] = None):
        logger.info("Running Celerite")
        assert hasattr(
            self.ts, 'ls'), "Celerite step requires a prior Lomb-Scargle step"
        self.period = period if period is not None else self.ts.ls.period

        gp = GP(SHOTerm(log(self.ts.flux.var()), log(10),
                        log(2 * pi / self.period)),
                mean=1.)
        gp.freeze_parameter('kernel:log_omega0')
        gp.compute(self.ts.time, yerr=self.ts.ferr)

        def minfun(pv):
            gp.set_parameter_vector(pv)
            gp.compute(self.ts.time, yerr=self.ts.ferr)
            return -gp.log_likelihood(self.ts.flux)

        res = minimize(minfun,
                       gp.get_parameter_vector(),
                       jac=False,
                       method='powell')
        self.result = res
        self.parameters = res.x
        self.prediction = gp.predict(self.ts.flux, return_cov=False)
Пример #7
0
class LineFitter(object):
    def __init__(self,
                 x,
                 flux,
                 ivar=None,
                 absorp_emiss=None,
                 n_bg_coef=2,
                 target_x=None):
        """

        Parameters
        ----------
        x : array_like
            Dispersion parameter. Usually either pixel or wavelength.
        flux : array_like
            Flux array.
        ivar : array_like
            Inverse-variance array.
        absorp_emiss : numeric [-1, 1] (optional)
            If -1, absorption line. If +1, emission line. If not specified,
            will try to guess.
        n_bg_coef : int (optional)
            The order of the polynomial used to fit the background.
            1 = constant, 2 = linear, 3 = quadratic, etc.
        target_x : numeric (optional)
            Where we think the line of interest is.
        """
        self.x = np.array(x)
        self.flux = np.array(flux)

        if ivar is not None:
            self.ivar = np.array(ivar)
            self._err = 1 / np.sqrt(self.ivar)

        else:
            self.ivar = np.ones_like(flux)
            self._err = None

        if absorp_emiss is None:
            raise NotImplementedError(
                "You must supply an absorp_emiss for now")
        self.absorp_emiss = float(absorp_emiss)
        self.target_x = target_x

        self.n_bg_coef = int(n_bg_coef)

        # result of fitting
        self.gp = None
        self.success = None

    @classmethod
    def transform_pars(cls, p):
        new_p = OrderedDict()
        for k, v in p.items():
            if k in cls._log_pars:
                k = 'ln_{0}'.format(k)
                v = np.log(v)
            new_p[k] = v
        return new_p

    def get_init_generic(self, amp=None, x0=None, bg=None, bg_buffer=None):
        """
        Get initial guesses for the generic line parameters.

        Parameters
        ----------
        amp : numeric
            Line amplitude. This should be strictly positive; the
            ``absorp_emiss`` parameter controls whether it is absorption or
            emission.
        x0 : numeric
            Line centroid.
        bg : iterable
            Background polynomial coefficients.
        bg_buffer : int
            The number of values to use on either end of the flux array to
            estimate the background parameters.
        """
        target_x = self.target_x
        if x0 is None:  # estimate the initial guess for the centroid
            relmins = argrelmin(-self.absorp_emiss * self.flux)[0]

            if len(relmins) > 1 and target_x is None:
                logger.log(
                    0, "no target_x specified - taking largest line "
                    "in spec region")
                target_x = self.x[np.argmin(-self.absorp_emiss * self.flux)]

            if len(relmins) == 1:
                x0 = self.x[relmins[0]]

            else:
                x0_idx = relmins[np.abs(self.x[relmins] - target_x).argmin()]
                x0 = self.x[x0_idx]

        # shift x array so that line is approximately at 0
        _x = np.array(self.x, copy=True)
        x = np.array(_x) - x0

        # background polynomial parameters
        if bg_buffer is None:
            bg_buffer = len(x) // 4
            bg_buffer = max(1, bg_buffer)

        if bg is None:
            if self.n_bg_coef < 2:
                bg = np.array([0.])
                bg[0] = np.median(self.flux)

            else:
                # estimate linear background model
                bg = np.array([0.] * self.n_bg_coef)

                i1 = argmedian(self.flux[:bg_buffer])
                i2 = argmedian(self.flux[-bg_buffer:])
                f1 = self.flux[:bg_buffer][i1]
                f2 = self.flux[-bg_buffer:][i2]
                x1 = x[:bg_buffer][i1]
                x2 = x[-bg_buffer:][i2]
                bg[1] = (f2 - f1) / (x2 - x1)  # slope
                bg[0] = f2 - bg[1] * x2  # estimate constant term

        else:
            if len(bg) != self.n_bg_coef:
                raise ValueError('Number of bg polynomial coefficients does '
                                 'not match n_bg_coef specified when fitter '
                                 'was created.')

        if amp is None:  # then estimate the initial guess for amplitude
            _i = np.argmin(np.abs(x))
            if len(bg) > 1:
                _bg = bg[0] + bg[1] * x[_i]
            else:
                _bg = bg[0]
            # amp = np.sqrt(2*np.pi) * (flux[_i] - bg)
            amp = self.flux[_i] - _bg

        p0 = OrderedDict()
        p0['amp'] = np.abs(amp)
        p0['x0'] = x0
        p0['bg_coef'] = bg
        return p0

    def get_init_gp(self, log_sigma=None, log_rho=None, x0=None):
        """
        Set up the GP kernel parameters.
        """

        if log_sigma is None:
            if x0 is not None:
                # better initial guess for GP parameters
                mask = np.abs(self.x - x0) > 2.
                y_MAD = np.median(
                    np.abs(self.flux[mask] - np.median(self.flux[mask])))
            else:
                y_MAD = np.median(np.abs(self.flux - np.median(self.flux)))
            log_sigma = np.log(3 * y_MAD)

        if log_rho is None:
            log_rho = np.log(5.)

        p0 = OrderedDict()
        p0['log_sigma'] = log_sigma
        p0['log_rho'] = log_rho
        return p0

    def init_gp(self,
                log_sigma=None,
                log_rho=None,
                amp=None,
                x0=None,
                bg=None,
                bg_buffer=None,
                **kwargs):
        """
        **kwargs:
        """

        # Call the different get_init methods with the correct kwargs passed
        sig = inspect.signature(self.get_init)
        kw = OrderedDict()
        for k in list(sig.parameters.keys()):
            kw[k] = kwargs.pop(k, None)
        p0 = self.get_init(**kw)

        # Call the generic init method - all line models must have these params
        p0_generic = self.get_init_generic(amp=amp,
                                           x0=x0,
                                           bg=bg,
                                           bg_buffer=bg_buffer)
        for k, v in p0_generic.items():
            p0[k] = v

        # expand bg parameters
        bgs = p0.pop('bg_coef')
        for i in range(self.n_bg_coef):
            p0['bg{}'.format(i)] = bgs[i]

        # transform
        p0 = self.transform_pars(p0)

        # initialize model
        mean_model = self.MeanModel(n_bg_coef=self.n_bg_coef,
                                    absorp_emiss=self.absorp_emiss,
                                    **p0)

        p0_gp = self.get_init_gp(log_sigma=log_sigma, log_rho=log_rho)
        kernel = terms.Matern32Term(log_sigma=p0_gp['log_sigma'],
                                    log_rho=p0_gp['log_rho'])

        # set up the gp model
        self.gp = GP(kernel, mean=mean_model, fit_mean=True)

        if self._err is not None:
            self.gp.compute(self.x, self._err)
        else:
            self.gp.compute(self.x)

        init_params = self.gp.get_parameter_vector()
        init_ll = self.gp.log_likelihood(self.flux)
        logger.log(0, "Initial log-likelihood: {0}".format(init_ll))

        return init_params

    def get_gp_mean_pars(self):
        """
        Return a parameter dictionary for the mean model parameters only.
        """
        fit_pars = OrderedDict()
        for k, v in self.gp.get_parameter_dict().items():
            if 'mean' not in k:
                continue

            k = k[5:]  # remove 'mean:'
            if k.startswith('ln'):
                if 'amp' in k:
                    fit_pars[k[3:]] = self.absorp_emiss * np.exp(v)
                else:
                    fit_pars[k[3:]] = np.exp(v)

            elif k.startswith('bg'):
                if 'bg_coef' not in fit_pars:
                    fit_pars['bg_coef'] = []
                fit_pars['bg_coef'].append(v)

            else:
                fit_pars[k] = v

        return fit_pars

    def _neg_log_like(self, params):
        self.gp.set_parameter_vector(params)

        try:
            ll = self.gp.log_likelihood(self.flux)
        except (RuntimeError, LinAlgError):
            return np.inf

        if np.isnan(ll):
            return np.inf
        return -ll

    def fit(self, bounds=None, **kwargs):
        """
        """
        init_params = self.init_gp()

        if bounds is None:
            bounds = OrderedDict()

        # default bounds for mean model parameters
        i = self.gp.models['mean'].get_parameter_names().index('x0')
        mean_bounds = self.gp.models['mean'].get_parameter_bounds()
        if mean_bounds[i][0] is None and mean_bounds[i][1] is None:
            mean_bounds[i] = (min(self.x), max(self.x))

        for i, k in enumerate(self.gp.models['mean'].parameter_names):
            mean_bounds[i] = bounds.get(k, mean_bounds[i])
        self.gp.models['mean'].parameter_bounds = mean_bounds

        # HACK: default bounds for kernel parameters
        self.gp.models['kernel'].parameter_bounds = [(None, None),
                                                     (np.log(0.5), None)]

        soln = minimize(self._neg_log_like,
                        init_params,
                        method="L-BFGS-B",
                        bounds=self.gp.get_parameter_bounds())
        self.success = soln.success

        self.gp.set_parameter_vector(soln.x)

        if self.success:
            logger.debug("Success: {0}, Final log-likelihood: {1}".format(
                soln.success, -soln.fun))
        else:
            logger.warning("Fit failed! Final log-likelihood: {0}, "
                           "Final parameters: {1}".format(-soln.fun, soln.x))

        return self

    def plot_fit(self, axes=None, fit_alpha=0.5):
        unbinned_color = '#3182bd'
        binned_color = '#2ca25f'
        gp_color = '#ff7f0e'
        noise_color = '#de2d26'

        if self.gp is None:
            raise ValueError("You must run .fit() first!")

        # ----------------------------------------------------------------------
        # Plot the maximum likelihood model
        if axes is None:
            fig, axes = plt.subplots(1, 3, figsize=(15, 5), sharex=True)

        # data
        for ax in axes[:2]:
            ax.plot(self.x,
                    self.flux,
                    drawstyle='steps-mid',
                    marker='',
                    color='#777777',
                    zorder=2)

            if self._err is not None:
                ax.errorbar(self.x,
                            self.flux,
                            self._err,
                            marker='',
                            ls='none',
                            ecolor='#666666',
                            zorder=1)

        # mean model
        wave_grid = np.linspace(self.x.min(), self.x.max(), 256)
        mu, var = self.gp.predict(self.flux, self.x, return_var=True)
        std = np.sqrt(var)

        axes[0].plot(wave_grid,
                     self.gp.mean.get_unbinned_value(wave_grid),
                     marker='',
                     alpha=fit_alpha,
                     zorder=10,
                     color=unbinned_color)
        axes[0].plot(self.x,
                     self.gp.mean.get_value(self.x),
                     marker='',
                     alpha=fit_alpha,
                     zorder=10,
                     drawstyle='steps-mid',
                     color=binned_color)

        # full GP model
        axes[1].plot(self.x,
                     mu,
                     color=gp_color,
                     drawstyle='steps-mid',
                     marker='',
                     alpha=fit_alpha,
                     zorder=10)
        axes[1].fill_between(self.x,
                             mu + std,
                             mu - std,
                             color=gp_color,
                             alpha=fit_alpha / 10.,
                             edgecolor="none",
                             step='mid')

        # just GP noise component
        mean_model = self.gp.mean.get_value(self.x)
        axes[2].plot(self.x,
                     mu - mean_model,
                     marker='',
                     alpha=fit_alpha,
                     zorder=10,
                     drawstyle='steps-mid',
                     color=noise_color)

        axes[2].plot(self.x,
                     self.flux - mean_model,
                     drawstyle='steps-mid',
                     marker='',
                     color='#777777',
                     zorder=2)

        if self._err is not None:
            axes[2].errorbar(self.x,
                             self.flux - mean_model,
                             self._err,
                             marker='',
                             ls='none',
                             ecolor='#666666',
                             zorder=1)

        axes[0].set_ylabel('flux')
        axes[0].set_xlim(self.x.min(), self.x.max())

        axes[0].set_title('Line model')
        axes[1].set_title('Line + noise model')
        axes[2].set_title('Noise model')

        fig = axes[0].figure
        fig.tight_layout()
        return fig
Пример #8
0
def drw_fit(lc_df, de=True, debug=False, plot=False, bounds=None):

    best_fit = np.zeros((2, 6))

    # fail_num = 0
    lc_df = lc_df.copy()
    std = np.std(lc_df.flux.values)

    if bounds is not None:
        first_bounds = bounds
    else:
        first_bounds = [(-4, np.log(4 * std)), (-4, 10)]

    # loop through lc in each passband
    for band in range(6):

        try:
            lc_band = lc_df[lc_df.passband == band].copy()
            t = lc_band.mjd.values - lc_band.mjd.min()
            y = lc_band.flux.values
            yerr = lc_band.flux_err.values

            rerun = True  # dynamic control of bounds
            counter = 0
            bounds = first_bounds
            jac_log_rec = 10

            # initialize parameter and kernel
            kernel = DRW_term(*drw_log_param_init(std))
            gp = GP(kernel, mean=np.mean(y))
            gp.compute(t, yerr)

            if de:
                # set bound based on LC std for amp
                while rerun and (counter < 5):
                    counter += 1
                    r = differential_evolution(neg_ll,
                                               bounds=bounds,
                                               args=(y, yerr, gp),
                                               maxiter=200)

                    if r.success:
                        best_fit[:, band] = np.exp(r.x)

                        if "jac" not in r.keys():
                            rerun = False
                        else:
                            jac_log = np.log10(np.dot(r.jac, r.jac) + 1e-8)

                            # if positive jac, then increase bounds
                            if jac_log > 0:
                                bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                            else:
                                rerun = False

                            # update best-fit if smaller jac found
                            if jac_log < jac_log_rec:
                                jac_log_rec = jac_log
                                best_fit[:, band] = np.exp(r.x)
                    else:
                        bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                        gp.set_parameter_vector(drw_log_param_init(std))

            else:
                initial_params = gp.get_parameter_vector()

                while rerun and (counter < 5):
                    counter += 1
                    r = minimize(
                        neg_ll,
                        initial_params,
                        method="L-BFGS-B",
                        bounds=bounds,
                        args=(y, yerr, gp),
                    )
                    if r.success:
                        best_fit[:, band] = np.exp(r.x)

                        if "jac" not in r.keys():
                            rerun = False
                        else:
                            jac_log = np.log10(np.dot(r.jac, r.jac) + 1e-8)

                            # if positive jac, then increase bounds
                            if jac_log > 0:
                                bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                            else:
                                rerun = False

                            # update best-fit if smaller jac found
                            if jac_log < jac_log_rec:
                                jac_log_rec = jac_log
                                best_fit[:, band] = np.exp(r.x)
                    else:
                        bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                        gp.set_parameter_vector(drw_log_param_init(std))

            if not r.success:
                best_fit[:, band] = np.nan

        except Exception as e:
            print(r)
            print(e)
            print(
                f"Exception at object_id: {lc_df.object_id.values[0]}, passband: {band}"
            )
            best_fit[:, band] = np.nan
            # fail_num += 1

        # Below code is used to visualize if stuck in local minima
        if debug:
            print(r)

        if plot:
            plot_drw_ll(t, y, yerr, np.exp(r.x), gp, vec_neg_ll)

    return np.concatenate([[lc_df.object_id.values[0]], best_fit.flatten()])
Пример #9
0
def carma_fit(lc_df, p, q, de=True, debug=False, plot=False, bounds=None):

    best_fit = np.zeros((int(p + q + 1), 6))
    lc_df = lc_df.copy()

    if bounds is not None:
        first_bounds = bounds
    else:
        first_bounds = [(-10, 5)] * int(p + q + 1)

    # loop through lc in each passband
    for band in range(6):

        try:
            lc_band = lc_df[lc_df.passband == band].copy()
            t = lc_band.mjd.values - lc_band.mjd.min()
            y = lc_band.flux.values
            yerr = lc_band.flux_err.values

            rerun = True  # dynamic control of bounds
            compute = True  # handle can't factorize in gp.compute()
            succeded = False  # ever succeded
            compute_ct = 0
            counter = 0
            bounds = first_bounds
            jac_log_rec = 10

            # initialize parameter, kernel and GP
            log_params = carma_param_init(int(p + q + 1))
            kernel = CARMA_term(log_params[:p], log_params[p:])
            gp = GP(kernel, mean=np.mean(y))

            # compute can't factorize, try 4 more times
            while compute & (compute_ct < 5):
                compute_ct += 1
                try:
                    gp.compute(t, yerr)
                    compute = False
                except celerite.solver.LinAlgError:
                    gp.set_parameter_vector(carma_param_init(int(p + q + 1)))

            if de:
                # set bound based on LC std for amp
                while rerun and (counter < 5):
                    counter += 1
                    r = differential_evolution(neg_ll,
                                               bounds=bounds,
                                               args=(y, yerr, gp),
                                               maxiter=200)

                    if r.success:
                        succeded = True
                        best_fit[:, band] = np.exp(r.x)

                        if "jac" not in r.keys():
                            rerun = False
                        else:
                            jac_log = np.log10(np.dot(r.jac, r.jac) + 1e-8)

                            # if positive jac, then increase bounds
                            if jac_log > 0:
                                bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                            else:
                                rerun = False

                            # update best-fit if smaller jac found
                            if jac_log < jac_log_rec:
                                jac_log_rec = jac_log
                                best_fit[:, band] = np.exp(r.x)
                    else:
                        bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                        gp.set_parameter_vector(
                            carma_param_init(int(p + q + 1)))

            else:
                initial_params = gp.get_parameter_vector()

                while rerun and (counter < 5):
                    counter += 1
                    r = minimize(
                        neg_ll,
                        initial_params,
                        method="L-BFGS-B",
                        bounds=bounds,
                        args=(y, yerr, gp),
                    )
                    if r.success:
                        succeded = True
                        best_fit[:, band] = np.exp(r.x)
                        jac_log = np.log10(np.dot(r.jac, r.jac) + 1e-8)

                        # if positive jac, then increase bounds
                        if jac_log > 0:
                            bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                        else:
                            rerun = False

                        # update best-fit if smaller jac found
                        if jac_log < jac_log_rec:
                            jac_log_rec = jac_log
                            best_fit[:, band] = np.exp(r.x)
                    else:
                        bounds = [(x[0] - 1, x[1] + 1) for x in bounds]
                        gp.set_parameter_vector(
                            carma_param_init(int(p + q + 1)))

            if not succeded:
                best_fit[:, band] = np.nan

        except Exception as e:
            print(e)
            print(
                f"Exception at object_id: {lc_df.object_id.values[0]}, passband: {band}"
            )
            best_fit[:, band] = np.nan

        # Below code is used to visualize if stuck in local minima
        if debug:
            print(r)

    #         if plot:
    #             plot_dho_ll(t, y, yerr, np.exp(r.x), gp, vec_neg_ll)

    return np.concatenate([[lc_df.object_id.values[0]], best_fit.flatten()])
Пример #10
0
def test_log_likelihood(seed=42):
    np.random.seed(seed)
    x = np.sort(np.random.rand(10))
    yerr = np.random.uniform(0.1, 0.5, len(x))
    y = np.sin(x)

    kernel = terms.RealTerm(0.1, 0.5)
    gp = GP(kernel)
    with pytest.raises(RuntimeError):
        gp.log_likelihood(y)

    termlist = [(0.1 + 10./j, 0.5 + 10./j) for j in range(1, 4)]
    termlist += [(1.0 + 10./j, 0.01 + 10./j, 0.5, 0.01) for j in range(1, 10)]
    termlist += [(0.6, 0.7, 1.0), (0.3, 0.05, 0.5, 0.6)]
    for term in termlist:
        if len(term) > 2:
            kernel += terms.ComplexTerm(*term)
        else:
            kernel += terms.RealTerm(*term)
        gp = GP(kernel)

        assert gp.computed is False

        with pytest.raises(ValueError):
            gp.compute(np.random.rand(len(x)), yerr)

        gp.compute(x, yerr)
        assert gp.computed is True
        assert gp.dirty is False

        ll = gp.log_likelihood(y)
        K = gp.get_matrix(include_diagonal=True)
        ll0 = -0.5 * np.dot(y, np.linalg.solve(K, y))
        ll0 -= 0.5 * np.linalg.slogdet(K)[1]
        ll0 -= 0.5 * len(x) * np.log(2*np.pi)
        assert np.allclose(ll, ll0)

    # Check that changing the parameters "un-computes" the likelihood.
    gp.set_parameter_vector(gp.get_parameter_vector())
    assert gp.dirty is True
    assert gp.computed is False

    # Check that changing the parameters changes the likelihood.
    gp.compute(x, yerr)
    ll1 = gp.log_likelihood(y)
    params = gp.get_parameter_vector()
    params[0] += 10.0
    gp.set_parameter_vector(params)
    gp.compute(x, yerr)
    ll2 = gp.log_likelihood(y)
    assert not np.allclose(ll1, ll2)

    gp[1] += 10.0
    assert gp.dirty is True
    gp.compute(x, yerr)
    ll3 = gp.log_likelihood(y)
    assert not np.allclose(ll2, ll3)

    # Test zero delta t
    ind = len(x) // 2
    x = np.concatenate((x[:ind], [x[ind]], x[ind:]))
    y = np.concatenate((y[:ind], [y[ind]], y[ind:]))
    yerr = np.concatenate((yerr[:ind], [yerr[ind]], yerr[ind:]))
    gp.compute(x, yerr)
    ll = gp.log_likelihood(y)
    K = gp.get_matrix(include_diagonal=True)
    ll0 = -0.5 * np.dot(y, np.linalg.solve(K, y))
    ll0 -= 0.5 * np.linalg.slogdet(K)[1]
    ll0 -= 0.5 * len(x) * np.log(2*np.pi)
    assert np.allclose(ll, ll0), "face"
Пример #11
0
def test_log_likelihood(with_general, seed=42):
    np.random.seed(seed)
    x = np.sort(np.random.rand(10))
    yerr = np.random.uniform(0.1, 0.5, len(x))
    y = np.sin(x)

    if with_general:
        U = np.vander(x - np.mean(x), 4).T
        V = U * np.random.rand(4)[:, None]
        A = np.sum(U * V, axis=0) + 1e-8
    else:
        A = np.empty(0)
        U = np.empty((0, 0))
        V = np.empty((0, 0))

    # Check quiet argument with a non-positive definite kernel.
    class NPDTerm(terms.Term):
        parameter_names = ("par1", )

        def get_real_coefficients(self, params):  # NOQA
            return [params[0]], [0.1]

    gp = GP(NPDTerm(-1.0))
    with pytest.raises(celerite.solver.LinAlgError):
        gp.compute(x, 0.0)
    with pytest.raises(celerite.solver.LinAlgError):
        gp.log_likelihood(y)
    assert np.isinf(gp.log_likelihood(y, quiet=True))
    if terms.HAS_AUTOGRAD:
        assert np.isinf(gp.grad_log_likelihood(y, quiet=True)[0])

    kernel = terms.RealTerm(0.1, 0.5)
    gp = GP(kernel)
    with pytest.raises(RuntimeError):
        gp.log_likelihood(y)

    termlist = [(0.1 + 10. / j, 0.5 + 10. / j) for j in range(1, 4)]
    termlist += [(1.0 + 10. / j, 0.01 + 10. / j, 0.5, 0.01)
                 for j in range(1, 10)]
    termlist += [(0.6, 0.7, 1.0), (0.3, 0.05, 0.5, 0.6)]
    for term in termlist:
        if len(term) > 2:
            kernel += terms.ComplexTerm(*term)
        else:
            kernel += terms.RealTerm(*term)
        gp = GP(kernel)

        assert gp.computed is False

        with pytest.raises(ValueError):
            gp.compute(np.random.rand(len(x)), yerr)

        gp.compute(x, yerr, A=A, U=U, V=V)
        assert gp.computed is True
        assert gp.dirty is False

        ll = gp.log_likelihood(y)
        K = gp.get_matrix(include_diagonal=True)
        ll0 = -0.5 * np.dot(y, np.linalg.solve(K, y))
        ll0 -= 0.5 * np.linalg.slogdet(K)[1]
        ll0 -= 0.5 * len(x) * np.log(2 * np.pi)
        assert np.allclose(ll, ll0)

    # Check that changing the parameters "un-computes" the likelihood.
    gp.set_parameter_vector(gp.get_parameter_vector())
    assert gp.dirty is True
    assert gp.computed is False

    # Check that changing the parameters changes the likelihood.
    gp.compute(x, yerr, A=A, U=U, V=V)
    ll1 = gp.log_likelihood(y)
    params = gp.get_parameter_vector()
    params[0] += 10.0
    gp.set_parameter_vector(params)
    gp.compute(x, yerr, A=A, U=U, V=V)
    ll2 = gp.log_likelihood(y)
    assert not np.allclose(ll1, ll2)

    gp[1] += 10.0
    assert gp.dirty is True
    gp.compute(x, yerr, A=A, U=U, V=V)
    ll3 = gp.log_likelihood(y)
    assert not np.allclose(ll2, ll3)

    # Test zero delta t
    ind = len(x) // 2
    x = np.concatenate((x[:ind], [x[ind]], x[ind:]))
    y = np.concatenate((y[:ind], [y[ind]], y[ind:]))
    yerr = np.concatenate((yerr[:ind], [yerr[ind]], yerr[ind:]))
    gp.compute(x, yerr)
    ll = gp.log_likelihood(y)
    K = gp.get_matrix(include_diagonal=True)
    ll0 = -0.5 * np.dot(y, np.linalg.solve(K, y))
    ll0 -= 0.5 * np.linalg.slogdet(K)[1]
    ll0 -= 0.5 * len(x) * np.log(2 * np.pi)
    assert np.allclose(ll, ll0)