Identify the exact measurement before opening a model
The source is CMADF-WASP_39b_NIRISS_transmission_spectrum_R100.csv from author repository commit 0608071e1e70ec7ff12707774ea03ace4b52ea85, linked to the published Feinstein and collaborators analysis. Its unchanged original is 11,063 bytes. The accompanying provenance file gives its complete SHA256, author license and archived Zenodo version.
Select order one, quality zero, and bins whose entire supplied interval lies between 0.87 and 2.00 micrometres. This leaves 74 rows, with actual outer edges near 0.8732 and 1.9882 micrometres. The reported vertical errors span about 28.2 to 73.4 ppm. The filename says R100, while the generic header says Native; the supplied widths imply resolving powers about 82.8 to 94.7. The package preserves those original labels and uses the numeric widths explicitly.
Depth and uncertainty are already in ppm. The horizontal wave_error is treated as a halfwidth, consistent with the author plotting script. These intervals become independent top-hat response approximations. There is no silent conversion of them to Gaussian errors, and no claim that they reproduce the full detector response.
Reading: WASP-39 b NIRISS author data · Zenodo 7709712 and fixed repository commit · Feinstein et al. (2023) · Early Release Science of WASP-39 b with JWST NIRISS
Check the physical inputs and the order of operations
The molecular input is the actual ExoMolOP POKAZATEL sampled cross-section product. Its original HDF5 file contains 22 pressure rows, 27 temperatures and 76,744 wavenumber samples. Exact byte ranges retain all 22 pressures, nine temperatures from 800 to 1600 kelvin and 15,084 samples covering the working wavelength interval. The extraction manifest records the original total file size, array offset, lack of compression, every selected range and its hash.
Three original PHOENIX medium-resolution stellar members at 3500, 4500 and 5500 kelvin come from the explicitly licensed Zenodo version 1.0 derivative. The headers give nanometres and surface flux in erg per square centimetre per second per nanometre. The calculation retains their common physical normalization. Source members, CRC32, hashes and attribution accompany the package.
The forward model uses the inverse-square isothermal atmosphere, finite top and pressure-dependent cross section derived in the course. It transfers every native wavelength before computing a photon-weighted occulting area in each measured bin. Gray-cloud and unocculted-star corrections act on this same physical calculation.
The browser uses a compact logarithmic encoding of the same positive source opacity. Its maximum final-bin difference from the Python float64 route is about 0.015 ppm across 21 corner/preset and 16 withheld states. This encoding test is separate from radial quadrature and from the offline observable-grid interpolation used for the posterior.
Reading: Chubb et al. (2021) · ExoMolOP cross sections and k-tables · Polyansky et al. (2018) · The POKAZATEL water line list · Stuitje · PHOENIX medium-resolution stellar spectra, version 1.0 · Husser et al. (2013) · A PHOENIX library of stellar atmospheres and spectra
Verify the observable grid before spending time sampling
The posterior grid stores already transferred, photon-binned planetary areas after subtracting the exact reference-radius-squared baseline. It never stores a coarse mean cross section. Temperature interpolation stays inside each original 100-kelvin opacity interval, and extrapolation is rejected.
An initial high-water edge failed the 2 ppm numerical target. Four extra values on the water-abundance axis required 476 additional complete native gas-column calculations, increasing the total from 2499 to 2975. After uniform refinement to 384 pressure layers, 77 independently checked states include new withheld interiors, edges and every preset. The maximum difference is about 0.425 ppm from the native 384-layer route and 1.636 ppm from a separately cloud-bounded 1280-layer reference.
The supplied validate_grid.py reruns those actual transfer comparisons from the original extracted opacity and stellar inputs. The 2 ppm threshold concerns numerical agreement inside this defined source-product model. It is not an added observational error, a calibrated distribution of model discrepancy, or a line-by-line physical accuracy guarantee.
Separate source sensitivities are larger: halving the native wavelength samples changes five preset spectra by about 40–145 ppm, and removing a known temperature row changes them by about 3.4–31.8 ppm. These are comparable to measured uncertainties. The sub-two-ppm internal check conditions on the complete retained source product and specified interpolation; it does not turn these representation changes into a total accuracy bound or Gaussian noise.
An optional rebuild_grid.py recreates all 2975 complete columns and checks the final float32 grid hash. It is the slowest step. The posterior rerun can use the delivered grid after its input hashes and independent validation have been checked.
python3 validate_grid.py --materials . --output rerun-validation
python3 rebuild_grid.py --materials . --output rebuilt-gridReading: Chubb et al. (2021) · ExoMolOP cross sections and k-tables · Heng and Kitzmann (2017) · Transmission spectra and the radius–pressure degeneracy
Check whether the reference itself is fine enough
The earlier 320-layer calculation looked acceptable against a 640/960-layer reference. A further check against 1280 layers exposed two grid discrepancies of about 2.13 and 2.09 ppm. Those actual failures are preserved, with the old grid hash and enough input information to reproduce them.
Production therefore uses 384 layers consistently for the scene, spectra, grid and synthetic recovery. The difficult points are also compared with 2048 layers: their current grid differences are below 1.73 ppm. The public finer_reference.py replays the retired native result and the current calculation. The old grid is kept for failure reproduction; the posterior uses the 384-layer version.
Agreement with a stated finite quadrature is a numerical comparison, not a strict error bound against an unknown continuous atmosphere. It also leaves the much larger source-sampling and temperature-interpolation sensitivities intact. The posterior remains conditional on that complete frozen product and its physical assumptions.
python3 finer_reference.py --materials . --output rerun-finerReading: Heng and Kitzmann (2017) · Transmission spectra and the radius–pressure degeneracy · Chubb et al. (2021) · ExoMolOP cross sections and k-tables
Run the same proper posterior under four stated conditions
Install the pinned NumPy version and run analyze.py in the unpacked directory. The default command runs cloud only, cool regions at 4500 kelvin with an upper fraction of 0.05, cool regions at 3500 kelvin with the same fraction prior, and a narrower 4500-kelvin prior capped at 0.01. All use the same actual 74 bins, normalized Gaussian likelihood and atmospheric priors given in L3.
Each run uses four chains, 6000 warmup iterations and initially 16,000 retained iterations per chain. The retained positions are correlated samples. The summary therefore reports bulk and tail effective sample size separately from the total retained count. Warmup adaptation stops before retention, and out-of-prior proposals are rejected.
The script saves full physical and computational chains, parameter quantiles, diagnostics and per-bin prediction intervals. It separately generates noisy replicated measurements. The comparison script checks fixed priors and the convergence targets, and uses stated numerical tolerances for posterior quantiles. Seeds and software versions are fixed in the instructions.
python3 -m pip install -r requirements.txt
python3 analyze.py --materials . --output rerun
python3 verify_outputs.py --expected expected --actual rerunReading: Vehtari et al. (2021) · Rank-normalized split R-hat and effective sample size · WASP-39 b NIRISS author data · Zenodo 7709712 and fixed repository commit · Heng and Kitzmann (2017) · Transmission spectra and the radius–pressure degeneracy
Keep the failed results in the answer
Open cloud-summary.json and spots4500-summary.json, then their prediction CSV files. The retained minimum chi-squares are about 332 and 257. Their median-curve standardized residual RMS values are about 2.13 and 1.88. Respectively 28 and 23 observations lie outside their central 95 percent replicated-measurement intervals. These failures remain visible even though every varying parameter passes the chain diagnostics.
Read the full parameter intervals. Temperature crowds the low prior boundary, water abundance crowds the high boundary, and cloud pressure trades against the reference radius. The 4500-kelvin cool fraction has a median near 0.0224; changing the cool spectrum to 3500 kelvin moves it to about 0.0373. Narrowing its allowed fraction changes both the posterior and the remaining discrepancy.
A positive interval inside a continuously positive prior is not a test of the point hypothesis . No evidence integral or Bayes factor is reported. Nor should a chi-square difference between these restricted models be promoted to a model-independent molecular or stellar detection significance.
The exercise omits other absorbers and non-gray cloud physics and assumes unknown inter-bin covariance is zero. The original published analysis used richer atmospheric models. These simple models explain some band structure and leave wavelength-dependent residuals larger than expected under the assumed errors.
Reading: Feinstein et al. (2023) · Early Release Science of WASP-39 b with JWST NIRISS · Rackham, Apai and Giampapa (2019) · The Transit Light Source Effect II · Brogi and Line (2019) · Retrieval with high-resolution cross-correlation spectroscopy · Vehtari et al. (2021) · Rank-normalized split R-hat and effective sample size
Use a known atmosphere to test a narrower question
The verification command independently solves a non-grid atmosphere at 1123 kelvin, water logarithmic fraction minus 3.47, cloud logarithmic pressure minus 1.37, ten-bar radius ratio 0.1337 and cool fraction 0.018. It then adds a fixed Gaussian noise realization using the reported bin uncertainties. The synthetic CSV is clearly labelled and kept separate from the observed NIRISS input.
Its four-chain posterior passes the same diagnostics, and every injected parameter lies inside its marginal 95 percent interval in the saved run. A single success checks implementation and one recovery case. It is not an empirical 95 percent coverage study across atmospheres and noise realizations.
Other independent checks turn water absorption off exactly, integrate a homogeneous absorbing spherical shell, approach the thin-atmosphere tangent-column limit, verify an identical stellar spectrum produces no contamination, test the finite prior normalization, and compare effective sample size with an autoregressive reference. A deliberately separated set of chains must fail the diagnostic.
Finally compare actual and synthetic residuals. Successful recovery when the model generates the data, alongside failed prediction for actual data, is a useful result: it separates a working conditional calculation from an adequate physical explanation of a planet.
python3 verify_science.py --materials . --output rerun-checks --syntheticReading: Vehtari et al. (2021) · Rank-normalized split R-hat and effective sample size · Heng and Kitzmann (2017) · Transmission spectra and the radius–pressure degeneracy · Feinstein et al. (2023) · Early Release Science of WASP-39 b with JWST NIRISS