// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only // SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "FitProfileRadius.h" #include // std::nth_element #include // std::fabs std::optional FitProfileRadius_MAD(const std::vector& xs) { std::vector absx; absx.reserve(xs.size()); for (const auto &s: xs) { if (s.indexed) absx.push_back(std::fabs(s.dist_ewald_sphere)); } if (absx.empty()) return std::nullopt; std::nth_element(absx.begin(), absx.begin() + absx.size() / 2, absx.end()); float med; if (absx.size() % 2 == 1) { med = absx[absx.size() / 2]; } else { auto it1 = absx.begin() + (absx.size() / 2 - 1); auto it2 = absx.begin() + (absx.size() / 2); float a = *it1; float b = *it2; med = 0.5f * (a + b); } // Normal consistency factor for MAD return 1.4826f * med; } std::optional FitProfileRadius(const std::vector& spots) { float sum_squares = 0.0f; int count = 0; for (const auto &s: spots) { if (s.indexed) { sum_squares += s.dist_ewald_sphere * s.dist_ewald_sphere; count++; } } if (count == 0) return std::nullopt; auto std_dev = std::sqrt(sum_squares / count); return std_dev; }