def add_transits(self,planet_parameters,planet_name='b'): self.params = planet_parameters self.transits = True if not hasattr(self,'flux_transits'+planet_name): t0 = self.params[0] #mid-transit time p = self.params[1] #orbital period b = self.params[2] #impact parameter rho = self.params[3] #stellar density in cgs rp = self.params[4] #scaled radius ldc = [self.params[5],self.params[6]] #LDC #Get the semi-major axis from the stellar density G_SI = 6.67408e-11 #SI rho = 1e3*rho #Go from cgs to SI a = (rho*(p*24*3600)**2*G_SI/3./np.pi)**(1./3.) #Get the inclination angle from the impact parameter inc = np.arccos(b/a) #Let us use PyTransit to compute the transits tm = QuadraticModel(interpolate=False) tm.set_data(self.time) flux = tm.evaluate(k=rp, ldc=ldc, t0=t0, p=p, a=a, i=inc) #Set attribute to the class setattr(self,'flux_transits'+planet_name,flux) #self.flux = self.flux * self.flux_transits self.flux = self.flux * getattr(self,'flux_transits'+planet_name)
def __init__(self, target: str, datasets: M2LCSet, filters: tuple, model='pb_independent_k', use_oec: bool = False, period: float = 5.): assert (model in self.models), 'Model must be one of:\n\t' + ', '.join(self.models) self.model = model self.datasets = datasets self.use_oec = use_oec self.planet = None if datasets is not None: super().__init__(target, filters, datasets.btimes, datasets.bfluxes, datasets.bwn, datasets.pbids, datasets.bcovariates, tm = QuadraticModel(interpolate=True, klims=(0.01, 0.75), nk=512, nz=512)) # Read the planet parameters from the OEC # --------------------------------------- if self.use_oec: with warnings.catch_warnings(): warnings.simplefilter('ignore') import exodata exocat = exodata.OECDatabase(join(split(__file__)[0], '../ext/oec/systems/')) self.planet = exocat.searchPlanet(target) p = self.planet.P if self.planet else period t0 = datasets[0].time.mean() if datasets is not None else 0.0 tce = datasets[0].time.ptp() / 10 if datasets is not None else 1e-5 self.set_prior(0, N(t0, tce)) self.set_prior(1, N( p, 1e-5))
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 test_evaluate_pvd(self): tm = QuadraticModel(interpolate=False) tm.set_data(self.time) pvp = array([[0.12, 0.00, 1.0, 3.0, 0.500*pi, 0.0, 0.0], [0.11, 0.01, 0.9, 2.9, 0.495*pi, 0.0, 0.0]]) ldc = [[0.1, 0.2],[0.3, 0.1]] flux = tm.evaluate_pv(pvp[0], ldc[0]) assert flux.ndim == 1 assert flux.size == self.time.size ldc = [[0.1, 0.2],[0.3, 0.1]] flux = tm.evaluate_pv(pvp, ldc) assert flux.ndim == 2 assert flux.shape == (2, self.time.size)
def get_light_curve(self, planet_sed, wavelength, timegrid, t0, trinsit_is_primary = True, apply_phase_curve = False): """ get_light_curve Calculate light curve models based on Mandel & MandelAgol Parameters ---------- planet_sed : array the planet CR wavelength : array wavelength corresponding to the input CR timegrid : array like the timegrid array (units of days) used to generate lightcurves t0 : scalar The time at mid-transit in days trinsit_is_primary : boolean True for primary transit Returns ------- lc : 2D array dim=0 contains the wavelength dependence dim=1 contains the time dependence z : array Normalised centre-centre distance i0, i1 : scalars index of first and last contact (assuming max contrast ratio) """ ##TODO REMOVE useNewCode and entire block when ready useNewCode = True setLdCoeffsToZero = not(trinsit_is_primary) isEclipse = not(trinsit_is_primary) u = self.ldCoeffs.getCoeffs(self.planet.star.T, wavelength, forceZero=setLdCoeffsToZero) self.u = u ## required for outputing into fits file at the end m = QuadraticModel(is_secondary=isEclipse, klims=(0,1)) m.set_data(timegrid.rescale(aq.day).magnitude) # m = pytransit.MandelAgol(eclipse=isEclipse ) # z = m._calculate_z(timegrid.rescale(aq.day).magnitude, # t0.rescale(aq.day), # self.planet.P.rescale(aq.day), # self.planet.a/self.planet.star.R.rescale(self.planet.a.units), # self.planet.i.rescale(aq.radians), # self.planet.e, # 0.0) lc = np.zeros( (planet_sed.size, timegrid.size) ) k2 = (self.planet.R.rescale(aq.m)/ self.planet.a.rescale(aq.m))**2 albedo = self.planet.albedo def apply_mandel_primary(i): # lc[i, ...] = m(z, np.sqrt(planet_sed[i]), u[i, ...]) + phase_function * (k2 * albedo) * apply_phase_curve lc[i, ...] = m.evaluate_ps(np.sqrt(planet_sed[i]), u[i, ...], t0.rescale(aq.day), self.planet.P.rescale(aq.day), self.planet.a/self.planet.star.R.rescale(self.planet.a.units), self.planet.i.rescale(aq.radians), self.planet.e, 0.0) + phase_function * (k2 * albedo) * apply_phase_curve def apply_mandel_secondary(i): # f_e = (planet_sed[i] + (m(z, np.sqrt(planet_sed[i]), u[i, ...])-1.0))/planet_sed[i] # dtmp = phase_function * (k2 *albedo + planet_sed[i]) if apply_phase_curve else planet_sed[i] # lc[i, ...] = 1.0 + f_e*dtmp f_e = (planet_sed[i] + (m.evaluate_ps(np.sqrt(planet_sed[i]), u[i, ...], t0.rescale(aq.day), self.planet.P.rescale(aq.day), self.planet.a/self.planet.star.R.rescale(self.planet.a.units), self.planet.i.rescale(aq.radians), self.planet.e, 0.0)-1.0))/planet_sed[i] if apply_phase_curve: dtmp = phase_function * (k2 * albedo + planet_sed[i]) else: dtmp = planet_sed[i] lc[i, ...] = 1.0 + f_e * dtmp if trinsit_is_primary: #phaseFactor1 = 1 #phaseFactor2 = -1 useMandelFunction = apply_mandel_primary phi = np.pi # phase in transit is pi for primari, zero for secondary else: #phaseFactor1 = 0 #phaseFactor2 = 1 useMandelFunction = apply_mandel_secondary phi = 0.0 alpha = 2*np.pi*( timegrid.rescale(aq.day) - t0.rescale(aq.day) ) / \ self.planet.P.rescale(aq.day) + phi ### Old - coded by Andreas # phase_function = (phaseFactor1 + phaseFactor2 * np.cos(alpha)) ### Lambert shpere, Seager's Exoplanet Atmospheres, eq. 3.58 # phase_function = (np.sin(np.abs(alpha)) + (np.pi-np.abs(alpha))*np.cos(alpha))/np.pi ### Enzo's simple projection - this is the fraction of the dayside observed phase_function = (1+np.cos(alpha))/2.0 # Calculate z (PyTransit no longer does this) # Assumes planet moves at a constant velocity (no eccentricity) # Calculate y component (impact parameter) z_y = self.planet.a.rescale(self.planet.star.R.units) / self.planet.star.R \ * np.sin(np.pi/2 - self.planet.i.rescale(aq.radians)) # Calculate distance of chord traveled d = 2 * (((self.planet.R.rescale(self.planet.star.R.units) + \ self.planet.star.R) \ / self.planet.star.R)**2 - z_y**2)**0.5 # Velocity of planet across chord v = d / self.t14.rescale(aq.day) # X component of z as a function of time z_x = v * (timegrid.rescale(aq.day) - t0.rescale(aq.day)) # Total z vector as a function of time z = (z_x**2 + z_y**2)**0.5 #map(useMandelFunction, np.arange(lc.shape[0]) ) for i in np.arange(lc.shape[0]): useMandelFunction(i) z_12 = 1.0+planet_sed.max() idx = np.where(z < z_12) return lc, z, idx[0], idx[-1]
def __init__(self, target: str, photometry: list, tid: int, cids: list, filters: tuple, aperture_lims: tuple = (0, inf), use_opencl: bool = False, n_legendre: int = 0, use_toi_info=True, with_transit=True, with_contamination=False, radius_ratio: str = 'achromatic'): assert radius_ratio in ('chromatic', 'achromatic') self.use_opencl = use_opencl self.planet = None self.photometry_frozen = False self.with_transit = with_transit self.with_contamination = with_contamination self.chromatic_transit = radius_ratio == 'chromatic' self.radius_ratio = radius_ratio self.n_legendre = n_legendre self.toi = None if self.with_transit and 'toi' in target.lower() and use_toi_info: self.toi = get_toi(float(target.lower().strip('toi'))) # Set photometry # -------------- self.phs = photometry self.nph = len(photometry) # Set the aperture ranges # ----------------------- self.min_apt = amin = min(max(aperture_lims[0], 0), photometry[0].flux.aperture.size) self.max_apt = amax = max( min(aperture_lims[1], photometry[0].flux.aperture.size), 0) self.napt = amax - amin # Target and comparison star IDs # ------------------------------ self.tid = atleast_1d(tid) if self.tid.size == 1: self.tid = tile(self.tid, self.nph) self.cids = atleast_2d(cids) if self.cids.shape[0] == 1: self.cids = tile(self.cids, (self.nph, 1)) assert self.tid.size == self.nph assert self.cids.shape[0] == self.nph self.covnames = 'intercept sky airmass xshift yshift entropy'.split() times = [array(ph.bjd) for ph in photometry] fluxes = [ array(ph.flux[:, tid, 1]) for tid, ph in zip(self.tid, photometry) ] fluxes = [f / nanmedian(f) for f in fluxes] self.apertures = ones(len(times)).astype('int') self.t0 = floor(times[0].min()) times = [t - self.t0 for t in times] self._tmin = times[0].min() self._tmax = times[0].max() covariates = [] for ph in photometry: covs = concatenate( [ones([ph._fmask.sum(), 1]), array(ph.aux)[:, [1, 3, 4, 5]]], 1) covariates.append(covs) self.airmasses = [array(ph.aux[:, 2]) for ph in photometry] wns = [ones(ph.nframes) for ph in photometry] if use_opencl: import pyopencl as cl ctx = cl.create_some_context() queue = cl.CommandQueue(ctx) tm = QuadraticModelCL(klims=(0.005, 0.25), nk=512, nz=512, cl_ctx=ctx, cl_queue=queue) else: tm = QuadraticModel(interpolate=True, klims=(0.005, 0.25), nk=512, nz=512) super().__init__(target, filters, times, fluxes, wns, arange(len(photometry)), covariates, arange(len(photometry)), tm=tm) self.legendre = [ legvander((t - t.min()) / (0.5 * t.ptp()) - 1, self.n_legendre)[:, 1:] for t in self.times ] # Create the target and reference star flux arrays # ------------------------------------------------ self.ofluxes = [ array(ph.flux[:, self.tid[i], amin:amax + 1] / ph.flux[:, self.tid[i], amin:amax + 1].median('mjd')) for i, ph in enumerate(photometry) ] self.refs = [] for ip, ph in enumerate(photometry): self.refs.append([ pad(array(ph.flux[:, cid, amin:amax + 1]), ((0, 0), (1, 0)), mode='constant') for cid in self.cids[ip] ]) self.set_orbit_priors()
import numpy as np from astropy import constants from pytransit import QuadraticModel Msun = constants.M_sun.cgs.value Rsun = constants.R_sun.cgs.value Rearth = constants.R_earth.cgs.value G = constants.G.cgs.value au = constants.au.cgs.value pi = np.pi tm = QuadraticModel(interpolate=False) def simulate_TP_transit(time: np.ndarray, R_p: float, P_orb: float, inc: float, a: float, R_s: float, u1: float, u2: float, companion_fluxratio: float = 0.0, companion_is_host: bool = False): """ Simulates a transiting planet light curve using PyTransit. Args: time (numpy array): Time of each data point [days from transit midpoint]. R_p (float): Planet radius [Earth radii]. P_orb (float): Orbital period [days].
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 get_light_curve(opt, planet_sed, wavelength, obs_type): wavelength = wavelength.value timegrid = opt.z_params[0] t0 = opt.z_params[1] per = opt.z_params[2] ars = opt.z_params[3] inc = opt.z_params[4] ecc = opt.z_params[5] omega = opt.z_params[6] if opt.observation.obs_type.val == 2: opt.timeline.useLDC.val = 0 if opt.timeline.useLDC.val == 0: # linear ldc jexosim_msg('LDCs set to zero', 1) u0 = np.zeros(len(wavelength)) u1 = np.zeros(len(wavelength)) ldc = np.vstack((wavelength, u0, u1)) elif opt.timeline.useLDC.val == 1: # use to get ldc from filed values u0, u1 = getLDC_interp(opt, opt.planet.planet, wavelength) ldc = np.vstack((wavelength, u0, u1)) gamma = np.zeros((ldc.shape[1], 2)) gamma[:, 0] = ldc[1] gamma[:, 1] = ldc[2] jexosim_plot('ldc', opt.diagnostics, ydata=ldc[1]) jexosim_plot('ldc', opt.diagnostics, ydata=ldc[2]) tm = QuadraticModel(interpolate=False) tm.set_data(timegrid) lc = np.zeros((len(planet_sed), len(timegrid))) if obs_type == 1: #primary transit for i in range(len(planet_sed)): k = np.sqrt(planet_sed[i]).value lc[i, ...] = tm.evaluate(k=k, ldc=gamma[i, ...], t0=t0, p=per, a=ars, i=inc, e=ecc, w=omega) jexosim_plot('light curve check', opt.diagnostics, ydata=lc[i, ...]) elif obs_type == 2: # secondary eclipse for i in range(len(planet_sed)): k = np.sqrt(planet_sed[i]) # planet star radius ratio lc_base = tm.evaluate(k=k, ldc=[0, 0], t0=t0, p=per, a=ars, i=inc, e=ecc, w=omega) jexosim_plot('light curve check', opt.diagnostics, ydata=lc_base) # f_e = (planet_sed[i] + ( lc_base -1.0))/planet_sed[i] # lc[i, ...] = 1.0 + f_e*(planet_sed[i]) lc[i, ...] = lc_base + planet_sed[i] jexosim_plot('light curve check', opt.diagnostics, ydata=lc[i, ...]) return lc, ldc
def test_evaluate_3i(self): tm = QuadraticModel(interpolate=True) tm.set_data(self.time, self.lcids, self.pbids) flux = tm.evaluate(self.radius_ratios[0], self.ldc[0], self.zero_epochs[0], self.periods[0], self.smas[0], self.inclinations[0]) assert flux.ndim == 1 assert flux.size == self.time.size
def test_set_data(self): tm = QuadraticModel(interpolate=False) tm.set_data(self.time) assert tm.npb == 1 tm.set_data(self.time, lcids=self.lcids) assert tm.npb == 1 tm.set_data(self.time, lcids=self.lcids, pbids=self.pbids) assert tm.npb == 2 tm = QuadraticModel(interpolate=True) tm.set_data(self.time) assert tm.npb == 1 tm.set_data(self.time, lcids=self.lcids) assert tm.npb == 1 tm.set_data(self.time, lcids=self.lcids, pbids=self.pbids) assert tm.npb == 2
def test_init(self): QuadraticModel() QuadraticModel(interpolate=True) QuadraticModel(interpolate=False)
def test_evaluate_psd(self): tm = QuadraticModel(interpolate=False) tm.set_data(self.time) flux = tm.evaluate(0.1, [0.2, 0.3], 0.0, 1.0, 3.0, 0.5*pi) assert flux.ndim == 1 assert flux.size == self.time.size
G = 6.674e-11 period_seconds = period * 24. * 3600. mass_kg = star_mass * 2.e30 a1 = (G * mass_kg * period_seconds**2 / 4. / (np.pi**2))**(1. / 3.) return a1 / 1.496e11 a_au = calculate_semi_major_axis(0.5, M_s) a_Rs = a_au / (R_s * 0.00465047) # TODO start with rp_rs that causes twice depth than curve RMS curve_rms = np.std(flux) min_depth = 2 * curve_rms initial_rp = (min_depth * (R_s**2))**(1 / 2) rp_rs = initial_rp / R_s from pytransit import QuadraticModel tm = QuadraticModel() time_model = np.arange(0, 1, 0.0001) tm.set_data(time_model) # k is the radius ratio, ldc is the limb darkening coefficient vector, t0 the zero epoch, p the orbital period, a the # semi-major axis divided by the stellar radius, i the inclination in radians, e the eccentricity, and w the argument # of periastron. Eccentricity and argument of periastron are optional, and omitting them defaults to a circular orbit. model = tm.evaluate(k=rp_rs, ldc=ld_coefficients, t0=0.5, p=1.0, a=a_Rs, i=0.5 * np.pi) model = model[model < 1] baseline_model = np.full(len(model), 1) model = np.append(baseline_model, model) model = np.append(model, baseline_model)
def __call__(self, npop: int = 40, de_niter: int = 1000, mcmc_niter: int = 200, mcmc_repeats: int = 3, initialize_only: bool = False): self.logger = getLogger(f"{self.name}:{self.ts.name.lower().replace('_','-')}") self.logger.info(f"Fitting {self.mode} transits") self.ts.transit_fits[self.mode] = self epochs = epoch(self.ts.time, self.ts.zero_epoch, self.ts.period) if self.mode == 'all': mask = ones(self.ts.time.size, bool) elif self.mode == 'even': mask = epochs % 2 == 0 elif self.mode == 'odd': mask = epochs % 2 == 1 else: raise NotImplementedError mask &= abs(self.ts.phase - 0.5*self.ts.period) < 4 * 0.5 * self.ts.duration self.ts.transit_fit_masks[self.mode] = self.mask = mask self.epochs = epochs = epochs[mask] self.time = self.ts.time[mask] self.fobs = self.ts.flux[mask] tref = floor(self.time.min()) tm = QuadraticModelCL(klims=(0.01, 0.60)) if self.use_opencl else QuadraticModel(interpolate=False) self.lpf = lpf = SearchLPF(times=self.time, fluxes=self.fobs, epochs=epochs, tm=tm, nsamples=self.nsamples, exptimes=self.exptime, tref=tref) # TODO: V-shaped transits are not always modelled well. Need to set smarter priors (or starting population) # for the impact parameter and stellar density. lpf.set_prior('rho', 'UP', 0.01, 25) if self.mode == 'all': d = min(self.ts.depth, 0.75) lpf.set_prior('tc', 'NP', self.ts.zero_epoch, 0.01) lpf.set_prior('p', 'NP', self.ts.period, 0.001) lpf.set_prior('k2', 'UP', max(0.01**2, 0.5*d), min(max(0.08**2, 4*d), 0.75**2)) else: pr = self.ts.tf_all.parameters lpf.set_prior('tc', 'NP', pr.tc.med, 5*pr.tc.err) lpf.set_prior('p', 'NP', pr.p.med, pr.p.err) lpf.set_prior('k2', 'UP', max(0.01**2, 0.5 * pr.k2.med), max(0.08**2, min(0.6**2, 2 * pr.k2.med))) lpf.set_prior('q1', 'NP', pr.q1.med, pr.q1.err) lpf.set_prior('q2', 'NP', pr.q2.med, pr.q2.err) # TODO: The limb darkening table has been computed for TESS. Needs to be made flexible. if self.ts.teff is not None: ldcs = Table.read(Path(__file__).parent / "data/ldc_table.fits").to_pandas() ip = interp1d(ldcs.teff, ldcs[['q1', 'q2']].T) q1, q2 = ip(clip(self.ts.teff, 2000., 12000.)) lpf.set_prior('q1', 'NP', q1, 1e-5) lpf.set_prior('q2', 'NP', q2, 1e-5) if initialize_only: return else: lpf.optimize_global(niter=de_niter, npop=npop, use_tqdm=self.use_tqdm, plot_convergence=False) lpf.sample_mcmc(mcmc_niter, repeats=mcmc_repeats, use_tqdm=self.use_tqdm, leave=False) df = lpf.posterior_samples(derived_parameters=True) df = pd.DataFrame((df.median(), df.std()), index='med err'.split()) pv = lpf.posterior_samples(derived_parameters=False).median().values self.phase = fold(self.time, pv[1], pv[0], 0.5) * pv[1] - 0.5 * pv[1] self.fmod = lpf.flux_model(pv) self.ftra = lpf.transit_model(pv) self.fbase = lpf.baseline(pv) # Calculate the per-orbit log likelihood differences # -------------------------------------------------- ues = unique(epochs) lnl = zeros(ues.size) err = 10 ** pv[7] def lnlike_normal(o, m, e): npt = o.size return -npt * log(e) - 0.5 * npt * log(2. * pi) - 0.5 * sum((o - m) ** 2 / e ** 2) for i, e in enumerate(ues): m = epochs == e lnl[i] = lnlike_normal(self.fobs[m], self.fmod[m], err) - lnlike_normal(self.fobs[m], 1.0, err) self.parameters = df self.dll_epochs = ues self.dll_values = lnl self.zero_epoch = df.tc.med self.period = df.p.med self.duration = df.t14.med self.depth = df.k2.med if self.mode == 'all': self.delta_bic = self.ts.dbic = delta_bic(lnl.sum(), 0, 9, self.time.size) self.ts.update_ephemeris(self.zero_epoch, self.period, self.duration, self.depth)
def add_transits(self,pars,ldc): """ This method includes the planets to the instance detrending It assumes all orbits are circular pars -> [T0, P, a/R*,b, Rp/R*] x Number of planets ldc -> u1, u2 """ #Initialise the planet-related fluxes #this attribute contains only the planetary models for each self.time self.flux_planet = np.ones(len(self.time)) #this attribute contains only the planetary models for each self.time_bin self.flux_planet_bin = np.ones(len(self.time_bin)) #this attribute contains only the planetary models for each self.time_model self.flux_planet_model = np.ones(len(self.time_model)) #Add parameters to the class #This attribute constains all the parameters for all the planets self.planet_pars = pars #this attribute constains the limb darkening coefficients following a Mandel & Agol model self.ldc = ldc #number of planets to be added npl = int(len(pars)/5) #Save the number of planets as an attribute self.nplanets = npl #We compute the model with pytransit for self.time tm = QuadraticModel() tm.set_data(self.time) #We compute the model with pytransit for self.time_bin tm_bin = QuadraticModel() tm_bin.set_data(self.time_bin) #We compute the model with pytransit for self.time_model tm_model = QuadraticModel() tm_model.set_data(self.time_model) #Compute the models for all the time-series for i in range(npl): incl = np.arccos(pars[3+5*i]/pars[2+5*i]) self.flux_planet *= tm.evaluate(t0=pars[0+5*i], p=pars[1+5*i], a=pars[2+5*i], i=incl,k=pars[4+5*i], ldc=ldc) self.flux_planet_bin *= tm_bin.evaluate(t0=pars[0+5*i], p=pars[1+5*i], a=pars[2+5*i], i=incl,k=pars[4+5*i], ldc=ldc) self.flux_planet_model *= tm_model.evaluate(t0=pars[0+5*i], p=pars[1+5*i], a=pars[2+5*i], i=incl,k=pars[4+5*i], ldc=ldc) #Remove the planet model from the no_planet and no_planet_bin models in order to have a light curve with no planets self.flux_no_planet = self.flux / self.flux_planet self.flux_no_planet_bin = self.flux_bin / self.flux_planet_bin