From eb6589f6473431d25b244c5cec045ffe4e249d00 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 19 Sep 2026 23:22:12 +0200 Subject: [PATCH] rugnux: sixteen-bit Miller indices in the ingest sort key and the post-refine partial Both arrays are one record per integrated observation - tens of millions on a fine-sliced long axis, gigabytes each - and both carry the raw hkl only to sort and group on. A Miller index needs sixteen bits (|h| <= a / d_min, in the hundreds even on the longest axis at atomic resolution), which takes the ingest sort key from 24 to 20 bytes and the post-refine partial from 32 to 28. Same comparisons, same order; merged output byte-identical. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_013nW6FNRP1bBJJ8pfHiByAT --- image_analysis/geom_refinement/PostRefine.cpp | 4 +++- image_analysis/geom_refinement/PostRefine.h | 5 ++++- image_analysis/scale_merge/RotationScaleMerge.cpp | 3 ++- image_analysis/scale_merge/RotationScaleMerge.h | 8 +++++--- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/image_analysis/geom_refinement/PostRefine.cpp b/image_analysis/geom_refinement/PostRefine.cpp index 4ad21536e..3d80f578e 100644 --- a/image_analysis/geom_refinement/PostRefine.cpp +++ b/image_analysis/geom_refinement/PostRefine.cpp @@ -219,7 +219,9 @@ PostRefineObservations GatherPostRefineObservations(std::vector(r.h), static_cast(r.k), + static_cast(r.l), r.image_number, + r.I, r.sigma, ox, oy}; } // The caller said it will never read this image's reflections again, so hand the // vector back the moment it is consumed: the payload shrinks image by image as it diff --git a/image_analysis/geom_refinement/PostRefine.h b/image_analysis/geom_refinement/PostRefine.h index b6f20833c..15d1ff4ac 100644 --- a/image_analysis/geom_refinement/PostRefine.h +++ b/image_analysis/geom_refinement/PostRefine.h @@ -94,7 +94,10 @@ struct PostRefineSettings { // per-bucket sort move all of it. The goniometer angle is not stored - it is a function of the // image number alone, and is rebuilt from it where it is needed. struct PostRefinePartial { - int h, k, l; + // Sixteen bits are plenty for a Miller index - |h| <= a / d_min, in the hundreds even on the + // longest axis at atomic resolution - and here four bytes of every partial are four bytes of an + // array that is gigabytes on a large cell. + int16_t h, k, l; float img; float I, sigma; float obs_x, obs_y; // observed spot centroid (pixels); NAN if the box sum found no centroid diff --git a/image_analysis/scale_merge/RotationScaleMerge.cpp b/image_analysis/scale_merge/RotationScaleMerge.cpp index 93c39fea9..13e526acf 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.cpp +++ b/image_analysis/scale_merge/RotationScaleMerge.cpp @@ -432,7 +432,8 @@ void RotationScaleMerge::Ingest() { for (int o = lo; o < hi; ++o) { int32_t at = src_start[o]; for (const auto &r : partials_out[o].reflections) { - keys[fill[r.h - h_min]++] = SortKey{r.h, r.k, r.l, r.image_number, at, r.d}; + keys[fill[r.h - h_min]++] = SortKey{static_cast(r.h), static_cast(r.k), + static_cast(r.l), r.image_number, at, r.d}; ++at; } } diff --git a/image_analysis/scale_merge/RotationScaleMerge.h b/image_analysis/scale_merge/RotationScaleMerge.h index 5fd1e8ca8..5731f5c11 100644 --- a/image_analysis/scale_merge/RotationScaleMerge.h +++ b/image_analysis/scale_merge/RotationScaleMerge.h @@ -142,10 +142,12 @@ private: // The narrow per-observation record the ingest sort orders: the raw hkl the runs are cut on, the // frame position that breaks a tie inside one, the observation's own index (which makes the order - // total - see the .cpp), and the resolution the range test reads. Twenty-four bytes against the - // Obs's eighty, and it is all the ingest needs before it knows which observations survive. + // total - see the .cpp), and the resolution the range test reads. Twenty bytes against the Obs's + // eighty, and it is all the ingest needs before it knows which observations survive. Sixteen bits + // are plenty for a Miller index - |h| <= a / d_min, in the hundreds even on the longest axis at + // atomic resolution - and on a long axis this array sets the sort's memory high-water mark. struct SortKey { - int32_t h, k, l; + int16_t h, k, l; float image_number; int32_t idx; float d;