def test_class_setup(): cosmology = astropy.cosmology.Planck13 assert cosmology.Om0 == cosmology.Odm0 + cosmology.Ob0 assert 1 == (cosmology.Om0 + cosmology.Ode0 + cosmology.Ok0 + cosmology.Ogamma0 + cosmology.Onu0) class_parameters = get_class_parameters(cosmology) try: from classy import Class cosmo = Class() cosmo.set(class_parameters) cosmo.compute() assert cosmo.h() == cosmology.h assert cosmo.T_cmb() == cosmology.Tcmb0.value assert cosmo.Omega_b() == cosmology.Ob0 # Calculate Omega(CDM)_0 two ways: assert abs((cosmo.Omega_m() - cosmo.Omega_b()) - (cosmology.Odm0 - cosmology.Onu0)) < 1e-8 assert abs(cosmo.Omega_m() - (cosmology.Om0 - cosmology.Onu0)) < 1e-8 # CLASS calculates Omega_Lambda itself so this is a non-trivial test. calculated_Ode0 = cosmo.get_current_derived_parameters( ['Omega_Lambda'])['Omega_Lambda'] assert abs(calculated_Ode0 - (cosmology.Ode0 + cosmology.Onu0)) < 1e-5 cosmo.struct_cleanup() cosmo.empty() except ImportError: pass
def calculate_spectra(self, cosmo_params, force_recalc=False): settings = cosmo_params.copy() settings.update({ "output": "tCl,mPk", "evolver": "1", "gauge": "newtonian", "P_k_max_1/Mpc": 10, }) database = Database(config.DATABASE_DIR, "spectra.dat") if settings in database and not force_recalc: data = database[settings] ell = data["ell"] tt = data["tt"] kh = data["kh"] Pkh = data["Pkh"] self.z_rec = data["z_rec"] else: cosmo = Class() cosmo.set(settings) cosmo.compute() # Cl's data = cosmo.raw_cl() ell = data["ell"] tt = data["tt"] # Matter spectrum k = np.logspace(-3, 1, config.MATTER_SPECTRUM_CLIENT_SAMPLES_PER_DECADE * 4) Pk = np.vectorize(cosmo.pk)(k, 0) kh = k * cosmo.h() Pkh = Pk / cosmo.h()**3 # Get redshift of decoupling z_rec = cosmo.get_current_derived_parameters(['z_rec'])['z_rec'] self.z_rec = z_rec # Store to database database[settings] = { "ell": data["ell"], "tt": data["tt"], "kh": k, "Pkh": Pk, "z_rec": z_rec, } return ClSpectrum(ell[2:], tt[2:]), PkSpectrum(kh, Pkh)
def calculate_power(cosmology, k_min, k_max, z=0, num_k=500, scaled_by_h=True, n_s=0.9619, logA=3.0980): """ Calculate the power spectrum P(k,z) over the range k_min <= k <= k_max. """ try: from classy import Class cosmo = Class() except ImportError: raise RuntimeError('power.calculate_power requires classy.') class_parameters = get_class_parameters(cosmology) class_parameters['output'] = 'mPk' if scaled_by_h: class_parameters['P_k_max_h/Mpc'] = k_max else: class_parameters['P_k_max_1/Mpc'] = k_max class_parameters['n_s'] = n_s class_parameters['ln10^{10}A_s'] = logA cosmo.set(class_parameters) cosmo.compute() if scaled_by_h: k_scale = cosmo.h() Pk_scale = cosmo.h()**3 else: k_scale = 1. Pk_scale = 1. result = np.empty((num_k, ), dtype=[('k', float), ('Pk', float)]) result['k'][:] = np.logspace(np.log10(k_min), np.log10(k_max), num_k) for i, k in enumerate(result['k']): result['Pk'][i] = cosmo.pk(k * k_scale, z) * Pk_scale cosmo.struct_cleanup() cosmo.empty() return result
def calculate_power(cosmology, k_min, k_max, z=0, num_k=500, scaled_by_h=True, n_s=0.9619, logA=3.0980): """ Calculate the power spectrum P(k,z) over the range k_min <= k <= k_max. """ try: from classy import Class cosmo = Class() except ImportError: raise RuntimeError('power.calculate_power requires classy.') class_parameters = get_class_parameters(cosmology) class_parameters['output'] = 'mPk' if scaled_by_h: class_parameters['P_k_max_h/Mpc'] = k_max else: class_parameters['P_k_max_1/Mpc'] = k_max class_parameters['n_s'] = n_s class_parameters['ln10^{10}A_s'] = logA cosmo.set(class_parameters) cosmo.compute() if scaled_by_h: k_scale = cosmo.h() Pk_scale = cosmo.h()**3 else: k_scale = 1. Pk_scale = 1. result = np.empty((num_k,), dtype=[('k', float), ('Pk', float)]) result['k'][:] = np.logspace(np.log10(k_min), np.log10(k_max), num_k) for i, k in enumerate(result['k']): result['Pk'][i] = cosmo.pk(k * k_scale, z) * Pk_scale cosmo.struct_cleanup() cosmo.empty() return result
class Cosmology(object): """ Class to hold the basic cosmology and CLASS attributes. This can be initialized by a set of cosmological parameters or a pre-defined cosmology. Loaded cosmological models: - **Planck18**: Bestfit cosmology from Planck 2018, using the baseline TT,TE,EE+lowE+lensing likelihood. - **Quijote**: Fiducial cosmology from the Quijote simulations of Francisco Villaescusa-Navarro et al. - **Abacus**: Fiducial cosmology from the Abacus simulations of Lehman Garrison et al. Args: redshift (float): Desired redshift :math:`z` name (str): Load cosmology from a list of predetermined cosmologies (see above). params (kwargs): Any other CLASS parameters. (Note that sigma8 does not seem to be supported by CLASS in Python 3). Keyword Args: verb (bool): If true output useful messages througout run-time, default: False. npoints (int): Number of points to use in the interpolators for sigma^2, default: 100000 """ loaded_models = {'Quijote':{"h":0.6711,"omega_cdm":(0.3175 - 0.049)*0.6711**2, "Omega_b":0.049, "n_s":0.9624, "N_eff":3.046, "A_s":2.134724e-09}, #"sigma8":0.834, 'Abacus':{"h":0.6726,"omega_cdm":0.1199, "omega_b":0.02222,"n_s":0.9652,"A_s":2.135472e-09,#"sigma8":0.830, "N_eff":3.046}, 'Planck18':{"h":0.6732,"omega_cdm":0.12011,"omega_b":0.022383, "n_s":0.96605,"A_s":2.042644e-09}}#,"sigma8":0.8120}} def __init__(self,redshift,name="",verb=False,npoints=int(1e5),**params): """ Initialize the cosmology class with cosmological parameters or a defined model. """ ## Load parameters into a dictionary to pass to CLASS class_params = dict(**params) if len(name)>0: if len(params.items())>0: raise Exception('Must either choose a preset cosmology or specify parameters!') if name in self.loaded_models.keys(): if verb: print('Loading the %s cosmology at z = %.2f'%(name,redshift)) loaded_model = self.loaded_models[name] for key in loaded_model.keys(): class_params[key] = loaded_model[key] else: raise Exception("This cosmology isn't yet implemented") else: if len(params.items())==0: if verb: print('Using default CLASS cosmology') for name, param in params.items(): class_params[name] = param ## # Check we have the correct parameters if 'sigma8' in class_params.keys() and 'A_s' in class_params.keys(): raise NameError('Cannot specify both A_s and sigma8!') ## Define other parameters self.z = redshift self.a = 1./(1.+redshift) if 'output' not in class_params.keys(): class_params['output']='mPk' if 'P_k_max_h/Mpc' not in class_params.keys() and 'P_k_max_1/Mpc' not in class_params.keys(): class_params['P_k_max_h/Mpc']=300. if 'z_pk' in class_params.keys(): assert class_params['z_pk']==redshift, "Can't pass multiple redshifts!" else: class_params['z_pk']=redshift ## Load CLASS and set parameters if verb: print('Loading CLASS') self.cosmo = Class() self.cosmo.set(class_params) self.cosmo.compute() self.h = self.cosmo.h() self.name = name self.npoints = npoints self.verb = verb ## Check if we're using neutrinos here if self.cosmo.Omega_nu>0.: if self.verb: print("Using a neutrino fraction of Omega_nu = %.3e"%self.cosmo.Omega_nu) self.use_neutrinos = True # Define neutrino mass fraction self.f_nu = self.cosmo.Omega_nu/self.cosmo.Omega_m() if self.cosmo.Neff()>3.5: print("N_eff > 3.5, which seems large (standard value: 3.046). This may indicate that N_ur has not been set.") else: if self.verb: print("Assuming massless neturinos.") self.use_neutrinos = False ## Create a vectorized sigma(R) function from CLASS if self.use_neutrinos: self.vector_sigma_R = np.vectorize(lambda r: self.cosmo.sigma_cb(r/self.h,self.z)) else: self.vector_sigma_R = np.vectorize(lambda r: self.cosmo.sigma(r/self.h,self.z)) # get density in physical units at z = 0 # rho_critical is in Msun/h / (Mpc/h)^3 units # rhoM is in **physical** units of Msun/Mpc^3 self.rho_critical = ((3.*100.*100.)/(8.*np.pi*6.67408e-11)) * (1000.*1000.*3.085677581491367399198952281E+22/1.9884754153381438E+30) self.rhoM = self.rho_critical*self.cosmo.Omega0_m() def compute_linear_power(self,kh,kh_min=0.,with_neutrinos=False): """Compute the linear power spectrum from CLASS for a vector of input k. If set, we remove any modes below some minimum k. Args: kh (float, np.ndarray): Wavenumber or vector of wavenumbers (in h/Mpc units) to compute linear power with. Keyword Args: kh_min (float): Value of k (in h/Mpc units) below which to set :math:`P(k) = 0`, default: 0. with_neutrinos (bool): If True, return the full matter power spectrum, else return the CDM+baryon power spectrum (which is generally used in the halo model). Default: False. Returns: np.ndarray: Linear power spectrum in :math:`(h^{-1}\mathrm{Mpc})^3` units """ if type(kh)==np.ndarray: # Define output vector and filter modes with too-small k output = np.zeros_like(kh) filt = np.where(kh>kh_min) N_k = len(filt[0]) # Compute Pk using CLASS (vectorized) if not hasattr(self,'vector_linear_power'): ## NB: This works in physical 1/Mpc units so we convert here if self.use_neutrinos: # Here we need both the CDM+baryon (cb) power spectra and the full matter power spectra # The CDM+baryon spectrum is used for the halo model parts, and the residual (matter-cb) added at the end self.vector_linear_power = np.vectorize(lambda k: self.cosmo.pk_cb_lin(k*self.h,self.z)*self.h**3.) self.vector_linear_power_total = np.vectorize(lambda k: self.cosmo.pk_lin(k*self.h,self.z)*self.h**3.) else: self.vector_linear_power = np.vectorize(lambda k: self.cosmo.pk_lin(k*self.h,self.z)*self.h**3.) if self.use_neutrinos and with_neutrinos: output[filt] = self.vector_linear_power_total(kh[filt]) else: output[filt] = self.vector_linear_power(kh[filt]) return output else: if kh<kh_min: return 0. else: if self.use_neutrinos and with_neutrinos: return self.vector_linear_power_total(kh) else: return self.vector_linear_power(kh) def sigma_logM_int(self,logM_h): """Return the value of :math:`\sigma(M,z)` using the prebuilt interpolators, which are constructed if not present. Args: logM (np.ndarray): Input :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})` Returns: np.ndarray: :math:`\sigma(M,z)` """ if not hasattr(self,'sigma_logM_int_func'): self._interpolate_sigma_and_deriv(npoints=self.npoints) return self._sigma_logM_int_func(logM_h) def dlns_dlogM_int(self,logM_h): """Return the value of :math:`d\ln\sigma/d\log M` using the prebuilt interpolators, which are constructed if not present. Args: logM (np.ndarray): Input :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})` Returns: np.ndarray: :math:`d\ln\sigma/d\log M` """ if not hasattr(self,'dlns_dlogM_int_func'): self._interpolate_sigma_and_deriv(npoints=self.npoints) return self._dlns_dlogM_int_func(logM_h) def _sigmaM(self,M_h): """Compute :math:`\sigma(M,z)` from CLASS as a vector function. Args: M_h (np.ndarray): Mass in :math:`h^{-1}M_\mathrm{sun}` units. z (float): Redshift. Returns: np.ndarray: :math:`\sigma(M,z)` """ # convert to Lagrangian radius r_h = np.power((3.*M_h)/(4.*np.pi*self.rhoM),1./3.) sigma_func = self.vector_sigma_R(r_h) return sigma_func def _interpolate_sigma_and_deriv(self,logM_h_min=6,logM_h_max=17,npoints=int(1e5)): """Create an interpolator function for :math:`d\ln\sigma/d\log M` and :math:`sigma(M)`. NB: This has no effect if the interpolator has already been computed. Keyword Args: logM_min (float): Minimum mass in :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`, default: 6 logM_max (float): Maximum mass in :math:`\log_{10}(M/h^{-1}M_\mathrm{sun})`, default 17 npoints (int): Number of sampling points, default 100000 """ if not hasattr(self,'_sigma_logM_int_func'): if self.verb: print("Creating an interpolator for sigma(M) and its derivative.") ## Compute log derivative by interpolation and numerical differentiation # First compute the grid of M and sigma M_h_grid = np.logspace(logM_h_min,logM_h_max,10000) all_sigM = self._sigmaM(M_h_grid) logM_h_grid = np.log10(M_h_grid) # Define ln(sigma) and numerical derivatives all_lns = np.log(all_sigM) all_diff = -np.diff(all_lns)/np.diff(logM_h_grid) mid_logM_h = 0.5*(logM_h_grid[:-1]+logM_h_grid[1:]) self._sigma_logM_int_func = interp1d(logM_h_grid,all_sigM) self._dlns_dlogM_int_func = interp1d(mid_logM_h,all_diff) def _h_over_h0(self): """Return the value of :math:`H(z)/H(0)` at the class redshift Returns: float: :math:`H(z)/H(0)` """ Omega0_k = 1.-self.cosmo.Omega0_m()-self.cosmo.Omega_Lambda() Ea = np.sqrt((self.cosmo.Omega0_m()+self.cosmo.Omega_Lambda()*pow(self.a,-3)+Omega0_k*self.a)/pow(self.a,3)) return Ea def _Omega_m(self): """Return the value of :math:`\Omega_m(z)` at the class redshift
class classy(BoltzmannBase): # Name of the Class repo/folder and version to download _classy_repo_name = "lesgourg/class_public" _min_classy_version = "v2.9.3" _classy_repo_version = os.environ.get('CLASSY_REPO_VERSION', _min_classy_version) def initialize(self): """Importing CLASS from the correct path, if given, and if not, globally.""" # Allow global import if no direct path specification allow_global = not self.path if not self.path and self.packages_path: self.path = self.get_path(self.packages_path) self.classy_module = self.is_installed(path=self.path, allow_global=allow_global) if not self.classy_module: raise NotInstalledError( self.log, "Could not find CLASS. Check error message above.") from classy import Class, CosmoSevereError, CosmoComputationError global CosmoComputationError, CosmoSevereError self.classy = Class() super().initialize() # Add general CLASS stuff self.extra_args["output"] = self.extra_args.get("output", "") if "sBBN file" in self.extra_args: self.extra_args["sBBN file"] = ( self.extra_args["sBBN file"].format(classy=self.path)) # Derived parameters that may not have been requested, but will be necessary later self.derived_extra = [] self.log.info("Initialized!") def must_provide(self, **requirements): # Computed quantities required by the likelihood super().must_provide(**requirements) for k, v in self._must_provide.items(): # Products and other computations if k == "Cl": if any(("t" in cl.lower()) for cl in v): self.extra_args["output"] += " tCl" if any((("e" in cl.lower()) or ("b" in cl.lower())) for cl in v): self.extra_args["output"] += " pCl" # For modern experiments, always lensed Cl's! self.extra_args["output"] += " lCl" self.extra_args["lensing"] = "yes" # For l_max_scalars, remember previous entries. self.extra_args["l_max_scalars"] = max(v.values()) self.collectors[k] = Collector( method="lensed_cl", kwargs={"lmax": self.extra_args["l_max_scalars"]}) if 'T_cmb' not in self.derived_extra: self.derived_extra += ['T_cmb'] elif k == "Hubble": self.collectors[k] = Collector( method="Hubble", args=[np.atleast_1d(v["z"])], args_names=["z"], arg_array=0) elif k == "angular_diameter_distance": self.collectors[k] = Collector( method="angular_distance", args=[np.atleast_1d(v["z"])], args_names=["z"], arg_array=0) elif k == "comoving_radial_distance": self.collectors[k] = Collector( method="z_of_r", args_names=["z"], args=[np.atleast_1d(v["z"])]) elif isinstance(k, tuple) and k[0] == "Pk_grid": self.extra_args["output"] += " mPk" v = deepcopy(v) self.add_P_k_max(v.pop("k_max"), units="1/Mpc") # NB: Actually, only the max z is used, and the actual sampling in z # for computing P(k,z) is controlled by `perturb_sampling_stepsize` # (default: 0.1). But let's leave it like this in case this changes # in the future. self.add_z_for_matter_power(v.pop("z")) if v["nonlinear"] and "non linear" not in self.extra_args: self.extra_args["non linear"] = non_linear_default_code pair = k[2:] if pair == ("delta_tot", "delta_tot"): v["only_clustering_species"] = False elif pair == ("delta_nonu", "delta_nonu"): v["only_clustering_species"] = True else: raise LoggedError(self.log, "NotImplemented in CLASS: %r", pair) self.collectors[k] = Collector( method="get_pk_and_k_and_z", kwargs=v, post=(lambda P, kk, z: (kk, z, np.array(P).T))) elif isinstance(k, tuple) and k[0] == "sigma_R": raise LoggedError( self.log, "Classy sigma_R not implemented as yet - use CAMB only") elif v is None: k_translated = self.translate_param(k) if k_translated not in self.derived_extra: self.derived_extra += [k_translated] else: raise LoggedError(self.log, "Requested product not known: %r", {k: v}) # Derived parameters (if some need some additional computations) if any(("sigma8" in s) for s in self.output_params or requirements): self.extra_args["output"] += " mPk" self.add_P_k_max(1, units="1/Mpc") # Adding tensor modes if requested if self.extra_args.get("r") or "r" in self.input_params: self.extra_args["modes"] = "s,t" # If B spectrum with l>50, or lensing, recommend using Halofit cls = self._must_provide.get("Cl", {}) has_BB_l_gt_50 = (any(("b" in cl.lower()) for cl in cls) and max(cls[cl] for cl in cls if "b" in cl.lower()) > 50) has_lensing = any(("p" in cl.lower()) for cl in cls) if (has_BB_l_gt_50 or has_lensing) and not self.extra_args.get("non linear"): self.log.warning("Requesting BB for ell>50 or lensing Cl's: " "using a non-linear code is recommended (and you are not " "using any). To activate it, set " "'non_linear: halofit|hmcode|...' in classy's 'extra_args'.") # Cleanup of products string self.extra_args["output"] = " ".join(set(self.extra_args["output"].split())) self.check_no_repeated_input_extra() def add_z_for_matter_power(self, z): if getattr(self, "z_for_matter_power", None) is None: self.z_for_matter_power = np.empty(0) self.z_for_matter_power = np.flip(np.sort(np.unique(np.concatenate( [self.z_for_matter_power, np.atleast_1d(z)]))), axis=0) self.extra_args["z_pk"] = " ".join(["%g" % zi for zi in self.z_for_matter_power]) def add_P_k_max(self, k_max, units): r""" Unifies treatment of :math:`k_\mathrm{max}` for matter power spectrum: ``P_k_max_[1|h]/Mpc]``. Make ``units="1/Mpc"|"h/Mpc"``. """ # Fiducial h conversion (high, though it may slow the computations) h_fid = 1 if units == "h/Mpc": k_max *= h_fid # Take into account possible manual set of P_k_max_***h/Mpc*** through extra_args k_max_old = self.extra_args.pop( "P_k_max_1/Mpc", h_fid * self.extra_args.pop("P_k_max_h/Mpc", 0)) self.extra_args["P_k_max_1/Mpc"] = max(k_max, k_max_old) def set(self, params_values_dict): # If no output requested, remove arguments that produce an error # (e.g. complaints if halofit requested but no Cl's computed.) # Needed for facilitating post-processing if not self.extra_args["output"]: for k in ["non linear"]: self.extra_args.pop(k, None) # Prepare parameters to be passed: this-iteration + extra args = {self.translate_param(p): v for p, v in params_values_dict.items()} args.update(self.extra_args) # Generate and save self.log.debug("Setting parameters: %r", args) self.classy.set(**args) def calculate(self, state, want_derived=True, **params_values_dict): # Set parameters self.set(params_values_dict) # Compute! try: self.classy.compute() # "Valid" failure of CLASS: parameters too extreme -> log and report except CosmoComputationError as e: if self.stop_at_error: self.log.error( "Computation error (see traceback below)! " "Parameters sent to CLASS: %r and %r.\n" "To ignore this kind of error, make 'stop_at_error: False'.", state["params"], dict(self.extra_args)) raise else: self.log.debug("Computation of cosmological products failed. " "Assigning 0 likelihood and going on. " "The output of the CLASS error was %s" % e) return False # CLASS not correctly initialized, or input parameters not correct except CosmoSevereError: self.log.error("Serious error setting parameters or computing results. " "The parameters passed were %r and %r. To see the original " "CLASS' error traceback, make 'debug: True'.", state["params"], self.extra_args) raise # No LoggedError, so that CLASS traceback gets printed # Gather products for product, collector in self.collectors.items(): # Special case: sigma8 needs H0, which cannot be known beforehand: if "sigma8" in self.collectors: self.collectors["sigma8"].args[0] = 8 / self.classy.h() method = getattr(self.classy, collector.method) arg_array = self.collectors[product].arg_array if arg_array is None: state[product] = method( *self.collectors[product].args, **self.collectors[product].kwargs) elif isinstance(arg_array, int): state[product] = np.zeros( len(self.collectors[product].args[arg_array])) for i, v in enumerate(self.collectors[product].args[arg_array]): args = (list(self.collectors[product].args[:arg_array]) + [v] + list(self.collectors[product].args[arg_array + 1:])) state[product][i] = method( *args, **self.collectors[product].kwargs) elif arg_array in self.collectors[product].kwargs: value = np.atleast_1d(self.collectors[product].kwargs[arg_array]) state[product] = np.zeros(value.shape) for i, v in enumerate(value): kwargs = deepcopy(self.collectors[product].kwargs) kwargs[arg_array] = v state[product][i] = method( *self.collectors[product].args, **kwargs) if collector.post: state[product] = collector.post(*state[product]) # Prepare derived parameters d, d_extra = self._get_derived_all(derived_requested=want_derived) if want_derived: state["derived"] = {p: d.get(p) for p in self.output_params} # Prepare necessary extra derived parameters state["derived_extra"] = deepcopy(d_extra) def _get_derived_all(self, derived_requested=True): """ Returns a dictionary of derived parameters with their values, using the *current* state (i.e. it should only be called from the ``compute`` method). Parameter names are returned in CLASS nomenclature. To get a parameter *from a likelihood* use `get_param` instead. """ # TODO: fails with derived_requested=False # Put all parameters in CLASS nomenclature (self.derived_extra already is) requested = [self.translate_param(p) for p in ( self.output_params if derived_requested else [])] requested_and_extra = dict.fromkeys(set(requested).union(set(self.derived_extra))) # Parameters with their own getters if "rs_drag" in requested_and_extra: requested_and_extra["rs_drag"] = self.classy.rs_drag() if "Omega_nu" in requested_and_extra: requested_and_extra["Omega_nu"] = self.classy.Omega_nu if "T_cmb" in requested_and_extra: requested_and_extra["T_cmb"] = self.classy.T_cmb() # Get the rest using the general derived param getter # No need for error control: classy.get_current_derived_parameters is passed # every derived parameter not excluded before, and cause an error, indicating # which parameters are not recognized requested_and_extra.update( self.classy.get_current_derived_parameters( [p for p, v in requested_and_extra.items() if v is None])) # Separate the parameters before returning # Remember: self.output_params is in sampler nomenclature, # but self.derived_extra is in CLASS derived = { p: requested_and_extra[self.translate_param(p)] for p in self.output_params} derived_extra = {p: requested_and_extra[p] for p in self.derived_extra} return derived, derived_extra def get_Cl(self, ell_factor=False, units="FIRASmuK2"): try: cls = deepcopy(self._current_state["Cl"]) except: raise LoggedError( self.log, "No Cl's were computed. Are you sure that you have requested them?") # unit conversion and ell_factor ells_factor = ((cls["ell"] + 1) * cls["ell"] / (2 * np.pi))[ 2:] if ell_factor else 1 units_factor = self._cmb_unit_factor( units, self._current_state['derived_extra']['T_cmb']) for cl in cls: if cl not in ['pp', 'ell']: cls[cl][2:] *= units_factor ** 2 * ells_factor if "pp" in cls and ell_factor: cls['pp'][2:] *= ells_factor ** 2 * (2 * np.pi) return cls def _get_z_dependent(self, quantity, z): try: z_name = next(k for k in ["redshifts", "z"] if k in self.collectors[quantity].kwargs) computed_redshifts = self.collectors[quantity].kwargs[z_name] except StopIteration: computed_redshifts = self.collectors[quantity].args[ self.collectors[quantity].args_names.index("z")] i_kwarg_z = np.concatenate( [np.where(computed_redshifts == zi)[0] for zi in np.atleast_1d(z)]) values = np.array(deepcopy(self._current_state[quantity])) if quantity == "comoving_radial_distance": values = values[0] return values[i_kwarg_z] def close(self): self.classy.empty() def get_can_provide_params(self): names = ['Omega_Lambda', 'Omega_cdm', 'Omega_b', 'Omega_m', 'rs_drag', 'z_reio', 'YHe', 'Omega_k', 'age', 'sigma8'] for name, mapped in self.renames.items(): if mapped in names: names.append(name) return names def get_version(self): return getattr(self.classy_module, '__version__', None) # Installation routines @classmethod def get_path(cls, path): return os.path.realpath(os.path.join(path, "code", cls.__name__)) @classmethod def get_import_path(cls, path): log = logging.getLogger(cls.__name__) classy_build_path = os.path.join(path, "python", "build") if not os.path.isdir(classy_build_path): log.error("Either CLASS is not in the given folder, " "'%s', or you have not compiled it.", path) return None py_version = "%d.%d" % (sys.version_info.major, sys.version_info.minor) try: post = next(d for d in os.listdir(classy_build_path) if (d.startswith("lib.") and py_version in d)) except StopIteration: log.error("The CLASS installation at '%s' has not been compiled for the " "current Python version.", path) return None return os.path.join(classy_build_path, post) @classmethod def is_compatible(cls): import platform if platform.system() == "Windows": return False return True @classmethod def is_installed(cls, **kwargs): log = logging.getLogger(cls.__name__) if not kwargs.get("code", True): return True path = kwargs["path"] if path is not None and path.lower() == "global": path = None if path and not kwargs.get("allow_global"): log.info("Importing *local* CLASS from '%s'.", path) if not os.path.exists(path): log.error("The given folder does not exist: '%s'", path) return False classy_build_path = cls.get_import_path(path) if not classy_build_path: return False elif not path: log.info("Importing *global* CLASS.") classy_build_path = None else: log.info("Importing *auto-installed* CLASS (but defaulting to *global*).") classy_build_path = cls.get_import_path(path) try: return load_module( 'classy', path=classy_build_path, min_version=cls._classy_repo_version) except ImportError: if path is not None and path.lower() != "global": log.error("Couldn't find the CLASS python interface at '%s'. " "Are you sure it has been installed there?", path) else: log.error("Could not import global CLASS installation. " "Specify a Cobaya or CLASS installation path, " "or install the CLASS Python interface globally with " "'cd /path/to/class/python/ ; python setup.py install'") return False except VersionCheckError as e: log.error(str(e)) return False @classmethod def install(cls, path=None, force=False, code=True, no_progress_bars=False, **kwargs): log = logging.getLogger(cls.__name__) if not code: log.info("Code not requested. Nothing to do.") return True log.info("Installing pre-requisites...") exit_status = pip_install("cython") if exit_status: log.error("Could not install pre-requisite: cython") return False log.info("Downloading classy...") success = download_github_release( os.path.join(path, "code"), cls._classy_repo_name, cls._classy_repo_version, repo_rename=cls.__name__, no_progress_bars=no_progress_bars, logger=log) if not success: log.error("Could not download classy.") return False classy_path = cls.get_path(path) log.info("Compiling classy...") from subprocess import Popen, PIPE env = deepcopy(os.environ) env.update({"PYTHON": sys.executable}) process_make = Popen(["make"], cwd=classy_path, stdout=PIPE, stderr=PIPE, env=env) out, err = process_make.communicate() if process_make.returncode: log.info(out) log.info(err) log.error("Compilation failed!") return False return True
plt.ylabel(r'$[\ell(\ell+1)/2\pi] C_\ell^\mathrm{TT}$') plt.plot(ll,clTT*ll*(ll+1)/2./pi,'r-') # In[ ]: plt.savefig('warmup_cltt.pdf') # In[ ]: # get P(k) at redhsift z=0 import numpy as np kk = np.logspace(-4,np.log10(3),1000) # k in h/Mpc Pk = [] # P(k) in (Mpc/h)**3 h = LambdaCDM.h() # get reduced Hubble for conversions to 1/Mpc for k in kk: Pk.append(LambdaCDM.pk(k*h,0.)*h**3) # function .pk(k,z) # In[ ]: # plot P(k) plt.figure(2) plt.xscale('log');plt.yscale('log');plt.xlim(kk[0],kk[-1]) plt.xlabel(r'$k \,\,\,\, [h/\mathrm{Mpc}]$') plt.ylabel(r'$P(k) \,\,\,\, [\mathrm{Mpc}/h]^3$') plt.plot(kk,Pk,'b-') # In[ ]:
class tsz_cl: def __init__(self): self.fort_lib_cl = cdll.LoadLibrary(LIBDIR + "/source/calc_cl") self.fort_lib_cl.calc_cl_.argtypes = [ POINTER(c_double), #h0 POINTER(c_double), #obh2 POINTER(c_double), #och2 POINTER(c_double), #mnu POINTER(c_double), #bias POINTER(c_int64), #pk_nk POINTER(c_int64), #pk_nz np.ctypeslib.ndpointer(dtype=np.double), #karr np.ctypeslib.ndpointer(dtype=np.double), #pkarr np.ctypeslib.ndpointer(dtype=np.double), #pk_z_arr POINTER(c_int64), #n_ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ptilde_arr POINTER(c_int64), #nl np.ctypeslib.ndpointer(dtype=np.double), #ell np.ctypeslib.ndpointer(dtype=np.double), #yy np.ctypeslib.ndpointer(dtype=np.double), #tll POINTER(c_int64), #flag_nu POINTER(c_int64), #flag_tll POINTER(c_double), #zmin POINTER(c_double), #zmax POINTER(c_double), #Mmin POINTER(c_double) #Mmax ] self.fort_lib_cl.calc_cl_.restype = c_void_p self.fort_lib_by = cdll.LoadLibrary(LIBDIR + "/source/calc_by") self.fort_lib_by.calc_by_.argtypes = [ POINTER(c_double), #h0 POINTER(c_double), #obh2 POINTER(c_double), #och2 POINTER(c_double), #mnu POINTER(c_double), #bias POINTER(c_int64), #pk_nk np.ctypeslib.ndpointer(dtype=np.double), #karr np.ctypeslib.ndpointer(dtype=np.double), #pkarr POINTER(c_int64), #n_ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ptilde_arr POINTER(c_int64), #nz np.ctypeslib.ndpointer(dtype=np.double), #z_arr np.ctypeslib.ndpointer(dtype=np.double), #by_arr np.ctypeslib.ndpointer(dtype=np.double), #dydz_arr POINTER(c_int64), #flag_nu POINTER(c_double), #Mmin POINTER(c_double) #Mmax ] self.fort_lib_by.calc_by_.restype = c_void_p self.fort_lib_dydzdMh = cdll.LoadLibrary(LIBDIR + "/source/calc_dydzdMh") self.fort_lib_dydzdMh.calc_dydzdmh_.argtypes = [ POINTER(c_double), #h0 POINTER(c_double), #obh2 POINTER(c_double), #och2 POINTER(c_double), #mnu POINTER(c_double), #bias POINTER(c_int64), #pk_nk POINTER(c_int64), #pk_nz np.ctypeslib.ndpointer(dtype=np.double), #karr np.ctypeslib.ndpointer(dtype=np.double), #pkarr POINTER(c_int64), #n_ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ell_ptilde np.ctypeslib.ndpointer(dtype=np.double), #ptilde_arr POINTER(c_double), # z POINTER(c_double), # Mh POINTER(c_double), # dydzdMh POINTER(c_int64), #flag_nu ] self.fort_lib_dydzdMh.calc_dydzdmh_.restype = c_void_p # Calcualtion setup self.kmin = 1e-3 self.kmax = 5. self.zmin = 1e-5 self.zmax = 4. self.dz = 0.04 self.nk_pk = 200 self.nz_pk = int((self.zmax - self.zmin) / self.dz) + 1 self.Mmin = 1e11 self.Mmax = 5e15 self.ptilde_in = np.loadtxt(LIBDIR + '/data/ptilde.txt') self.ell_ptilde = np.array(self.ptilde_in[:, 0]) self.ptilde_arr = np.array(self.ptilde_in[:, 1]) self.n_ptilde = len(self.ell_ptilde) # Class self.cosmo = Class() def get_tsz_cl(self, ell_arr, params, zmin=None, zmax=None, Mmin=None, Mmax=None): # integration range, optional if zmin == None: zmin = self.zmin if zmax == None: zmax = self.zmax nz_pk = int((zmax - zmin) / self.dz) + 1 if Mmin == None: Mmin = self.Mmin if Mmax == None: Mmax = self.Mmax obh2 = params['obh2'] och2 = params['och2'] As = params['As'] ns = params['ns'] mnu = params['mnu'] mass_bias = params['mass_bias'] flag_nu_logic = params['flag_nu'] flag_tll_logic = params['flag_tll'] if type(flag_nu_logic) != bool: print('flag_nu must be boolean.') sys.exit() if type(flag_tll_logic) != bool: print('flag_tll must be boolean.') sys.exit() if flag_nu_logic: flag_nu = 1 else: flag_nu = 0 if flag_tll_logic: flag_tll = 1 else: flag_tll = 0 if 'theta' in params.keys(): theta = params['theta'] pars = {'output':'mPk','100*theta_s':theta, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':self.zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() h0 = self.cosmo.h() elif 'h0' in params.keys(): h0 = params['h0'] pars = {'output':'mPk','h':h0, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':self.zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() kh_arr = np.logspace(np.log10(self.kmin), np.log10(self.kmax), self.nk_pk) kh = np.zeros((nz_pk, self.nk_pk)) pk = np.zeros((nz_pk, self.nk_pk)) pk_zarr = np.linspace(zmin, zmax, nz_pk + 1) for i in range(self.nz_pk): kh[i, :] = kh_arr if flag_nu == 0: pk[i, :] = np.array([ self.cosmo.pk(k * h0, pk_zarr[i]) * h0**3 for k in kh_arr ]) elif flag_nu == 1: pk[i, :] = np.array([ self.cosmo.pk_cb(k * h0, pk_zarr[i]) * h0**3 for k in kh_arr ]) #### set variables for fortran codes ### nk = byref(c_int64(self.nk_pk)) # indx_z, indx_k nz = byref(c_int64(self.nz_pk)) # params h0_in = byref(c_double(h0)) obh2_in = byref(c_double(obh2)) och2_in = byref(c_double(och2)) mnu_in = byref(c_double(mnu)) mass_bias_in = byref(c_double(mass_bias)) flag_nu_in = byref(c_int64(flag_nu)) flag_tll_in = byref(c_int64(flag_tll)) zmin_in = byref(c_double(zmin)) zmax_in = byref(c_double(zmax)) Mmin_in = byref(c_double(Mmin)) Mmax_in = byref(c_double(Mmax)) # outputs nl = len(ell_arr) cl_yy = np.zeros((2, nl)) tll = np.zeros((nl, nl)) nl = c_int64(nl) self.fort_lib_cl.calc_cl_( h0_in, obh2_in, och2_in, mnu_in,\ mass_bias_in, nk, nz,\ np.array(kh),np.array(pk),np.array(pk_zarr),\ byref(c_int64(self.n_ptilde)), self.ell_ptilde, self.ptilde_arr,\ nl,np.array(ell_arr),\ cl_yy,tll,\ flag_nu_in,flag_tll_in,\ zmin_in,zmax_in,\ Mmin_in,Mmax_in ) self.cosmo.struct_cleanup() return cl_yy, tll def get_by_dydz(self, z_arr, params, Mmin=None, Mmax=None): if Mmin == None: Mmin = self.Mmin if Mmax == None: Mmax = self.Mmax nz = len(z_arr) zmax = np.max(z_arr) obh2 = params['obh2'] och2 = params['och2'] As = params['As'] ns = params['ns'] mnu = params['mnu'] mass_bias = params['mass_bias'] flag_nu_logic = params['flag_nu'] if type(flag_nu_logic) != bool: print('flag_nu must be boolean.') sys.exit() if flag_nu_logic: flag_nu = 1 else: flag_nu = 0 if 'theta' in params.keys(): theta = params['theta'] pars = {'output':'mPk','100*theta_s':theta, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() h0 = self.cosmo.h() elif 'h0' in params.keys(): h0 = params['h0'] pars = {'output':'mPk','h':h0, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() kh_arr = np.logspace(np.log10(self.kmin), np.log10(self.kmax), self.nk_pk) kh = np.zeros((nz, self.nk_pk)) pk = np.zeros((nz, self.nk_pk)) for i in range(nz): kh[i, :] = kh_arr if flag_nu == 0: pk[i, :] = np.array( [self.cosmo.pk(k * h0, z_arr[i]) * h0**3 for k in kh_arr]) elif flag_nu == 1: pk[i, :] = np.array([ self.cosmo.pk_cb(k * h0, z_arr[i]) * h0**3 for k in kh_arr ]) #### set variables for fortran codes ### nk = byref(c_int64(self.nk_pk)) # indx_z, indx_k # params h0_in = byref(c_double(h0)) obh2_in = byref(c_double(obh2)) och2_in = byref(c_double(och2)) mnu_in = byref(c_double(mnu)) mass_bias_in = byref(c_double(mass_bias)) flag_nu_in = byref(c_int64(flag_nu)) # outputs by_arr = np.zeros(nz) dydz_arr = np.zeros(nz) nz = c_int64(nz) Mmin_in = byref(c_double(Mmin)) Mmax_in = byref(c_double(Mmax)) self.fort_lib_by.calc_by_( h0_in, obh2_in, och2_in, mnu_in, \ mass_bias_in, nk, \ np.array(kh),np.array(pk), \ byref(c_int64(self.n_ptilde)), self.ell_ptilde, self.ptilde_arr,\ nz,np.array(z_arr), \ by_arr,dydz_arr, \ flag_nu_in, \ Mmin_in, Mmax_in ) self.cosmo.struct_cleanup() return by_arr, dydz_arr def get_dydzdlogMh(self, z, Mh, params): obh2 = params['obh2'] och2 = params['och2'] As = params['As'] ns = params['ns'] mnu = params['mnu'] mass_bias = params['mass_bias'] flag_nu_logic = params['flag_nu'] if type(flag_nu_logic) != bool: print('flag_nu must be boolean.') sys.exit() if flag_nu_logic: flag_nu = 1 else: flag_nu = 0 if 'theta' in params.keys(): theta = params['theta'] pars = {'output':'mPk','100*theta_s':theta, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':z,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() h0 = self.cosmo.h() elif 'h0' in params.keys(): h0 = params['h0'] pars = {'output':'mPk','h':h0, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':z,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() kh_arr = np.logspace(np.log10(self.kmin), np.log10(self.kmax), self.nk_pk) kh = np.zeros((1, self.nk_pk)) pk = np.zeros((1, self.nk_pk)) kh[0, :] = kh_arr if flag_nu == 0: pk[0, :] = np.array( [self.cosmo.pk(k * h0, z) * h0**3 for k in kh_arr]) elif flag_nu == 1: pk[0, :] = np.array( [self.cosmo.pk_cb(k * h0, z) * h0**3 for k in kh_arr]) #### set variables for fortran codes ### nk = byref(c_int64(self.nk_pk)) # indx_z, indx_k nz = byref(c_int64(1)) # params h0_in = byref(c_double(h0)) obh2_in = byref(c_double(obh2)) och2_in = byref(c_double(och2)) mnu_in = byref(c_double(mnu)) mass_bias_in = byref(c_double(mass_bias)) flag_nu_in = byref(c_int64(flag_nu)) # outputs z_in = byref(c_double(z)) Mh_in = byref(c_double(Mh)) dydzdMh = c_double(0.0) self.fort_lib_dydzdMh.calc_dydzdmh_( h0_in, obh2_in, och2_in, mnu_in, \ mass_bias_in, nk, nz, \ np.array(kh),np.array(pk), \ byref(c_int64(self.n_ptilde)), self.ell_ptilde, self.ptilde_arr,\ z_in,Mh_in, \ dydzdMh, \ flag_nu_in \ ) self.cosmo.struct_cleanup() return dydzdMh.value
tau2[-1] *= 0.999 # this tiny shift avoids interpolation errors tau = np.concatenate((tau1,tau2)) tau_num = len(tau) # # use table of background and thermodynamics quantitites to define some functions # returning some characteristic scales # (of Hubble crossing, sound horizon crossing, etc.) at different time # background = M.get_background() # load background table #print background.viewkeys() thermodynamics = M.get_thermodynamics() # load thermodynamics table #print thermodynamics.viewkeys() # background_tau = background['conf. time [Mpc]'] # read conformal times in background table background_z = background['z'] # read redshift background_aH = 2.*math.pi*background['H [1/Mpc]']/(1.+background['z'])/M.h() # read 2pi * aH in [h/Mpc] background_ks = 2.*math.pi/background['comov.snd.hrz.']/M.h() # read 2pi/(comoving sound horizon) in [h/Mpc] background_rho_m_over_r = (background['(.)rho_b']+background['(.)rho_cdm']) /(background['(.)rho_g']+background['(.)rho_ur']) # read rho_r / rho_m (to find time of equality) background_rho_l_over_m = background['(.)rho_lambda'] /(background['(.)rho_b']+background['(.)rho_cdm']) # read rho_m / rho_lambda (to find time of equality) thermodynamics_tau = thermodynamics['conf. time [Mpc]'] # read confromal times in thermodynamics table thermodynamics_kd = 2.*math.pi/thermodynamics['r_d']/M.h() # read 2pi(comoving diffusion scale) in [h/Mpc] # # define a bunch of interpolation functions based on previous quantities # background_z_at_tau = interp1d(background_tau,background_z) background_aH_at_tau = interp1d(background_tau,background_aH) background_ks_at_tau = interp1d(background_tau,background_ks) background_tau_at_mr = interp1d(background_rho_m_over_r,background_tau) background_tau_at_lm = interp1d(background_rho_l_over_m,background_tau) thermodynamics_kd_at_tau = interp1d(thermodynamics_tau, thermodynamics_kd) #
class classy(Theory): def initialise(self): """Importing CLASS from the correct path, if given, and if not, globally.""" # If path not given, try using general path to modules path_to_installation = get_path_to_installation() if not self.path and path_to_installation: self.path = os.path.join(path_to_installation, "code", classy_repo_rename) if self.path: self.log.info("Importing *local* classy from " + self.path) classy_build_path = os.path.join(self.path, "python", "build") post = next(d for d in os.listdir(classy_build_path) if d.startswith("lib.")) classy_build_path = os.path.join(classy_build_path, post) if not os.path.exists(classy_build_path): self.log.error( "Either CLASS is not in the given folder, " "'%s', or you have not compiled it.", self.path) raise HandledException # Inserting the previously found path into the list of import folders sys.path.insert(0, classy_build_path) else: self.log.info("Importing *global* CLASS.") try: from classy import Class, CosmoSevereError, CosmoComputationError except ImportError: self.log.error( "Couldn't find the CLASS python interface. " "Make sure that you have compiled it, and that you either\n" " (a) specify a path (you didn't) or\n" " (b) install the Python interface globally with\n" " '/path/to/class/python/python setup.py install --user'") raise HandledException self.classy = Class() # Propagate errors up global CosmoComputationError, CosmoSevereError # Generate states, to avoid recomputing self.n_states = 3 self.states = [{ "params": None, "derived": None, "derived_extra": None, "last": 0 } for i in range(self.n_states)] # Dict of named tuples to collect requirements and computation methods self.collectors = {} # Additional input parameters to pass to CLASS self.extra_args = self.extra_args or {} self.extra_args["output"] = self.extra_args.get("output", "") if "sBBN file" in self.extra_args: self.extra_args["sBBN file"] = (os.path.join( self.path, self.extra_args["sBBN file"])) # Derived parameters that may not have been requested, but will be necessary later self.derived_extra = [] def current_state(self): lasts = [self.states[i]["last"] for i in range(self.n_states)] return self.states[lasts.index(max(lasts))] def needs(self, arguments): # Computed quantities requiered by the likelihood arguments = arguments or {} for k, v in arguments.items(): # Precision parameters and boundaries (in general, take max of all requested) if k == "l_max": self.extra_args["l_max_scalars"] = (max( v, self.extra_args.get("l_max_scalars", 0))) elif k == "k_max": self.extra_args["P_k_max_h/Mpc"] = (max( v, self.extra_args.get("P_k_max_h/Mpc", 0))) # Products and other computations elif k == "Cl": if any([("t" in cl.lower()) for cl in v]): self.extra_args["output"] += " tCl" if any([(("e" in cl.lower()) or ("b" in cl.lower())) for cl in v]): self.extra_args["output"] += " pCl" # For modern experiments, always lensed Cl's! self.extra_args["output"] += " lCl" self.extra_args["lensing"] = "yes" self.extra_args["non linear"] = "halofit" self.collectors[k] = collector(method="lensed_cl", kwargs={}) self.collectors["TCMB"] = collector(method="T_cmb", kwargs={}) elif k == "fsigma8": self.collectors["growth_factor_f"] = collector( method="scale_independent_growth_factor_f", args=[np.atleast_1d(v["redshifts"])], arg_array=0) self.collectors["sigma8"] = collector( method="sigma", # Notice: Needs H0 for 1st arg (R), so added later args=[None, np.atleast_1d(v["redshifts"])], arg_array=1) if "H0" not in self.input_params: self.derived_extra += ["H0"] self.extra_args["output"] += " mPk" self.extra_args["P_k_max_h/Mpc"] = (max( 1, self.extra_args.get("P_k_max_h/Mpc", 0))) self.add_z_for_matter_power(v["redshifts"]) elif k == "h_of_z": self.collectors[k] = collector( method="Hubble", args=[np.atleast_1d(v["redshifts"])], arg_array=0) self.H_units_conv_factor = { "/Mpc": 1, "km/s/Mpc": _c }[v["units"]] elif k == "angular_diameter_distance": self.collectors[k] = collector( method="angular_distance", args=[np.atleast_1d(v["redshifts"])], arg_array=0) else: # Extra derived parameters if v is None: self.derived_extra += [self.translate_param(k)] else: self.log.error("Unknown required product: '%s:%s'.", k, v) raise HandledException # Derived parameters (if some need some additional computations) if "sigma8" in self.output_params or arguments: self.extra_args["output"] += " mPk" self.extra_args["P_k_max_h/Mpc"] = (max( 1, self.extra_args.get("P_k_max_h/Mpc", 0))) # Since the Cl collector needs lmax, update it now, in case it has increased # *after* declaring the Cl collector if "Cl" in self.collectors: self.collectors["Cl"].kwargs["lmax"] = self.extra_args[ "l_max_scalars"] # Cleanup of products string self.extra_args["output"] = " ".join( set(self.extra_args["output"].split())) def add_z_for_matter_power(self, z): if not hasattr(self, "z_for_matter_power"): self.z_for_matter_power = np.empty((0)) self.z_for_matter_power = np.flip(np.sort( np.unique( np.concatenate([self.z_for_matter_power, np.atleast_1d(z)]))), axis=0) self.extra_args["z_pk"] = " ".join( ["%g" % zi for zi in self.z_for_matter_power]) def translate_param(self, p): if self.use_planck_names: return self.planck_to_classy.get(p, p) return p def set(self, params_values_dict, i_state): # Store them, to use them later to identify the state self.states[i_state]["params"] = deepcopy(params_values_dict) # Prepare parameters to be passed: this-iteration + extra args = { self.translate_param(p): v for p, v in params_values_dict.items() } args.update(self.extra_args) # Generate and save self.log.debug("Setting parameters: %r", args) self.classy.struct_cleanup() self.classy.set(**args) def compute(self, derived=None, **params_values_dict): lasts = [self.states[i]["last"] for i in range(self.n_states)] try: # are the parameter values there already? i_state = next(i for i in range(self.n_states) if self.states[i]["params"] == params_values_dict) # Get (pre-computed) derived parameters if derived == {}: derived.update(self.states[i_state]["derived"]) self.log.debug("Re-using computed results (state %d)", i_state) except StopIteration: # update the (first) oldest one and compute i_state = lasts.index(min(lasts)) self.log.debug("Computing (state %d)", i_state) # Set parameters self.set(params_values_dict, i_state) # Compute! try: self.classy.compute() # "Valid" failure of CLASS: parameters too extreme -> log and report except CosmoComputationError: self.log.debug("Computation of cosmological products failed. " "Assigning 0 likelihood and going on.") return False # CLASS not correctly initialised, or input parameters not correct except CosmoSevereError: self.log.error( "Serious error setting parameters or computing results. " "The parameters passed were %r and %r. " "See original CLASS's error traceback below.\n", self.states[i_state]["params"], self.extra_args) raise # No HandledException, so that CLASS traceback gets printed # Gather products for product, collector in self.collectors.items(): # Special case: sigma8 needs H0, which cannot be known beforehand: if "sigma8" in self.collectors: self.collectors["sigma8"].args[0] = 8 / self.classy.h() method = getattr(self.classy, collector.method) if self.collectors[product].arg_array is None: self.states[i_state][product] = method( *self.collectors[product].args, **self.collectors[product].kwargs) else: i_array = self.collectors[product].arg_array self.states[i_state][product] = np.zeros( len(self.collectors[product].args[i_array])) for i, v in enumerate( self.collectors[product].args[i_array]): args = ( list(self.collectors[product].args[:i_array]) + [v] + list(self.collectors[product].args[i_array + 1:])) self.states[i_state][product][i] = method( *args, **self.collectors[product].kwargs) # Prepare derived parameters d, d_extra = self.get_derived_all( derived_requested=(derived == {})) derived.update(d) self.states[i_state]["derived"] = odict( [[p, derived.get(p)] for p in self.output_params]) # Prepare necessary extra derived parameters self.states[i_state]["derived_extra"] = deepcopy(d_extra) # make this one the current one by decreasing the antiquity of the rest for i in range(self.n_states): self.states[i]["last"] -= max(lasts) self.states[i_state]["last"] = 1 return True def get_derived_all(self, derived_requested=True): """ Returns a dictionary of derived parameters with their values, using the *current* state (i.e. it should only be called from the ``compute`` method). To get a parameter *from a likelihood* use `get_param` instead. """ list_requested_derived = self.output_params if derived_requested else [] de_translated = { self.translate_param(p): p for p in list_requested_derived } requested_derived_with_extra = list(de_translated.keys()) + list( self.derived_extra) derived_aux = {} # Exceptions if "rs_drag" in requested_derived_with_extra: requested_derived_with_extra.remove("rs_drag") derived_aux["rs_drag"] = self.classy.rs_drag() derived_aux.update( self.classy.get_current_derived_parameters( requested_derived_with_extra)) # Fill return dictionaries derived = { de_translated[p]: derived_aux[self.translate_param(p)] for p in de_translated } derived_extra = {p: derived_aux[p] for p in self.derived_extra} # No need for error control: classy.get_current_derived_parameters is passed # every derived parameter not excluded before, and cause an error if if founds a # parameter that it does not recognise return derived, derived_extra def get_param(self, p): """ Interface function for likelihoods to get sampled and derived parameters. """ current_state = self.current_state() for pool in ["params", "derived", "derived_extra"]: value = current_state[pool].get(self.translate_param(p), None) if value is not None: return value self.log.error("Parameter not known: '%s'", p) raise HandledException def get_cl(self, ell_factor=False): """ Returns the power spectra in microK^2 (unitless for lensing potential), using the *current* state. """ current_state = self.current_state() # get C_l^XX from the cosmological code try: cl = deepcopy(current_state["Cl"]) except: self.log.error( "No Cl's were computed. Are you sure that you have requested them?" ) raise HandledException ell_factor = ((cl["ell"] + 1) * cl["ell"] / (2 * np.pi))[2:] if ell_factor else 1 # convert dimensionless C_l's to C_l in muK**2 T = current_state["TCMB"] for key in cl: # All quantities need to be multiplied by this factor, except the # phi-phi term, that is already dimensionless if key not in ['pp', 'ell']: cl[key][2:] *= (T * 1.e6)**2 * ell_factor if "pp" in cl and ell_factor is not 1: cl['pp'][2:] *= ell_factor**2 * (2 * np.pi) return cl def get_fsigma8(self, z): indices = np.where(self.z_for_matter_power == z) return (self.current_state()["growth_factor_f"][indices] * self.current_state()["sigma8"][indices]) def get_h_of_z(self, z): return self.current_state()["h_of_z"][np.where( self.collectors["h_of_z"].args[self.collectors["h_of_z"].arg_array] == z)] * self.H_units_conv_factor def get_angular_diameter_distance(self, z): return self.current_state()["angular_diameter_distance"][np.where( self.collectors["angular_diameter_distance"].args[ self.collectors["angular_diameter_distance"].arg_array] == z)]
import myfuncs as my from numpy import linalg as LA import pickle #Run ClASS-code and get transfer function for delta_cdm cosmo = Class() cosmo.set({ 'output': 'tCl mPk dTk vTk', 'P_k_max_1/Mpc': 35, 'gauge': 'Synchronous', 'z_pk': '100., 0.' }) cosmo.compute() tr = cosmo.get_transfer(49) delta_cdm = tr['d_cdm'] k = tr['k (h/Mpc)'] * cosmo.h() # Create interpolating function for transfer function dfunc = interp1d(k, delta_cdm, kind='cubic', bounds_error=False, fill_value=0) # define class for saving data class data: def __init__(self, Dat): self.Dat = Dat self.K = [] self.Kused = [] self.Kl = [] self.Klu = [] self.d1 = [] self.d2 = []
def turboSij(zstakes=default_zstakes, cosmo_params=default_cosmo_params, cosmo_Class=None): # If the cosmology is not provided (in the same form as CLASS), run CLASS if cosmo_Class is None: cosmo = Class() dico_for_CLASS = cosmo_params dico_for_CLASS['output'] = 'mPk' cosmo.set(dico_for_CLASS) cosmo.compute() else: cosmo = cosmo_Class h = cosmo.h() #for conversions Mpc/h <-> Mpc # Define arrays of z, r(z), k, P(k)... nzbins = len(zstakes) - 1 nz_perbin = 10 z_arr = np.zeros((nz_perbin, nzbins)) comov_dist = np.zeros((nz_perbin, nzbins)) for j in range(nzbins): z_arr[:, j] = np.linspace(zstakes[j], zstakes[j + 1], nz_perbin) comov_dist[:, j] = (cosmo.z_of_r(z_arr[:, j]))[0] #In Mpc keq = 0.02 / h #Equality matter radiation in 1/Mpc (more or less) klogwidth = 10 #Factor of width of the integration range. 10 seems ok ; going higher needs to increase nk_fft to reach convergence (fine cancellation issue noted in Lacasa & Grain) kmin = min(keq, 1. / comov_dist.max()) / klogwidth kmax = max(keq, 1. / comov_dist.min()) * klogwidth nk_fft = 2**11 #seems to be enough. Increase to test precision, reduce to speed up. k_4fft = np.linspace(kmin, kmax, nk_fft) #linear grid on k, as we need to use an FFT Deltak = kmax - kmin Dk = Deltak / nk_fft Pk_4fft = np.zeros(nk_fft) for ik in range(nk_fft): Pk_4fft[ik] = cosmo.pk(k_4fft[ik], 0.) #In Mpc^3 dr_fft = np.linspace(0, nk_fft // 2, nk_fft // 2 + 1) * 2 * pi / Deltak # Compute necessary FFTs and make interpolation functions fft2 = np.fft.rfft(Pk_4fft / k_4fft**2) * Dk dct2 = fft2.real dst2 = -fft2.imag km2Pk_dct = interp1d(dr_fft, dct2, kind='cubic') fft3 = np.fft.rfft(Pk_4fft / k_4fft**3) * Dk dct3 = fft3.real dst3 = -fft3.imag km3Pk_dst = interp1d(dr_fft, dst3, kind='cubic') fft4 = np.fft.rfft(Pk_4fft / k_4fft**4) * Dk dct4 = fft4.real dst4 = -fft4.imag km4Pk_dct = interp1d(dr_fft, dct4, kind='cubic') # Compute Sij finally Sij = np.zeros((nzbins, nzbins)) for j1 in range(nzbins): rmin1 = (comov_dist[:, j1]).min() rmax1 = (comov_dist[:, j1]).max() zmean1 = ((z_arr[:, j1]).min() + (z_arr[:, j1]).max()) / 2 growth1 = cosmo.scale_independent_growth_factor(zmean1) pref1 = 3. * growth1 / (rmax1**3 - rmin1**3) for j2 in range(nzbins): rmin2 = (comov_dist[:, j2]).min() rmax2 = (comov_dist[:, j2]).max() zmean2 = ((z_arr[:, j2]).min() + (z_arr[:, j2]).max()) / 2 growth2 = cosmo.scale_independent_growth_factor(zmean2) pref2 = 3. * growth2 / (rmax2**3 - rmin2**3) #p1p2: rmax1 & rmax2 rsum = rmax1 + rmax2 rdiff = abs(rmax1 - rmax2) rprod = rmax1 * rmax2 Icp2 = km2Pk_dct(rsum) Icm2 = km2Pk_dct(rdiff) Isp3 = km3Pk_dst(rsum) Ism3 = km3Pk_dst(rdiff) Icp4 = km4Pk_dct(rsum) Icm4 = km4Pk_dct(rdiff) Fp1p2 = -Icp4 + Icm4 - rsum * Isp3 + rdiff * Ism3 + rprod * (Icp2 + Icm2) #p1m2: rmax1 & rmin2 rsum = rmax1 + rmin2 rdiff = abs(rmax1 - rmin2) rprod = rmax1 * rmin2 Icp2 = km2Pk_dct(rsum) Icm2 = km2Pk_dct(rdiff) Isp3 = km3Pk_dst(rsum) Ism3 = km3Pk_dst(rdiff) Icp4 = km4Pk_dct(rsum) Icm4 = km4Pk_dct(rdiff) Fp1m2 = -Icp4 + Icm4 - rsum * Isp3 + rdiff * Ism3 + rprod * (Icp2 + Icm2) #m1p2: rmin1 & rmax2 rsum = rmin1 + rmax2 rdiff = abs(rmin1 - rmax2) rprod = rmin1 * rmax2 Icp2 = km2Pk_dct(rsum) Icm2 = km2Pk_dct(rdiff) Isp3 = km3Pk_dst(rsum) Ism3 = km3Pk_dst(rdiff) Icp4 = km4Pk_dct(rsum) Icm4 = km4Pk_dct(rdiff) Fm1p2 = -Icp4 + Icm4 - rsum * Isp3 + rdiff * Ism3 + rprod * (Icp2 + Icm2) #m1m2: rmin1 & rmin2 rsum = rmin1 + rmin2 rdiff = abs(rmin1 - rmin2) rprod = rmin1 * rmin2 Icp2 = km2Pk_dct(rsum) Icm2 = km2Pk_dct(rdiff) Isp3 = km3Pk_dst(rsum) Ism3 = km3Pk_dst(rdiff) Icp4 = km4Pk_dct(rsum) Icm4 = km4Pk_dct(rdiff) Fm1m2 = -Icp4 + Icm4 - rsum * Isp3 + rdiff * Ism3 + rprod * (Icp2 + Icm2) #now group everything Fsum = Fp1p2 - Fp1m2 - Fm1p2 + Fm1m2 Sij[j1, j2] = pref1 * pref2 * Fsum / (4 * pi**2) return Sij
def Sij_alt(z_arr, windows, cosmo_params=default_cosmo_params, cosmo_Class=None): # Assert everything as the good type and shape, and find number of redshifts, bins etc zz = np.asarray(z_arr) win = np.asarray(windows) assert zz.ndim == 1, 'z_arr must be a 1-dimensional array' assert win.ndim == 2, 'windows must be a 2-dimensional array' nz = len(zz) nbins = win.shape[0] assert win.shape[1] == nz, 'windows must have shape (nbins,nz)' assert zz.min() > 0, 'z_arr must have values > 0' # If the cosmology is not provided (in the same form as CLASS), run CLASS if cosmo_Class is None: cosmo = Class() dico_for_CLASS = cosmo_params dico_for_CLASS['output'] = 'mPk' cosmo.set(dico_for_CLASS) cosmo.compute() else: cosmo = cosmo_Class h = cosmo.h() #for conversions Mpc/h <-> Mpc # Define arrays of r(z), k, P(k)... zofr = cosmo.z_of_r(zz) comov_dist = zofr[0] #Comoving distance r(z) in Mpc dcomov_dist = 1 / zofr[1] #Derivative dr/dz in Mpc dV = comov_dist**2 * dcomov_dist #Comoving volume per solid angle in Mpc^3/sr growth = np.zeros(nz) #Growth factor for iz in range(nz): growth[iz] = cosmo.scale_independent_growth_factor(zz[iz]) keq = 0.02 / h #Equality matter radiation in 1/Mpc (more or less) klogwidth = 10 #Factor of width of the integration range. #10 seems ok ; going higher needs to increase nk_fft to reach convergence (fine cancellation issue noted in Lacasa & Grain) kmin = min(keq, 1. / comov_dist.max()) / klogwidth kmax = max(keq, 1. / comov_dist.min()) * klogwidth nk_fft = 2**11 #seems to be enough. Increase to test precision, reduce to speed up. k_4fft = np.linspace(kmin, kmax, nk_fft) #linear grid on k, as we need to use an FFT Deltak = kmax - kmin Dk = Deltak / nk_fft Pk_4fft = np.zeros(nk_fft) for ik in range(nk_fft): Pk_4fft[ik] = cosmo.pk(k_4fft[ik], 0.) #In Mpc^3 dr_fft = np.linspace(0, nk_fft // 2, nk_fft // 2 + 1) * 2 * pi / Deltak # Compute necessary FFTs and make interpolation functions fft0 = np.fft.rfft(Pk_4fft) * Dk dct0 = fft0.real dst0 = -fft0.imag Pk_dct = interp1d(dr_fft, dct0, kind='cubic') # Compute sigma^2(z1,z2) sigma2_nog = np.zeros((nz, nz)) #First with P(k,z=0) and z1<=z2 for iz in range(nz): r1 = comov_dist[iz] for jz in range(iz, nz): r2 = comov_dist[jz] rsum = r1 + r2 rdiff = abs(r1 - r2) Icp0 = Pk_dct(rsum) Icm0 = Pk_dct(rdiff) sigma2_nog[iz, jz] = (Icm0 - Icp0) / (4 * pi**2 * r1 * r2) #Now fill by symmetry and put back growth functions sigma2 = np.zeros((nz, nz)) for iz in range(nz): growth1 = growth[iz] for jz in range(nz): growth2 = growth[jz] sigma2[iz, jz] = sigma2_nog[min(iz, jz), max(iz, jz)] * growth1 * growth2 # Compute normalisations Inorm = np.zeros(nbins) for i1 in range(nbins): integrand = dV * windows[i1, :]**2 Inorm[i1] = integrate.simps(integrand, zz) # Compute Sij finally prefactor = sigma2 * (dV * dV[:, None]) Sij = np.zeros((nbins, nbins)) #For i<=j for i1 in range(nbins): for i2 in range(i1, nbins): integrand = prefactor * (windows[i1, :]**2 * windows[i2, :, None]**2) Sij[i1, i2] = integrate.simps(integrate.simps(integrand, zz), zz) / (Inorm[i1] * Inorm[i2]) #Fill by symmetry for i1 in range(nbins): for i2 in range(nbins): Sij[i1, i2] = Sij[min(i1, i2), max(i1, i2)] return Sij
def Sij(z_arr, windows, cosmo_params=default_cosmo_params, precision=10, cosmo_Class=None): # Assert everything as the good type and shape, and find number of redshifts, bins etc zz = np.asarray(z_arr) win = np.asarray(windows) assert zz.ndim == 1, 'z_arr must be a 1-dimensional array' assert win.ndim == 2, 'windows must be a 2-dimensional array' nz = len(zz) nbins = win.shape[0] assert win.shape[1] == nz, 'windows must have shape (nbins,nz)' assert zz.min() > 0, 'z_arr must have values > 0' # If the cosmology is not provided (in the same form as CLASS), run CLASS if cosmo_Class is None: cosmo = Class() dico_for_CLASS = cosmo_params dico_for_CLASS['output'] = 'mPk' cosmo.set(dico_for_CLASS) cosmo.compute() else: cosmo = cosmo_Class h = cosmo.h() #for conversions Mpc/h <-> Mpc # Define arrays of r(z), k, P(k)... zofr = cosmo.z_of_r(zz) comov_dist = zofr[0] #Comoving distance r(z) in Mpc dcomov_dist = 1 / zofr[1] #Derivative dr/dz in Mpc dV = comov_dist**2 * dcomov_dist #Comoving volume per solid angle in Mpc^3/sr growth = np.zeros(nz) #Growth factor for iz in range(nz): growth[iz] = cosmo.scale_independent_growth_factor(zz[iz]) # Compute normalisations Inorm = np.zeros(nbins) for i1 in range(nbins): integrand = dV * windows[i1, :]**2 Inorm[i1] = integrate.simps(integrand, zz) # Compute U(i,k) keq = 0.02 / h #Equality matter radiation in 1/Mpc (more or less) klogwidth = 10 #Factor of width of the integration range. 10 seems ok kmin = min(keq, 1. / comov_dist.max()) / klogwidth kmax = max(keq, 1. / comov_dist.min()) * klogwidth nk = 2**precision #10 seems to be enough. Increase to test precision, reduce to speed up. #kk = np.linspace(kmin,kmax,num=nk) #linear grid on k logkmin = np.log(kmin) logkmax = np.log(kmax) logk = np.linspace(logkmin, logkmax, num=nk) kk = np.exp(logk) #logarithmic grid on k Pk = np.zeros(nk) for ik in range(nk): Pk[ik] = cosmo.pk(kk[ik], 0.) #In Mpc^3 Uarr = np.zeros((nbins, nk)) for ibin in range(nbins): for ik in range(nk): kr = kk[ik] * comov_dist integrand = dV * windows[ibin, :]**2 * growth * np.sin(kr) / kr Uarr[ibin, ik] = integrate.simps(integrand, zz) # Compute Sij finally Cl_zero = np.zeros((nbins, nbins)) #For i<=j for ibin in range(nbins): U1 = Uarr[ibin, :] / Inorm[ibin] for jbin in range(ibin, nbins): U2 = Uarr[jbin, :] / Inorm[jbin] integrand = kk**2 * Pk * U1 * U2 #Cl_zero[ibin,jbin] = 2/pi * integrate.simps(integrand,kk) #linear integration Cl_zero[ibin, jbin] = 2 / pi * integrate.simps( integrand * kk, logk) #log integration #Fill by symmetry for ibin in range(nbins): for jbin in range(nbins): Cl_zero[ibin, jbin] = Cl_zero[min(ibin, jbin), max(ibin, jbin)] Sij = Cl_zero / (4 * pi) return Sij
def fitEE(self): # function to cimpute the band powers cosmo = Class() cosmo.set(self.cosmoParams) if self.settings.include_neutrino: cosmo.set(self.other_settings) cosmo.set(self.neutrino_settings) cosmo.set(self.class_argumets) try: cosmo.compute() except CosmoComputationError as failure_message: print(failure_message) self.sigma_8 = np.nan cosmo.struct_cleanup() cosmo.empty() return np.array([np.nan] * self.nzcorrs * self.bo_EE), np.array( [np.nan] * self.nzcorrs * self.bo_EE), np.array( [np.nan] * self.nzcorrs * self.bo_EE) except CosmoSevereError as critical_message: print(critical_message) self.sigma_8 = np.nan cosmo.struct_cleanup() cosmo.empty() return np.array([np.nan] * self.nzcorrs * self.bo_EE), np.array( [np.nan] * self.nzcorrs * self.bo_EE), np.array( [np.nan] * self.nzcorrs * self.bo_EE) # retrieve Omega_m and h from cosmo (CLASS) self.Omega_m = cosmo.Omega_m() self.small_h = cosmo.h() self.rho_crit = self.get_critical_density() # derive the linear growth factor D(z) linear_growth_rate = np.zeros_like(self.redshifts) # print self.redshifts for index_z, z in enumerate(self.redshifts): try: # for CLASS ver >= 2.6: linear_growth_rate[ index_z] = cosmo.scale_independent_growth_factor(z) except BaseException: # my own function from private CLASS modification: linear_growth_rate[index_z] = cosmo.growth_factor_at_z(z) # normalize to unity at z=0: try: # for CLASS ver >= 2.6: linear_growth_rate /= cosmo.scale_independent_growth_factor(0.) except BaseException: # my own function from private CLASS modification: linear_growth_rate /= cosmo.growth_factor_at_z(0.) # get distances from cosmo-module: r, dzdr = cosmo.z_of_r(self.redshifts) self.sigma_8 = cosmo.sigma8() # Get power spectrum P(k=l/r,z(r)) from cosmological module # this doesn't really have to go into the loop over fields! pk = np.zeros((self.settings.nellsmax, self.settings.nzmax), 'float64') k_max_in_inv_Mpc = self.settings.k_max_h_by_Mpc * self.small_h # note that this is being computed at only nellsmax # followed by an interplation record = np.zeros((self.settings.nellsmax, self.settings.nzmax)) record_k = np.zeros((self.settings.nellsmax, self.settings.nzmax)) for index_ells in range(self.settings.nellsmax): for index_z in range(1, self.settings.nzmax): k_in_inv_Mpc = (self.ells[index_ells] + 0.5) / r[index_z] z = self.redshifts[index_z] record[index_ells, index_z] = self.baryon_feedback_bias_sqr( k_in_inv_Mpc / self.small_h, self.redshifts[index_z], A_bary=self.systematics['A_bary']) record_k[index_ells, index_z] = k_in_inv_Mpc self.record_bf = record[:, 1:].flatten() self.record_k = record_k[:, 1:].flatten() self.k_max_in_inv_Mpc = k_max_in_inv_Mpc for index_ells in range(self.settings.nellsmax): for index_z in range(1, self.settings.nzmax): # standard Limber approximation: # k = ells[index_ells] / r[index_z] # extended Limber approximation (cf. LoVerde & Afshordi 2008): k_in_inv_Mpc = (self.ells[index_ells] + 0.5) / r[index_z] if k_in_inv_Mpc > k_max_in_inv_Mpc: pk_dm = 0. else: pk_dm = cosmo.pk(k_in_inv_Mpc, self.redshifts[index_z]) # pk[index_ells,index_z] = cosmo.pk(ells[index_ells]/r[index_z], self.redshifts[index_z]) if self.settings.baryon_feedback: pk[index_ells, index_z] = pk_dm * self.baryon_feedback_bias_sqr( k_in_inv_Mpc / self.small_h, self.redshifts[index_z], A_bary=self.systematics['A_bary']) else: pk[index_ells, index_z] = pk_dm # for KiDS-450 constant biases in photo-z are not sufficient: if self.settings.bootstrap_photoz_errors: # draw a random bootstrap n(z); borders are inclusive! random_index_bootstrap = np.random.randint( int(self.settings.index_bootstrap_low), int(self.settings.index_bootstrap_high) + 1) # print 'Bootstrap index:', random_index_bootstrap pz = np.zeros((self.settings.nzmax, self.nzbins), 'float64') pz_norm = np.zeros(self.nzbins, 'float64') for zbin in range(self.nzbins): redshift_bin = self.redshift_bins[zbin] # ATTENTION: hard-coded subfolder! # index can be recycled since bootstraps for tomographic bins # are independent! fname = os.path.join( self.settings.data_directory, '{:}/bootstraps/{:}/n_z_avg_bootstrap{:}.hist'.format( self.settings.photoz_method, redshift_bin, random_index_bootstrap)) z_hist, n_z_hist = np.loadtxt(fname, unpack=True) shift_to_midpoint = np.diff(z_hist)[0] / 2. spline_pz = itp.splrep(z_hist + shift_to_midpoint, n_z_hist) mask_min = self.redshifts >= z_hist.min() + shift_to_midpoint mask_max = self.redshifts <= z_hist.max() + shift_to_midpoint mask = mask_min & mask_max # points outside the z-range of the histograms are set to 0! pz[mask, zbin] = itp.splev(self.redshifts[mask], spline_pz) dz = self.redshifts[1:] - self.redshifts[:-1] pz_norm[zbin] = np.sum(0.5 * (pz[1:, zbin] + pz[:-1, zbin]) * dz) pr = pz * (dzdr[:, np.newaxis] / pz_norm) else: pr = self.pz * (dzdr[:, np.newaxis] / self.pz_norm) # pr[pr < 0] = 0 g = np.zeros((self.settings.nzmax, self.nzbins), 'float64') for zbin in range(self.nzbins): # assumes that z[0] = 0 for nr in range(1, self.settings.nzmax - 1): # for nr in range(self.nzmax - 1): fun = pr[nr:, zbin] * (r[nr:] - r[nr]) / r[nr:] g[nr, zbin] = np.sum(0.5 * (fun[1:] + fun[:-1]) * (r[nr + 1:] - r[nr:-1])) g[nr, zbin] *= 2. * r[nr] * (1. + self.redshifts[nr]) # Start loop over l for computation of C_l^shear Cl_GG_integrand = np.zeros( (self.settings.nzmax, self.nzbins, self.nzbins), 'float64') Cl_GG = np.zeros((self.settings.nellsmax, self.nzbins, self.nzbins), 'float64') Cl_II_integrand = np.zeros_like(Cl_GG_integrand) Cl_II = np.zeros_like(Cl_GG) Cl_GI_integrand = np.zeros_like(Cl_GG_integrand) Cl_GI = np.zeros_like(Cl_GG) dr = r[1:] - r[:-1] for index_ell in range(self.settings.nellsmax): # find Cl_integrand = (g(r) / r)**2 * P(l/r,z(r)) for zbin1 in range(self.nzbins): for zbin2 in range(zbin1 + 1): # self.nzbins): Cl_GG_integrand[1:, zbin1, zbin2] = g[1:, zbin1] * \ g[1:, zbin2] / r[1:]**2 * pk[index_ell, 1:] factor_IA = self.get_factor_IA( self.redshifts[1:], linear_growth_rate[1:], self.systematics['A_IA']) # / self.dzdr[1:] # print F_of_x # print self.eta_r[1:, zbin1].shape Cl_II_integrand[1:, zbin1, zbin2] = pr[1:, zbin1] * \ pr[1:, zbin2] * factor_IA**2 / r[1:]**2 * pk[index_ell, 1:] pref = g[1:, zbin1] * pr[1:, zbin2] + g[1:, zbin2] * pr[ 1:, zbin1] Cl_GI_integrand[1:, zbin1, zbin2] = pref * factor_IA / r[1:]**2 * pk[ index_ell, 1:] # Integrate over r to get C_l^shear_ij = P_ij(l) # C_l^shear_ii = 9/4 Omega0_m^2 H_0^4 \sum_0^rmax dr (g_i(r) g_j(r) # /r**2) P(k=l/r,z(r)) for zbin1 in range(self.nzbins): for zbin2 in range(zbin1 + 1): # self.nzbins): Cl_GG[index_ell, zbin1, zbin2] = np.sum( 0.5 * (Cl_GG_integrand[1:, zbin1, zbin2] + Cl_GG_integrand[:-1, zbin1, zbin2]) * dr) # here we divide by 16, because we get a 2^2 from g(z)! Cl_GG[index_ell, zbin1, zbin2] *= 9. / 16. * \ self.Omega_m**2 # in units of Mpc**4 # dimensionless Cl_GG[index_ell, zbin1, zbin2] *= (self.small_h / 2997.9)**4 Cl_II[index_ell, zbin1, zbin2] = np.sum( 0.5 * (Cl_II_integrand[1:, zbin1, zbin2] + Cl_II_integrand[:-1, zbin1, zbin2]) * dr) Cl_GI[index_ell, zbin1, zbin2] = np.sum( 0.5 * (Cl_GI_integrand[1:, zbin1, zbin2] + Cl_GI_integrand[:-1, zbin1, zbin2]) * dr) # here we divide by 4, because we get a 2 from g(r)! Cl_GI[index_ell, zbin1, zbin2] *= 3. / 4. * self.Omega_m Cl_GI[index_ell, zbin1, zbin2] *= (self.small_h / 2997.9)**2 # ordering of redshift bins is correct in definition of theory below! theory_EE_GG = np.zeros((self.nzcorrs, self.bo_EE), 'float64') theory_EE_II = np.zeros((self.nzcorrs, self.bo_EE), 'float64') theory_EE_GI = np.zeros((self.nzcorrs, self.bo_EE), 'float64') index_corr = 0 # A_noise_corr = np.zeros(self.nzcorrs) for zbin1 in range(self.nzbins): for zbin2 in range(zbin1 + 1): # self.nzbins): # correlation = 'z{:}z{:}'.format(zbin1 + 1, zbin2 + 1) # print(zbin1, zbin2) Cl_sample_GG = Cl_GG[:, zbin1, zbin2] spline_Cl_GG = itp.splrep(self.ells, Cl_sample_GG) D_l_EE_GG = self.ell_norm * \ itp.splev(self.ells_sum, spline_Cl_GG) theory_EE_GG[index_corr, :] = self.get_theory( self.ells_sum, D_l_EE_GG, self.band_window_matrix, index_corr, band_type_is_EE=True) Cl_sample_GI = Cl_GI[:, zbin1, zbin2] spline_Cl_GI = itp.splrep(self.ells, Cl_sample_GI) D_l_EE_GI = self.ell_norm * \ itp.splev(self.ells_sum, spline_Cl_GI) theory_EE_GI[index_corr, :] = self.get_theory( self.ells_sum, D_l_EE_GI, self.band_window_matrix, index_corr, band_type_is_EE=True) Cl_sample_II = Cl_II[:, zbin1, zbin2] spline_Cl_II = itp.splrep(self.ells, Cl_sample_II) D_l_EE_II = self.ell_norm * \ itp.splev(self.ells_sum, spline_Cl_II) theory_EE_II[index_corr, :] = self.get_theory( self.ells_sum, D_l_EE_II, self.band_window_matrix, index_corr, band_type_is_EE=True) index_corr += 1 cosmo.struct_cleanup() cosmo.empty() return theory_EE_GG.flatten(), theory_EE_GI.flatten( ), theory_EE_II.flatten()
plt.xlim(2, 2500) plt.xlabel(r'$\ell$') plt.ylabel(r'$[\ell(\ell+1)/2\pi] C_\ell^\mathrm{TT}$') plt.plot(ll, clTT * ll * (ll + 1) / 2. / pi, 'r-') # In[ ]: plt.savefig('warmup_cltt.pdf') # In[ ]: # get P(k) at redhsift z=0 import numpy as np kk = np.logspace(-4, np.log10(3), 1000) # k in h/Mpc Pk = [] # P(k) in (Mpc/h)**3 h = LambdaCDM.h() # get reduced Hubble for conversions to 1/Mpc for k in kk: Pk.append(LambdaCDM.pk(k * h, 0.) * h**3) # function .pk(k,z) # In[ ]: # plot P(k) plt.figure(2) plt.xscale('log') plt.yscale('log') plt.xlim(kk[0], kk[-1]) plt.xlabel(r'$k \,\,\,\, [h/\mathrm{Mpc}]$') plt.ylabel(r'$P(k) \,\,\,\, [\mathrm{Mpc}/h]^3$') plt.plot(kk, Pk, 'b-') # In[ ]:
params_def = { 'output': 'mPk', 'non linear': 'halofit', 'Omega_cdm': ocdm_0, 'N_ncdm': 3, 'N_ur': 0.00441, 'm_ncdm': str(m_0) + ',' + str(m_0) + ',' + str(m_0) } # Create an instance of the CLASS wrapper cosmo = Class() # Set the parameters to the cosmological code cosmo.set(params_def) cosmo.compute() #### Define the linear growth factor and growth rate (growth factor f in class) h = cosmo.h() # ~mcu = cosmo.N_ur() # ~print(mcu) Plin = np.zeros(len(karray)) Pnonlin = np.zeros(len(karray)) for i, k in enumerate(karray): Plin[i] = (cosmo.pk_lin(k, z)) # function .pk(k,z) Pnonlin[i] = (cosmo.pk(k, z)) # function .pk(k,z) Plin *= h**3 Pnonlin *= h**3 #------------------------------------------------------------------------- #------------------------------------------------------------------------- m_1 = 0.02
def Sijkl(z_arr, windows, cosmo_params=default_cosmo_params, precision=10, tol=1e-3, cosmo_Class=None): # Assert everything as the good type and shape, and find number of redshifts, bins etc zz = np.asarray(z_arr) win = np.asarray(windows) assert zz.ndim == 1, 'z_arr must be a 1-dimensional array' assert win.ndim == 2, 'windows must be a 2-dimensional array' nz = len(zz) nbins = win.shape[0] assert win.shape[1] == nz, 'windows must have shape (nbins,nz)' assert zz.min() > 0, 'z_arr must have values > 0' # If the cosmology is not provided (in the same form as CLASS), run CLASS if cosmo_Class is None: cosmo = Class() dico_for_CLASS = cosmo_params dico_for_CLASS['output'] = 'mPk' cosmo.set(dico_for_CLASS) cosmo.compute() else: cosmo = cosmo_Class h = cosmo.h() #for conversions Mpc/h <-> Mpc # Define arrays of r(z), k, P(k)... zofr = cosmo.z_of_r(zz) comov_dist = zofr[0] #Comoving distance r(z) in Mpc dcomov_dist = 1 / zofr[1] #Derivative dr/dz in Mpc dV = comov_dist**2 * dcomov_dist #Comoving volume per solid angle in Mpc^3/sr growth = np.zeros(nz) #Growth factor for iz in range(nz): growth[iz] = cosmo.scale_independent_growth_factor(zz[iz]) #Index pairs of bins npairs = (nbins * (nbins + 1)) // 2 pairs = np.zeros((2, npairs), dtype=int) count = 0 for ibin in range(nbins): for jbin in range(ibin, nbins): pairs[0, count] = ibin pairs[1, count] = jbin count += 1 # Compute normalisations Inorm = np.zeros(npairs) Inorm2D = np.zeros((nbins, nbins)) for ipair in range(npairs): ibin = pairs[0, ipair] jbin = pairs[1, ipair] integrand = dV * windows[ibin, :] * windows[jbin, :] integral = integrate.simps(integrand, zz) Inorm[ipair] = integral Inorm2D[ibin, jbin] = integral Inorm2D[jbin, ibin] = integral #Flag pairs with too small overlap as unreliable #Note: this will also speed up later computations #Default tolerance : tol=1e-3 flag = np.zeros(npairs, dtype=int) for ipair in range(npairs): ibin = pairs[0, ipair] jbin = pairs[1, ipair] ratio = abs(Inorm2D[ibin, jbin]) / np.sqrt( abs(Inorm2D[ibin, ibin] * Inorm2D[jbin, jbin])) if ratio < tol: flag[ipair] = 1 # Compute U(i,j;kk) keq = 0.02 / h #Equality matter radiation in 1/Mpc (more or less) klogwidth = 10 #Factor of width of the integration range. 10 seems ok kmin = min(keq, 1. / comov_dist.max()) / klogwidth kmax = max(keq, 1. / comov_dist.min()) * klogwidth nk = 2**precision #10 seems to be enough. Increase to test precision, reduce to speed up. #kk = np.linspace(kmin,kmax,num=nk) #linear grid on k logkmin = np.log(kmin) logkmax = np.log(kmax) logk = np.linspace(logkmin, logkmax, num=nk) kk = np.exp(logk) #logarithmic grid on k Pk = np.zeros(nk) for ik in range(nk): Pk[ik] = cosmo.pk(kk[ik], 0.) #In Mpc^3 Uarr = np.zeros((npairs, nk)) for ipair in range(npairs): if flag[ipair] == 0: ibin = pairs[0, ipair] jbin = pairs[1, ipair] for ik in range(nk): kr = kk[ik] * comov_dist integrand = dV * windows[ibin, :] * windows[ jbin, :] * growth * np.sin(kr) / kr Uarr[ipair, ik] = integrate.simps(integrand, zz) # Compute Sijkl finally Cl_zero = np.zeros((nbins, nbins, nbins, nbins)) #For ipair<=jpair for ipair in range(npairs): if flag[ipair] == 0: U1 = Uarr[ipair, :] / Inorm[ipair] ibin = pairs[0, ipair] jbin = pairs[1, ipair] for jpair in range(ipair, npairs): if flag[jpair] == 0: U2 = Uarr[jpair, :] / Inorm[jpair] kbin = pairs[0, jpair] lbin = pairs[1, jpair] integrand = kk**2 * Pk * U1 * U2 #integral = 2/(i * integrate.simps(integrand,kk) #linear integration integral = 2 / pi * integrate.simps(integrand * kk, logk) #log integration #Run through all valid symmetries to fill the 4D array #Symmetries: i<->j, k<->l, (i,j)<->(k,l) Cl_zero[ibin, jbin, kbin, lbin] = integral Cl_zero[ibin, jbin, lbin, kbin] = integral Cl_zero[jbin, ibin, kbin, lbin] = integral Cl_zero[jbin, ibin, lbin, kbin] = integral Cl_zero[kbin, lbin, ibin, jbin] = integral Cl_zero[kbin, lbin, jbin, ibin] = integral Cl_zero[lbin, kbin, ibin, jbin] = integral Cl_zero[lbin, kbin, jbin, ibin] = integral Sijkl = Cl_zero / (4 * pi) return Sijkl # End of PySSC.py
'Omega_cdm': 0.2607, 'YHe': 0.245, 'z_reio': 7.82, 'n_s': 0.9665, 'A_s': 2.105e-9, 'P_k_max_1/Mpc': 500.0, 'perturbed recombination': 'y', 'non linear': 'halofit' } M = Class() M.set(class_parameters) M.set({'z_pk': z_compute}) M.compute() h = M.h() # get reduced Hubble for conversions to 1/Mpc one_time = M.get_transfer(z_compute) # Transfer functions # Convert to units of Mpc^{-1} k_ary = one_time['k (h/Mpc)'] * h delta_b_ary = one_time['d_b'] delta_chi_ary = one_time['d_chi'] n_s = M.n_s() # Primordial PS k_pivot = 0.05
class tsz_gal_cl: def __init__(self): # print 'Class for tSZ Cl' # self.ptilde = np.loadtxt(LIBDIR+'/aux_files/ptilde.txt') self.fort_lib_cl = cdll.LoadLibrary(LIBDIR + "/source/calc_cl") self.fort_lib_cl.calc_cl_.argtypes = [ POINTER(c_double), #h0 POINTER(c_double), #obh2 POINTER(c_double), #och2 POINTER(c_double), #mnu POINTER(c_double), #bias POINTER(c_double), #Mcut POINTER(c_double), #M1 POINTER(c_double), #kappa POINTER(c_double), #sigma_Ncen POINTER(c_double), #alp_Nsat POINTER(c_double), #rmax POINTER(c_double), #rgs POINTER(c_int64), #pk_nk POINTER(c_int64), #pk_nz np.ctypeslib.ndpointer(dtype=np.double), #karr np.ctypeslib.ndpointer(dtype=np.double), #pkarr np.ctypeslib.ndpointer(dtype=np.double), #dndz POINTER(c_int64), #nz_dndz POINTER(c_double), #z1 POINTER(c_double), #z2 POINTER(c_double), #z1_ng POINTER(c_double), #z2_ng POINTER(c_int64), #nl np.ctypeslib.ndpointer(dtype=np.double), #ell np.ctypeslib.ndpointer(dtype=np.double), #gg np.ctypeslib.ndpointer(dtype=np.double), #gy np.ctypeslib.ndpointer(dtype=np.double), #tll POINTER(c_double), #ng(z1<z<z2) POINTER(c_int64), #flag_nu POINTER(c_int64), #flag_tll POINTER(c_int64), #nm POINTER(c_int64) #nz ] self.fort_lib_cl.calc_cl_.restype = c_void_p # Calcualtion setup self.kmin = 1e-3 self.kmax = 5. self.zmax = 4. # should be consistent with fortran code self.nk_pk = 200 self.nz_pk = 51 # Class self.cosmo = Class() def get_tsz_cl(self, ell_arr, params, dndz, z1, z2, z1_ng, z2_ng, nm, nz): self.zmin = z1 self.zmax = z2 obh2 = params['obh2'] och2 = params['och2'] As = params['As'] ns = params['ns'] mnu = params['mnu'] mass_bias = params['mass_bias'] Mcut = params['Mcut'] M1 = params['M1'] kappa = params['kappa'] sigma_Ncen = params['sigma_Ncen'] alp_Nsat = params['alp_Nsat'] rmax = params['rmax'] rgs = params['rgs'] flag_nu_logic = params['flag_nu'] flag_tll_logic = params['flag_tll'] if type(flag_nu_logic) != bool: print 'flag_nu must be boolean.' sys.exit() if flag_nu_logic: flag_nu = 1 else: flag_nu = 0 if type(flag_tll_logic) != bool: print 'flag_tll must be boolean.' sys.exit() if flag_tll_logic: flag_tll = 1 else: flag_tll = 0 if 'theta' in params.keys(): theta = params['theta'] pars = {'output':'mPk','100*theta_s':theta, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':self.zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() h0 = self.cosmo.h() elif 'h0' in params.keys(): h0 = params['h0'] pars = {'output':'mPk','h':h0, 'omega_b':obh2,'omega_cdm':och2, 'A_s':As,'n_s':ns,\ 'N_ur':0.00641,'N_ncdm':1,'m_ncdm':mnu/3.,\ 'T_ncdm':0.71611,\ 'P_k_max_h/Mpc': self.kmax,'z_max_pk':self.zmax,\ 'deg_ncdm':3.} self.cosmo.set(pars) self.cosmo.compute() # get matter power spectra kh_arr = np.logspace(np.log10(self.kmin), np.log10(self.kmax), self.nk_pk) kh = np.zeros((self.nz_pk, self.nk_pk)) pk = np.zeros((self.nz_pk, self.nk_pk)) pk_zarr = np.linspace(self.zmin, self.zmax, self.nz_pk) for i in range(self.nz_pk): kh[i, :] = kh_arr if flag_nu == 0: pk[i, :] = np.array([ self.cosmo.pk(k * h0, pk_zarr[i]) * h0**3 for k in kh_arr ]) elif flag_nu == 1: pk[i, :] = np.array([ self.cosmo.pk_cb(k * h0, pk_zarr[i]) * h0**3 for k in kh_arr ]) # params h0_in = byref(c_double(h0)) obh2_in = byref(c_double(obh2)) och2_in = byref(c_double(och2)) mnu_in = byref(c_double(mnu)) mass_bias_in = byref(c_double(mass_bias)) Mcut_in = byref(c_double(Mcut)) M1_in = byref(c_double(M1)) kappa_in = byref(c_double(kappa)) sigma_Ncen_in = byref(c_double(sigma_Ncen)) alp_Nsat_in = byref(c_double(alp_Nsat)) rmax_in = byref(c_double(rmax)) rgs_in = byref(c_double(rgs)) flag_nu_in = byref(c_int64(flag_nu)) flag_tll_in = byref(c_int64(flag_tll)) # dNdz nz_dndz = byref(c_int64(len(dndz))) # integration setting z1_in = byref(c_double(self.zmin)) z2_in = byref(c_double(self.zmax)) # outputs nl = len(ell_arr) cl_gg = np.zeros((2, nl)) cl_gy = np.zeros((2, nl)) tll = np.zeros((nl * 2, nl * 2)) ng = c_double(0.0) nl = c_int64(nl) self.fort_lib_cl.calc_cl_( h0_in, obh2_in, och2_in, mnu_in,\ mass_bias_in, \ Mcut_in, M1_in, kappa_in, sigma_Ncen_in, alp_Nsat_in,\ rmax_in, rgs_in,\ byref(c_int64(self.nk_pk)), byref(c_int64(self.nz_pk)),\ np.array(kh),np.array(pk),\ np.array(dndz),nz_dndz,\ z1_in, z2_in,\ byref(c_double(z1_ng)),byref(c_double(z2_ng)),\ nl,np.array(ell_arr),\ cl_gg,cl_gy,tll,ng,\ flag_nu_in,flag_tll_in,\ c_int64(nm), c_int64(nz) ) self.cosmo.struct_cleanup() return cl_gg, cl_gy, tll, ng.value
tau = np.concatenate((tau1,tau2)) tau_num = len(tau) # # use table of background and thermodynamics quantitites to define some functions # returning some characteristic scales # (of Hubble crossing, sound horizon crossing, etc.) at different time # background = M.get_background() # load background table #print background.viewkeys() thermodynamics = M.get_thermodynamics() # load thermodynamics table #print thermodynamics.viewkeys() # background_tau = background['conf. time [Mpc]'] # read conformal times in background table background_z = background['z'] # read redshift # background_aH = 2.*math.pi*background['H [1/Mpc]']/(1.+background['z'])/M.h() # read 2pi * aH in [h/Mpc] background_aH = background['H [1/Mpc]']/(1.+background['z'])/M.h() # read 2pi * aH in [h/Mpc] background_ks = 2.*math.pi/background['comov.snd.hrz.']/M.h() # read 2pi/(comoving sound horizon) in [h/Mpc] background_rho_m_over_r = (background['(.)rho_b']+background['(.)rho_cdm']) /(background['(.)rho_g']+background['(.)rho_ur']) # read rho_r / rho_m (to find time of equality) background_rho_l_over_m = background['(.)rho_lambda'] /(background['(.)rho_b']+background['(.)rho_cdm']) # read rho_m / rho_lambda (to find time of equality) thermodynamics_tau = thermodynamics['conf. time [Mpc]'] # read confromal times in thermodynamics table # thermodynamics_kd = 2.*math.pi/thermodynamics['r_d']/M.h() # read 2pi(comoving diffusion scale) in [h/Mpc] # # define a bunch of interpolation functions based on previous quantities # background_z_at_tau = interp1d(background_tau,background_z) background_tau_at_z = interp1d(background_z,background_tau) background_aH_at_tau = interp1d(background_tau,background_aH) background_ks_at_tau = interp1d(background_tau,background_ks) background_tau_at_mr = interp1d(background_rho_m_over_r,background_tau) background_tau_at_lm = interp1d(background_rho_l_over_m,background_tau) #
NH.set(commonsettings) NH.set({'m_ncdm': str(m1) + ',' + str(m2) + ',' + str(m3)}) NH.compute() # inverted hierarchy [m1, m2, m3] = get_masses(2.45e-3, 7.50e-5, sum_masses, 'IH') IH = Class() IH.set(commonsettings) IH.set({'m_ncdm': str(m1) + ',' + str(m2) + ',' + str(m3)}) IH.compute() pkNH = [] pkIH = [] for k in kvec: pkNH.append(NH.pk(k, 0.)) pkIH.append(IH.pk(k, 0.)) NH.struct_cleanup() IH.struct_cleanup() # extract h value to convert k from 1/Mpc to h/Mpc h = NH.h() plt.semilogx(kvec / h, 1 - np.array(pkNH) / np.array(pkIH)) legarray.append(r'$\Sigma m_i = ' + str(sum_masses) + '$eV') plt.axhline(0, color='k') plt.xlim(kvec[0] / h, kvec[-1] / h) plt.xlabel(r'$k [h \mathrm{Mpc}^{-1}]$') plt.ylabel(r'$1-P(k)^\mathrm{NH}/P(k)^\mathrm{IH}$') plt.legend(legarray) # In[6]: plt.savefig('neutrinohierarchy.pdf')
tau_num = len(tau) # # use table of background and thermodynamics quantitites to define some functions # returning some characteristic scales # (of Hubble crossing, sound horizon crossing, etc.) at different time # background = M.get_background() # load background table #print background.viewkeys() thermodynamics = M.get_thermodynamics() # load thermodynamics table #print thermodynamics.viewkeys() # background_tau = background[ 'conf. time [Mpc]'] # read conformal times in background table background_z = background['z'] # read redshift background_aH = 2. * math.pi * background['H [1/Mpc]'] / ( 1. + background['z']) / M.h() # read 2pi * aH in [h/Mpc] background_ks = 2. * math.pi / background['comov.snd.hrz.'] / M.h( ) # read 2pi/(comoving sound horizon) in [h/Mpc] background_rho_m_over_r = (background['(.)rho_b'] + background['(.)rho_cdm']) / ( background['(.)rho_g'] + background['(.)rho_ur'] ) # read rho_r / rho_m (to find time of equality) background_rho_l_over_m = background['(.)rho_lambda'] / ( background['(.)rho_b'] + background['(.)rho_cdm'] ) # read rho_m / rho_lambda (to find time of equality) thermodynamics_tau = thermodynamics[ 'conf. time [Mpc]'] # read confromal times in thermodynamics table thermodynamics_kd = 2. * math.pi / thermodynamics['r_d'] / M.h( ) # read 2pi(comoving diffusion scale) in [h/Mpc] # # define a bunch of interpolation functions based on previous quantities
NH.set({'m_ncdm':str(m1)+','+str(m2)+','+str(m3)}) NH.compute() # inverted hierarchy [m1, m2, m3] = get_masses(2.45e-3,7.50e-5, sum_masses, 'IH') IH = Class() IH.set(commonsettings) IH.set({'m_ncdm':str(m1)+','+str(m2)+','+str(m3)}) IH.compute() pkNH = [] pkIH = [] for k in kvec: pkNH.append(NH.pk(k,0.)) pkIH.append(IH.pk(k,0.)) NH.struct_cleanup() IH.struct_cleanup() # extract h value to convert k from 1/Mpc to h/Mpc h = NH.h() plt.semilogx(kvec/h,1-np.array(pkNH)/np.array(pkIH)) legarray.append(r'$\Sigma m_i = '+str(sum_masses)+'$eV') plt.axhline(0,color='k') plt.xlim(kvec[0]/h,kvec[-1]/h) plt.xlabel(r'$k [h \mathrm{Mpc}^{-1}]$') plt.ylabel(r'$1-P(k)^\mathrm{NH}/P(k)^\mathrm{IH}$') plt.legend(legarray) # In[6]: plt.savefig('neutrinohierarchy.pdf')
class classy(_cosmo): def initialize(self): """Importing CLASS from the correct path, if given, and if not, globally.""" # If path not given, try using general path to modules if not self.path and self.path_install: self.path = os.path.join( self.path_install, "code", classy_repo_rename) if self.path: self.log.info("Importing *local* classy from " + self.path) classy_build_path = os.path.join(self.path, "python", "build") post = next(d for d in os.listdir(classy_build_path) if d.startswith("lib.")) classy_build_path = os.path.join(classy_build_path, post) if not os.path.exists(classy_build_path): self.log.error("Either CLASS is not in the given folder, " "'%s', or you have not compiled it.", self.path) raise HandledException # Inserting the previously found path into the list of import folders sys.path.insert(0, classy_build_path) else: self.log.info("Importing *global* CLASS.") try: from classy import Class, CosmoSevereError, CosmoComputationError except ImportError: self.log.error( "Couldn't find the CLASS python interface. " "Make sure that you have compiled it, and that you either\n" " (a) specify a path (you didn't) or\n" " (b) install the Python interface globally with\n" " '/path/to/class/python/python setup.py install --user'") raise HandledException self.classy = Class() # Propagate errors up global CosmoComputationError, CosmoSevereError # Generate states, to avoid recomputing self.n_states = 3 self.states = [{"params": None, "derived": None, "derived_extra": None, "last": 0} for i in range(self.n_states)] # Dict of named tuples to collect requirements and computation methods self.collectors = {} # Additional input parameters to pass to CLASS self.extra_args = self.extra_args or {} # Add general CLASS stuff self.extra_args["output"] = self.extra_args.get("output", "") if "sBBN file" in self.extra_args: self.extra_args["sBBN file"] = ( self.extra_args["sBBN file"].format(classy=self.path)) # Set aliases self.planck_to_classy = self.renames # Derived parameters that may not have been requested, but will be necessary later self.derived_extra = [] def current_state(self): lasts = [self.states[i]["last"] for i in range(self.n_states)] return self.states[lasts.index(max(lasts))] def needs(self, **requirements): # Computed quantities required by the likelihood super(classy, self).needs(**requirements) for k, v in self._needs.items(): # Products and other computations if k.lower() == "cl": if any([("t" in cl.lower()) for cl in v]): self.extra_args["output"] += " tCl" if any([(("e" in cl.lower()) or ("b" in cl.lower())) for cl in v]): self.extra_args["output"] += " pCl" # For modern experiments, always lensed Cl's! self.extra_args["output"] += " lCl" self.extra_args["lensing"] = "yes" # For l_max_scalars, remember previous entries. self.extra_args["l_max_scalars"] = max(v.values()) self.collectors[k.lower()] = collector( method="lensed_cl", kwargs={"lmax": self.extra_args["l_max_scalars"]}) elif k.lower() == "h": self.collectors[k.lower()] = collector( method="Hubble", args=[np.atleast_1d(v["z"])], args_names=["z"], arg_array=0) self.H_units_conv_factor = {"1/Mpc": 1, "km/s/Mpc": _c_km_s} elif k.lower() == "angular_diameter_distance": self.collectors[k.lower()] = collector( method="angular_distance", args=[np.atleast_1d(v["z"])], args_names=["z"], arg_array=0) elif k.lower() == "comoving_radial_distance": self.collectors[k.lower()] = collector( method="z_of_r", args_names=["z"], args=[np.atleast_1d(v["z"])]) elif k.lower() == "pk_interpolator": self.extra_args["output"] += " mPk" self.extra_args["P_k_max_h/Mpc"] = max( v.pop("k_max"), self.extra_args.get("P_k_max_h/Mpc", 0)) self.add_z_for_matter_power(v.pop("z")) # Use halofit by default if non-linear requested but no code specified if v.get("nonlinear", False) and "non linear" not in self.extra_args: self.extra_args["non linear"] = non_linear_default_code for pair in v.pop("vars_pairs", [["delta_tot", "delta_tot"]]): if any([x.lower() != "delta_tot" for x in pair]): self.log.error("NotImplemented in CLASS: %r", pair) raise HandledException self._Pk_interpolator_kwargs = { "logk": True, "extrap_kmax": v.pop("extrap_kmax", None)} name = "Pk_interpolator_%s_%s" % (pair[0], pair[1]) self.collectors[name] = collector( method="get_pk_and_k_and_z", kwargs=v, post=(lambda P, k, z:PowerSpectrumInterpolator( z, k, P.T, **self._Pk_interpolator_kwargs))) elif v is None: k_translated = self.translate_param(k, force=True) if k_translated not in self.derived_extra: self.derived_extra += [k_translated] else: self.log.error("Requested product not known: %r", {k: v}) raise HandledException # Derived parameters (if some need some additional computations) if any([("sigma8" in s) for s in self.output_params or requirements]): self.extra_args["output"] += " mPk" self.extra_args["P_k_max_h/Mpc"] = ( max(1, self.extra_args.get("P_k_max_h/Mpc", 0))) # Adding tensor modes if requested if self.extra_args.get("r") or "r" in self.input_params: self.extra_args["modes"] = "s,t" # If B spectrum with l>50, or lensing, recommend using Halofit try: cls = self.needs[next(k for k in ["cl", "Cl", "CL"] if k in self._needs)] except: cls = {} if (((any([("b" in cl.lower()) for cl in cls]) and max([cls[cl] for cl in cls if "b" in cl.lower()]) > 50) or any([("p" in cl.lower()) for cl in cls]) and not self.extra_args.get("non linear"))): self.log.warning("Requesting BB for ell>50 or lensing Cl's: " "using a non-linear code is recommended (and you are not " "using any). To activate it, set " "'non_linear: halofit|hmcode|...' in classy's 'extra_args'.") # Cleanup of products string self.extra_args["output"] = " ".join(set(self.extra_args["output"].split())) # Finally, check that there are no repeated parameters between input and extra if set(self.input_params).intersection(set(self.extra_args)): self.log.error( "The following parameters appear both as input parameters and as CLASS " "extra arguments: %s. Please, remove one of the definitions of each.", list(set(self.input_params).intersection(set(self.extra_args)))) raise HandledException def add_z_for_matter_power(self, z): if not hasattr(self, "z_for_matter_power"): self.z_for_matter_power = np.empty((0)) self.z_for_matter_power = np.flip(np.sort(np.unique(np.concatenate( [self.z_for_matter_power, np.atleast_1d(z)]))), axis=0) self.extra_args["z_pk"] = " ".join(["%g" % zi for zi in self.z_for_matter_power]) def translate_param(self, p, force=False): # "force=True" is used when communicating with likelihoods, which speak "planck" if self.use_planck_names or force: return self.planck_to_classy.get(p, p) return p def set(self, params_values_dict, i_state): # Store them, to use them later to identify the state self.states[i_state]["params"] = deepcopy(params_values_dict) # Prepare parameters to be passed: this-iteration + extra args = {self.translate_param(p): v for p, v in params_values_dict.items()} args.update(self.extra_args) # Generate and save self.log.debug("Setting parameters: %r", args) self.classy.struct_cleanup() self.classy.set(**args) def compute(self, _derived=None, cached=True, **params_values_dict): lasts = [self.states[i]["last"] for i in range(self.n_states)] try: if not cached: raise StopIteration # are the parameter values there already? i_state = next(i for i in range(self.n_states) if self.states[i]["params"] == params_values_dict) # has any new product been requested? for product in self.collectors: next(k for k in self.states[i_state] if k == product) reused_state = True # Get (pre-computed) derived parameters if _derived == {}: _derived.update(self.states[i_state]["derived"]) self.log.debug("Re-using computed results (state %d)", i_state) except StopIteration: reused_state = False # update the (first) oldest one and compute i_state = lasts.index(min(lasts)) self.log.debug("Computing (state %d)", i_state) if self.timing: a = time() # Set parameters self.set(params_values_dict, i_state) # Compute! try: self.classy.compute() # "Valid" failure of CLASS: parameters too extreme -> log and report except CosmoComputationError: self.log.debug("Computation of cosmological products failed. " "Assigning 0 likelihood and going on.") return 0 # CLASS not correctly initialized, or input parameters not correct except CosmoSevereError: self.log.error("Serious error setting parameters or computing results. " "The parameters passed were %r and %r. " "See original CLASS's error traceback below.\n", self.states[i_state]["params"], self.extra_args) raise # No HandledException, so that CLASS traceback gets printed # Gather products for product, collector in self.collectors.items(): # Special case: sigma8 needs H0, which cannot be known beforehand: if "sigma8" in self.collectors: self.collectors["sigma8"].args[0] = 8 / self.classy.h() method = getattr(self.classy, collector.method) arg_array = self.collectors[product].arg_array if arg_array is None: self.states[i_state][product] = method( *self.collectors[product].args, **self.collectors[product].kwargs) elif isinstance(arg_array, Number): self.states[i_state][product] = np.zeros( len(self.collectors[product].args[arg_array])) for i, v in enumerate(self.collectors[product].args[arg_array]): args = (list(self.collectors[product].args[:arg_array]) + [v] + list(self.collectors[product].args[arg_array + 1:])) self.states[i_state][product][i] = method( *args, **self.collectors[product].kwargs) elif arg_array in self.collectors[product].kwargs: value = np.atleast_1d(self.collectors[product].kwargs[arg_array]) self.states[i_state][product] = np.zeros(value.shape) for i, v in enumerate(value): kwargs = deepcopy(self.collectors[product].kwargs) kwargs[arg_array] = v self.states[i_state][product][i] = method( *self.collectors[product].args, **kwargs) self.states[i_state][product] = collector.post( self.states[i_state][product]) # Prepare derived parameters d, d_extra = self.get_derived_all(derived_requested=(_derived == {})) if _derived == {}: _derived.update(d) self.states[i_state]["derived"] = odict( [[p, _derived.get(p)] for p in self.output_params]) # Prepare necessary extra derived parameters self.states[i_state]["derived_extra"] = deepcopy(d_extra) if self.timing: self.n += 1 self.time_avg = (time() - a + self.time_avg * (self.n - 1)) / self.n self.log.debug("Average running time: %g seconds", self.time_avg) # make this one the current one by decreasing the antiquity of the rest for i in range(self.n_states): self.states[i]["last"] -= max(lasts) self.states[i_state]["last"] = 1 return 1 if reused_state else 2 def get_derived_all(self, derived_requested=True): """ Returns a dictionary of derived parameters with their values, using the *current* state (i.e. it should only be called from the ``compute`` method). Parameter names are returned in CLASS nomenclature. To get a parameter *from a likelihood* use `get_param` instead. """ # Put all pamaremters in CLASS nomenclature (self.derived_extra already is) requested = [self.translate_param(p) for p in ( self.output_params if derived_requested else [])] requested_and_extra = { p: None for p in set(requested).union(set(self.derived_extra))} # Parameters with their own getters if "rs_drag" in requested_and_extra: requested_and_extra["rs_drag"] = self.classy.rs_drag() elif "Omega_nu" in requested_and_extra: requested_and_extra["Omega_nu"] = self.classy.Omega_nu # Get the rest using the general derived param getter # No need for error control: classy.get_current_derived_parameters is passed # every derived parameter not excluded before, and cause an error, indicating # which parameters are not recognized requested_and_extra.update( self.classy.get_current_derived_parameters( [p for p, v in requested_and_extra.items() if v is None])) # Separate the parameters before returning # Remember: self.output_params is in sampler nomenclature, # but self.derived_extra is in CLASS derived = { p: requested_and_extra[self.translate_param(p)] for p in self.output_params} derived_extra = {p: requested_and_extra[p] for p in self.derived_extra} return derived, derived_extra def get_param(self, p): current_state = self.current_state() for pool in ["params", "derived", "derived_extra"]: value = deepcopy( current_state[pool].get(self.translate_param(p, force=True), None)) if value is not None: return value self.log.error("Parameter not known: '%s'", p) raise HandledException def get_cl(self, ell_factor=False, units="muK2"): current_state = self.current_state() try: cls = deepcopy(current_state["cl"]) except: self.log.error( "No Cl's were computed. Are you sure that you have requested them?") raise HandledException # unit conversion and ell_factor ell_factor = ((cls["ell"] + 1) * cls["ell"] / (2 * np.pi))[2:] if ell_factor else 1 units_factors = {"1": 1, "muK2": _T_CMB_K * 1.e6, "K2": _T_CMB_K} try: units_factor = units_factors[units] except KeyError: self.log.error("Units '%s' not recognized. Use one of %s.", units, list(units_factors)) raise HandledException for cl in cls: if cl not in ['pp', 'ell']: cls[cl][2:] *= units_factor ** 2 * ell_factor if "pp" in cls and ell_factor is not 1: cls['pp'][2:] *= ell_factor ** 2 * (2 * np.pi) return cls def _get_z_dependent(self, quantity, z): try: z_name = next(k for k in ["redshifts", "z"] if k in self.collectors[quantity].kwargs) computed_redshifts = self.collectors[quantity].kwargs[z_name] except StopIteration: computed_redshifts = self.collectors[quantity].args[ self.collectors[quantity].args_names.index("z")] i_kwarg_z = np.concatenate( [np.where(computed_redshifts == zi)[0] for zi in np.atleast_1d(z)]) values = np.array(deepcopy(self.current_state()[quantity])) if quantity == "comoving_radial_distance": values = values[0] return values[i_kwarg_z] def get_H(self, z, units="km/s/Mpc"): try: return self._get_z_dependent("h", z) * self.H_units_conv_factor[units] except KeyError: self.log.error("Units not known for H: '%s'. Try instead one of %r.", units, list(self.H_units_conv_factor)) raise HandledException def get_angular_diameter_distance(self, z): return self._get_z_dependent("angular_diameter_distance", z) def get_comoving_radial_distance(self, z): return self._get_z_dependent("comoving_radial_distance", z) def get_Pk_interpolator(self): current_state = self.current_state() prefix = "Pk_interpolator_" return {k[len(prefix):]: deepcopy(v) for k, v in current_state.items() if k.startswith(prefix)} def close(self): self.classy.struct_cleanup()
# # call CLASS a first time just to compute z_rec (will compute transfer functions at default: z=0) # ############### M = Class() M.set(common_settings) M.compute() derived = M.get_current_derived_parameters(['z_rec','tau_rec','conformal_age']) print (derived.keys()) z_rec = derived['z_rec'] z_rec = int(1000.*z_rec)/1000. # round down at 4 digits after coma print ('z_rec=',z_rec) # # In the last figure the x-axis will show l/(tau_0-tau_rec), so we need (tau_0-tau_rec) in units of [Mpc/h] # tau_0_minus_tau_rec_hMpc = (derived['conformal_age']-derived['tau_rec'])*M.h() # In[ ]: ################ # # call CLASS again for the perturbations (will compute transfer functions at input value z_rec) # ################ M.empty() # reset input parameters to default, before passing a new parameter set M.set(common_settings) M.set({'z_pk':z_rec}) M.compute() #
# get Theta0 oscillation amplitude (for vertical scale of plot) # Theta0_amp = max(Theta0.max(), -Theta0.min()) # # use table of background quantitites to find the wavenumbers corresponding to # Hubble crossing (k = 2 pi a H), sound horizon crossing (k = 2pi / rs) # background = M.get_background() # load background table #print background.viewkeys() # background_tau = background[ 'conf. time [Mpc]'] # read confromal times in background table background_z = background['z'] # read redshift background_kh = 2. * math.pi * background['H [1/Mpc]'] / ( 1. + background['z'] ) / M.h() # read kh = 2pi aH = 2pi H/(1+z) converted to [h/Mpc] background_ks = 2. * math.pi / background['comov.snd.hrz.'] / M.h( ) # read ks = 2pi/rs converted to [h/Mpc] # # define interpolation functions; we want the value of tau when the argument is equal to 2pi # kh_at_tau = interp1d(background_tau, background_kh) ks_at_tau = interp1d(background_tau, background_ks) # # finally get these scales # tau_rec = derived['tau_rec'] kh = kh_at_tau(tau_rec) ks = ks_at_tau(tau_rec) # #################
plt.plot((ttCLASS[:ell_max + 1] - ttCAMB[:ell_max + 1]) / ttCAMB[:ell_max + 1], '-') plt.xlabel(r'$\ell$') plt.ylabel(r'$\Delta C_{\ell}^{TT} / C_{\ell}^{TT}$') plt.title('TT Comparison of CAMB and CLASS') ########## P(k) ######################### pars.set_matter_power(redshifts=[0.], kmax=2.0) pars.NonLinear = model.NonLinear_none results = camb.get_results(pars) kh, z, pk = results.get_matter_power_spectrum(minkh=1e-4, maxkh=1, npoints=200) s8 = np.array(results.get_sigma8()) PCLASS = np.array([cosmo.pk_lin(ki * cosmo.h(), 0) for ki in kh]) # plt.loglog(kh, Pmm, '-') plt.loglog(kh, PCLASS / (cosmo.h())**(-3), '-') plt.loglog(kh, pk[0, :], '-') plt.title('LINEAR') # P(k) Comparison plt.loglog(kh, np.abs((PCLASS / (cosmo.h())**(-3) - pk[0, :]) / pk[0, :])) plt.xlabel(r'$k/h$') plt.ylabel(r'$|\Delta P(k)| / P(k)$') # Nonlinear P(k) Difference pars.NonLinear = model.NonLinear_both
'omega_cdm': omega_cdm, 'n_s': n_s } # update the CLASS object with the current parameters class_cosmo = Class() # update the cosmology new_cosmo = {**fid_cosmo, **updated_dict} new_cosmo['output'] = 'mPk' new_cosmo['z_max_pk'] = 1.1 class_cosmo.set(new_cosmo) class_cosmo.compute() # search for the corresponding value of H0 that keeps theta_s constant and update Omega_b and c h = class_cosmo.h() #h = H0_search(class_cosmo, fid_cosmo['100*theta_s'], prec=1.e4, tol_t=1.e-4) print(h) param_dict['h'] = h param_dict['Omega_c'] = omega_cdm / h**2 param_dict['Omega_b'] = omega_b / h**2 param_dict['A_s'] = A_s # remove parameters not recognized by ccl param_not_ccl = ['100*theta_s', 'omega_cdm', 'omega_b', 'output', 'sigma8'] for p in param_not_ccl: if p in param_dict.keys(): param_dict.pop(p) #param_dict['T_cmb'] = header['T_cmb'] # cosmology of the current step cosmo_ccl = ccl.Cosmology(**param_dict)
R = 3./4.*M.Omega_b()/M.Omega_g()/(1+z_rec) # R = 3/4 * (rho_b/rho_gamma) at z_rec zero_point = -(1.+R)*psi # zero point of oscillations: -(1.+R)*psi # # get Theta0 oscillation amplitude (for vertical scale of plot) # Theta0_amp = max(Theta0.max(),-Theta0.min()) # # use table of background quantitites to find the wavenumbers corresponding to # Hubble crossing (k = 2 pi a H), sound horizon crossing (k = 2pi / rs) # background = M.get_background() # load background table #print background.viewkeys() # background_tau = background['conf. time [Mpc]'] # read confromal times in background table background_z = background['z'] # read redshift background_kh = 2.*math.pi*background['H [1/Mpc]']/(1.+background['z'])/M.h() # read kh = 2pi aH = 2pi H/(1+z) converted to [h/Mpc] background_ks = 2.*math.pi/background['comov.snd.hrz.']/M.h() # read ks = 2pi/rs converted to [h/Mpc] # # define interpolation functions; we want the value of tau when the argument is equal to 2pi # kh_at_tau = interp1d(background_tau,background_kh) ks_at_tau = interp1d(background_tau,background_ks) # # finally get these scales # tau_rec = derived['tau_rec'] kh = kh_at_tau(tau_rec) ks = ks_at_tau(tau_rec) # ################# #