Spectrum

Spectrum

The Spectrum class — a single observed spectrum.

class unite.spectrum.spectrum.Spectrum(low, high, flux, error, disperser, *, name='')[source]

Bases: object

A single observed spectrum.

A spectrum is defined by pixel bin edges (low, high), flux and error arrays, and a Disperser. Calibration parameters live on the disperser as CalibParam tokens (disperser.r_scale, disperser.flux_scale, disperser.pix_offset).

Use from_arrays(), from_DJA(), or from_sdss_fits() to construct spectra from arrays or instrument-native file formats.

Parameters:
lowastropy.units.Quantity

Lower wavelength edges of each pixel. Must be 1-D with wavelength (length) dimensions.

highastropy.units.Quantity

Upper wavelength edges of each pixel. Same shape and compatible units as low.

fluxastropy.units.Quantity

Flux density values per pixel. Must be 1-D with the same length as low and carry spectral flux density per wavelength units (f_lambda, e.g. erg / s / cm^2 / Angstrom).

errorastropy.units.Quantity

Flux density uncertainty per pixel. Must be 1-D with the same length as low and carry units compatible with flux.

disperserDisperser

Instrumental disperser associated with this spectrum. Carries any calibration tokens (r_scale, flux_scale, pix_offset).

namestr, optional

Human-readable label (e.g. 'G235H'). Used in repr and for constructing numpyro site names. Defaults to disperser.name.

Raises:
TypeError

If low / high are not Quantities with wavelength dimensions, if flux / error are not Quantities with f_lambda dimensions, or if disperser is not a Disperser instance.

ValueError

If array shapes are inconsistent or lowhigh for any pixel.

Parameters:
  • low (u.Quantity)

  • high (u.Quantity)

  • flux (u.Quantity)

  • error (u.Quantity)

  • disperser (Disperser)

  • name (str)

property low: Array

Lower pixel-edge wavelengths in the disperser’s unit.

property high: Array

Upper pixel-edge wavelengths in the disperser’s unit.

property wavelength: Array

Pixel-center wavelengths (mean of low and high edges).

property edges: Array

Unique sorted pixel edges, length E = npix + num_gaps + 1.

Contiguous pixels share an edge (one entry per shared boundary); chip gaps contribute two entries — high of the pixel before the gap and low of the pixel after. Use together with keep_mask to recover per-pixel quantities from edge-evaluated cumulative arrays via diff + masking.

property keep_mask: Array

Boolean mask of length E - 1 selecting real-pixel diffs.

jnp.diff(edges)[keep_mask] gives the per-pixel widths; the masked-out entries span inter-pixel gaps and should be discarded from any edge-cumulative-then-diff reduction.

property midpoints: Array

Midpoint of each (edges[i], edges[i+1]) pair, length E - 1.

Entries where keep_mask is False fall inside chip gaps and should be ignored.

property widths: Array

diff(edges), length E - 1.

Entries where keep_mask is False are inter-pixel gap widths, not pixel widths, and should be ignored.

property pixel_idx: Array

Indices into the length-(E - 1) axis selecting real pixels in order.

Convenience accessor equivalent to jnp.where(keep_mask)[0] but cached at construction time as a concrete array.

property flux: Array

Observed flux values per pixel.

property error: Array

Flux uncertainty per pixel.

property npix: int

Number of pixels.

property unit: UnitBase

Wavelength unit inherited from the disperser.

property flux_unit: UnitBase

Flux density unit (f_lambda).

property error_scale: Array | float

Multiplicative scale factor applied to errors.

Can be a scalar (applied uniformly) or a per-pixel array.

property scaled_error: Array

Flux uncertainty scaled by error_scale.

property scale_diagnostic

Continuum-fit diagnostics from the most recent compute_scales() call.

Returns a SpectrumScaleDiagnostic holding the line mask, the fitted continuum model array, and per-region fit details. None if compute_scales() has not been called yet.

The spectrum’s own wavelength, flux, error, and unit attributes provide the full picture alongside this diagnostic.

Examples

>>> diag = spectrum.scale_diagnostic
>>> if diag is not None:
...     cont = diag.continuum_model   # NaN outside fitted regions
...     mask = diag.line_mask         # True where a pixel was excluded
property wavelength_range: tuple[float, float]

(min, max) wavelength in the disperser’s unit.

property has_calibration_priors: bool

True if any calibration token is set on the disperser.

covers(low, high)[source]

Return True if any pixel overlaps [low, high].

Return type:

bool

Parameters:
lowfloat

Lower bound in the disperser’s unit.

highfloat

Upper bound in the disperser’s unit.

Parameters:
pixel_mask(low, high)[source]

Return a boolean array selecting pixels that overlap [low, high].

Return type:

Array

Parameters:
lowfloat

Lower bound in the disperser’s unit.

highfloat

Upper bound in the disperser’s unit.

Returns:
jnp.ndarray

Boolean array of shape (npix,).

Parameters:

Spectra Collection

Spectrum collection and scale diagnostics.

class unite.spectrum.collection.RegionDiagnostic(obs_low, obs_high, in_region, good_mask, model_on_region, chi2_red, fit_params=<factory>)[source]

Bases: object

Diagnostics for a single continuum region fit.

Attributes:
obs_lowfloat

Observed-frame lower bound of the region (disperser’s unit).

obs_highfloat

Observed-frame upper bound of the region (disperser’s unit).

in_regionjnp.ndarray

Boolean mask of shape (npix,) selecting all pixels inside the region bounds.

good_maskjnp.ndarray

Boolean mask of shape (npix,) selecting pixels used for fitting (in_region & ~line_mask).

model_on_regionjnp.ndarray or None

Best-fit continuum model evaluated at the in_region pixels. None if the fit failed (too few unmasked pixels).

chi2_redfloat or None

Reduced chi-squared of the fit, or None if the fit failed.

fit_paramsdict of str to float

Best-fit parameter dict returned by fit_continuum_form(). Empty if the fit failed.

Parameters:
obs_low: float
obs_high: float
in_region: Array
good_mask: Array
model_on_region: Array | None
chi2_red: float | None
fit_params: dict
class unite.spectrum.collection.ScaleDiagnosticList(iterable=(), /)[source]

Bases: list

A list of SpectrumScaleDiagnostic objects that also supports lookup by spectrum name.

Inherits all standard list behaviour. Additionally, diags["my_spectrum"] returns the first diagnostic whose name matches the given string, raising KeyError if no match is found.

class unite.spectrum.collection.SpectrumScaleDiagnostic(name, line_mask, continuum_model, regions)[source]

Bases: object

Diagnostics for one spectrum produced by Spectra.compute_scales().

Stored directly on the spectrum via scale_diagnostic so callers always have the spectrum’s own wavelength, flux, and error to hand — those fields are not duplicated here.

Attributes:
namestr

Spectrum name (from name).

line_maskjnp.ndarray

Boolean mask of shape (npix,); True where a pixel was excluded because it lies near an emission line.

continuum_modeljnp.ndarray

Full-spectrum continuum model array of shape (npix,). Pixels not covered by any continuum region are NaN.

regionslist of RegionDiagnostic

Per-region fit diagnostics (one entry per region that overlaps this spectrum).

Parameters:
name: str
line_mask: Array
continuum_model: Array
regions: list
class unite.spectrum.collection.Spectra(spectra, redshift=0.0, canonical_unit=None)[source]

Bases: object

Collection of spectra with coverage filtering.

Wraps one or more Spectrum objects together with a systemic redshift estimate. The main role of this class is filter_config(), which drops lines and continuum regions not covered by any spectrum.

Parameters:
spectrasequence of Spectrum

Individual spectrum objects. Must not be empty.

redshiftfloat

Systemic redshift estimate used for rest-frame → observed-frame conversion during coverage checks. Default 0.0.

canonical_unitastropy.units.UnitBase, optional

Wavelength unit used for all internal model computations (line centers, continuum bounds, pixel edges). Defaults to the first spectrum’s disperser unit. Override this if you want a specific unit regardless of spectrum order.

Raises:
ValueError

If spectra is empty or contains non-Spectrum objects.

Parameters:
  • spectra (Sequence[Spectrum])

  • redshift (float)

  • canonical_unit (u.UnitBase | None)

property redshift: float

Systemic redshift estimate.

property canonical_unit: UnitBase

Canonical wavelength unit used for all internal model computations.

Defaults to the first spectrum’s wavelength unit. Can be overridden via the canonical_unit constructor parameter.

property line_scale: Quantity | None

Characteristic line flux scale (integrated flux), or None.

property continuum_scale: Quantity | None

Characteristic continuum flux density scale, or None.

property scale_diagnostics: ScaleDiagnosticList | None

Per-spectrum diagnostics from the most recent compute_scales() call.

Returns a ScaleDiagnosticList of SpectrumScaleDiagnostic objects (one per spectrum). Supports both integer indexing and lookup by spectrum name (e.g. diags["my_spectrum"]). None if compute_scales() has not been called yet.

The diagnostic for an individual spectrum is also available via scale_diagnostic, which is the preferred access pattern when iterating over spectra:

for s in spectra:
    diag = s.scale_diagnostic
    # s.wavelength / s.flux / s.error available directly
compute_scales(line_config, continuum_config=None, *, line_mask_width=<Quantity 1000. km / s>, box_width=<Quantity 1000. km / s>, error_scale=False)[source]

Estimate characteristic flux scales for lines and continuum.

The algorithm:

  1. Mask pixels near emission lines (using line_mask_fwhm, a full FWHM convolved in quadrature with the local LSF).

  2. Fit a low-order polynomial to the unmasked pixels in each continuum region.

  3. Estimate the line scale as peak_above_continuum * line_width where the peak is measured relative to the fitted continuum.

  4. Estimate the continuum scale as the maximum median |flux| across continuum regions (after masking lines).

  5. Optionally compute per-region error scale factors (sqrt(chi2_red)) and store them as per-pixel arrays on each Spectrum.

Both flux scales are stored as Quantity objects: integrated flux for line_scale and flux density for continuum_scale.

Parameters:
line_configLineConfiguration

Line configuration.

continuum_configContinuumConfiguration, optional

Continuum configuration. If None, only line scale is computed (without continuum subtraction).

max_fwhmastropy.units.Quantity

Maximum expected intrinsic line FWHM (full width). Must have velocity units. Default 1000 km/s.

line_mask_fwhmastropy.units.Quantity

Full FWHM used for masking lines when fitting continuum. Must have velocity units. Default 1000 km/s.

error_scalebool

If True, compute per-region error scale factors from the reduced chi-squared of the continuum fit residuals and store them as per-pixel arrays on each spectrum via error_scale. Default False.

:rtype: :sphinx_autodoc_typehints_type:`:py:obj:`None``
Parameters:
Return type:

None

prepare(line_config, continuum_config=None, *, linedet_width=<Quantity 1000. km / s>, drop_empty_regions=True)[source]

Filter configs for coverage and optionally drop empty continuum regions.

Calls filter_config() to remove lines and continuum regions not covered by any spectrum, then optionally drops continuum regions that contain no emission lines. Stores the filtered configs on this object.

Return type:

tuple[LineConfiguration, ContinuumConfiguration | None]

Parameters:
line_configLineConfiguration

Line configuration.

continuum_configContinuumConfiguration, optional

Continuum configuration.

linedet_widthastropy.units.Quantity

Detection width. Must have velocity units. Default 1000 km/s.

drop_empty_regionsbool

If True (default), drop continuum regions that do not contain any filtered line (in rest frame).

Returns:
filtered_linesLineConfiguration
filtered_continuumContinuumConfiguration or None
Parameters:
property is_prepared: bool

True if prepare() has been called.

property prepared_line_config: LineConfiguration | None

Filtered line configuration from prepare(), or None.

property prepared_cont_config: ContinuumConfiguration | None

Filtered continuum configuration from prepare(), or None.

filter_config(line_config, continuum_config=None, *, linedet_width=<Quantity 1000. km / s>)[source]

Drop lines and continuum regions not covered by any spectrum.

Each line’s rest-frame wavelength is shifted to the observed frame using redshift, then padded by linedet_width to form a detection window. A line is kept if any spectrum partially overlaps that window. Continuum regions are checked the same way.

Return type:

tuple[LineConfiguration, ContinuumConfiguration | None]

Parameters:
line_configLineConfiguration

Line configuration to filter.

continuum_configContinuumConfiguration, optional

Continuum configuration to filter. None is passed through.

linedet_widthastropy.units.Quantity

Detection width. Must have velocity units. Default 1000 km/s.

Returns:
filtered_linesLineConfiguration
filtered_continuumContinuumConfiguration or None
Parameters:

Loaders

Spectrum loader functions.

Convenience functions for constructing Spectrum objects from pre-loaded arrays or instrument-native file formats.

All loaders are re-exported from unite.spectrum:

from unite.spectrum import from_arrays, from_edges, from_centers
from unite.spectrum import from_DJA, from_sdss_fits, from_desi_fits
unite.spectrum.loaders.from_arrays(*, low=None, high=None, center=None, flux, error, disperser, mask=None, name='')[source]

Construct a Spectrum from pre-loaded arrays.

All arguments are keyword-only. Pixel boundaries may be supplied either as explicit bin edges (low + high) or as pixel centres (center), but not both. Use from_edges() or from_centers() for a positional-argument interface.

Return type:

Spectrum

Parameters:
lowastropy.units.Quantity, optional

Lower wavelength edge of each pixel. Required when center is not given. Must be 1-D with wavelength (length) dimensions.

highastropy.units.Quantity, optional

Upper wavelength edge of each pixel. Required when center is not given. Same shape and compatible units as low.

centerastropy.units.Quantity, optional

Pixel-centre wavelengths. Required when low / high are not given. Pixel edges are derived via numpy.gradient(), so this path is most accurate for gapless, reasonably uniform grids. For spectra with detector gaps or non-uniform spacing, supply low and high directly.

fluxastropy.units.Quantity

Flux density values per pixel (f_lambda). Must be 1-D with the same length as the wavelength arrays.

errorastropy.units.Quantity

Flux density uncertainty per pixel. Same length and compatible units as flux.

disperserDisperser

The disperser associated with this spectrum. Carries any calibration tokens (r_scale, flux_scale, pix_offset).

masknumpy.ndarray, optional

Boolean bad-pixel mask of shape (npix,). True marks a pixel as bad (excluded); False keeps it. Follows the same convention as numpy.ma.MaskedArray. None (default) keeps all pixels.

namestr, optional

Human-readable label. Defaults to disperser.name.

Returns:
Spectrum
Raises:
ValueError

If both center and low / high are provided, if only one of low / high is provided, if neither center nor low / high are provided, or if mask is not 1-D or its length does not match npix.

Parameters:
unite.spectrum.loaders.from_edges(low, high, flux, error, disperser, *, mask=None, name='')[source]

Construct a Spectrum from pixel bin edges.

Positional-argument convenience wrapper around from_arrays() for the common case where pixel bin edges are already known.

Return type:

Spectrum

Parameters:
lowastropy.units.Quantity

Lower wavelength edge of each pixel. Must be 1-D with wavelength (length) dimensions.

highastropy.units.Quantity

Upper wavelength edge of each pixel. Same shape and compatible units as low.

fluxastropy.units.Quantity

Flux density values per pixel (f_lambda). Must be 1-D with the same length as low.

errorastropy.units.Quantity

Flux density uncertainty per pixel. Same length and compatible units as flux.

disperserDisperser

The disperser associated with this spectrum. Carries any calibration tokens (r_scale, flux_scale, pix_offset).

masknumpy.ndarray, optional

Boolean bad-pixel mask of shape (npix,). True marks a pixel as bad (excluded); False keeps it. None (default) keeps all pixels.

namestr, optional

Human-readable label. Defaults to disperser.name.

Returns:
Spectrum
Parameters:
unite.spectrum.loaders.from_centers(center, flux, error, disperser, *, mask=None, name='')[source]

Construct a Spectrum from pixel-centre wavelengths.

Positional-argument convenience wrapper around from_arrays() for the common case where only pixel centres are available. Pixel bin edges are derived via numpy.gradient(), so this path is most accurate for gapless, reasonably uniform grids. For spectra with detector gaps or non-uniform spacing, supply low and high directly via from_edges().

Return type:

Spectrum

Parameters:
centerastropy.units.Quantity

Pixel-centre wavelengths. Must be 1-D with wavelength (length) dimensions.

fluxastropy.units.Quantity

Flux density values per pixel (f_lambda). Must be 1-D with the same length as center.

errorastropy.units.Quantity

Flux density uncertainty per pixel. Same length and compatible units as flux.

disperserDisperser

The disperser associated with this spectrum. Carries any calibration tokens (r_scale, flux_scale, pix_offset).

masknumpy.ndarray, optional

Boolean bad-pixel mask of shape (npix,). True marks a pixel as bad (excluded); False keeps it. None (default) keeps all pixels.

namestr, optional

Human-readable label. Defaults to disperser.name.

Returns:
Spectrum
Parameters:
unite.spectrum.loaders.from_DJA(path, disperser, *, name='', cache=False)[source]

Construct a Spectrum from a DJA FITS file.

Reads a NIRSpec x1d spectrum from the Dawn JWST Archive (DJA) format. Any Disperser is accepted; a built-in NIRSpec disperser or a GenericDisperser are both valid.

Return type:

Spectrum

Parameters:
pathstr or Path

Local path or URL to a NIRSpec x1d FITS file.

disperserDisperser

The disperser associated with this spectrum.

namestr, optional

Human-readable label. Defaults to disperser.name.

cachebool, optional

Whether to use astropy’s caching when fetching a remote file. Defaults to False.

Returns:
Spectrum
Raises:
FileNotFoundError

If path does not exist.

KeyError

If the expected FITS extensions or columns are not found.

Parameters:
unite.spectrum.loaders.from_sdss_fits(path, disperser, *, name='', cache=False)[source]

Construct a Spectrum from an SDSS FITS file.

Reads a standard SDSS spec-*.fits file (DR7-DR17 format). The coadded spectrum is read from the COADD HDU. The disperser’s internal wavelength and resolving-power grids are updated from the loglam and wdisp columns in the file.

Return type:

Spectrum

Parameters:
pathstr or Path

Path to an SDSS spec FITS file.

disperserSDSSDisperser

The SDSS disperser for this spectrum. Its internal wavelength grid and R(λ) curve will be updated from the FITS data. Must be an SDSSDisperser instance.

namestr, optional

Human-readable label. Defaults to disperser.name.

cachebool, optional

Whether to use astropy’s caching when reading the file. Defaults to False.

Returns:
Spectrum
Raises:
TypeError

If disperser is not an SDSSDisperser.

FileNotFoundError

If path does not exist.

KeyError

If the expected columns are not found.

Parameters:
unite.spectrum.loaders.from_desi_fits(path, *, dispersers=None, arms=('B', 'R', 'Z'), index=0, name='', cache=False)[source]

Construct Spectrum objects from a DESI FITS file.

DESI spectra are split across three spectrograph arms (B, R, Z). Each arm is returned as a separate Spectrum so that unite’s coverage-filtering handles the ~40-100 Angstrom overlaps between arms naturally. Wrap the result in a Spectra collection:

spectra = Spectra(from_desi_fits('spectra.fits'), redshift=1.29)

The resolving power R(λ) is derived from the banded LSF resolution matrix stored in the FITS file using the Gaussian second-moment method (assumes a Gaussian LSF, appropriate for DESI).

Return type:

list[Spectrum]

Parameters:
pathstr or Path

Path to a DESI spectra-*.fits file.

dispersersdict, optional

Pre-constructed DESIDisperser instances keyed by upper-case arm letter ('B', 'R', 'Z'). Useful when calibration tokens (RScale, FluxScale, PixOffset) need to be attached before loading. Missing arms are auto-created.

armssequence of {‘B’, ‘R’, ‘Z’}, optional

Which arms to load. Defaults to all three. Arms absent from the file emit a UserWarning and are skipped.

indexint, optional

Index of the spectrum to extract from the file. DESI coadd files may contain multiple spectra. Defaults to 0.

namestr, optional

Base label for each arm’s spectrum. Each arm is named '{name}_{arm.lower()}' when name is non-empty, otherwise just the lower-case arm letter ('b', 'r', 'z').

cachebool, optional

Unused; kept for API consistency with other loaders.

Returns:
list of Spectrum

One entry per successfully loaded arm, in the order given by arms.

Raises:
IndexError

If index is out of range for the number of spectra in the file.

ValueError

If an element of arms is not one of 'B', 'R', 'Z'.

Parameters: