// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include "AzimuthalIntegrationMapping.h" #include "../common/JFJochException.h" #include "../common/DiffractionGeometry.h" #include "../common/RawToConvertedGeometry.h" AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const AzimuthalIntegrationSettings &settings) : low_q(settings.GetLowQ_recipA()), high_q(settings.GetHighQ_recipA()), q_spacing(settings.GetQSpacing_recipA()), max_bin_number(0) { if (q_spacing < 0.0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Q-spacing has to be >= 0.0"); if (low_q >= high_q) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Low-Q must be smaller than high-Q"); if (low_q <= 0) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Low-Q must be > 0"); if (std::ceil((high_q-low_q) / q_spacing ) >= UINT16_MAX) throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Cannot accommodate more than 65536 rings"); } AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionExperiment& experiment) : AzimuthalIntegrationMapping(experiment.GetAzimuthalIntegrationSettings()) { pixel_to_bin.resize(experiment.GetModulesNum() * RAW_MODULE_SIZE); DiffractionGeometry geom = experiment.GetDiffractionGeometry(); for (int m = 0; m < experiment.GetModulesNum(); m++) { for (int pxl = 0; pxl < RAW_MODULE_SIZE; pxl++) { auto [x,y] = RawToConvertedCoordinate(experiment, m, pxl); float pixel_q = 2 * M_PI / geom.PxlToRes(x, y); if ((pixel_q < low_q) || (pixel_q >= high_q)) pixel_to_bin[m * RAW_MODULE_SIZE + pxl] = UINT16_MAX; else pixel_to_bin[m * RAW_MODULE_SIZE + pxl] = std::floor((pixel_q - low_q) / q_spacing); } } Setup(); } AzimuthalIntegrationMapping::AzimuthalIntegrationMapping(const DiffractionGeometry &geom, int64_t width, int64_t height, const AzimuthalIntegrationSettings &settings) : AzimuthalIntegrationMapping(settings) { pixel_to_bin.resize(width * height); for (int row = 0; row < height; row++) { for (int col = 0; col < width; col++) { float pixel_q = 2 * M_PI / geom.PxlToRes(col, row); if ((pixel_q < low_q) || (pixel_q >= high_q)) pixel_to_bin[row * width + col] = UINT16_MAX; else pixel_to_bin[row * width + col] = std::floor((pixel_q - low_q) / q_spacing); } } Setup(); } void AzimuthalIntegrationMapping::Setup() { // In principle max bin number is equal to std::floor((high_q - low_q) / q_spacing), but it might be lower than this // depending on detector distance and beam center position for (const auto &i: pixel_to_bin) { if ((i != UINT16_MAX) && (i > max_bin_number)) max_bin_number = i; } bin_to_q.resize(max_bin_number + 1); for (int i = 0; i < max_bin_number + 1; i++) bin_to_q[i] = static_cast(q_spacing * (i + 0.5) + low_q); } uint16_t AzimuthalIntegrationMapping::GetBinNumber() const { return max_bin_number + 1; } const std::vector &AzimuthalIntegrationMapping::GetPixelToBin() const { return pixel_to_bin; } const std::vector &AzimuthalIntegrationMapping::GetBinToQ() const { return bin_to_q; } float AzimuthalIntegrationMapping::QToBin(float q) const { return std::min(static_cast(max_bin_number), std::max(0.0f, (q - low_q) / q_spacing)); }