"Analyze dataset" and `rugnux` with no options are two front ends onto the same library and are meant to agree, but they decided their defaults separately and the two lists had drifted. The viewer was missing: - the de-novo starting point. The CLI discards the cell and space group stored in the input file before it does anything; the viewer left them on the experiment. Rugnux only searches for a space group when none is set, so the search was skipped entirely and the stored group was reported straight back. That is self-reinforcing: a finished job's own _process.h5 becomes the active snapshot, so a run that ended in P1 pinned every later run to P1 - which is what "lysozyme keeps coming out P1 in the viewer" was. - the polarization factor, so the Lp correction was omitted altogether. The missing factor is azimuthal and intensity-proportional, and symmetry mates sit at the same 2-theta but different azimuth - the exact "unequal intensities forced together" signature the space-group search vetoes as pseudo-symmetry, which can land a genuinely de-novo run in P1 on its own. - five rotation scaling defaults: the smooth-G range, the minimum captured fraction, the capture-aware sigma, outlier rejection and --search-min-zeta. The CLI's own comments tie the captured-fraction default to a crystal recovering its true space group instead of P1. Put the policy in one place (RugnuxDefaults) and have both front ends start from it. The CLI now takes its defaults from there and applies user options on top; its output is unchanged, verified bit-for-bit on four battery crystals. The stored cell/group is still available: the job dialog offers "Use the stored unit cell / space group", off by default, shown only when the file has one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
54 lines
2.5 KiB
C++
54 lines
2.5 KiB
C++
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#include "RugnuxDefaults.h"
|
|
|
|
namespace {
|
|
// Smoothing range for the per-frame scale G on rotation data (XDS DELPHI-like), in degrees.
|
|
constexpr double SMOOTH_G_DEG = 5.0;
|
|
// Per-observation outlier rejection for the rotation combine, in sigma.
|
|
constexpr double REJECT_OUTLIERS_NSIGMA = 6.0;
|
|
}
|
|
|
|
void ApplyRugnuxExperimentDefaults(DiffractionExperiment &experiment) {
|
|
// The Lp correction the integrator applies to every reflection. Without it the intensities carry an
|
|
// azimuthal, intensity-proportional modulation (~1.3x at 2 A for a 1 A beam) that symmetry mates do
|
|
// NOT share, because they sit at the same 2-theta but a different azimuth - which is exactly the
|
|
// "unequal intensities forced together" signature the space-group search vetoes as pseudo-symmetry.
|
|
experiment.PolarizationFactor(0.99);
|
|
}
|
|
|
|
void ClearStoredCrystal(DiffractionExperiment &experiment) {
|
|
experiment.SpaceGroupNumber(std::nullopt);
|
|
experiment.SetUnitCell(std::nullopt);
|
|
}
|
|
|
|
ScalingSettings RugnuxDefaultScalingSettings(bool rotation) {
|
|
ScalingSettings s;
|
|
|
|
// Refit the per-frame scale on the combined fulls. Rotation only - it is what lifts ISa there, and
|
|
// there is no combine on the stills path.
|
|
s.ScaleFulls(rotation);
|
|
s.SmoothGDegrees(rotation ? SMOOTH_G_DEG : 0.0);
|
|
|
|
// Drop edge-of-sweep fulls whose rocking curve was captured less than this. 0.7 rather than 0.5 also
|
|
// strips the partiality-extrapolated fulls that dominate the intensity second moment on weakly
|
|
// diffracting crystals, without which the de-novo space-group search is starved by the error-model
|
|
// I/sigma floor and falls back to P1.
|
|
s.MinCapturedFraction(rotation ? 0.7 : 0.0);
|
|
|
|
// Capture-aware systematic sigma: down-weights the over-extrapolated under-captured fulls.
|
|
s.CaptureUncertaintyCoeff(rotation ? 1.0 : 0.0);
|
|
|
|
// A single un-rejected artifact wrecks the intensity-correlation and second-moment statistics the
|
|
// space-group and twinning tests are built on.
|
|
s.OutlierRejectNsigma(rotation ? REJECT_OUTLIERS_NSIGMA : 0.0);
|
|
|
|
// Run the de-novo space-group search a second time on a merge of only the well-measured
|
|
// observations and keep whichever found more symmetry. It cannot lose symmetry, so an imperfect cut
|
|
// only means the second opinion contributes nothing.
|
|
s.SearchMinZeta(rotation ? 0.85 : 0.0);
|
|
|
|
return s;
|
|
}
|