Build Packages / build:viewer-tgz:cpu (push) Successful in 16m51s
Build Packages / build:viewer-tgz:cuda (push) Successful in 18m44s
Build Packages / build:rpm (ubuntu2404_nocuda) (push) Successful in 20m42s
Build Packages / build:rpm (rocky9_nocuda) (push) Successful in 21m37s
Build Packages / build:rpm (ubuntu2204_nocuda) (push) Successful in 24m37s
Build Packages / build:rpm (rocky8_nocuda) (push) Successful in 24m48s
Build Packages / build:rpm (rocky9_sls9) (push) Successful in 20m13s
Build Packages / build:rpm (rocky8_sls9) (push) Successful in 25m19s
Build Packages / build:rpm (rocky9) (push) Successful in 23m23s
Build Packages / DIALS test (push) Successful in 21m35s
Build Packages / Generate python client (push) Successful in 40s
Build Packages / build:rpm (rocky8) (push) Successful in 29m16s
Build Packages / Create release (push) Skipped
Build Packages / build:rpm (ubuntu2404) (push) Successful in 23m17s
Build Packages / XDS test (durin plugin) (push) Successful in 11m5s
Build Packages / Build documentation (push) Successful in 1m14s
Build Packages / build:rpm (ubuntu2204) (push) Successful in 27m29s
Build Packages / XDS test (JFJoch plugin) (push) Successful in 9m21s
Build Packages / XDS test (neggia plugin) (push) Successful in 7m24s
Build Packages / build:windows:nocuda (push) Successful in 13m58s
Build Packages / build:windows:cuda (push) Successful in 16m6s
Build Packages / Unit tests (push) Successful in 1h18m59s
Reverts the profile-radius part of 457b1bfd1; the comparison-script and mosaicity-column changes from that commit are kept. The cap was validated on the rotation battery, which cannot test it: the profile radius feeds `ewald_dist_cutoff` in IndexAndRefine, and that is read only by the STILLS predictors (BraggPrediction/BraggPredictionGPU). The rotation predictors gate on the mosaicity window instead and never look at it. So "no space-group changes, 36 of 37 crystals bit-identical" showed the quantity is inert for rotation, not that capping it is safe - and the one regime where it does act was never exercised. Validating it needs the serial-stills battery, which is a much larger exercise. Until then the arbitrary constant is not worth carrying in a code path nobody measured. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
36 lines
1.6 KiB
C++
36 lines
1.6 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "FitProfileRadius.h"
|
|
#include <algorithm> // std::nth_element
|
|
#include <cmath> // std::fabs
|
|
|
|
std::optional<float> FitProfileRadius(const std::vector<SpotToSave>& spots,
|
|
float bandwidth_sigma, float wavelength_A) {
|
|
double sum_squares = 0.0; // measured excitation-error variance (sum dist_ewald^2)
|
|
double sum_bw_var = 0.0; // energy-bandwidth contribution to subtract out
|
|
int count = 0;
|
|
|
|
for (const auto &s: spots) {
|
|
if (!s.indexed)
|
|
continue;
|
|
sum_squares += static_cast<double>(s.dist_ewald_sphere) * s.dist_ewald_sphere;
|
|
// The energy bandwidth smears each reflection radially by sigma_bw = bandwidth_sigma*|recip_z|
|
|
// = bandwidth_sigma*lambda/(2 d^2) (the same term prediction re-adds per reflection, ~1/d^2 so
|
|
// largest at high resolution). Deconvolve it from the measured spread so the profile radius is
|
|
// the *intrinsic* mosaicity+divergence width and bandwidth is not double-counted at prediction.
|
|
if (bandwidth_sigma > 0.0f && s.d_A > 0.0f) {
|
|
const double sigma_bw = bandwidth_sigma * wavelength_A / (2.0 * static_cast<double>(s.d_A) * s.d_A);
|
|
sum_bw_var += sigma_bw * sigma_bw;
|
|
}
|
|
count++;
|
|
}
|
|
|
|
if (count == 0)
|
|
return std::nullopt;
|
|
|
|
const double variance = std::max(0.0, (sum_squares - sum_bw_var) / count);
|
|
return static_cast<float>(std::sqrt(variance));
|
|
}
|
|
|