Refinement: an own L-BFGS whose memory outlives the macro-cycle, B steps scaled by their curvature

Each macro-cycle of a weight trial used to start a fresh Ceres solve: the L-BFGS memory was dropped every
10 (positions) or 5 (B) iterations and every cycle began with a steepest-descent step. RefinementMinimiser
keeps one memory for the positions and one for the B factors across a trial's macro-cycles (the target's
scale and likelihood parameters are refitted in between, which the memory tolerates), with a backtracking
Armijo line search and Oren-Shanno scaling of a diagonal initial inverse Hessian.

The diagonal: for B, the X-ray curvature per atom - the likelihood's curvature in |F_model| per resolution
shell against the atom's (s^2/4)^2 f^2 exp(-B s^2/2), calibrated once per trial by a central-difference
probe along a random direction - plus the B restraints'. For the positions none: tried with the restraints'
Gauss-Newton diagonal (bonds and angles, ~1e4 per axis against the X-ray's ~1e2) it slowed the minimiser,
since that stiffness is in directions that move bonded atoms together.

Same budget (10 cycles x 10 + 5 iterations, same ladder), median R-free (REFMAC 0-cycle scorer) from the
refinement battery's MD starts, base -> this: 5f6m (8 starts) 0.250 -> 0.210, 8dqb (8) 0.387 -> 0.345,
7arr 0.383 -> 0.356, 11if 0.325 -> 0.295, 5reo 0.316 -> 0.326 (CA RMSD 0.48 -> 0.43), 7d98 0.416 -> 0.393;
REFMAC converged: 0.168 / 0.284 / 0.311 / 0.251 / 0.261 / 0.361. Deposited models (14 parity sets): R-work
lower, R-free +0.0035 on average (their free sets were fitted to; the minimiser now moves the bottom rung
further). Time unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
(cherry picked from commit dfba4c1bd3c9345f31b64fd1cadc805810960825)
This commit is contained in:
leonarski_f committed 2026-10-26 01:38:24 +01:00
1 parent 626afc49dd
commit 4424d8884d
7 files changed
+343 -18

No files matched your search

@@ -324,6 +324,16 @@ double EvaluateRestraints(const RestraintSet &set, const std::vector<std::array<
return sum;
}
std::vector<double> BRestraintCurvature(const RestraintSet &set, const std::vector<std::array<double, 4>> &xyzb) {
std::vector<double> h(xyzb.size(), 0.0);
for (const RestraintRecord &r : set.records)
if (r.kind == static_cast<int>(RestraintKind::BSimilarity)) {
h[r.atom[0]] += 2.0 / (r.sigma * r.sigma);
h[r.atom[1]] += 2.0 / (r.sigma * r.sigma);
}
return h;
}
RefinementTopology BuildRefinementTopology(gemmi::Structure &st, bool hydrogens) {
RefinementTopology out;
gemmi::Model &model = st.models.at(0);