Files
he11lib/CLAUDE.md
T
Martino Ferrari 03b63ba03a Initial commit: he11lib mode-purity reconstruction library
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>
2026-07-02 21:47:49 +02:00

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.pyMeasurementPlane, ReconstructionResult (the shared input/output types) and validate_planes (>=3 planes, matching shapes, distinct z).
  • modes.pyLGBasis: closed-form paraxial LG fields, beam radius w(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.pyGeometryCalibration: resolves a plane's pixel-to-physical coordinate grid, deferring to known pixel_scale/viewing_angle_deg on the plane over any override passed in.
  • noise.pyNoiseEstimator: automatic per-image noise-std estimation (Laplacian method) and per-pixel weights for noise-weighted least squares.
  • deconvolution.pyDiffusionDeconvolver: 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 when viewing_angle_deg == 0 (an oblique view makes x/y pixel scales differ) — an accepted approximation, not a bug.
  • synthetic.pySyntheticBeamGenerator: forward model that produces MeasurementPlanes from known ground-truth coefficients/center/pointing/geometry. Used throughout the test suite and examples to validate the pipeline end-to-end.
  • fitting.pyModalFitter (fit, fit_auto) and generate_mode_shells: the core joint nonlinear least-squares fit (complex LG coefficients + beam center/pointing + unknown geometry) via scipy.optimize.least_squares. fit_auto grows the candidate mode set shell-by-shell (by order 2p + |l|), stopping via a BIC improvement threshold, capped at max_order (emits UserWarning, doesn't raise, if still improving at the cap).
  • phase_retrieval.pypropagate_angular_spectrum (FFT-based paraxial free-space propagation) and PhaseRetriever (multi-plane Gerchberg-Saxton), the fallback reconstruction path for when a finite mode basis doesn't fit well.
  • reconstruct.pyBeamReconstructor: the orchestrator. Pipeline order: validate planes → optional deconvolution (requires known pixel_scale per plane) → ModalFitter.fit_auto → optional PhaseRetriever fallback (forced via force_phase_retrieval, or triggered automatically when the noise-weighted RMS residual exceeds phase_retrieval_residual_threshold). The fallback path projects the recovered field onto all modes up to max_order and produces a ReconstructionResult with used_phase_retrieval=True, empty residuals, and NaN coefficient_uncertainty (no fit covariance available from phase retrieval).
  • plotting.py — diagnostic figures (plot_mode_purity, plot_center_trace, plot_residuals); each returns a Figure rather than calling plt.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:

  1. Rayleigh-range / frame clipping. w(z) grows with |z - z0| relative to zR = pi*w0**2/wavelength. With typical test parameters (w0=5e-3, wavelength=1.76e-3), zR is only ~4.46 cm, so z-distances spanning tens of cm put the beam many Rayleigh ranges out, where w(z) can exceed a small test frame — clipping the beam and corrupting fits, or introducing FFT wraparound artifacts in propagate_angular_spectrum. Keep z-distances within roughly ±1-2 Rayleigh ranges of z0, or enlarge the frame/pixel_scale accordingly.
  2. 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 at max_order=3 vs. matching ground truth almost exactly at max_order=1, for the same 2-mode ground truth). When demonstrating growth with deconvolution or noise, set max_order close to the true expected mode content rather than generously high, unless the test specifically targets growth behavior itself.