From 009555bc49b0aa23a55af06220e13ad4d6d054e6 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Thu, 30 Jul 2026 10:55:19 +0200 Subject: [PATCH] Spot finding: a zero high-resolution limit means no limit here too Every other reader of spot_finding.high_resolution_limit spells "unset" as value_or(0) and compares, so 0 and nullopt are interchangeable - except in SpotAnalyze, which passed the 0 straight to ResolutionShells and threw "Resolution must be above zero" on every image. Reachable over the REST API, where 0 is the natural way to say "no limit" and the settings check lets it through; the rugnux CLI already maps 0 to unset before this point. While here, check that a limit that IS set is finite regardless of its sign - NaN fails the > 0 test and was skipping validation entirely. Co-Authored-By: Claude Opus 5 (1M context) --- common/DiffractionExperiment.cpp | 5 ++++- image_analysis/spot_finding/SpotUtils.cpp | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/common/DiffractionExperiment.cpp b/common/DiffractionExperiment.cpp index 21068756..8ca90dc6 100644 --- a/common/DiffractionExperiment.cpp +++ b/common/DiffractionExperiment.cpp @@ -614,8 +614,11 @@ void DiffractionExperiment::CheckDataProcessingSettings(const SpotFindingSetting check_finite("Spot finding low resolution limit", settings.low_resolution_limit); // An unset high-resolution limit means "as far as the detector reaches", so there is nothing to check. - if (settings.high_resolution_limit.value_or(0.0f) > 0) { + // A value that is present still has to be finite - NaN fails every comparison below, so testing it + // inside the branch would let it through unchecked. + if (settings.high_resolution_limit.has_value()) check_finite("Spot finding high resolution limit", *settings.high_resolution_limit); + if (settings.high_resolution_limit.value_or(0.0f) > 0) { check_min("Spot finding high resolution limit", *settings.high_resolution_limit, 0.5); check_max("Spot finding high resolution limit", *settings.high_resolution_limit, 50.0); if (settings.low_resolution_limit > 0) { diff --git a/image_analysis/spot_finding/SpotUtils.cpp b/image_analysis/spot_finding/SpotUtils.cpp index 638e0c7c..210cf595 100644 --- a/image_analysis/spot_finding/SpotUtils.cpp +++ b/image_analysis/spot_finding/SpotUtils.cpp @@ -147,8 +147,11 @@ void SpotAnalyze(const DiffractionExperiment &experiment, CountSpots(output, spots_out, spot_finding_settings.cutoff_spot_count_low_res); + // 0 spells "no limit" everywhere else the limit is read (value_or(0) then compares against it), so it + // has to mean the same here - passing it on as a resolution makes ResolutionShells throw per image. + const auto &spot_d_min = spot_finding_settings.high_resolution_limit; GenerateSpotPlot(output, spots_out, - spot_finding_settings.high_resolution_limit.value_or(experiment.GetDetectorMaxResolution_A())); + spot_d_min.value_or(0.0f) > 0 ? *spot_d_min : experiment.GetDetectorMaxResolution_A()); output.resolution_estimate = GetResolution(spots_out);