A master with known modules (every geometry-transformed JUNGFRAU since
10bdf1d11, and inputs with CrystFEL/CXI/XTC geometry) carried the whole-image
/entry/instrument/detector/module beside module_0..N. DIALS takes every
NXdetector_module as a panel: a JF4M file became 9 panels and dials.find_spots
counted every spot twice (5-image JF4M test file: 7124 spots, 3562 of them on
the whole-image panel). The whole-image module is now written only when there
are no modules; then 8 panels, 3562 spots, the same per panel as before.
Three things DIALS needs for the module-only layout to come out right:
- dxtbx lists the groups by name, so module_10 came before module_2 and DIALS
panel n was not module n (nor the index /entry/MX/peakPanel gives). The index
is zero-padded to the width of the last one: module_0..7, module_00..15.
- For several modules dxtbx builds panel groups from runs of transformations
sharing an equipment_component and composes a group in reverse depends_on
order: with translation and rot1-3 all "detector_arm" the translation stayed
unrotated on a tilted detector (CI dials_tilted: 5.6 mm off). The detector
transformations no longer name one; each is then its own level.
- data_origin/data_size stay [row, column], which dxtbx reads as slow, fast.
Reader: ReadNXmxModules accepts padded and unpadded names; the image
orientation is taken from the whole-image module, then detectorSpecific, and
only then from the first module, whose axes are its own placement. Old files
(whole-image only, whole-image + module_N) read as before.
DetectorModules::Moved() compares within 1e-3 px: a module read back went
through a float length and unit vector, ~1e-4 px off, so an as-imaged JUNGFRAU
read back as moved and a rotation run on such a file kept its modules instead
of processing one panel (rugnux: "placed off the image's own grid" on a
jfjoch_hdf5_test JF4M file).
Test: JFJochReader_VerticalModules, the CrMX layout (vertical modules, mirrored
in Y), identity and a mirrored quarter-turn orientation, round trip incl.
orientation. tests/nxmx_geometry_dials_test.py maps pixels through the panel
holding them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVeDQqrcrEZy6XBUCMZvyT