FPGA receiver: index only

MXAnalysisAfterFPGA indexes each image (IndexAndRefine::IndexFrameOnly) and
no longer predicts or integrates; its Bragg prediction and CPU integration
engine go. Per-image reflections, integrated-reflection counts and B factors
are now left unset on this path - integration is rugnux's. jfjoch_fpga_test
loses -Q and the receiver-test helper its quick_integrate parameter. The two
processing tests that integrated now check that indexing happens and
integration does not.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVeDQsU5a8AJUdJPgWevAK
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-11-08 09:07:50 +01:00
1 parent 3d631d2f69
commit 68ec8a7f9f
6 files changed
+21 -45

No files matched your search

+3 -12
View File
@@ -9,7 +9,6 @@
#include "../common/CUDAWrapper.h"
#include "../common/JFJochException.h"
#include "spot_finding/SpotUtils.h"
#include "bragg_prediction/BraggPredictionFactory.h"
double stddev(const std::vector<float> &v) {
if (v.size() <= 1)
@@ -34,13 +33,7 @@ MXAnalysisAfterFPGA::MXAnalysisAfterFPGA(const DiffractionExperiment &in_experim
IndexAndRefine &indexer)
: experiment(in_experiment),
integration(in_integration),
indexer(indexer),
prediction(CreateBraggPrediction(experiment.IsRotationIndexing())),
// No pixel mask reaches this path: the FPGA image marks its own masked pixels, so only a
// saturated pixel is read as an overload here. The edge mask is taken in the image's own layout,
// which is the raw one when the geometry is not transformed.
bragg_engine(std::make_unique<BraggIntegrationEngineCPU>(
in_experiment, PixelMask(PixelMask(in_experiment).GetMask(in_experiment)))) {
indexer(indexer) {
if (experiment.IsSpotFindingEnabled())
find_spots = true;
@@ -151,11 +144,9 @@ void MXAnalysisAfterFPGA::Process(DataMessage &message, const SpotFindingSetting
const auto t1 = std::chrono::steady_clock::now();
spot_finding_time_total += (t1 - t0);
// Indexing only: integration is rugnux's (live or offline), not the FPGA receiver's.
if (spot_finding_settings.indexing)
indexer.ProcessImage(message, spot_finding_settings, *prediction,
[this, &message](const std::vector<Reflection> &predicted, size_t npredicted, int64_t image_number) {
return bragg_engine->Run(message.image, predicted, npredicted, image_number);
});
indexer.IndexFrameOnly(message, spot_finding_settings);
}
if (spot_finding_timing_active) {
-7
View File
@@ -4,8 +4,6 @@
#pragma once
#include "../common/DiffractionExperiment.h"
#include "bragg_prediction/BraggPrediction.h"
#include "bragg_integration/BraggIntegrationEngineCPU.h"
#include "indexing/IndexerThreadPool.h"
#include "spot_finding/StrongPixelSet.h"
#include "azint/AzIntEngineCPU.h"
@@ -16,13 +14,8 @@ class MXAnalysisAfterFPGA {
const DiffractionExperiment &experiment;
const AzimuthalIntegrationMapping &integration;
IndexAndRefine &indexer;
std::unique_ptr<BraggPrediction> prediction;
std::unique_ptr<AzIntEngineCPU> cpu_azint;
// The FPGA host has no usable GPU bandwidth for integration, so Bragg integration here is always on
// the CPU, reading the assembled detector image straight (only the reflection disks - no copy).
std::unique_ptr<BraggIntegrationEngineCPU> bragg_engine;
bool find_spots = false;
std::vector<DiffractionSpot> spots;
constexpr static const float spot_distance_threshold_pxl = 2.0f;
+3 -6
View File
@@ -38,8 +38,7 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
const DiffractionExperiment &x,
const PixelMask &pixel_mask,
uint16_t nthreads,
size_t send_buf_size_MiB,
bool quick_integrate) {
size_t send_buf_size_MiB) {
std::vector<uint16_t> raw_expected_image(RAW_MODULE_SIZE * x.GetModulesNum());
@@ -47,7 +46,7 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
raw_expected_image[i] = i % 65536;
return JFJochReceiverTest(output, logger, aq_devices, x, pixel_mask, raw_expected_image, nthreads,
send_buf_size_MiB, quick_integrate);
send_buf_size_MiB);
}
bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
@@ -56,8 +55,7 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
const PixelMask &pixel_mask,
const std::vector<uint16_t> &raw_expected_image,
uint16_t nthreads,
size_t send_buf_size_MiB,
bool quick_integrate) {
size_t send_buf_size_MiB) {
std::vector<uint16_t> raw_expected_image_with_mask = raw_expected_image;
if (x.IsApplyPixelMask()) {
for (int i = 0; i < raw_expected_image_with_mask.size(); i++)
@@ -86,7 +84,6 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
settings.photon_count_threshold = 5;
settings.min_pix_per_spot = 1;
settings.max_pix_per_spot = 200;
settings.quick_integration = quick_integrate;
service.SetSpotFindingSettings(settings);
+2 -4
View File
@@ -13,8 +13,7 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
const DiffractionExperiment &x,
const PixelMask &pixel_mask,
uint16_t nthreads,
size_t send_buf_size_MiB = 1024,
bool quick_integrate = false);
size_t send_buf_size_MiB = 1024);
bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
AcquisitionDeviceGroup &aq_devices,
@@ -22,5 +21,4 @@ bool JFJochReceiverTest(JFJochReceiverOutput &output, Logger &logger,
const PixelMask &pixel_mask,
const std::vector<uint16_t> &data,
uint16_t nthreads,
size_t send_buf_size_MiB = 1024,
bool quick_integrate = false);
size_t send_buf_size_MiB = 1024);
+11 -9
View File
@@ -283,7 +283,7 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_and_index_refinement_tetragona
REQUIRE_NOTHROW(writer_future.get());
}
TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_and_integrate", "[JFJochReceiver]") {
TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_no_integration", "[JFJochReceiver]") {
Logger logger(Catch::getResultCapture().getCurrentTestName());
RegisterHDF5Filter();
@@ -322,7 +322,7 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_and_integrate", "[JFJoch
settings.max_pix_per_spot = 200;
settings.high_resolution_limit = 2.0;
settings.low_resolution_limit = 50.0;
settings.quick_integration = true;
settings.quick_integration = true; // asked for, and still not done
std::vector<CardImage> images;
images.push_back(Int16Image(experiment, pixel_mask, image_raw_geom, settings));
AcquisitionDeviceGroup aq_devices = MockDevices(experiment, images);
@@ -367,16 +367,19 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_and_integrate", "[JFJoch
// No progress value at the end of measurement
REQUIRE(!service.GetProgress().has_value());
auto b_factor = service.GetDataProcessingPlot(
PlotRequest{.type = PlotType::BFactor, .binning = 1});
REQUIRE(b_factor.GetPlots().size() == 1);
REQUIRE(b_factor.GetPlots()[0].x.size() == experiment.GetImageNum());
logger.Info("B-factor {}", b_factor.GetPlots()[0].y[0]);
// The FPGA receiver indexes each image and integrates none, even when the settings ask for it:
// integration is rugnux's.
REQUIRE(receiver_out.scan_result.images.size() == experiment.GetImageNum());
for (const auto &i: receiver_out.scan_result.images) {
CHECK(i.uc.has_value());
CHECK(!i.integrated_reflections.has_value());
CHECK(!i.b_factor.has_value());
}
REQUIRE_NOTHROW(writer_future.get());
}
TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_and_integrate_no_spots", "[JFJochReceiver]") {
TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_no_spots", "[JFJochReceiver]") {
Logger logger(Catch::getResultCapture().getCurrentTestName());
RegisterHDF5Filter();
@@ -415,7 +418,6 @@ TEST_CASE("JFJochIntegrationTest_ZMQ_crystal_spot_index_and_integrate_no_spots",
settings.max_pix_per_spot = 200;
settings.high_resolution_limit = 2.0;
settings.low_resolution_limit = 50.0;
settings.quick_integration = true;
std::vector<CardImage> images;
images.push_back(Int16Image(experiment, pixel_mask, image_raw_geom, settings));
AcquisitionDeviceGroup aq_devices = MockDevices(experiment, images);
+2 -7
View File
@@ -32,7 +32,6 @@ void print_usage(Logger &logger) {
logger.Info(" -X<txt> Indexing (none|fft|ffbidx), ffbidx is default");
logger.Info(" -t<num> Indexing thread pool size (default: 4)");
logger.Info(" -f<num> FFT indexing search vectors");
logger.Info(" -Q Quick integration");
}
int main(int argc, char **argv) {
@@ -56,7 +55,6 @@ int main(int argc, char **argv) {
bool force_32bit = false;
bool force_8bit = false;
bool apply_pixel_mask = false;
bool quick_integrate = false;
std::optional<int64_t> eiger_bit_depth;
DetectorType detector_type = DetectorType::JUNGFRAU;
bool hls_simulation = false;
@@ -71,7 +69,7 @@ int main(int argc, char **argv) {
}
int opt;
while ((opt = getopt(argc, argv, "s:i:m:N:P:vRIS:E::HB:q:T:cM0ZX:t:f:Q")) != -1) {
while ((opt = getopt(argc, argv, "s:i:m:N:P:vRIS:E::HB:q:T:cM0ZX:t:f:")) != -1) {
switch (opt) {
case '0':
compr = CompressionAlgorithm::NO_COMPRESSION;
@@ -148,9 +146,6 @@ int main(int argc, char **argv) {
case 'f':
fft_num_vectors = atol(optarg);
break;
case 'Q':
quick_integrate = true;
break;
default: /* '?' */
print_usage(logger);
@@ -246,7 +241,7 @@ int main(int argc, char **argv) {
std::thread run_thread([&] {
try {
ret = JFJochReceiverTest(output, logger, aq_devices, x, mask, input, nthreads,
send_buffer_size_MiB, quick_integrate);
send_buffer_size_MiB);
} catch (std::exception &e) {
logger.Error(e.what());
ret = false;