Bragg integration: a CCD rotation sweep's sigmas at the measured gain, intensities in photons
The pre-scan measures the gain of an SMV/marCCD detector (background variance per unit mean) but the
integrator used it only for the background clip: sigma, var_bkg, the strong-spot flag (I/sigma >= 5)
and the profile-vs-box-sum guard (10 box sigmas) all treated one ADU as one photon, so on a Saturn
(g 4.7-5.8) the guard sat at ~4.5 true sigma. The new BraggIntegrationSettings::PixelGain (set by
rugnux from the same measurement, rotation only, at max(1, g)) takes every variance the engine forms
at the gain, and Finalize converts I, sigma, bkg and var_bkg to photons, which is what the merge's
variance model (var_bkg + I) assumes. CPU and CUDA engines; Metal runs the CPU code for this. Gain 1
(every photon-counting input, ADSC/marCCD whose measured ratio is below 1, and stills) is bit-identical.
Battery --only, 12 open-arm CCD/background-dominated sets vs the base build (987e812e2), GPU:
the six Saturn sets (g 4.7-5.8) all improve - guard fallbacks 4.1-17.3% -> 1.2-6.1%,
anomalous peak height 3mc4 x1.10, 3p85 x1.02, 3r6o x1.06, 5cc8 x1.03, 5uth x1.05, 5vml x1.04;
R_meas 0.880-0.993x on all six; R_model shell-scaled better on 5/6 (5cc8 +0.0005); ISa 5uth +1.5%,
5vml +15%, 3p85 +3%, the twinned 3mc4/3r6o -5%/-1%. 6cee, 6i3j, 6v2r, 7kcn, 8v4j, 9jzo 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
b6f4973908
commit
46da7fb359
9 files changed
+114
-19
No files matched your search
@@ -351,3 +351,46 @@ TEST_CASE("BraggIntegrationEngineCPU_StillKeepsOnlySaturatedOverloads", "[Integr
|
||||
CHECK(out[1].overloaded);
|
||||
CHECK(still.Counts().overloads_kept == 1);
|
||||
}
|
||||
|
||||
// A detector that reports gain ADU per photon: the same spot read at gain 4 leaves the integrator in
|
||||
// photons - a quarter of the ADU intensity, at the Poisson sigma of that many photons, i.e. half the
|
||||
// sigma the ADU counted as photons gave.
|
||||
TEST_CASE("BraggIntegrationEngineCPU_PixelGainGivesPhotons", "[Integration][portable]") {
|
||||
DiffractionExperiment experiment(DetJF(2));
|
||||
experiment.DetectorDistance_mm(100.0f).IncidentEnergy_keV(WVL_1A_IN_KEV).BeamX_pxl(400.0f).BeamY_pxl(400.0f);
|
||||
const size_t width = experiment.GetXPixelsNum(), npixel = experiment.GetPixelsNum();
|
||||
|
||||
const int cx = 600, cy = 300;
|
||||
ImagePreprocessorBuffer image(npixel);
|
||||
for (size_t i = 0; i < npixel; ++i)
|
||||
image[i] = 40;
|
||||
for (int dy = -6; dy <= 6; ++dy)
|
||||
for (int dx = -6; dx <= 6; ++dx)
|
||||
image[(cy + dy) * width + cx + dx] += static_cast<int32_t>(std::lround(800.0 * std::exp(-(dx * dx + dy * dy) / (2 * 1.3 * 1.3))));
|
||||
|
||||
Reflection r{};
|
||||
r.h = 1; r.k = 2; r.l = 3;
|
||||
r.predicted_x = cx; r.predicted_y = cy;
|
||||
r.d = 2.0f;
|
||||
r.prescaling_corr = 1.0f;
|
||||
r.partiality = 1.0f;
|
||||
const std::vector<Reflection> predicted{r};
|
||||
|
||||
for (const auto mode : {IntegratorMode::BoxSum, IntegratorMode::ProfileGaussian}) {
|
||||
BraggIntegrationSettings settings;
|
||||
settings.Integrator(mode);
|
||||
experiment.ImportBraggIntegrationSettings(settings);
|
||||
BraggIntegrationEngineCPU adu(experiment, PixelMask(experiment));
|
||||
const auto out_adu = adu.Run(image, predicted, 1, 0);
|
||||
settings.PixelGain(4.0f);
|
||||
experiment.ImportBraggIntegrationSettings(settings);
|
||||
BraggIntegrationEngineCPU photons(experiment, PixelMask(experiment));
|
||||
const auto out_ph = photons.Run(image, predicted, 1, 0);
|
||||
REQUIRE(out_adu.size() == 1);
|
||||
REQUIRE(out_ph.size() == 1);
|
||||
CHECK(out_ph[0].I == Catch::Approx(out_adu[0].I / 4.0f));
|
||||
CHECK(out_ph[0].sigma == Catch::Approx(out_adu[0].sigma / 2.0f));
|
||||
CHECK(out_ph[0].bkg == Catch::Approx(out_adu[0].bkg / 4.0f));
|
||||
CHECK(out_ph[0].var_bkg == Catch::Approx(out_adu[0].var_bkg / 4.0f));
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user