Stills: background clip follows the radial curve; signal disk from the lattice spacing
Two stills-only changes to the integration stencil.
1. Where the whole-frame radial curve is in use (the correction on), the ring's high-side clip
follows it: a ring pixel is clipped against the threshold plus the curve's rise from the
reflection's radius to its own (BraggIntegrationEngine::RadialClipOffset, rounded to whole counts
so CPU, CUDA and Metal keep the same pixels). On a background falling steeply away from the beam
the flat mean + 4 sqrt(mean) threshold cut the beam-side half of the ring as outliers, so the
background read low and reflections near the beam stop read 3-150x too strong. The empty-aperture
test's corrected column clips the same way, so the per-run correction decision sees it.
Measured with r1 6 (dimple R_free, battery arguments, all frames):
lcls222 0.196 -> 0.1856, pal86 0.216 -> 0.1997, sacla236 0.2559 -> 0.2559, alvra213_int16 0.1986 -> 0.1986.
2. The signal disk is taken from the lattice: it must not reach into the next node's spot. The
closest two nodes can come on the detector is the shortest reciprocal-lattice vector the centring
allows, s = F_px tan(2 asin(lambda / 2 d_max)), and a spot reaches 2 r80 (measured in the
pre-scan); r1 = the largest of 4, 5, 6 px not above s - 2 r80, never below 4, never above the
disk the run starts with (6). The empty apertures are measured for each candidate disk and the
ring is chosen on the chosen disk's tally. Pixel detectors keep 6 (sacla236 s 22 px, alvra213
20 px); the binned CCDs with a long axis shrink to 4 (lcls222 5.4 px, pal86 6.7 px), which the
radius scans there measured as the optimum; pal90 (s 21 px) and lcls242_s (15.5 px) keep 6.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015CeEGgpKdfkCTJb3YNMJcu
This commit is contained in:
1 parent
29000dd3d6
commit
61def00a1a
13 files changed
+228
-50
No files matched your search
@@ -7,6 +7,7 @@
|
||||
#include <cmath>
|
||||
|
||||
#include "../../common/JFJochMath.h"
|
||||
#include "SystematicAbsence.h"
|
||||
|
||||
std::vector<float> background_aperture::CandidateR3(float r2, float max_r3) {
|
||||
std::vector<float> out;
|
||||
@@ -84,6 +85,12 @@ void background_aperture::MeasureFrame(ImagePreprocessorBuffer &image, int width
|
||||
}
|
||||
if (!readable || disk.empty())
|
||||
continue;
|
||||
// The ring background at the aperture's centre: what the clip with the correction follows the
|
||||
// curve from (BraggIntegrationEngine::RadialClipOffset).
|
||||
double centre_b = 0.0;
|
||||
for (const auto &p : disk)
|
||||
if (p.d2 == 0.0f)
|
||||
centre_b = p.b;
|
||||
double disk_v = 0.0, disk_b = 0.0;
|
||||
for (const auto &p : disk) {
|
||||
disk_v += p.v;
|
||||
@@ -112,17 +119,26 @@ void background_aperture::MeasureFrame(ImagePreprocessorBuffer &image, int width
|
||||
}
|
||||
const double mean = sum / n;
|
||||
const double thr = mean + clip_nsigma * std::sqrt(gain * std::max(mean, 1.0));
|
||||
double kept = 0.0;
|
||||
int n_kept = 0;
|
||||
for (const auto &p : ring)
|
||||
if (p.d2 < r3_sq && (clip_nsigma <= 0.0f || p.v <= thr)) {
|
||||
// Plain, and - for the correction - with the clip following the curve, as the integrator
|
||||
// clips where the correction is on.
|
||||
double kept = 0.0, kept_radial = 0.0;
|
||||
int n_kept = 0, n_kept_radial = 0;
|
||||
for (const auto &p : ring) {
|
||||
if (p.d2 >= r3_sq)
|
||||
continue;
|
||||
if (clip_nsigma <= 0.0f || p.v <= thr) {
|
||||
kept += p.v;
|
||||
++n_kept;
|
||||
}
|
||||
measured = n_kept > 0;
|
||||
if (clip_nsigma <= 0.0f || p.v <= thr + std::round(p.b - centre_b)) {
|
||||
kept_radial += p.v;
|
||||
++n_kept_radial;
|
||||
}
|
||||
}
|
||||
measured = n_kept > 0 && n_kept_radial > 0;
|
||||
if (measured) {
|
||||
d_plain[k] = disk_v - kept / n_kept;
|
||||
d_radial[k] = d_plain[k] - (disk_b - sum_b / n);
|
||||
d_radial[k] = disk_v - kept_radial / n_kept_radial - (disk_b - sum_b / n);
|
||||
}
|
||||
}
|
||||
if (!measured)
|
||||
@@ -179,3 +195,22 @@ int background_aperture::Best(const std::vector<double> &mean_square) {
|
||||
return -1;
|
||||
return static_cast<int>(std::min_element(mean_square.begin(), mean_square.end()) - mean_square.begin());
|
||||
}
|
||||
|
||||
double background_aperture::NodeSpacing_px(const UnitCell &cell, char centring, double f_px, double wavelength_A) {
|
||||
const gemmi::UnitCell uc = cell;
|
||||
double d_max = 0.0;
|
||||
for (int h = -2; h <= 2; ++h)
|
||||
for (int k = -2; k <= 2; ++k)
|
||||
for (int l = -2; l <= 2; ++l)
|
||||
if (!systematic_absence(h, k, l, centring))
|
||||
d_max = std::max(d_max, uc.calculate_d({h, k, l}));
|
||||
return f_px * std::tan(2.0 * std::asin(wavelength_A / (2.0 * d_max)));
|
||||
}
|
||||
|
||||
float background_aperture::DiskRadius(double node_spacing_px, double spot_extent_px, const std::vector<float> &options) {
|
||||
float r1 = options.front();
|
||||
for (const float o : options)
|
||||
if (o <= node_spacing_px - spot_extent_px)
|
||||
r1 = o;
|
||||
return r1;
|
||||
}
|
||||
Reference in new issue
Block a user