def make_lightcone(filenames, z_low = None, z_high = None, file_redshifts = None, \ cbin_bits = 32, cbin_order = 'c', los_axis = 0, raw_density = False, interpolation='linear'): ''' Make a lightcone from xfrac, density or dT data. Replaces freq_box. Parameters: * filenames (string or array): The coeval cubes. Can be either any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * cbin_bits (int): If the data files are in cbin format, you may specify the number of bits. * cbin_order (char): If the data files are in cbin format, you may specify the order of the data. * los_axis (int): the axis to use as line-of-sight for the coeval cubes * raw_density (bool): if this is true, and the data is a density file, the raw (simulation units) density will be returned instead of the density in cgs units * interpolation (string): can be 'linear', 'step', 'sigmoid' or 'step_cell'. Determines how slices in between output redshifts are interpolated. Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight .. note:: If z_low is given, that redshift will be the lowest one included, even if there is no coeval box at exactly that redshift. This can give results that are subtly different from results calculated with the old freq_box routine. ''' if not interpolation in ['linear', 'step', 'sigmoid', 'step_cell']: raise ValueError('Unknown interpolation type: %s' % interpolation) #Figure out output redshifts, file names and size of output filenames = _get_filenames(filenames) file_redshifts = _get_file_redshifts(file_redshifts, filenames) assert len(file_redshifts) == len(filenames) mesh_size = get_mesh_size(filenames[0]) output_z = _get_output_z(file_redshifts, z_low, z_high, mesh_size[0]) #Make the output 32-bit to save memory lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z)), dtype='float32') comoving_pos_idx = 0 z_bracket_low = None; z_bracket_high = None data_low = None; data_high = None #Make the lightcone, one slice at a time print_msg('Making lightcone between %f < z < %f' % (output_z.min(), output_z.max())) for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts <= z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() #Do we need a new file for the low z? if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) if data_high == None: data_low, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order, raw_density) else: #No need to read the file again data_low = data_high #Do we need a new file for the high z? if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) data_high, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order, raw_density) #Make the slice by interpolating, then move to next index data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis, interpolation) lightcone[:,:,comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z
def freq_box(xfrac_dir, dens_dir, z_low, z_high): ''' Make frequency (lightcone) boxes of density, ionized fractions, and brightness temperature. The function reads xfrac and density files from the specified directories and combines them into a lighcone box going from z_low to z_high. This routine is more or less a direct translation of Garrelt's IDL routine. Parameters: * xfrac_dir (string): directory containing xfrac files * dens_dir (string): directory containing density files * z_low (float): lowest redshift to include * z_high (float): highest redshift to include. Returns: Tuple with (density box, xfrac box, dt box, redshifts), where density box, xfrac box and dt box are numpy arrays containing the lightcone quantities. redshifts is an array containing the redshift for each slice. .. note:: Since this function relies on filenames to get redshifts, all the data files must follow the common naming convenstions. Ionization files must be named xfrac3d_z.bin and densityfiles zn_all.dat .. note:: The make_lightcone method is meant to replace this method. It is more general and easier to use. Example: Make a lightcone cube ranging from z = 7 to z = 8: >>> xfrac_dir = '/path/to/data/xfracs/' >>> dens_dir = '/path/to/data/density/' >>> xcube, dcube, dtcube, z = c2t.freq_box(xfrac_dir, density_dir, z_low=7.0, z_high=8.) ''' #Get the list of redshifts where we have simulation output files dens_redshifts = get_dens_redshifts(dens_dir, z_low) mesh_size = get_mesh_size( os.path.join(dens_dir, '%.3fn_all.dat' % dens_redshifts[0])) #Get the list of redhifts and frequencies that we want for the observational box output_z = redshifts_at_equal_comoving_distance(z_low, z_high, box_grid_n=mesh_size[0]) output_z = output_z[output_z > dens_redshifts[0]] output_z = output_z[output_z < dens_redshifts[-1]] if len(output_z) < 1: raise Exception('No valid redshifts in range!') #Keep track of output simulation files to use xfrac_file_low = XfracFile() xfrac_file_high = XfracFile() dens_file_low = DensityFile() dens_file_high = DensityFile() z_bracket_low = None z_bracket_high = None #The current position in comoving coordinates comoving_pos_idx = 0 #Build the cube xfrac_lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z))) dens_lightcone = np.zeros_like(xfrac_lightcone) dt_lightcone = np.zeros_like(xfrac_lightcone) for z in output_z: #Find the output files that bracket the redshift z_bracket_low_new = dens_redshifts[dens_redshifts <= z][0] z_bracket_high_new = dens_redshifts[dens_redshifts >= z][0] if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new xfrac_file_low = XfracFile( os.path.join(xfrac_dir, 'xfrac3d_%.3f.bin' % z_bracket_low)) dens_file_low = DensityFile( os.path.join(dens_dir, '%.3fn_all.dat' % z_bracket_low)) dt_cube_low = calc_dt(xfrac_file_low, dens_file_low) if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new xfrac_file_high = XfracFile( os.path.join(xfrac_dir, 'xfrac3d_%.3f.bin' % z_bracket_high)) dens_file_high = DensityFile( os.path.join(dens_dir, '%.3fn_all.dat' % z_bracket_high)) dt_cube_high = calc_dt(xfrac_file_high, dens_file_high) slice_ind = comoving_pos_idx % xfrac_file_high.mesh_x #Ionized fraction xi_interp = _get_interp_slice(xfrac_file_high.xi, xfrac_file_low.xi, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx) xfrac_lightcone[:, :, comoving_pos_idx] = xi_interp #Density rho_interp = _get_interp_slice(dens_file_high.cgs_density, dens_file_low.cgs_density, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx) dens_lightcone[:, :, comoving_pos_idx] = rho_interp #Brightness temperature dt_interp = _get_interp_slice(dt_cube_high, dt_cube_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx) dt_lightcone[:, :, comoving_pos_idx] = dt_interp print_msg('Slice %d of %d' % (comoving_pos_idx, len(output_z))) comoving_pos_idx += 1 return xfrac_lightcone, dens_lightcone, dt_lightcone, output_z
def make_velocity_lightcone(vel_filenames, dens_filenames, z_low = None, \ z_high = None, file_redshifts = None, los_axis = 0): ''' Make a lightcone from velocity data. Since velocity files contain momentum rather than actual velocity, you must specify filenames for both velocity and density. Parameters: * vel_filenames (string or array): The coeval velocity cubes. Can be any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * dens_filenames (string or array): The coeval density cubes. Same format as vel_filenames. * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * los_axis (int): the axis to use as line-of-sight for the coeval cubes Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight ''' dens_filenames = _get_filenames(dens_filenames) file_redshifts = _get_file_redshifts(file_redshifts, dens_filenames) vel_filenames = _get_filenames(vel_filenames) assert(len(file_redshifts) == len(vel_filenames)) assert(len(vel_filenames) == len(dens_filenames)) mesh_size = get_mesh_size(dens_filenames[0]) output_z = _get_output_z(file_redshifts, z_low, z_high, mesh_size[0]) lightcone = np.zeros((3, mesh_size[0], mesh_size[1], len(output_z)), dtype='float32') comoving_pos_idx = 0 z_bracket_low = None; z_bracket_high = None for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts <= z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) dfile = DensityFile(dens_filenames[file_idx]) vel_file = VelocityFile(vel_filenames[file_idx]) data_low = vel_file.get_kms_from_density(dfile) del dfile del vel_file if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) dfile = DensityFile(dens_filenames[file_idx]) vel_file = VelocityFile(vel_filenames[file_idx]) data_high = vel_file.get_kms_from_density(dfile) del dfile del vel_file data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis) lightcone[:,:,:,comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z
def make_lightcone(filenames, z_low = None, z_high = None, file_redshifts = None, \ cbin_bits = 32, cbin_order = 'c', los_axis = 0, raw_density = False, interpolation='linear'): ''' Make a lightcone from xfrac, density or dT data. Replaces freq_box. Parameters: * filenames (string or array): The coeval cubes. Can be either any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * cbin_bits (int): If the data files are in cbin format, you may specify the number of bits. * cbin_order (char): If the data files are in cbin format, you may specify the order of the data. * los_axis (int): the axis to use as line-of-sight for the coeval cubes * raw_density (bool): if this is true, and the data is a density file, the raw (simulation units) density will be returned instead of the density in cgs units * interpolation (string): can be 'linear', 'step', 'sigmoid' or 'step_cell'. Determines how slices in between output redshifts are interpolated. Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight .. note:: If z_low is given, that redshift will be the lowest one included, even if there is no coeval box at exactly that redshift. This can give results that are subtly different from results calculated with the old freq_box routine. ''' if not interpolation in ['linear', 'step', 'sigmoid', 'step_cell']: raise ValueError('Unknown interpolation type: %s' % interpolation) #Figure out output redshifts, file names and size of output filenames = _get_filenames(filenames) file_redshifts = _get_file_redshifts(file_redshifts, filenames) assert len(file_redshifts) == len(filenames) mesh_size = get_mesh_size(filenames[0]) output_z = _get_output_z(file_redshifts, z_low, z_high, mesh_size[0]) #Make the output 32-bit to save memory lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z)), dtype='float32') comoving_pos_idx = 0 z_bracket_low = None z_bracket_high = None data_low = None data_high = None #Make the lightcone, one slice at a time print_msg('Making lightcone between %f < z < %f' % (output_z.min(), output_z.max())) for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts <= z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() #Do we need a new file for the low z? if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) if data_high == None: data_low, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order, raw_density) else: #No need to read the file again data_low = data_high #Do we need a new file for the high z? if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) data_high, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order, raw_density) #Make the slice by interpolating, then move to next index data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis, interpolation) lightcone[:, :, comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z
def make_velocity_lightcone(vel_filenames, dens_filenames, z_low = None, \ z_high = None, file_redshifts = None, los_axis = 0): ''' Make a lightcone from velocity data. Since velocity files contain momentum rather than actual velocity, you must specify filenames for both velocity and density. Parameters: * vel_filenames (string or array): The coeval velocity cubes. Can be any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * dens_filenames (string or array): The coeval density cubes. Same format as vel_filenames. * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * los_axis (int): the axis to use as line-of-sight for the coeval cubes Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight ''' dens_filenames = _get_filenames(dens_filenames) file_redshifts = _get_file_redshifts(file_redshifts, dens_filenames) vel_filenames = _get_filenames(vel_filenames) assert (len(file_redshifts) == len(vel_filenames)) assert (len(vel_filenames) == len(dens_filenames)) mesh_size = get_mesh_size(dens_filenames[0]) output_z = _get_output_z(file_redshifts, z_low, z_high, mesh_size[0]) lightcone = np.zeros((3, mesh_size[0], mesh_size[1], len(output_z)), dtype='float32') comoving_pos_idx = 0 z_bracket_low = None z_bracket_high = None for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts <= z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) dfile = DensityFile(dens_filenames[file_idx]) vel_file = VelocityFile(vel_filenames[file_idx]) data_low = vel_file.get_kms_from_density(dfile) del dfile del vel_file if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) dfile = DensityFile(dens_filenames[file_idx]) vel_file = VelocityFile(vel_filenames[file_idx]) data_high = vel_file.get_kms_from_density(dfile) del dfile del vel_file data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis) lightcone[:, :, :, comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z
def make_lightcone(filenames, z_low = None, z_high = None, file_redshifts = None, \ cbin_bits = 32, cbin_order = 'c', los_axis = 0): ''' Make a lightcone from xfrac, density or dT data. Replaces freq_box. Parameters: * filenames (string or array): The coeval cubes. Can be either any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * cbin_bits (int): If the data files are in cbin format, you may specify the number of bits. * cbin_order (char): If the data files are in cbin format, you may specify the order of the data. * los_axis (int): the axis to use as line-of-sight for the coeval cubes Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight .. note:: If z_low is given, that redshift will be the lowest one included, even if there is no coeval box at exactly that redshift. This can give results that are subtly different from results calculated with the old freq_box routine. ''' filenames = _get_filenames(filenames) file_redshifts = _get_file_redshifts(file_redshifts, filenames) assert(len(file_redshifts) == len(filenames)) mesh_size = get_mesh_size(filenames[0]) if z_low == None: z_low = file_redshifts.min() if z_high == None: z_high = file_redshifts.max() output_z = redshifts_at_equal_comoving_distance(z_low, z_high, box_grid_n=mesh_size[0]) if min(output_z) < min(file_redshifts) or max(output_z) > max(file_redshifts): print 'Warning! You have specified a redshift range of %.3f < z < %.3f' % (min(output_z), max(output_z)) print 'but you only have files for the range %.3f < z < %.3f.' % (min(file_redshifts), max(file_redshifts)) print 'The redshift range will be truncated.' output_z = output_z[output_z >= min(file_redshifts)] output_z = output_z[output_z <= max(file_redshifts)] if len(output_z) < 1: raise Exception('No valid redshifts in range!') lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z))) comoving_pos_idx = 0 z_bracket_low = None; z_bracket_high = None for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts < z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) data_low, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order) if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) data_high, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order) data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis) lightcone[:,:,comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z
def freq_box(xfrac_dir, dens_dir, z_low, z_high): """ Make frequency (lightcone) boxes of density, ionized fractions, and brightness temperature. The function reads xfrac and density files from the specified directories and combines them into a lighcone box going from z_low to z_high. This routine is more or less a direct translation of Garrelt's IDL routine. Parameters: * xfrac_dir (string): directory containing xfrac files * dens_dir (string): directory containing density files * z_low (float): lowest redshift to include * z_high (float): highest redshift to include. Returns: Tuple with (density box, xfrac box, dt box, redshifts), where density box, xfrac box and dt box are numpy arrays containing the lightcone quantities. redshifts is an array containing the redshift for each slice. .. note:: Since this function relies on filenames to get redshifts, all the data files must follow the common naming convenstions. Ionization files must be named xfrac3d_z.bin and densityfiles zn_all.dat .. note:: The make_lightcone method is meant to replace this method. It is more general and easier to use. Example: Make a lightcone cube ranging from z = 7 to z = 8: >>> xfrac_dir = '/path/to/data/xfracs/' >>> dens_dir = '/path/to/data/density/' >>> xcube, dcube, dtcube, z = c2t.freq_box(xfrac_dir, density_dir, z_low=7.0, z_high=8.) """ # Get the list of redshifts where we have simulation output files dens_redshifts = get_dens_redshifts(dens_dir, z_low) mesh_size = get_mesh_size(os.path.join(dens_dir, "%.3fn_all.dat" % dens_redshifts[0])) # Get the list of redhifts and frequencies that we want for the observational box output_z = redshifts_at_equal_comoving_distance(z_low, z_high, box_grid_n=mesh_size[0]) output_z = output_z[output_z > dens_redshifts[0]] output_z = output_z[output_z < dens_redshifts[-1]] if len(output_z) < 1: raise Exception("No valid redshifts in range!") # Keep track of output simulation files to use xfrac_file_low = XfracFile() xfrac_file_high = XfracFile() dens_file_low = DensityFile() dens_file_high = DensityFile() z_bracket_low = None z_bracket_high = None # The current position in comoving coordinates comoving_pos_idx = 0 # Build the cube xfrac_lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z))) dens_lightcone = np.zeros_like(xfrac_lightcone) dt_lightcone = np.zeros_like(xfrac_lightcone) for z in output_z: # Find the output files that bracket the redshift z_bracket_low_new = dens_redshifts[dens_redshifts <= z][0] z_bracket_high_new = dens_redshifts[dens_redshifts >= z][0] if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new xfrac_file_low = XfracFile(os.path.join(xfrac_dir, "xfrac3d_%.3f.bin" % z_bracket_low)) dens_file_low = DensityFile(os.path.join(dens_dir, "%.3fn_all.dat" % z_bracket_low)) dt_cube_low = calc_dt(xfrac_file_low, dens_file_low) if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new xfrac_file_high = XfracFile(os.path.join(xfrac_dir, "xfrac3d_%.3f.bin" % z_bracket_high)) dens_file_high = DensityFile(os.path.join(dens_dir, "%.3fn_all.dat" % z_bracket_high)) dt_cube_high = calc_dt(xfrac_file_high, dens_file_high) slice_ind = comoving_pos_idx % xfrac_file_high.mesh_x # Ionized fraction xi_interp = _get_interp_slice( xfrac_file_high.xi, xfrac_file_low.xi, z_bracket_high, z_bracket_low, z, comoving_pos_idx ) xfrac_lightcone[:, :, comoving_pos_idx] = xi_interp # Density rho_interp = _get_interp_slice( dens_file_high.cgs_density, dens_file_low.cgs_density, z_bracket_high, z_bracket_low, z, comoving_pos_idx ) dens_lightcone[:, :, comoving_pos_idx] = rho_interp # Brightness temperature dt_interp = _get_interp_slice(dt_cube_high, dt_cube_low, z_bracket_high, z_bracket_low, z, comoving_pos_idx) dt_lightcone[:, :, comoving_pos_idx] = dt_interp print_msg("Slice %d of %d" % (comoving_pos_idx, len(output_z))) comoving_pos_idx += 1 return xfrac_lightcone, dens_lightcone, dt_lightcone, output_z
def make_lightcone(filenames, z_low = None, z_high = None, file_redshifts = None, \ cbin_bits = 32, cbin_order = 'c', los_axis = 0): ''' Make a lightcone from xfrac, density or dT data. Replaces freq_box. Parameters: * filenames (string or array): The coeval cubes. Can be either any of the following: - An array with the file names - A text file containing the file names - The directory containing the files (must only contain one type of files) * z_low (float): the lowest redshift. If not given, the redshift of the lowest-z coeval cube is used. * z_high (float): the highest redshift. If not given, the redshift of the highest-z coeval cube is used. * file_redshifts (string or array): The redshifts of the coeval cubes. Can be any of the following types: - None: determine the redshifts from file names - array: array containing the redshift of each coeval cube - filename: the name of a data file to read the redshifts from * cbin_bits (int): If the data files are in cbin format, you may specify the number of bits. * cbin_order (char): If the data files are in cbin format, you may specify the order of the data. * los_axis (int): the axis to use as line-of-sight for the coeval cubes Returns: (lightcone, z) tuple lightcone is the lightcone volume where the first two axes have the same size as the input cubes z is an array containing the redshifts along the line-of-sight .. note:: If z_low is given, that redshift will be the lowest one included, even if there is no coeval box at exactly that redshift. This can give results that are subtly different from results calculated with the old freq_box routine. ''' filenames = _get_filenames(filenames) file_redshifts = _get_file_redshifts(file_redshifts, filenames) assert (len(file_redshifts) == len(filenames)) mesh_size = get_mesh_size(filenames[0]) if z_low == None: z_low = file_redshifts.min() if z_high == None: z_high = file_redshifts.max() output_z = redshifts_at_equal_comoving_distance(z_low, z_high, box_grid_n=mesh_size[0]) if min(output_z) < min(file_redshifts) or max(output_z) > max( file_redshifts): print 'Warning! You have specified a redshift range of %.3f < z < %.3f' % ( min(output_z), max(output_z)) print 'but you only have files for the range %.3f < z < %.3f.' % ( min(file_redshifts), max(file_redshifts)) print 'The redshift range will be truncated.' output_z = output_z[output_z >= min(file_redshifts)] output_z = output_z[output_z <= max(file_redshifts)] if len(output_z) < 1: raise Exception('No valid redshifts in range!') lightcone = np.zeros((mesh_size[0], mesh_size[1], len(output_z))) comoving_pos_idx = 0 z_bracket_low = None z_bracket_high = None for z in output_z: z_bracket_low_new = file_redshifts[file_redshifts < z].max() z_bracket_high_new = file_redshifts[file_redshifts > z].min() if z_bracket_low_new != z_bracket_low: z_bracket_low = z_bracket_low_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_low)) data_low, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order) if z_bracket_high_new != z_bracket_high: z_bracket_high = z_bracket_high_new file_idx = np.argmin(np.abs(file_redshifts - z_bracket_high)) data_high, datatype = get_data_and_type(filenames[file_idx], cbin_bits, cbin_order) data_interp = _get_interp_slice(data_high, data_low, z_bracket_high, \ z_bracket_low, z, comoving_pos_idx, los_axis) lightcone[:, :, comoving_pos_idx] = data_interp comoving_pos_idx += 1 return lightcone, output_z