Stills integration: background ring reach measured on empty apertures, radial curvature from the whole frame
Two changes to the stills integration background, both stills-only (rotation keeps its path bit for bit): 1. The r2..r3 background ring's outer radius is measured per run. The pre-scan lays apertures on a grid over its frames, away from every found spot, and for each candidate r3 (r2+2 .. 14) takes the mean square difference between the r1 disk mean and the clipped ring mean. With nothing in the aperture that is exactly the background error the ring makes (noise + bias); the run keeps the minimum. On a photon-counting pixel detector the noise wins and the shipped r3=14 is kept; on a binned CCD the background structure wins and the narrowest ring is taken. r1 stays 6: a smaller disk (4,6,14) costs 0.0013 dimple R_free on a JUNGFRAU set, so it does not pass the photon-counting gate. --adaptive-integration-radius now defaults on for stills too (=off restores the fixed 6/8/14). The pre-scan bandwidth estimate is not applied to stills. 2. The radial background-curvature correction on stills takes its curve from the adaptive spot finder's peak-excluded per-ring background (whole frame) instead of the predicted reflections' own ring pixels, and auto applies it to every stills image (no ice-score gate: a solvent/carrier hump curves the background as much as ice). New engine call RadialBackgroundFromRings; CPU, GPU and Metal read the handed-over curve. The GPU box sum now sizes the radial bin index separately from accumulating, so a handed-over curve is read at the right radius. Measured (dimple R_free, deposited free set, battery arguments, all frames unless noted): pal86 (Rayonix 4x4, 156 um): 0.354 -> 0.218 (ring 10; at 4,6,10 0.213) lcls222 (Rayonix 4x4, 177 um): 0.205 -> 0.196 (ring 10) sacla236 (MPCCD): 0.2588 -> 0.2558 (ring 11) alvra213_int16 (JUNGFRAU): 0.1986 -> 0.1986 (ring 14, unchanged) 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
987e812e23
commit
e8145d8d2f
17 files changed
+558
-42
No files matched your search
@@ -15,6 +15,7 @@
|
||||
#include "../common/BraggIntegrationSettings.h"
|
||||
#include "../common/DetectorSetup.h"
|
||||
#include "../common/DiffractionExperiment.h"
|
||||
#include "../common/JFJochMath.h"
|
||||
#include "../common/Reflection.h"
|
||||
#include "../image_analysis/bragg_integration/BraggIntegrationEngineCPU.h"
|
||||
#include "../image_analysis/bragg_integration/BraggIntegrationEngineGPU.h"
|
||||
@@ -413,6 +414,60 @@ TEST_CASE("BraggIntegrationEngineGPU_ReusedEngineMatchesFresh") {
|
||||
}
|
||||
}
|
||||
|
||||
// The radial correction with its curve handed over from a per-ring profile (RadialBackgroundFromRings), as
|
||||
// on stills: the GPU reads the same curve and corrects the same empty aperture as the CPU.
|
||||
TEST_CASE("BraggIntegrationEngineGPU_RadialCurveFromRingsMatchesCPU", "[Integration]") {
|
||||
if (get_gpu_count() == 0) {
|
||||
WARN("No CUDA GPU present. Skipping");
|
||||
return;
|
||||
}
|
||||
DiffractionExperiment experiment(DetJF(2));
|
||||
experiment.DetectorDistance_mm(100.0f).IncidentEnergy_keV(WVL_1A_IN_KEV).BeamX_pxl(400.0f).BeamY_pxl(400.0f);
|
||||
const float bx = 400.0f, by = 400.0f;
|
||||
const auto background = [](double r) { return 50.0 + 0.05 * (r - 300.0) * (r - 300.0); };
|
||||
const size_t width = experiment.GetXPixelsNum(), npixel = experiment.GetPixelsNum();
|
||||
ImagePreprocessorBuffer cpu_image(npixel);
|
||||
ImagePreprocessorBufferGPU gpu_image(npixel);
|
||||
for (size_t i = 0; i < npixel; ++i) {
|
||||
cpu_image[i] = static_cast<int32_t>(std::lround(
|
||||
background(std::hypot(static_cast<double>(i % width) - bx, static_cast<double>(i / width) - by))));
|
||||
gpu_image[i] = cpu_image[i];
|
||||
}
|
||||
auto stream = std::make_shared<CudaStream>();
|
||||
REQUIRE(cudaMemcpyAsync(gpu_image.getGPUBuffer(), gpu_image.getBuffer().data(),
|
||||
npixel * sizeof(int32_t), cudaMemcpyHostToDevice, *stream) == cudaSuccess);
|
||||
|
||||
const float low_q = 0.05f, dq = 0.01f;
|
||||
const double F_px = 100.0 / 0.075, lambda = 1.0;
|
||||
std::vector<float> rings(500);
|
||||
for (size_t i = 0; i < rings.size(); ++i) {
|
||||
const double q = low_q + (i + 0.5) * dq;
|
||||
rings[i] = static_cast<float>(background(F_px * std::tan(2.0 * std::asin(q * lambda / (4.0 * PI)))));
|
||||
}
|
||||
|
||||
std::vector<Reflection> predicted;
|
||||
for (int i = 0; i < 8; ++i)
|
||||
predicted.push_back(MakeReflection(bx + 300.0f * std::cos(0.7f * i), by + 300.0f * std::sin(0.7f * i), 2.0f, i + 1));
|
||||
|
||||
for (const auto mode : {IntegratorMode::BoxSum, IntegratorMode::ProfileGaussian}) {
|
||||
experiment.ImportBraggIntegrationSettings(BraggIntegrationSettings().Integrator(mode).BackgroundRadialCorrection(true));
|
||||
BraggIntegrationEngineCPU cpu(experiment, PixelMask(experiment));
|
||||
BraggIntegrationEngineGPU gpu(experiment, stream, PixelMask(experiment));
|
||||
cpu.RadialBackgroundFromRings(rings, static_cast<int32_t>(rings.size()), low_q, dq);
|
||||
gpu.RadialBackgroundFromRings(rings, static_cast<int32_t>(rings.size()), low_q, dq);
|
||||
const auto out_cpu = cpu.Run(cpu_image, predicted, predicted.size(), 0);
|
||||
const auto out_gpu = gpu.Run(gpu_image, predicted, predicted.size(), 0);
|
||||
REQUIRE(out_cpu.size() == predicted.size());
|
||||
REQUIRE(out_gpu.size() == out_cpu.size());
|
||||
for (size_t i = 0; i < out_cpu.size(); ++i) {
|
||||
INFO("mode " << static_cast<int>(mode) << " reflection " << i);
|
||||
CHECK(out_gpu[i].bkg == Catch::Approx(out_cpu[i].bkg).epsilon(0.001).margin(0.05));
|
||||
CHECK(std::fabs(out_gpu[i].I) < 10.0f);
|
||||
CHECK(std::fabs(out_cpu[i].I) < 10.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hidden ([.]) benchmark: the raison d'etre of the GPU port is < 2 ms/frame (vs ~142 ms on the CPU
|
||||
// for ProfileIntegrate2D). Run explicitly with: ./jfjoch_test "[bragg_bench]"
|
||||
TEST_CASE("BraggIntegrationEngineGPU_Benchmark", "[.][bragg_bench]") {
|
||||
|
||||
Reference in new issue
Block a user