RigidBodyRefine: reuse the residuals of an accepted step when Ceres asks for its Jacobian
Ceres evaluates some points twice - the residuals alone to decide whether to take a step, then residuals and Jacobian together at the same point - and every evaluation is a full Fcalc, a solvent mask and a scale fit. The residuals are a function of the placement alone (the zone's bulk solvent is fixed by its first evaluation), so the second computation is replaced by a copy of the first. On the null of a 1.63 A P2 set the replicates' evaluations drop 46/64/72/89/136 -> 44/59/68/82/123, and each saved evaluation is a serial one on the replicate's critical path. With the previous commit the null there goes 152 s -> 87 s (27 busy cores); 8sa8 60 -> 53 s. Exact: p.hkl, p.mtz, p.cif, p_maps.mtz, p_model.cif byte-identical to rc173 and the model-validation report unchanged on 9hnc, 8sa8, 8xtg, 9fhc, 5epe, 6oel (battery commands, --model); rigid-body rotations and translations in the log identical. [ModelValidation] tests pass. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D1G8gJVAy6gp1K5Dz3NE5C
This commit is contained in:
1 parent
ce87b98280
commit
dff1543bd7
1 file changed
+13
-2
@@ -214,8 +214,17 @@ public:
|
||||
|
||||
bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const override {
|
||||
const int n = num_residuals();
|
||||
if (!ev_.Residuals(parameters[0], residuals))
|
||||
return false;
|
||||
// Ceres evaluates every step it accepts twice: the residuals alone to decide whether to take
|
||||
// it, then residuals and Jacobian together at the same point. The residuals are a function of
|
||||
// the placement alone, so the second time they are the first time's, copied.
|
||||
if (!last_residuals_.empty() && std::equal(parameters[0], parameters[0] + 6, last_q_.begin())) {
|
||||
std::copy(last_residuals_.begin(), last_residuals_.end(), residuals);
|
||||
} else {
|
||||
if (!ev_.Residuals(parameters[0], residuals))
|
||||
return false;
|
||||
std::copy(parameters[0], parameters[0] + 6, last_q_.begin());
|
||||
last_residuals_.assign(residuals, residuals + n);
|
||||
}
|
||||
if (jacobians != nullptr && jacobians[0] != nullptr) {
|
||||
const double step = ev_.JacobianStep();
|
||||
std::vector<std::vector<double>> shifted(6, std::vector<double>(n));
|
||||
@@ -244,6 +253,8 @@ private:
|
||||
Evaluator &ev_;
|
||||
std::vector<Evaluator> &columns_;
|
||||
size_t nthreads_;
|
||||
mutable std::array<double, 6> last_q_{};
|
||||
mutable std::vector<double> last_residuals_; // at last_q_; empty until an evaluation succeeds
|
||||
};
|
||||
|
||||
// The directions in which this space group's origin is free. Translating the whole cell content along
|
||||
|
||||
Reference in new issue
Block a user