Files
Jungfraujoch/image_analysis/indexing/FFTIndexer.h
T
leonarski_fandClaude Opus 5 7e47afe47f
Build Packages / build:viewer-tgz:cpu (push) Successful in 20m26s
Build Packages / build:viewer-tgz:cuda (push) Successful in 21m30s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 22m36s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 24m4s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 28m10s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 28m12s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 28m23s
Build Packages / XDS test (durin plugin) (push) Successful in 11m21s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 20m56s
Build Packages / build:rpm (rocky9) (push) Successful in 21m10s
Build Packages / Generate python client (push) Successful in 40s
Build Packages / Build documentation (push) Successful in 1m34s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (rocky8) (push) Successful in 25m28s
Build Packages / DIALS test (push) Successful in 21m15s
Build Packages / build:rpm (ubuntu2404) (push) Successful in 21m26s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 25m51s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 10m53s
Build Packages / XDS test (neggia plugin) (push) Successful in 9m41s
Build Packages / Unit tests (push) Successful in 2h21m29s
Build Packages / build:windows:nocuda (push) Successful in 1m15s
Build Packages / build:windows:cuda (push) Successful in 28m0s
rugnux: parallelise candidate-cell refinement, and stop repeating work in the tail
Three independent changes to the CPU-bound parts of an offline rotation run, none
of which alters a result.

Candidate-cell refinement now splits across threads. RefineCandidateCells already
took a (block, nblocks) partition, but the only call site passed nblocks=1, so the
whole first pass of a two-pass rotation run sat on one thread per scheme - two
threads, unchanged at every -N, for a third of the run. A block touches only its
own scores(j) and cells rows and holds its own scratch, so the split is exact.
The budget is a new IndexingSettings::RefineThreads, left at 1 by default and set
only where few indexer threads exist: raising it unconditionally would
oversubscribe the paths that already run one indexer per image across all workers.

The mmCIF writer built a std::ostringstream per formatted number, twelve per
reflection. snprintf gives the same digits for 0.535 -> 0.220 s per file.

The space-group search built the same orbit mapping twice per candidate point
group - once for the merge chi^2 and once for the systematic-error b, an
apply_to_hkl and Canonicalize per observation per operator each time. Build it
once and hand it to both.

18 Mpx rotation set 24.6 -> 18.7 s, 2.5 Mpx 13.0 -> 10.7 s, and the 37-crystal
battery 13m55s -> 10m47s with no failures, the same 34/37 space groups, and
statistics unchanged on 30 of 37 (the rest drift within the run-to-run spread the
binary already had, which a control build with the split disabled reproduces).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-03 07:30:33 +02:00

55 lines
2.0 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include "Indexer.h"
#include "../../common/UnitCell.h"
#include "../../common/Coord.h"
#include "../../common/CrystalLattice.h"
#include "../../common/IndexingSettings.h"
#include "FFTResult.h"
#define FFT_MAX_SPOTS (64*1024)
class FFTIndexer : public Indexer {
protected:
const float min_length_A;
const float max_length_A;
const float min_angle_deg;
const float max_angle_deg;
const int nDirections;
const unsigned refine_threads;
float histogram_spacing;
int64_t histogram_size;
std::vector<Coord> direction_vectors;
size_t input_size;
size_t output_size;
// Per-direction best peaks (host)
std::vector<FFTResult> result_fft;
void SetupUnitCell(const std::optional<UnitCell> &cell) override;
// widen=false: combine only the shortest few filtered vectors (fast, correct for compact cells).
// widen=true: anchor the two short axes but let the third range over all vectors (reaches the long
// axis of a large/elongated cell). Used only as a fallback when the standard reduction indexes poorly.
std::vector<CrystalLattice> ReduceResults(const std::vector<Coord> &results, bool widen) const;
std::vector<Coord> FilterFFTResults(size_t max_vectors) const;
std::vector<CrystalLattice> ReduceAndRefine(const std::vector<Coord> &coord, size_t nspots,
const std::vector<Coord> &filtered, bool widen);
float IndexedFraction(const CrystalLattice &latt, const std::vector<Coord> &coord, size_t nspots) const;
void SetupDirectionVectors();
virtual void ExecuteFFT(const std::vector<Coord> &coord, size_t nspots) = 0;
public:
explicit FFTIndexer(const IndexingSettings& settings);
~FFTIndexer() override = default;
std::vector<CrystalLattice> RunInternal(const std::vector<Coord> &coord, size_t nspots) override;
};