api: record the beam size at the sample, and write it where NXmx puts it

dataset_settings gains beam_size_x_um and beam_size_y_um, the horizontal and
vertical size of the X-ray beam where it meets the sample. They follow the same
route total_flux takes - OpenAPI, DatasetSettings, the CBOR start message, the
HDF5 master, and back out of a stored file - and nothing consumes them; this is
metadata a beamline can state and a downstream program can read.

NXmx puts this in the application definition rather than the base class: not
NXbeam's extent (rank 2, nP x 2, per scan point, always FWHM of a rectangular
aperture) but NXmx's own incident_beam_size, a recommended rank-1 two-element
array in the order x, y. Both are live and neither is deprecated, so the choice
matters; the MX definition wins in an MX file. Written as one array with a
units attribute of "m", like every other length in the master, so the settings
hold micrometres and FillMessage converts once.

The unit table of ReadLength_m becomes LengthUnitFactor so the array read can
share it: a master written elsewhere may state this in millimetres.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
2026-09-02 09:59:34 +02:00
co-authored by Claude Opus 5
parent 7890149ad6
commit 8a04773d1d
20 changed files with 253 additions and 10 deletions
@@ -1276,6 +1276,10 @@ namespace {
message.incident_wavelength = GetCBORFloat(value);
else if (key == "incident_wavelength_spread")
message.incident_wavelength_spread = GetCBORFloat(value);
else if (key == "beam_size_x")
message.beam_size_x = GetCBORFloat(value);
else if (key == "beam_size_y")
message.beam_size_y = GetCBORFloat(value);
else if (key == "frame_time")
message.frame_time = GetCBORFloat(value);
else if (key == "count_time")