125 lines
4.8 KiB
C++
125 lines
4.8 KiB
C++
// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// 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;
|
|
is_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<DeviceOutput>();
|
|
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<class Tdst, class Tsrc>
|
|
void Add(DeviceOutput &output, const DeviceOutput &input) {
|
|
auto in_pixel = reinterpret_cast<const Tsrc *>(input.pixels);
|
|
auto out_pixel = reinterpret_cast<Tdst *>(output.pixels);
|
|
|
|
Tdst err_val_dst = std::is_signed_v<Tdst> ? std::numeric_limits<Tdst>::min() : std::numeric_limits<Tdst>::max();
|
|
Tsrc err_val_src = std::is_signed_v<Tsrc> ? std::numeric_limits<Tsrc>::min() : std::numeric_limits<Tsrc>::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<Tsrc>::max())
|
|
|| (out_pixel[i] == std::numeric_limits<Tdst>::max())
|
|
|| (static_cast<int64_t>(out_pixel[i]) + static_cast<int64_t>(in_pixel[i]) >= std::numeric_limits<
|
|
Tdst>::max()))
|
|
out_pixel[i] = std::numeric_limits<Tdst>::max();
|
|
else
|
|
out_pixel[i] = out_pixel[i] + in_pixel[i];
|
|
}
|
|
}
|
|
|
|
void ModuleSummation::AddFPGAOutput(const DeviceOutput &input, const std::optional<uint32_t> &in_fpga_depth_bytes) {
|
|
std::unique_lock ul(module_summation_mutex);
|
|
|
|
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
|
|
switch (in_fpga_depth_bytes.value_or(fpga_depth_bytes)) {
|
|
case 2:
|
|
if (pixel_signed)
|
|
Add<int32_t, int16_t>(*output, input);
|
|
else
|
|
Add<uint32_t, uint16_t>(*output, input);
|
|
break;
|
|
case 4:
|
|
if (pixel_signed)
|
|
Add<int32_t, int32_t>(*output, input);
|
|
else
|
|
Add<uint32_t, uint32_t>(*output, input);
|
|
break;
|
|
case 1:
|
|
if (pixel_signed)
|
|
Add<int32_t, int8_t>(*output, input);
|
|
else
|
|
Add<uint32_t, uint8_t>(*output, input);
|
|
break;
|
|
default:
|
|
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
|
|
"Unknown bit depth");
|
|
}
|
|
|
|
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() {
|
|
is_empty = true;
|
|
}
|
|
|
|
bool ModuleSummation::empty() const {
|
|
return is_empty;
|
|
}
|