def power_spectrum_multipoles(input_array, kbins = 10, box_dims = None,\ los_axis = 0): ''' Calculate the power spectrum of an array and expand it in the first three Legendre polynomials. Parameters: * input_array (numpy array): the array to calculate the power spectrum of. Can be of any dimensions. * kbins = 10 (integer or array-like): The number of bins, or a list containing the bin edges. If an integer is given, the bins are logarithmically spaced. * box_dims = None (float or array-like): the dimensions of the box. If this is None, the current box volume is used along all dimensions. If it is a float, this is taken as the box length along all dimensions. If it is an array-like, the elements are taken as the box length along each axis. * los_axis = 0 (integer): the line-of-sight axis Returns: A tuple with (P0, P2, P4, k) where P0, P2 and P4 are the multipole moments as a function of k and k contains the midpoints of the k bins. All four arrays have the same length ''' assert (los_axis >= 0 and los_axis <= len(input_array.shape)) #First calculate the power spectrum box_dims = _get_dims(box_dims, input_array.shape) ps = power_spectrum_nd(input_array, box_dims) #Get k values and bins k_comp, k = _get_k(input_array, box_dims) kbins = _get_kbins(kbins, box_dims, k) dk = (kbins[1:] - kbins[:-1]) / 2. mu = _get_mu(k_comp, k, los_axis) #Legendre polynomials P0 = np.ones_like(mu) P2 = 0.5 * (3. * mu**2 - 1.) P4 = 4.375 * (mu**2 - 0.115587) * (mu**2 - 0.741556) #Bin data n_kbins = len(kbins) - 1 outdata_P0 = np.zeros(n_kbins) outdata_P2 = np.zeros_like(outdata_P0) outdata_P4 = np.zeros_like(outdata_P0) for i in range(n_kbins): idx = (k > kbins[i]) * (k <= kbins[i + 1]) outdata_P0[i] = np.sum(ps[idx] * P0[idx]) / np.sum(P0[idx]**2) outdata_P2[i] = np.sum(ps[idx] * P2[idx]) / np.sum(P2[idx]**2) outdata_P4[i] = np.sum(ps[idx] * P4[idx]) / np.sum(P4[idx]**2) return outdata_P0, outdata_P2, outdata_P4, kbins[:-1] + dk
def make_gaussian_random_field(dims, box_dims, power_spectrum, random_seed=None): ''' Generate a Gaussian random field with the specified power spectrum. Parameters: * dims (tuple): the dimensions of the field in number of cells. Can be 2D or 3D. * box_dims (float or tuple): the dimensions of the field in cMpc. * power_spectrum (callable, one parameter): the desired spherically-averaged power spectrum of the output. Given as a function of k * random_seed (int): the seed for the random number generation Returns: The Gaussian random field as a numpy array ''' #Verify input assert len(dims) == 2 or len(dims) == 3 #Generate FT map if random_seed != None: np.random.seed(random_seed) map_ft_real = np.random.normal(loc=0., scale=1., size=dims) map_ft_imag = np.random.normal(loc=0., scale=1., size=dims) map_ft = map_ft_real + 1j * map_ft_imag #Get k modes box_dims = _get_dims(box_dims, map_ft_real.shape) assert len(box_dims) == len(dims) k_comp, k = _get_k(map_ft_real, box_dims) #k[np.abs(k) < 1.e-6] = 1.e-6 #Scale factor boxvol = np.product(map(float, box_dims)) pixelsize = boxvol / (np.product(map_ft_real.shape)) scale_factor = pixelsize**2 / boxvol #Scale to power spectrum map_ft *= np.sqrt(power_spectrum(k) / scale_factor) #Inverse FT map_ift = fftpack.ifftn(fftpack.fftshift(map_ft)) #Return real part map_real = np.real(map_ift) return map_real
def make_gaussian_random_field(dims, box_dims, power_spectrum, random_seed=None): ''' Generate a Gaussian random field with the specified power spectrum. Parameters: * dims (tuple): the dimensions of the field in number of cells. Can be 2D or 3D. * box_dims (float or tuple): the dimensions of the field in cMpc. * power_spectrum (callable, one parameter): the desired spherically-averaged power spectrum of the output. Given as a function of k * random_seed (int): the seed for the random number generation Returns: The Gaussian random field as a numpy array ''' #Verify input assert len(dims) == 2 or len(dims) == 3 #Generate FT map if random_seed != None: np.random.seed(random_seed) map_ft_real = np.random.normal(loc=0., scale=1., size=dims) map_ft_imag = np.random.normal(loc=0., scale=1., size=dims) map_ft = map_ft_real + 1j*map_ft_imag #Get k modes box_dims = _get_dims(box_dims, map_ft_real.shape) assert len(box_dims) == len(dims) k_comp, k = _get_k(map_ft_real, box_dims) #k[np.abs(k) < 1.e-6] = 1.e-6 #Scale factor boxvol = np.product(map(float,box_dims)) pixelsize = boxvol/(np.product(map_ft_real.shape)) scale_factor = pixelsize**2/boxvol #Scale to power spectrum map_ft *= np.sqrt(power_spectrum(k)/scale_factor) #Inverse FT map_ift = fftpack.ifftn(fftpack.fftshift(map_ft)) #Return real part map_real = np.real(map_ift) return map_real
def power_spectrum_multipoles(input_array, kbins = 10, box_dims = None,\ los_axis = 0, output=['P0', 'P2', 'P4', 'nmodes'], exclude_zero_modes=False): ''' Calculate the power spectrum of an array and expand it in the first three Legendre polynomials. Parameters: * input_array (numpy array): the array to calculate the power spectrum of. Can be of any dimensions. * kbins = 10 (integer or array-like): The number of bins, or a list containing the bin edges. If an integer is given, the bins are logarithmically spaced. * box_dims = None (float or array-like): the dimensions of the box. If this is None, the current box volume is used along all dimensions. If it is a float, this is taken as the box length along all dimensions. If it is an array-like, the elements are taken as the box length along each axis. * los_axis = 0 (integer): the line-of-sight axis * output = ['P0', 'P2', 'P4', 'nmodes'] (list): the multipole moments to include in the output. For example, to get only the P2 moment, pass in ['P2']. Can also contain 'nmodes' to return the number of Fourier modes per bin * exlude_zero_modes = True (bool): if true, modes with any components of k equal to zero will be excluded. Returns: A tuple with (multipoles, k) where multipoles is a dictionary containing the multipoles (the keys are the values passed to the output parameter) and k contains the midpoints of the k bins. All arrays have the same dimension ''' assert(los_axis >= 0 and los_axis <= len(input_array.shape)) #First calculate the power spectrum box_dims = _get_dims(box_dims, input_array.shape) ps = power_spectrum_nd(input_array, box_dims) #Get k values and bins k_comp, k = _get_k(input_array, box_dims) kbins = _get_kbins(kbins, box_dims, k) dk = (kbins[1:]-kbins[:-1])/2. mu = _get_mu(k_comp, k, los_axis) #Exclude k_perp = 0 modes if exclude_zero_modes: good_idx = _get_nonzero_idx(ps.shape, los_axis) else: good_idx = np.ones_like(ps) #Legendre polynomials if 'P0' in output: P0 = np.ones_like(mu) if 'P2' in output: P2 = 0.5*(3.*mu**2 - 1.) if 'P4' in output: P4 = 4.375*(mu**2-0.115587)*(mu**2-0.741556) #Bin data n_kbins = len(kbins)-1 multipoles = {} if 'P0' in output: multipoles['P0'] = np.zeros(n_kbins) if 'P2' in output: multipoles['P2'] = np.zeros(n_kbins) if 'P4' in output: multipoles['P4'] = np.zeros(n_kbins) nmodes = np.zeros(n_kbins) for i in range(n_kbins): kmin = kbins[i] kmax = kbins[i+1] idx = get_eval()('(k >= kmin) & (k < kmax)') idx *= good_idx nmodes[i] = len(np.nonzero(idx)) if 'P0' in output: multipoles['P0'][i] = np.sum(ps[idx]*P0[idx])/np.sum(P0[idx]**2) if 'P2' in output: multipoles['P2'][i] = np.sum(ps[idx]*P2[idx])/np.sum(P2[idx]**2) if 'P4' in output: multipoles['P4'][i] = np.sum(ps[idx]*P4[idx])/np.sum(P4[idx]**2) multipoles['nmodes'] = nmodes return multipoles, kbins[:-1]+dk
def power_spectrum_multipoles(input_array, kbins = 10, box_dims = None,\ los_axis = 0): ''' Calculate the power spectrum of an array and expand it in the first three Legendre polynomials. Parameters: * input_array (numpy array): the array to calculate the power spectrum of. Can be of any dimensions. * kbins = 10 (integer or array-like): The number of bins, or a list containing the bin edges. If an integer is given, the bins are logarithmically spaced. * box_dims = None (float or array-like): the dimensions of the box. If this is None, the current box volume is used along all dimensions. If it is a float, this is taken as the box length along all dimensions. If it is an array-like, the elements are taken as the box length along each axis. * los_axis = 0 (integer): the line-of-sight axis Returns: A tuple with (P0, P2, P4, k) where P0, P2 and P4 are the multipole moments as a function of k and k contains the midpoints of the k bins. All four arrays have the same length ''' assert(los_axis >= 0 and los_axis <= len(input_array.shape)) #First calculate the power spectrum box_dims = _get_dims(box_dims, input_array.shape) ps = power_spectrum_nd(input_array, box_dims) #Get k values and bins k_comp, k = _get_k(input_array, box_dims) kbins = _get_kbins(kbins, box_dims, k) dk = (kbins[1:]-kbins[:-1])/2. mu = _get_mu(k_comp, k, los_axis) #Legendre polynomials P0 = np.ones_like(mu) P2 = 0.5*(3.*mu**2 - 1.) P4 = 4.375*(mu**2-0.115587)*(mu**2-0.741556) #Bin data n_kbins = len(kbins)-1 outdata_P0 = np.zeros(n_kbins) outdata_P2 = np.zeros_like(outdata_P0) outdata_P4 = np.zeros_like(outdata_P0) for i in range(n_kbins): idx = (k > kbins[i]) * (k <= kbins[i+1]) outdata_P0[i] = np.sum(ps[idx]*P0[idx])/np.sum(P0[idx]**2) outdata_P2[i] = np.sum(ps[idx]*P2[idx])/np.sum(P2[idx]**2) outdata_P4[i] = np.sum(ps[idx]*P4[idx])/np.sum(P4[idx]**2) return outdata_P0, outdata_P2, outdata_P4, kbins[:-1]+dk