Source code for skyscapes.disk.exovista

"""ExovistaDisk: port of legacy Disk -- wavelength-interpolated contrast cube."""

from __future__ import annotations

import interpax
from jaxtyping import Array

from .base import AbstractDisk


[docs] class ExovistaDisk(AbstractDisk): """Wavelength-interpolated 3D contrast cube loaded from ExoVista FITS. Attributes: pixel_scale_arcsec: Pixel scale [arcsec/pixel]. wavelengths_nm: 1-D wavelength grid [nm], shape ``(n_wl,)``. contrast_cube: Contrast cube, shape ``(n_wl, ny, nx)``. """ pixel_scale_arcsec: float wavelengths_nm: Array contrast_cube: Array _contrast_interp: interpax.CubicSpline def __init__( self, pixel_scale_arcsec: float, wavelengths_nm: Array, contrast_cube: Array, ): """Store geometry and pre-build the wavelength cubic spline.""" self.pixel_scale_arcsec = pixel_scale_arcsec self.wavelengths_nm = wavelengths_nm self.contrast_cube = contrast_cube self._contrast_interp = interpax.CubicSpline( wavelengths_nm, contrast_cube, axis=0 )
[docs] def surface_brightness( self, wavelength_nm: Array, time_jd: Array, incl_deg: Array, pa_deg: Array, ) -> Array: """Contrast map at the requested wavelength, shape ``(ny, nx)``. ``time_jd``, ``incl_deg``, and ``pa_deg`` are part of the AbstractDisk interface but ignored here: the cube is a single time snapshot with disk geometry already baked in by the loader. """ return self._contrast_interp(wavelength_nm)
[docs] def spatial_extent(self) -> tuple[float, float]: """Return ``(width_arcsec, height_arcsec)``.""" ny, nx = self.contrast_cube.shape[-2:] return (nx * self.pixel_scale_arcsec, ny * self.pixel_scale_arcsec)
[docs] def __repr__(self) -> str: """One-line summary of cube shape, pixel scale, and wavelength grid.""" n_wl = int(self.wavelengths_nm.shape[0]) ny, nx = self.contrast_cube.shape[-2:] wl_min = float(self.wavelengths_nm.min()) wl_max = float(self.wavelengths_nm.max()) return ( f"ExovistaDisk(loaded cube, " f"image: {ny}x{nx} @ {self.pixel_scale_arcsec} arcsec/px, " f"wl={wl_min:.0f}-{wl_max:.0f} nm ({n_wl} pts))" )