Spectra and scenarios

Scenarios

Every showcase target offers the same five scenarios. They are presets of the parametric model (lazuli_exo.presets), evaluated at the registry values of the planet; observe() and simulate() run one model.

Scenario

Parameters

What it represents

clear

solar metallicity, no deck, no haze

Full-amplitude molecular features, the optimistic case.

cloudy

gray deck at 1 mbar (log_P_cloud_bar = -3)

An opaque deck truncating the features from below.

hazy

haze 100× H2 Rayleigh at 0.35 µm, slope −6 (log_a_haze = 2, haze_slope = -6)

A scattering haze steepening the blue continuum.

high_metallicity

100× solar (log_met = 2)

Higher mean molecular weight, so a smaller scale height.

flat

gray deck at 10 nbar (log_P_cloud_bar = -8)

A featureless \((R_p/R_s)^2\) line, to within a few ppm.

All scenarios use C/O = 0.55, mu=None (the equilibrium-chemistry mean molecular weight) and a single isothermal \(T = T_\mathrm{eq}\) layer. The opacity grid carries H2O, CO, CO2, CH4, NH3, Na and K.

The parameters are recorded on every observation, so you never have to trust this table:

obs = lazuli_exo.observe("WASP-39 b", scenario="hazy")
obs.meta["params"]
# {'name': 'WASP-39 b', 'scenario': 'hazy', 'T_eq_K': 1166.0, ...,
#  'log_met': 0.0, 'c_to_o': 0.55, 'mu': None, 'log_P_cloud_bar': None,
#  'log_a_haze': 2.0, 'haze_slope': -6.0, ...}
obs.meta["atmosphere"]
# {'g_ms2': ..., 'H_m': ..., 'H_over_Rp': ..., 'mu_used': ...,
#  'mu_source': 'chemistry', 'T_chem_K': 1166.0, 'T_clamped': False,
#  'feature_amplitude_ppm': ..., ...}

The physics behind the presets is in The parametric model.

The flat baseline

flat is the reference the template statistic is measured against: a deck above every line core, leaving a constant \((R_p/R_s)^2\) line with under a ppm of ripple. Running detect() on it returns a template S/N below 0.01, an invariant the test suite asserts.

The geometric \((R_p/R_s)^2\) from the registry radii is also on every observation as obs.flat_depth, so you can compare a scenario’s continuum level against the featureless baseline without a second call.

The model grid

The model is evaluated on the opacity grid’s constant-resolving-power wavelengths, \(R = 10\,000\) over 0.35–1.85 µm, with margin around the 0.40–1.70 µm IFS bandpass so the instrument response never runs off the end of the model. The grid matches POSEIDON.core.wl_grid_constant_R.

Binning

bin_observation() turns the native model and the per-channel noise into the binned spectrum in four steps:

  1. Constant-R bin edges (constant_R_edges(), the same fractional width \(1 + 1/R\) everywhere) are snapped to the nearest detector channel edges, so every bin is a whole number of pixels.

  2. The model is seen through the spectrograph (instrument_response()): the stellar photon flux times \(1 - d(\lambda)\) and the flux alone are convolved with the Gaussian line-spread function (sigma 1.15 px) and integrated per pixel, so the per-channel depth is photon weighted within each pixel.

  3. The per-channel depths are combined with the channel \(1/\sigma^2\) weights (bin_weighted()), the same combination whose uncertainty step 4 returns.

  4. The channel uncertainties are combined in inverse variance (bin_sigma()), which is why coarser R buys precision.

obs.meta["instrument_response"] records the LSF width, the instrument resolving-power range over the band and which photon weighting was used (the R = 10 000 star table for observe(), the R = 1000 PHOENIX SED for simulate()).

Note

Only complete bins are kept, so coverage can stop up to one bin short of the band edge. If you are matching grids between two calls, take obs.wavelength from one call rather than recomputing the edges.

The two resolution limits are set by the instrument and the noise tables, not by the model; see The noise model.