// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "ModuleSummation.h" #include "JFJochException.h" ModuleSummation::ModuleSummation(bool in_pixel_signed,uint32_t in_fpga_depth_bytes) { pixel_signed = in_pixel_signed; first = true; empty = false; output_depth_bytes = 4; fpga_depth_bytes = in_fpga_depth_bytes; if ((fpga_depth_bytes != 4) && (fpga_depth_bytes != 2) && (fpga_depth_bytes != 1)) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "FPGA byte depth can be only 1, 2 or 4"); output = std::make_unique(); memset(output.get(), 0, sizeof(DeviceOutput)); } ModuleSummation::ModuleSummation(const DiffractionExperiment &experiment) : ModuleSummation(experiment.IsPixelSigned(), experiment.GetByteDepthFPGA()) { if (!experiment.IsCPUSummation()) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "CPU summation not turned on"); if (experiment.GetByteDepthImage() != 4) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "CPU summation works only for 32-bit output"); } const DeviceOutput& ModuleSummation::GetOutput() const { return *output; } DeviceOutput &ModuleSummation::GetOutput() { return *output; } template void Add(DeviceOutput& output, const DeviceOutput& input) { auto in_pixel = reinterpret_cast(input.pixels); auto out_pixel = reinterpret_cast(output.pixels); Tdst err_val_dst = std::is_signed_v ? std::numeric_limits::min() : std::numeric_limits::max(); Tsrc err_val_src = std::is_signed_v ? std::numeric_limits::min() : std::numeric_limits::max(); for (int i = 0; i < RAW_MODULE_SIZE; i++) { if ((in_pixel[i] == err_val_src) || (out_pixel[i] == err_val_dst)) out_pixel[i] = err_val_dst; else if ((in_pixel[i] == std::numeric_limits::max()) || (out_pixel[i] == std::numeric_limits::max()) || (static_cast(out_pixel[i]) + static_cast(in_pixel[i]) >= std::numeric_limits::max())) out_pixel[i] = std::numeric_limits::max(); else out_pixel[i] = out_pixel[i] + in_pixel[i]; } } void ModuleSummation::AddFPGAOutput(const DeviceOutput &input) { if (first) { output->module_statistics = input.module_statistics; first = false; } else { output->module_statistics.err_pixels += input.module_statistics.err_pixels; output->module_statistics.saturated_pixels += input.module_statistics.saturated_pixels; output->module_statistics.packet_count += input.module_statistics.packet_count; } // The only function not handled is spot finding if (fpga_depth_bytes == 2) { if (pixel_signed) Add(*output, input); else Add(*output, input); } else if (fpga_depth_bytes == 4) { if (pixel_signed) Add(*output, input); else Add(*output, input); } else if (fpga_depth_bytes == 1) { if (pixel_signed) Add(*output, input); else Add(*output, input); } for (int i = 0; i < FPGA_INTEGRATION_BIN_COUNT; i++) { output->integration_result[i].count += input.integration_result[i].count; output->integration_result[i].sum += input.integration_result[i].sum; } for (int i = 0; i < ADU_HISTO_BIN_COUNT; i++) output->adu_histogram[i] += input.adu_histogram[i]; for (int i = 0; i < FPGA_ROI_COUNT; i++) { output->roi_counts[i].sum += input.roi_counts[i].sum; output->roi_counts[i].sum2 += input.roi_counts[i].sum2; output->roi_counts[i].good_pixels += input.roi_counts[i].good_pixels; output->roi_counts[i].sum_x_weighted += input.roi_counts[i].sum_x_weighted; output->roi_counts[i].sum_y_weighted += input.roi_counts[i].sum_y_weighted; if (output->roi_counts[i].max_value < input.roi_counts[i].max_value) output->roi_counts[i].max_value = input.roi_counts[i].max_value; } } void ModuleSummation::AddEmptyOutput() { empty = true; } bool ModuleSummation::IsEmpty() const { return empty; }