For stills indexing the minimum-pixels-per-spot filter is now chosen per image instead of being fixed: the frame is indexed at min-pix 3/2/1 and the setting that maximises indexed-spot count weighted by indexed fraction (n_indexed^2 / n_total) is kept, then integrated once at that min-pix. The fraction factor keeps a smaller min-pix's extra spots only when the lattice actually explains them, so strong frames retain their real weak spots (extending resolution) while noise-flooded frames stay strict. The mode is selected by the presence of --min-pix-per-spot, now optional (SpotFindingSettings::min_pix_per_spot is std::optional<int64_t>): omit it for the adaptive per-image path, give a value to force a fixed min-pix. It applies only to the stills indexing path -- rotation indexing builds one global lattice and keeps a fixed min-pix, and the online receiver and the FPGA host path always carry a concrete value, so neither changes. IndexAndRefine::ProcessImage now returns whether the frame indexed, to drive the per-image selection. Exposed in the jfjoch_viewer spot-finding settings (adaptive-threshold and adaptive-min-pix checkboxes, each greying out the control it overrides); the broker uses neither. Validated on the full rotation regression battery (no regression) and the whole serial-stills target battery at full image count. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
39 lines
1.9 KiB
C++
39 lines
1.9 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <optional>
|
|
#include <cstdint>
|
|
|
|
struct SpotFindingSettings {
|
|
bool enable = true;
|
|
float signal_to_noise_threshold = 4.0; // STRONG_PIXEL in XDS
|
|
int64_t photon_count_threshold = 10; // Threshold in photon counts
|
|
// Minimum connected pixels per spot. std::nullopt = choose it per image: on the stills indexing
|
|
// path the frame is indexed at min-pix 3/2/1 and the one maximising indexed count x indexed fraction
|
|
// is kept (see MXAnalysisWithoutFPGA::Analyze); a value fixes it. Defaults to a concrete value, so
|
|
// the online receiver and the FPGA path keep the single-pass fixed behaviour unless set otherwise.
|
|
std::optional<int64_t> min_pix_per_spot = 2;
|
|
int64_t max_pix_per_spot = 50; // Maximum pixels per spot
|
|
float high_resolution_limit = 2.0;
|
|
float low_resolution_limit = 50.0;
|
|
float cutoff_spot_count_low_res = 5.0;
|
|
std::optional<float> high_res_gap_Q_recipA = 1.5; // 0.25 * 2 * pi
|
|
|
|
// Half-width of the ice-ring exclusion band in q (2*pi/d). Measured hexagonal-ice ring FWHM on the
|
|
// JUNGFRAU is ~0.06 q, so the band half-width is ~0.03; 0.02 under-covered the strong low-res rings.
|
|
float ice_ring_width_Q_recipA = 0.03;
|
|
|
|
bool indexing = true;
|
|
bool quick_integration = true;
|
|
|
|
// Self-calibrating detection (offline/rugnux path): when true, the fixed photon_count_threshold is
|
|
// replaced by a per-resolution-ring threshold set from the image's own noise (see
|
|
// AdaptiveSpotFinderCPU), so the same setting adapts across datasets with no per-dataset tuning.
|
|
// false_pixels_per_frame is the one portable knob: the expected number of noise pixels tolerated
|
|
// per frame (the threshold's operating point), ~100 for a multi-megapixel detector.
|
|
bool adaptive_threshold = false;
|
|
float false_pixels_per_frame = 100.0f;
|
|
};
|