jwspecfit.fitter

Core emission-line fitting engine.

The main entry point is fit_lines(), which: 1. Subtracts a polynomial continuum. 2. Sets up Gaussian line models with resolution-aware widths. 3. Optimises via scipy.optimize.least_squares with bounds. 4. Returns a FitResult with per-line fluxes, EWs, and SNR.

Functions

fit_lines(spectrum, z, *[, grating, R, ...])

Fit emission lines in a spectrum.

Classes

FitResult(lines, params, model_flux, ...[, ...])

Container for a complete line-fit result.

LineResult(name, rest_wave_A, amplitude, ...)

Fit result for a single emission line.

class jwspecfit.fitter.FitResult(lines, params, model_flux, continuum, residuals, chi2, spectrum, line_names=<factory>, constraints=None, success=True, lya_params=None)[source]

Bases: object

Container for a complete line-fit result.

Parameters:
lines

Per-line results, keyed by line name.

Type:

dict of LineResult

params

Full best-fit parameter vector.

Type:

np.ndarray

model_flux

Best-fit emission-line model (continuum-subtracted flux density).

Type:

np.ndarray

continuum

Best-fit continuum (µJy).

Type:

np.ndarray

residuals

Fit residuals (data − continuum − model), in µJy.

Type:

np.ndarray

chi2

Reduced χ² of the fit.

Type:

float

spectrum

Input spectrum.

Type:

Spectrum

line_names

Ordered line names.

Type:

list of str

constraints

Applied constraints.

Type:

ConstraintSet

success

Whether the optimiser converged.

Type:

bool

chi2: float
constraints: ConstraintSet | None = None
continuum: ndarray
flux_upper_limit(line_name, n_sigma=3.0)[source]

Compute a noise-based flux upper limit for a line.

Uses the local RMS of the residuals near the line position, multiplied by n_sigma and the line width.

Parameters:
  • line_name (str) – Line name.

  • n_sigma (float) – Number of sigma for the upper limit (default 3).

Returns:

Integrated flux upper limit in f_lam units, or None if there are insufficient pixels near the line.

Return type:

float or None

flux_upper_limits(line_names=None, n_sigma=3.0, snr_threshold=3.0)[source]

Compute noise-based upper limits for low-SNR lines.

Parameters:
  • line_names (list of str, optional) – Lines to check. If None, checks all fitted lines.

  • n_sigma (float) – Number of sigma for the upper limit (default 3).

  • snr_threshold (float) – Only compute upper limits for lines with SNR below this (default 3.0).

Returns:

dict of {str{line_name: flux_upper_limit} for each line below the SNR threshold.

Return type:

float}

line_names: list[str]
lines: dict[str, LineResult]
lya_params: ndarray | None = None
model_flux: ndarray
params: ndarray
residuals: ndarray
spectrum: Spectrum
success: bool = True
class jwspecfit.fitter.LineResult(name, rest_wave_A, amplitude, centroid_A, sigma_A, flux, flux_err, ew_A, snr_int_err, snr_int_cont, snr_peak_err, snr_peak_cont)[source]

Bases: object

Fit result for a single emission line.

Parameters:
name

Line name.

Type:

str

rest_wave_A

Rest-frame wavelength (Å).

Type:

float

amplitude

Best-fit amplitude (flux × Å, in flux-density units × Å).

Type:

float

centroid_A

Best-fit observed centroid (Å).

Type:

float

sigma_A

Best-fit observed Gaussian σ (Å).

Type:

float

flux

Integrated line flux (amplitude, since profile is area-normalised).

Type:

float

flux_err

Bootstrap uncertainty on flux.

Type:

float

ew_A

Rest-frame equivalent width (Å).

Type:

float

snr_int_err

Integrated SNR: flux / bootstrap flux error.

Type:

float

snr_int_cont

Integrated SNR: flux / (local continuum RMS × √N_pix).

Type:

float

snr_peak_err

Peak SNR: model peak / uncertainty array at peak pixel.

Type:

float

snr_peak_cont

Peak SNR: model peak / local continuum RMS.

Type:

float

amplitude: float
centroid_A: float
ew_A: float
flux: float
flux_err: float
name: str
rest_wave_A: float
sigma_A: float
property snr: float

Backward-compatible alias for snr_int_err.

snr_int_cont: float
snr_int_err: float
snr_peak_cont: float
snr_peak_err: float
upper_limit(n_sigma=3.0)[source]

Return n-sigma flux upper limit.

Return type:

float

Parameters:

n_sigma (float)

jwspecfit.fitter.fit_lines(spectrum, z, *, grating=None, R=None, lines=None, wave_range_A=None, deg=2, n_boot=1000, clip_sigma=2.5, n_jobs=-1, save_path=None, sigma_factor=1.0, centroid_vmax=500.0, centroid_max_sigma=1.0, moving_average=False, tie_balmer_to_oiii=True, tie_uv_doublets=True, tie_uv_centroids=True, tie_uv_widths=True, sigma_overrides=None, centroid_overrides=None, lya_break=False, niv_doublet_ratio=None, ciii_doublet_ratio=None, _label='', _p0_hint=None)[source]

Fit emission lines in a spectrum.

Parameters:
  • spectrum (Spectrum) – Input spectrum.

  • z (float) – Source redshift.

  • grating (str, optional) – Grating name. If None, uses spectrum.grating.

  • R (float or callable, optional) – Resolving power. If None, uses spectrum.R or derives from grating.

  • lines (list of str, optional) – Lines to fit. If None, auto-detected from grating and wavelength coverage.

  • wave_range_A (tuple of float, optional) – (lo, hi) observed wavelength range in Angstroms. If given, only pixels within this range are used for continuum fitting and line fitting. Lines outside the range are excluded.

  • deg (int) – Continuum polynomial degree (default 2).

  • n_boot (int) – Number of bootstrap iterations for uncertainty estimation (default 200).

  • clip_sigma (float) – Continuum sigma-clipping threshold.

  • n_jobs (int) – Number of parallel jobs for bootstrap. -1 uses all cores, 1 runs sequentially. Default -1.

  • save_path (str or Path, optional) – If given, export per-line measurements to this text file after fitting.

  • sigma_factor (float) – Multiplicative factor applied to the upper line-width bound. Use values > 1 for stacked spectra where redshift scatter broadens lines beyond the instrumental resolution (default 1.0).

  • centroid_vmax (float) – Maximum centroid offset in km/s (default 500). Sets the velocity ceiling on how far any line’s centroid can wander from its systemic prediction. Increase for stacked spectra with larger velocity offsets between lines.

  • centroid_max_sigma (float) – Resolution-aware cap on narrow-line centroids: each narrow line’s centroid can drift at most centroid_max_sigma × σ_inst from its systemic prediction, where σ_inst is the instrumental Gaussian σ evaluated at the line. The actual bound is min(centroid_vmax/c × λ_obs, centroid_max_sigma × σ_inst). Broad components (_BROAD/_BROAD2) bypass this cap so real outflow blueshifts aren’t clipped. Default 1.0 (≈ ±130 km/s at G395M OIII; ≈ ±60 km/s at G395H).

  • moving_average (bool or int) – If False (default), use polynomial continuum. If True, use a median filter with a default window of 75 pixels. If an int, use that as the median-filter window size.

  • tie_balmer_to_oiii (bool) – Tie Balmer line widths and centroids to [OIII] 5007 in velocity space (default True). Set to False for stacked spectra where OIII may be broader than the true narrow component, causing Ha to absorb flux from neighbouring lines like [NII] 6585.

  • tie_uv_doublets (bool) – Tie UV doublet kinematics and fix resonance-line flux ratios. Recommended for stacked spectra where doublets are poorly resolved (default False).

  • sigma_overrides (dict, optional) – Per-line sigma (width) bounds in Angstroms, keyed by line name. Each value is (sigma_lo, sigma_hi). Overrides the automatic grating-based bounds for the specified lines. Convert from velocity: sigma_A = sigma_kms / 299792.458 * lambda_obs_A.

  • centroid_overrides (dict, optional) – Per-line centroid bounds in observed-frame Angstroms, keyed by line name. Each value is (mu_lo, mu_hi). Overrides the automatic centroid bounds for the specified lines. Useful for anchoring closely-spaced doublet members in noisy spectra.

  • tie_uv_centroids (bool)

  • tie_uv_widths (bool)

  • lya_break (bool)

  • niv_doublet_ratio (float | None)

  • ciii_doublet_ratio (float | None)

  • _label (str)

  • _p0_hint (dict[str, tuple[float, float, float]] | None)

Return type:

FitResult