// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include #include #include "AnalyzeIndexing.h" #include "FitProfileRadius.h" inline bool ok(float x) { if (!std::isfinite(x)) return false; if (x < 0.0) return false; return true; }; bool AnalyzeIndexing(DataMessage &message, const DiffractionExperiment &experiment, const CrystalLattice &latt) { size_t nspots = message.spots.size(); uint64_t indexed_spot_count = 0; std::vector indexed_spots(nspots); std::vector distance_ewald_sphere(nspots); // Check spots const Coord a = latt.Vec0(); const Coord b = latt.Vec1(); const Coord c = latt.Vec2(); const Coord astar = latt.Astar(); const Coord bstar = latt.Bstar(); const Coord cstar = latt.Cstar(); const auto geom = experiment.GetDiffractionGeometry(); const auto indexing_tolerance = experiment.GetIndexingSettings().GetTolerance(); const auto viable_cell_min_spots = experiment.GetIndexingSettings().GetViableCellMinSpots(); // identify indexed spots for (int i = 0; i < message.spots.size(); i++) { auto recip = message.spots[i].ReciprocalCoord(geom); float h_fp = recip * a; float k_fp = recip * b; float l_fp = recip * c; float h_frac = h_fp - std::round(h_fp); float k_frac = k_fp - std::round(k_fp); float l_frac = l_fp - std::round(l_fp); float norm_sq = h_frac * h_frac + k_frac * k_frac + l_frac * l_frac; Coord recip_pred = std::round(h_fp) * astar + std::round(k_fp) * bstar + std::round(l_fp) * cstar; // See indexing_peak_check() in peaks.c in CrystFEL if (norm_sq < indexing_tolerance * indexing_tolerance) { indexed_spot_count++; indexed_spots[i] = 1; message.spots[i].dist_ewald_sphere = geom.DistFromEwaldSphere(recip_pred); message.spots[i].h = std::lround(h_fp); message.spots[i].k = std::lround(k_fp); message.spots[i].l = std::lround(l_fp); } } auto spot_count_threshold = std::max(viable_cell_min_spots, std::lround(min_percentage_spots * nspots)); if (indexed_spot_count >= spot_count_threshold) { auto uc = latt.GetUnitCell(); if (!ok(uc.a) || !ok(uc.b) || !ok(uc.c) || !ok(uc.alpha) || !ok(uc.beta) || !ok(uc.gamma)) return {}; message.indexing_result = true; assert(indexed_spots.size() == message.spots.size()); for (int i = 0; i < message.spots.size(); i++) message.spots[i].indexed = indexed_spots[i]; message.profile_radius = FitProfileRadius(message.spots); message.spot_count_indexed = indexed_spot_count; message.indexing_lattice = latt; message.indexing_unit_cell = latt.GetUnitCell(); return true; } message.indexing_result = false; return false; }