def redshifts_at_equal_comoving_distance(z_low, z_high, box_grid_n=256, \ box_length_mpc=None): ''' Make a frequency axis vector with equal spacing in co-moving LOS coordinates. The comoving distance between each frequency will be the same as the cell size of the box. Parameters: * z_low (float): The lower redshift * z_high (float): The upper redhisft * box_grid_n = 256 (int): the number of slices in an input box * box_length_mpc (float): the size of the box in cMpc. If None, set to conv.LB Returns: numpy array containing the redshifts ''' if box_length_mpc == None: box_length_mpc = conv.LB assert (z_high > z_low) z = z_low z_array = [] while z < z_high: z_array.append(z) nu = const.nu0 / (1.0 + z) dnu = const.nu0 * const.Hz(z) * box_length_mpc / ( 1.0 + z)**2 / const.c / float(box_grid_n) z = const.nu0 / (nu - dnu) - 1.0 return np.array(z_array)
def get_distorted_dt(dT, kms, redsh, los_axis=0, velocity_axis=0, num_particles=10, periodic=True): ''' Apply peculiar velocity distortions to a differential temperature box, using the Mesh-Particle-Mesh method, as described in http://arxiv.org/abs/1303.5627 Parameters: * dT (numpy array): the differential temperature box * kms (numpy array): velocity in km/s, array of dimensions (3,mx,my,mz) where (mx,my,mz) is dimensions of dT * redsh (float): the redshift * los_axis = 0 (int): the line-of-sight axis of the output volume (must be 0, 1 or 2) * velocity_axis = 0 (int): the index that indicates los velocity * num_particles = 10 (int): the number of particles to use per cell A higher number gives better accuracy, but worse performance. * periodic = True (bool): whether or not to apply periodic boundary conditions along the line-of-sight. If you are making a lightcone volume, this should be False. Returns: The redshift space box as a numpy array with same dimensions as dT. Example: Read a density file, a velocity file and an xfrac file, calculate the brightness temperature, and convert it to redshift space. >>> vfile = c2t.VelocityFile('/path/to/data/8.515v_all.dat') >>> dfile = c2t.DensityFile('/path/to/data/8.515n_all.dat') >>> xfile = c2t.XfracFile('/path/to/data/xfrac3d_8.515.bin') >>> dT = c2t.calc_dt(xfile, dfile) >>> kms = vfile.get_kms_from_density(dfile) >>> dT_zspace = get_distorted_dt(dT, kms, dfile.z, los_axis = 0) .. note:: At the moment, it is a requirement that dimensions perpendicular to the line-of-sight are equal. For example, if the box dimensions are (mx, my, mz) and the line-of-sight is along the z axis, then mx has to be equal to my. .. note:: If dT is a lightcone volume, los_axis is not necessarily the same as velocity_axis. The lightcone volume methods in c2raytools all give output volumes that have the line-of-sight as the last index, regardless of the line-of-sight axis. For these volumes, you should always use los_axis=2 and set velocity_axis equal to whatever was used when producing the real-space lightcones. ''' #Volume dimensions mx, my, mz = dT.shape assert (mx == my or my == mz or mx == mz) #TODO: this should not be a requirement grid_depth = dT.shape[los_axis] grid_width = dT.shape[(los_axis + 1) % 3] box_depth = grid_depth * (conv.LB / float(grid_width)) #Take care of different LOS axes assert (los_axis == 0 or los_axis == 1 or los_axis == 2) if los_axis == 0: get_skewer = lambda data, i, j: data[:, i, j] elif los_axis == 1: get_skewer = lambda data, i, j: data[i, :, j] else: get_skewer = lambda data, i, j: data[i, j, :] #Input redshift can be a float or an array, but we need an array redsh = np.atleast_1d(redsh) print_msg('Making velocity-distorted box...') print_msg('The (min) redshift is %.3f' % redsh[0]) print_msg('The box size is %.3f cMpc' % conv.LB) #Figure out the apparent position shift vpar = kms[velocity_axis, :, :, :] z_obs = (1 + redsh) / (1. - vpar / const.c) - 1. dr = (1. + z_obs) * vpar / const.Hz(z_obs) #Make the distorted box distbox = np.zeros_like(dT) particle_dT = np.zeros(grid_depth * num_particles) last_percent = 0 for i in range(grid_width): percent_done = int(float(i) / float(grid_width) * 100) if percent_done % 10 == 0 and percent_done != last_percent: print_msg('%d %%' % percent_done) last_percent = percent_done for j in range(grid_width): #Take a 1D skewer from the dT box dT_skewer = get_skewer(dT, i, j) #Create particles along the skewer and assign dT to the particles particle_pos = np.linspace(0, box_depth, grid_depth * num_particles) for n in range(num_particles): particle_dT[n::num_particles] = dT_skewer / float( num_particles) #Calculate LOS velocity for each particle dr_skewer_pad = get_skewer(dr, i, j) np.insert(dr_skewer_pad, 0, dr_skewer_pad[-1]) dr_skewer = get_interpolated_array(dr_skewer_pad, len(particle_pos), 'linear') #Apply velocity shift particle_pos += dr_skewer #Periodic boundary conditions if periodic: particle_pos[np.where(particle_pos < 0)] += box_depth particle_pos[np.where(particle_pos > box_depth)] -= box_depth #Regrid particles to original resolution dist_skewer = np.histogram(particle_pos, \ bins=np.linspace(0, box_depth, grid_depth+1), \ weights=particle_dT)[0] if los_axis == 0: distbox[:, i, j] = dist_skewer elif los_axis == 1: distbox[i, :, j] = dist_skewer else: distbox[i, j, :] = dist_skewer print_msg('Old dT (mean,var): %3f, %.3f' % (dT.astype('float64').mean(), dT.var())) print_msg('New dT (mean,var): %.3f, %.3f' % (distbox.mean(), distbox.var())) return distbox
def get_distorted_dt(dT, kms, redsh, los_axis=0, num_particles=10): ''' Apply peculiar velocity distortions to a differential temperature box, using the Mesh-Particle-Mesh method, as described in http://arxiv.org/abs/1303.5627 Parameters: * dT (numpy array): the differential temperature box * kms (numpy array): velocity in km/s, array of dimensions (3,mx,my,mz) where (mx,my,mz) is dimensions of dT * redsh (float): the redshift * los_axis = 0 (int): the line-of-sight axis (must be 0, 1 or 2) * num_particles = 10 (int): the number of particles to use per cell A higher number gives better accuracy, but worse performance. Returns: The redshift space box as a numpy array with same dimensions as dT. Example: Read a density file, a velocity file and an xfrac file, calculate the brightness temperature, and convert it to redshift space. >>> vfile = c2t.VelocityFile('/path/to/data/8.515v_all.dat') >>> dfile = c2t.DensityFile('/path/to/data/8.515n_all.dat') >>> xfile = c2t.XfracFile('/path/to/data/xfrac3d_8.515.bin') >>> dT = c2t.calc_dt(xfile, dfile) >>> kms = vfile.get_kms_from_density(dfile) >>> dT_zspace = get_distorted_dt(dT, dfile, dfile.z, los_axis = 0) ''' #Take care of different LOS axes assert (los_axis == 0 or los_axis == 1 or los_axis == 2) if los_axis == 0: get_slice = lambda data, i, j: data[:, i, j] elif los_axis == 1: get_slice = lambda data, i, j: data[i, :, j] else: get_slice = lambda data, i, j: data[i, j, :] #Dimensions mx, my, mz = dT.shape print_msg('Making velocity-distorted box...') print_msg('The redshift is %.3f' % redsh) print_msg('The box size is %.3f cMpc' % conv.LB) #Figure out the apparent position shift vpar = kms[los_axis, :, :, :] z_obs = (1 + redsh) / (1. - vpar / const.c) - 1. dr = (1. + z_obs) * kms[los_axis, :, :, :] / const.Hz(z_obs) #Make the distorted box distbox = np.zeros((mx, my, mz)) part_dT = np.zeros(mx * num_particles) last_percent = 0 for i in range(my): percent_done = int(float(i) / float(my) * 100) if percent_done % 10 == 0 and percent_done != last_percent: print_msg('%d %%' % percent_done) last_percent = percent_done for j in range(mz): #Take a 1D slice from the dT box dT_slice = get_slice(dT, i, j) #Divide slice into particles partpos = np.linspace(0, conv.LB, mx * num_particles) #Positions before dist. for n in range(num_particles): #Assign dT to particles part_dT[n::num_particles] = dT_slice / float(num_particles) #Calculate and apply redshift distortions cell_length = conv.LB / float(mx) dr_slice_pad = get_slice(dr, i, j) np.insert(dr_slice_pad, 0, dr_slice_pad[-1]) dr_slice = get_interpolated_array(dr_slice_pad, len(partpos), 'linear') dr_slice = np.roll(dr_slice, num_particles / 2) partpos += dr_slice #Boundary conditions partpos[np.where(partpos < 0)] += conv.LB partpos[np.where(partpos > conv.LB)] -= conv.LB #Regrid particles dist_slice = np.histogram(partpos, bins=np.linspace(0, conv.LB, mx + 1), weights=part_dT)[0] if los_axis == 0: distbox[:, i, j] = dist_slice elif los_axis == 1: distbox[i, :, j] = dist_slice else: distbox[i, j, :] = dist_slice print_msg('Old dT (mean,var): %3f, %.3f' % (dT.mean(), dT.var())) print_msg('New (mean,var): %.3f, %.3f' % (distbox.mean(), distbox.var())) return distbox