regrid#

ctis.regrid(coordinates_input, coordinates_output, values_input, axis_wavelength, axis_position)[source]#

Conservatively resample a spectral cube from one spectral/spatial grid onto another.

The resampling is split into two independent conservative steps: a 1D conservative interpolation along the wavelength axis, followed by a 2D conservative interpolation along the two spatial axes. Separating the spectral and spatial resampling is much cheaper than a single 3D conservative regrid and is exact whenever the wavelength grid does not depend on spatial position (and vice versa), which is the usual case for a CTIS scene.

Each input voxel is weighted by its volume (the wavelength bin width times the solid angle subtended by each field pixel) before the conservative regridding and divided by the output voxel volume afterward, so the integral of the field is preserved and values_input is treated as a density (such as a spectral radiance) rather than a per-voxel total. Both steps use named_arrays.regridding.regrid() with method="conservative".

Parameters:
  • coordinates_input (AbstractSpectralPositionalVectorArray) – The wavelength and position of the vertices of each voxel of the input grid.

  • coordinates_output (AbstractSpectralPositionalVectorArray) – The wavelength and position of the vertices of each voxel of the output grid.

  • values_input (AbstractScalar) – The value in each voxel of the input grid, sampled on the voxel centers.

  • axis_wavelength (str) – The logical axis corresponding to changing wavelength coordinate. Shared by the input and output grids.

  • axis_position (tuple[str, str]) – The two logical axes corresponding to changing position coordinate. Shared by the input and output grids.

Return type:

AbstractScalarArray

Examples

Resample a random spectral cube onto a finer grid.

import matplotlib.pyplot as plt
import astropy.units as u
import astropy.visualization
import named_arrays as na
import ctis

# Define the vertices of the (fine) input grid.
coordinates_input = na.SpectralPositionalVectorArray(
    wavelength=na.linspace(500, 600, axis="wavelength", num=9) * u.nm,
    position=na.Cartesian2dVectorLinearSpace(
        start=-10 * u.arcsec,
        stop=+10 * u.arcsec,
        axis=na.Cartesian2dVectorArray("x", "y"),
        num=13,
    ),
)

# Define the vertices of the (coarser) output grid.
coordinates_output = na.SpectralPositionalVectorArray(
    wavelength=na.linspace(500, 600, axis="wavelength", num=5) * u.nm,
    position=na.Cartesian2dVectorLinearSpace(
        start=-10 * u.arcsec,
        stop=+10 * u.arcsec,
        axis=na.Cartesian2dVectorArray("x", "y"),
        num=7,
    ),
)

# Define a random cube sampled on the input voxel centers.
values_input = na.random.uniform(
    low=0,
    high=1,
    shape_random=dict(wavelength=8, x=12, y=12),
)

# Resample the cube onto the coarser output grid.
values_output = ctis.regrid(
    coordinates_input=coordinates_input,
    coordinates_output=coordinates_output,
    values_input=values_input,
    axis_wavelength="wavelength",
    axis_position=("x", "y"),
)

# Plot the input and output grids side by side, with wavelength
# represented by color. The resampling preserves the field density, so
# a shared normalization lets one colorbar describe both panels.
vmax = values_output.max()
wavelength_min = coordinates_input.wavelength.min()
wavelength_max = coordinates_input.wavelength.max()
with astropy.visualization.quantity_support():
    fig, ax = plt.subplots(
        ncols=3,
        gridspec_kw=dict(width_ratios=[0.45, 0.45, 0.1]),
        sharex=False,
        figsize=(9, 4),
        constrained_layout=True,
    )
    colorbar = na.plt.rgbmesh(
        coordinates_input,
        C=values_input,
        axis_wavelength="wavelength",
        vmin=0,
        vmax=vmax,
        wavelength_min=wavelength_min,
        wavelength_max=wavelength_max,
        ax=ax[0],
    )
    na.plt.rgbmesh(
        coordinates_output,
        C=values_output,
        axis_wavelength="wavelength",
        vmin=0,
        vmax=vmax,
        wavelength_min=wavelength_min,
        wavelength_max=wavelength_max,
        ax=ax[1],
    )
    na.plt.pcolormesh(
        C=colorbar,
        axis_rgb="wavelength",
        ax=ax[2],
    )
    ax[2].yaxis.tick_right()
    ax[2].yaxis.set_label_position("right")
    ax[0].set_title("input grid")
    ax[1].set_title("output grid")
../_images/ctis.regrid_0_0.png