def manual_fitting(tic_id, sector, days, flux, t0_guess, period_guess, star_radius, star_mass, x_fold): with pm.Model() as model: lower_log = np.log(np.std(flux)) - 1 logs = pm.Uniform("logs", lower=lower_log, upper=0, testval=np.log(np.std(flux))) mean_flux = pm.Normal("mean_flux", mu=0, sd=np.std(flux)) u = xo.distributions.QuadLimbDark("u") period = pm.Uniform("period", lower=period_guess * 0.9, upper=period_guess * 1.1, testval=period_guess) t0 = pm.Uniform("t0", lower=t0_guess - 0.2, upper=t0_guess + 0.2) r, b = xo.distributions.get_joint_radius_impact(min_radius=0.0005, max_radius=0.5, testval_r=0.015) orbit = xo.orbits.KeplerianOrbit(period=period, t0=t0, b=b, r_star=star_radius, m_star=star_mass) # The light curve model is computed using "starry" star = xo.StarryLightCurve(u) light_curve = star.get_light_curve(orbit=orbit, r=r, t=days) # The returned light curve will always have the shape (ntime, nplanet) # but we only have one planet so we can "squeeze" the result # 1e2 it is because it's the percentage. light_curve = tt.squeeze(star.get_light_curve( orbit=orbit, r=r, t=days)) * 1e2 + mean_flux # Finally, this is the likelihoood for the observations pm.Normal("obs", mu=light_curve, sd=tt.exp(logs), observed=flux) with model: transit_model = xo.utils.eval_in_model(light_curve) inds = np.argsort(x_fold) p = plotting_folded(days, flux, tic_id, sector, x_fold) p.line(x_fold[inds], transit_model[inds], legend="initial model", line_width=3, line_alpha=0.6, line_color="black") # output_file("test.html", title="test.py example") show(p) return model, light_curve
def _build_model(self, gp_timescale_prior=10, fractional_prior_width=10): time = np.asarray(self.lc.time, np.float64) lc_flux = np.asarray(self.lc.flux, np.float64) lc_flux_err = np.asarray(self.lc.flux_err, np.float64) # Covariance matrix diagonal with pm.Model() as model: mean = pm.Normal("mean", mu=np.nanmean(lc_flux), sd=np.nanstd(lc_flux)) # Star Priors # --------------------- M_star = pm.Normal("M_star", mu=self.host.mass.value, sd=self.host.mass_error[1]) R_star = pm.Normal("R_star", mu=self.host.radius.value, sd=self.host.radius_error[1]) T_star = pm.Normal("T_star", mu=self.host.temperature.value, sd=self.host.temperature_error[1]) # EB Model # --------------------- rprs = pm.Normal("rprs", mu=self.planet.rprs, sd=self.planet.rprs_error[1]) pm.Potential("rprs_prior", tt.switch(rprs > 0, 0, np.inf)) logP = pm.Normal("logP", mu=np.log(self.planet.period.value), sd=0.01) period = pm.Deterministic("period", pm.math.exp(logP)) t0 = pm.Normal("t0", mu=self.planet.t0, sd=self.planet.t0_error[1]) r = pm.Deterministic("r", rprs * R_star) logr = pm.Deterministic("logr", tt.log(rprs * R_star)) inclination = pm.Normal("inclination", mu=self.planet.inclination, sd=self.planet.inclination_error[1]) pm.Potential("r_prior", -logr) albedo = pm.Uniform("albedo", lower=0, upper=1) # Transit transit_orbit = xo.orbits.KeplerianOrbit(period=period, t0=t0, incl=inclination) u = xo.distributions.QuadLimbDark("u", testval=np.asarray([0.4, 0.3])) transit = xo.StarryLightCurve(u).get_light_curve( orbit=transit_orbit, r=r, t=time) transit = pm.math.sum(transit, axis=-1) # Secondary Eclipse eclipse_orbit = xo.orbits.KeplerianOrbit(period=period, t0=t0 + period/2, incl=inclination) eclipse = xo.StarryLightCurve([0, 0]).get_light_curve( orbit=eclipse_orbit, r=r, t=time) eclipse = pm.math.sum(eclipse, axis=-1) # Reflection re = pm.Deterministic('re', albedo * (rprs/transit_orbit.a)**2) reflection = -re * tt.cos(2 * np.pi * ((time - t0) / period)) + re reflection += ((eclipse)/r**2) * (2 * re)# + (2 * re) # Thermal teq = pm.Deterministic('teq', T_star * tt.sqrt(0.5*(1/transit_orbit.a))) norm = pm.Deterministic("norm", tt.sum(blackbody_theano(bandpass[:, 0], teq) * bandpass[:, 1])/self.host.norm) thermal = ((eclipse)/r**2) * norm + norm dT = pm.Uniform('dT', lower=0, upper=1000) phase_shift = pm.Normal('phase_shift', mu=0, sd=0.1) A1 = ((dT)**4/teq**4) thermal_cosine = -(A1 * norm) * tt.cos(2 * np.pi * ((time - t0) / period) + phase_shift) - (A1 * norm) thermal += thermal_cosine pm.Deterministic('thermal_cosine', thermal_cosine) # Doppler dp = pm.Uniform('dp', lower=0, upper=0.0001) doppler = pm.Deterministic('doppler', dp * np.sin((2 * np.pi * (time-t0))/(period))) # Elipsoidal ep = pm.Uniform('ep', lower=0, upper=0.0001) elipsoidal = pm.Deterministic('elipsoidal', -ep * np.cos((2 * np.pi * (time-t0))/(0.5 * period))) # Build the light curve eb_model = transit + reflection + thermal + doppler + elipsoidal eb_model = ((eb_model + 1)/(1 + norm + (2 * re))) eb_model *= mean # GP and Motion Fitting # --------------------- # Create a Gaussian Process to model the long-term stellar variability # log(sigma) is the amplitude of variability, estimated from the raw flux scatter logsigma = pm.Normal("logsigma", mu=np.log(np.std(lc_flux)), sd=3) # log(rho) is the timescale of variability with a user-defined prior logrho = pm.Normal("logrho", mu=np.log(gp_timescale_prior), sd=np.log(fractional_prior_width*gp_timescale_prior)) # Enforce that the scale of variability should be no shorter than 0.5 days pm.Potential("logrho_prior", tt.switch(logrho > np.log(self.planet.period.value * 1.1), 0, np.inf)) # log(s2) is a jitter term to compensate for underestimated flux errors # We estimate the magnitude of jitter from the CDPP (normalized to the flux) logs2 = pm.Normal("logs2", mu=np.log(self._logs2_prior), sd=3) kernel = xo.gp.terms.Matern32Term(log_sigma=logsigma, log_rho=logrho) # Store the GP and cadence mask to aid debugging model.gp = xo.gp.GP(kernel, time, self._diag + tt.exp(logs2)) # The motion model regresses against the design matrix A = tt.dot(self.design_matrix.T, model.gp.apply_inverse(self.design_matrix)) # To ensure the weights can be solved for, we need to perform ridge regression # to avoid an ill-conditioned matrix A. Here we define the size of the diagonal # along which we will add small values ridge = np.array(range(self.design_matrix.shape[1])) # Cast the ridge indices into tensor space ridge = tt.cast(ridge, 'int64') # Apply ridge regression by adding small numbers along the diagonal A = tt.set_subtensor(A[ridge, ridge], A[ridge, ridge] + 1e-6) # Corrected flux, with the EB model removed. cflux = np.reshape(lc_flux, (lc_flux.shape[0], 1)) cflux -= tt.reshape(eb_model, (eb_model.shape[0], 1)) B = tt.dot(self.design_matrix.T, model.gp.apply_inverse(cflux)) weights = tt.slinalg.solve(A, B) motion_model = pm.Deterministic("motion_model", tt.dot(self.design_matrix, weights)[:, 0]) pm.Deterministic("weights", weights) # Observables # --------------------- # Track Quanities pm.Deterministic("eb_model", eb_model) pm.Deterministic("thermal", thermal) pm.Deterministic("reflection", reflection) pm.Deterministic("transit", transit) # pm.Normal("obs", mu=eb_model, sd=lc_flux_err, observed=lc_flux) # Likelihood to optimize pm.Potential("obs", model.gp.log_likelihood(lc_flux - (motion_model + eb_model))) return model
def build_model(mask=None, start=None): ''' Build a PYMC3 model Parameters ---------- mask : np.ndarray Boolean array to mask cadences. Cadences that are False will be excluded from the model fit start : dict MAP Solution from exoplanet Returns ------- model : pymc3.model.Model A pymc3 model map_soln : dict Best fit solution ''' if mask is None: mask = np.ones(len(time), dtype=bool) with pm.Model() as model: # Parameters for the stellar properties mean = pm.Normal("mean", mu=0.0, sd=10.0) u_star = xo.distributions.QuadLimbDark("u_star") m_star = pm.Normal("m_star", mu=M_star[0], sd=M_star[1]) r_star = pm.Normal("r_star", mu=R_star[0], sd=R_star[1]) t_star = pm.Normal("t_star", mu=T_star[0], sd=T_star[1]) # Prior to require physical parameters pm.Potential("m_star_prior", tt.switch(m_star > 0, 0, -np.inf)) pm.Potential("r_star_prior", tt.switch(r_star > 0, 0, -np.inf)) # Orbital parameters for the planets logP = pm.Normal("logP", mu=np.log(period_value), sd=0.01, shape=shape) t0 = pm.Normal("t0", mu=t0_value, sd=0.01, shape=shape) b = pm.Uniform("b", lower=0, upper=1, testval=0.5, shape=shape) logr = pm.Normal("logr", sd=1.0, mu=0.5 * np.log(np.array(depth_value)) + np.log(R_star[0]), shape=shape) r_pl = pm.Deterministic("r_pl", tt.exp(logr)) ror = pm.Deterministic("ror", r_pl / r_star) # Tracking planet parameters period = pm.Deterministic("period", tt.exp(logP)) # Orbit model orbit = xo.orbits.KeplerianOrbit(r_star=r_star, m_star=m_star, period=period, t0=t0, b=b) incl = pm.Deterministic('incl', orbit.incl) a = pm.Deterministic('a', orbit.a) teff = pm.Deterministic('teff', t_star * tt.sqrt(0.5 * (1 / a))) # Compute the model light curve using starry light_curves = xo.StarryLightCurve(u_star).get_light_curve( orbit=orbit, r=r_pl, t=time[mask], texp=texp) * 1e3 light_curve = pm.math.sum(light_curves, axis=-1) + mean pm.Deterministic("light_curves", light_curves) # GP # -------- logs2 = pm.Normal("logs2", mu=np.log(1e-4 * np.var(raw_flux[mask])), sd=10) logsigma = pm.Normal("logsigma", mu=np.log(np.std(raw_flux[mask])), sd=10) logrho = pm.Normal("logrho", mu=np.log(150), sd=10) kernel = xo.gp.terms.Matern32Term(log_rho=logrho, log_sigma=logsigma) gp = xo.gp.GP(kernel, time[mask], tt.exp(logs2) + raw_flux_err[mask]**2) # Motion model #------------------ A = tt.dot(X_pld[mask].T, gp.apply_inverse(X_pld[mask])) B = tt.dot(X_pld[mask].T, gp.apply_inverse(raw_flux[mask, None])) C = tt.slinalg.solve(A, B) motion_model = pm.Deterministic("motion_model", tt.dot(X_pld[mask], C)[:, 0]) # Likelihood #------------------ pm.Potential("obs", gp.log_likelihood(raw_flux[mask] - motion_model)) # gp predicted flux gp_pred = gp.predict() pm.Deterministic("gp_pred", gp_pred) pm.Deterministic("weights", C) # Optimize #------------------ if start is None: start = model.test_point map_soln = xo.optimize(start=start, vars=[logrho, logsigma]) map_soln = xo.optimize(start=start, vars=[logr]) map_soln = xo.optimize(start=map_soln, vars=[logs2]) map_soln = xo.optimize(start=map_soln, vars=[logrho, logsigma, logs2, logr]) map_soln = xo.optimize(start=map_soln, vars=[mean, logr]) map_soln = xo.optimize(start=map_soln, vars=[logP, t0]) map_soln = xo.optimize(start=map_soln, vars=[b]) map_soln = xo.optimize(start=map_soln, vars=[u_star]) map_soln = xo.optimize(start=map_soln, vars=[logrho, logsigma, logs2]) map_soln = xo.optimize(start=map_soln) return model, map_soln, gp
pop_sd = pm.Deterministic('pop_sd', T.sqrt(T.exp(log_pop_var))) else: pop_sd = np.sqrt(2)*ttv_rms_amp[npl] # transit times tt_offset = pm.StudentT('tt_offset', nu=2, shape=len(fixed_ephem)) poly_omc = pm.Deterministic('poly_omc', C0*Leg0 + C1*Leg1 + C2*Leg2) omc_trend = pm.Deterministic('omc_trend', poly_omc + sin_omc) transit_times = pm.Deterministic('tts', fixed_ephem + omc_trend + tt_offset*pop_sd) # set up stellar model and planetary orbit exoSLC = exo.StarryLightCurve(u) orbit = exo.orbits.TTVOrbit(transit_times=[transit_times], transit_inds=[fixed_inds], b=b[npl], r_star=Rstar, m_star=Mstar) # track period and epoch T0 = pm.Deterministic('T0', orbit.t0) P = pm.Deterministic('P', orbit.period) # nuissance parameters (one mean flux; variance by quarter) flux0 = pm.Normal('flux0', mu=np.ones(len(wq)), sd=np.sqrt(vbq_all[wq])/4, shape=len(wq)) logvar = pm.Normal('logvar', mu=np.log(vbq_all[wq]), sd=np.log(4)*np.ones(len(wq)), shape=len(wq)) # build the GP kernel using a different noise model for each season logSw4 = [None]*4 logw0 = [None]*4
periods = [] for npl, p in enumerate(planets): use = (p.tts > tmin) * (p.tts < tmax) if np.sum(use) > 0: transit_times.append(p.tts[use]) transit_inds.append(np.arange(np.sum(use), dtype="int")) radii.append(p.radius / RSRE) impacts.append(p.impact) periods.append(p.period) # model the transits if len(transit_times) > 0: exoSLC = exo.StarryLightCurve(UCOEFFS) orbit = exo.orbits.TTVOrbit(transit_times=transit_times, transit_inds=transit_inds, period=periods, b=impacts, r_star=RSTAR, m_star=MSTAR) light_curves = exoSLC.get_light_curve(orbit=orbit, r=radii, t=xtime, oversample=1) model_flux = 1.0 + pm.math.sum(light_curves, axis=-1).eval() else: model_flux = np.ones_like(yflux)
def build_model(x, y, yerr, period_prior, t0_prior, depth, minimum_period=2, maximum_period=30, r_star_prior=5.0, t_star_prior=5000, m_star_prior=None, start=None): """Build an exoplanet model for a dataset and set of planets Paramters --------- x : array-like The time series (in days); this should probably be centered y : array-like The relative fluxes (in parts per thousand) yerr : array-like The uncertainties on ``y`` period_prior : list The literature values for periods of the planets (in days) t0_prior : list The literature values for phases of the planets in the same coordinates as `x` rprs_prior : list The literature values for the ratio of planet radius to star radius start : dict A dictionary of model parameters where the optimization should be initialized Returns: A PyMC3 model specifying the probabilistic model for the light curve """ model = BoxLeastSquares(x, y) results = model.autopower(0.16, minimum_period=minimum_period, maximum_period=maximum_period) if period_prior is None: period_prior = results.period[np.argmax(results.power)] if t0_prior is None: t0_prior = results.transit_time[np.argmax(results.power)] if depth is None: depth = results.depth[np.argmax(results.power)] period_prior = np.atleast_1d(period_prior) t0_prior = np.atleast_1d(t0_prior) # rprs_prior = np.atleast_1d(rprs_prior) with pm.Model() as model: # Set model variables model.x = np.asarray(x, dtype=np.float64) model.y = np.asarray(y, dtype=np.float64) model.yerr = np.asarray(yerr + np.zeros_like(x), dtype=np.float64) '''Stellar Parameters''' # The baseline (out-of-transit) flux for the star in ppt mean = pm.Normal("mean", mu=0.0, sd=10.0) try: r_star_mu = target_list[target_list['ID'] == ticid]['rad'].values[0] except: r_star_mu = r_star_prior if m_star_prior is None: try: m_star_mu = target_list[target_list['ID'] == ticid]['mass'].values[0] except: m_star_mu = 1.2 if np.isnan(m_star_mu): m_star_mu = 1.2 else: m_star_mu = m_star_prior r_star = pm.Normal("r_star", mu=r_star_mu, sd=1.) m_star = pm.Normal("m_star", mu=m_star_mu, sd=1.) t_star = pm.Normal("t_star", mu=t_star_prior, sd=200) rho_star_mu = ((m_star_mu*u.solMass).to(u.g) / ((4/3) * np.pi * ((r_star_mu*u.solRad).to(u.cm))**3)).value rho_star = pm.Normal("rho_star", mu=rho_star_mu, sd=.25) '''Orbital Parameters''' # The time of a reference transit for each planet t0 = pm.Normal("t0", mu=t0_prior, sd=2., shape=1) period = pm.Uniform("period", testval=period_prior, lower=minimum_period, upper=maximum_period, shape=1) b = pm.Uniform("b", testval=0.5, shape=1) # Set up a Keplerian orbit for the planets model.orbit = xo.orbits.KeplerianOrbit( period=period, t0=t0, b=b, r_star=r_star, m_star=m_star)#rho_star=rho_star) # track additional orbital parameters a = pm.Deterministic("a", model.orbit.a) incl = pm.Deterministic("incl", model.orbit.incl) '''Planet Parameters''' # quadratic limb darkening paramters u_ld = xo.distributions.QuadLimbDark("u_ld") estimated_rpl = r_star*(depth)**(1/2) # logr = pm.Normal("logr", testval=np.log(estimated_rpl), sd=1.) r_pl = pm.Uniform("r_pl", testval=estimated_rpl, lower=0., upper=1.) # r_pl = pm.Deterministic("r_pl", tt.exp(logr)) rprs = pm.Deterministic("rprs", r_pl / r_star) teff = pm.Deterministic('teff', t_star * tt.sqrt(0.5*(1/a))) # Compute the model light curve using starry model.light_curves = xo.StarryLightCurve(u_ld).get_light_curve( orbit=model.orbit, r=r_pl, t=model.x) model.light_curve = pm.math.sum(model.light_curves, axis=-1) + mean pm.Normal("obs", mu=model.light_curve, sd=model.yerr, observed=model.y) # Fit for the maximum a posteriori parameters, I've found that I can get # a better solution by trying different combinations of parameters in turn if start is None: start = model.test_point map_soln = xo.optimize(start=start, vars=[period, t0]) map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean]) map_soln = xo.optimize(start=map_soln, vars=[period, t0, mean]) map_soln = xo.optimize(start=map_soln, vars=[r_pl, mean]) map_soln = xo.optimize(start=map_soln) model.map_soln = map_soln return model
def build_model(mask=None, start=None): if mask is None: mask = np.ones(len(x), dtype=bool) with pm.Model() as model: # Parameters for the stellar properties mean = pm.Normal("mean", mu=0.0, sd=10.0) u_star = xo.distributions.QuadLimbDark("u_star") m_star = pm.Normal("m_star", mu=M_star[0], sd=M_star[1]) r_star = pm.Normal("r_star", mu=R_star[0], sd=R_star[1]) t_star = pm.Normal("t_star", mu=T_star[0], sd=T_star[1]) # Prior to require physical parameters pm.Potential("m_star_prior", tt.switch(m_star > 0, 0, -np.inf)) pm.Potential("r_star_prior", tt.switch(r_star > 0, 0, -np.inf)) # Orbital parameters for the planets logP = pm.Normal("logP", mu=np.log(period_value), sd=0.01, shape=shape) t0 = pm.Normal("t0", mu=t0_value, sd=0.01, shape=shape) b = pm.Uniform("b", lower=0, upper=1, testval=0.5, shape=shape) logr = pm.Normal("logr", sd=1.0, mu=0.5 * np.log(np.array(depth_value)) + np.log(R_star[0]), shape=shape) r_pl = pm.Deterministic("r_pl", tt.exp(logr)) ror = pm.Deterministic("ror", r_pl / r_star) # Tracking planet parameters period = pm.Deterministic("period", tt.exp(logP)) # Orbit model orbit = xo.orbits.KeplerianOrbit(r_star=r_star, m_star=m_star, period=period, t0=t0, b=b) incl = pm.Deterministic('incl', orbit.incl) a = pm.Deterministic('a', orbit.a) teff = pm.Deterministic('teff', t_star * tt.sqrt(0.5 * (1 / a))) # Compute the model light curve using starry light_curves = xo.StarryLightCurve(u_star).get_light_curve( orbit=orbit, r=r_pl, t=x[mask], texp=texp) * 1e3 light_curve = pm.math.sum(light_curves, axis=-1) + mean pm.Deterministic("light_curves", light_curves) pm.Normal('obs', mu=light_curve, sd=yerr[mask], observed=y[mask]) # Optimize #------------------ if start is None: start = model.test_point map_soln = xo.optimize(start=start, vars=[logr]) map_soln = xo.optimize(start=map_soln, vars=[b]) map_soln = xo.optimize(start=map_soln, vars=[logP, t0]) map_soln = xo.optimize(start=map_soln, vars=[u_star]) map_soln = xo.optimize(start=map_soln, vars=[logr]) map_soln = xo.optimize(start=map_soln, vars=[b]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln) return model, map_soln
def build_GPmodel(self, mask=None, start=None, pl=True): """from exoplanet""" # Find rotation period rotper, ls_results = self.find_rotper(self.time, self.flux) if mask is None: mask = np.ones(len(self.time), dtype=bool) with pm.Model() as GPmodel: # Parameters for the stellar properties mean = pm.Normal("mean", mu=0.0, sd=10.0) u_star = xo.distributions.QuadLimbDark("u_star") # Stellar parameters from Huang et al (2018) M_star_huang = 1.094, 0.039 R_star_huang = 1.10, 0.023 BoundedNormal = pm.Bound(pm.Normal, lower=0, upper=3) if self.vet == False and self.EB == False: # Orbital parameters for the planets logP = pm.Normal("logP", mu=np.log(self.bls_period), sd=1) t0 = pm.Normal("t0", mu=self.bls_t0, sd=1) # Tracking planet parameters period = pm.Deterministic("period", tt.exp(logP)) m_star = BoundedNormal("m_star", mu=M_star_huang[0], sd=M_star_huang[1]) r_star = BoundedNormal("r_star", mu=R_star_huang[0], sd=R_star_huang[1]) b = pm.Uniform("b", lower=0, upper=0.9) BoundedNormal_logr = pm.Bound(pm.Normal, lower=-5, upper=0) logr = BoundedNormal_logr( 'logr', mu=0.5 * np.log(np.array(self.bls_depth)) + np.log(R_star_huang[0]), sd=1.0) r_pl = pm.Deterministic("r_pl", tt.exp(logr)) ror = pm.Deterministic("ror", r_pl / r_star) # This is the eccentricity prior from Kipping (2013): # https://arxiv.org/abs/1306.4982 BoundedBeta = pm.Bound(pm.Beta, lower=0, upper=1 - 1e-5) ecc = BoundedBeta("ecc", alpha=0.867, beta=3.03, testval=0.1) omega = xo.distributions.Angle("omega") # Even-Odd Test elif self.vet == True and self.EB == False: logP_even = pm.Normal("logP_even", mu=np.log(2 * self.bls_period), sd=1) t0_even = pm.Normal("t0_even", mu=self.bls_t0, sd=1) period_even = pm.Deterministic("period_even", tt.exp(logP_even)) m_star_even = BoundedNormal("m_star_even", mu=M_star_huang[0], sd=M_star_huang[1]) r_star_even = BoundedNormal("r_star_even", mu=R_star_huang[0], sd=R_star_huang[1]) b_even = pm.Uniform("b_even", lower=0, upper=0.9) BoundedNormal_logr_even = pm.Bound(pm.Normal, lower=-5, upper=0) logr_even = BoundedNormal_logr_even( 'logr_even', mu=0.5 * np.log(np.array(self.bls_depth)) + np.log(R_star_huang[0]), sd=1.0) r_pl_even = pm.Deterministic("r_pl_even", tt.exp(logr_even)) ror_even = pm.Deterministic("ror_even", r_pl_even / r_star_even) # This is the eccentricity prior from Kipping (2013): # https://arxiv.org/abs/1306.4982 BoundedBeta_even = pm.Bound(pm.Beta, lower=0, upper=1 - 1e-5) ecc_even = BoundedBeta_even("ecc_even", alpha=0.867, beta=3.03, testval=0.1) omega_even = xo.distributions.Angle("omega_even") logP_odd = pm.Normal("logP_odd", mu=np.log(2 * self.bls_period), sd=1) t0_odd = pm.Normal("t0_odd", mu=self.bls_period + self.bls_t0, sd=1) period_odd = pm.Deterministic("period_odd", tt.exp(logP_odd)) m_star_odd = BoundedNormal("m_star_odd", mu=M_star_huang[0], sd=M_star_huang[1]) r_star_odd = BoundedNormal("r_star_odd", mu=R_star_huang[0], sd=R_star_huang[1]) b_odd = pm.Uniform("b_odd", lower=0, upper=0.9) BoundedNormal_logr_odd = pm.Bound(pm.Normal, lower=-5, upper=0) logr_odd = BoundedNormal_logr_odd( 'logr_odd', mu=0.5 * np.log(np.array(self.bls_depth)) + np.log(R_star_huang[0]), sd=1.0) r_pl_odd = pm.Deterministic("r_pl_odd", tt.exp(logr_odd)) ror_odd = pm.Deterministic("ror_odd", r_pl_odd / r_star_odd) # This is the eccentricity prior from Kipping (2013): # https://arxiv.org/abs/1306.4982 BoundedBeta_odd = pm.Bound(pm.Beta, lower=0, upper=1 - 1e-5) ecc_odd = BoundedBeta_odd("ecc_odd", alpha=0.867, beta=3.03, testval=0.1) omega_odd = xo.distributions.Angle("omega_odd") #EB modeling else: logP_1 = pm.Normal("logP_1", mu=np.log(self.bls_period), sd=0.1) t0_1 = pm.Normal("t0_1", mu=self.bls_t0, sd=0.1) period_1 = pm.Deterministic("period_1", tt.exp(logP_1)) m_star_1 = BoundedNormal("m_star_1", mu=M_star_huang[0], sd=M_star_huang[1]) r_star_1 = BoundedNormal("r_star_1", mu=R_star_huang[0], sd=R_star_huang[1]) b_1 = pm.Uniform("b_1", lower=0, upper=0.9) BoundedNormal_logr_1 = pm.Bound(pm.Normal, lower=-5, upper=0) logr_1 = BoundedNormal_logr_1( 'logr_1', mu=0.5 * np.log(np.array(self.bls_depth)) + np.log(R_star_huang[0]), sd=1.0) r_pl_1 = pm.Deterministic("r_pl_1", tt.exp(logr_1)) ror_1 = pm.Deterministic("ror_1", r_pl_1 / r_star_1) # This is the eccentricity prior from Kipping (2013): # https://arxiv.org/abs/1306.4982 BoundedBeta_1 = pm.Bound(pm.Beta, lower=0, upper=1 - 1e-5) ecc_1 = BoundedBeta_1("ecc_1", alpha=0.867, beta=3.03, testval=0.1) omega_1 = xo.distributions.Angle("omega_1") logP_2 = pm.Normal("logP_2", mu=np.log(self.bls_period), sd=0.1) t0_2 = pm.Normal("t0_2", mu=self.bls_t0 + (self.bls_period / 2), sd=0.1) period_2 = pm.Deterministic("period_2", tt.exp(logP_2)) m_star_2 = BoundedNormal("m_star_2", mu=M_star_huang[0], sd=M_star_huang[1]) r_star_2 = BoundedNormal("r_star_2", mu=R_star_huang[0], sd=R_star_huang[1]) b_2 = pm.Uniform("b_2", lower=0, upper=0.9) BoundedNormal_logr_2 = pm.Bound(pm.Normal, lower=-5, upper=0) logr_2 = BoundedNormal_logr_2( 'logr_2', mu=0.5 * np.log(np.array(self.bls_depth)) + np.log(R_star_huang[0]), sd=1.0) r_pl_2 = pm.Deterministic("r_pl_2", tt.exp(logr_2)) ror_2 = pm.Deterministic("ror_2", r_pl_2 / r_star_2) # This is the eccentricity prior from Kipping (2013): # https://arxiv.org/abs/1306.4982 BoundedBeta_2 = pm.Bound(pm.Beta, lower=0, upper=1 - 1e-5) ecc_2 = BoundedBeta_2("ecc_2", alpha=0.867, beta=3.03, testval=0.1) omega_2 = xo.distributions.Angle("omega_2") # The parameters of the RotationTerm kernel logamp = pm.Normal("logamp", mu=np.log(np.var(self.flux[mask])), sd=5.0) logrotperiod = pm.Normal("logrotperiod", mu=np.log(rotper), sd=5.0) logQ0 = pm.Normal("logQ0", mu=1.0, sd=10.0) logdeltaQ = pm.Normal("logdeltaQ", mu=2.0, sd=10.0) mix = pm.Uniform("mix", lower=0, upper=1.0) # Transit jitter & GP parameters logs2 = pm.Normal("logs2", mu=2 * np.log(np.min(self.flux_err[mask])), sd=5.0) # Track the rotation period as a deterministic rotperiod = pm.Deterministic("rotation_period", tt.exp(logrotperiod)) # GP model for the light curve kernel = xo.gp.terms.RotationTerm(log_amp=logamp, period=rotperiod, log_Q0=logQ0, log_deltaQ=logdeltaQ, mix=mix) gp = xo.gp.GP(kernel, self.time[mask], ((self.flux_err[mask])**2 + tt.exp(logs2)), J=4) if self.vet == False and self.EB == False: # Orbit model orbit = xo.orbits.KeplerianOrbit(r_star=r_star, m_star=m_star, period=period, t0=t0, b=b, ecc=ecc, omega=omega) if pl is True: #r = r_pl # Compute the model light curve using starry light_curves = xo.StarryLightCurve(u_star).get_light_curve( orbit=orbit, r=r_pl, t=self.time[mask], texp=0.021) else: #r = 0 (no planet model) light_curves = xo.StarryLightCurve(u_star).get_light_curve( orbit=orbit, r=0, t=self.time[mask], texp=0.021) light_curve = pm.math.sum(light_curves, axis=-1) pm.Deterministic("light_curves", light_curves) # Compute the Gaussian Process likelihood and add it into the # the PyMC3 model as a "potential" pm.Potential( "loglike", gp.log_likelihood(self.flux[mask] - mean - light_curve)) # Compute the mean model prediction for plotting purposes pm.Deterministic("pred", gp.predict()) pm.Deterministic( "loglikelihood", gp.log_likelihood(self.flux[mask] - mean - light_curve)) # Fit for the maximum a posteriori parameters, I've found that I can get # a better solution by trying different combinations of parameters in turn if start is None: start = GPmodel.test_point # Optimize to find the maximum a posteriori parameters map_soln = xo.optimize(start=start, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[b]) map_soln = xo.optimize(start=map_soln, vars=[logP, t0]) map_soln = xo.optimize(start=map_soln, vars=[u_star]) map_soln = xo.optimize(start=map_soln, vars=[logr]) map_soln = xo.optimize(start=map_soln, vars=[b]) map_soln = xo.optimize(start=map_soln, vars=[ecc, omega]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln, vars=[logamp]) map_soln = xo.optimize(start=map_soln, vars=[logrotperiod]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[mix]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln) # Even-Odd Test elif self.vet == True and self.EB == False: orbit_even = xo.orbits.KeplerianOrbit(r_star=r_star_even, m_star=m_star_even, period=period_even, t0=t0_even, b=b_even, ecc=ecc_even, omega=omega_even) orbit_odd = xo.orbits.KeplerianOrbit(r_star=r_star_odd, m_star=m_star_odd, period=period_odd, t0=t0_odd, b=b_odd, ecc=ecc_odd, omega=omega_odd) if pl is True: #r = r_pl # Compute the model light curve using starry light_curves_even = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_even, r=r_pl_even, t=self.time[mask], texp=0.021) light_curves_odd = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_odd, r=r_pl_odd, t=self.time[mask], texp=0.021) else: #r = 0 (no planet model) light_curves_even = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_even, r=0, t=self.time[mask], texp=0.021) light_curves_odd = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_odd, r=0, t=self.time[mask], texp=0.021) light_curve_even = pm.math.sum(light_curves_even, axis=-1) light_curve_odd = pm.math.sum(light_curves_odd, axis=-1) pm.Deterministic("light_curves_even", light_curves_even) pm.Deterministic("light_curves_odd", light_curves_odd) # Compute the Gaussian Process likelihood and add it into the # the PyMC3 model as a "potential" pm.Potential( "loglike", gp.log_likelihood(self.flux[mask] - mean - (light_curve_even + light_curve_odd))) # Compute the mean model prediction for plotting purposes pm.Deterministic("pred", gp.predict()) pm.Deterministic( "loglikelihood", gp.log_likelihood(self.flux[mask] - mean - (light_curve_even + light_curve_odd))) # Fit for the maximum a posteriori parameters, I've found that I can get # a better solution by trying different combinations of parameters in turn if start is None: start = GPmodel.test_point # Optimize to find the maximum a posteriori parameters map_soln = xo.optimize(start=start, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[b_even]) map_soln = xo.optimize(start=map_soln, vars=[b_odd]) map_soln = xo.optimize(start=map_soln, vars=[logP_even, t0_even]) map_soln = xo.optimize(start=map_soln, vars=[logP_odd, t0_odd]) map_soln = xo.optimize(start=map_soln, vars=[u_star]) map_soln = xo.optimize(start=map_soln, vars=[logr_even]) map_soln = xo.optimize(start=map_soln, vars=[logr_odd]) map_soln = xo.optimize(start=map_soln, vars=[b_even]) map_soln = xo.optimize(start=map_soln, vars=[b_odd]) map_soln = xo.optimize(start=map_soln, vars=[ecc_even, omega_even]) map_soln = xo.optimize(start=map_soln, vars=[ecc_odd, omega_odd]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln, vars=[logamp]) map_soln = xo.optimize(start=map_soln, vars=[logrotperiod]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[mix]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln) # EB modeling else: orbit_1 = xo.orbits.KeplerianOrbit(r_star=r_star_1, m_star=m_star_1, period=period_1, t0=t0_1, b=b_1, ecc=ecc_1, omega=omega_1) orbit_2 = xo.orbits.KeplerianOrbit(r_star=r_star_2, m_star=m_star_2, period=period_2, t0=t0_2, b=b_2, ecc=ecc_2, omega=omega_2) if pl is True: #r = r_pl # Compute the model light curve using starry light_curves_1 = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_1, r=r_pl_1, t=self.time[mask], texp=0.021) light_curves_2 = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_2, r=r_pl_2, t=self.time[mask], texp=0.021) else: #r = 0 (no planet model) light_curves_1 = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_1, r=0, t=self.time[mask], texp=0.021) light_curves_2 = xo.StarryLightCurve( u_star).get_light_curve(orbit=orbit_2, r=0, t=self.time[mask], texp=0.021) light_curve_1 = pm.math.sum(light_curves_1, axis=-1) light_curve_2 = pm.math.sum(light_curves_2, axis=-1) pm.Deterministic("light_curves_1", light_curves_1) pm.Deterministic("light_curves_2", light_curves_2) # Compute the Gaussian Process likelihood and add it into the # the PyMC3 model as a "potential" pm.Potential( "loglike", gp.log_likelihood(self.flux[mask] - mean - (light_curve_1 + light_curve_2))) # Compute the mean model prediction for plotting purposes pm.Deterministic("pred", gp.predict()) pm.Deterministic( "loglikelihood", gp.log_likelihood(self.flux[mask] - mean - (light_curve_1 + light_curve_2))) # Fit for the maximum a posteriori parameters, I've found that I can get # a better solution by trying different combinations of parameters in turn if start is None: start = GPmodel.test_point # Optimize to find the maximum a posteriori parameters map_soln = xo.optimize(start=start, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[b_1]) map_soln = xo.optimize(start=map_soln, vars=[b_2]) map_soln = xo.optimize(start=map_soln, vars=[logP_1, t0_1]) map_soln = xo.optimize(start=map_soln, vars=[logP_2, t0_2]) map_soln = xo.optimize(start=map_soln, vars=[u_star]) map_soln = xo.optimize(start=map_soln, vars=[logr_1]) map_soln = xo.optimize(start=map_soln, vars=[logr_2]) map_soln = xo.optimize(start=map_soln, vars=[b_1]) map_soln = xo.optimize(start=map_soln, vars=[b_2]) map_soln = xo.optimize(start=map_soln, vars=[ecc_1, omega_1]) map_soln = xo.optimize(start=map_soln, vars=[ecc_2, omega_2]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln, vars=[logamp]) map_soln = xo.optimize(start=map_soln, vars=[logrotperiod]) map_soln = xo.optimize(start=map_soln, vars=[mean]) map_soln = xo.optimize(start=map_soln, vars=[mix]) map_soln = xo.optimize(start=map_soln, vars=[logs2, logQ0, logdeltaQ]) map_soln = xo.optimize(start=map_soln) return GPmodel, map_soln
def recreate_mod(self): ''' ''' with pm.Model() as self.model: # Parameters for the stellar properties mean = pm.Normal("mean", mu=self.soln['mean'], sd=10.0) u_star = xo.distributions.QuadLimbDark("u_star") # Stellar parameters from Huang et al (2018) M_star_huang = 1.094, 0.039 R_star_huang = 1.10, 0.023 BoundedNormal = pm.Bound(pm.Normal, lower=0, upper=3) if self.do_even_odd == False: logP = pm.Normal("logP", mu=self.soln['logP'], sd=1) t0 = pm.Normal("t0", mu=self.soln['t0'], sd=1) period = pm.Deterministic("period", tt.exp(logP)) m_star = BoundedNormal("m_star", mu=self.soln['m_star'], sd=M_star_huang[1]) r_star = BoundedNormal("r_star", mu=self.soln['r_star'], sd=R_star_huang[1]) b = pm.Uniform("b", lower=0, upper=0.9, testval=self.soln['b']) BoundedNormal_logr = pm.Bound(pm.Normal, lower=-5, upper=0) logr = BoundedNormal_logr('logr', mu=self.soln['logr'], sd=1.0) r_pl = pm.Deterministic("r_pl", tt.exp(logr)) ror = pm.Deterministic("ror", r_pl / r_star) BoundedBeta = pm.Bound(pm.Beta, lower=0, upper=1-1e-5) ecc = BoundedBeta("ecc", alpha=0.867, beta=3.03, testval=self.soln['ecc']) omega = xo.distributions.Angle("omega") # Even-Odd Test else: logP_even = pm.Normal("logP_even", mu=self.soln['logP_even'], sd=1) t0_even = pm.Normal("t0_even", mu=self.soln['t0_even'], sd=1) period_even = pm.Deterministic("period_even", tt.exp(logP_even)) m_star_even = BoundedNormal("m_star_even", mu=self.soln['m_star_even'], sd=M_star_huang[1]) r_star_even = BoundedNormal("r_star_even", mu=self.soln['r_star_even'], sd=R_star_huang[1]) b_even = pm.Uniform("b_even", lower=0, upper=0.9, testval=self.soln['b_even']) BoundedNormal_logr = pm.Bound(pm.Normal, lower=-5, upper=0) logr_even = BoundedNormal_logr('logr_even', mu=self.soln['logr_even'], sd=1.0) r_pl_even = pm.Deterministic("r_pl_even", tt.exp(logr_even)) ror_even = pm.Deterministic("ror_even", r_pl_even / r_star_even) BoundedBeta = pm.Bound(pm.Beta, lower=0, upper=1-1e-5) ecc_even = BoundedBeta("ecc_even", alpha=0.867, beta=3.03, testval=self.soln['ecc_even']) omega_even = xo.distributions.Angle("omega_even") logP_odd = pm.Normal("logP_odd", mu=self.soln['logP_odd'], sd=1) t0_odd = pm.Normal("t0_odd", mu=self.soln['t0_odd'], sd=1) period_odd = pm.Deterministic("period_odd", tt.exp(logP_odd)) m_star_odd = BoundedNormal("m_star_odd", mu=self.soln['m_star_odd'], sd=M_star_huang[1]) r_star_odd = BoundedNormal("r_star_odd", mu=self.soln['r_star_odd'], sd=R_star_huang[1]) b_odd = pm.Uniform("b_odd", lower=0, upper=0.9, testval=self.soln['b_odd']) logr_odd = BoundedNormal_logr('logr_odd', mu=self.soln['logr_odd'], sd=1.0) r_pl_odd = pm.Deterministic("r_pl_odd", tt.exp(logr_odd)) ror_odd = pm.Deterministic("ror_odd", r_pl_odd / r_star_odd) ecc_odd = BoundedBeta("ecc_odd", alpha=0.867, beta=3.03, testval=self.soln['ecc_odd']) omega_odd = xo.distributions.Angle("omega_odd") # The parameters of the RotationTerm kernel logamp = pm.Normal("logamp", mu=self.soln['logamp'], sd=5.0) logrotperiod = pm.Normal("logrotperiod", mu=self.soln['logrotperiod'], sd=5.0) logQ0 = pm.Normal("logQ0", mu=self.soln['logQ0'], sd=10.0) logdeltaQ = pm.Normal("logdeltaQ", mu=self.soln['logdeltaQ'], sd=10.0) mix = pm.Uniform("mix", lower=0, upper=1.0, testval=self.soln['mix']) # Transit jitter & GP parameters logs2 = pm.Normal("logs2", mu=self.soln['logs2'], sd=5.0) # Track the rotation period as a deterministic rotperiod = pm.Deterministic("rotation_period", tt.exp(logrotperiod)) # GP model for the light curve kernel = xo.gp.terms.RotationTerm(log_amp=logamp, period=rotperiod, log_Q0=logQ0, log_deltaQ=logdeltaQ, mix=mix) gp = xo.gp.GP(kernel, self.time[self.mask], ((self.flux_err[self.mask])**2 + tt.exp(logs2)), J=4) if self.do_even_odd == False: # Orbit model orbit = xo.orbits.KeplerianOrbit(r_star=r_star, m_star=m_star, period=period, t0=t0, b=b, ecc=ecc, omega=omega) light_curves = xo.StarryLightCurve(u_star).get_light_curve(orbit=orbit, r=r_pl, t=self.time[self.mask], texp=0.021) light_curve = pm.math.sum(light_curves, axis=-1) pm.Deterministic("light_curves", light_curves) # Compute the Gaussian Process likelihood and add it into the # the PyMC3 model as a "potential" pm.Potential("loglike", gp.log_likelihood(self.flux[self.mask] - mean - light_curve)) # Compute the mean model prediction for plotting purposes pm.Deterministic("pred", gp.predict()) pm.Deterministic("loglikelihood", gp.log_likelihood(self.flux[self.mask] - mean - light_curve)) else: orbit_even = xo.orbits.KeplerianOrbit(r_star=r_star_even, m_star=m_star_even, period=period_even, t0=t0_even, b=b_even, ecc=ecc_even, omega=omega_even) orbit_odd = xo.orbits.KeplerianOrbit(r_star=r_star_odd, m_star=m_star_odd, period=period_odd, t0=t0_odd, b=b_odd, ecc=ecc_odd, omega=omega_odd) light_curves_even = xo.StarryLightCurve(u_star).get_light_curve(orbit=orbit_even, r=r_pl_even, t=self.time[self.mask], texp=0.021) light_curves_odd = xo.StarryLightCurve(u_star).get_light_curve(orbit=orbit_odd, r=r_pl_odd, t=self.time[self.mask], texp=0.021) light_curve_even = pm.math.sum(light_curves_even, axis=-1) light_curve_odd = pm.math.sum(light_curves_odd, axis=-1) pm.Deterministic("light_curves_even", light_curves_even) pm.Deterministic("light_curves_odd", light_curves_odd) # Compute the Gaussian Process likelihood and add it into the # the PyMC3 model as a "potential" pm.Potential("loglike", gp.log_likelihood(self.flux[self.mask] - mean - (light_curve_even + light_curve_odd))) # Compute the mean model prediction for plotting purposes pm.Deterministic("pred", gp.predict()) pm.Deterministic("loglikelihood", gp.log_likelihood(self.flux[self.mask] - mean - (light_curve_even + light_curve_odd)))