viscube package#

Submodules#

viscube.deapodization module#

viscube.deapodization.load_apodization_map(path: str) ndarray[source]#

Load only the apodization map from a .npz file created by save_apodization_map.

viscube.deapodization.make_apodization_1d(*, npix: int, delta_u: float, window_name: str | None = 'kaiser_bessel', window_kwargs: dict | None = None, window_fn: Callable | None = None, normalize: str = 'peak') ndarray[source]#

Build the 1D image-plane apodization profile implied by a separable UV gridding kernel sampled on the FFT grid.

Parameters:
  • npix (int) – FFT grid size.

  • delta_u (float) – UV-cell size of the final gridded plane, in wavelengths.

  • window_fn (window_name / window_kwargs /) – Same conventions as VisCube gridding.

  • normalize ({"peak", "center", None}) – Normalization applied to the 1D profile.

Returns:

apo_1d – Real-valued, fftshifted image-plane apodization profile.

Return type:

ndarray, shape (npix,)

viscube.deapodization.make_apodization_map(*, npix: int, delta_u: float, window_name: str | None = 'kaiser_bessel', window_kwargs: dict | None = None, window_fn: Callable | None = None, normalize: str = 'peak') ndarray[source]#

Build the 2D separable image-plane apodization map.

Returns:

apo_2d

Return type:

ndarray, shape (npix, npix)

viscube.deapodization.save_apodization_map(path: str, apodization_map: ndarray, *, npix: int | None = None, delta_u: float | None = None, window_name: str | None = None, window_kwargs: dict | None = None, normalize: str | None = None)[source]#

Save apodization map plus minimal metadata to a .npz file.

viscube.grid_cube module#

viscube.grid_cube.build_grid_centers(u_edges: ndarray, v_edges: ndarray) ndarray[source]#

Measurement Set conventions for grid centers.

viscube.grid_cube.grid_channel(uu_i: ndarray, vv_i: ndarray, vis_re_i: ndarray, vis_imag_i: ndarray, w_i: ndarray, u_edges: ndarray, v_edges: ndarray, window_fn, truncation_radius, uv_tree: cKDTree, grid_tree: cKDTree, pairs: Sequence[Sequence[int]], *, verbose_mean: int = 1, verbose_std: int = 2) Tuple[ndarray, ndarray, ndarray, ndarray, ndarray][source]#

Grid one frequency channel using your existing bin_data.

viscube.grid_cube.grid_cube_all_stats(*, frequencies: ndarray, uu: ndarray, vv: ndarray, vis_re: ndarray, vis_imag: ndarray, weight: ndarray, invvar_group_re: ndarray, invvar_group_im: ndarray, npix: int = 501, fov_arcsec: float | None = None, pad_uv: float = 0.0, window_name: str | None = 'kaiser_bessel', window_kwargs: dict | None = None, window_fn=None, p_metric: int = 1, std_p: int = 1, std_workers: int = 6, std_min_effective: int = 5, n_eff_mode: str = 'both') Tuple[ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray][source]#
viscube.grid_cube.grid_cube_all_stats_wbinned(*, frequencies: ndarray, uu: ndarray, vv: ndarray, ww: ndarray, vis_re: ndarray, vis_imag: ndarray, weight: ndarray, invvar_group_re: ndarray, invvar_group_im: ndarray, npix: int = 501, fov_arcsec: float | None = None, pad_uv: float = 0.0, w_bins: int | ndarray = 8, w_range: Tuple[float, float] | None = None, w_abs: bool = False, window_name: str | None = 'kaiser_bessel', window_kwargs: dict | None = None, window_fn: Callable | None = None, p_metric: int = 1, std_p: int = 1, std_workers: int = 6, std_min_effective: int = 5, tqdm_ncols: int = 200, n_eff_mode: str = 'both') Tuple[ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray][source]#

Grid complex visibilities into UVW-binned UV pixels using bin_data.

viscube.grid_cube.hermitian_augment(u0: ndarray, v0: ndarray, vis0: ndarray, w0: ndarray, sigma_re0: ndarray, sigma_im0: ndarray) Tuple[ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray][source]#
Hermitian augment:

(u, v, Re, Im, w, sigma_re, sigma_im) -> concat with (-u, -v, +Re, -Im, w, sigma_re, sigma_im)

Return type:

uu, vv, vis_re, vis_imag, w, sigma_re_aug, sigma_im_aug

viscube.grid_cube.load_and_mask(frequencies: ndarray, uu: ndarray, vv: ndarray, vis: ndarray, weight: ndarray, sigma_re: ndarray, sigma_im: ndarray, mask: ndarray) Tuple[ndarray, ndarray, ndarray, ndarray, ndarray, ndarray, ndarray][source]#

Apply per-channel mask and compact arrays. Returns frequencies, u0, v0, vis0, w0, sigma_re0, sigma_im0.

Assumes the number of valid visibilities is the same for every channel (as in your current implementation). If not, this should be changed to ragged lists.

viscube.grid_cube.make_uv_grid(uu: ndarray, vv: ndarray, npix: int, pad_uv: float, *, fov_arcsec: float | None = None, warn_crop: bool = True) Tuple[ndarray, ndarray, float, float][source]#

Build symmetric square uv grid; truncation_radius == delta_u.

Parameters:

fov_arcsec (float, optional) – Image-plane field of view in arcseconds. If provided, uv cell size is set by delta_u = 1 / fov_rad, where fov_rad = fov_arcsec / 206265.

Notes

Assumes u,v are in wavelengths. Then:
  • image-plane angle is radians,

  • Fourier dual spacing satisfies FOV ≈ 1/delta_u.

viscube.grid_cube.precompute_pairs(uu_i: ndarray, vv_i: ndarray, centers: ndarray, truncation_radius: float, *, p_metric: int = 1) Tuple[cKDTree, cKDTree, Sequence[Sequence[int]]][source]#

Build KD-trees and query neighbor pairs for a single channel.

viscube.grid_cube.uv_grid_to_fft_image_convention(arr_uv: ndarray) ndarray[source]#

Convert UV grid from [u, v] axis order to image/FFT-friendly [v, u] row/col order. Works for 2D or cubes with last two axes = (Nu, Nv).

viscube.gridder module#

viscube.gridder.bin_data(u, v, values, weights, invvar_group, bins, window_fn: Callable, truncation_radius, uv_tree: cKDTree, grid_tree: cKDTree, pairs: Sequence[Sequence[int]], statistics_fn='mean', verbose=0, window_kwargs: Dict | None = None, std_p: int = 1, std_workers: int = 6, std_min_effective: int = 5, std_expand_step: float = 0.1, collect_stats: bool = False, n_eff_mode: str = 'both')[source]#
Hybrid std behavior:
  • Normal pixels: empirical within-pixel scatter -> SE(mean)

  • Low-info pixels: propagated SE(mean) using invvar_group (per-visibility inverse variance)

Parameters:
  • invvar_group (ndarray or None) – Per-visibility inverse variance aligned with values (same length as u/v/values). Used ONLY in low-info std fallback.

  • n_eff_mode ({"geometric", "both"}) –

    Choice of effective sample size definition used consistently for both:

    1. the fallback trigger

    2. the normal-case SE(mean) correction

    • ”geometric”:

      n_eff = (sum imp)^2 / sum(imp^2) Uses kernel-only support / geometric weighting.

    • ”both”:

      n_eff = (sum local_w)^2 / sum(local_w^2) Uses full weights * kernel, i.e. incorporates both geometric interpolation weighting and measurement weighting.

Returns:

  • grid (ndarray) – Output gridded statistic.

  • If collect_stats is True – returns (grid, n_fallback)

viscube.sigma_per_baseline module#

viscube.sigma_per_baseline.mad_std(x: ndarray, axis=None) ndarray[source]#

Robust std estimate via MAD. For Gaussian: std ≈ 1.4826 * MAD.

Parameters:
  • x (ndarray) – Input array (can contain NaNs).

  • axis (int or tuple of ints, optional) – Axis along which to compute the robust std.

Returns:

std – Robust standard deviation estimate.

Return type:

ndarray

viscube.sigma_per_baseline.sigma_by_baseline_scan_time_diff(data: ndarray, mask: ndarray, time_row: ndarray, scan_row: ndarray, ant1_row: ndarray, ant2_row: ndarray, *, min_pairs: int = 8, sigma_floor: float = 1e-12) Tuple[ndarray, ndarray][source]#

Estimate per-visibility sigma separately for real and imaginary parts using time-differenced visibilities within groups defined by (scan, baseline).

Sigma is computed per-channel per-group, then assigned to all visibilities in that group.

Uses consecutive time differences:

diff = x[t+1] - x[t]

and converts diff-std to per-sample std via:

sigma = std(diff) / sqrt(2)

Parameters:
  • data (ndarray, complex, shape (nchan, nvis)) – Complex visibilities.

  • mask (ndarray, bool, shape (nchan, nvis)) – Valid-data mask.

  • time_row (ndarray, shape (nvis,)) – Time stamps per visibility row.

  • scan_row (ndarray, shape (nvis,)) – Scan number per visibility row.

  • ant1_row (ndarray, shape (nvis,)) – Antenna IDs defining baselines.

  • ant2_row (ndarray, shape (nvis,)) – Antenna IDs defining baselines.

  • min_pairs (int, optional) – Minimum number of valid consecutive pairs required per channel/group.

  • sigma_floor (float, optional) – Lower floor for sigma values.

Returns:

  • sigma_re (ndarray, shape (nchan, nvis)) – Estimated per-visibility sigma for real part.

  • sigma_im (ndarray, shape (nchan, nvis)) – Estimated per-visibility sigma for imaginary part.

viscube.windows module#

viscube.windows.casa_pswf_window(u, center: float, *, pixel_size: float = 0.015, m: int = 5, normalize: bool = True) ndarray[source]#

CASA/Schwab prolate-spheroidal gridding kernel (1-D separable form).

Parameters:
  • u (array-like)

  • center (float)

  • pixel_size (float)

  • m (int) – Total integer support (number of pixels). Typical choice: m=5.

  • normalize (bool) – Normalize so that peak value at center is 1.

Returns:

w

Return type:

ndarray

viscube.windows.kaiser_bessel_window(u, center: float, *, pixel_size: float = 0.015, m: int = 6, beta: float | None = None, normalize: bool = True) ndarray[source]#

1D Kaiser–Bessel interpolation window (separable in u, v).

Parameters:
  • u (array-like) – Coordinates (same units as center).

  • center (float) – Grid-cell center coordinate.

  • pixel_size (float) – Grid pixel size in uv units.

  • m (int) – Total support width in pixel units (covers m * pixel_size). Effective half-width = 0.5 * m * pixel_size.

  • beta (float, optional) –

    Shape parameter. If None, use a reasonable default for oversamp≈2:

    beta ≈ π * sqrt( (m/2)^2 - 0.8 )

  • normalize (bool) – If True, normalize so that window(center) == 1.

Returns:

w

Return type:

ndarray (same shape as u)

viscube.windows.pillbox_window(u, center: float, pixel_size: float = 0.015, m: int = 1)[source]#

Boxcar window with total width m * pixel_size.

viscube.windows.sinc_window(u, center: float, pixel_size: float = 0.015, m: int = 1)[source]#

Sinc window truncated by m * pixel_size (soft truncation).

Module contents#