Source code for unite.instrument.sdss.disperser

"""SDSS spectrograph disperser implementation.

Provides :class:`SDSSDisperser`, a concrete
:class:`~unite.instrument.base.Disperser` for SDSS optical spectra.
The resolving power *R(λ)* is derived from the ``wdisp`` column
(wavelength dispersion per pixel, in Angstroms) of standard SDSS
``spec-*.fits`` files at load time via
:func:`~unite.instrument.from_sdss_fits`.

Before data is loaded, the disperser can be constructed with
default or placeholder R values, allowing calibration tokens
to be configured and the disperser configuration to be serialized.

Examples
--------
>>> from unite.instrument.sdss import SDSSDisperser
>>> d = SDSSDisperser()
>>> d.unit
Unit("Angstrom")
"""

from __future__ import annotations

import jax.numpy as jnp
from astropy import units as u
from jax.typing import ArrayLike

from unite.instrument.base import Disperser, FluxScale, PixOffset, RScale


[docs] class SDSSDisperser(Disperser): """Disperser for SDSS optical spectra. The SDSS spectrographs use a log-linear wavelength grid. The resolving power and linear dispersion are set from data at spectrum load time (:func:`~unite.instrument.from_sdss_fits`), but the disperser can also be pre-constructed with calibration tokens for serialization. Parameters ---------- wavelength : ArrayLike, optional Pixel-center wavelengths in Angstroms. When not provided, :meth:`R` and :meth:`dlam_dpix` return placeholder values (constant R=2000, dlam_dpix=1.0). wdisp : ArrayLike, optional Wavelength dispersion per pixel (Angstroms/pixel) from the SDSS ``wdisp`` column. Same length as *wavelength*. The resolving power is computed as ``R(λ) = λ / (2.355 * wdisp)`` (since ``wdisp`` is sigma in wavelength units per pixel, and FWHM = 2.355 * sigma). name : str, optional Human-readable label. Defaults to ``'SDSS'``. r_scale : RScale, optional Token for the resolving-power scale. flux_scale : FluxScale, optional Token for the flux normalisation. pix_offset : PixOffset, optional Token for the pixel shift. """ def __init__( self, name: str = '', r_scale: RScale | None = None, flux_scale: FluxScale | None = None, pix_offset: PixOffset | None = None, ) -> None: super().__init__( unit=u.AA, name=name or 'SDSS', r_scale=r_scale, flux_scale=flux_scale, pix_offset=pix_offset, ) # Placeholder grids — overwritten by from_sdss_fits() at load time. self._wavelength_grid: jnp.ndarray = jnp.array([3800.0, 9200.0], dtype=float) self._R_grid: jnp.ndarray = jnp.array([2000.0, 2000.0], dtype=float) self._dlam_dpix_grid: jnp.ndarray = jnp.array([1.0, 1.0], dtype=float)
[docs] def R(self, wavelength: ArrayLike) -> ArrayLike: """Return the resolving power at the given wavelengths (Angstrom). Parameters ---------- wavelength : ArrayLike Wavelength values in Angstroms. Returns ------- ArrayLike Resolving power *R* at each wavelength. """ return jnp.interp(wavelength, self._wavelength_grid, self._R_grid)
[docs] def dlam_dpix(self, wavelength: ArrayLike) -> ArrayLike: """Return *dλ/dpix* in Angstrom/pixel. Parameters ---------- wavelength : ArrayLike Wavelength values in Angstroms. Returns ------- ArrayLike Linear dispersion at each wavelength. """ return jnp.interp(wavelength, self._wavelength_grid, self._dlam_dpix_grid)
def __repr__(self) -> str: """Return a readable string representation.""" return f'SDSSDisperser(name={self.name!r})'