// SPDX-FileCopyrightText: 2024 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include "../image_analysis/spot_finding/SpotUtils.h" TEST_CASE("FilterSpuriousHighResolutionSpots") { std::vector spots; spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 18.0, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 20.0, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 30.0, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 6.0, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 2.0, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 1.9, .indexed = false}); spots.push_back(SpotToSave{.x = 1, .y = 2, .intensity = 3, .d_A = 1.3, .indexed = false}); FilterSpuriousHighResolutionSpots(spots, 1.57); // roughly 0.25 in 1/d REQUIRE(spots.size() == 4); // Spots are sorted by resolution CHECK(spots[0].d_A == Catch::Approx(30.0)); CHECK(spots[1].d_A == Catch::Approx(20.0)); CHECK(spots[2].d_A == Catch::Approx(18.0)); CHECK(spots[3].d_A == Catch::Approx(6.0)); } TEST_CASE("GetResolution") { // Eleven equally strong spots at 1/d^2 = 0.1, 0.2, ... 1.1. Walking in from the highest-resolution // one, four of the eleven are the first to carry 30% of the weight, so the quantile is the fourth // spot in, 1/d^2 = 0.8. The estimate is that resolution taken 2.25x further in 1/d. std::vector spots; for (int i = 1; i <= 11; i++) spots.push_back(SpotToSave{.intensity = 100.0f, .d_A = 1.0f / std::sqrt(0.1f * static_cast(i))}); const auto d = GetResolution(spots); REQUIRE(d.has_value()); CHECK(*d == Catch::Approx(1.0 / (2.25 * std::sqrt(0.8))).epsilon(1e-4)); // The merged data cannot beat the corner of the detector. CHECK(*GetResolution(spots, 2.0f) == Catch::Approx(2.0)); // Ice-flagged spots take no part, however strong they are. std::vector with_ice = spots; with_ice.push_back(SpotToSave{.intensity = 1e6f, .d_A = 0.5f, .ice_ring = true}); CHECK(*GetResolution(with_ice) == Catch::Approx(*d)); // A weak high-resolution spot moves the answer far less than a strong one, which is the point of // weighting by sqrt(I) rather than counting: the old order statistic would follow it entirely. std::vector with_spur = spots; with_spur.push_back(SpotToSave{.intensity = 1.0f, .d_A = 0.5f}); CHECK(*GetResolution(with_spur) == Catch::Approx(*d).epsilon(0.02)); // Too few spots to have a fall-off at all. CHECK_FALSE(GetResolution(std::vector(3)).has_value()); }