Files
Jungfraujoch/common/ScalingSettings.cpp
T
leonarski_fandClaude Fable 5.1 7547df77de rugnux: --report-resolution, a second statistics table at a reference range
Comparing a run with another program's table has meant running rugnux AT that
program's resolution range (--scaling-high-resolution), which is a different
run: the range moves the cut, the space-group decision and everything after
them, so the comparison buys itself a different answer. --report-resolution
<dmin>[,<dmax>] instead leaves the run alone and adds a second table to
section 3 of the report - the REFRES_* keys and a shell table - binned from the
same merged reflections over the range given, with the completeness
denominator enumerated over that range and the shells in equal steps of 1/d^2
so they read row for row against a CORRECT.LP at the same range. Report-only:
the merged files and every decision are byte-identical with and without it.

The table holds only what the run kept. Where the reference range is finer
than the run's own limit, the shells past it are printed as not merged (with
their possible count) rather than as zeros, REFRES_SHELLS_PAST_LIMIT counts
them so a consumer can tell "not merged" from a measured zero, REFRES_
COMPLETENESS counts their reflections as missing, and the other overall numbers
are over the shells the run reached; nothing is read from the observations the
run judged to carry no signal. REFRES_ISA is the error model refitted on the
reflections of the table alone, in XDS's convention (rotation only; the stills
model is fitted over the whole range already).

On the rotation path the statistics block of MergeAndStats becomes a lambda
over a shell grid, called once for the run's own grid and once for the
reference one; the reference call floors every observation-level count at the
cut by group d, the rule the erase applied. The stills MergeStats takes a
declared range, whose bounds are the grid's whether or not any reflection
reaches them. Both --mode mx and --mode scale report it, the viewer's command
line echoes it, and the docs describe the keys.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 18:45:03 +02:00

318 lines
9.6 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#include "ScalingSettings.h"
ScalingSettings& ScalingSettings::MergeFriedel(bool input) {
merge_friedel = input;
return *this;
}
ScalingSettings& ScalingSettings::HighResolutionLimit_A(double limit) {
if (limit <= 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, "High resolution limit must be positive");
high_resolution_limit_A = limit;
return *this;
}
ScalingSettings& ScalingSettings::HighResolutionLimit_A(std::optional<double> limit) {
if (limit.has_value() && limit.value() <= 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, "High resolution limit must be positive");
high_resolution_limit_A = limit;
return *this;
}
ScalingSettings& ScalingSettings::LowResolutionLimit_A(std::optional<double> limit) {
if (limit.has_value() && limit.value() <= 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterBelowMin, "Low resolution limit must be positive");
low_resolution_limit_A = limit;
return *this;
}
bool ScalingSettings::GetMergeFriedel() const {
return merge_friedel;
}
ScalingSettings &ScalingSettings::RefineRotationWedge(bool input) {
refine_wedge = input;
return *this;
}
bool ScalingSettings::GetRefineWedge() const {
return refine_wedge;
}
std::optional<double> ScalingSettings::GetHighResolutionLimit_A() const {
return high_resolution_limit_A;
}
std::optional<double> ScalingSettings::GetLowResolutionLimit_A() const {
return low_resolution_limit_A;
}
double ScalingSettings::GetMinMosaicity() const {
return 0.001;
}
double ScalingSettings::GetMaxMosaicity() const {
return 1.0;
}
double ScalingSettings::GetMinWedge() const {
return 0.001;
}
double ScalingSettings::GetMaxWedge() const {
return 10.0;
}
double ScalingSettings::GetDefaultMosaicity() const {
return 0.1;
}
ScalingSettings &ScalingSettings::RotationWedgeForScaling(std::optional<double> input) {
if (input) {
// TODO: Use fmt
if (input.value() < GetMinWedge() || input.value() > GetMaxWedge())
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Wedge for scaling must be between " + std::to_string(GetMinWedge()) +
" and " + std::to_string(GetMaxWedge()));
}
wedge_for_scaling = input;
return *this;
}
std::optional<double> ScalingSettings::GetRotationWedgeForScaling() const {
return wedge_for_scaling;
}
ScalingSettings &ScalingSettings::MinPartiality(double input) {
if (min_partiality < 0.0 || min_partiality > 1.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Min partiality must be between 0 and 1");
min_partiality = input;
return *this;
}
double ScalingSettings::GetMinCCForImage() const {
return min_cc_for_image;
}
double ScalingSettings::GetSearchMinZeta() const {
return search_min_zeta;
}
ScalingSettings &ScalingSettings::SearchMinZeta(double input) {
if (input < 0.0 || input >= 1.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Search zeta limit must be in [0,1)");
search_min_zeta = input;
return *this;
}
ScalingSettings &ScalingSettings::MinCCForImage(double input) {
if (input < 0.0 || input > 1.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Min CC for image must be between 0 and 1");
min_cc_for_image = input;
return *this;
}
double ScalingSettings::GetOutlierRejectNsigma() const {
return outlier_reject_nsigma;
}
ScalingSettings &ScalingSettings::OutlierRejectNsigma(double input) {
outlier_reject_nsigma = input; // <= 0 disables; no upper bound (large = effectively off)
return *this;
}
ScalingSettings &ScalingSettings::ScaleFulls(bool input) {
scale_fulls = input;
return *this;
}
bool ScalingSettings::GetScaleFulls() const {
return scale_fulls;
}
ScalingSettings &ScalingSettings::AbsorptionIter(int input) {
if (input < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Absorption iterations must be non-negative");
absorption_iter = input;
return *this;
}
int ScalingSettings::GetAbsorptionIter() const {
return absorption_iter;
}
ScalingSettings &ScalingSettings::CorrectionSurfaces(bool input) {
correction_surfaces = input;
return *this;
}
bool ScalingSettings::GetCorrectionSurfaces() const {
return correction_surfaces;
}
ScalingSettings &ScalingSettings::StillsPartialityRefine(bool input) {
stills_partiality_refine = input;
return *this;
}
bool ScalingSettings::GetStillsPartialityRefine() const {
return stills_partiality_refine;
}
ScalingSettings &ScalingSettings::ExpectedVarianceMerge(bool input) {
expected_variance_merge = input;
return *this;
}
bool ScalingSettings::GetExpectedVarianceMerge() const {
return expected_variance_merge;
}
float ScalingSettings::GetIceMinScore() const {
return ice_min_score;
}
float ScalingSettings::GetIceMinSpotRatio() const {
return ice_min_spot_ratio;
}
ScalingSettings &ScalingSettings::IceMinSpotRatio(float input) {
if (input < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Ice spot-ratio gate must be non-negative");
ice_min_spot_ratio = input;
return *this;
}
ScalingSettings &ScalingSettings::IceMinScore(float input) {
if (input < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Ice score gate must be non-negative");
ice_min_score = input;
return *this;
}
ScalingSettings &ScalingSettings::SmoothGDegrees(double input) {
if (input < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Smooth-G range must be non-negative");
smooth_g_deg = input;
return *this;
}
double ScalingSettings::GetSmoothGDegrees() const {
return smooth_g_deg;
}
ScalingSettings &ScalingSettings::RelativeBDegrees(double input) {
if (input < 0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "Relative-B batch width must be non-negative");
relative_b_deg = input;
return *this;
}
double ScalingSettings::GetRelativeBDegrees() const {
return relative_b_deg;
}
double ScalingSettings::GetMinPartiality() const {
return min_partiality;
}
ScalingSettings &ScalingSettings::ForcedMosaicity(std::optional<double> input) {
if (input.has_value() && (input.value() < GetMinMosaicity() || input.value() > GetMaxMosaicity()))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Forced mosaicity must be between " + std::to_string(GetMinMosaicity()) +
" and " + std::to_string(GetMaxMosaicity()));
forced_mosaicity = input;
return *this;
}
std::optional<double> ScalingSettings::GetForcedMosaicity() const {
return forced_mosaicity;
}
ScalingSettings &ScalingSettings::CaptureUncertaintyCoeff(double input) {
if (input < 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Capture uncertainty coefficient must be non-negative");
capture_uncertainty_coeff = input;
return *this;
}
double ScalingSettings::GetCaptureUncertaintyCoeff() const {
return capture_uncertainty_coeff;
}
ScalingSettings &ScalingSettings::MinCapturedFraction(double input) {
if (input < 0.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Minimum captured fraction must be non-negative");
min_captured_fraction = input;
return *this;
}
double ScalingSettings::GetMinCapturedFraction() const {
return min_captured_fraction;
}
ScalingSettings &ScalingSettings::RfreeFraction(double input) {
if (input < 0.0 || input > 1.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid, "R-free fraction must be between 0 and 1");
rfree_fraction = input;
return *this;
}
double ScalingSettings::GetRfreeFraction() const {
return rfree_fraction;
}
ScalingSettings &ScalingSettings::ResolutionCutoff(ResolutionCutoffMethod input) {
resolution_cutoff = input;
return *this;
}
ResolutionCutoffMethod ScalingSettings::GetResolutionCutoff() const {
return resolution_cutoff;
}
ScalingSettings &ScalingSettings::ResolutionCCTarget(double input) {
if (input <= 0.0 || input >= 1.0)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Resolution CC target must be between 0 and 1");
resolution_cc_target = input;
return *this;
}
double ScalingSettings::GetResolutionCCTarget() const {
return resolution_cc_target;
}
ScalingSettings &ScalingSettings::ReportShellCount(int input) {
if (input < 1)
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Number of report shells must be at least 1");
report_shell_count = input;
return *this;
}
int ScalingSettings::GetReportShellCount() const {
return report_shell_count;
}
ScalingSettings& ScalingSettings::ReportResolutionRange_A(std::optional<ReportResolutionRange> input) {
if (input && !(input->d_min > 0.0 && input->d_max > input->d_min))
throw JFJochException(JFJochExceptionCategory::InputParameterInvalid,
"Report resolution range must be positive and d_max coarser than d_min");
report_resolution_range = input;
return *this;
}
std::optional<ReportResolutionRange> ScalingSettings::GetReportResolutionRange_A() const {
return report_resolution_range;
}