symmetry: say when the cell metric hosts more symmetry than the group adopted
Every symmetry under-call in the corpus has the same signature: a lattice whose metric carries rotations the adopted group does not, with nothing in the run saying so. The user is left to notice that a P1 answer sits on a cell whose axes are equal and whose angles are 60 degrees. So a run that determines its own group now compares the two and says what it sees. It decides nothing - no threshold, no promotion, no demotion, no reprocessing - and the message says as much, because a pseudo-symmetric metric is ordinary and only the intensities can settle whether the extra rotations are real. Measured over 83 crystals it fires on 19 and covers 6 of the 7 point-group under-calls; on the crystal whose deposited group is F 4 3 2 and which rugnux reports as P 1, the line reads "the cell metric is cubic - it admits 24 rotations where P 1 has 1". The metric symmetry is Le Page's, taken through GEMMI's implementation, at an obliquity of 1 degree - the middle of the band over which the answer is stable. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
This commit is contained in:
@@ -149,6 +149,13 @@ structure-factor machinery, and MTZ / XDS_ASCII I/O. Vendored in `gemmi_gph/`, s
|
||||
licence obligation. M. Wojdyr, "GEMMI: A library for structural biology" (2022), J. Open Source
|
||||
Softw. 7, 4200 [doi:10.21105/joss.04200](https://doi.org/10.21105/joss.04200).
|
||||
|
||||
**Le Page's metric-symmetry search** - the obliquity of each of the 81 candidate two-folds of a
|
||||
reduced cell, which is what tells a run that its lattice metric hosts more rotational symmetry than
|
||||
the group its intensities supported. Used through GEMMI's implementation of it. Y. Le Page, "The
|
||||
derivation of the axes of the conventional unit cell from the dimensions of the Buerger-reduced
|
||||
cell" (1982), J. Appl. Cryst. 15, 255-259
|
||||
[doi:10.1107/S0021889882011959](https://doi.org/10.1107/S0021889882011959).
|
||||
|
||||
**Hexagonal-ice ring positions** — the eleven ring $d$ spacings from 3.895 to 1.522 Å that the
|
||||
ice-ring score, the ice-ring flagging and the ice calibrant are all built on are taken from the
|
||||
measurements of, not enumerated from a cell. D. W. Moreau, H. Atakisi and R. E. Thorne, "Ice in
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
* `rugnux` writes the unmerged MTZ `<prefix>_unmerged.mtz` by default; `--no-export-unmerged` skips it.
|
||||
* Every rotation run that determines its own space group also writes `<prefix>_P1.mtz`, the same observations merged in P1, so a wrong space group can be re-merged, re-solved or re-refined without processing the images again; `--no-p1-crosscheck` declines it, and a run given `-S` writes nothing because its space group's centring absences were never integrated.
|
||||
* The space-group search names the setting the data support, so a screw or a 2-fold on the a or c axis is reported as such instead of costing the crystal its space group.
|
||||
* A run whose cell metric admits more rotational symmetry than the space group it adopted says so, naming both, so a symmetry the intensities were too weak to confirm is visible rather than silent.
|
||||
* The run report carries `SPACE_GROUP_NAME` beside `SPACE_GROUP_NUMBER`, since the number alone does not say which axes a group's symmetry lies on.
|
||||
* `jfjoch_viewer` opens PILATUS miniCBF sweeps - naming any frame opens the whole sweep - and can run a processing job on one.
|
||||
* A miniCBF sweep takes its rotation axis from the goniometer angles the header states, instead of assuming the axis every such file was previously assumed to have.
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include "../image_analysis/geom_refinement/GeometryRefiner.h"
|
||||
#include "../image_analysis/indexing/IndexerThreadPool.h"
|
||||
#include "../image_analysis/spot_finding/ImageSpotFinderCPU.h"
|
||||
#include "gemmi/twin.hpp"
|
||||
#include "../image_analysis/azint/AzIntEngineCPU.h"
|
||||
#include "../image_analysis/image_preprocessing/ImagePreprocessorCPU.h"
|
||||
#include "../image_analysis/image_preprocessing/ImagePreprocessorBuffer.h"
|
||||
@@ -370,6 +371,44 @@ namespace {
|
||||
// construction, all five of its searches agree, and the small sigma they report says nothing is
|
||||
// wrong. Only the background estimator recovers that case, and only a human reading this line knows
|
||||
// to look.
|
||||
// The lattice METRIC can carry more rotational symmetry than the group the intensities supported.
|
||||
// That is not by itself a mistake - a pseudo-symmetric metric is ordinary, and only the intensities
|
||||
// can say whether the extra rotations are real - but it is where the corpus's symmetry under-calls
|
||||
// live, so the run says it out loud rather than leaving the user to notice. It decides nothing: no
|
||||
// threshold, no promotion, no demotion.
|
||||
//
|
||||
// The metric symmetry is Le Page's, and its obliquity is the continuous measure of how nearly a
|
||||
// two-fold holds; 1 degree is the middle of the band over which the answer is stable.
|
||||
// Following Le Page (1982) J. Appl. Cryst. 15, 255-259
|
||||
static void WarnIfMetricHostsMoreSymmetry(const std::optional<UnitCell> &cell,
|
||||
const gemmi::SpaceGroup &sg) {
|
||||
if (!cell)
|
||||
return;
|
||||
Logger logger("Rugnux");
|
||||
const gemmi::UnitCell gc(cell->a, cell->b, cell->c, cell->alpha, cell->beta, cell->gamma);
|
||||
const size_t metric_rotations =
|
||||
gemmi::find_lattice_symmetry(gc, sg.centring_type(), 1.0).sym_ops.size();
|
||||
const size_t group_rotations = sg.operations().sym_ops.size();
|
||||
if (metric_rotations <= group_rotations)
|
||||
return;
|
||||
// The proper rotations of each holohedry, which is what find_lattice_symmetry returns.
|
||||
const char *metric_system = "a higher";
|
||||
switch (metric_rotations) {
|
||||
case 2: metric_system = "monoclinic"; break;
|
||||
case 4: metric_system = "orthorhombic"; break;
|
||||
case 6: metric_system = "trigonal"; break;
|
||||
case 8: metric_system = "tetragonal"; break;
|
||||
case 12: metric_system = "hexagonal"; break;
|
||||
case 24: metric_system = "cubic"; break;
|
||||
default: break;
|
||||
}
|
||||
logger.Warning("The cell metric is {} - it admits {} rotations where {} has {}. The intensities "
|
||||
"did not support the extra ones, so they are either absent or too weak to see; "
|
||||
"this is a note, not a correction. Where the higher symmetry is real, merging in "
|
||||
"it would raise multiplicity and completeness.",
|
||||
metric_system, metric_rotations, sg.xhm(), group_rotations);
|
||||
}
|
||||
|
||||
static void LogHeaderBeamCenter(const DiffractionExperiment &experiment, const PixelMask &pixel_mask) {
|
||||
Logger logger("Rugnux");
|
||||
const float beam_x = experiment.GetBeamX_pxl();
|
||||
@@ -3652,6 +3691,7 @@ ProcessResult Rugnux::RunPipeline(RugnuxObserver *observer, bool write_output, b
|
||||
end_msg.space_group_name = sg.xhm();
|
||||
end_msg.space_group_number = static_cast<uint64_t>(sg.number);
|
||||
result.space_group = sg;
|
||||
WarnIfMetricHostsMoreSymmetry(result.consensus_cell, sg);
|
||||
phase("Re-scaling in space group " + sg.short_name());
|
||||
sm = scale_and_merge(sg.short_name(), false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user