// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include // Upper bound accepted by IndexingSettings::RefineThreads. Callers deriving a thread count from the // machine must clamp to it - on a big host -N/2 exceeds it and the setter throws. constexpr int MAX_REFINE_THREADS = 64; enum class IndexingAlgorithmEnum {FFBIDX, FFT, FFTW, Auto, None}; // Flex = "let the pipeline decide": try several per-image refinements and keep whichever indexes the // most spots (CLI -r flex; the legacy -r multi name is still accepted as an alias). enum class GeomRefinementAlgorithmEnum {None, OrientationOnly, BeamCenter, Flex}; class IndexingSettings { IndexingAlgorithmEnum algorithm; int64_t fft_num_vectors = 16*1024; float fft_max_unit_cell_A = 500.0; float fft_min_unit_cell_A = 10.0; float fft_max_angle_deg = 150.0; float fft_min_angle_deg = 30.0; float fft_high_resolution_A = 2.0; float indexing_tolerance = 0.1; float max_angle_from_ewald_deg = 2.0; float unit_cell_dist_tolerance_vs_reference = 0.05; // relative static constexpr float unit_cell_angle_tolerance_deg = 5.0; // degree public: // The longest cell the FFT search can be asked to reach, and so the longest it can ever find: // FFTIndexer sizes its histogram from fft_max_unit_cell_A and the transform's last usable bin IS // that length. Callers that widen the bound (a given cell, the long-axis rescue) must clamp to // this rather than let the setter throw - a rescue that recovers an implausible axis must not // take the whole run down with it. static constexpr float fft_max_unit_cell_limit_A = 1200.0; // The other end of the same search: any candidate whose reduced cell has an axis shorter than // fft_min_unit_cell_A is discarded, and this is the lowest floor the setter accepts. A caller // lowering the floor to reach a given cell clamps to it rather than let the setter throw. static constexpr float fft_min_unit_cell_limit_A = 5.0; private: int64_t indexing_threads = 4; // Threads splitting the candidate-cell refinement WITHIN one indexer call. 1 (the default) is the // right answer whenever indexers already run one per image across all workers; it is raised only // where few indexer threads exist and cores would otherwise sit idle. int64_t refine_threads = 1; // The setter's own floor. A frame that carries fewer spots than this cannot validate a // lattice, and on a weakly diffracting crystal a bar set above what its frames can reach // is arithmetic rather than evidence: the true lattice is found, indexes every frame it // can, and is refused because too few frames could clear a count they never had the spots // for. The fraction of frames that must validate is the gate that carries the meaning. // // It is NOT only the validation bar, and lowering it loosens more than that: the same number // is the order statistic the candidate scorer ranks cells on, the stopping condition of the // iterative residual contraction, and the adoption gate of per-frame refinement (see // PostIndexingRefinement.cpp). Those three want a count that makes a fit trustworthy, which // is not the same question as whether a frame had spots to spare, and they are coupled here // only because one constant has always served both. int64_t viable_cell_min_spots = 6; int64_t max_extra_lattices = 2; bool blocking_behavior = true; bool index_ice_rings = false; // Refuse the Bravais class the metric was promoted to on a LENGTH equality, and index in the // class left when that equality is struck out. Not a user setting: rugnux runs one pass with it // and one without, and keeps the one whose re-integrated held-out positional residual is lower // (see RunAllPasses). The promotion is decided against a 3 % relative tolerance on a cell the // spot positions place to ~0.1 %, so on a small cell a genuinely orthorhombic crystal is // integrated with a = b imposed and nothing downstream can recover from it. bool lattice_class_demoted = false; bool enable_rotation_indexing = false; float rotation_indexing_min_angular_range_deg = 20.0; float rotation_indexing_angular_stride_deg = 0.5; GeomRefinementAlgorithmEnum refinement = GeomRefinementAlgorithmEnum::BeamCenter; public: IndexingSettings(); IndexingSettings& ViableCellMinSpots(int64_t input); IndexingSettings& Algorithm(IndexingAlgorithmEnum input); IndexingSettings& FFT_MaxUnitCell_A(float input); IndexingSettings& FFT_MinUnitCell_A(float input); IndexingSettings& FFT_MaxAngle_deg(float input); IndexingSettings& FFT_MinAngle_deg(float input); IndexingSettings& FFT_NumVectors(int64_t input); IndexingSettings& FFT_HighResolution_A(float input); IndexingSettings& Tolerance(float input); IndexingSettings& IndexingThreads(int64_t input); IndexingSettings& RefineThreads(int64_t input); IndexingSettings& UnitCellDistTolerance(float input); IndexingSettings& GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum input); IndexingSettings& IndexIceRings(bool input); IndexingSettings& RotationIndexing(bool input); IndexingSettings& RotationIndexingMinAngularRange_deg(float input); IndexingSettings& RotationIndexingAngularStride_deg(float input); IndexingSettings& BlockingBehavior(bool input); IndexingSettings& MaxExtraLattices(int64_t input); IndexingSettings& LatticeClassDemoted(bool input); [[nodiscard]] int64_t GetViableCellMinSpots() const; [[nodiscard]] IndexingAlgorithmEnum GetAlgorithm() const; [[nodiscard]] GeomRefinementAlgorithmEnum GetGeomRefinementAlgorithm() const; [[nodiscard]] float GetFFT_MaxUnitCell_A() const; [[nodiscard]] float GetFFT_MinUnitCell_A() const; [[nodiscard]] int64_t GetFFT_NumVectors() const; [[nodiscard]] float GetFFT_HighResolution_A() const; [[nodiscard]] float GetTolerance() const; [[nodiscard]] float GetFFT_MinAngle_deg() const; [[nodiscard]] float GetFFT_MaxAngle_deg() const; [[nodiscard]] int64_t GetIndexingThreads() const; [[nodiscard]] int64_t GetRefineThreads() const; [[nodiscard]] float GetUnitCellDistTolerance() const; [[nodiscard]] float GetUnitCellAngleTolerance_deg() const; [[nodiscard]] bool GetIndexIceRings() const; [[nodiscard]] bool GetRotationIndexing() const; [[nodiscard]] float GetRotationIndexingMinAngularRange_deg() const; [[nodiscard]] float GetRotationIndexingAngularStride_deg() const; [[nodiscard]] bool GetBlockingBehavior() const; [[nodiscard]] int64_t GetMaxExtraLattices() const; [[nodiscard]] bool GetLatticeClassDemoted() const; };