Refinement: placement steps kept only where R-free drops; a wider weight ladder

On deposited models the per-residue B shift raised R-free at every resolution tried (2.56 A: 0.320 ->
0.327) and the rigid bodies rarely helped; each is now kept only where it lowers R-free by more than the
0.001 tie, otherwise the model goes on as it was. The positions' weight ladder runs from 1/1024 to 1/32 of
the gradient-balanced weight: the R-free optimum sat near 1/500 at 2.6 A and near 1/50 at 1.1-1.7 A.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
(cherry picked from commit d444fb03f610db70903de04f53f0489a71540b37)
This commit is contained in:
leonarski_f committed 2026-10-25 07:20:32 +01:00
1 parent a3082c1500
commit 9cb5cc6237
3 files changed
+35 -12

No files matched your search

@@ -411,7 +411,7 @@ private:
};
// The placement stage: rigid bodies, then group B.
void RefinePlacement(Context &ctx, RefinementResult &result) {
void RefinePlacement(Context &ctx, bool group_b, RefinementResult &result) {
std::vector<std::vector<int>> bodies, groups;
size_t i = 0;
for (const gemmi::Chain &ch : ctx.Model().chains) {
@@ -429,8 +429,11 @@ void RefinePlacement(Context &ctx, RefinementResult &result) {
if (body.size() >= 50)
bodies.push_back(body);
}
result.rigid_bodies = static_cast<int>(bodies.size());
// Each step is kept only where it lowers R-free beyond the tie: a deposited model was refined atom by atom
// already, and moving its chains or shifting its B factors residue by residue then only makes it worse.
RFactors before = ctx.Refit();
if (!bodies.empty()) {
const std::vector<gemmi::Position> pos0 = ctx.Positions();
std::vector<double> q(6 * bodies.size(), 0.0);
auto target = std::make_unique<RigidBodiesTarget>(ctx, bodies);
RigidBodiesTarget *rb = target.get();
@@ -438,9 +441,17 @@ void RefinePlacement(Context &ctx, RefinementResult &result) {
ceres::GradientProblemSolver::Summary summary;
ceres::Solve(SolverOptions(30), problem, q.data(), &summary);
rb->Place(q.data());
const RFactors after = ctx.Refit();
if (after.r_free < before.r_free - R_FREE_TIE) {
result.rigid_bodies = static_cast<int>(bodies.size());
before = after;
} else {
ctx.SetPositions(pos0);
before = ctx.Refit();
}
}
ctx.Refit();
{
if (group_b) {
const std::vector<double> b0 = ctx.B();
std::vector<double> q(groups.size(), 0.0);
auto target = std::make_unique<GroupBTarget>(ctx, groups);
GroupBTarget *gb = target.get();
@@ -448,6 +459,9 @@ void RefinePlacement(Context &ctx, RefinementResult &result) {
ceres::GradientProblemSolver::Summary summary;
ceres::Solve(SolverOptions(30), problem, q.data(), &summary);
gb->Place(q.data());
result.group_b = ctx.Refit().r_free < before.r_free - R_FREE_TIE;
if (!result.group_b)
ctx.SetB(b0);
}
}
@@ -642,12 +656,12 @@ RefinementResult RefineModel(const gemmi::Structure &placed, const std::vector<M
ctx.atoms.size(), ctx.refl.Size(), result.d_min, r.n_free, result.on_gpu ? "GPU" : "CPU", r.r_work,
r.r_free);
RefinePlacement(ctx, result);
RefinePlacement(ctx, settings.group_b, result);
r = ctx.Refit();
result.r_work_placement = r.r_work;
result.r_free_placement = r.r_free;
logger.Info("Refinement, placement ({} rigid bodies, B per residue): R-work {:.4f}, R-free {:.4f}",
result.rigid_bodies, r.r_work, r.r_free);
logger.Info("Refinement, placement ({} rigid bodies kept, B per residue {}): R-work {:.4f}, R-free {:.4f}",
result.rigid_bodies, result.group_b ? "kept" : "not kept", r.r_work, r.r_free);
if (settings.restrained) {
RefinementTopology topo = BuildRefinementTopology(ctx.st, settings.riding_hydrogens);