rugnux: the device merge before the correction surfaces sees the collapsed-scale drop

DropCollapsedFullScales zeroes the corr of fulls whose frame scale collapsed on
the host copy of the fulls; on the resident-fulls (GPU) path that zero reached
the device only with the corrected corr pushed after the surfaces. The merge
that measures CC1/2 before the correction surfaces runs in between, so on the
GPU it still merged the dropped frames' fulls while the host path excluded
them - the two builds measured different observations.

The corr is now pushed to the device right after the drop, and the later push
covers only the surfaces and the frame rejection.

This changes the input of the two-pass quality guard (cc_half_before_corrections)
on GPU runs where a full scale collapsed; the final merge is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
leonarski_fandClaude Opus 5 committed 2026-09-20 18:45:03 +02:00
1 parent d5220014b3
commit 091ef41f8d
1 file changed
+22 -13
@@ -4841,9 +4841,8 @@ RotationScaleMerge::Result RotationScaleMerge::Run(bool for_search, bool full_st
}
// The total scale each frame's fulls were amplified by - partial scale, incident flux and the fulls'
// own G (corr = 1/G here) - taken BEFORE the correction surfaces fold per-observation terms into
// corr, and before a collapsed frame's fulls are zeroed: the resident fulls only get that zero with
// the corrected corr, so a merge on the device before then still sees them, and must weigh them by
// their own scale. Read by MergeAndStats for the CC1/2 weight.
// corr, and before a collapsed frame's fulls are zeroed (a zeroed corr says nothing about the
// frame's scale). Read by MergeAndStats for the CC1/2 weight.
frame_scale_fulls.assign(n_frames, NAN);
for (const auto &o : fulls)
if (std::isfinite(o.corr) && o.corr > 0.0f && !std::isfinite(frame_scale_fulls[o.frame])) {
@@ -4852,6 +4851,22 @@ RotationScaleMerge::Result RotationScaleMerge::Run(bool for_search, bool full_st
}
const bool rejected_full_scales =
scale_fulls && DropCollapsedFullScales(combined_on_gpu && scaled_fulls_on_gpu);
#ifdef JFJOCH_USE_CUDA
// The host fulls' corr is the truth from here on; a merge on the resident (GPU) fulls reads the
// device copy, so every change to it is pushed back before the next device merge.
auto upload_fulls_corr = [&]() {
std::vector<float> fcorr(fulls.size());
ParallelChunks(static_cast<int>(fulls.size()), ThreadsForWork(fulls.size(), nthreads),
[&](int lo, int hi) {
for (int i = lo; i < hi; ++i) fcorr[i] = fulls[i].corr;
});
gpu_->SetFullsCorr(fcorr.data());
};
// Right away, not with the corrections below: the merge just before the surfaces must see the
// collapsed frames' fulls gone on the device exactly as the host merge does.
if (rejected_full_scales && combined_on_gpu && scaled_fulls_on_gpu)
upload_fulls_corr();
#endif
// --- 4b. Optional correction surfaces (decay = resolution x time; absorption = goniometer-frame
// diffracted-beam direction), each an alternating multiplicative fit of the fulls' corr against
@@ -4917,16 +4932,10 @@ RotationScaleMerge::Result RotationScaleMerge::Run(bool for_search, bool full_st
CountSweepDisposition();
}
#ifdef JFJOCH_USE_CUDA
// The corrections mutate the host fulls' corr; when the merge runs on the resident (GPU) fulls, push
// the corrected corr back to the device so the merge reads it.
if ((corrections || rejected_full_scales || rejected_frames) && combined_on_gpu && scaled_fulls_on_gpu) {
std::vector<float> fcorr(fulls.size());
ParallelChunks(static_cast<int>(fulls.size()), ThreadsForWork(fulls.size(), nthreads),
[&](int lo, int hi) {
for (int i = lo; i < hi; ++i) fcorr[i] = fulls[i].corr;
});
gpu_->SetFullsCorr(fcorr.data());
}
// The corrections and the frame rejection mutate the host fulls' corr; push it to the device so the
// merge reads it. (The collapsed-scale drop was pushed where it happened.)
if ((corrections || rejected_frames) && combined_on_gpu && scaled_fulls_on_gpu)
upload_fulls_corr();
#endif
// --- 5. Error model + merge + statistics. ---