Files
Jungfraujoch/image_analysis/rotation_indexer/RotationIndexer.h
T
leonarski_fandClaude Opus 4.8 c86beeb393 rotation indexer: fix sub-range crash, explicit angle, settings + guards
Running rotation indexing on a sub-range (e.g. images 60-120) segfaulted: the
first pass passed the *global* image number to RotationIndexer::ProcessImage,
which indexes v_ (sized to the run's image count) -> out-of-bounds write.

- ProcessImage now takes an explicit mid-exposure angle (optional; falls back to
  the goniometer at the image index), so the indexer no longer assumes its slot
  index equals the goniometer image index. IndexAndRefine supplies it via
  RotationAngle(), matching the angle used for prediction. Added a bounds guard in
  ProcessImage so a bad index can never corrupt memory.
- JFJochProcess feeds the rotation indexer the local ordinal (not the global
  index), and shifts the goniometer (start += start_image*incr, incr *= stride,
  per-image wedge preserved) so local index i maps to the angle of original image
  start+i*stride - fixing rotation angles for the whole sub-range pipeline
  (prediction, refinement, output), not just the indexer.
- Expose "Rotation images" (number used for the first pass) in the job dialog,
  enabled when rotation indexing is on. (Count > available is already clamped by
  select_equally_spaced_image_ordinals.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-22 15:59:21 +02:00

57 lines
1.9 KiB
C++

// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <vector>
#include <mutex>
#include "../../common/DiffractionSpot.h"
#include "../../common/DiffractionExperiment.h"
#include "../indexing/IndexerThreadPool.h"
#include "../lattice_search/LatticeSearch.h"
struct RotationIndexerResult {
CrystalLattice lattice;
std::vector<CrystalLattice> extra_lattices;
LatticeSearchResult search_result;
DiffractionGeometry geom;
std::optional<GoniometerAxis> axis;
};
class RotationIndexer {
mutable std::mutex m;
const DiffractionExperiment& experiment;
constexpr static size_t max_spots = 10000;
constexpr static size_t max_spots_per_image = 200;
const bool index_ice_rings;
std::vector<std::vector<SpotToSave>> v_;
// Per-image rotation angle (mid-exposure, deg) supplied by the caller; falls back to the
// goniometer evaluated at the image index when not given.
std::vector<std::optional<float>> angle_deg_;
std::optional<GoniometerAxis> axis_;
const DiffractionGeometry geom_;
DiffractionGeometry updated_geom_;
LatticeSearchResult search_result_;
std::vector<CrystalLattice> extra_lattices_;
IndexerThreadPool &indexer_;
size_t accumulated_spots = 0;
std::optional<CrystalLattice> indexed_lattice;
public:
RotationIndexer(const DiffractionExperiment& x, IndexerThreadPool& indexer);
// angle_deg is the image's mid-exposure rotation angle; if omitted, the goniometer angle at
// `image` is used (only valid when `image` is the goniometer's own image index).
void ProcessImage(int64_t image, const std::vector<SpotToSave>& spots,
std::optional<float> angle_deg = std::nullopt);
void RunIndexing();
std::optional<RotationIndexerResult> GetLattice() const;
void ForceLattice(const CrystalLattice& lattice);
};