indexing: stop computing angles the candidate filter only compares
Build Packages / build:windows:nocuda (push) Successful in 16m15s
Build Packages / build:viewer-tgz:cpu (push) Successful in 19m47s
Build Packages / build:viewer-tgz:cuda (push) Successful in 22m4s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 22m49s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 23m7s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 28m2s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 28m7s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 28m19s
Build Packages / build:windows:cuda (push) Successful in 15m41s
Build Packages / XDS test (durin plugin) (push) Successful in 10m48s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m55s
Build Packages / build:rpm (rocky9) (push) Successful in 21m11s
Build Packages / Generate python client (push) Successful in 40s
Build Packages / Build documentation (push) Successful in 1m44s
Build Packages / Create release (push) Skipped
Build Packages / DIALS test (push) Successful in 20m53s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 26m15s
Build Packages / build:rpm (rocky8) (push) Successful in 27m37s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 21m36s
Build Packages / XDS test (neggia plugin) (push) Successful in 10m11s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 11m5s
Build Packages / Unit tests (push) Successful in 1h21m20s
Build Packages / build:windows:nocuda (push) Successful in 16m15s
Build Packages / build:viewer-tgz:cpu (push) Successful in 19m47s
Build Packages / build:viewer-tgz:cuda (push) Successful in 22m4s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 22m49s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 23m7s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 28m2s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 28m7s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 28m19s
Build Packages / build:windows:cuda (push) Successful in 15m41s
Build Packages / XDS test (durin plugin) (push) Successful in 10m48s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 19m55s
Build Packages / build:rpm (rocky9) (push) Successful in 21m11s
Build Packages / Generate python client (push) Successful in 40s
Build Packages / Build documentation (push) Successful in 1m44s
Build Packages / Create release (push) Skipped
Build Packages / DIALS test (push) Successful in 20m53s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 26m15s
Build Packages / build:rpm (rocky8) (push) Successful in 27m37s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 21m36s
Build Packages / XDS test (neggia plugin) (push) Successful in 10m11s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 11m5s
Build Packages / Unit tests (push) Successful in 1h21m20s
Candidate cell filtering called acos three times per candidate to turn dot products into degrees, then compared those against the min/max angle bounds. acos is strictly decreasing on [-1, 1], so "angle outside [min, max]" is exactly "cosine outside [cos(max), cos(min)]" with the ends swapped - the bounds convert once, and the three acos calls per candidate disappear. The same loop also re-derived every already-accepted candidate's unit cell on each new triple, inside the duplicate scan: three more acos each, for every candidate accepted so far. Those cells are now kept alongside the candidates. Measured on de-novo serial stills, where the indexer runs once per image: 34.43 s -> 14.17 s on one dataset and 21.92 s -> 6.59 s on another, with the indexing rate and the merged reflection count unchanged (one gained 0.25 points of indexing rate). acos had been 40% of the whole process there. Scope is narrower than that number suggests, and worth stating: the win is on the de-novo path, which Auto selects for stills only when NO cell is known. With a known cell Auto picks ffbidx, which reaches the same filter but feeds it few candidates - measured neutral there (+0.5% instructions, -1.6% wall, identical output), and that path already runs 14x faster in absolute terms. Rotation runs the indexer twice per dataset rather than per image, so it is unaffected: the full 37-crystal battery is identical, crystal for crystal. Comparing cosines instead of angles can only move a candidate that sits on the bound, so the filter's behaviour is unchanged except at that measure-zero boundary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -135,6 +135,7 @@ std::vector<CrystalLattice> FFTIndexer::ReduceResults(const std::vector<Coord> &
|
||||
// most triples of one lattice Niggli-reduce to the same cell (keeps the refine set small).
|
||||
const size_t n = std::min<size_t>(results.size(), 64);
|
||||
const size_t n_short = std::min<size_t>(n, 12);
|
||||
std::vector<UnitCell> candidate_cells; // parallel to `candidates`, see the dedup scan below
|
||||
for (size_t i = 0; i < n_short; i++) {
|
||||
for (size_t j = i + 1; j < n_short; j++) {
|
||||
for (size_t k = j + 1; k < n; k++) {
|
||||
@@ -151,10 +152,15 @@ std::vector<CrystalLattice> FFTIndexer::ReduceResults(const std::vector<Coord> &
|
||||
continue;
|
||||
|
||||
bool duplicate = false;
|
||||
for (const auto &c : candidates)
|
||||
if (c.GetUnitCell().is_close(uc, 0.02f, 1.0f)) { duplicate = true; break; }
|
||||
if (!duplicate)
|
||||
for (const auto &c : candidate_cells)
|
||||
if (c.is_close(uc, 0.02f, 1.0f)) { duplicate = true; break; }
|
||||
if (!duplicate) {
|
||||
// Keep each accepted candidate's cell rather than re-deriving it on the next
|
||||
// triple: GetUnitCell costs three acos, and this scan runs over every candidate
|
||||
// accepted so far, for every triple.
|
||||
candidate_cells.push_back(uc);
|
||||
candidates.emplace_back(std::move(reduced));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,6 +149,10 @@ std::vector<CrystalLattice> Refine(const std::vector<Coord> &in_spots,
|
||||
|
||||
std::vector<RefinedCandidate> candidates;
|
||||
|
||||
// Angle bounds as cosines, once, for the per-candidate test below.
|
||||
const float cos_min_angle = std::cos(p.min_angle_deg * PI / 180.0f);
|
||||
const float cos_max_angle = std::cos(p.max_angle_deg * PI / 180.0f);
|
||||
|
||||
for (int i = 0; i < scores.size(); i++) {
|
||||
Eigen::Matrix3f cell_rows = oCell.block(3u * i, 0u, 3u, 3u);
|
||||
Eigen::Matrix3f cell_cols = cell_rows.transpose();
|
||||
@@ -208,14 +212,18 @@ std::vector<CrystalLattice> Refine(const std::vector<Coord> &in_spots,
|
||||
continue;
|
||||
}
|
||||
|
||||
// Filter for wrong angles
|
||||
float alpha = std::acos(cell_rows.row(1).normalized().dot(cell_rows.row(2).normalized())) * 180.0f / PI;
|
||||
float beta = std::acos(cell_rows.row(0).normalized().dot(cell_rows.row(2).normalized())) * 180.0f / PI;
|
||||
float gamma = std::acos(cell_rows.row(0).normalized().dot(cell_rows.row(1).normalized())) * 180.0f / PI;
|
||||
// Filter for wrong angles. Compared as COSINES, not angles: acos is strictly decreasing on
|
||||
// [-1, 1], so "angle outside [min_angle, max_angle]" is exactly "cosine outside
|
||||
// [cos(max_angle), cos(min_angle)]" with the ends swapped - and the three acos calls the
|
||||
// comparison needed disappear. They were not cheap: this runs per candidate cell per image,
|
||||
// and on a serial-stills run acos was 41% of the whole process.
|
||||
const float cos_alpha = cell_rows.row(1).normalized().dot(cell_rows.row(2).normalized());
|
||||
const float cos_beta = cell_rows.row(0).normalized().dot(cell_rows.row(2).normalized());
|
||||
const float cos_gamma = cell_rows.row(0).normalized().dot(cell_rows.row(1).normalized());
|
||||
|
||||
if (alpha < p.min_angle_deg || alpha > p.max_angle_deg ||
|
||||
beta < p.min_angle_deg || beta > p.max_angle_deg ||
|
||||
gamma < p.min_angle_deg || gamma > p.max_angle_deg)
|
||||
if (cos_alpha > cos_min_angle || cos_alpha < cos_max_angle ||
|
||||
cos_beta > cos_min_angle || cos_beta < cos_max_angle ||
|
||||
cos_gamma > cos_min_angle || cos_gamma < cos_max_angle)
|
||||
continue;
|
||||
|
||||
int64_t indexed_spot_count = 0;
|
||||
|
||||
Reference in New Issue
Block a user