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 _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))
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)
def _init_instrument(self): self.instrument = Instrument('MuSCAT2', [sdss_g, sdss_r, sdss_i, sdss_z]) self.cm = SMContamination(self.instrument, "i'")
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
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
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))
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
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