// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include "../../common/CrystalLattice.h" #include "../../common/UnitCell.h" // What a lattice indexed from the spots the crystal's lattice left over is, relative to that lattice. enum class LeftoverLatticeKind { Self, // the same cell within 1 deg: spots of the crystal's own lattice its tolerance missed Domain, // the same cell, misoriented, spread over the sweep: a split crystal TwinDomain, // the same, turned by ~180 deg: a non-merohedral twin domain Segmented, // the same cell, but its spots are concentrated in part of the sweep: the crystal in // the beam changes along the rotation RelatedCell, // a cell n or 1/n times the volume: a question about the crystal's own cell Foreign // an unrelated cell: a second crystal species, or a wrong main lattice }; const char *LeftoverLatticeKindName(LeftoverLatticeKind kind); // The smallest rotation, in degrees, taking lattice `a` onto lattice `b`, over every basis of `b` whose // metric matches `a`'s (so a symmetry of the lattice is not read as a misorientation). Both are // primitive reduced cells. NaN where no basis of `b` matches `a`'s metric. double LatticeMisorientationDeg(const CrystalLattice &a, const CrystalLattice &b); // `volume_ratio` is the reduced volume against the crystal's lattice, `sweep_concentration` the share of // the lattice's spots in the 2 densest of 8 equal blocks of the sweep (0.25 is uniform). LeftoverLatticeKind ClassifyLeftoverLattice(double misorientation_deg, double volume_ratio, double sweep_concentration); struct LeftoverLattice { LeftoverLatticeKind kind = LeftoverLatticeKind::Foreign; UnitCell cell{}; char centering = 'P'; std::string system; double volume_ratio = 0.0; double misorientation_deg = 0.0; // NaN where the cell differs double z = 0.0; // leftover validation spots on it, against a wrong spindle angle double spots_pct = 0.0; // of the non-ice spots of the census frames double intensity_pct = 0.0; // of their summed intensity double sweep_concentration = 0.0; }; // The lattices the leftover spots index to, beside the crystal's own share of the same spots. // Only lattices clear of the displaced-angle null (z >= 5) and not the crystal's own lattice. struct LeftoverLatticeCensus { double primary_spots_pct = 0.0; double primary_intensity_pct = 0.0; int frames = 0; std::vector lattices; };