Derive the rotation width for a chain that was sent

A chain carried in the END message was written verbatim and stopped there, so AXISNAME_end and the
rotation width - which the writer produces when it builds the chain itself - were simply absent. A
one-image sweep sent that way imported as a still, since dxtbx prefers AXISNAME_end and only falls
back to np.diff; omega_range_average is what DECTRIS-oriented tooling reads for the oscillation.

They are derived here rather than added to the wire format: for a constant step they follow from the
values, which is every case there is today, so carrying them would cost an array per axis and say
nothing new. The step is taken over the endpoints, because the values arrive as floats and a single
difference puts that noise straight into the reported width.

The test now compares the two routes on the files. It could not have caught this before: it went
through the reader, and the reader reads neither of these.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VfYvJT5Nb71suJCowRBn5z
This commit is contained in:
2026-08-23 11:20:34 +02:00
co-authored by Claude Opus 5
parent c1b6030c4f
commit 583da3c6a0
3 changed files with 36 additions and 1 deletions
+14
View File
@@ -2991,6 +2991,20 @@ TEST_CASE("JFJochReader_TransformationChain_SentAndBuilt", "[HDF5][Full]") {
CHECK(sent.GetDatasetSettings().GetSmargonPosition()->phi_deg
== Catch::Approx(-7.25f).margin(1e-3));
// Compared on the files, not through the reader: the reader reads neither AXISNAME_end nor the
// rotation width, so it cannot see the two routes diverge - and it did, until the writer started
// deriving them for a chain it was handed.
{
HDF5ReadOnlyFile built_file("test_chain_built_master.h5");
HDF5ReadOnlyFile sent_file("test_chain_sent_master.h5");
CHECK(built_file.FindLeafs("/entry/sample/transformations")
== sent_file.FindLeafs("/entry/sample/transformations"));
CHECK(sent_file.ReadVector<double>("/entry/sample/transformations/omega_end").size()
== static_cast<size_t>(x.GetImageNum()));
CHECK(sent_file.ReadVector<double>("/entry/sample/transformations/omega_range_average").at(0)
== Catch::Approx(0.1).margin(1e-4));
}
remove("test_chain_built_master.h5");
remove("test_chain_sent_master.h5");
REQUIRE(H5Fget_obj_count(H5F_OBJ_ALL, H5F_OBJ_ALL) == 0);