def __init__(self, ds, normal, fields, center='c', width=(1.0, 'unitary'), weight_field=None, image_res=512, depth_res=256, north_vector=None, depth=(1.0,"unitary"), no_ghost=False, method='integrate'): fields = ensure_list(fields) center, dcenter = ds.coordinates.sanitize_center(center, 4) buf = {} width = ds.coordinates.sanitize_width(normal, width, depth) wd = tuple(el.in_units('code_length').v for el in width) if not iterable(image_res): image_res = (image_res, image_res) res = (image_res[0], image_res[1], depth_res) for field in fields: buf[field] = off_axis_projection(ds, center, normal, wd, res, field, no_ghost=no_ghost, north_vector=north_vector, method=method, weight=weight_field).swapaxes(0, 1) center = ds.arr([0.0] * 2, 'code_length') w, not_an_frb = construct_image(ds, normal, buf, center, width=width, image_res=image_res) super(FITSOffAxisProjection, self).__init__(buf, fields=fields, wcs=w)
def __init__(self, ds, normal, fields, center='c', width=(1.0, 'unitary'), weight_field=None, image_res=512, depth_res=256, north_vector=None, depth=(1.0, "unitary"), no_ghost=False, method='integrate'): fields = ensure_list(fields) center, dcenter = ds.coordinates.sanitize_center(center, 4) buf = {} width = ds.coordinates.sanitize_width(normal, width, depth) wd = tuple(el.in_units('code_length').v for el in width) if not iterable(image_res): image_res = (image_res, image_res) res = (image_res[0], image_res[1], depth_res) for field in fields: buf[field] = off_axis_projection(ds, center, normal, wd, res, field, no_ghost=no_ghost, north_vector=north_vector, method=method, weight=weight_field).swapaxes( 0, 1) center = ds.arr([0.0] * 2, 'code_length') w, not_an_frb = construct_image(ds, normal, buf, center, width=width, image_res=image_res) super(FITSOffAxisProjection, self).__init__(buf, fields=fields, wcs=w)
def __init__(self, ds, normal, field, velocity_bounds, center="c", width=(1.0, "unitary"), dims=100, thermal_broad=False, atomic_weight=56., depth=(1.0, "unitary"), depth_res=256, method="integrate", weight_field=None, no_shifting=False, north_vector=None, no_ghost=True): r""" Initialize a PPVCube object. Parameters ---------- ds : dataset The dataset. normal : array_like or string The normal vector along with to make the projections. If an array, it will be normalized. If a string, it will be assumed to be along one of the principal axes of the domain ("x", "y", or "z"). field : string The field to project. velocity_bounds : tuple A 4-tuple of (vmin, vmax, nbins, units) for the velocity bounds to integrate over. center : A sequence of floats, a string, or a tuple. The coordinate of the center of the image. If set to 'c', 'center' or left blank, the plot is centered on the middle of the domain. If set to 'max' or 'm', the center will be located at the maximum of the ('gas', 'density') field. Centering on the max or min of a specific field is supported by providing a tuple such as ("min","temperature") or ("max","dark_matter_density"). Units can be specified by passing in *center* as a tuple containing a coordinate and string unit name or by passing in a YTArray. If a list or unitless array is supplied, code units are assumed. width : float, tuple, or YTQuantity. The width of the projection. A float will assume the width is in code units. A (value, unit) tuple or YTQuantity allows for the units of the width to be specified. Implies width = height, e.g. the aspect ratio of the PPVCube's spatial dimensions is 1. dims : integer, optional The spatial resolution of the cube. Implies nx = ny, e.g. the aspect ratio of the PPVCube's spatial dimensions is 1. thermal_broad : boolean, optional Whether or not to broaden the line using the gas temperature. Default: False. atomic_weight : float, optional Set this value to the atomic weight of the particle that is emitting the line if *thermal_broad* is True. Defaults to 56 (Fe). depth : A tuple or a float, optional A tuple containing the depth to project through and the string key of the unit: (width, 'unit'). If set to a float, code units are assumed. Only for off-axis cubes. depth_res : integer, optional The resolution of integration along the line of sight for off-axis cubes. Default: 256 method : string, optional Set the projection method to be used. "integrate" : line of sight integration over the line element. "sum" : straight summation over the line of sight. weight_field : string, optional The name of the weighting field. Set to None for no weight. no_shifting : boolean, optional If set, no shifting due to velocity will occur but only thermal broadening. Should not be set when *thermal_broad* is False, otherwise nothing happens! north_vector : a sequence of floats A vector defining the 'up' direction. This option sets the orientation of the plane of projection. If not set, an arbitrary grid-aligned north_vector is chosen. Ignored in the case of on-axis cubes. no_ghost: bool, optional Optimization option for off-axis cases. If True, homogenized bricks will extrapolate out from grid instead of interpolating from ghost zones that have to first be calculated. This can lead to large speed improvements, but at a loss of accuracy/smoothness in resulting image. The effects are less notable when the transfer function is smooth and broad. Default: True Examples -------- >>> i = 60*np.pi/180. >>> L = [0.0,np.sin(i),np.cos(i)] >>> cube = PPVCube(ds, L, "density", (-5.,4.,100,"km/s"), width=(10.,"kpc")) """ self.ds = ds self.field = field self.width = width self.particle_mass = atomic_weight * mh self.thermal_broad = thermal_broad self.no_shifting = no_shifting if not isinstance(normal, string_types): width = ds.coordinates.sanitize_width(normal, width, depth) width = tuple(el.in_units('code_length').v for el in width) if no_shifting and not thermal_broad: raise RuntimeError( "no_shifting cannot be True when thermal_broad is False!") self.center = ds.coordinates.sanitize_center(center, normal)[0] self.nx = dims self.ny = dims self.nv = velocity_bounds[2] if method not in ["integrate", "sum"]: raise RuntimeError("Only the 'integrate' and 'sum' projection +" "methods are supported in PPVCube.") dd = ds.all_data() fd = dd._determine_fields(field)[0] self.field_units = ds._get_field_info(fd).units self.vbins = ds.arr( np.linspace(velocity_bounds[0], velocity_bounds[1], velocity_bounds[2] + 1), velocity_bounds[3]) self._vbins = self.vbins.copy() self.vmid = 0.5 * (self.vbins[1:] + self.vbins[:-1]) self.vmid_cgs = self.vmid.in_cgs().v self.dv = self.vbins[1] - self.vbins[0] self.dv_cgs = self.dv.in_cgs().v self.current_v = 0.0 _vlos = create_vlos(normal, self.no_shifting) self.ds.add_field(("gas", "v_los"), function=_vlos, units="cm/s") _intensity = self._create_intensity() self.ds.add_field(("gas", "intensity"), function=_intensity, units=self.field_units) if method == "integrate" and weight_field is None: self.proj_units = str(ds.quan(1.0, self.field_units + "*cm").units) elif method == "sum": self.proj_units = self.field_units storage = {} pbar = get_pbar("Generating cube.", self.nv) for sto, i in parallel_objects(range(self.nv), storage=storage): self.current_v = self.vmid_cgs[i] if isinstance(normal, string_types): prj = ds.proj("intensity", ds.coordinates.axis_id[normal], method=method, weight_field=weight_field) buf = prj.to_frb(width, self.nx, center=self.center)["intensity"] else: buf = off_axis_projection(ds, self.center, normal, width, (self.nx, self.ny, depth_res), "intensity", north_vector=north_vector, no_ghost=no_ghost, method=method, weight=weight_field).swapaxes(0, 1) sto.result_id = i sto.result = buf pbar.update(i) pbar.finish() self.data = ds.arr(np.zeros((self.nx, self.ny, self.nv)), self.proj_units) if is_root(): for i, buf in sorted(storage.items()): self.data[:, :, i] = buf.transpose() self.axis_type = "velocity" # Now fix the width if iterable(self.width): self.width = ds.quan(self.width[0], self.width[1]) elif not isinstance(self.width, YTQuantity): self.width = ds.quan(self.width, "code_length") self.ds.field_info.pop(("gas", "intensity")) self.ds.field_info.pop(("gas", "v_los"))
def __init__(self, ds, normal, field, velocity_bounds, center="c", width=(1.0,"unitary"), dims=100, thermal_broad=False, atomic_weight=56., depth=(1.0,"unitary"), depth_res=256, method="integrate", weight_field=None, no_shifting=False, north_vector=None, no_ghost=True): r""" Initialize a PPVCube object. Parameters ---------- ds : dataset The dataset. normal : array_like or string The normal vector along with to make the projections. If an array, it will be normalized. If a string, it will be assumed to be along one of the principal axes of the domain ("x", "y", or "z"). field : string The field to project. velocity_bounds : tuple A 4-tuple of (vmin, vmax, nbins, units) for the velocity bounds to integrate over. center : A sequence of floats, a string, or a tuple. The coordinate of the center of the image. If set to 'c', 'center' or left blank, the plot is centered on the middle of the domain. If set to 'max' or 'm', the center will be located at the maximum of the ('gas', 'density') field. Centering on the max or min of a specific field is supported by providing a tuple such as ("min","temperature") or ("max","dark_matter_density"). Units can be specified by passing in *center* as a tuple containing a coordinate and string unit name or by passing in a YTArray. If a list or unitless array is supplied, code units are assumed. width : float, tuple, or YTQuantity. The width of the projection. A float will assume the width is in code units. A (value, unit) tuple or YTQuantity allows for the units of the width to be specified. Implies width = height, e.g. the aspect ratio of the PPVCube's spatial dimensions is 1. dims : integer, optional The spatial resolution of the cube. Implies nx = ny, e.g. the aspect ratio of the PPVCube's spatial dimensions is 1. thermal_broad : boolean, optional Whether or not to broaden the line using the gas temperature. Default: False. atomic_weight : float, optional Set this value to the atomic weight of the particle that is emitting the line if *thermal_broad* is True. Defaults to 56 (Fe). depth : A tuple or a float, optional A tuple containing the depth to project through and the string key of the unit: (width, 'unit'). If set to a float, code units are assumed. Only for off-axis cubes. depth_res : integer, optional The resolution of integration along the line of sight for off-axis cubes. Default: 256 method : string, optional Set the projection method to be used. "integrate" : line of sight integration over the line element. "sum" : straight summation over the line of sight. weight_field : string, optional The name of the weighting field. Set to None for no weight. no_shifting : boolean, optional If set, no shifting due to velocity will occur but only thermal broadening. Should not be set when *thermal_broad* is False, otherwise nothing happens! north_vector : a sequence of floats A vector defining the 'up' direction. This option sets the orientation of the plane of projection. If not set, an arbitrary grid-aligned north_vector is chosen. Ignored in the case of on-axis cubes. no_ghost: bool, optional Optimization option for off-axis cases. If True, homogenized bricks will extrapolate out from grid instead of interpolating from ghost zones that have to first be calculated. This can lead to large speed improvements, but at a loss of accuracy/smoothness in resulting image. The effects are less notable when the transfer function is smooth and broad. Default: True Examples -------- >>> i = 60*np.pi/180. >>> L = [0.0,np.sin(i),np.cos(i)] >>> cube = PPVCube(ds, L, "density", (-5.,4.,100,"km/s"), width=(10.,"kpc")) """ self.ds = ds self.field = field self.width = width self.particle_mass = atomic_weight*mh self.thermal_broad = thermal_broad self.no_shifting = no_shifting if not isinstance(normal, string_types): width = ds.coordinates.sanitize_width(normal, width, depth) width = tuple(el.in_units('code_length').v for el in width) if no_shifting and not thermal_broad: raise RuntimeError("no_shifting cannot be True when thermal_broad is False!") self.center = ds.coordinates.sanitize_center(center, normal)[0] self.nx = dims self.ny = dims self.nv = velocity_bounds[2] if method not in ["integrate","sum"]: raise RuntimeError("Only the 'integrate' and 'sum' projection +" "methods are supported in PPVCube.") dd = ds.all_data() fd = dd._determine_fields(field)[0] self.field_units = ds._get_field_info(fd).units self.vbins = ds.arr(np.linspace(velocity_bounds[0], velocity_bounds[1], velocity_bounds[2]+1), velocity_bounds[3]) self._vbins = self.vbins.copy() self.vmid = 0.5*(self.vbins[1:]+self.vbins[:-1]) self.vmid_cgs = self.vmid.in_cgs().v self.dv = self.vbins[1]-self.vbins[0] self.dv_cgs = self.dv.in_cgs().v self.current_v = 0.0 _vlos = create_vlos(normal, self.no_shifting) self.ds.add_field(("gas","v_los"), function=_vlos, units="cm/s") _intensity = self._create_intensity() self.ds.add_field(("gas","intensity"), function=_intensity, units=self.field_units) if method == "integrate" and weight_field is None: self.proj_units = str(ds.quan(1.0, self.field_units+"*cm").units) elif method == "sum": self.proj_units = self.field_units storage = {} pbar = get_pbar("Generating cube.", self.nv) for sto, i in parallel_objects(range(self.nv), storage=storage): self.current_v = self.vmid_cgs[i] if isinstance(normal, string_types): prj = ds.proj("intensity", ds.coordinates.axis_id[normal], method=method, weight_field=weight_field) buf = prj.to_frb(width, self.nx, center=self.center)["intensity"] else: buf = off_axis_projection(ds, self.center, normal, width, (self.nx, self.ny, depth_res), "intensity", north_vector=north_vector, no_ghost=no_ghost, method=method, weight=weight_field).swapaxes(0,1) sto.result_id = i sto.result = buf pbar.update(i) pbar.finish() self.data = ds.arr(np.zeros((self.nx,self.ny,self.nv)), self.proj_units) if is_root(): for i, buf in sorted(storage.items()): self.data[:,:,i] = buf.transpose() self.axis_type = "velocity" # Now fix the width if iterable(self.width): self.width = ds.quan(self.width[0], self.width[1]) elif not isinstance(self.width, YTQuantity): self.width = ds.quan(self.width, "code_length") self.ds.field_info.pop(("gas","intensity")) self.ds.field_info.pop(("gas","v_los"))
def test_fits_image(): tmpdir = tempfile.mkdtemp() curdir = os.getcwd() os.chdir(tmpdir) fields = ("density", "temperature") units = ( 'g/cm**3', 'K', ) ds = fake_random_ds(64, fields=fields, units=units, nprocs=16, length_unit=100.0) prj = ds.proj("density", 2) prj_frb = prj.to_frb((0.5, "unitary"), 128) fid1 = FITSImageData(prj_frb, fields=["density", "temperature"], units="cm") fits_prj = FITSProjection(ds, "z", ["density", "temperature"], image_res=128, width=(0.5, "unitary")) yield assert_equal, fid1.get_data("density"), fits_prj.get_data("density") yield assert_equal, fid1.get_data("temperature"), fits_prj.get_data( "temperature") fid1.writeto("fid1.fits", clobber=True) new_fid1 = FITSImageData.from_file("fid1.fits") yield assert_equal, fid1.get_data("density"), new_fid1.get_data("density") yield assert_equal, fid1.get_data("temperature"), new_fid1.get_data( "temperature") ds2 = load("fid1.fits") ds2.index assert ("fits", "density") in ds2.field_list assert ("fits", "temperature") in ds2.field_list dw_cm = ds2.domain_width.in_units("cm") assert dw_cm[0].v == 50. assert dw_cm[1].v == 50. slc = ds.slice(2, 0.5) slc_frb = slc.to_frb((0.5, "unitary"), 128) fid2 = FITSImageData(slc_frb, fields=["density", "temperature"], units="cm") fits_slc = FITSSlice(ds, "z", ["density", "temperature"], image_res=128, width=(0.5, "unitary")) yield assert_equal, fid2.get_data("density"), fits_slc.get_data("density") yield assert_equal, fid2.get_data("temperature"), fits_slc.get_data( "temperature") dens_img = fid2.pop("density") temp_img = fid2.pop("temperature") # This already has some assertions in it, so we don't need to do anything # with it other can just make one fid_comb = FITSImageData.from_images([dens_img, temp_img]) cut = ds.cutting([0.1, 0.2, -0.9], [0.5, 0.42, 0.6]) cut_frb = cut.to_frb((0.5, "unitary"), 128) fid3 = FITSImageData(cut_frb, fields=["density", "temperature"], units="cm") fits_cut = FITSOffAxisSlice(ds, [0.1, 0.2, -0.9], ["density", "temperature"], image_res=128, center=[0.5, 0.42, 0.6], width=(0.5, "unitary")) yield assert_equal, fid3.get_data("density"), fits_cut.get_data("density") yield assert_equal, fid3.get_data("temperature"), fits_cut.get_data( "temperature") fid3.create_sky_wcs([30., 45.], (1.0, "arcsec/kpc")) fid3.writeto("fid3.fits", clobber=True) new_fid3 = FITSImageData.from_file("fid3.fits") assert_same_wcs(fid3.wcs, new_fid3.wcs) assert new_fid3.wcs.wcs.cunit[0] == "deg" assert new_fid3.wcs.wcs.cunit[1] == "deg" assert new_fid3.wcs.wcs.ctype[0] == "RA---TAN" assert new_fid3.wcs.wcs.ctype[1] == "DEC--TAN" buf = off_axis_projection(ds, ds.domain_center, [0.1, 0.2, -0.9], 0.5, 128, "density").swapaxes(0, 1) fid4 = FITSImageData(buf, fields="density", width=100.0) fits_oap = FITSOffAxisProjection(ds, [0.1, 0.2, -0.9], "density", width=(0.5, "unitary"), image_res=128, depth_res=128, depth=(0.5, "unitary")) yield assert_equal, fid4.get_data("density"), fits_oap.get_data("density") cvg = ds.covering_grid(ds.index.max_level, [0.25, 0.25, 0.25], [32, 32, 32], fields=["density", "temperature"]) fid5 = FITSImageData(cvg, fields=["density", "temperature"]) assert fid5.dimensionality == 3 fid5.update_header("density", "time", 0.1) fid5.update_header("all", "units", "cgs") assert fid5["density"].header["time"] == 0.1 assert fid5["temperature"].header["units"] == "cgs" assert fid5["density"].header["units"] == "cgs" os.chdir(curdir) shutil.rmtree(tmpdir)
def test_fits_image(): tmpdir = tempfile.mkdtemp() curdir = os.getcwd() os.chdir(tmpdir) fields = ("density", "temperature") units = ('g/cm**3', 'K',) ds = fake_random_ds(64, fields=fields, units=units, nprocs=16, length_unit=100.0) prj = ds.proj("density", 2) prj_frb = prj.to_frb((0.5, "unitary"), 128) fid1 = FITSImageData(prj_frb, fields=["density","temperature"], units="cm") fits_prj = FITSProjection(ds, "z", ["density","temperature"], image_res=128, width=(0.5,"unitary")) yield assert_equal, fid1.get_data("density"), fits_prj.get_data("density") yield assert_equal, fid1.get_data("temperature"), fits_prj.get_data("temperature") fid1.writeto("fid1.fits", clobber=True) new_fid1 = FITSImageData.from_file("fid1.fits") yield assert_equal, fid1.get_data("density"), new_fid1.get_data("density") yield assert_equal, fid1.get_data("temperature"), new_fid1.get_data("temperature") ds2 = load("fid1.fits") ds2.index assert ("fits","density") in ds2.field_list assert ("fits","temperature") in ds2.field_list dw_cm = ds2.domain_width.in_units("cm") assert dw_cm[0].v == 50. assert dw_cm[1].v == 50. slc = ds.slice(2, 0.5) slc_frb = slc.to_frb((0.5, "unitary"), 128) fid2 = FITSImageData(slc_frb, fields=["density","temperature"], units="cm") fits_slc = FITSSlice(ds, "z", ["density","temperature"], image_res=128, width=(0.5,"unitary")) yield assert_equal, fid2.get_data("density"), fits_slc.get_data("density") yield assert_equal, fid2.get_data("temperature"), fits_slc.get_data("temperature") dens_img = fid2.pop("density") temp_img = fid2.pop("temperature") # This already has some assertions in it, so we don't need to do anything # with it other can just make one fid_comb = FITSImageData.from_images([dens_img, temp_img]) cut = ds.cutting([0.1, 0.2, -0.9], [0.5, 0.42, 0.6]) cut_frb = cut.to_frb((0.5, "unitary"), 128) fid3 = FITSImageData(cut_frb, fields=["density","temperature"], units="cm") fits_cut = FITSOffAxisSlice(ds, [0.1, 0.2, -0.9], ["density","temperature"], image_res=128, center=[0.5, 0.42, 0.6], width=(0.5,"unitary")) yield assert_equal, fid3.get_data("density"), fits_cut.get_data("density") yield assert_equal, fid3.get_data("temperature"), fits_cut.get_data("temperature") fid3.create_sky_wcs([30.,45.], (1.0,"arcsec/kpc")) fid3.writeto("fid3.fits", clobber=True) new_fid3 = FITSImageData.from_file("fid3.fits") assert_same_wcs(fid3.wcs, new_fid3.wcs) assert new_fid3.wcs.wcs.cunit[0] == "deg" assert new_fid3.wcs.wcs.cunit[1] == "deg" assert new_fid3.wcs.wcs.ctype[0] == "RA---TAN" assert new_fid3.wcs.wcs.ctype[1] == "DEC--TAN" buf = off_axis_projection(ds, ds.domain_center, [0.1, 0.2, -0.9], 0.5, 128, "density").swapaxes(0, 1) fid4 = FITSImageData(buf, fields="density", width=100.0) fits_oap = FITSOffAxisProjection(ds, [0.1, 0.2, -0.9], "density", width=(0.5,"unitary"), image_res=128, depth_res=128, depth=(0.5,"unitary")) yield assert_equal, fid4.get_data("density"), fits_oap.get_data("density") cvg = ds.covering_grid(ds.index.max_level, [0.25,0.25,0.25], [32, 32, 32], fields=["density","temperature"]) fid5 = FITSImageData(cvg, fields=["density","temperature"]) assert fid5.dimensionality == 3 fid5.update_header("density", "time", 0.1) fid5.update_header("all", "units", "cgs") assert fid5["density"].header["time"] == 0.1 assert fid5["temperature"].header["units"] == "cgs" assert fid5["density"].header["units"] == "cgs" os.chdir(curdir) shutil.rmtree(tmpdir)
def __init__(self, ds, normal, field, width=(1.0, "unitary"), dims=(100, 100, 100), velocity_bounds=None): r""" Initialize a PPVCube object. Parameters ---------- ds : dataset The dataset. normal : array_like The normal vector along with to make the projections. field : string The field to project. width : float or tuple, optional The width of the projection in length units. Specify a float for code_length units or a tuple (value, units). dims : tuple, optional A 3-tuple of dimensions (nx,ny,nv) for the cube. velocity_bounds : tuple, optional A 3-tuple of (vmin, vmax, units) for the velocity bounds to integrate over. If None, the largest velocity of the dataset will be used, e.g. velocity_bounds = (-v.max(), v.max()) Examples -------- >>> i = 60*np.pi/180. >>> L = [0.0,np.sin(i),np.cos(i)] >>> cube = PPVCube(ds, L, "density", width=(10.,"kpc"), ... velocity_bounds=(-5.,4.,"km/s")) """ self.ds = ds self.field = field self.width = width self.nx = dims[0] self.ny = dims[1] self.nv = dims[2] normal = np.array(normal) normal /= np.sqrt(np.dot(normal, normal)) vecs = np.identity(3) t = np.cross(normal, vecs).sum(axis=1) ax = t.argmax() north = np.cross(normal, vecs[ax, :]).ravel() orient = Orientation(normal, north_vector=north) dd = ds.all_data() fd = dd._determine_fields(field)[0] self.field_units = ds._get_field_info(fd).units if velocity_bounds is None: vmin, vmax = dd.quantities.extrema("velocity_magnitude") self.v_bnd = -vmax, vmax else: self.v_bnd = (ds.quan(velocity_bounds[0], velocity_bounds[2]), ds.quan(velocity_bounds[1], velocity_bounds[2])) self.vbins = np.linspace(self.v_bnd[0], self.v_bnd[1], num=self.nv + 1) self.vmid = 0.5 * (self.vbins[1:] + self.vbins[:-1]) self.dv = (self.v_bnd[1] - self.v_bnd[0]) / self.nv _vlos = create_vlos(orient.unit_vectors[2]) ds.field_info.add_field(("gas", "v_los"), function=_vlos, units="cm/s") self.data = ds.arr(np.zeros((self.nx, self.ny, self.nv)), self.field_units) pbar = get_pbar("Generating cube.", self.nv) for i in xrange(self.nv): _intensity = self._create_intensity(i) ds.add_field(("gas", "intensity"), function=_intensity, units=self.field_units) prj = off_axis_projection(ds, ds.domain_center, normal, width, (self.nx, self.ny), "intensity") self.data[:, :, i] = prj[:, :] ds.field_info.pop(("gas", "intensity")) pbar.update(i) pbar.finish()
def off_axis(self, L, center="c", width=(1, "unitary"), nx=800, source=None): r""" Make an off-axis projection of the SZ signal. Parameters ---------- L : array_like The normal vector of the projection. center : A sequence of floats, a string, or a tuple. The coordinate of the center of the image. If set to 'c', 'center' or left blank, the plot is centered on the middle of the domain. If set to 'max' or 'm', the center will be located at the maximum of the ('gas', 'density') field. Centering on the max or min of a specific field is supported by providing a tuple such as ("min","temperature") or ("max","dark_matter_density"). Units can be specified by passing in *center* as a tuple containing a coordinate and string unit name or by passing in a YTArray. If a list or unitless array is supplied, code units are assumed. width : float, tuple, or YTQuantity. The width of the projection. A float will assume the width is in code units. A (value, unit) tuple or YTQuantity allows for the units of the width to be specified. nx : integer, optional The dimensions on a side of the projection image. source : yt.data_objects.data_containers.YTSelectionContainer, optional If specified, this will be the data source used for selecting regions to project. Currently unsupported in yt 2.x. Examples -------- >>> L = np.array([0.5, 1.0, 0.75]) >>> szprj.off_axis(L, center="c", width=(2.0, "Mpc")) """ if iterable(width): w = self.ds.quan(width[0], width[1]).in_units("code_length").value elif isinstance(width, YTQuantity): w = width.in_units("code_length").value else: w = width ctr, dctr = self.ds.coordinates.sanitize_center(center, L) if source is not None: mylog.error("Source argument is not currently supported for off-axis S-Z projections.") raise NotImplementedError beta_par = generate_beta_par(L) self.ds.add_field(("gas","beta_par"), function=beta_par, units="g/cm**3") setup_sunyaev_zeldovich_fields(self.ds) dens = off_axis_projection(self.ds, ctr, L, w, nx, "density") Te = off_axis_projection(self.ds, ctr, L, w, nx, "t_sz")/dens bpar = off_axis_projection(self.ds, ctr, L, w, nx, "beta_par")/dens omega1 = off_axis_projection(self.ds, ctr, L, w, nx, "t_squared")/dens omega1 = omega1/(Te*Te) - 1. if self.high_order: bperp2 = off_axis_projection(self.ds, ctr, L, w, nx, "beta_perp_squared")/dens sigma1 = off_axis_projection(self.ds, ctr, L, w, nx, "t_beta_par")/dens sigma1 = sigma1/Te - bpar kappa1 = off_axis_projection(self.ds, ctr, L, w, nx, "beta_par_squared")/dens kappa1 -= bpar else: bperp2 = np.zeros((nx,nx)) sigma1 = np.zeros((nx,nx)) kappa1 = np.zeros((nx,nx)) tau = sigma_thompson*dens*self.mueinv/mh self.bounds = np.array([-0.5*w, 0.5*w, -0.5*w, 0.5*w]) self.dx = w/nx self.dy = w/nx self.nx = nx self._compute_intensity(np.array(tau), np.array(Te), np.array(bpar), np.array(omega1), np.array(sigma1), np.array(kappa1), np.array(bperp2)) self.ds.field_info.pop(("gas","beta_par"))
def off_axis(self, L, center="c", width=(1, "unitary"), nx=800, source=None): r""" Make an off-axis projection of the SZ signal. Parameters ---------- L : array_like The normal vector of the projection. center : array_like or string, optional The center of the projection. width : float or tuple The width of the projection. nx : integer, optional The dimensions on a side of the projection image. source : yt.data_objects.api.AMRData, optional If specified, this will be the data source used for selecting regions to project. Currently unsupported in yt 2.x. Examples -------- >>> L = np.array([0.5, 1.0, 0.75]) >>> szprj.off_axis(L, center="c", width=(2.0, "Mpc")) """ if iterable(width): w = self.ds.quan(width[0], width[1]).in_units("code_length").value elif isinstance(width, YTQuantity): w = width.in_units("code_length").value else: w = width if center == "c": ctr = self.ds.domain_center elif center == "max": v, ctr = self.ds.find_max("density") else: ctr = center if source is not None: mylog.error( "Source argument is not currently supported for off-axis S-Z projections." ) raise NotImplementedError beta_par = generate_beta_par(L) self.ds.add_field(("gas", "beta_par"), function=beta_par, units="g/cm**3") setup_sunyaev_zeldovich_fields(self.ds) dens = off_axis_projection(self.ds, ctr, L, w, nx, "density") Te = off_axis_projection(self.ds, ctr, L, w, nx, "t_sz") / dens bpar = off_axis_projection(self.ds, ctr, L, w, nx, "beta_par") / dens omega1 = off_axis_projection(self.ds, ctr, L, w, nx, "t_squared") / dens omega1 = omega1 / (Te * Te) - 1. if self.high_order: bperp2 = off_axis_projection(self.ds, ctr, L, w, nx, "beta_perp_squared") / dens sigma1 = off_axis_projection(self.ds, ctr, L, w, nx, "t_beta_par") / dens sigma1 = sigma1 / Te - bpar kappa1 = off_axis_projection(self.ds, ctr, L, w, nx, "beta_par_squared") / dens kappa1 -= bpar else: bperp2 = np.zeros((nx, nx)) sigma1 = np.zeros((nx, nx)) kappa1 = np.zeros((nx, nx)) tau = sigma_thompson * dens * self.mueinv / mh self.bounds = np.array([-0.5 * w, 0.5 * w, -0.5 * w, 0.5 * w]) self.dx = w / nx self.dy = w / nx self.nx = nx self._compute_intensity(np.array(tau), np.array(Te), np.array(bpar), np.array(omega1), np.array(sigma1), np.array(kappa1), np.array(bperp2)) self.ds.field_info.pop(("gas", "beta_par"))