def __init__(self, z_d, z_s, D_d_sample, D_delta_t_sample, sampling_option="H0_only", omega_m_fixed=0.3, omega_lambda_fixed=0.7, omega_mh2_fixed=0.14157, kde_type='scipy_gaussian', bandwidth=1, flat=True): """ initializes all the classes needed for the chain (i.e. redshifts of lens and source) """ self.z_d = z_d self.z_s = z_s self.cosmoProp = LCDM(z_lens=z_d, z_source=z_s, flat=flat) self._kde_likelihood = KDELikelihood(D_d_sample, D_delta_t_sample, kde_type=kde_type, bandwidth=bandwidth) self.sampling_option = sampling_option self.omega_m_fixed = omega_m_fixed self.omega_mh2_fixed = omega_mh2_fixed self._omega_lambda_fixed = omega_lambda_fixed
def test_kde_likelihood(self): # define redshift of lens and source z_L = 0.8 z_S = 3.0 # define the "truth" H0_true = 70 omega_m_true = 0.3 # setup the true cosmology cosmo = FlatLambdaCDM(H0_true, Om0=omega_m_true) lensCosmo = LensCosmo(z_L, z_S, cosmo=cosmo) # compute the true angular diameter distances Dd_true = lensCosmo.D_d D_dt_true = lensCosmo.D_dt # define a measurement uncertainty/spread in the posteriors # the example contains uncorrelated Gaussians sigma_Dd = 100 sigma_Ddt = 100 # make a realization of the posterior sample, centered around the "truth" with given uncertainties num_samples = 50000 D_dt_samples = np.random.normal(D_dt_true, sigma_Ddt, num_samples) D_d_samples = np.random.normal(Dd_true, sigma_Dd, num_samples) # initialize a KDELikelihood class with the posterior sample kdeLikelihood = KDELikelihood(D_d_samples, D_dt_samples, kde_type='scipy_gaussian', bandwidth=2) # evaluate the maximum likelihood (arbitrary normalization!) logL_max = kdeLikelihood.logLikelihood(Dd_true, D_dt_true) # evaluate the likelihood 1-sigma away from Dd logL_sigma = kdeLikelihood.logLikelihood(Dd_true + sigma_Dd, D_dt_true) # compute likelihood ratio delta_log = logL_max - logL_sigma # check whether likelihood ratio is consistent with input distribution # (in relative percent level in the likelihoods) npt.assert_almost_equal(delta_log, 0.5, decimal=2) # test the same in D_dt dimension logL_sigma = kdeLikelihood.logLikelihood(Dd_true, D_dt_true + sigma_Ddt) # compute likelihood ratio delta_log = logL_max - logL_sigma # check whether likelihood ratio is consistent with input distribution npt.assert_almost_equal(delta_log, 0.5, decimal=2)
def kdelikelihood(self, kde_type, bandwidth=20): """ Evaluates the likelihood of a angular diameter distance to the deflector Dd (in Mpc) versus its time-delay distance Ddt (in Mpc) against the model predictions, using a loglikelihood sampled from a Kernel Density Estimator. """ self.ddt = self.ddt_vs_dd["ddt"] self.dd = self.ddt_vs_dd["dd"] KDEl = KDELikelihood(self.dd.values, self.ddt.values, kde_type=kde_type, bandwidth=bandwidth) return KDEl.logLikelihood
def __init__(self, z_lens, z_source, dd_samples, ddt_samples, kde_type='scipy_gaussian', bandwidth=1, interpol=False, num_interp_grid=100): """ :param z_lens: lens redshift :param z_source: source redshift :param dd_samples: angular diameter to the lens posteriors (in physical Mpc) :param ddt_samples: time-delay distance posteriors (in physical Mpc) :param kde_type: kernel density estimator type (see KDELikelihood class) :param bandwidth: width of kernel (in same units as the angular diameter quantities) :param interpol: bool, if True pre-computes an interpolation likelihood in 2d on a grid :param num_interp_grid: int, number of interpolations per axis """ self._kde_likelihood = KDELikelihood(dd_samples, ddt_samples, kde_type=kde_type, bandwidth=bandwidth) if interpol is True: dd_grid = np.linspace(start=max(np.min(dd_samples), 0), stop=min(np.max(dd_samples), 10000), num=num_interp_grid) ddt_grid = np.linspace(np.min(ddt_samples), np.max(ddt_samples), num=num_interp_grid) z = np.zeros((num_interp_grid, num_interp_grid)) for i, dd in enumerate(dd_grid): for j, ddt in enumerate(ddt_grid): z[j, i] = self._kde_likelihood.logLikelihood(dd, ddt)[0] self._interp_log_likelihood = interpolate.interp2d(dd_grid, ddt_grid, z, kind='cubic') self._interpol = interpol self.num_data = 2
class CosmoLikelihood(object): """ this class contains the likelihood function of the Strong lensing analysis """ def __init__(self, z_d, z_s, D_d_sample, D_delta_t_sample, sampling_option="H0_only", omega_m_fixed=0.3, omega_lambda_fixed=0.7, omega_mh2_fixed=0.14157, kde_type='scipy_gaussian', bandwidth=1, flat=True): """ initializes all the classes needed for the chain (i.e. redshifts of lens and source) """ self.z_d = z_d self.z_s = z_s self.cosmoProp = LCDM(z_lens=z_d, z_source=z_s, flat=flat) self._kde_likelihood = KDELikelihood(D_d_sample, D_delta_t_sample, kde_type=kde_type, bandwidth=bandwidth) self.sampling_option = sampling_option self.omega_m_fixed = omega_m_fixed self.omega_mh2_fixed = omega_mh2_fixed self._omega_lambda_fixed = omega_lambda_fixed def X2_chain_H0(self, args): """ routine to compute X2 given variable parameters for a MCMC/PSO chain """ #extract parameters H0 = args[0] omega_m = self.omega_m_fixed Ode0 = self._omega_lambda_fixed logL, bool = self.prior_H0(H0) if bool is True: logL += self.LCDM_lensLikelihood(H0, omega_m, Ode0) return logL, None def X2_chain_omega_mh2(self, args): """ routine to compute the log likelihood given a omega_m h**2 prior fixed :param args: :return: """ H0 = args[0] h = H0 / 100. omega_m = self.omega_mh2_fixed / h**2 Ode0 = self._omega_lambda_fixed logL, bool = self.prior_omega_mh2(h, omega_m) if bool is True: logL += self.LCDM_lensLikelihood(H0, omega_m, Ode0) return logL, None def X2_chain_H0_omgega_m(self, args): """ routine to compute X^2 :param args: :return: """ #extract parameters [H0, omega_m] = args Ode0 = self._omega_lambda_fixed logL_H0, bool_H0 = self.prior_H0(H0) logL_omega_m, bool_omega_m = self.prior_omega_m(omega_m) logL = logL_H0 + logL_omega_m if bool_H0 is True and bool_omega_m is True: logL += self.LCDM_lensLikelihood(H0, omega_m, Ode0) return logL + logL_H0 + logL_omega_m, None def X2_chain_H0_omgega_m_omega_de(self, args): """ routine to compute X^2 :param args: :return: """ #extract parameters [H0, omega_m, Ode0] = args logL_H0, bool_H0 = self.prior_H0(H0) logL_omega_m, bool_omega_m = self.prior_omega_m(omega_m) logL = logL_H0 + logL_omega_m if bool_H0 is True and bool_omega_m is True: logL += self.LCDM_lensLikelihood(H0, omega_m, Ode0) return logL + logL_H0 + logL_omega_m, None def LCDM_lensLikelihood(self, H0, omega_m, Ode0=None): Dd = self.cosmoProp.D_d(H0, omega_m, Ode0) Ddt = self.cosmoProp.D_dt(H0, omega_m, Ode0) return self.lensLikelihood(Dd, Ddt) def lensLikelihood(self, Dd, Ddt): """ :param alpha: :param beta: :param sigma_D: :return: """ logL = self._kde_likelihood.logLikelihood(Dd, Ddt) return logL @staticmethod def prior_H0(H0, H0_min=0, H0_max=200): """ checks whether the parameter vector has left its bound, if so, adds a big number """ if H0 < H0_min or H0 > H0_max: penalty = -10**15 return penalty, False else: return 0, True @staticmethod def prior_omega_m(omega_m, omega_m_min=0, omega_m_max=1): """ checks whether the parameter omega_m is within the given bounds :param omega_m: :param omega_m_min: :param omega_m_max: :return: """ if omega_m < omega_m_min or omega_m > omega_m_max: penalty = -10**15 return penalty, False else: return 0, True def prior_omega_mh2(self, h, omega_m, h_max=2): """ """ if omega_m > 1 or h > h_max: penalty = -10**15 return penalty, False else: prior = np.log(np.sqrt(1 + 4 * self.omega_mh2_fixed**2 / h**6)) return prior, True def likelihood(self, a): logL, _ = self._likelihood(a) return logL def _likelihood(self, a): if self.sampling_option == 'H0_only': return self.X2_chain_H0(a) elif self.sampling_option == 'H0_omega_m': return self.X2_chain_H0_omgega_m(a) elif self.sampling_option == "fix_omega_mh2": return self.X2_chain_omega_mh2(a) elif self.sampling_option == 'H0_omega_m_omega_de': return self.X2_chain_H0_omgega_m_omega_de(a) else: raise ValueError("sampling method %s not supported!" % self.sampling_option)
class DdtDdKDELikelihood(object): """ class for evaluating the 2-d posterior of Ddt vs Dd coming from a lens with time delays and kinematics measurement """ def __init__(self, z_lens, z_source, dd_samples, ddt_samples, kde_type='scipy_gaussian', bandwidth=1, interpol=False, num_interp_grid=100): """ :param z_lens: lens redshift :param z_source: source redshift :param dd_samples: angular diameter to the lens posteriors (in physical Mpc) :param ddt_samples: time-delay distance posteriors (in physical Mpc) :param kde_type: kernel density estimator type (see KDELikelihood class) :param bandwidth: width of kernel (in same units as the angular diameter quantities) :param interpol: bool, if True pre-computes an interpolation likelihood in 2d on a grid :param num_interp_grid: int, number of interpolations per axis """ self._kde_likelihood = KDELikelihood(dd_samples, ddt_samples, kde_type=kde_type, bandwidth=bandwidth) if interpol is True: dd_grid = np.linspace(start=max(np.min(dd_samples), 0), stop=min(np.max(dd_samples), 10000), num=num_interp_grid) ddt_grid = np.linspace(np.min(ddt_samples), np.max(ddt_samples), num=num_interp_grid) z = np.zeros((num_interp_grid, num_interp_grid)) for i, dd in enumerate(dd_grid): for j, ddt in enumerate(ddt_grid): z[j, i] = self._kde_likelihood.logLikelihood(dd, ddt)[0] self._interp_log_likelihood = interpolate.interp2d(dd_grid, ddt_grid, z, kind='cubic') self._interpol = interpol self.num_data = 2 def log_likelihood(self, ddt, dd, aniso_scaling=None): """ :param ddt: time-delay distance :param dd: angular diameter distance to the deflector :param aniso_scaling: array of size of the velocity dispersion measurement or None, scaling of the predicted dimensionless quantity J (proportional to sigma_v^2) of the anisotropy model in the sampling relative to the anisotropy model used to derive the prediction and covariance matrix in the init of this class. :return: log likelihood given the single lens analysis """ if aniso_scaling is not None: dd_ = dd * aniso_scaling[0] else: dd_ = dd if self._interpol is True: return self._interp_log_likelihood(dd_, ddt)[0] return self._kde_likelihood.logLikelihood(dd_, ddt)[0]