Full implementation of Laguerre-Gauss modal reconstruction for gyrotron beam diagnostics, per the approved design spec, plus tests, docs, and a runnable end-to-end example. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.2 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What this is
he11lib reconstructs the Laguerre-Gauss (LG) modal content ("mode purity") of a
free-space-propagating gyrotron RF beam from a set of thermal (flux) images taken at
different distances from the output window. It accounts for camera geometry (unknown
pixel scale / oblique viewing angle), sensor noise, target thermal-diffusion blur, and
unknown beam center/pointing.
The full design rationale lives in
docs/superpowers/specs/2026-07-02-gyrotron-mode-purity-design.md — read it before
making architectural changes. docs/api.md is the API reference for the implemented
public interface; keep it in sync when changing public signatures.
Commands
pip install -e ".[dev]" # editable install with test dependencies (numpy, scipy, matplotlib, pytest)
pytest # run the full test suite (discovers tests/, per pyproject.toml)
pytest tests/test_modes.py # run one test file
pytest tests/test_modes.py::test_field_at_waist # run one test
python examples/full_pipeline_example.py # runnable end-to-end demo
There is a project .venv; activate it or otherwise ensure the editable install's
dependencies are available before running tests.
tests/conftest.py forces the Agg matplotlib backend so plotting tests run headless.
This project is not (yet) a git repository.
Architecture
Data flows through the pipeline as a list of MeasurementPlane (one per imaging
distance z), each holding a raw 2D flux array plus optionally-known
pixel_scale/viewing_angle_deg. Everything downstream is keyed off LGBasis, which
defines the mode basis relative to a known waist w0/z0/wavelength.
Module responsibilities (he11lib/):
data.py—MeasurementPlane,ReconstructionResult(the shared input/output types) andvalidate_planes(>=3 planes, matching shapes, distinctz).modes.py—LGBasis: closed-form paraxial LG fields, beam radiusw(z), Gouy phase, inverse radius of curvature, and projection of a measured field onto a candidate mode set. This is the analytic ground truth all fitting is checked against.geometry.py—GeometryCalibration: resolves a plane's pixel-to-physical coordinate grid, deferring to knownpixel_scale/viewing_angle_degon the plane over any override passed in.noise.py—NoiseEstimator: automatic per-image noise-std estimation (Laplacian method) and per-pixel weights for noise-weighted least squares.deconvolution.py—DiffusionDeconvolver: optional forward blur / Wiener deconvolution for thermal-diffusion blur in the absorbing target. The blur kernel is isotropic in pixel space, so it's only exact whenviewing_angle_deg == 0(an oblique view makes x/y pixel scales differ) — an accepted approximation, not a bug.synthetic.py—SyntheticBeamGenerator: forward model that producesMeasurementPlanes from known ground-truth coefficients/center/pointing/geometry. Used throughout the test suite and examples to validate the pipeline end-to-end.fitting.py—ModalFitter(fit,fit_auto) andgenerate_mode_shells: the core joint nonlinear least-squares fit (complex LG coefficients + beam center/pointing + unknown geometry) viascipy.optimize.least_squares.fit_autogrows the candidate mode set shell-by-shell (by order2p + |l|), stopping via a BIC improvement threshold, capped atmax_order(emitsUserWarning, doesn't raise, if still improving at the cap).phase_retrieval.py—propagate_angular_spectrum(FFT-based paraxial free-space propagation) andPhaseRetriever(multi-plane Gerchberg-Saxton), the fallback reconstruction path for when a finite mode basis doesn't fit well.reconstruct.py—BeamReconstructor: the orchestrator. Pipeline order: validate planes → optional deconvolution (requires knownpixel_scaleper plane) →ModalFitter.fit_auto→ optionalPhaseRetrieverfallback (forced viaforce_phase_retrieval, or triggered automatically when the noise-weighted RMS residual exceedsphase_retrieval_residual_threshold). The fallback path projects the recovered field onto all modes up tomax_orderand produces aReconstructionResultwithused_phase_retrieval=True, emptyresiduals, and NaNcoefficient_uncertainty(no fit covariance available from phase retrieval).plotting.py— diagnostic figures (plot_mode_purity,plot_center_trace,plot_residuals); each returns aFigurerather than callingplt.show().
Everything above is re-exported from the top-level he11lib package (see
he11lib/__init__.py); import from there rather than submodules.
Known physics/fitting pitfalls (read before writing new tests or examples)
These aren't library bugs — they're consequences of realistic optics parameters and of automatic order-selection being genuinely data-driven — but they've caused most of the debugging time in this project's history:
- Rayleigh-range / frame clipping.
w(z)grows with|z - z0|relative tozR = pi*w0**2/wavelength. With typical test parameters (w0=5e-3,wavelength=1.76e-3),zRis only ~4.46 cm, so z-distances spanning tens of cm put the beam many Rayleigh ranges out, wherew(z)can exceed a small test frame — clipping the beam and corrupting fits, or introducing FFT wraparound artifacts inpropagate_angular_spectrum. Keep z-distances within roughly ±1-2 Rayleigh ranges ofz0, or enlarge the frame/pixel_scale accordingly. - Automatic mode-set growth can overfit deconvolution artifacts. Wiener-deconvolved
data always has some residual imperfection;
fit_auto's BIC-driven growth will try to "explain" it with spurious higher-order modes, degrading fitted beam center/pointing via parameter degeneracy (observed: pointing angle off by 4-6x atmax_order=3vs. matching ground truth almost exactly atmax_order=1, for the same 2-mode ground truth). When demonstrating growth with deconvolution or noise, setmax_orderclose to the true expected mode content rather than generously high, unless the test specifically targets growth behavior itself.