rugnux: scale self-referenced stills in a single pass (fix weak-data collapse)
The stills self-scaling loop rebuilt the merge reference FROM the just-scaled reflections every iteration, so on weak data each pass re-fit its own noise and the merged CC1/2 collapsed (PfluDING combine: 0.3% at the default 3 iters). It is provably pointless too: ScaleOnTheFly::Scale re-solves the per-image G from raw I and never reads the prior correction, so against a fixed reference passes 2..N are bit-identical - the single G is the exact one-pass solution and iteration only ever does the harmful reference rebuild (N=1 is best on every dataset, including strong lyso 82% vs 76% at N=3; leave-one-out and external anchors were tested and do not beat it). Do one self-reference pass; rotation (RotationScaleMerge) and the external-reference branch are untouched. Validated: PfluDING-combined CC1/2 0.3% -> 42.0% by default (pinned 2.5 A); strong data unchanged. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+6
-6
@@ -594,12 +594,12 @@ ProcessResult Rugnux::Run(RugnuxObserver *observer) {
|
||||
// running merge with ScaleOnTheFly (fixed partiality), then merge directly. With an external
|
||||
// reference each image is already scaled against it during the per-image pass, so skip.
|
||||
if (config_.reference_data.empty()) {
|
||||
for (int i = 0; i < config_.scaling_iter; i++) {
|
||||
phase("Scaling images (" + label + ", iteration " + std::to_string(i + 1) + "/"
|
||||
+ std::to_string(config_.scaling_iter) + ")");
|
||||
auto merge_result = MergeAll(experiment_, indexer->GetIntegrationOutcome(), false);
|
||||
indexer->ScaleAllImages(merge_result);
|
||||
}
|
||||
// One pass: the per-image scale G is the exact one-pass solution, so iterating only
|
||||
// rebuilds the reference from the freshly-scaled (noisy) data - degrading weak stills
|
||||
// instead of converging (measured CC1/2 collapse at the default 3 iters on weak data).
|
||||
phase("Scaling images (" + label + ")");
|
||||
auto merge_result = MergeAll(experiment_, indexer->GetIntegrationOutcome(), false);
|
||||
indexer->ScaleAllImages(merge_result);
|
||||
}
|
||||
const std::vector<IntegrationOutcome> &merge_input = indexer->GetIntegrationOutcome();
|
||||
|
||||
|
||||
@@ -1035,7 +1035,12 @@ int main(int argc, char **argv) {
|
||||
merged_statistics = std::move(r.statistics);
|
||||
error_model_isa = r.isa;
|
||||
} else {
|
||||
for (int i = 0; i < scaling_iter; i++) {
|
||||
// The per-image scale G is the exact one-pass solution (Scale re-solves from raw I and never
|
||||
// reads the prior correction), so with a self-rebuilt reference iterating only re-fits the
|
||||
// freshly-scaled noise and degrades weak stills (measured CC1/2 collapse at the default 3
|
||||
// iters). Scale the self-reference merge once; a fixed external reference keeps scaling_iter.
|
||||
const int n_self = reference_data.empty() ? 1 : scaling_iter;
|
||||
for (int i = 0; i < n_self; i++) {
|
||||
if (reference_data.empty())
|
||||
ScaleOnTheFly(experiment, MergeAll(experiment, reflections)).Scale(reflections, nthreads);
|
||||
else
|
||||
|
||||
Reference in New Issue
Block a user