Write module_offset as a float, and declare offset_units
Build Packages / build:viewer-tgz:cpu (push) Successful in 13m34s
Build Packages / build:viewer-tgz:cuda (push) Successful in 15m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 19m43s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 23m14s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 18m44s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 24m21s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 18m50s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 22m37s
Build Packages / build:rpm (rocky9) (push) Successful in 19m37s
Build Packages / XDS test (durin plugin) (push) Successful in 11m11s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 19m20s
Build Packages / build:rpm (rocky8) (push) Successful in 26m9s
Build Packages / Generate python client (push) Successful in 39s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m13s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 24m8s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m22s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m20s
Build Packages / DIALS test (push) Successful in 19m31s
Build Packages / Unit tests (push) Failing after 1h22m37s
Build Packages / build:windows:nocuda (push) Successful in 11m9s
Build Packages / build:windows:cuda (push) Successful in 13m51s
Build Packages / build:viewer-tgz:cpu (push) Successful in 13m34s
Build Packages / build:viewer-tgz:cuda (push) Successful in 15m43s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 19m43s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 23m14s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 18m44s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 24m21s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 18m50s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 22m37s
Build Packages / build:rpm (rocky9) (push) Successful in 19m37s
Build Packages / XDS test (durin plugin) (push) Successful in 11m11s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 19m20s
Build Packages / build:rpm (rocky8) (push) Successful in 26m9s
Build Packages / Generate python client (push) Successful in 39s
Build Packages / Create release (push) Skipped
Build Packages / Build documentation (push) Successful in 1m13s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 24m8s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m22s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m20s
Build Packages / DIALS test (push) Successful in 19m31s
Build Packages / Unit tests (push) Failing after 1h22m37s
Build Packages / build:windows:nocuda (push) Successful in 11m9s
Build Packages / build:windows:cuda (push) Successful in 13m51s
Two latent traps in the NXtransformations attributes, both inert today and both wrong the moment they are not. module_offset was an int32 with @vector = (0,0,0). NXmx types the field NX_FLOAT, and a translation needs a unit vector to be well formed - the direction of a zero-magnitude translation is arbitrary, not absent. Now a float with (0,0,1); the transformation it describes is unchanged, since the magnitude is still zero. Every transformation that carries an @offset wrote it without @offset_units, and every caller passed an empty string. A reader then falls back to the axis's own `units` - which on a rotation axis is degrees - and converts a length from degrees to millimetres. nxmx only performs that conversion when the offset is non-zero, so ours have never triggered it, but the first non-zero offset on a goniometer axis would. The helper now always declares it, rather than leaving it to a caller to remember. Measured after the change: module_offset is H5T_IEEE_F32LE, a rotation axis carries offset_units "m" beside units "deg", dials.import still reads the file, and the tilted-geometry cross-check is unchanged at 1.6e-6 mm. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -15,6 +15,7 @@ This is an UNSTABLE release. It includes many experimental features, as well as
|
||||
* rugnux: the detector geometry is also logged in XDS's convention (`ORGX`/`ORGY`, detector axis vectors, rotation axis), so it can be compared directly with an XDS refinement.
|
||||
* HDF5: a data file missing next to a VDS master now reads as the error-pixel marker instead of zero counts, so those frames are masked rather than silently integrated as blank.
|
||||
* The writer refuses a stream whose start message declares a different pixel format than its images carry, instead of writing a master that does not describe its own data.
|
||||
* HDF5: `module_offset` is written as a float with a proper unit vector, and every transformation offset declares `offset_units`, so a reader does not fall back to the axis's own units - degrees on a rotation - when interpreting a length.
|
||||
* The image stream carries the sample transformation chain (`transformations`) in mounting order, so a goniometer axis, the Smargon chi/phi and a grid stage can be described together and unambiguously.
|
||||
* Smargon chi/phi are written for a still as well, and are read back from HDF5; before, they were dropped unless the run also had a rotation axis or a grid scan, and nothing read them.
|
||||
|
||||
|
||||
+6
-2
@@ -584,9 +584,13 @@ void NXmx::DetectorModule(const std::string &name, const std::vector<int32_t> &o
|
||||
"", "", "translation", slow_axis,
|
||||
{0,0,0}, "");
|
||||
|
||||
SaveScalar(module_group, "module_offset", 0)->
|
||||
// The module origin coincides with the detector origin, so the offset is zero - but it is still
|
||||
// a translation, and NXmx types module_offset NX_FLOAT. Write a float with a proper unit vector
|
||||
// rather than an integer with a zero-length one, which is degenerate: the direction of a
|
||||
// zero-magnitude translation is arbitrary, not absent.
|
||||
SaveScalar(module_group, "module_offset", 0.0f)->
|
||||
Transformation("m", "/entry/instrument/detector/transformations/" + nx_axis,
|
||||
"", "", "translation", {0,0,0});
|
||||
"", "", "translation", {0, 0, 1});
|
||||
}
|
||||
|
||||
void NXmx::Facility(const StartMessage &start) {
|
||||
|
||||
@@ -672,7 +672,11 @@ HDF5Object& HDF5Object::Transformation(const std::string& units, const std::stri
|
||||
const std::vector<double> &offset, const std::string& offset_units) {
|
||||
Transformation(units, depends_on, equipment, equipment_component, transformation_type, vector);
|
||||
Attr("offset", offset);
|
||||
if (!offset_units.empty()) Attr("offset_units", offset_units);
|
||||
// An offset is a length, whatever the axis is. Without this attribute a reader falls back to
|
||||
// `units`, which on a rotation axis is degrees - NXmx readers then try to convert degrees to
|
||||
// millimetres and raise. Harmless while every offset we write is zero, and wrong the moment one
|
||||
// is not, so state it always rather than only when a caller remembers to.
|
||||
Attr("offset_units", offset_units.empty() ? std::string("m") : offset_units);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user