diff --git a/receiver/JFJochReceiverService.cpp b/receiver/JFJochReceiverService.cpp index 47c1b2743..6a8022a47 100644 --- a/receiver/JFJochReceiverService.cpp +++ b/receiver/JFJochReceiverService.cpp @@ -101,6 +101,7 @@ void JFJochReceiverService::Start(const DiffractionExperiment &experiment, try { // First clean-up old measurement receiver.reset(); + analysis_warning.clear(); if (fpga_puller) { image_puller.reset(); fpga_puller.reset(); @@ -152,6 +153,19 @@ void JFJochReceiverService::Start(const DiffractionExperiment &experiment, else image_puller = std::make_shared(experiment.GetDetectorSetup().GetDECTRISStream2Addr()); + bool rugnux_rotation = rugnux_enable && (experiment.GetDetectorMode() == DetectorMode::Standard) + && RugnuxRotationData(experiment); + // Rugnux reads the images back from the buffer: a collection that does not fit gets the per-image analysis instead + const int64_t slots = image_buffer.GetBufferSize() / experiment.GetImageBufferLocationSize(); + if (rugnux_rotation && (slots < experiment.GetImageNum())) { + analysis_warning = fmt::format("no rugnux analysis: the image buffer holds {} images, the collection " + "has {}", slots, experiment.GetImageNum()); + logger.Warning("{}", analysis_warning); + rugnux_status.Start(experiment.GetImageNum(), {}, std::chrono::steady_clock::now()); + rugnux_status.Finish(RugnuxLiveState::Skipped, "the image buffer cannot hold the whole collection"); + rugnux_rotation = false; + } + // The dark frames of the mask sequence have a receiver of their own, with rugnux on as well. if (experiment.GetDetectorMode() == DetectorMode::DarkMask) receiver = std::make_unique(experiment, @@ -164,13 +178,14 @@ void JFJochReceiverService::Start(const DiffractionExperiment &experiment, receiver_status, plots, image_buffer); - else if (rugnux_enable && (experiment.GetDetectorMode() == DetectorMode::Standard) && RugnuxRotationData(experiment)) + else if (rugnux_rotation) receiver = std::make_unique( experiment, pixel_mask, *image_puller, image_pusher, logger, nthreads, std::max(1, static_cast(AvailableCpus()) - rugnux_reserved_cpus), rugnux_model, rugnux_deadline_s, rugnux_status, spot_finding_settings, receiver_status, plots, image_buffer, zmq_preview_socket.get(), zmq_metadata_socket.get()); - else if (rugnux_enable && (experiment.GetDetectorMode() == DetectorMode::Standard)) + else if (rugnux_enable && (experiment.GetDetectorMode() == DetectorMode::Standard) + && !RugnuxRotationData(experiment)) receiver = std::make_unique( experiment, pixel_mask, *image_puller, image_pusher, logger, nthreads, rugnux_model, rugnux_deadline_s, rugnux_status, spot_finding_settings, receiver_status, plots, @@ -235,7 +250,10 @@ JFJochReceiverOutput JFJochReceiverService::Stop() { logger.Warning("Request to stop while receiver not running"); throw JFJochException(JFJochExceptionCategory::WrongReceiverState, "Receiver idle, cannot stop"); } - return receiver->GetFinalStatistics(); + auto ret = receiver->GetFinalStatistics(); + if (!analysis_warning.empty()) + ret.analysis_warning = analysis_warning; + return ret; } void JFJochReceiverService::SetSpotFindingSettings(const SpotFindingSettings &settings) { diff --git a/receiver/JFJochReceiverService.h b/receiver/JFJochReceiverService.h index 8a580ae65..beabb604c 100644 --- a/receiver/JFJochReceiverService.h +++ b/receiver/JFJochReceiverService.h @@ -35,6 +35,7 @@ class JFJochReceiverService { int rugnux_reserved_cpus = 4; // left to the forward threads and the pusher double rugnux_deadline_s = 60; // the analysis is cut this long after the last image (0 = never) RugnuxLiveStatus rugnux_status; // of the last collection, kept after it ends + std::string analysis_warning; // why the collection was not analysed as asked, for the broker's status // A PSI detector's frames go through FPGAImagePuller and the stream receivers. Off unless asked for. bool fpga_image_puller = false; diff --git a/tests/JFJochReceiverRugnuxTest.cpp b/tests/JFJochReceiverRugnuxTest.cpp index 4acc7e11b..def6341d9 100644 --- a/tests/JFJochReceiverRugnuxTest.cpp +++ b/tests/JFJochReceiverRugnuxTest.cpp @@ -619,6 +619,42 @@ TEST_CASE("JFJochReceiverRugnux_Rotation", "[JFJochReceiverRugnux]") { CHECK(live.state != RugnuxLiveState::Running); } +TEST_CASE("JFJochReceiverRugnux_Rotation_DoesNotFit", "[JFJochReceiverRugnux]") { + // A scan the image buffer cannot hold is analysed image by image, and the live status says why rugnux did not run. + Logger logger(Catch::getResultCapture().getCurrentTestName()); + RegisterHDF5Filter(); + + const int64_t images = 5; + DiffractionExperiment x = StillsExperiment(images); + x.Goniometer(GoniometerAxis("omega", 0.0f, 0.1f, {1, 0, 0}, {})); + PixelMask mask(x); + Stream stream(x, images); + stream.Frames(0, images); + stream.End(); + + // Three slots + const size_t buffer_MiB = (3 * x.GetImageBufferLocationSize()) / (1024 * 1024) + 1; + REQUIRE(buffer_MiB * 1024 * 1024 / x.GetImageBufferLocationSize() < images); + + RecordingPusher pusher; + AcquisitionDeviceGroup group; + JFJochReceiverService service(group, logger, pusher, buffer_MiB); + service.NumThreads(4); + service.Indexing(x.GetIndexingSettings()); + service.RugnuxLive(true, nullptr, 4, 60); + + service.Start(x, mask, nullptr, stream.puller); + const auto out = service.Stop(); + + CHECK(out.status.images_collected == images); + CHECK(out.scan_result.images.size() == images); + CHECK(pusher.Events() == std::vector{"start", "image", "end"}); + CHECK(out.analysis_warning.find("image buffer") != std::string::npos); + const auto live = service.GetRugnuxStatus(); + CHECK(live.state == RugnuxLiveState::Skipped); + CHECK(live.message.find("image buffer") != std::string::npos); +} + TEST_CASE("JFJochReceiverRugnux_Rotation_Cancel", "[JFJochReceiverRugnux]") { Logger logger(Catch::getResultCapture().getCurrentTestName()); RegisterHDF5Filter();