def tabulate_3D_variances(ell, DA, growth, power): """ Tabulate 3D matter-power contributions to shear power variances. This function is defined as: .. math:: V(\ell, D_A) = \\frac{\pi}{\ell} G(D)^2 \Delta^2_\delta(k=\ell/D_A(D), z=0) where :math:`D` is the comoving distance corresponding to the comoving transverse distance :math:`D_A` and :math:`\ell` is a 2D wavenumber. Use :func:`calculate_shear_power` to calculate the lensing shear power associated with the returned 3D matter-power contributions. Parameters ---------- ell : numpy.ndarray 1D array of 2D wavenumbers where shear power variances should be tabulated. Values must be positive and increasing, but do not need to be equally spaced. DA : numpy.ndarray 1D array of :meth:`comoving transverse distances <astropy.cosmology.FLRW.comoving_transverse_distance>` :math:`D_A(z)` where shear power variances should be tabulated. Values must be positive and increasing, but do not need to be equally spaced. Values can be in either Mpc/h or Mpc, but must be consistent with the power spectrum normalization. growth : numpy.ndarray 1D array of growth function values :math:`G(z)` corresponding to each input :math:`DA(z)` value. Must have the same number of elements as DA. Can be calculated using :func:`randomfield.cosmotools.get_growth_function`. power : structured numpy.ndarray Power spectrum to use, which meets the criteria tested by :func:`randomfield.powertools.validate_power`. Can be calculated using :func:`randomfield.cosmotools.calculate_power` if the optional ``classy`` package is installed. Values of k and P(k) can either be in Mpc/h or Mpc units, but must be consistent with the values of DA. Returns ------- numpy.ndarray Two dimensional array with shape (nell, nDA) where nell = len(ell) and nDA = len(DA). The value ``out[i,j]`` gives the contribution to the shear variance :math:`\Delta^2_{EE}` at 2D wavenumber ``ell[i]`` from lensing by mass inhomogeneities at comoving transverse distance ``DA[j]``. The output is dimensionless. """ try: assert len(ell.shape) == 1 except (AssertionError, AttributeError): raise ValueError('Wavenumbers ell must be a 1D array.') if not np.array_equal(np.unique(ell), ell) or ell[0] <= 0: raise ValueError('Wavenumbers ell must be increasing values > 0.') try: assert len(DA.shape) == 1 except (AssertionError, AttributeError): raise ValueError('Distances DA must be a 1D array.') if not np.array_equal(np.unique(DA), DA) or DA[0] <= 0: raise ValueError('Distances DA must be increasing values > 0.') try: assert DA.shape == growth.shape except (AssertionError, AttributeError): raise ValueError('Growth array must match DA array dimensions.') # Build an interpolator for the dimensionless function # Delta**2(k) = k**3/(2*pi**2) * P(k) that is linear in log10(k). power = powertools.validate_power(power) k_grid = power['k'] Delta2_grid = k_grid**3 / (2 * np.pi**2) * power['Pk'] Delta2 = scipy.interpolate.interp1d(np.log10(k_grid), Delta2_grid, kind='linear', copy=False) # Tabulate a 2D array of k values for each (ell, DA). log10k_of_DA = np.log10(ell[:, np.newaxis] / DA) # Tabulate pi/ell * Delta**2(k) * G(DA)**2 values on this grid. return (np.pi / ell[:, np.newaxis]) * Delta2(log10k_of_DA) * growth**2
def __init__(self, nx, ny, nz, grid_spacing_Mpc_h, num_plot_sections=4, cosmology=None, power=None, verbose=False): self.plan_c2r = transform.Plan(shape=(nx, ny, nz), dtype_in=np.complex64, packed=True, overwrite=True, inverse=True, use_pyfftw=True) self.plan_r2c = self.plan_c2r.create_reverse_plan(reuse_output=True, overwrite=True) self.grid_spacing_Mpc_h = grid_spacing_Mpc_h self.k_min, self.k_max = powertools.get_k_bounds(self.plan_c2r.data_in, grid_spacing_Mpc_h, packed=True) self.potential = None if nz % num_plot_sections != 0: raise ValueError( 'Z-axis does not evenly divided into {0} plot sections.'. format(num_plot_sections)) self.num_plot_sections = num_plot_sections if cosmology is None: self.cosmology = cosmotools.create_cosmology() if power is None: power = powertools.load_default_power() else: self.cosmology = cosmology if power is None: power = cosmotools.calculate_power(self.cosmology, k_min=self.k_min, k_max=self.k_max, scaled_by_h=True) self.power = powertools.validate_power(power) self.redshifts = cosmotools.get_redshifts( self.cosmology, self.plan_c2r.data_out, spacing=self.grid_spacing_Mpc_h, scaled_by_h=True, z_axis=2).reshape(nz) self.redshift_to_index = scipy.interpolate.interp1d(self.redshifts, np.arange(nz), kind='linear', bounds_error=False) # Tabulate the comoving distance DC and transverse separation DA along # the line of sight in units of Mpc/h. self.DC = np.arange(nz) * self.grid_spacing_Mpc_h self.DA = (self.cosmology.comoving_transverse_distance( self.redshifts).to(u.Mpc).value) * self.cosmology.h # Calculate angular spacing in transverse (x,y) grid units per degree, # indexed by position along the z-axis. self.angular_spacing = (self.DA * (np.pi / 180.) / self.grid_spacing_Mpc_h) self.z_max = self.redshifts.flat[-1] # Use the plane-parallel approximation here. self.x_fov = nx / self.angular_spacing.flat[-1] self.y_fov = ny / self.angular_spacing.flat[-1] self.growth_function = cosmotools.get_growth_function( self.cosmology, self.redshifts) self.mean_matter_density = cosmotools.get_mean_matter_densities( self.cosmology, self.redshifts) self.verbose = verbose if self.verbose: Mb = (self.plan_c2r.nbytes_allocated + self.plan_r2c.nbytes_allocated) / 2.0**20 print('Allocated {0:.1f} Mb for {1} x {2} x {3} grid.'.format( Mb, nx, ny, nz)) print('{0} Mpc/h spacing covered by k = {1:.5f} - {2:.5f} h/Mpc.'. format(self.grid_spacing_Mpc_h, self.k_min, self.k_max)) print( 'Grid has z < {0:.3f} with {1:.4f} deg x {2:.4f} deg'.format( self.z_max, self.x_fov, self.y_fov), ' = {0:.4f} deg**2 field of view.'.format(self.x_fov * self.y_fov))
def __init__(self, nx, ny, nz, grid_spacing_Mpc_h, num_plot_sections=4, cosmology=None, power=None, verbose=False): self.plan_c2r = transform.Plan( shape=(nx, ny, nz), dtype_in=np.complex64, packed=True, overwrite=True, inverse=True, use_pyfftw=True) self.plan_r2c = self.plan_c2r.create_reverse_plan( reuse_output=True, overwrite=True) self.grid_spacing_Mpc_h = grid_spacing_Mpc_h self.k_min, self.k_max = powertools.get_k_bounds( self.plan_c2r.data_in, grid_spacing_Mpc_h, packed=True) self.potential = None if nz % num_plot_sections != 0: raise ValueError( 'Z-axis does not evenly divided into {0} plot sections.' .format(num_plot_sections)) self.num_plot_sections = num_plot_sections if cosmology is None: self.cosmology = cosmotools.create_cosmology() if power is None: power = powertools.load_default_power() else: self.cosmology = cosmology if power is None: power = cosmotools.calculate_power( self.cosmology, k_min=self.k_min, k_max=self.k_max, scaled_by_h=True) self.power = powertools.validate_power(power) self.redshifts = cosmotools.get_redshifts( self.cosmology, self.plan_c2r.data_out, spacing=self.grid_spacing_Mpc_h, scaled_by_h=True, z_axis=2).reshape(nz) self.redshift_to_index = scipy.interpolate.interp1d( self.redshifts, np.arange(nz), kind='linear', bounds_error=False) # Tabulate the comoving distance DC and transverse separation DA along # the line of sight in units of Mpc/h. self.DC = np.arange(nz) * self.grid_spacing_Mpc_h self.DA = (self.cosmology.comoving_transverse_distance(self.redshifts) .to(u.Mpc).value) * self.cosmology.h # Calculate angular spacing in transverse (x,y) grid units per degree, # indexed by position along the z-axis. self.angular_spacing = ( self.DA * (np.pi / 180.) / self.grid_spacing_Mpc_h) self.z_max = self.redshifts.flat[-1] # Use the plane-parallel approximation here. self.x_fov = nx / self.angular_spacing.flat[-1] self.y_fov = ny / self.angular_spacing.flat[-1] self.growth_function = cosmotools.get_growth_function( self.cosmology, self.redshifts) self.mean_matter_density = cosmotools.get_mean_matter_densities( self.cosmology, self.redshifts) self.verbose = verbose if self.verbose: Mb = (self.plan_c2r.nbytes_allocated + self.plan_r2c.nbytes_allocated) / 2.0**20 print('Allocated {0:.1f} Mb for {1} x {2} x {3} grid.' .format(Mb, nx, ny, nz)) print('{0} Mpc/h spacing covered by k = {1:.5f} - {2:.5f} h/Mpc.' .format(self.grid_spacing_Mpc_h, self.k_min, self.k_max)) print('Grid has z < {0:.3f} with {1:.4f} deg x {2:.4f} deg' .format(self.z_max, self.x_fov, self.y_fov), ' = {0:.4f} deg**2 field of view.' .format(self.x_fov * self.y_fov))