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>
This commit is contained in:
Martino Ferrari
2026-07-02 21:47:40 +02:00
commit 03b63ba03a
31 changed files with 3341 additions and 0 deletions
+223
View File
@@ -0,0 +1,223 @@
# he11lib API Reference
`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.
See `examples/full_pipeline_example.py` for a runnable end-to-end
demonstration, and
`docs/superpowers/specs/2026-07-02-gyrotron-mode-purity-design.md` for the
full design rationale.
Every class/function below is exported from the top-level `he11lib` package
(e.g. `from he11lib import BeamReconstructor`), except where noted.
## Quick start
```python
from he11lib import BeamReconstructor, MeasurementPlane
# planes: a list of >=3 MeasurementPlane objects built from your own
# flux arrays (see MeasurementPlane below).
reconstructor = BeamReconstructor(w0=5e-3, z0=0.5, wavelength=1.76e-3)
result = reconstructor.reconstruct(planes)
for mode, (power_fraction, phase_rad) in result.purity.items():
print(mode, power_fraction, phase_rad)
```
## `data` — `MeasurementPlane`, `ReconstructionResult`
### `MeasurementPlane(flux, z, pixel_scale=None, viewing_angle_deg=None, label=None)`
One measurement: a 2D flux array plus its acquisition metadata.
- `flux` — 2D `np.ndarray` of flux values. Dead-pixel correction, background
subtraction, and saturation clipping are assumed already handled upstream.
- `z` — nominal distance from the output window, in meters. Must be `> 0`.
- `pixel_scale` — known meters/pixel, or `None` if unknown (then jointly
fit by `ModalFitter`/`BeamReconstructor`).
- `viewing_angle_deg` — known camera viewing angle relative to the beam
axis, in degrees, or `None` if unknown (also jointly fit).
- `label` — optional human-readable identifier.
### `validate_planes(planes)`
Raises `ValueError` if there are fewer than 3 planes, planes have
mismatched flux shapes, or `z` values are not all distinct. Called
internally by `ModalFitter.fit`/`fit_auto`, `PhaseRetriever.retrieve`, and
`BeamReconstructor.reconstruct` — you generally don't need to call it
yourself. Not exported from the top-level package; import via
`from he11lib.data import validate_planes` if needed.
### `ReconstructionResult`
Output of a full reconstruction (returned by `ModalFitter.fit`/`fit_auto`
and `BeamReconstructor.reconstruct`):
- `purity: dict[(p, l), (power_fraction, phase_rad)]`
- `reconstructed_field: np.ndarray` — reconstructed complex field.
- `centers: list[(x, y)]` — fitted beam transverse center per plane, meters.
- `pointing_angle_deg: float` — fitted shared beam pointing angle (tilt).
- `geometry: dict[str, float]` — geometry parameters used or fitted (keys
`pixel_scale_{i}`, `viewing_angle_deg_{i}` per plane index `i`).
- `residuals: list[np.ndarray]` — per-plane (measured modeled) flux maps.
Empty when `used_phase_retrieval` is `True`.
- `coefficient_uncertainty: dict[(p, l), float]` — 1-sigma uncertainty on
each mode's fitted power fraction. `NaN` per mode when
`used_phase_retrieval` is `True`.
- `used_phase_retrieval: bool` — whether the phase-retrieval fallback (not
the modal fit) produced this result.
## `modes` — `LGBasis`
`LGBasis(w0, z0, wavelength)` — the LG mode basis referenced to a known
waist radius `w0` (m), waist location `z0` (m), and radiation `wavelength`
(m).
- `beam_radius(z)``w(z)`.
- `inverse_radius_of_curvature(z)``1/R(z)` (well-defined, `0`, at the
waist).
- `gouy_phase(z, p, l)` — Gouy phase of mode `(p, l)` at `z`.
- `field(x, y, z, p, l)` — complex `LG_{p,l}` field sampled on the `(x, y)`
grid at distance `z`.
- `field_superposition(x, y, z, coefficients)` — complex field for
`coefficients: dict[(p, l), complex]`.
- `project(complex_field, x, y, dx, z, modes)` — projects `complex_field`
onto each `(p, l)` in `modes`, returning `dict[(p, l), complex]`
coefficients (Riemann-sum inner product; `dx` is the grid spacing).
## `geometry` — `GeometryCalibration`
`GeometryCalibration(plane)` wraps a single `MeasurementPlane` and resolves
its pixel-to-physical-coordinate mapping.
- `pixel_scale_known` / `viewing_angle_known``bool` properties.
- `physical_coordinates(pixel_scale=None, viewing_angle_deg=None)`
returns `(x, y)` physical coordinate grids matching the plane's flux
shape. Values known on the `MeasurementPlane` take precedence over the
`override` arguments; raises `ValueError` if a value is neither known nor
overridden.
## `noise` — `NoiseEstimator`
`NoiseEstimator()` — automatic per-image noise estimation (no
user-supplied noise parameter needed).
- `estimate_std(image)` — fast Laplacian-based (Immerkær 1996) noise
standard-deviation estimate.
- `weights(image)` — per-pixel weights (`1/sigma**2`) for noise-weighted
least squares.
## `deconvolution` — `DiffusionDeconvolver`
`DiffusionDeconvolver(thermal_diffusivity, dwell_time)` — optional
correction for lateral thermal-diffusion blur in the absorbing target
(`thermal_diffusivity` in m²/s, `dwell_time` in s). Disabled unless you
pass a `deconvolver` to `BeamReconstructor`.
- `blur_sigma_m()` — Gaussian blur standard deviation, in meters.
- `blur(image, pixel_scale)` — forward blur (for synthetic testing).
- `deconvolve(image, pixel_scale, noise_to_signal_ratio=1e-3)` — regularized
(Wiener) removal of the blur.
Note: the blur/deconvolution kernel is isotropic in pixel space. If a
plane has a nonzero `viewing_angle_deg`, its `x` and `y` pixel axes have
different physical scales (see `SyntheticBeamGenerator` below), so
deconvolution is only exact for `viewing_angle_deg == 0`; at oblique
angles it is an approximation.
## `synthetic` — `SyntheticBeamGenerator`
`SyntheticBeamGenerator(basis, image_shape, pixel_scale)` — forward model
used to validate the pipeline against known ground truth, and to evaluate
experimental design (e.g. "would these distances separate my modes?").
`pixel_scale` is the physical pixel size, in meters, along the non-tilted
`y` axis; the `x` axis is compressed by `1/cos(viewing_angle_deg)` to model
an oblique camera view.
- `generate(coefficients, z_list, *, center=(0, 0), pointing_angle_deg=0.0, viewing_angle_deg=0.0, noise_std=0.0, seed=None)`
— returns one `MeasurementPlane` per `z` in `z_list`. The beam's
transverse center drifts linearly with `z` according to
`pointing_angle_deg`, starting from `center` at `z0`.
## `fitting` — `ModalFitter`, `generate_mode_shells`
### `generate_mode_shells(max_order)`
Groups candidate `LG_{p,l}` modes into shells of increasing order
`2p + |l|`, up to and including `max_order`. Returns
`list[list[(p, l)]]`, one list of modes per order.
### `ModalFitter(basis, noise_estimator=None)`
Core reconstruction path: a joint nonlinear least-squares fit of complex LG
coefficients, beam center/pointing, and (if unknown) geometry.
- `fit(planes, modes, initial_coefficients=None, initial_center=(0.0, 0.0), initial_tilt_deg=(0.0, 0.0), initial_pixel_scale=None, initial_viewing_angle_deg=0.0) -> ReconstructionResult`
— fits exactly the given candidate `modes`.
- `fit_auto(planes, max_order=4, bic_improvement_threshold=10.0) -> ReconstructionResult`
— starts from `LG_00` and grows the candidate mode set shell-by-shell
(via `generate_mode_shells`), stopping once BIC no longer improves by
more than `bic_improvement_threshold`, capped at `max_order`. Emits a
`UserWarning` (does not raise) if the cap is reached while the fit is
still improving.
## `phase_retrieval` — `PhaseRetriever`, `propagate_angular_spectrum`
Fallback reconstruction path for when the modal fit's residual stays high,
or when the mode content isn't well described by a small finite mode set.
### `propagate_angular_spectrum(field, dx, dz, wavelength)`
Free-space-propagates a complex `field` (pixel spacing `dx`) by distance
`dz` via the (paraxial) angular-spectrum method — the same propagation
model implicitly assumed by `LGBasis`'s closed-form paraxial modes.
### `PhaseRetriever(wavelength)`
- `retrieve(planes, pixel_scale=None, viewing_angle_deg=None, max_iterations=200) -> PhaseRetrievalResult`
— multi-plane Gerchberg-Saxton phase retrieval: propagates a trial
complex field back and forth between planes, enforcing the measured
amplitude (`sqrt(flux)`) at each plane, without assuming a finite mode
basis.
### `PhaseRetrievalResult`
`field, x, y, z, center, residual` — the recovered complex field (at the
smallest-`z` plane) on its `(x, y)` grid, the estimated beam center
(intensity centroid), and the final RMS amplitude-mismatch residual.
Project `field` onto `LGBasis` (via `LGBasis.project`) to get a purity
table, as `BeamReconstructor` does internally for its fallback path.
## `reconstruct` — `BeamReconstructor`
`BeamReconstructor(w0, z0, wavelength, max_order=4, noise_estimator=None, deconvolver=None, force_phase_retrieval=False, phase_retrieval_residual_threshold=None)`
High-level orchestrator wiring together the full pipeline: optional
diffusion deblurring → `ModalFitter.fit_auto` → optional
`PhaseRetriever` fallback.
- `reconstruct(planes) -> ReconstructionResult`
1. Validates `planes` (see `validate_planes`).
2. If `deconvolver` is set, deblurs each plane (raises `ValueError` if a
plane's `pixel_scale` isn't known).
3. Runs `ModalFitter(basis, noise_estimator).fit_auto(planes, max_order)`.
4. Runs the `PhaseRetriever` fallback instead, projecting its recovered
field onto all modes up to `max_order`, if `force_phase_retrieval` is
`True`, or if `phase_retrieval_residual_threshold` is set and the
modal fit's noise-weighted RMS residual exceeds it. In that case
`result.residuals` is empty and `coefficient_uncertainty` is `NaN`
per mode (phase retrieval doesn't produce a fit covariance).
## `plotting` — diagnostic visualizations
Each function returns a `matplotlib.figure.Figure` for the caller to
display (`fig.show()`) or save (`fig.savefig(...)`); none of them call
`plt.show()` themselves.
- `plot_mode_purity(result)` — bar chart of power fraction per mode.
- `plot_center_trace(planes, result)` — fitted beam center `(x, y)` vs. `z`.
- `plot_residuals(planes, result)` — per-plane residual maps. Raises
`ValueError` if `result.residuals` is empty (e.g. after the
phase-retrieval fallback).