How far the predictor walks the lattice became a setting defaulting to "derive it from the refined cell", which is what is wanted offline. Online it is not: per-image prediction cost then depends on whichever crystal is mounted, and the cube (2n+1)^3 grows quickly. The broker was only ever handed a concrete value when a client sent a bragg_integration block, and none of the shipped configs has one, so the derived path was the normal deployment. Four places in the tree - the conversion, the predictor, the OpenAPI description and the changelog - already state that the broker keeps a fixed bootstrap. Make that true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
72 lines
4.0 KiB
C++
72 lines
4.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 <optional>
|
|
|
|
// Spot-intensity extraction method used by the Bragg integration engine. ProfileGaussian (default)
|
|
// profile-fits with a measured-width Gaussian (Kabsch-style) - more accurate intensities than the
|
|
// classical uniform BoxSum; validated on anomalous data (stronger S/Cl peaks vs box-sum). BoxSum is
|
|
// the simpler, faster fallback. ProfileEmpirical learns the profile per resolution shell from strong
|
|
// spots - see docs/CPU_DATA_ANALYSIS.md (Bragg integration).
|
|
enum class IntegratorMode { BoxSum, ProfileGaussian, ProfileEmpirical };
|
|
|
|
// The hkl half-width the broker bootstraps when a config carries no bragg_integration block. Matches
|
|
// the max_hkl default in broker/jfjoch_api.yaml, so an omitting client and an omitting config agree.
|
|
constexpr int BRAGG_ONLINE_DEFAULT_MAX_HKL = 100;
|
|
|
|
class BraggIntegrationSettings {
|
|
IntegratorMode integrator_mode = IntegratorMode::ProfileGaussian;
|
|
float r_1 = 4;
|
|
float r_2 = 6;
|
|
float r_3 = 10;
|
|
// Integration/prediction resolution limit. Unset means "as far as the detector reaches", resolved
|
|
// from the geometry where it is used. The predictor independently rejects any reflection that misses
|
|
// the detector, so this is a bound on how far the lattice walk goes rather than a second opinion on
|
|
// what is measurable - a fixed default simply truncated every experiment whose detector reached
|
|
// past it.
|
|
std::optional<float> d_min_limit_A;
|
|
std::optional<float> fixed_profile_radius;
|
|
float minimum_sigma_in_regards_to_i = 0.02;
|
|
// Symmetric trimmed-mean fraction for the r2..r3 background ring: drop the lowest and highest this
|
|
// fraction of ring pixels before averaging. Resists the high-side contamination (neighbour-spot
|
|
// wings, tails, zingers) that biases the plain ring mean up and makes it over-subtract weak
|
|
// high-angle reflections. Applied to monochromatic data (rotation and still); the integration engine
|
|
// keeps the tuned high-side sigma-clip for broadband (non-zero bandwidth) data instead. 0 = plain ring
|
|
// mean (rugnux --background-trim).
|
|
float bkg_trim_fraction = 0.10f;
|
|
// Half-width of the hkl cube the predictor walks: every reflection with |h|,|k|,|l| <= this is
|
|
// tested against the Ewald sphere, and nothing outside it can ever be predicted. An axis is
|
|
// truncated once a/d_min exceeds this, and the GPU cost is the cube (2n+1)^3 of candidates, so
|
|
// neither a small nor a large fixed value is right for every crystal.
|
|
//
|
|
// Unset (the default) means "take it from the refined cell", which is exact: the predictor keeps
|
|
// only |q| <= 1/d_min and h = a.q, so no reflection can have |h| > a/d_min. See MaxHKLForCell.
|
|
// Offline that is what is wanted. ONLINE it is not: the broker bootstraps a concrete value
|
|
// (BRAGG_ONLINE_DEFAULT_MAX_HKL) so per-image cost stays predictable across samples.
|
|
std::optional<int> max_hkl;
|
|
|
|
public:
|
|
BraggIntegrationSettings& R1(float input);
|
|
BraggIntegrationSettings& R2(float input);
|
|
BraggIntegrationSettings& R3(float input);
|
|
BraggIntegrationSettings& DMinLimit_A(std::optional<float> input);
|
|
BraggIntegrationSettings& FixedProfileRadius_recipA(std::optional<float> input);
|
|
BraggIntegrationSettings& Integrator(IntegratorMode input);
|
|
BraggIntegrationSettings& BackgroundTrimFraction(float input);
|
|
BraggIntegrationSettings& MaxHKL(std::optional<int> input);
|
|
|
|
|
|
[[nodiscard]] IntegratorMode GetIntegrator() const;
|
|
[[nodiscard]] float GetR1() const;
|
|
[[nodiscard]] float GetR2() const;
|
|
[[nodiscard]] float GetR3() const;
|
|
[[nodiscard]] std::optional<float> GetFixedProfileRadius_recipA() const;
|
|
[[nodiscard]] std::optional<float> GetDMinLimit_A() const;
|
|
|
|
[[nodiscard]] float GetMinimumSigmaInRegardsToI() const;
|
|
[[nodiscard]] float GetBackgroundTrimFraction() const;
|
|
[[nodiscard]] std::optional<int> GetMaxHKL() const;
|
|
};
|