Make the saturation limit convert once, in one place
The limit is EXCLUSIVE inside Jungfraujoch - the first value that is no longer a count - and NXmx saturation_value is INCLUSIVE, the highest value that still is one. XDS OVERLOAD and the DIALS trusted_range read it inclusively too. The write side subtracted the count and no read side added it back, so the value fell by one on every write-read-write cycle, unbounded: four chained runs over one dataset gave 32766, 32765, 32764, 32763. It also fed the preprocessor, so one more real count was called saturated after each cycle. SaturationValueFromLimit / SaturationLimitFromValue now carry the conversion, used by the writer and by all three readers (HDF5, the lite receiver, the viewer). JFJochReaderImage's summation test moves from > to >= in the same commit: it was silently compensating for the missing count, and correcting one without the other would have shifted it instead. Two more places said the wrong thing about the same pixels: error_value was GetUnderflow(), which is -1 for an unsigned image - a value no unsigned pixel can hold. The marker those images really carry is UINTx_MAX, and GetImageFillValue() already returned it, so the class held two disagreeing definitions of one marker. bit_depth_readout is now written for unsigned images only. DIALS remaps the top two codes of 2^bit_depth_readout to -1 and -2 whenever the field is present, without looking at the pixel type. For an unsigned image those fall below underload_value and are masked, which is what we want. For a signed one they land INSIDE the trusted range, so a saturated pixel reached DIALS as a trusted count of -2 - on the strongest reflections. Verified with DIALS 3.27: an int32 file now masks both sentinels. The field stays where it earns its keep, since dxtbx cannot read unsigned 32-bit without it. Neither the values themselves nor the wire format change. Verified against NXmx, DECTRIS SIMPLON, Durin (Global Phasing fork), XDS and DIALS 3.27; the chained run now holds at 32766. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VfYvJT5Nb71suJCowRBn5z
This commit is contained in:
@@ -748,7 +748,8 @@ HDF5MetadataSource::OpenResult HDF5MetadataSource::Open(const std::string &filen
|
||||
detector.SensorThickness_um(master_file->GetFloat("/entry/instrument/detector/sensor_thickness") * 1e6);
|
||||
if (master_file->Exists("/entry/instrument/detector/sensor_material"))
|
||||
detector.SensorMaterial(master_file->GetString("/entry/instrument/detector/sensor_material"));
|
||||
detector.SaturationLimit(master_file->GetInt("/entry/instrument/detector/saturation_value"));
|
||||
detector.SaturationLimit(SaturationLimitFromValue(
|
||||
master_file->GetInt("/entry/instrument/detector/saturation_value")));
|
||||
// The reader hands every image out as signed int32 whatever the file stored (see PixelSigned
|
||||
// below), so that is the container depth the rest of the code has to see. DetectorSetup defaults
|
||||
// DECTRIS to 16 bits and GetByteDepthImage() prefers the detector's value over the image
|
||||
|
||||
Reference in New Issue
Block a user