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;
}
}](../_images/graphviz-8273df122d170bb60c16aed61f3d08d91cc912c9.png)
API Reference#
- class spectrex.InstrumentConfig(grism, filter_name, wavelengths, orders, sensitivity, trace)[source]#
Bases:
objectInstrument 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 thatsum(sensitivity) == 1(approximately).trace (GrismTrace)
- classmethod from_files(conf_path, wavelengthrange_path, sensitivity_dir, filter_name, n_wavelengths=150)[source]#
Build an
InstrumentConfigfrom calibration files.- Parameters:
conf_path (Path) – Path to the grism
.confconfiguration 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
.asdffile.sensitivity_dir (Path) – Directory containing sensitivity
.fitsfiles namedNIRISS.{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:
- get_trace(x0, y0, order)[source]#
Return trace pixel coordinates for a source at
(x0, y0).- Parameters:
- Returns:
(x_trace, y_trace)arrays atself.wavelengths, each shape(n_wav,).- Return type:
tuple[np.ndarray, np.ndarray]
- Raises:
ValueError – If
orderis not inself.orders.
- class spectrex.EigenspectraBasis(wavelengths, components, n_components)[source]#
Bases:
objectPCA 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.
- 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:
- Raises:
ValueError – If
wavelengthslies 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
See also
spectrex mock example — end-to-end example loading config files and building a forward operator
Forward Operators — how
InstrumentConfigandEigenspectraBasisfeed into the forward operator