GeometryRefiner: residuals carry only the blocks a fit moves; beam and distance one block
The stills geometry refinement (module placement fits, the held-out fits that decide them, the tilt decision) spent most of its time differentiating parameters it never moves and in Ceres' general Schur elimination: - Each spot's residual declared the rotation axis, the cell angles and the (usually held) tilt as blocks. Ceres sizes its dual numbers from the declared blocks, so a placement residual carried 20 derivatives to use 12. They now enter as plain numbers (SpotResidual / TiltedSpotResidual). - A fit that moves only the orientations (the held-out scoring) gets a residual over the orientation alone, with the observed and predicted vectors taken once per spot (OrientationResidual): 3 derivatives instead of 17. - The beam and the distance are one block of three, so every refined block has three parameters and Ceres uses its fixed-size Schur eliminator (1.7x faster linear solve on one thread). A held distance is a SubsetManifold on that block. - One robust loss shared by every spot instead of one allocated per spot. Same arithmetic on the same values: replaying the dumped placement inputs of four multi-panel stills runs (AGIPD 128 ASICs, MPCCD 8, JF4M 8, JF16M 32 modules) on one thread gives identical held-out residuals, beam, distance, cell and every module shift at the printed precision. Single- thread CPU of the nine placement fits: 397 -> 112 s (MPCCD), 179 -> 80 s (JF4M), 131 -> 68 s (JF16M). On AGIPD the concurrent step goes 8.5 -> 6.4 s wall (quiet replay, 32 threads). Test: RefineGlobalGeometry_ModulePlacement now also covers a held distance and an orientation-only fit. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
1 parent
077fad9379
commit
f6c948732b
2 files changed
+176
-75
No files matched your search
@@ -103,6 +103,24 @@ TEST_CASE("RefineGlobalGeometry_ModulePlacement") {
|
||||
CHECK(placed.beam_x_px == Catch::Approx(1000).margin(0.1));
|
||||
CHECK(placed.beam_y_px == Catch::Approx(1000).margin(0.1));
|
||||
CHECK(placed.distance_mm == Catch::Approx(150).margin(0.05));
|
||||
|
||||
// The distance held (it shares a block with the beam): it stays exactly where it was given.
|
||||
GeometryRefinerSettings held_distance = st;
|
||||
held_distance.refine_distance = false;
|
||||
const auto fixed = RefineGlobalGeometry(geom, latt.GetUnitCell(), frames, held_distance);
|
||||
REQUIRE(fixed.ok);
|
||||
CHECK(fixed.distance_mm == geom.GetDetectorDistance_mm());
|
||||
CHECK(fixed.modules[0].dx == Catch::Approx(truth[0].dx).margin(0.1));
|
||||
|
||||
// Only the orientations moved, on the modules as placed: the spots fit as well as in the placement.
|
||||
GeometryRefinerSettings ev = st;
|
||||
ev.refine_modules = false;
|
||||
ev.refine_beam_distance = false;
|
||||
ev.modules = placed.modules;
|
||||
const auto scored = RefineGlobalGeometry(geom, latt.GetUnitCell(), frames, ev);
|
||||
REQUIRE(scored.ok);
|
||||
CHECK(scored.median_residual_px < 0.1);
|
||||
CHECK(scored.distance_mm == geom.GetDetectorDistance_mm());
|
||||
}
|
||||
|
||||
// The coarse search ahead of the placement: a module off by several pixels is found near where it is, and the
|
||||
|
||||
Reference in new issue
Block a user