Files
Jungfraujoch/image_analysis/indexing/Indexer.cpp
T
leonarski_fandClaude Opus 5 f5c2720b02 spindle: the cone is the sweep's, so its width comes from the detector, not the still
The severity took theta_max from the still's own spot resolution - the 95th percentile of |q| -
so a weak, attenuated grid still reaching 3 A scored a row at an 11 deg miss-angle as exactly 0,
while the real sweep collected afterwards at the detector's 1.8 A loses a fifth of a cone that
wide. The number exists to decide whether that sweep needs a second orientation, so the cone it
must describe is the sweep's, and the still's spot list systematically understates it in the one
direction that produces silent misses.

theta_max is now asin(lambda/2d) at the geometric resolution of the setup - the detector corner
at the recorded distance and wavelength. That is an upper bound on any sweep collected without
moving the detector, it is available on every frame however weak, and where it overstates what
the sweep will reach it errs towards reporting loss, which is the cheap error. Computed once per
Setup in the Indexer base rather than per frame in the FFT implementation, because nothing about
it is specific to either the frame or the indexer.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
2026-09-04 10:59:05 +02:00

36 lines
1.5 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "Indexer.h"
void Indexer::Setup(const DiffractionExperiment& experiment) {
geom = experiment.GetDiffractionGeometry();
indexing_tolerance = experiment.GetIndexingSettings().GetTolerance();
dist_tolerance_vs_reference = experiment.GetIndexingSettings().GetUnitCellDistTolerance();
viable_cell_min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots();
index_ice_rings = experiment.GetIndexingSettings().GetIndexIceRings();
wavelength_A = experiment.GetWavelength_A();
spindle_axis = {};
if (const auto goniometer = experiment.GetGoniometer())
spindle_axis = goniometer->GetAxis();
spindle_theta_max_deg = SpindleThetaMax_deg(wavelength_A, experiment.GetDetectorMaxResolution_A());
SetupUnitCell(experiment.GetUnitCell());
}
IndexerResult Indexer::Run(const std::vector<Coord> &coord) {
IndexerResult ret;
auto start = std::chrono::steady_clock::now();
ret.lattice = RunInternal(coord, coord.size());
auto end = std::chrono::steady_clock::now();
std::chrono::duration<float> duration = end - start;
ret.indexing_time_s = duration.count();
ret.executed = true;
if (const auto severity = GetSpindleSeverity()) {
ret.spindle_blind_fraction = severity->score;
ret.spindle_row_length_A = severity->row_length_A;
ret.spindle_miss_angle_deg = severity->miss_angle_deg;
}
return ret;
}