Files
Jungfraujoch/common/ModuleSummation.cpp
2024-11-26 16:04:38 +01:00

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;
}