def _model_setup(self): with self._model: # COSMOLOGY omega_m = pm.Uniform("OmegaM", lower=0, upper=1.) # dark energy EOS w = pm.Normal("w", mu=-1, sd=1) # My custom distance mod. function to enable # ADVI and HMC smapling. dm = distmod_w_flat(omega_m, self._h0, w, self._zcmb) # PHILIPS PARAMETERS # M0 is the location parameter for the distribution # sys_scat is the scale parameter for the M0 distribution # rather than "unexpalined variance" M0 = pm.Normal("M0", mu=-19.3, sd=2.) sys_scat = pm.HalfCauchy('sys_scat', beta=2.5) # Gelman recommendation for variance parameter M_true = pm.Normal('M_true', M0, sys_scat, shape=self._n_SN) # following Rubin's Unity model... best idea? not sure taninv_alpha = pm.Uniform("taninv_alpha", lower=-.2, upper=.3) taninv_beta = pm.Uniform("taninv_beta", lower=-1.4, upper=1.4) # Transform variables alpha = pm.Deterministic('alpha', T.tan(taninv_alpha)) beta = pm.Deterministic('beta', T.tan(taninv_beta)) # Again using Rubin's Unity model. # After discussion with Rubin, the idea is that # these parameters are ideally sampled from a Gaussian, # but we know they are not entirely correct. So instead, # the Cauchy is less informative around the mean, while # still having informative tails. xm = pm.Cauchy('xm', alpha=0, beta=1) cm = pm.Cauchy('cm', alpha=0, beta=1) Rx_log = pm.Uniform('Rx_log', lower=-0.5, upper=0.5) Rc_log = pm.Uniform('Rc_log', lower=-1.5, upper=1.5) # Transformed variables Rx = pm.Deterministic("Rx", T.pow(10., Rx_log)) Rc = pm.Deterministic("Rc", T.pow(10., Rc_log)) x_true = pm.Normal('x_true', mu=xm, sd=Rx, shape=self._n_SN) c_true = pm.Normal('c_true', mu=cm, sd=Rc, shape=self._n_SN) # Do the correction mb = pm.Deterministic("mb", M_true + dm - alpha * x_true + beta * c_true) # Likelihood and measurement error obsc = pm.Normal("obsc", mu=c_true, sd=self._dcolor, observed=self._color) obsx = pm.Normal("obsx", mu=x_true, sd=self._dx1, observed=self._x1) obsm = pm.Normal("obsm", mu=mb, sd=self._dmb_obs, observed=self._mb_obs)
def sky_position(period, t0, e, omega, incl, t, **kwargs): # Shorthands n = 2.0 * np.pi / period cos_omega = tt.cos(omega) sin_omega = tt.sin(omega) # Find the reference time that puts the center of transit at t0 E0 = 2.0 * tt.atan2( tt.sqrt(1.0 - e) * cos_omega, tt.sqrt(1.0 + e) * (1.0 + sin_omega)) tref = t0 - (E0 - e * tt.sin(E0)) / n # Solve Kepler's equation for the true anomaly M = (t - tref) * n kepler = KeplerOp(**kwargs) E = kepler(M, e + tt.zeros_like(M)) f = 2.0 * tt.atan2( tt.sqrt(1.0 + e) * tt.tan(0.5 * E), tt.sqrt(1.0 - e) + tt.zeros_like(E)) # Rotate into sky coordinates cf = tt.cos(f) sf = tt.sin(f) swpf = sin_omega * cf + cos_omega * sf cwpf = cos_omega * cf - sin_omega * sf # Star / planet distance r = (1.0 - e**2) / (1 + e * cf) return tt.stack( [-r * cwpf, -r * swpf * tt.cos(incl), r * swpf * tt.sin(incl)])
def build_model(self, name='normal_model'): # Define Stochastic variables with pm.Model(name=name) as self.model: # Global mean pitch angle self.mu_phi = pm.Uniform('mu_phi', lower=0, upper=90) self.sigma_phi = pm.InverseGamma('sigma_phi', alpha=2, beta=15, testval=8) self.sigma_gal = pm.InverseGamma('sigma_gal', alpha=2, beta=15, testval=8) # define a mean galaxy pitch angle self.phi_gal = pm.TruncatedNormal( 'phi_gal', mu=self.mu_phi, sd=self.sigma_phi, lower=0, upper=90, shape=len(self.galaxies), ) # draw arm pitch angles centred around this mean self.phi_arm = pm.TruncatedNormal( 'phi_arm', mu=self.phi_gal[self.gal_arm_map], sd=self.sigma_gal, lower=0, upper=90, shape=len(self.gal_arm_map), ) # convert to a gradient for a linear fit self.b = tt.tan(np.pi / 180 * self.phi_arm) # arm offset parameter self.c = pm.Cauchy('c', alpha=0, beta=10, shape=self.n_arms, testval=np.tile(0, self.n_arms)) # radial noise self.sigma_r = pm.InverseGamma('sigma_r', alpha=2, beta=0.5) r = pm.Deterministic( 'r', tt.exp(self.b[self.point_arm_map] * self.data['theta'] + self.c[self.point_arm_map])) # likelihood function self.likelihood = pm.Normal( 'Likelihood', mu=r, sigma=self.sigma_r, observed=self.data['r'], )
def build_model(self, name=''): # Define Stochastic variables with pm.Model(name=name) as self.model: # Global mean pitch angle self.phi_gal = pm.Uniform('phi_gal', lower=0, upper=90, shape=len(self.galaxies)) # note we don't model inter-galaxy dispersion here # intra-galaxy dispersion self.sigma_gal = pm.InverseGamma('sigma_gal', alpha=2, beta=20, testval=5) # arm offset parameter self.c = pm.Cauchy('c', alpha=0, beta=10, shape=self.n_arms, testval=np.tile(0, self.n_arms)) # radial noise self.sigma_r = pm.InverseGamma('sigma_r', alpha=2, beta=0.5) # define prior for Student T degrees of freedom # self.nu = pm.Uniform('nu', lower=1, upper=100) # Define Dependent variables self.phi_arm = pm.TruncatedNormal( 'phi_arm', mu=self.phi_gal[self.gal_arm_map], sd=self.sigma_gal, lower=0, upper=90, shape=self.n_arms) # convert to a gradient for a linear fit self.b = tt.tan(np.pi / 180 * self.phi_arm) r = pm.Deterministic( 'r', tt.exp(self.b[self.data['arm_index'].values] * self.data['theta'] + self.c[self.data['arm_index'].values])) # likelihood function self.likelihood = pm.StudentT( 'Likelihood', mu=r, sigma=self.sigma_r, nu=1, #self.nu, observed=self.data['r'], )
def hierarchial(subject_id=20902040): X_all = np.concatenate([ np.stack(((arm.t * arm.chirality), arm.R, arm.point_weights, np.tile(arm_no, len(arm.R))), axis=1) for arm_no, arm in enumerate(get_arms(subject_id, err=False)) ]) # remove values with zero weight X = X_all[X_all.T[2] > 0] t, R, point_weights = X.T[:3] # get an arm index enc = OrdinalEncoder(dtype=np.int32) arm_idx = enc.fit_transform(X[:, [3]]).T[0] n_unique_arms = len(np.unique(arm_idx)) with pm.Model() as hierarchical_model: print('Defining model') mu_psi = pm.Uniform('mu_psi', lower=0, upper=80, testval=15.0) sigma_psi = pm.HalfCauchy('sigma_psi', beta=1) psi_offset = pm.Normal('psi_offset', mu=0, sd=1) psi = pm.Deterministic('psi', mu_psi + sigma_psi * psi_offset) psi_radians = psi * np.pi / 180 a = pm.Uniform('a', lower=0, upper=200, testval=1, shape=n_unique_arms) # define our equation for mu_r r_est = (a[arm_idx] / 100 * tt.exp(tt.tan(psi_radians) * t)) # define our expected error on r here we assume this sigma is the # same for all galaxies (not necessarily true) base_sigma = pm.HalfCauchy('sigma', beta=5, testval=0.02) sigma_y = theano.shared(np.asarray(np.sqrt(point_weights), dtype=theano.config.floatX), name='sigma_y') sigmas = base_sigma / sigma_y # define our likelihood function pm.Normal('R_like', mu=r_est, sd=sigmas, observed=R) with hierarchical_model: trace = pm.sample(2000, tune=1000, cores=2) pm.traceplot(trace) plt.gcf().set_size_inches(6, 15) pm.plots.pairplot(trace, varnames=['mu_psi', 'sigma_psi', 'sigma']) plt.gcf().set_size_inches(10, 10) pm.plots.plot_posterior(trace, kde_plot=True) plt.gcf().set_size_inches(10, 10) plt.show()
def build_model(self, name=''): # Define Stochastic variables with pm.Model(name=name) as self.model: # Global mean pitch angle self.phi_gal = pm.Uniform('phi_gal', lower=0, upper=90, shape=len(self.galaxies)) # note we don't model inter-galaxy dispersion here # intra-galaxy dispersion self.sigma_gal = pm.InverseGamma('sigma_gal', alpha=2, beta=20, testval=5) # arm offset parameter self.c = pm.Cauchy('c', alpha=0, beta=10, shape=self.n_arms, testval=np.tile(0, self.n_arms)) # radial noise self.sigma_r = pm.InverseGamma('sigma_r', alpha=2, beta=0.5) # ----- Define Dependent variables ----- # Phi arm is drawn from a truncated normal centred on phi_gal with # spread sigma_gal gal_idx = self.gal_arm_map.astype('int32') self.phi_arm = pm.TruncatedNormal('phi_arm', mu=self.phi_gal[gal_idx], sd=self.sigma_gal, lower=0, upper=90, shape=self.n_arms) # transform to gradient for fitting self.b = tt.tan(np.pi / 180 * self.phi_arm) # r = exp(theta * tan(phi) + c) # do not track this as it uses a lot of memory arm_idx = self.data['arm_index'].values.astype('int32') r = tt.exp(self.b[arm_idx] * self.data['theta'] + self.c[arm_idx]) # likelihood function (assume likelihood here) self.likelihood = pm.Normal( 'Likelihood', mu=r, sigma=self.sigma_r, observed=self.data['r'], )
def get_rvmodels(self, t, name=None): K = tt.exp(tt.stack([p.logK for p in self.planets])) n = tt.stack([p.n for p in self.planets]) t0 = tt.stack([p.t0 for p in self.planets]) e = tt.stack([p.eccen for p in self.planets]) cosw = tt.stack([p.omegavec[0] for p in self.planets]) sinw = tt.stack([p.omegavec[1] for p in self.planets]) mean_anom = n * (t[:, None] - t0) eccen_arg = e + tt.zeros_like(mean_anom) eccen_anom = self.kepler(mean_anom, eccen_arg) f = 2 * tt.arctan2( tt.sqrt(1 + e) * tt.tan(0.5 * eccen_anom), tt.sqrt(1 - e) + tt.zeros_like(eccen_anom)) return pm.Deterministic( join_names(self.name, name, "rvmodels"), K * (cosw * (tt.cos(f) + e) - sinw * tt.sin(f)))
def construct_likelihood(self): pm.Deterministic('gradient', tt.tan(self.model['angle'])) pm.Deterministic( 'intercept', self.model['displacement'] / tt.cos(self.model['angle'])) if self.data_covariances is not None: pm.Potential( 'like', likelihood(self.model['angle'], self.model['displacement'], self.model['ln_variance'], self.z, self.s)) else: sigma = tt.exp(self.model['ln_variance'])**0.5 pm.Normal('like', mu=self.relation(self.z[:, 0]), sd=sigma, observed=self.z[:, 1], shape=len(self.data))
def get_logsp_trace_from_arms(arms, nsamples=3000): X = np.concatenate([ np.stack(((arm.t * arm.chirality), arm.R, arm.point_weights, np.tile(i, len(arm.R))), axis=1) for i, arm in enumerate(arms) ]) pw_mask = X[:, 2] > 0 t = X[:, 0][pw_mask] R = X[:, 1][pw_mask] weights = X[:, 2][pw_mask] pa, sigma_pa = arms[0].get_parent().get_pitch_angle(arms) with pm.Model() as model: # psi has a uniform prior over all reasonable values (-80, 80) # not -90 to 90 to avoid infinities / overflows psi = pm.Uniform('psi', lower=0, upper=80, testval=pa) psi_radians = psi * np.pi / 180 # model a as a uniform, which we scale later so our varibles have # similar magnitude a = pm.Uniform('a', lower=0, upper=200, testval=1, shape=len(arms)) a_arr = tt.concatenate( [tt.tile(a[i], len(arms[i].t)) for i in range(len(arms))])[pw_mask] # define our equation for mu_r mu_r = a_arr / 100 * tt.exp(tt.tan(psi_radians) * t) # define our expected error on r (different to error on psi) base_sigma = pm.HalfCauchy('sigma', beta=5, testval=0.02) sigma_y = theano.shared(np.asarray(np.sqrt(weights), dtype=theano.config.floatX), name='sigma_y') sigmas = base_sigma / sigma_y # define our likelihood function likelihood = pm.Normal('R', mu=mu_r, sd=sigmas, observed=R) # run the sampler with model: trace = pm.sample(nsamples, tune=1500, cores=2) return trace
def model(inp): """ MODEL 1: fc1 = T.dot(inp, weight1) ** np.sqrt(2) fc2 = T.tan(T.dot(fc1, weight2)) fc3 = T.dot(fc2, weight3) """ """ MODEL 2: This model is particularly interesting because of the piecewise nature of the non-linearity (max). This results in fragments or shards in the end fractal. fc1 = T.maximum(T.dot(inp, weight1) ** np.sqrt(2), 0) fc2 = T.maximum(T.tan(T.dot(fc1, weight2)), 0) fc3 = T.dot(fc2, weight3) """ """ MODEL 3: """ fc1 = T.dot(T.minimum(inp, 0), weight1)**np.sqrt(2) fc2 = T.tan(T.dot(fc1, weight2)) fc3 = T.dot(fc2, weight3) return fc3
def B(self, alpha, beta): return (1 / alpha) * T.arctan(beta * T.tan(self.pi * alpha / 2))
def B(self, alpha, beta): return (1/alpha)*T.arctan(beta*T.tan(self.pi*alpha/2))
def UNSQUASH(self, unit_box_sample): """ Perform the unboxing operation symbolically (see .unsquash). """ return tns.tan(np.pi * (unit_box_sample - 0.5))
t = np.linspace(0, 10, 2) x = np.random.uniform(0, 10, 50) y = x * true_params[0] + true_params[1] y_obs = y + np.exp(true_params[-1]) * np.random.randn(N) plt.plot(x, y_obs, ".k", label="observations") plt.plot(t, true_params[0] * t + true_params[1], label="truth") plt.xlabel("x") plt.ylabel("y") plt.legend(fontsize=14) import pymc3 as pm import theano.tensor as tt with pm.Model() as model: logs = pm.Uniform("logs", lower=-10, upper=10) alphaperp = pm.Uniform("alphaperp", lower=-10, upper=10) theta = pm.Uniform("theta", -2 * np.pi, 2 * np.pi, testval=0.0) # alpha_perp = alpha * cos(theta) alpha = pm.Deterministic("alpha", alphaperp / tt.cos(theta)) # beta = tan(theta) beta = pm.Deterministic("beta", tt.tan(theta)) # The observation model mu = alpha * x + beta pm.Normal("obs", mu=mu, sd=tt.exp(logs), observed=y_obs) trace = pm.sample(draws=2000, tune=2000)
n_times = 100 #n_times = len(df["X"].unique()) #時間の数 basic_model = Model() #subtensorの使い方↓ #http://deeplearning.net/software/theano/library/tensor/basic.html with basic_model: #事前分布 #コーシー分布は逆関数法にて乱数生成 s_mu = HalfNormal('s_mu', sd=1) #コーシー分布の分散 s_Y = HalfNormal('s_Y', sd=1) #観測誤差 mu_0 = Normal('mu_0',mu=0, sd=1) #初期状態 x = Uniform("x" ,lower=-math.pi/2,upper=math.pi/2, shape=n_times-1) #Cauchyの誤差process c = tt.dot(s_mu,tt.tan(x)) #状態process mu = tt.zeros((n_times)) mu = tt.set_subtensor(mu[0], mu_0) for i in range(n_times-1): mu = tt.set_subtensor(mu[i+1], mu[i]+c[i]) #likelihood Y_obs = Normal('Y_obs', mu=mu, sd=s_Y, observed=Y) #サンプリング trace = sample(1000,n_init=5000) summary(trace)
def tan(x): return T.tan(x)
def _model_setup(self): with self._model: # COSMOLOGY omega_m = pm.Uniform("OmegaM", lower=0., upper=1.) omega_k = pm.Uniform("Omegak", lower=-1., upper=1.) # My custom distance mod. function to enable # ADVI and HMC sampling. # We are going to have to break this into # four likelihoods dm_0 = distmod_constant_curve(omega_m, omega_k, self._h0, self._zcmb_survey[0]) dm_1 = distmod_constant_curve(omega_m, omega_k, self._h0, self._zcmb_survey[1]) dm_2 = distmod_constant_curve(omega_m, omega_k, self._h0, self._zcmb_survey[2]) dm_3 = distmod_constant_curve(omega_m, omega_k, self._h0, self._zcmb_survey[3]) # PHILIPS PARAMETERS # M0 is the location parameter for the distribution # sys_scat is the scale parameter for the M0 distribution # rather than "unexpalined variance" M0 = pm.Uniform("M0", lower=-20., upper=-18.) sys_scat = pm.HalfCauchy('sys_scat', beta=2.5) # Gelman recommendation for variance parameter M_true_0 = pm.Normal('M_true_0', M0, sys_scat, shape=self._n_SN_survey[0]) M_true_1 = pm.Normal('M_true_1', M0, sys_scat, shape=self._n_SN_survey[1]) M_true_2 = pm.Normal('M_true_2', M0, sys_scat, shape=self._n_SN_survey[2]) M_true_3 = pm.Normal('M_true_3', M0, sys_scat, shape=self._n_SN_survey[3]) # following Rubin's Unity model... best idea? not sure taninv_alpha = pm.Uniform("taninv_alpha", lower=-.2, upper=.3) taninv_beta = pm.Uniform("taninv_beta", lower=-1.4, upper=1.4) # Transform variables alpha = pm.Deterministic('alpha', T.tan(taninv_alpha)) beta = pm.Deterministic('beta', T.tan(taninv_beta)) # Again using Rubin's Unity model. # After discussion with Rubin, the idea is that # these parameters are ideally sampled from a Gaussian, # but we know they are not entirely correct. So instead, # the Cauchy is less informative around the mean, while # still having informative tails. xm = pm.Cauchy('xm', alpha=0, beta=1) cm = pm.Cauchy('cm', alpha=0, beta=1, shape=4) s = pm.Uniform('s', lower=-2, upper=2, shape=4) c_shift_0 = cm[0] + s[0] * self._zcmb_survey[0] c_shift_1 = cm[1] + s[1] * self._zcmb_survey[1] c_shift_2 = cm[2] + s[2] * self._zcmb_survey[2] c_shift_3 = cm[3] + s[3] * self._zcmb_survey[3] Rx_log = pm.Uniform('Rx_log', lower=-0.5, upper=0.5) Rc_log = pm.Uniform('Rc_log', lower=-1.5, upper=1.5, shape=4) # Transformed variables Rx = pm.Deterministic("Rx", T.pow(10., Rx_log)) Rc = pm.Deterministic("Rc", T.pow(10., Rc_log)) x_true_0 = pm.Normal('x_true_0', mu=xm, sd=Rx, shape=self._n_SN_survey[0]) c_true_0 = pm.Normal('c_true_0', mu=c_shift_0, sd=Rc[0], shape=self._n_SN_survey[0]) x_true_1 = pm.Normal('x_true_1', mu=xm, sd=Rx, shape=self._n_SN_survey[1]) c_true_1 = pm.Normal('c_true_1', mu=c_shift_1, sd=Rc[1], shape=self._n_SN_survey[1]) x_true_2 = pm.Normal('x_true_2', mu=xm, sd=Rx, shape=self._n_SN_survey[2]) c_true_2 = pm.Normal('c_true_2', mu=c_shift_2, sd=Rc[2], shape=self._n_SN_survey[2]) x_true_3 = pm.Normal('x_true_3', mu=xm, sd=Rx, shape=self._n_SN_survey[3]) c_true_3 = pm.Normal('c_true_3', mu=c_shift_3, sd=Rc[3], shape=self._n_SN_survey[3]) # Do the correction mb_0 = pm.Deterministic("mb_0", M_true_0 + dm_0 - alpha * x_true_0 + beta * c_true_0) mb_1 = pm.Deterministic("mb_1", M_true_1 + dm_1 - alpha * x_true_1 + beta * c_true_1) mb_2 = pm.Deterministic("mb_2", M_true_2 + dm_2 - alpha * x_true_2 + beta * c_true_2) mb_3 = pm.Deterministic("mb_3", M_true_3 + dm_3 - alpha * x_true_3 + beta * c_true_3) # Likelihood and measurement error obsc_0 = pm.Normal("obsc_0", mu=c_true_0, sd=self._dcolor_survey[0], observed=self._color_survey[0]) obsx_0 = pm.Normal("obsx_0", mu=x_true_0, sd=self._dx1_survey[0], observed=self._x1_survey[0]) obsm_0 = pm.Normal("obsm_0", mu=mb_0, sd=self._dmbObs_survey[0], observed=self._mbObs_survey[0]) obsc_1 = pm.Normal("obsc_1", mu=c_true_1, sd=self._dcolor_survey[1], observed=self._color_survey[1]) obsx_1 = pm.Normal("obsx_1", mu=x_true_1, sd=self._dx1_survey[1], observed=self._x1_survey[1]) obsm_1 = pm.Normal("obsm_1", mu=mb_1, sd=self._dmbObs_survey[1], observed=self._mbObs_survey[1]) obsc_2 = pm.Normal("obsc_2", mu=c_true_2, sd=self._dcolor_survey[2], observed=self._color_survey[2]) obsx_2 = pm.Normal("obsx_2", mu=x_true_2, sd=self._dx1_survey[2], observed=self._x1_survey[2]) obsm_2 = pm.Normal("obsm_2", mu=mb_2, sd=self._dmbObs_survey[2], observed=self._mbObs_survey[2]) obsc_3 = pm.Normal("obsc_3", mu=c_true_3, sd=self._dcolor_survey[3], observed=self._color_survey[3]) obsx_3 = pm.Normal("obsx_3", mu=x_true_3, sd=self._dx1_survey[3], observed=self._x1_survey[3]) obsm_3 = pm.Normal("obsm_3", mu=mb_3, sd=self._dmbObs_survey[3], observed=self._mbObs_survey[3])
def reflected_phase_curve(phases, omega, g, a_rp, return_q=True): """ Reflected light phase curve for a homogeneous sphere by Heng, Morris & Kitzmann (2021). Parameters ---------- phases : `~np.ndarray` Orbital phases of each observation defined on (0, 1) omega : tensor-like Single-scattering albedo as defined in g : tensor-like Scattering asymmetry factor, ranges from (-1, 1). a_rp : float, tensor-like Semimajor axis scaled by the planetary radius Returns ------- flux_ratio_ppm : tensor-like Flux ratio between the reflected planetary flux and the stellar flux in units of ppm. A_g : tensor-like Geometric albedo derived for the planet given {omega, g}. q : tensor-like Integral phase function """ # Convert orbital phase on (0, 1) to "alpha" on (0, np.pi) alpha = (2 * np.pi * phases - np.pi).astype(floatX) abs_alpha = np.abs(alpha).astype(floatX) alpha_sort_order = np.argsort(alpha) sin_abs_sort_alpha = np.sin(abs_alpha[alpha_sort_order]).astype(floatX) sort_alpha = alpha[alpha_sort_order].astype(floatX) gamma = tt.sqrt(1 - omega) eps = (1 - gamma) / (1 + gamma) # Equation 34 for Henyey-Greestein P_star = (1 - g**2) / (1 + g**2 + 2 * g * tt.cos(alpha))**1.5 # Equation 36 P_0 = (1 - g) / (1 + g)**2 # Equation 10: Rho_S = P_star - 1 + 0.25 * ((1 + eps) * (2 - eps))**2 Rho_S_0 = P_0 - 1 + 0.25 * ((1 + eps) * (2 - eps))**2 Rho_L = 0.5 * eps * (2 - eps) * (1 + eps)**2 Rho_C = eps**2 * (1 + eps)**2 alpha_plus = tt.sin(abs_alpha / 2) + tt.cos(abs_alpha / 2) alpha_minus = tt.sin(abs_alpha / 2) - tt.cos(abs_alpha / 2) # Equation 11: Psi_0 = tt.log((1 + alpha_minus) * (alpha_plus - 1) / (1 + alpha_plus) / (1 - alpha_minus)) Psi_S = 1 - 0.5 * (tt.cos(abs_alpha / 2) - 1.0 / tt.cos(abs_alpha / 2)) * Psi_0 Psi_L = (tt.sin(abs_alpha) + (np.pi - abs_alpha) * tt.cos(abs_alpha)) / np.pi Psi_C = (-1 + 5 / 3 * tt.cos(abs_alpha / 2)**2 - 0.5 * tt.tan(abs_alpha / 2) * tt.sin(abs_alpha / 2)**3 * Psi_0) # Equation 8: A_g = omega / 8 * (P_0 - 1) + eps / 2 + eps**2 / 6 + eps**3 / 24 # Equation 9: Psi = ((12 * Rho_S * Psi_S + 16 * Rho_L * Psi_L + 9 * Rho_C * Psi_C) / (12 * Rho_S_0 + 16 * Rho_L + 6 * Rho_C)) flux_ratio_ppm = 1e6 * (a_rp**-2 * A_g * Psi) if return_q: q = _integral_phase_function(Psi, sin_abs_sort_alpha, sort_alpha, alpha_sort_order) return flux_ratio_ppm, A_g, q else: return flux_ratio_ppm, A_g
def run_simultaneous_hierarchial(recalculate=False, sample_size=None, max_ngals=None, outfolder='hierarchical-model'): enc = OrdinalEncoder(dtype=np.int32) sid_list = pd.read_csv('lib/subject-id-list.csv').values.T[0] if os.path.isfile('Xall.npy') and not recalculate: X_all = np.load('Xall.npy') else: X_all = make_X_all(sid_list) np.save('Xall.npy', X_all) # remove all points with weight of zero (or less..?) all_gal_idx, all_arm_idx = enc.fit_transform(X_all[:, [3, 4]]).T if max_ngals is not None and max_ngals <= all_gal_idx.max(): gals = np.random.choice(np.arange(all_gal_idx.max() + 1), max_ngals, replace=False) else: gals = np.arange(len(all_gal_idx.max() + 1)) X_masked = X_all[(X_all.T[2] > 0) & np.isin(all_gal_idx, gals)] sample = np.random.choice(len(X_masked), size=sample_size, replace=False) if sample_size else np.arange( len(X_masked)) X = X_masked[sample] t, R, point_weights = X.T[:3] # encode categorical variables into an index enc = OrdinalEncoder(dtype=np.int32) gal_idx, arm_idx = enc.fit_transform(X[:, [3, 4]]).T n_gals = len(np.unique(gal_idx)) n_unique_arms = len(np.unique(arm_idx)) print('{} galaxies, {} spiral arms, {} points'.format( n_gals, n_unique_arms, len(X))) with pm.Model() as hierarchical_model: print('Defining model') # Hyperpriors (informative for now) mu_psi = pm.Uniform('mu_psi', lower=0, upper=80, testval=15) # sigma_psi = pm.Gamma('sigma_psi', alpha=2, beta=10) sigma_psi = pm.HalfCauchy('sigma_psi', beta=1) psi_offset = pm.Normal('psi_offset', mu=0, sd=1, shape=n_gals) psi = pm.Deterministic('psi', mu_psi + sigma_psi * psi_offset) psi_radians = psi * np.pi / 180 a = pm.Uniform('a', lower=0, upper=200, testval=1, shape=n_unique_arms) # define our equation for mu_r r_est = (a[arm_idx] / 100 * tt.exp(tt.tan(psi_radians[gal_idx]) * t)) # define our expected error on r here we assume this sigma is the # same for all galaxies (not necessarily true) base_sigma = pm.HalfCauchy('sigma', beta=1, testval=0.02) sigma_y = theano.shared(np.asarray(np.sqrt(point_weights), dtype=theano.config.floatX), name='sigma_y') sigmas = base_sigma / sigma_y # define our likelihood function likelihood = pm.Normal('R_like', mu=r_est, sd=sigmas, observed=R) with hierarchical_model: trace = pm.sample(2000, tune=1000, cores=2, target_accept=0.95) if outfolder is not None: traces_dir = os.path.join('uniform-traces', outfolder) try: os.mkdir(traces_dir) except FileExistsError: shutil.rmtree(traces_dir) pm.save_trace(trace, directory=traces_dir, overwrite=True) pm.traceplot(trace, varnames=['mu_psi', 'sigma_psi', 'sigma']) plt.show()
def reflected_phase_curve_inhomogeneous(phases, omega_0, omega_prime, x1, x2, A_g, a_rp, return_q=True): """ Reflected light phase curve for an inhomogeneous sphere by Heng, Morris & Kitzmann (2021), with inspiration from Hu et al. (2015). Parameters ---------- phases : `~np.ndarray` Orbital phases of each observation defined on (0, 1) omega_0 : tensor-like Single-scattering albedo of the less reflective region. Defined on (0, 1). omega_prime : tensor-like Additional single-scattering albedo of the more reflective region, such that the single-scattering albedo of the reflective region is ``omega_0 + omega_prime``. Defined on (0, ``1-omega_0``). x1 : tensor-like Start longitude of the darker region [radians] on (-pi/2, pi/2) x2 : tensor-like Stop longitude of the darker region [radians] on (-pi/2, pi/2) a_rp : float, tensor-like Semimajor axis scaled by the planetary radius Returns ------- flux_ratio_ppm : tensor-like Flux ratio between the reflected planetary flux and the stellar flux in units of ppm. g : tensor-like Scattering asymmetry factor on (-1, 1) q : tensor-like Integral phase function """ g = _g_from_ag(A_g, omega_0, omega_prime, x1, x2) # Redefine alpha to be on (-pi, pi) alpha = (2 * np.pi * phases - np.pi).astype(floatX) abs_alpha = np.abs(alpha).astype(floatX) # Equation 34 for Henyey-Greestein P_star = (1 - g**2) / (1 + g**2 + 2 * g * tt.cos(abs_alpha))**1.5 # Equation 36 P_0 = (1 - g) / (1 + g)**2 Rho_S, Rho_S_0, Rho_L, Rho_C = rho(omega_0, P_0, P_star) Rho_S_prime, Rho_S_0_prime, Rho_L_prime, Rho_C_prime = rho( omega_prime, P_0, P_star) alpha_plus = tt.sin(abs_alpha / 2) + tt.cos(abs_alpha / 2) alpha_minus = tt.sin(abs_alpha / 2) - tt.cos(abs_alpha / 2) # Equation 11: Psi_0 = tt.log((1 + alpha_minus) * (alpha_plus - 1) / (1 + alpha_plus) / (1 - alpha_minus)) Psi_S = 1 - 0.5 * (tt.cos(abs_alpha / 2) - 1.0 / tt.cos(abs_alpha / 2)) * Psi_0 Psi_L = (tt.sin(abs_alpha) + (np.pi - abs_alpha) * tt.cos(abs_alpha)) / np.pi Psi_C = (-1 + 5 / 3 * tt.cos(abs_alpha / 2)**2 - 0.5 * tt.tan(abs_alpha / 2) * tt.sin(abs_alpha / 2)**3 * Psi_0) # Table 1: condition_a = (-np.pi / 2 <= alpha - np.pi / 2) condition_0 = ((alpha - np.pi / 2 <= np.pi / 2) & (np.pi / 2 <= alpha + x1) & (alpha + x1 <= alpha + x2)) condition_1 = ((alpha - np.pi / 2 <= alpha + x1) & (alpha + x1 <= np.pi / 2) & (np.pi / 2 <= alpha + x2)) condition_2 = ((alpha - np.pi / 2 <= alpha + x1) & (alpha + x1 <= alpha + x2) & (alpha + x2 <= np.pi / 2)) condition_b = (alpha + np.pi / 2 <= np.pi / 2) condition_3 = ((alpha + x1 <= alpha + x2) & (alpha + x2 <= -np.pi / 2) & (-np.pi / 2 <= alpha + np.pi / 2)) condition_4 = ((alpha + x1 <= -np.pi / 2) & (-np.pi / 2 <= alpha + x2) & (alpha + x2 <= alpha + np.pi / 2)) condition_5 = ((-np.pi / 2 <= alpha + x1) & (alpha + x1 <= alpha + x2) & (alpha + x2 <= alpha + np.pi / 2)) integration_angles = [ [alpha - np.pi / 2, np.pi / 2], [alpha - np.pi / 2, alpha + x1], [alpha - np.pi / 2, alpha + x1, alpha + x2, np.pi / 2], [-np.pi / 2, alpha + np.pi / 2], [alpha + x2, alpha + np.pi / 2], [-np.pi / 2, alpha + x1, alpha + x2, alpha + np.pi / 2] ] conditions = [ condition_a & condition_0, condition_a & condition_1, condition_a & condition_2, condition_b & condition_3, condition_b & condition_4, condition_b & condition_5, ] Psi_S_prime = 0 Psi_L_prime = 0 Psi_C_prime = 0 for condition_i, angle_i in zip(conditions, integration_angles): for i, phi_i in enumerate(angle_i): sign = (-1)**(i + 1) I_phi_S, I_phi_L, I_phi_C = I(alpha, phi_i) Psi_S_prime += tt.switch(condition_i, sign * I_phi_S, 0) Psi_L_prime += tt.switch(condition_i, sign * I_phi_L, 0) Psi_C_prime += tt.switch(condition_i, sign * I_phi_C, 0) # Compute everything for alpha=0 angles_alpha0 = [-np.pi / 2, x1, x2, np.pi / 2] Psi_S_prime_alpha0 = 0 Psi_L_prime_alpha0 = 0 Psi_C_prime_alpha0 = 0 for i, phi_i in enumerate(angles_alpha0): sign = (-1)**(i + 1) I_phi_S_alpha0, I_phi_L_alpha0, I_phi_C_alpha0 = I(0, phi_i) Psi_S_prime_alpha0 += sign * I_phi_S_alpha0 Psi_L_prime_alpha0 += sign * I_phi_L_alpha0 Psi_C_prime_alpha0 += sign * I_phi_C_alpha0 # P_star_alpha0 = (1 - g ** 2) / (1 + g ** 2 + 2 * g * 1) ** 1.5 # Rho_S_alpha0, Rho_S_0_alpha0, Rho_L_alpha0, Rho_C_alpha0 = rho(omega_0, P_0, # P_star_alpha0) # # Rho_S_prime_alpha0, Rho_S_0_prime_alpha0, Rho_L_prime_alpha0, Rho_C_prime_alpha0 = rho( # omega_prime, P_0, P_star_alpha0 # ) # # Equation 11: # Psi_S_alpha0 = 1 # Psi_L_alpha0 = 1 # Psi_C_alpha0 = (-1 + 5 / 3) # # Equation 37 # F_S_alpha0 = np.pi / 16 * (omega_0 * Rho_S_alpha0 * Psi_S_alpha0 + # omega_prime * Rho_S_prime_alpha0 * # Psi_S_prime_alpha0) # F_L_alpha0 = np.pi / 12 * (omega_0 * Rho_L_alpha0 * Psi_L_alpha0 + # omega_prime * Rho_L_prime_alpha0 * # Psi_L_prime_alpha0) # F_C_alpha0 = 3 * np.pi / 64 * (omega_0 * Rho_C_alpha0 * Psi_C_alpha0 + # omega_prime * Rho_C_prime_alpha0 * # Psi_C_prime_alpha0) # Equation 37 F_S = np.pi / 16 * (omega_0 * Rho_S * Psi_S + omega_prime * Rho_S_prime * Psi_S_prime) F_L = np.pi / 12 * (omega_0 * Rho_L * Psi_L + omega_prime * Rho_L_prime * Psi_L_prime) F_C = 3 * np.pi / 64 * (omega_0 * Rho_C * Psi_C + omega_prime * Rho_C_prime * Psi_C_prime) sobolev_fluxes = F_S + F_L + F_C F_max = tt.max(sobolev_fluxes) Psi = sobolev_fluxes / F_max flux_ratio_ppm = 1e6 * a_rp**-2 * Psi * A_g if return_q: alpha_sort_order = np.argsort(alpha) sin_abs_sort_alpha = np.sin(abs_alpha[alpha_sort_order]).astype(floatX) sort_alpha = alpha[alpha_sort_order].astype(floatX) q = _integral_phase_function(Psi, sin_abs_sort_alpha, sort_alpha, alpha_sort_order) # F_0 = F_S_alpha0 + F_L_alpha0 + F_C_alpha0 return flux_ratio_ppm, g, q else: return flux_ratio_ppm, g
def do_some_ops(x): tdb_trace(tt.tan(x), 'tan(x)') return {'cos': tt.cos(x), 'sin': tt.sin(x), 'exp': tt.exp(x), 'log': tt.log(x)}
def S(self, alpha, beta): inner = 1 + (beta**2) * (T.tan(self.pi * alpha / 2)**2) S = inner**(1 / (2 * alpha)) return S
# we want this: # arm_pa = pm.TruncatedNormal( # 'arm_pa', # mu=gal_pa_mu, sd=gal_pa_sd, # lower=0.1, upper=60, # shape=n_arms, # ) # Specified in a non-centred way: arm_pa_mu_offset = pm.Normal('arm_pa_mu_offset', mu=0, sd=1, shape=n_arms) arm_pa = pm.Deterministic('arm_pa', gal_pa_mu + gal_pa_sd * arm_pa_mu_offset) pm.Potential('arm_pa_mu_bound', (tt.switch(tt.all(arm_pa > 0.1), 0, -np.inf) + tt.switch(tt.all(arm_pa < 70), 0, -np.inf))) arm_b = pm.Deterministic('b', tt.tan(np.pi / 180 * arm_pa)) arm_r = tt.exp(arm_b[arm_idx] * T + arm_c[arm_idx]) # prevent r from being very large pm.Potential('arm_r_bound', tt.switch(tt.all(arm_r < 1E4), 0, -np.inf)) likelihood = pm.Normal('L', mu=arm_r, sigma=sigma, observed=R) # it's important we now check the model specification, namely do we have any # problems with logp being undefined? with model: print(model.check_test_point()) with model: trace = pm.sample(500, tune=500, target_accept=0.95, init='advi+adapt_diag')
def S(self, alpha, beta): inner = 1+(beta**2)*(T.tan(self.pi*alpha/2)**2) S = inner**(1/(2*alpha)) return S