Instrument Configuration & Spectral Basis#

Building the forward operator \(H\) requires two inputs: a description of how the grism disperses light across the detector (the instrument configuration), and a compact representation of the source spectral energy distributions in terms of a PCA basis (the eigenspectra basis). The classes on this page provide both.

InstrumentConfig#

InstrumentConfig reads a NIRISS WFSS configuration file and wraps the per-order GrismTrace objects that map (x, y) source positions to detector pixel positions, wavelengths, and sensitivity curves. It is a plain class (not a dataclass) because GrismTrace is not hashable.

Construct it with from_files(), passing the path to the configuration file and the wavelength range over which extraction should be performed. Once built, call get_trace() for any source at detector position (x, y) and a diffraction order to obtain the arrays of pixel positions, wavelengths, and sensitivity values needed to populate the forward operator.

EigenspectraBasis#

EigenspectraBasis stores a truncated PCA decomposition of a library of stellar SEDs. It is a frozen dataclass — all arrays are marked read-only via numpy.ndarray.setflags() — so it can be safely shared between operators and solvers without defensive copying.

Load it from a CSV of eigenspectra with from_csv(), specifying the wavelength range that matches the instrument configuration. A given source’s SED is approximated as \(\mathrm{SED}(\lambda) = \mathbf{E}(\lambda)\,\mathbf{c}\), where \(\mathbf{E}\) is the matrix of eigenspectra components and \(\mathbf{c}\) is the coefficient vector.

reconstruct() recovers the SED from coefficients; broadband_image() integrates the reconstructed SED over the sensitivity curves of an image filter to produce a predicted broadband map; integrated_weights() returns the pre-integrated weight matrix used internally by the operators.

Data Flow#

digraph instrument_basis {
    rankdir=LR;
    node [fontname="Helvetica", fontsize=11];

    subgraph cluster_instrument {
        label="InstrumentConfig";
        style=filled; fillcolor="#eef5ff"; color="#6baed6";

        conf_file [label="conf file", shape=parallelogram, style=filled, fillcolor="#f0f0f0"];
        from_files [label="from_files(\nwav_min, wav_max)", shape=box, style=filled, fillcolor="#cce5ff"];
        IC [label="InstrumentConfig", style=filled, fillcolor="#cce5ff"];
        get_trace [label="get_trace(x, y, order)", shape=box, style=filled, fillcolor="#cce5ff"];
        trace_out [label="(positions,\nwavelengths,\nsensitivities)", shape=parallelogram, style=filled, fillcolor="#f0f0f0"];

        conf_file -> from_files -> IC -> get_trace -> trace_out;
    }

    subgraph cluster_basis {
        label="EigenspectraBasis";
        style=filled; fillcolor="#efffef"; color="#74c476";

        eigen_csv [label="eigenspectra\nCSV", shape=parallelogram, style=filled, fillcolor="#f0f0f0"];
        from_csv  [label="from_csv(\nwav_min, wav_max)", shape=box, style=filled, fillcolor="#d4edda"];
        EB [label="EigenspectraBasis", style=filled, fillcolor="#d4edda"];
        reconstruct [label="reconstruct(c)", shape=box, style=filled, fillcolor="#d4edda"];
        bb_image    [label="broadband_image(\nc, image_shape)", shape=box, style=filled, fillcolor="#d4edda"];
        sed_out [label="SED\n(n_wav,)", shape=parallelogram, style=filled, fillcolor="#f0f0f0"];
        img_out [label="broadband map\n(H, W)", shape=parallelogram, style=filled, fillcolor="#f0f0f0"];

        eigen_csv -> from_csv -> EB;
        EB -> reconstruct -> sed_out;
        EB -> bb_image    -> img_out;
    }
}

API Reference#

class spectrex.InstrumentConfig(grism, filter_name, wavelengths, orders, sensitivity, trace)[source]#

Bases: object

Instrument configuration for a specific grism/filter combination.

All instrument data is loaded eagerly at construction via from_files(). No file I/O occurs after that point.

Parameters:
  • grism (str) – Grism identifier, e.g. "GR150R".

  • filter_name (str) – Filter identifier, e.g. "F150W".

  • wavelengths (np.ndarray) – Shared wavelength grid in Angstrom, shape (n_wav,).

  • orders (list[str]) – Diffraction order labels, e.g. ["A", "B", "C"].

  • sensitivity (dict[str, np.ndarray]) – Per-order sensitivity curves, each shape (n_wav,), normalised so that sum(sensitivity) == 1 (approximately).

  • trace (GrismTrace)

classmethod from_files(conf_path, wavelengthrange_path, sensitivity_dir, filter_name, n_wavelengths=150)[source]#

Build an InstrumentConfig from calibration files.

Parameters:
  • conf_path (Path) – Path to the grism .conf configuration file. The grism name is inferred from the filename stem (e.g. GR150R.F150W.220725.conf -> "GR150R").

  • wavelengthrange_path (Path) – Path to the JWST NIRISS wavelength-range .asdf file.

  • sensitivity_dir (Path) – Directory containing sensitivity .fits files named NIRISS.{grism}.{filter_name}.{order_int}.*.sens.fits.

  • filter_name (str) – Filter name, e.g. "F150W".

  • n_wavelengths (int, optional) – Number of wavelength sampling points. Default 150.

Return type:

InstrumentConfig

get_trace(x0, y0, order)[source]#

Return trace pixel coordinates for a source at (x0, y0).

Parameters:
  • x0 (float) – Source row position in detector coordinates.

  • y0 (float) – Source column position in detector coordinates.

  • order (str) – Diffraction order label, e.g. "A".

Returns:

(x_trace, y_trace) arrays at self.wavelengths, each shape (n_wav,).

Return type:

tuple[np.ndarray, np.ndarray]

Raises:

ValueError – If order is not in self.orders.

class spectrex.EigenspectraBasis(wavelengths, components, n_components)[source]#

Bases: object

PCA eigenspectra basis for representing source spectra.

Parameters:
  • wavelengths (np.ndarray) – Wavelength grid in Angstrom, shape (n_wav,). Read-only.

  • components (np.ndarray) – Basis components, shape (n_wav, n_components). Read-only.

  • n_components (int) – Number of basis components (components.shape[1]).

broadband_image(a_tilde, image_shape)[source]#

Reconstruct broadband direct image from full coefficient vector.

Vectorised; no Python loop over pixels.

Parameters:
  • a_tilde (np.ndarray) – Shape (n_rows * n_cols * n_components,).

  • image_shape (tuple[int, int]) – (n_rows, n_cols).

Returns:

Shape (n_rows, n_cols).

Return type:

np.ndarray

components: ndarray#
classmethod from_csv(csv_path, wavelengths)[source]#

Load and interpolate eigenspectra from a CSV file.

Parameters:
  • csv_path (Path) – CSV file with a header row, first column wavelength in µm, remaining columns as eigenspectra components.

  • wavelengths (np.ndarray) – Target wavelength grid in Angstrom to interpolate onto.

Return type:

EigenspectraBasis

Raises:

ValueError – If wavelengths lies outside the CSV wavelength range.

integrated_weights()[source]#

Trapezoidal integral of each basis component over wavelength.

Computed as np.trapezoid(components, wavelengths, axis=0).

Returns:

Shape (n_components,). Dot with a pixel’s coefficients gives its broadband flux.

Return type:

np.ndarray

n_components: int#
reconstruct(coefficients)[source]#

Reconstruct a spectrum from PCA coefficients.

Parameters:

coefficients (np.ndarray) – Shape (n_components,).

Returns:

Shape (n_wav,) — flux at each wavelength.

Return type:

np.ndarray

wavelengths: ndarray#

See also