Direct imaging scientific exercise
==================================

Follow the same synthetic camera frames through subtraction, spectral mixing
and contrast extraction. A separate exercise downloads three original reduced
GPI exposures from the author repository and checks their sparse extraction.
The website and this ZIP include OUR synthetic pixels, standalone scientific
Python, original FITS headers and numerical results. They contain no native or
derived observed GPI image pixels and no interactive Lab Engine. Observed-pixel
redistribution terms remain unresolved; the separate upstream downloader grants
no new licence. It requests only the exact public author-hosted ranges.

Download and verify
-------------------

Use the complete direct-imaging-science.zip link, unpack into a fresh directory,
then run python verify-public-inputs.py . . Individual scientific files are also
listed with MIME, length and SHA256 in public-reproduction.json.

Alternatively, fetch the named anonymous client and request its archive mode:

  curl -fLsS -A 'SandboxPhysics-Public-Tutorial/1.0' https://sandboxphysics.com/stories/direct-imaging/materials/download-tutorial.py -o download-tutorial.py
  python3 download-tutorial.py --archive --output direct-imaging-tutorial
  cd direct-imaging-tutorial

The client checks one same-origin scientific ZIP by length/SHA256/MIME, unpacks
ordinary filenames and checks every scientific member. Its receipt distinguishes
actual HTTP transfers from a verified local cache. Local ZIP reconstruction or a
local test server is not evidence of production HTTP delivery.

Tested reference environment and reproduction
---------------------------------------------

The final independent reference uses CPython 3.12 and NumPy 2.3.5. Downloaders
need only Python 3.9+ standard library. Plotting is optional, Matplotlib 3.10.7.
No SciPy, private checkout or pyKLIP installation is required.

  python3.12 -m venv .venv
  . .venv/bin/activate
  python -m pip install numpy==2.3.5
  python verify-public-inputs.py .
  python reproduce-synthetic.py --materials . --output synthetic-rerun.json
  python verify-small-sample.py --reference small-sample-reference.json
  python validate-response-recovery.py --materials . --output response-rerun.json

The independent NumPy propagation agrees with 27 actual TypeScript optical
states. It reprocesses the delivered five-band cube, including fitted-source
photon covariance. The five aperture contrasts alone have zero residual degrees
of freedom; the 15-dimensional spatial measurements supply a separate check.
Omitting source photon noise produces chi-square about 52.9 for ten residual
dimensions in this synthetic example; including it gives about 2.73. Neither
value certifies a covariance estimated from a small comparison sample.

Longer checks, preferably with one BLAS thread:

  OPENBLAS_NUM_THREADS=1 python run-noise-validations.py --materials . --output noise-rerun
  OPENBLAS_NUM_THREADS=1 python validate-blind-search.py --materials . --draws 64 --output null-rerun.json
  OPENBLAS_NUM_THREADS=1 python validate-supported-optics.py --output supported-optics-rerun.json
  OPENBLAS_NUM_THREADS=1 python validate-band-pixels.py --output band-pixel-rerun.json
  OPENBLAS_NUM_THREADS=1 python validate-extraction-grid.py --materials . --output extraction-grid-rerun.json

The combined noise driver reuses deterministic optical templates, but every
trial generates new Poisson/read noise and re-estimates the comparison covariance
and the data-dependent KL basis. It performs 64 ADI, 64 ASDI and 24 KLIP complete
acquisitions. One-standard-error coverage counts, in wavelength order, are:
  ADI: 48,44,41,38,39 /64; ASDI:44,46,35,43,34 /64; KLIP:11,15,8,12,11 /24.
The local position minima reach the small grid boundary 22,31,15 times. These
undercoverage and boundary failures remain in the complete trial reports. This
is a conditional optical/noise population, not new atmospheric realizations or
calibrated confidence intervals. The blind search tries 140 positions and five
processing choices; zero exceedances in 64 null trials have a finite binomial
upper bound, not probability zero.

Synthetic optics and units
--------------------------

D=8 metres; lambda_ref=1.24 micrometres. Angular coordinates use lambda_ref/D.
Detector x points right, y up. Five 0.02-micrometre top-hat bands assume flat
stellar F_lambda and constant source contrast inside each band. Photon weighting
contains one wavelength factor. Thirty million potential photoelectrons per
band/exposure already include that band integral; QE is one in this teaching
instrument. Star/source are mutually incoherent, so their intensities add.

The current Fourier size is 512, pupil diameter 64 samples, camera 80 by 80 with
0.25 reference angular units/pixel. Physical pupil, hard focal mask and Lyot
stop have circular edges. Exact circle/cell areas project a field treated as
constant inside each cell. This is a numerical quadrature, not a soft physical
apodizer or exact continuous propagation. Clear-entrance normalization uses the
physical area pi*diameter^2/4. Projection, masks and finite-camera losses remain;
transmitted PSFs are never renormalized to unit flux. Complex cubic interpolation
is evaluated at 2-by-2 Gauss pixel nodes before squaring and adding intensities, so
camera probabilities stay nonnegative without an intensity floor.

The 96 control-corner comparisons outside separation 3 against independent
1024/128 sampling have worst relative image L1 difference 0.2245%, absolute
transmission difference 0.001441 of the entrance budget, and aperture correction
0.03598%. Two harder 2048/256 references give at most 0.2675% image L1 and 0.04330%
aperture correction. These are finite reference comparisons, not uniform
continuum/physical-error bounds. Full default-sequence calibration differences
are 0.029--0.045 of the saved working spectral sigma. Twelve further checks find
3 versus 5 band-node relative L1 at most 3.31e-6 and 2-by-2 versus 3-by-3 pixel quadrature at most 2.97e-4.

The Lab retains near-mask camera/processed images but withholds inference below
separation 3. It also withholds fitted error bars narrower than 0.2% relative
precision, a conservative display screen informed by those finite checks.
No artificial Gaussian noise is added to pass a fit. Default/presets immediately
show saved actual native acquisitions. A new parameter or a different displayed
band starts an asynchronous complete acquisition; the previous image and its
wavelength label stay together until that calculation completes. A Node native
sequence takes roughly 20 seconds on the checked machine; this is not a browser
frame-rate promise. A saved preview contains the middle band only and is never
relabeled as another band.

The fixed mask radius is 2.5 reference units, Lyot radius 0.82 pupil radii. Eighteen
one-second exposures are spaced 120 seconds. Field rotation represents pupil
tracking, not orbital motion. OPD is a prescribed area-weighted RMS path length,
not mirror height or a reproduced AO control loop. Counts are Poisson plus
Gaussian read noise 2 electrons; background 5 electrons/pixel. Full NPZ order is
wavelength,exposure,row,column and stores the same acquired cube/source templates.
Aperture estimates condition on position/PSF. Mean ADI/ASDI use their actual
linear transpose for photon covariance; KLIP resamples source photons and
recomputes the reference basis. Position/PSF and sparse-covariance uncertainty
are checked separately; working Gaussian profiles include logdet C with one
adopted covariance per acquisition.

Original GPI exercise
---------------------

  python download-gpi-ranges.py --manifest data-source-manifest.json --output gpi-cache
  python reproduce-gpi.py --manifest data-source-manifest.json --cache gpi-cache --output local-results
  python reproduce-gpi.py --manifest data-source-manifest.json --cache gpi-cache --output local-results --algorithm asdi
  python validate-gpi-registration.py --manifest data-source-manifest.json --cache gpi-cache --output registration-rerun.json

The downloader checks every 206 Content-Range, length and SHA256. It has no
whole-file fallback. Three 2013-12-10 exposures, programme GS-ENG-GPI-COM, reduced
in 2016, are pinned to author commit 72a7517b1a34bdc29c33211f2ef591ddff64dcf9.
Original channels 0,4,...,36 remain ADU/coadd. There is no supplied ERR extension
or calibrated gain, so no invented Poisson electron covariance is assigned.
CD gives 14.14 mas/pixel; stale CDELT and inaccurate PAR_ANG are not used.
Repeated SATS/PSFCENT headers stay intact; actual satellite spots are remeasured
with a local Gaussian plus plane. SATF is a peak, not an integrated aperture.
Quality bits 0--2 mask invalid pixels; stricter rejection is a separate sensitivity.
A constant historical 9.36+/-0.15 mag spot ratio gives a COMMON calibration term.
The original off-axis table is not used as a precision wavelength calibration.

The ten-channel spectrum and full 30-dimensional local position profile retain
poor fits and negative ASDI contrasts. The expanded and refined profile keeps
its measurement ROI and empirical covariance fixed. ADI reaches an interior
minimum near 175 for 20 residual dimensions; ASDI remains near 389 and its local
refinement still touches an edge. Grid boundaries and minima are reported; no calibrated astrometric interval, atmospheric abundance,
dynamical mass, blind discovery or nineteen-exposure published replication is
claimed. Local registration injection failures remain in their own report.

Observed images created with --local-images stay in the reader's folder. The
website ZIP contains no such pixels. SVG figures use our synthetic camera only.
Source, code/data rights and exact native metadata are retained in the source
manifest and original BSD notice. Static bytes are hash-checked. Floating
results use explicit numerical tolerances across NumPy/BLAS builds; equal chain
bytes or one small residual is not scientific certification.
