Stop treating a goniometer axis and a grid scan as alternatives
They are not alternatives: a grid is usually collected at a particular head position, so an axis and a grid describe different parts of the same setup. The exclusion was enforced independently in four places - the API converter, the CBOR serializer, the writer and the reader - and each silently dropped the grid scan when an axis was present. Nothing warned. The writer now builds one chain from the base outwards, spindle -> chi -> phi -> helical -> grid translations, instead of two branches. NXmx applies the deepest dependency first, so the sample ends up innermost, which is what it physically is: the grid stage rides on the head and the head rides on the spindle. The grid translations consequently move inside the rotation - identical to before at omega = 0, and right rather than wrong when it is not. A grid scan with no axis at all now writes a stationary omega. NXmx has no way to say "there is no rotation", and a sample chain of translations alone is not something readers accept: dxtbx raises outright on it, so every grid-scan master we have written so far cannot be opened by DIALS. Measured on a file matching the new chain: dials.import reads it. At 0 degrees the rotation is the identity whatever the axis points along, so the conventional vector carries no geometric claim - it only has to be well formed. The API change is deliberately not breaking: no field changes type or cardinality, only the prose saying the two were exclusive, and a request that set both used to lose one silently and now does not. JFJochReader_GridScan asserted the absence of a goniometer; it now asserts the axis is present and stationary, which is the contract that matters - a grid scan must not read back as a sweep. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -688,9 +688,10 @@ void CBORStream2Serializer::SerializeSequenceStart(const StartMessage& message)
|
||||
CBOR_ENC(mapEncoder, "series_id", message.run_number);
|
||||
CBOR_ENC(mapEncoder, "fluorescence", message.fluorescence_spectrum);
|
||||
|
||||
// Both, when both are present - the decoder has always read the two keys independently.
|
||||
if (message.goniometer)
|
||||
CBOR_ENC_GONIOMETER_MAP(mapEncoder, "goniometer", message);
|
||||
else if (message.grid_scan)
|
||||
if (message.grid_scan)
|
||||
CBOR_ENC_GRID_SCAN(mapEncoder, "grid_scan", message.grid_scan.value());
|
||||
|
||||
CBOR_ENC(mapEncoder, "jungfrau_conversion_enabled", message.jungfrau_conversion_enabled);
|
||||
|
||||
Reference in New Issue
Block a user