def test_oversampled_gridding(): """ Integration test of the convolve_to_grid function with oversampling Mostly tests same functionality as ``test_kernel_caching``. """ # Let's grid a triangle function n_image = 8 support = 2 uv = np.array([(1.0, 0.0), (1.3, 0.0), (.01, -1.32), ]) vis = np.ones(len(uv), dtype=np.float_) vis_weights=np.ones_like(vis) kernel_func = conv_funcs.Triangle(2.0) vis_grid, sample_grid = convolve_to_grid(kernel_func, support=support, image_size=n_image, uv=uv, vis=vis, vis_weights=vis_weights, exact=False, oversampling=9 ) # simplification true since weights are all 1: assert vis_grid.sum() == vis.sum()
def test_triangle(): # Now let's try a triangle function, larger support this time: n_image = 8 support = 2 uv = np.array([(1.0, 0.0)]) subpix_offset = np.array([(0.1, -0.15)]) vis = np.ones(len(uv), dtype=np.float_) # offset = np.array([(0.0, 0.0)]) uv += subpix_offset kernel_func = conv_funcs.Triangle(2.0) grid, _ = convolve_to_grid(kernel_func, support=support, image_size=n_image, uv=uv, vis=vis, oversampling=None) kernel = Kernel(kernel_func=kernel_func, support=support, offset=subpix_offset[0], oversampling=1) assert grid.sum() == vis.sum() # uv location of sample is 1, therefore pixel index = n_image/2 +1 xrange = slice(n_image / 2 + 1 - support, n_image / 2 + 1 + support + 1) yrange = slice(n_image / 2 - support, n_image / 2 + support + 1) assert (grid[yrange, xrange] == (kernel.array / kernel.array.sum())).all()
def test_triangle_func(): triangle2 = conv_funcs.Triangle(half_base_width=2.0) io_pairs = np.array([ [0.0, 1.0], [1.0, 0.5], [2.0, 0.0], [2.000001, 0.0], [100, 0.0], [0.1, 0.95], [0.5, 0.75], ]) check_function_results_close(triangle2, io_pairs)
def test_stepped_vs_exact_convolution(): # We use a triangle to compare, since even a tiny pixel offset should # result in differing values when using exact convolution, # this makes it easier to verify that the 'stepped' kernel is behaving # as expected. n_image = 8 support = 3 kernel_func = conv_funcs.Triangle(half_base_width=2.5) oversampling = 5 # Choose sub-pixel steps that align with oversampling grid: steps = np.array([-0.4, 0.2, 0.0, 0.2, 0.4]) substeps = np.linspace(-0.099999, 0.099999, num=50) kernel_cache = populate_kernel_cache(kernel_func=kernel_func, support=support, oversampling=oversampling) for x_offset in steps: offset = (x_offset, 0.0) aligned_exact_kernel = Kernel(kernel_func=kernel_func, support=support, offset=offset) aligned_cache_idx = calculate_oversampled_kernel_indices( offset, oversampling) cached_kernel = kernel_cache[tuple(aligned_cache_idx)] # Check that for oversampling-grid aligned positions, cache == exact assert (aligned_exact_kernel.array == cached_kernel.array).all() # Now check the results for non-aligned positions for sub_offset in substeps: offset = (x_offset + sub_offset, 0.0) if sub_offset != 0.0: unaligned_exact_kernel = Kernel(kernel_func=kernel_func, support=support, offset=offset) unaligned_cache_idx = calculate_oversampled_kernel_indices( offset, oversampling) # We expect to return the same kernel as nearest grid-point assert (unaligned_cache_idx == aligned_cache_idx).all()
def make_image_map_fits(vis_path, output_dir, image_size, cell_size): out_path = derive_out_path(vis_path, output_dir, out_extension='.pyimg') uvw_in_wavelengths = casa_io.get_uvw_in_lambda(vis_path) stokes_i = casa_io.get_stokes_i_vis(vis_path) image_size = int(image_size.to(u.pix).value) grid_pixel_width_in_wavelengths = 1.0 / (cell_size.to(u.rad) * image_size) uvw_in_pixels = uvw_in_wavelengths / grid_pixel_width_in_wavelengths uv_in_pixels = uvw_in_pixels[:, :2] kernel = kfuncs.Triangle(1.5) uvgrid = exact_convolve_to_grid(kernel, support=2, image_size=image_size, uv=uv_in_pixels, vis=stokes_i) image = np.fft.ifftshift(np.fft.fft2(np.fft.fftshift(uvgrid))) return image
def test_regular_sampling_triangle(): testfunc = conv_funcs.Triangle(half_base_width=1.5) support = 2 oversampling = 1 kernel_value_at_1pix = 1. - 1. / 1.5 kv1 = kernel_value_at_1pix kv1sq = kv1 * kv1 # Map subpixel offset to expected results expected_results = {} # No offset expected_results[(0., 0.)] = np.array([[0., 0., 0., 0., 0.], [0., kv1sq, kv1, kv1sq, 0.], [0., kv1, 1., kv1, 0.], [0., kv1sq, kv1, kv1sq, 0.], [0., 0., 0., 0., 0.]]) # .5 pix offset right: kv_half = 1. - 0.5 / 1.5 expected_results[(0.5, 0.)] = np.array( [[0., 0., 0., 0., 0.], [0., 0., kv_half * kv1, kv_half * kv1, 0.], [0., 0., kv_half, kv_half, 0.], [0., 0., kv_half * kv1, kv_half * kv1, 0.], [0., 0., 0., 0., 0.]]) for offset, expected_array in expected_results.items(): k = Kernel( kernel_func=testfunc, support=support, offset=offset, oversampling=oversampling, normalize=False, ) assert (k.array == expected_array).all()
def test_kernel_caching(): """ Test generation of cached (offset) kernels, and demonstrate correct usage. In this test, we assume an oversampling of 5, resulting in step-widths of 0.2 regular pixels. We then iterate through a bunch of possible sub-pixel offsets, checking that we pick the nearest (closest to exact-positioned) cached kernel correctly. """ # We use a triangle to compare, since even a tiny pixel offset should # result in differing values when using exact convolution, # this makes it easier to verify that the 'stepped' kernel is behaving # as expected. n_image = 8 support = 3 kernel_func = conv_funcs.Triangle(half_base_width=2.5) oversampling = 5 # Choose sub-pixel steps that align with oversampling grid: steps = np.array([-0.4, 0.2, 0.0, 0.2, 0.4]) substeps = np.linspace(-0.099999, 0.099999, num=15) kernel_cache = populate_kernel_cache( kernel_func=kernel_func, support=support, oversampling=oversampling) for x_offset in steps: offset = (x_offset, 0.0) aligned_exact_kernel = Kernel(kernel_func=kernel_func, support=support, offset=offset) # Generate an index into the kernel-cache at the precise offset # (i.e. a multiple of 0.2-regular-pixel-widths) aligned_cache_idx = calculate_oversampled_kernel_indices(offset, oversampling) cached_kernel = kernel_cache[tuple(aligned_cache_idx)] # Check that for oversampling-grid aligned positions, cache == exact assert (aligned_exact_kernel.array == cached_kernel.array).all() # Now check the results for non-aligned positions for sub_offset in substeps: offset = (x_offset + sub_offset, 0.0) if sub_offset != 0.0: unaligned_exact_kernel = Kernel(kernel_func=kernel_func, support=support, offset=offset) # Check that the irregular position resolves to the correct # nearby aligned position: unaligned_cache_idx = calculate_oversampled_kernel_indices( offset, oversampling) assert (unaligned_cache_idx == aligned_cache_idx).all() ## Demonstrate retrieval of the cached kernel: cached_kernel = kernel_cache[tuple(unaligned_cache_idx)] assert (aligned_exact_kernel.array == cached_kernel.array).all() ## Sanity check - we expect the exact-calculated kernel to ## be different by a small amount diff = ( aligned_exact_kernel.array - unaligned_exact_kernel.array) eps = 10e-9 assert not (np.fabs(diff) < eps).all()