Files
he11lib/docs/api.md
T
Martino Ferrari c6b824660d Update docs/api.md for the CameraModel geometry redesign
Documents CameraModel/CameraModelTolerance, the rewritten
GeometryCalibration, z_tolerance, the two pointing angles, and every
downstream signature change (ModalFitter, SyntheticBeamGenerator,
PhaseRetriever, BeamReconstructor) introduced by the redesign.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-03 12:33:00 +02:00

308 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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,
CameraModel,
CameraModelTolerance,
MeasurementPlane,
)
# planes: a list of >=3 MeasurementPlane objects built from your own
# flux arrays (see MeasurementPlane below).
# Nominal camera pose/intrinsics from calibration; every field here is
# refined jointly with the mode fit because its tolerance is nonzero.
camera = CameraModel(
focal_length_px=2000.0,
position=(0.0, 0.0, -2.0),
orientation_deg=(0.0, 0.0, 0.0),
)
camera_tolerance = CameraModelTolerance(
focal_length_px=20.0,
position=(0.01, 0.01, 0.05),
orientation_deg=(2.0, 2.0, 2.0),
)
reconstructor = BeamReconstructor(
w0=5e-3, z0=0.5, wavelength=1.76e-3,
camera=camera, camera_tolerance=camera_tolerance,
)
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, z_tolerance=0.0, 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`.
- `z_tolerance``+/-` bound, in meters, around the nominal `z` within
which the true distance is jointly refined by `ModalFitter`. Must be
`>= 0`; `0` (the default) means `z` is trusted exactly and held fixed.
- `label` — optional human-readable identifier.
Per-plane camera geometry (`pixel_scale`/`viewing_angle_deg`) no longer
lives on `MeasurementPlane` — camera pose/intrinsics are a single shared
`CameraModel` for the whole reconstruction (see `geometry` below).
### `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_horizontal_deg`, `pointing_angle_vertical_deg: float`
fitted shared beam pointing (tilt) angles, independent horizontal and
vertical.
- `geometry: dict[str, float]` — geometry parameters used or fitted: the 9
`CameraModel` field names from `he11lib.geometry.CAMERA_FIELD_NAMES`
(`focal_length_px`, `position_x`, `position_y`, `position_z`, `yaw_deg`,
`pitch_deg`, `roll_deg`, `principal_point_x`, `principal_point_y`), plus
`z_{i}` per plane index `i` (that plane's fitted/held distance).
- `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` — `CameraModel`, `CameraModelTolerance`, `GeometryCalibration`
### `CameraModel(focal_length_px, position, orientation_deg, principal_point=(0.0, 0.0))`
A nominal pinhole camera pose/intrinsics shared across every plane in one
reconstruction. Always a point estimate — never trusted as exact by
itself; trust is expressed via the paired `CameraModelTolerance`.
- `focal_length_px` — focal length in pixel units.
- `position``(x, y, z)` camera position in the beam-axis world frame,
meters; `z=0` is the output window.
- `orientation_deg``(yaw, pitch, roll)`, degrees. All-zero means the
boresight is normal to every `z=const` target plane with no in-plane
rotation.
- `principal_point``(px, px)` offset from the frame center.
### `CameraModelTolerance(focal_length_px, position, orientation_deg, principal_point=(0.0, 0.0))`
Per-field `+/-` refinement bound, same shape as `CameraModel`. Every field
must be `>= 0` (raises `ValueError` otherwise). A field's tolerance of `0`
holds that `CameraModel` field fixed at its nominal value during fitting;
`> 0` lets `ModalFitter` refine it within `[nominal - tolerance, nominal +
tolerance]`.
### `GeometryCalibration(camera)`
Wraps a `CameraModel` and resolves pixel <-> physical coordinate mappings
via true pinhole projection (not a uniform affine/cosine approximation).
- `pixel_coordinates(x, y, z) -> (row, col)` — forward-projects physical
`(x, y)` at depth `z` to pixel coordinates. Raises `ValueError` if the
point is behind the camera (`Z_cam <= 0`).
- `physical_coordinates(image_shape, z) -> (x, y)` — inverse-projects every
pixel in a frame of `image_shape` to physical `(x, y)` on the `z=const`
plane, via ray-plane intersection (this is what produces genuine
keystoning — non-uniform spacing across the frame — for tilted/off-axis
poses). Raises `ValueError` if the plane is edge-on to or behind the
camera.
- `effective_pixel_scale(image_shape, z) -> float` — a single isotropic
meters/pixel figure (finite-difference approximation at the frame
center), for callers like `DiffusionDeconvolver` that assume one
isotropic pixel-space kernel.
### `CAMERA_FIELD_NAMES`, `camera_to_values`, `tolerance_to_values`, `camera_from_values`
Module-level helpers used internally by `ModalFitter` to flatten/unflatten
`CameraModel`/`CameraModelTolerance` into the optimizer's parameter vector.
Not usually needed by application code, but exported for advanced use
(e.g. inspecting `CAMERA_FIELD_NAMES` to interpret `ReconstructionResult.geometry` keys).
## `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. A tilted
or off-axis `CameraModel` produces a pixel scale that varies across the
frame and between `x`/`y` (keystoning), so `deconvolve` uses
`GeometryCalibration.effective_pixel_scale` — a single isotropic
approximation evaluated at the frame center. This is exact only for an
on-axis, untilted camera; at oblique poses it is an accepted
approximation (see `CLAUDE.md`).
## `synthetic` — `SyntheticBeamGenerator`
`SyntheticBeamGenerator(basis, camera)` — forward model used to validate
the pipeline against known ground truth, and to evaluate experimental
design. `camera` is the ground-truth `CameraModel` (position/orientation/
intrinsics) used to render each plane via true perspective projection.
- `generate(coefficients, z_list, image_shape, *, center=(0.0, 0.0), pointing_angle_horizontal_deg=0.0, pointing_angle_vertical_deg=0.0, z_tolerance=0.0, nominal_z_offsets=None, noise_std=0.0, seed=None) -> list[MeasurementPlane]`
— returns one `MeasurementPlane` per (true) `z` in `z_list`. The beam's
transverse center drifts linearly with `z` according to the two
independent pointing angles, starting from `center` at the basis's
`z0`. `nominal_z_offsets`, if given, maps a true `z` to an offset
applied to that plane's *nominal* `z` — letting a reconstruction be
tested against a deliberately-offset nominal input while the plane's
flux is still rendered at the true `z`. Every resulting plane shares
`z_tolerance`.
## `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 any nonzero-tolerance camera/`z`
geometry.
- `fit(planes, modes, camera, camera_tolerance, initial_coefficients=None, initial_center=(0.0, 0.0), initial_pointing_deg=(0.0, 0.0)) -> ReconstructionResult`
— fits exactly the given candidate `modes`. Every `CameraModel` field
with a nonzero `camera_tolerance` entry, and every plane whose
`z_tolerance` is nonzero, is refined within `[nominal - tolerance,
nominal + tolerance]`; zero-tolerance fields are held fixed at their
nominal value.
- `fit_auto(planes, camera, camera_tolerance, 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, or if the number of free camera+`z` parameters is large
relative to the number of planes (see `CLAUDE.md`'s degeneracy pitfall).
## `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, camera, 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. All planes are propagated on one common physical grid, derived
from `camera` at the smallest-`z` plane's depth.
### `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, camera, camera_tolerance, 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. `camera`/`camera_tolerance` are the nominal
shared `CameraModel` and its per-field refinement bounds for this
reconstruction.
- `reconstruct(planes) -> ReconstructionResult`
1. Validates `planes` (see `validate_planes`).
2. If `deconvolver` is set, deblurs each plane using
`GeometryCalibration(camera).effective_pixel_scale(plane.flux.shape, plane.z)`.
3. Runs `ModalFitter(basis, noise_estimator).fit_auto(planes, camera, camera_tolerance, 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, `coefficient_uncertainty` is `NaN` per
mode, `geometry` is empty, and both pointing-angle fields are `NaN`
(phase retrieval doesn't fit geometry/pointing or 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).