Files
Jungfraujoch/tests/PostRefineTest.cpp
T
leonarski_fandClaude Opus 5 d245ae9d30 PostRefine: report the realised held-out residual, its noise and the starting cell
Each post-refinement now records, beside what it commits, what the integration
it was handed realises at the geometry it started from: the held-out residual
at nominal (the same value the log prints on the left of "held-out ... ->"),
its standard error over the held-out residual values, and the cell the pass's
own indexing refined. Nothing here changes a decision.

Two helpers read them: HeldOutResidualFell (a pass at a new geometry realises a
lower residual than another by more than the standard error of the difference)
and ReindexPushesCellBack (re-indexing at a committed geometry returns, on the
length the fit moved most, a cell on the side the fit moved away from). The
geometry walk in RunAllPasses uses both in the next commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-20 18:45:03 +02:00

54 lines
2.3 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include <catch2/catch_all.hpp>
#include "../image_analysis/geom_refinement/PostRefine.h"
namespace {
PostRefineResult Measured(double residual, double se) {
PostRefineResult r;
r.held_out_before = residual;
r.held_out_before_se = se;
return r;
}
PostRefineResult Fit(UnitCell before, UnitCell after) {
PostRefineResult r;
r.cell_refined = true;
r.cell_before = before;
r.cell = after;
return r;
}
UnitCell Cell(float a, float b, float c) {
return UnitCell{.a = a, .b = b, .c = c, .alpha = 90.0f, .beta = 90.0f, .gamma = 90.0f};
}
}
TEST_CASE("PostRefine_HeldOutResidualFell", "[PostRefine]") {
// Down by more than the standard error of the difference, sqrt(3^2 + 4^2) = 5.
CHECK(HeldOutResidualFell(Measured(100.0, 3.0), Measured(94.0, 4.0)));
// Down, but within that noise.
CHECK_FALSE(HeldOutResidualFell(Measured(100.0, 3.0), Measured(96.0, 4.0)));
// Up.
CHECK_FALSE(HeldOutResidualFell(Measured(100.0, 3.0), Measured(110.0, 4.0)));
// Not measured on either side.
CHECK_FALSE(HeldOutResidualFell(PostRefineResult{}, Measured(10.0, 1.0)));
CHECK_FALSE(HeldOutResidualFell(Measured(100.0, 3.0), PostRefineResult{}));
}
TEST_CASE("PostRefine_ReindexPushesCellBack", "[PostRefine]") {
// The fit shortens b the most; re-indexing at its geometry returns a longer b: pushed back.
const auto fit = Fit(Cell(96.9f, 107.9f, 112.9f), Cell(96.8f, 106.6f, 112.9f));
CHECK(ReindexPushesCellBack(fit, Fit(Cell(96.7f, 107.6f, 112.6f), Cell(96.6f, 106.4f, 112.8f))) == -2);
// A walk that re-indexing follows (and overshoots a little) is not pushed back.
const auto walk = Fit(Cell(60.48f, 60.48f, 196.7f), Cell(60.05f, 60.05f, 195.2f));
CHECK(ReindexPushesCellBack(walk, Fit(Cell(60.00f, 60.00f, 195.1f), Cell(59.8f, 59.8f, 194.2f))) == 0);
// Nothing committed, or no cell measured by the next pass: no evidence either way.
PostRefineResult refused = fit;
refused.cell_refined = false;
CHECK(ReindexPushesCellBack(refused, Fit(Cell(96.7f, 107.6f, 112.6f), Cell(96.6f, 106.4f, 112.8f))) == 0);
CHECK(ReindexPushesCellBack(fit, PostRefineResult{}) == 0);
}