# Offline planetary-ring analysis

Save all ten scientific downloads from the Cassini tutorial into one folder. The scripts run without repository access or a network connection. Python 3.10 or newer is supported; NumPy 2.0.2 generated the observed replay output. The synthetic reanalysis uses the standard library only.

```sh
python3 -W error replay-cassini.py
python3 -W error replay-synthetic.py
```

The commands write `cassini-replay-rerun.json` and `synthetic-replay-rerun.json` beside the input files. `--input <path>` and `--out <path>` override paths. From a repository checkout the same scripts discover their owned inputs and write the canonical docs outputs instead. Download URLs are the tutorial's `/stories/planetary-rings/downloads/` plus each displayed exact filename; they are static anonymous scientific resources, never protected Lab code.

The Cassini input is an exact 1001-record byte range of the archived binned UVIS HSP alpha Arae 2008-261 egress profile, dataset 3.0, product created 27 November 2020. It is not unbinned spacecraft telemetry or simulated photon data. The original twelve columns, original label and README, all-zero retained quality flags, geometry, model signals and per-bin sample counts are preserved. `cassini-provenance.json` records precise URLs, byte range, SHA-256 values, units and citation/licensing scope. The raw binned mean has not had background subtracted: remove it once and divide by the star-only model before taking a logarithm. Do not subtract again from the archive's published normal depth.

`replay-cassini.py` verifies the exact source hash, reconstructs optical depth and conditional counting errors, saves all actual arrays/flags, runs declared local spatial-frequency searches and 256 counting-noise perturbations, then combines neighboring **count** bins and repeats the searches. The UV band110–190 nm does not change. Reported wavelength is radial structure spacing. The model residuals are large; the last window is resolution-sensitive. Counting-noise intervals omit model/calibration errors and are not total physical-wave confidence intervals. No mass, viscosity or age is inferred.

`synthetic-results.json` is a separate seed 1010 Hill-sheet snapshot dataset, not Cassini particles. It includes the exact positions, velocities and synthetic Poisson counts used in the browser's frozen examples. `replay-synthetic.py` independently recomputes the normalized Gaussian optical column, transmission and photon-derived estimates from those saved positions/counts. It neither imports the Lab engine nor regenerates the many-body evolution. The local browser includes a prescribed softened moon and collisions; mutual particle gravity and global resonant propagation are absent.

Repository maintenance only: `freeze-synthetic.ts` regenerates frozen teaching snapshots from the source model. The public scientific replay needs no TypeScript or browser executable. `fetch-source.py` optionally refreshes the exact bounded public range and labels, verifying expected hashes before writing; normal replay never fetches changing data. Preserve the dataset citation requested by Colwell, Jerousek, Becker and Esposito in the original PDS README.
