예제 #1
0
 def _init_instrument(self):
     """Set up the instrument and contamination model."""
     self.instrument = Instrument('example',
                                  [sdss_g, sdss_r, sdss_i, sdss_z])
     self.cm = SMContamination(self.instrument, "i'")
     self.lnpriors.append(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
     self.lnpriors.append(lambda pv: where(pv[:, 8] < pv[:, 5], 0, -inf))
예제 #2
0
    def _init_instrument(self):
        """Set up the instrument and contamination model."""

        qe = TabulatedFilter('MockQE',
                             [300, 350, 500, 550, 700, 800, 1000, 1050],
                             [0.10, 0.20, 0.90, 0.96, 0.90, 0.75, 0.11, 0.05])
        self.instrument = Instrument('MockInstrument',
                                     [sdss_g, sdss_r, sdss_i, sdss_z],
                                     (qe, qe, qe, qe))
        self.cm = SMContamination(self.instrument, "i'")
        self.lnpriors.append(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
예제 #3
0
    def __init__(self, setup: SimulationSetup, **kwargs):
        self.setup = self.s = s = setup
        self.t_exposure_d = Qty(kwargs.get('exptime', 60), 's').rescale('d')
        self.t_baseline_d = Qty(s.t_baseline, 'h').rescale('d')
        self.ldcs = s.ldcs
        self.tm = QuadraticModel(klims=(0.01, 0.99), nk=512)

        self.filters = "g' r' i' z'".split()
        self.npb = len(self.filters)
        self.k_apparent, self.p, self.a, self.b, self.i = s.orbital_parameters

        self.duration_d = Qty(
            duration_eccentric(self.p, self.k_apparent, self.a, self.i, 0, 0,
                               1), 'd')

        # Contamination
        # -------------
        qe_be = TabulatedFilter('1024B_eXcelon', [
            300, 325, 350, 400, 450, 500, 700, 800, 850, 900, 950, 1050, 1150
        ], [
            0.0, 0.1, 0.25, 0.60, 0.85, 0.92, 0.96, 0.85, 0.70, 0.50, 0.30,
            0.05, 0.0
        ])
        qe_b = TabulatedFilter(
            '2014B', [300, 350, 500, 550, 700, 800, 1000, 1050],
            [0.10, 0.20, 0.90, 0.96, 0.90, 0.75, 0.11, 0.05])
        qes = qe_be, qe_b, qe_be, qe_be

        self.instrument = instrument = Instrument(
            'MuSCAT2', (sdss_g, sdss_r, sdss_i, sdss_z), qes)
        self.contaminator = SMContamination(instrument, "i'")

        self.hteff = setup.hteff
        self.cteff = setup.cteff
        self.i_contamination = setup.c
        self.k_true = setup.k_apparent / sqrt(1 - self.i_contamination)
        self.contamination = self.contaminator.contamination(
            self.i_contamination, self.hteff, self.cteff)
예제 #4
0
 def _init_instrument(self):
     self.instrument = Instrument('MuSCAT2',
                                  [sdss_g, sdss_r, sdss_i, sdss_z])
     self.cm = SMContamination(self.instrument, "i'")
예제 #5
0
class BaseTGCLPF(LinearModelBaseline, PhysContLPF):
    """Log posterior function that combined TESS light curve with ground-based transit light curves.

    Example log posterior function to model a TESS light curve jointly with with ground-based light curves observed in
    arbitrary passbands. The TESS light curve is assumed to contain an unknown amount of light contamination, and the
    ground-based observations are assumed to all be contaminated by an identical source, but the contamination follows
    a physical passband-dependent model.

    **Note:** This LPF is meant to be inherited by an LPF that implements the `read_data` method.
    """
    def __init__(self, name: str, zero_epoch, period, use_ldtk: bool = False):

        times, fluxes, pbnames, pbs, wns, covs = self.read_data()
        pbids = pd.Categorical(pbs, categories=pbnames).codes
        wnids = arange(len(times))

        self.wns = wns
        PhysContLPF.__init__(self, name, passbands=pbnames, times=times, fluxes=fluxes, pbids=pbids, wnids=wnids,
                             covariates=covs)

        self.result_dir = Path('.')
        self.set_prior('zero_epoch', NP(zero_epoch.n, zero_epoch.s))
        self.set_prior('period', NP(period.n, period.s))
        self.set_prior('k2_app', UP(0.10**2, 0.20**2))
        self.set_prior('teff_h', NP(3250, 140))

    def read_data(self):
        """Read in the TESS light curve and the ground-based data.

        Read in the TESS light curve and the ground-based data. This method needs to be implemented by the class inheriting
        the base ´TESSGBLPF`.
        """
        raise NotImplementedError

    def _init_p_planet(self):
        ps = self.ps
        pk2 = [PParameter('k2_app', 'apparent_area_ratio', 'A_s', UP(0.1**2, 0.30**2), (0.1**2, 0.30**2))]
        pcn = [GParameter('k2_true', 'true_area_ratio', 'As', UP(0.1**2, 0.75**2), bounds=(1e-8, inf)),
               GParameter('teff_h', 'host_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('teff_c', 'contaminant_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('k2_app_tess', 'tess_apparent_area_ratio', 'A_s', UP(0.1**2, 0.30**2), (0.1**2, 0.3**2))]
        ps.add_passband_block('k2', 1, 1, pk2)
        self._pid_k2 = repeat(ps.blocks[-1].start, self.npb)
        self._start_k2 = ps.blocks[-1].start
        self._sl_k2 = ps.blocks[-1].slice
        ps.add_global_block('contamination', pcn)
        self._pid_cn = arange(ps.blocks[-1].start, ps.blocks[-1].stop)
        self._sl_cn = ps.blocks[-1].slice

    def create_pv_population(self, npop: int = 50) -> ndarray:
        pvp = zeros((0, len(self.ps)))
        npv, i = 0, 0
        while npv < npop and i < 10:
            pvp_trial = self.ps.sample_from_prior(npop)
            pvp_trial[:, 5] = pvp_trial[:, 4]
            cref = uniform(0, 0.99, size=npop)
            pvp_trial[:, 5] = pvp_trial[:, 4] / (1. - cref)
            lnl = self.lnposterior(pvp_trial)
            ids = where(isfinite(lnl))
            pvp = concatenate([pvp, pvp_trial[ids]])
            npv = pvp.shape[0]
            i += 1
        pvp = pvp[:npop]
        return pvp

    def additional_priors(self, pv) -> ndarray:
        """Additional priors."""
        pv = atleast_2d(pv)
        return sum([f(pv) for f in self.lnpriors], 0)

    def _init_instrument(self):
        """Set up the instrument and contamination model."""
        self.instrument = Instrument('example', [sdss_g, sdss_r, sdss_i, sdss_z])
        self.cm = SMContamination(self.instrument, "i'")
        self.lnpriors.append(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
        self.lnpriors.append(lambda pv: where(pv[:, 8] < pv[:, 5], 0, -inf))

    def transit_model(self, pvp):
        pvp = atleast_2d(pvp)
        cnt = zeros((pvp.shape[0], self.npb))
        pvt = map_pv_pclpf(pvp)
        ldc = map_ldc(pvp[:, self._sl_ld])
        flux = self.tm.evaluate_pv(pvt, ldc)
        cnt[:, 0] = 1 - pvp[:, 8] / pvp[:, 5]
        for i, pv in enumerate(pvp):
            if (2500 < pv[6] < 12000) and (2500 < pv[7] < 12000):
                cnref = 1. - pv[4] / pv[5]
                cnt[i, 1:] = self.cm.contamination(cnref, pv[6], pv[7])
            else:
                cnt[i, 1:] = -inf
        return contaminate(flux, cnt, self.lcids, self.pbids)

    def plot_folded_tess_transit(self, method: str = 'de', pv: ndarray = None, binwidth: float = 1,
                                 plot_model: bool = True, plot_unbinned: bool = True, plot_binned: bool = True,
                                 xlim: tuple = None, ylim: tuple = None, ax=None, figsize: tuple = None):
        assert method in ('de', 'mc')
        if pv is None:
            if method == 'de':
                pv = self.de.minimum_location
            else:
                df = self.posterior_samples(derived_parameters=False)
                pv = df.median().values

        if ax is None:
            fig, ax = subplots(figsize=figsize)
        else:
            fig, ax = None, ax

        ax.autoscale(enable=True, axis='x', tight=True)

        etess = self._ntess
        t = self.timea[:etess]
        fo = self.ofluxa[:etess]
        fm = squeeze(self.transit_model(pv))[:etess]
        bl = squeeze(self.baseline(pv))[:etess]

        phase = 24 * pv[1] * (fold(t, pv[1], pv[0], 0.5) - 0.5)
        sids = argsort(phase)
        phase = phase[sids]
        bp, bf, be = downsample_time(phase, (fo / bl)[sids], binwidth / 60)
        if plot_unbinned:
            ax.plot(phase, (fo / bl)[sids], 'k.', alpha=0.1, ms=2)
        if plot_binned:
            ax.errorbar(bp, bf, be, fmt='ko', ms=3)
        if plot_model:
            ax.plot(phase, fm[sids], 'k')
        setp(ax, ylim=ylim, xlim=xlim, xlabel='Time - T$_c$ [h]', ylabel='Normalised flux')
        return fig

    def plot_gb_transits(self, method='de', pv: ndarray = None, figsize: tuple = (14, 2), axes=None, ncol: int = 4,
                         xlim: tuple = None, ylim: tuple = None):

        if pv is None:
            if method == 'de':
                pv = self.de.minimum_location
            else:
                raise NotImplementedError

        nlc = self.nlc - self._stess
        nrow = int(floor(nlc / ncol))

        if axes is None:
            fig, axs = subplots(nrow, ncol, figsize=figsize, constrained_layout=True, sharex='all', sharey='all',
                                squeeze=False)
        else:
            fig, axs = None, axes

        [ax.autoscale(enable=True, axis='x', tight=True) for ax in axs.flat]

        fmodel = squeeze(self.flux_model(pv))
        etess = self._stess
        t0, p = self.de.minimum_location[[0, 1]]

        for i, ax in enumerate(axs.T.flat):
            t = self.times[etess + i]
            e = epoch(t.mean(), t0, p)
            tc = t0 + e * p
            tt = 24 * (t - tc)
            ax.plot(tt, self.fluxes[etess + i], 'k.', alpha=0.2)
            ax.plot(tt, fmodel[self.lcslices[etess + i]], 'k')
            setp(ax, xlim=(-0.065, 0.065))

        setp(axs, xlim=xlim, ylim=ylim)
        setp(axs[-1, :], xlabel='Time - T$_c$ [h]')
        setp(axs[:, 0], ylabel='Normalised flux')
        return fig
예제 #6
0
class MockLC:
    pb_names = "g' r' i' z'".split()
    pb_centers = 1e-9 * array([470, 640, 780, 900])
    npb = len(pb_names)

    def __init__(self, setup: SimulationSetup, **kwargs):
        self.setup = self.s = s = setup
        self.t_exposure_d = Qty(kwargs.get('exptime', 60), 's').rescale('d')
        self.t_baseline_d = Qty(s.t_baseline, 'h').rescale('d')
        self.ldcs = s.ldcs
        self.tm = QuadraticModel(klims=(0.01, 0.99), nk=512)

        self.filters = "g' r' i' z'".split()
        self.npb = len(self.filters)
        self.k_apparent, self.p, self.a, self.b, self.i = s.orbital_parameters

        self.duration_d = Qty(
            duration_eccentric(self.p, self.k_apparent, self.a, self.i, 0, 0,
                               1), 'd')

        # Contamination
        # -------------
        qe_be = TabulatedFilter('1024B_eXcelon', [
            300, 325, 350, 400, 450, 500, 700, 800, 850, 900, 950, 1050, 1150
        ], [
            0.0, 0.1, 0.25, 0.60, 0.85, 0.92, 0.96, 0.85, 0.70, 0.50, 0.30,
            0.05, 0.0
        ])
        qe_b = TabulatedFilter(
            '2014B', [300, 350, 500, 550, 700, 800, 1000, 1050],
            [0.10, 0.20, 0.90, 0.96, 0.90, 0.75, 0.11, 0.05])
        qes = qe_be, qe_b, qe_be, qe_be

        self.instrument = instrument = Instrument(
            'MuSCAT2', (sdss_g, sdss_r, sdss_i, sdss_z), qes)
        self.contaminator = SMContamination(instrument, "i'")

        self.hteff = setup.hteff
        self.cteff = setup.cteff
        self.i_contamination = setup.c
        self.k_true = setup.k_apparent / sqrt(1 - self.i_contamination)
        self.contamination = self.contaminator.contamination(
            self.i_contamination, self.hteff, self.cteff)

    @property
    def t_total_d(self):
        return self.duration_d + 2 * self.t_baseline_d

    @property
    def duration_h(self):
        return self.duration_d.rescale('h')

    @property
    def n_exp(self):
        return int(self.t_total_d // self.t_exposure_d)

    def __call__(self,
                 rseed=0,
                 ldcs=None,
                 wnsigma=None,
                 rnsigma=None,
                 rntscale=0.5):
        return self.create(rseed, ldcs, wnsigma, rnsigma, rntscale)

    def create(self,
               rseed=0,
               ldcs=None,
               wnsigma=None,
               rnsigma=None,
               rntscale=0.5,
               nights=1):
        ldcs = ldcs if ldcs is not None else self.ldcs
        seed(rseed)

        self.time = linspace(-0.5 * float(self.t_total_d),
                             0.5 * float(self.t_total_d), self.n_exp)
        self.time = (tile(self.time, [nights, 1]) +
                     (self.p * arange(nights))[:, newaxis]).ravel()
        self.npt = self.time.size
        self.tm.set_data(self.time)

        self.transit = zeros([self.npt, 4])
        for i, (ldc, c) in enumerate(zip(ldcs, self.contamination)):
            self.transit[:, i] = self.tm.evaluate_ps(self.k_true, ldc, 0,
                                                     self.p, self.a, self.i)
            self.transit[:, i] = c + (1 - c) * self.transit[:, i]

        # White noise
        # -----------
        if wnsigma is not None:
            self.wnoise = multivariate_normal(
                zeros(atleast_2d(self.transit).shape[1]),
                diag(wnsigma)**2, self.npt)
        else:
            self.wnoise = zeros_like(self.transit)

        # Red noise
        # ---------
        if rnsigma and with_george:
            self.gp = GP(rnsigma**2 * ExpKernel(rntscale))
            self.gp.compute(self.time)
            self.rnoise = self.gp.sample(self.time, self.npb).T
            self.rnoise -= self.rnoise.mean(0)
        else:
            self.rnoise = zeros_like(self.transit)

        # Final light curve
        # -----------------
        self.time_h = Qty(self.time, 'd').rescale('h')
        self.flux = self.transit + self.wnoise + self.rnoise
        return self.lcdataset

    @property
    def lcdataset(self):
        return LCDataSet([
            LCData(self.time, flux, pb)
            for pb, flux in zip(self.pb_names, self.flux.T)
        ], self.instrument)

    def plot(self, figsize=(13, 4), yoffset=0.01):
        fig, axs = pl.subplots(1,
                               3,
                               figsize=figsize,
                               sharex='all',
                               sharey='all')
        yshift = yoffset * arange(4)
        axs[0].plot(self.time_h, self.flux + yshift)
        axs[1].plot(self.time_h, self.transit + yshift)
        axs[2].plot(self.time_h, 1 + self.rnoise + yshift)
        pl.setp(axs, xlabel='Time [h]', xlim=self.time_h[[0, -1]])
        pl.setp(axs[0], ylabel='Normalised flux')
        [
            pl.setp(ax, title=title) for ax, title in zip(
                axs, 'Transit model + noise, Transit model, Red noise'.split(
                    ', '))
        ]
        fig.tight_layout()
        return fig, axs

    def plot_color_difference(self, figsize=(13, 4)):
        fig, axs = pl.subplots(2,
                               3,
                               figsize=figsize,
                               sharex='all',
                               sharey='all')
        [
            ax.plot(self.time_h, 100 * (fl - self.transit[:, -1]))
            for ax, fl in zip(axs[0], self.transit[:, :-1].T)
        ]
        [
            ax.plot(self.time_h, 100 * (fl - self.flux[:, -1]))
            for ax, fl in zip(axs[1], self.flux[:, :-1].T)
        ]
        [
            pl.setp(ax, title='F$_{}$ - F$_z$'.format(pb))
            for ax, pb in zip(axs[0], self.pb_names[:-1])
        ]
        pl.setp(axs[:, 0], ylabel='$\Delta F$ [%]')
        pl.setp(axs[1, :], xlabel='Time [h]')
        pl.setp(axs, xlim=self.time_h[[0, -1]])
        fig.tight_layout()
        return fig
예제 #7
0
 def _init_instrument(self):
     self.instrument = Instrument('example', [sdss_g, sdss_r, sdss_i])
     self.cm = SMContamination(self.instrument, "i'")
     self.lnpriors.append(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
예제 #8
0
class BaseTGCLPF(PhysContLPF):
    """Log posterior function that combined TESS light curve with ground-based transit light curves.

    Example log posterior function to model a TESS light curve jointly with with ground-based light curves observed in
    arbitrary passbands. The TESS light curve is assumed to contain an unknown amount of light contamination, and the
    ground-based observations are assumed to all be contaminated by an identical source, but the contamination follows
    a physical passband-dependent model.

    **Note:** This LPF is meant to be inherited by an LPF that implements the `read_data` method.
    """

    def __init__(self, name: str, use_ldtk: bool = False, tm = None):
        self.result_dir = Path('.')
        self._stess = None
        self._ntess = None

        times, fluxes, pbnames, pbs, wns, covs = self.read_data()
        pbids = pd.Categorical(pbs, categories=pbnames).codes
        wnids = arange(len(times))
        tref = floor(concatenate(times).min())

        self.wns = wns
        PhysContLPF.__init__(self, name, passbands=pbnames, times=times, fluxes=fluxes, pbids=pbids, wnids=wnids,
                             covariates=covs, tref=tref, tm=tm)

    def read_data(self):
        """Read in the TESS light curve and the ground-based data.

        Read in the TESS light curve and the ground-based data. This method needs to be implemented by the class inheriting
        the base ´TESSGBLPF`.
        """
        raise NotImplementedError

    def _init_p_planet(self):
        ps = self.ps
        pk2 = [PParameter('k2_app', 'apparent_area_ratio', 'A_s', UP(0.01**2, 0.30**2), (0., inf))]
        pcn = [GParameter('k2_true', 'true_area_ratio', 'As', UP(0.01**2, 0.75**2), bounds=(1e-8, inf)),
               GParameter('teff_h', 'host_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('teff_c', 'contaminant_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('k2_app_tess', 'tess_apparent_area_ratio', 'A_s', UP(0.01**2, 0.30**2), (0., inf))]
        ps.add_passband_block('k2', 1, 1, pk2)
        self._pid_k2 = repeat(ps.blocks[-1].start, self.npb)
        self._start_k2 = ps.blocks[-1].start
        self._sl_k2 = ps.blocks[-1].slice
        ps.add_global_block('contamination', pcn)
        self._pid_cn = arange(ps.blocks[-1].start, ps.blocks[-1].stop)
        self._sl_cn = ps.blocks[-1].slice

    def _init_baseline(self):
        self._add_baseline_model(LinearModelBaseline(self))

    def create_pv_population(self, npop: int = 50) -> ndarray:
        pvp = zeros((0, len(self.ps)))
        npv, i = 0, 0
        while npv < npop and i < 10:
            pvp_trial = self.ps.sample_from_prior(npop)
            pvp_trial[:, 5] = pvp_trial[:, 4]
            cref = uniform(0, 0.99, size=npop)
            pvp_trial[:, 5] = pvp_trial[:, 4] / (1. - cref)
            lnl = self.lnposterior(pvp_trial)
            ids = where(isfinite(lnl))
            pvp = concatenate([pvp, pvp_trial[ids]])
            npv = pvp.shape[0]
            i += 1
        pvp = pvp[:npop]
        return pvp

    def posterior_samples(self, burn: int = 0, thin: int = 1, derived_parameters: bool = True):
        df = super().posterior_samples(burn, thin, derived_parameters)
        if derived_parameters:
            df['ctess'] = 1 - df.k2_app_tess / df.k2_true
        return df

    def _init_instrument(self):
        """Set up the instrument and contamination model."""
        self.instrument = Instrument('example', [sdss_g, sdss_r, sdss_i, sdss_z])
        self.cm = SMContamination(self.instrument, "i'")
        self.add_prior(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
        self.add_prior(lambda pv: where(pv[:, 8] < pv[:, 5], 0, -inf))

    def transit_model(self, pvp):
        pvp = atleast_2d(pvp)
        cnt = zeros((pvp.shape[0], self.npb))
        pvt = map_pv_pclpf(pvp)
        pvt[:,1] -= self._tref
        ldc = map_ldc(pvp[:, self._sl_ld])
        flux = self.tm.evaluate_pv(pvt, ldc)
        cnt[:, 0] = 1 - pvp[:, 8] / pvp[:, 5]
        cnref = 1. - pvp[:, 4] / pvp[:, 5]
        cnt[:, 1:] = self.cm.contamination(cnref, pvp[:, 6], pvp[:, 7])
        return contaminate(flux, cnt, self.lcids, self.pbids)

    def plot_folded_tess_transit(self, solution: str = 'de', pv: ndarray = None, binwidth: float = 1,
                                 plot_model: bool = True, plot_unbinned: bool = True, plot_binned: bool = True,
                                 xlim: tuple = None, ylim: tuple = None, ax=None, figsize: tuple = None):

        if pv is None:
            if solution.lower() == 'local':
                pv = self._local_minimization.x
            elif solution.lower() in ('de', 'global'):
                pv = self.de.minimum_location
            elif solution.lower() in ('mcmc', 'mc'):
                pv = self.posterior_samples().median().values
            else:
                raise NotImplementedError("'solution' should be either 'local', 'global', or 'mcmc'")

        if ax is None:
            fig, ax = subplots(figsize=figsize)
        else:
            fig, ax = None, ax

        ax.autoscale(enable=True, axis='x', tight=True)

        etess = self._ntess
        t = self.timea[:etess]
        fo = self.ofluxa[:etess]
        fm = squeeze(self.transit_model(pv))[:etess]
        bl = squeeze(self.baseline(pv))[:etess]

        phase = 24 * pv[1] * (fold(t, pv[1], pv[0], 0.5) - 0.5)
        sids = argsort(phase)
        phase = phase[sids]
        bp, bf, be = downsample_time(phase, (fo / bl)[sids], binwidth / 60)
        if plot_unbinned:
            ax.plot(phase, (fo / bl)[sids], 'k.', alpha=0.1, ms=2)
        if plot_binned:
            ax.errorbar(bp, bf, be, fmt='ko', ms=3)
        if plot_model:
            ax.plot(phase, fm[sids], 'k')
        setp(ax, ylim=ylim, xlim=xlim, xlabel='Time - T$_c$ [h]', ylabel='Normalised flux')

        if fig is not None:
            fig.tight_layout()
        return fig

    def plot_gb_transits(self, solution: str = 'de', pv: ndarray = None, figsize: tuple = None, axes=None, ncol: int = 4,
                         xlim: tuple = None, ylim: tuple = None, remove_baseline: bool = True, n_samples: int = 1500):

        solution = solution.lower()
        samples = None

        if pv is None:
            if solution == 'local':
                pv = self._local_minimization.x
            elif solution in ('de', 'global'):
                solution = 'global'
                pv = self.de.minimum_location
            elif solution in ('mcmc', 'mc'):
                solution = 'mcmc'
                samples = self.posterior_samples(derived_parameters=False)
                samples = permutation(samples.values)[:n_samples]
                pv = median(samples, 0)
            else:
                raise NotImplementedError("'solution' should be either 'local', 'global', or 'mcmc'")

        nlc = self.nlc - self._stess
        nrow = int(ceil(nlc / ncol))

        if axes is None:
            fig, axs = subplots(nrow, ncol, figsize=figsize, sharex='all', sharey='all', squeeze=False)
        else:
            fig, axs = None, axes

        [ax.autoscale(enable=True, axis='x', tight=True) for ax in axs.flat]

        if remove_baseline:
            if solution == 'mcmc':
                fbasel = median(self.baseline(samples), axis=0)
                fmodel, fmodm, fmodp = percentile(self.transit_model(samples), [50, 0.5, 99.5], axis=0)
            else:
                fbasel = squeeze(self.baseline(pv))
                fmodel, fmodm, fmodp = squeeze(self.transit_model(pv)), None, None
            fobs = self.ofluxa / fbasel
        else:
            if solution == 'mcmc':
                fbasel = median(self.baseline(samples), axis=0)
                fmodel, fmodm, fmodp = percentile(self.flux_model(samples), [50, 1, 99], axis=0)
            else:
                fbasel = squeeze(self.baseline(pv))
                fmodel, fmodm, fmodp = squeeze(self.flux_model(pv)), None, None
            fobs = self.ofluxa

        etess = self._stess
        t0, p = pv[[0, 1]]

        for i in range(nlc):
            ax = axs.flat[i]
            sl = self.lcslices[etess + i]
            t = self.times[etess + i]
            e = epoch(t.mean(), t0, p)
            tc = t0 + e * p
            tt = 24 * (t - tc)
            ax.plot(tt, fobs[sl], 'k.', alpha=0.2)
            ax.plot(tt, fmodel[sl], 'k')

            if solution == 'mcmc':
                ax.fill_between(tt, fmodm[sl], fmodp[sl], zorder=-100, alpha=0.2, fc='k')

            if not remove_baseline:
                ax.plot(tt, fbasel[sl], 'k--', alpha=0.2)

        setp(axs, xlim=xlim, ylim=ylim)
        setp(axs[-1, :], xlabel='Time - T$_c$ [h]')
        setp(axs[:, 0], ylabel='Normalised flux')

        if fig is not None:
            fig.tight_layout()
        return fig
예제 #9
0
class TMLPF(LinearModelBaseline, PhysContLPF):
    def __init__(self, name: str, tess_baseline_duration: float = 0.1, tess_transit_duration: float = 0.04,
                 use_ldtk: bool = False):

        times_t, fluxes_t, pbs_t, wns_t = read_tess(tess_file, zero_epoch.n, period.n,
                                                    baseline_duration_d=tess_baseline_duration,
                                                    transit_duration_d=tess_transit_duration)
        times_m, fluxes_m, pbs_m, wns_m, covs_m = read_m2(reduced_m2_files)
        times_l, fluxes_l, pbs_l, wns_l, covs_l = read_lco_data()

        times = times_t + times_m + times_l
        fluxes= fluxes_t + fluxes_m + fluxes_l
        pbs = pbs_t + pbs_m + pbs_l
        wns = wns_t + wns_m + wns_l
        covs = len(times_t)*[array([[]])] + covs_m + covs_l

        self._stess = len(times_t)
        self._ntess = sum([t.size for t in times_t])

        pbnames = 'tess g r i z_s'.split()
        pbids = pd.Categorical(pbs, categories=pbnames).codes
        #wnids = concatenate([zeros(len(times_t), 'int'), arange(1, 13)])
        wnids = arange(len(times))

        self.wns = wns

        PhysContLPF.__init__(self, name, passbands=pbnames, times=times, fluxes=fluxes, pbids=pbids, wnids=wnids,
                             covariates=covs)
        self.result_dir = Path('results')

        self.set_prior('zero_epoch', NP(zero_epoch.n, zero_epoch.s))
        self.set_prior('period', NP(period.n, period.s))
        self.set_prior('k2_app', UP(0.12 ** 2, 0.30 ** 2))
        self.set_prior('teff_h', NP(3250, 140))

        if use_ldtk:
            self.add_ldtk_prior(star_teff, star_logg, star_z, (tess, sdss_g, sdss_r, sdss_i, sdss_z))


    def _init_p_planet(self):
        ps = self.ps
        pk2 = [PParameter('k2_app', 'apparent_area_ratio', 'A_s', UP(0.1**2, 0.30**2), (0.1**2, 0.30**2))]
        pcn = [GParameter('k2_true', 'true_area_ratio', 'As', UP(0.1**2, 0.75**2), bounds=(1e-8, inf)),
               GParameter('teff_h', 'host_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('teff_c', 'contaminant_teff', 'K', UP(2500, 12000), bounds=(2500, 12000)),
               GParameter('k2_app_tess', 'tess_apparent_area_ratio', 'A_s', UP(0.1**2, 0.30**2), (0.1**2, 0.3**2))]
        ps.add_passband_block('k2', 1, 1, pk2)
        self._pid_k2 = repeat(ps.blocks[-1].start, self.npb)
        self._start_k2 = ps.blocks[-1].start
        self._sl_k2 = ps.blocks[-1].slice
        ps.add_global_block('contamination', pcn)
        self._pid_cn = arange(ps.blocks[-1].start, ps.blocks[-1].stop)
        self._sl_cn = ps.blocks[-1].slice

    def create_pv_population(self, npop=50):
        pvp = zeros((0, len(self.ps)))
        npv, i = 0, 0
        while npv < npop and i < 10:
            pvp_trial = self.ps.sample_from_prior(npop)
            pvp_trial[:, 5] = pvp_trial[:, 4]
            cref = uniform(0, 0.99, size=npop)
            pvp_trial[:, 5] = pvp_trial[:, 4] / (1. - cref)
            lnl = self.lnposterior(pvp_trial)
            ids = where(isfinite(lnl))
            pvp = concatenate([pvp, pvp_trial[ids]])
            npv = pvp.shape[0]
            i += 1
        pvp = pvp[:npop]
        return pvp

    def additional_priors(self, pv):
        """Additional priors."""
        pv = atleast_2d(pv)
        return sum([f(pv) for f in self.lnpriors], 0)

    def _init_instrument(self):
        """Set up the instrument and contamination model."""
        self.instrument = Instrument('example', [sdss_g, sdss_r, sdss_i, sdss_z])
        self.cm = SMContamination(self.instrument, "i'")
        self.lnpriors.append(lambda pv: where(pv[:, 4] < pv[:, 5], 0, -inf))
        self.lnpriors.append(lambda pv: where(pv[:, 8] < pv[:, 5], 0, -inf))

    def transit_model(self, pvp):
        pvp = atleast_2d(pvp)
        cnt = zeros((pvp.shape[0], self.npb))
        pvt = map_pv_pclpf(pvp)
        ldc = map_ldc(pvp[:, self._sl_ld])
        flux = self.tm.evaluate_pv(pvt, ldc)
        cnt[:, 0] = 1 - pvp[:, 8] / pvp[:, 5]
        for i, pv in enumerate(pvp):
            if (2500 < pv[6] < 12000) and (2500 < pv[7] < 12000):
                cnref = 1. - pv[4] / pv[5]
                cnt[i, 1:] = self.cm.contamination(cnref, pv[6], pv[7])
            else:
                cnt[i, 1:] = -inf
        return contaminate(flux, cnt, self.lcids, self.pbids)

    def plot_folded_tess_transit(self, method='de', pv=None, figsize=None, ylim=None):
        assert method in ('de', 'mc')
        if pv is None:
            if method == 'de':
                pv = self.de.minimum_location
            else:
                df = self.posterior_samples(derived_parameters=False)
                pv = df.median.values

        etess = self._ntess
        t = self.timea[:etess]
        fo = self.ofluxa[:etess]
        fm = squeeze(self.transit_model(self.de.population))[self.de.minimum_index, :etess]
        bl = squeeze(self.baseline(self.de.population))[self.de.minimum_index, :etess]

        fig, ax = subplots(figsize=figsize)
        phase = pv[1] * (fold(t, pv[1], pv[0], 0.5) - 0.5)
        sids = argsort(phase)
        phase = phase[sids]
        bp, bf, be = downsample_time(phase, (fo / bl)[sids], 4 / 24 / 60)
        ax.plot(phase, (fo / bl)[sids], 'k.', alpha=0.2)
        ax.errorbar(bp, bf, be, fmt='ko')
        ax.plot(phase, fm[sids], 'k')
        setp(ax, ylim=ylim, xlabel='Time', ylabel='Normalised flux')
        return fig

    def plot_m2_transits(self, figsize=(14, 5)):
        fig, axs = subplots(3, 4, figsize=figsize, constrained_layout=True, sharex='all', sharey='all')
        fmodel = squeeze(self.flux_model(self.de.population))[self.de.minimum_index]
        etess = self._stess
        t0, p = self.de.minimum_location[[0,1]]

        for i, ax in enumerate(axs.T.flat):
            t = self.times[etess + i]
            e = epoch(t.mean(), t0, p)
            tc = t0 + e * p
            ax.plot(t - tc, self.fluxes[etess + i], 'k.', alpha=0.2)
            ax.plot(t - tc, fmodel[self.lcslices[etess + i]], 'k')
            setp(ax, xlim=(-0.045, 0.045))


        setp(axs, ylim=(0.92, 1.05))
        setp(axs[-1, :], xlabel='Time [BJD]')
        setp(axs[:, 0], ylabel='Normalised flux')
        return fig