diff --git a/reader/HDF5MetadataSource.cpp b/reader/HDF5MetadataSource.cpp index 95bfc19a..40469725 100644 --- a/reader/HDF5MetadataSource.cpp +++ b/reader/HDF5MetadataSource.cpp @@ -1099,6 +1099,13 @@ std::vector HDF5MetadataSource::ReadReflections(size_t start std::vector ret; ret.reserve(end_image_val - start_image + 1); + // A self-contained integrated _process.h5 keeps all reflections in this master (one group per + // indexed image), so a missing per-image group means that image simply has none - never fall + // back to the linked source pixel files (which may be absent, and never hold a snapshot's + // reflections). A legacy/VDS acquisition has no /entry/reflections in the master and resolves + // reflections lazily from the source data files instead. + const bool master_reflections_authoritative = master_file->Exists("/entry/reflections"); + for (size_t img = start_image; img <= end_image_val; img++) { IntegrationOutcome outcome; @@ -1112,7 +1119,7 @@ std::vector HDF5MetadataSource::ReadReflections(size_t start HDF5ReadOnlyFile *meta_file = master_file.get(); size_t meta_image_id = img; std::string refl_group = fmt::format("/entry/reflections/image_{:06d}", img); - if (!master_file->Exists(refl_group)) { + if (!master_reflections_authoritative && !master_file->Exists(refl_group)) { const auto loc = ResolveMeta(static_cast(img)); meta_file = loc.file.get(); meta_image_id = loc.local_index; diff --git a/rugnux/rugnux_cli.cpp b/rugnux/rugnux_cli.cpp index 33d55ebc..e9f86dc1 100644 --- a/rugnux/rugnux_cli.cpp +++ b/rugnux/rugnux_cli.cpp @@ -986,6 +986,9 @@ int main(int argc, char **argv) { scaling_settings.MinCapturedFraction(min_captured_fraction_arg.value_or( (experiment.GetGoniometer().has_value() && !force_still) ? 0.7 : 0.0)); scaling_settings.MinCCForImage(min_image_cc / 100.0); // --min-image-cc is percent; the setting is a fraction + scaling_settings.OutlierRejectNsigma( + outlier_reject_nsigma.value_or( + (experiment.GetGoniometer().has_value() && !force_still) ? REJECT_OUTLIERS_DEFAULT_NSIGMA : 0.0)); if (intensity_format) scaling_settings.FileFormat(intensity_format.value()); experiment.ImportScalingSettings(scaling_settings); @@ -1031,6 +1034,15 @@ int main(int argc, char **argv) { } MergeOnTheFly merge_engine(experiment); merge_engine.ReferenceCell(experiment.GetUnitCell()); + // Fit the (a, b) error model from symmetry-mate scatter before merging, exactly as the full + // pipeline does (Rugnux.cpp). Without this the offline --scale merge would use the identity + // model and produce much worse stills intensities (no (b*I)^2 systematic term, no sigma floor). + merge_engine.RefineErrorModel(reflections); + if (merge_engine.ErrorModelActive()) + logger.Info("Error model: a={:.3f} b={:.3f} ISa={:.1f} chi2={:.2f}", merge_engine.ErrorModelA(), + merge_engine.ErrorModelB(), + merge_engine.ErrorModelB() > 0 ? 1.0 / merge_engine.ErrorModelB() : 0.0, + merge_engine.ErrorModelChi2()); for (size_t i = 0; i < reflections.size(); ++i) merge_engine.AddImage(reflections[i], static_cast(i)); merged_reflections = merge_engine.ExportReflections();