def test_center_1(): """Change the center to [0, 3, 0] Every point will be shifted by 3 in the y-domain With this, we should not be able to see any of the y-axis particles (0, 1, 0) -> (0, -2) (0, 2, 0) -> (0, -1) (0, 0, 1) -> (0, -3) (0, 0, 2) -> (0, -3) (0, 0, 3) -> (0, -3) (0, 0, 0) -> (0, -3) (1, 0, 0) -> (1, -3) """ expected_maxima = ([0.0, 0.0, 0.0, 1.0], [-2.0, -1.0, -3.0, -3.0]) normal_vector = [0.0, 0.0, 1.0] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge # center = [(left_edge[0] + right_edge[0])/2, # left_edge[1], # (left_edge[2] + right_edge[2])/2] center = [0.0, 3.0, 0.0] width = right_edge - left_edge buf1 = OffAP.off_axis_projection( ds, center, normal_vector, width, resolution, ("gas", "density") ) find_compare_maxima(expected_maxima, buf1, resolution, width)
def test_basic_rotation_1(): """All particles on Z-axis should now be on the negative Y-Axis fake_sph_orientation has three z-axis particles, so there should be three y-axis particles after rotation (0, 0, 1) -> (0, -1) (0, 0, 2) -> (0, -2) (0, 0, 3) -> (0, -3) In addition, we should find a local maxima at (0, 0) due to: (0, 0, 0) -> (0, 0) (0, 1, 0) -> (0, 0) (0, 2, 0) -> (0, 0) and the one particle on the x-axis should not change its position: (1, 0, 0) -> (1, 0) """ expected_maxima = ([0.0, 0.0, 0.0, 0.0, 1.0], [0.0, -1.0, -2.0, -3.0, 0.0]) normal_vector = [0.0, 1.0, 0.0] north_vector = [0.0, 0.0, -1.0] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = (left_edge + right_edge) / 2 width = right_edge - left_edge buf1 = OffAP.off_axis_projection( ds, center, normal_vector, width, resolution, ("gas", "density"), north_vector=north_vector, ) find_compare_maxima(expected_maxima, buf1, resolution, width)
def test_no_rotation(): """Determines if a projection processed through off_axis_projection with no rotation will give the same image buffer if processed directly through pixelize_sph_kernel_projection """ normal_vector = [0.0, 0.0, 1.0] resolution = (64, 64) ds = fake_sph_orientation_ds() ad = ds.all_data() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = (left_edge + right_edge) / 2 width = right_edge - left_edge px = ad[("all", "particle_position_x")] py = ad[("all", "particle_position_y")] hsml = ad[("all", "smoothing_length")] quantity_to_smooth = ad[("gas", "density")] density = ad[("io", "density")] mass = ad[("io", "particle_mass")] bounds = [-4, 4, -4, 4, -4, 4] buf2 = np.zeros(resolution) buf1 = OffAP.off_axis_projection( ds, center, normal_vector, width, resolution, ("gas", "density") ) pixelize_sph_kernel_projection( buf2, px, py, hsml, mass, density, quantity_to_smooth, bounds ) assert_almost_equal(buf1.ndarray_view(), buf2)
def test_basic_rotation_3(): """Rotation of z-axis onto negative z-axis. All fake particles on z-axis should now be of the negative z-Axis. fake_sph_orientation has three z-axis particles, so we should have a local maxima at (0, 0) (0, 0, 1) -> (0, 0) (0, 0, 2) -> (0, 0) (0, 0, 3) -> (0, 0) In addition, (0, 0, 0) should also contribute to the local maxima at (0, 0): (0, 0, 0) -> (0, 0) x-axis particles should be rotated as such: (1, 0, 0) -> (0, -1) and same goes for y-axis particles: (0, 1, 0) -> (-1, 0) (0, 2, 0) -> (-2, 0) """ expected_maxima = ([0.0, 0.0, -1.0, -2.0], [0.0, -1.0, 0.0, 0.0]) normal_vector = [0.0, 0.0, -1.0] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = (left_edge + right_edge) / 2 width = right_edge - left_edge buf1 = OffAP.off_axis_projection( ds, center, normal_vector, width, resolution, ("gas", "density") ) find_compare_maxima(expected_maxima, buf1, resolution, width)
def __init__(self, ds, normal, fields, center='c', width=(1.0, 'unitary'), weight_field=None, image_res=512, data_source=None, north_vector=None, depth=(1.0, "unitary"), method='integrate', length_unit=None): 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]) if data_source is None: source = ds else: source = data_source for field in fields: buf[field] = off_axis_projection(source, center, normal, wd, res, field, north_vector=north_vector, method=method, weight=weight_field).swapaxes(0,1) center = ds.arr([0.0]*2, 'code_length') w, not_an_frb, lunit = construct_image(ds, normal, buf, center, image_res, width, length_unit) super(FITSOffAxisProjection, self).__init__(buf, fields=fields, wcs=w, length_unit=lunit, ds=ds)
def test_basic_rotation_2(): """ Rotation of x-axis onto z-axis. All particles on z-axis should now be on the negative x-Axis fake_sph_orientation has three z-axis particles, so there should be three x-axis particles after rotation (0, 0, 1) -> (-1, 0) (0, 0, 2) -> (-2, 0) (0, 0, 3) -> (-3, 0) In addition, we should find a local maxima at (0, 0) due to: (0, 0, 0) -> (0, 0) (1, 0, 0) -> (0, 0) and the two particles on the y-axis should not change its position: (0, 1, 0) -> (0, 1) (0, 2, 0) -> (0, 2) """ expected_maxima = ([-1., -2., -3., 0., 0., 0.], [0., 0., 0., 0., 1., 2.]) normal_vector = [1., 0., 0.] north_vector = [0., 1., 0.] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = (left_edge + right_edge) / 2 width = (right_edge - left_edge) buf1 = OffAP.off_axis_projection(ds, center, normal_vector, width, resolution, ('gas', 'density'), north_vector=north_vector) find_compare_maxima(expected_maxima, buf1, resolution, width)
def test_basic_rotation_4(): """ Rotation of x-axis to z-axis and original z-axis to y-axis with the use of the north_vector. All fake particles on z-axis should now be on the y-Axis. All fake particles on the x-axis should now be on the z-axis, and all fake particles on the y-axis should now be on the x-axis. (0, 0, 1) -> (0, 1) (0, 0, 2) -> (0, 2) (0, 0, 3) -> (0, 3) In addition, (0, 0, 0) should contribute to the local maxima at (0, 0): (0, 0, 0) -> (0, 0) x-axis particles should be rotated and contribute to the local maxima at (0, 0): (1, 0, 0) -> (0, 0) and the y-axis particles shift into the positive x direction: (0, 1, 0) -> (1, 0) (0, 2, 0) -> (2, 0) """ expected_maxima = ([0., 0., 0., 0., 1., 2.], [1., 2., 3., 0., 0., 0.]) normal_vector = [1., 0., 0.] north_vector = [0., 0., 1.] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = (left_edge + right_edge) / 2 width = (right_edge - left_edge) buf1 = OffAP.off_axis_projection(ds, center, normal_vector, width, resolution, ('gas', 'density'), north_vector=north_vector) find_compare_maxima(expected_maxima, buf1, resolution, width)
def test_center_3(): """ Change the center to the left edge, or [0, -8, 0] Every point will be shifted by 8 in the y-domain With this, we should not be able to see anything ! """ expected_maxima = ([], []) normal_vector = [0., 0., 1.] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = [0., -1., 0.] width = [(right_edge[0] - left_edge[0]), left_edge[1], (right_edge[2] - left_edge[2])] buf1 = OffAP.off_axis_projection(ds, center, normal_vector, width, resolution, ('gas', 'density')) find_compare_maxima(expected_maxima, buf1, resolution, width)
def __init__( self, ds, normal, fields, center="c", width=(1.0, "unitary"), weight_field=None, image_res=512, data_source=None, north_vector=None, depth=(1.0, "unitary"), method="integrate", length_unit=None, ): fields = list(iter_fields(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 is_sequence(image_res): image_res = (image_res, image_res) res = (image_res[0], image_res[1]) if data_source is None: source = ds else: source = data_source for field in fields: buf[field] = off_axis_projection( source, center, normal, wd, res, field, north_vector=north_vector, method=method, weight=weight_field, ).swapaxes(0, 1) center = ds.arr([0.0] * 2, "code_length") w, not_an_frb, lunit = construct_image( ds, normal, buf, center, image_res, width, length_unit ) super().__init__(buf, fields=fields, wcs=w, length_unit=lunit, ds=ds)
def test_center_2(): """ Change the center to [0, -1, 0] Every point will be shifted by 1 in the y-domain With this, we should not be able to see any of the y-axis particles (0, 1, 0) -> (0, 2) (0, 2, 0) -> (0, 3) (0, 0, 1) -> (0, 1) (0, 0, 2) -> (0, 1) (0, 0, 3) -> (0, 1) (0, 0, 0) -> (0, 1) (1, 0, 0) -> (1, 1) """ expected_maxima = ([0., 0., 0., 1.], [2., 3., 1., 1.]) normal_vector = [0., 0., 1.] resolution = (64, 64) ds = fake_sph_orientation_ds() left_edge = ds.domain_left_edge right_edge = ds.domain_right_edge center = [0., -1., 0.] width = (right_edge - left_edge) buf1 = OffAP.off_axis_projection(ds, center, normal_vector, width, resolution, ('gas', 'density')) find_compare_maxima(expected_maxima, buf1, resolution, width)
if proj_axis in ['x', 'y', 'z']: # On-Axis Projections prj = ds_sync.proj(stokes.I, proj_axis) buf = prj.to_frb(width[0], res_obs, height=width[1]) else: # Off-Axis Projections buf = {} width = ds_sync.coordinates.sanitize_width(proj_axis, width, (1.0, 'unitary')) wd = tuple(w.in_units('code_length').v for w in width) for field in fields: buf[field] = off_axis_projection(ds_sync, [0, 0, 0], proj_axis, wd, res_obs, field, north_vector=[1, 0, 0], num_threads=0).swapaxes(0, 1) fits_image = FITSImageData(buf, fields=fields, wcs=w) for nu in nus: stokes = StokesFieldName(ptype, nu, proj_axis, field_type='flash') field = stokes.I[1] fits_image[field].data.units.registry.add( 'beam', float(beam_area.in_units('rad**2').v), dimensions=yt.units.dimensions.solid_angle, tex_repr='beam') fits_image.set_unit(field, 'Jy/beam') nu = yt.YTQuantity(*nu) header_dict.update({
def test_fits_image(): curdir = os.getcwd() tmpdir = tempfile.mkdtemp() 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 = prj_frb.to_fits_data( fields=[("gas", "density"), ("gas", "temperature")], length_unit="cm" ) fits_prj = FITSProjection( ds, "z", [ds.fields.gas.density, "temperature"], image_res=128, width=(0.5, "unitary"), ) assert_equal(fid1["density"].data, fits_prj["density"].data) assert_equal(fid1["temperature"].data, fits_prj["temperature"].data) fid1.writeto("fid1.fits", overwrite=True) new_fid1 = FITSImageData.from_file("fid1.fits") assert_equal(fid1["density"].data, new_fid1["density"].data) assert_equal(fid1["temperature"].data, new_fid1["temperature"].data) assert_equal(fid1.length_unit, new_fid1.length_unit) assert_equal(fid1.time_unit, new_fid1.time_unit) assert_equal(fid1.mass_unit, new_fid1.mass_unit) assert_equal(fid1.velocity_unit, new_fid1.velocity_unit) assert_equal(fid1.magnetic_unit, new_fid1.magnetic_unit) assert_equal(fid1.current_time, new_fid1.current_time) 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.0 assert dw_cm[1].v == 50.0 slc = ds.slice(2, 0.5) slc_frb = slc.to_frb((0.5, "unitary"), 128) fid2 = slc_frb.to_fits_data( fields=[("gas", "density"), ("gas", "temperature")], length_unit="cm" ) fits_slc = FITSSlice( ds, "z", [("gas", "density"), ("gas", "temperature")], image_res=128, width=(0.5, "unitary"), ) assert_equal(fid2["density"].data, fits_slc["density"].data) assert_equal(fid2["temperature"].data, fits_slc["temperature"].data) dens_img = fid2.pop("density") temp_img = fid2.pop("temperature") combined_fid = FITSImageData.from_images([dens_img, temp_img]) assert_equal(combined_fid.length_unit, dens_img.length_unit) assert_equal(combined_fid.time_unit, dens_img.time_unit) assert_equal(combined_fid.mass_unit, dens_img.mass_unit) assert_equal(combined_fid.velocity_unit, dens_img.velocity_unit) assert_equal(combined_fid.magnetic_unit, dens_img.magnetic_unit) assert_equal(combined_fid.current_time, dens_img.current_time) 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 = cut_frb.to_fits_data( fields=[("gas", "density"), ds.fields.gas.temperature], length_unit="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"), ) assert_equal(fid3["density"].data, fits_cut["density"].data) assert_equal(fid3["temperature"].data, fits_cut["temperature"].data) fid3.create_sky_wcs([30.0, 45.0], (1.0, "arcsec/kpc")) fid3.writeto("fid3.fits", overwrite=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=(0.5, "unitary"), ) assert_equal(fid4["density"].data, fits_oap["density"].data) fid4.create_sky_wcs([30.0, 45.0], (1.0, "arcsec/kpc"), replace_old_wcs=False) assert fid4.wcs.wcs.cunit[0] == "cm" assert fid4.wcs.wcs.cunit[1] == "cm" assert fid4.wcs.wcs.ctype[0] == "linear" assert fid4.wcs.wcs.ctype[1] == "linear" assert fid4.wcsa.wcs.cunit[0] == "deg" assert fid4.wcsa.wcs.cunit[1] == "deg" assert fid4.wcsa.wcs.ctype[0] == "RA---TAN" assert fid4.wcsa.wcs.ctype[1] == "DEC--TAN" cvg = ds.covering_grid( ds.index.max_level, [0.25, 0.25, 0.25], [32, 32, 32], fields=["density", "temperature"], ) fid5 = cvg.to_fits_data(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" fid6 = FITSImageData.from_images(fid5) fid5.change_image_name("density", "mass_per_volume") assert fid5["mass_per_volume"].name == "mass_per_volume" assert fid5["mass_per_volume"].header["BTYPE"] == "mass_per_volume" assert "mass_per_volume" in fid5.fields assert "mass_per_volume" in fid5.field_units assert "density" not in fid5.fields assert "density" not in fid5.field_units assert "density" in fid6.fields assert_equal(fid6["density"].data, fid5["mass_per_volume"].data) fid7 = FITSImageData.from_images(fid4) fid7.convolve("density", (3.0, "cm")) sigma = 3.0 / fid7.wcs.wcs.cdelt[0] kernel = _astropy.conv.Gaussian2DKernel(x_stddev=sigma) data_conv = _astropy.conv.convolve(fid4["density"].data.d, kernel) assert_allclose(data_conv, fid7["density"].data.d) # We need to manually close all the file descriptors so # that windows can delete the folder that contains them. ds2.close() for fid in (fid1, fid2, fid3, fid4, fid5, fid6, fid7, new_fid1, new_fid3): fid.close() 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")) assert_equal(fid1.get_data("density"), fits_prj.get_data("density")) assert_equal(fid1.get_data("temperature"), fits_prj.get_data("temperature")) fid1.writeto("fid1.fits", clobber=True) new_fid1 = FITSImageData.from_file("fid1.fits") assert_equal(fid1.get_data("density"), new_fid1.get_data("density")) 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")) assert_equal(fid2.get_data("density"), fits_slc.get_data("density")) 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 than just make one 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")) assert_equal(fid3.get_data("density"), fits_cut.get_data("density")) 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")) assert_equal(fid4.get_data("density"), fits_oap.get_data("density")) fid4.create_sky_wcs([30., 45.], (1.0, "arcsec/kpc"), replace_old_wcs=False) assert fid4.wcs.wcs.cunit[0] == "cm" assert fid4.wcs.wcs.cunit[1] == "cm" assert fid4.wcs.wcs.ctype[0] == "linear" assert fid4.wcs.wcs.ctype[1] == "linear" assert fid4.wcsa.wcs.cunit[0] == "deg" assert fid4.wcsa.wcs.cunit[1] == "deg" assert fid4.wcsa.wcs.ctype[0] == "RA---TAN" assert fid4.wcsa.wcs.ctype[1] == "DEC--TAN" 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 compare_vector_conversions(data_source): prng = np.random.RandomState(8675309) normals = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] + [ random_unit_vector(prng) for i in range(2) ] bulk_velocities = [random_velocity_vector(prng) for i in range(2)] for bv in bulk_velocities: bulk_velocity = bv * cm / s data_source.set_field_parameter("bulk_velocity", bulk_velocity) data_source.clear_data() vmag = data_source["velocity_magnitude"] vrad = data_source["velocity_spherical_radius"] for normal in normals: data_source.set_field_parameter("normal", normal) data_source.clear_data() assert_allclose_units(vrad, data_source["velocity_spherical_radius"]) vmag_new = data_source["velocity_magnitude"] assert_allclose_units(vmag, vmag_new) vmag_cart = np.sqrt( (data_source["velocity_x"] - bulk_velocity[0]) ** 2 + (data_source["velocity_y"] - bulk_velocity[1]) ** 2 + (data_source["velocity_z"] - bulk_velocity[2]) ** 2 ) assert_allclose_units(vmag, vmag_cart) vmag_cyl = np.sqrt( data_source["velocity_cylindrical_radius"] ** 2 + data_source["velocity_cylindrical_theta"] ** 2 + data_source["velocity_cylindrical_z"] ** 2 ) assert_allclose_units(vmag, vmag_cyl) vmag_sph = np.sqrt( data_source["velocity_spherical_radius"] ** 2 + data_source["velocity_spherical_theta"] ** 2 + data_source["velocity_spherical_phi"] ** 2 ) assert_allclose_units(vmag, vmag_sph) for i, d in enumerate("xyz"): assert_allclose_units( data_source[f"velocity_{d}"] - bulk_velocity[i], data_source[f"relative_velocity_{d}"], ) for i, ax in enumerate("xyz"): data_source.set_field_parameter("axis", i) data_source.clear_data() assert_allclose_units( data_source["velocity_los"], data_source[f"relative_velocity_{ax}"] ) for i, ax in enumerate("xyz"): prj = data_source.ds.proj("velocity_los", i, weight_field="density") assert_allclose_units(prj["velocity_los"], prj[f"velocity_{ax}"]) data_source.clear_data() ax = [0.1, 0.2, -0.3] data_source.set_field_parameter("axis", ax) ax /= np.sqrt(np.dot(ax, ax)) vlos = data_source["relative_velocity_x"] * ax[0] vlos += data_source["relative_velocity_y"] * ax[1] vlos += data_source["relative_velocity_z"] * ax[2] assert_allclose_units(data_source["velocity_los"], vlos) buf_los = off_axis_projection( data_source, data_source.ds.domain_center, ax, 0.5, 128, ("gas", "velocity_los"), weight=("gas", "density"), ) buf_x = off_axis_projection( data_source, data_source.ds.domain_center, ax, 0.5, 128, ("gas", "relative_velocity_x"), weight=("gas", "density"), ) buf_y = off_axis_projection( data_source, data_source.ds.domain_center, ax, 0.5, 128, ("gas", "relative_velocity_y"), weight=("gas", "density"), ) buf_z = off_axis_projection( data_source, data_source.ds.domain_center, ax, 0.5, 128, ("gas", "relative_velocity_z"), weight=("gas", "density"), ) vlos = buf_x * ax[0] + buf_y * ax[1] + buf_z * ax[2] assert_allclose_units(buf_los, vlos, rtol=1.0e-6)
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, data_source=None): 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 Deprecated, this is still in the function signature for API compatibility 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 data_source : yt.data_objects.data_containers.YTSelectionContainer, optional If specified, this will be the data source used for selecting regions to project. 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, str): width = ds.coordinates.sanitize_width(normal, width, depth) width = tuple(el.in_units('code_length').v for el in width) if not hasattr(ds.fields.gas, "temperature") and thermal_broad: raise RuntimeError("thermal_broad cannot be True if there is " "no 'temperature' field!") 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", sampling_type='cell') _intensity = self._create_intensity() self.ds.add_field(("gas", "intensity"), function=_intensity, units=self.field_units, sampling_type='cell') 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, str): prj = ds.proj("intensity", ds.coordinates.axis_id[normal], method=method, weight_field=weight_field, data_source=data_source) buf = prj.to_frb(width, self.nx, center=self.center)["intensity"] else: if data_source is None: source = ds else: source = data_source buf = off_axis_projection(source, self.center, normal, width, (self.nx, self.ny), "intensity", north_vector=north_vector, no_ghost=no_ghost, method=method, weight=weight_field) sto.result_id = i sto.result = buf.swapaxes(0, 1) 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 is_sequence(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 off_axis(self, L, center="c", width=(1.0, "unitary"), depth=(1.0, "unitary"), nx=800, nz=800, north_vector=None, no_ghost=False, 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 : tuple or a float. Width can have four different formats to support windows with variable x and y widths. They are: ================================== ======================= format example ================================== ======================= (float, string) (10,'kpc') ((float, string), (float, string)) ((10,'kpc'),(15,'kpc')) float 0.2 (float, float) (0.2, 0.3) ================================== ======================= For example, (10, 'kpc') requests a plot window that is 10 kiloparsecs wide in the x and y directions, ((10,'kpc'),(15,'kpc')) requests a window that is 10 kiloparsecs wide along the x axis and 15 kiloparsecs wide along the y axis. In the other two examples, code units are assumed, for example (0.2, 0.3) requests a plot that has an x width of 0.2 and a y width of 0.3 in code units. If units are provided the resulting plot axis labels will use the supplied units. depth : A tuple or a float 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 nx : integer, optional The dimensions on a side of the projection image. nz : integer, optional Deprecated, this is still in the function signature for API compatibility north_vector : a sequence of floats A vector defining the 'up' direction in the plot. This option sets the orientation of the slicing plane. If not set, an arbitrary grid-aligned north-vector is chosen. 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 source : yt.data_objects.data_containers.YTSelectionContainer, optional If specified, this will be the data source used for selecting regions to project. Examples -------- >>> L = np.array([0.5, 1.0, 0.75]) >>> szprj.off_axis(L, center="c", width=(2.0, "Mpc")) """ wd = self.ds.coordinates.sanitize_width(L, width, depth) w = tuple(el.in_units('code_length').v for el in wd) ctr, dctr = self.ds.coordinates.sanitize_center(center, L) res = (nx, nx) if source is None: source = self.ds 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(source, ctr, L, w, res, "density", north_vector=north_vector, no_ghost=no_ghost) Te = off_axis_projection(source, ctr, L, w, res, "t_sz", north_vector=north_vector, no_ghost=no_ghost) / dens bpar = off_axis_projection(source, ctr, L, w, res, "beta_par", north_vector=north_vector, no_ghost=no_ghost) / dens omega1 = off_axis_projection(source, ctr, L, w, res, "t_squared", north_vector=north_vector, no_ghost=no_ghost) / dens omega1 = omega1 / (Te * Te) - 1. if self.high_order: bperp2 = off_axis_projection(source, ctr, L, w, res, "beta_perp_squared", north_vector=north_vector, no_ghost=no_ghost) / dens sigma1 = off_axis_projection(source, ctr, L, w, res, "t_beta_par", north_vector=north_vector, no_ghost=no_ghost) / dens sigma1 = sigma1 / Te - bpar kappa1 = off_axis_projection(source, ctr, L, w, res, "beta_par_squared", north_vector=north_vector, no_ghost=no_ghost) / 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 = (-0.5 * wd[0], 0.5 * wd[0], -0.5 * wd[1], 0.5 * wd[1]) self.dx = wd[0] / nx self.dy = wd[1] / 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"))