Reworks the --model / French-Wilson / R-free path so a batch of datasets of one crystal form yields comparable maps and a shared test set, and fixes a French-Wilson prior bug. - French-Wilson: fix inverted centric/acentric prior - the call passed !centric into the selector, swapping the two Wilson forms for every weak reflection. Add a test pinning a centric weak |F| below an acentric one. - R-free flags: assign by a pure per-hkl hash instead of a per-dataset resolution-shell stratification, so every dataset of one crystal form gets the same free set (needed for ensemble refinement / PanDDA). Still a pure function of the Laue-ASU key, so Bijvoet/symmetry mates never split. - R-free flags: import a reference MTZ's FreeR_flag column when present (CCP4 test=0, auto-complement for a phenix-style test=1), so a whole campaign inherits one shared test set. New ApplyReferenceFreeFlags, wired post-merge in both the full-analysis and --scale paths. - Model maps: scale the model with an overall scale, anisotropic B and flat bulk solvent only - drop the free-form per-shell K(1/d^2) rescale, which reshaped each dataset's radial amplitude profile differently and made a batch of maps non-comparable. - Merohedral indexing: model validation resolves the ambiguity by lowest R-free only when there is no reference; with a reference MTZ the indexing is already resolved against it (merge stage / stills scaling) and that authoritative choice is kept. - Remove a stale <algorithm> include; update docs and changelog. Tests: french_wilson, rfree, reference_mtz (new), reindex, hkl_key all pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
62 lines
3.4 KiB
C++
62 lines
3.4 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <optional>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "../common/Reflection.h"
|
|
#include "../common/UnitCell.h"
|
|
|
|
// A column an MTZ offers as reference intensities/structure factors (type 'J' mean intensity or
|
|
// 'F' amplitude). Surfaced so the caller (CLI flag / viewer combo) can pick which one to scale
|
|
// against and report the choice, rather than the loader silently guessing.
|
|
struct ReferenceMtzColumn {
|
|
std::string label;
|
|
char type = '\0'; // 'J' = mean intensity, 'F' = structure-factor amplitude
|
|
};
|
|
|
|
// Reference reflections loaded from an MTZ, plus the metadata a user needs to judge whether the
|
|
// reference matches the data being scaled: which column was used, the cell / space group it was
|
|
// recorded in, its resolution range and reflection count.
|
|
struct ReferenceMtzData {
|
|
std::vector<MergedReflection> reflections; // h,k,l,I,d set (sigma stays NaN)
|
|
std::optional<UnitCell> cell;
|
|
std::optional<int> space_group_number;
|
|
std::string space_group_name; // Hermann-Mauguin short symbol, for display
|
|
std::string point_group; // point-group symbol, for the consistency check
|
|
std::string used_column;
|
|
char used_column_type = '\0';
|
|
bool squared = false; // an 'F' column was squared to an intensity
|
|
bool default_column = true; // column was auto-selected, not user-specified
|
|
std::vector<ReferenceMtzColumn> candidate_columns;
|
|
double d_min = 0.0;
|
|
double d_max = 0.0;
|
|
|
|
// Cross-validation (free-R) flags, if the MTZ carried a FreeR_flag column. When present, the
|
|
// per-reflection rfree_flag above is set from it and a whole campaign can inherit one test set.
|
|
bool has_free_flags = false;
|
|
std::string free_column; // the FreeR column label used, for display
|
|
int n_free = 0; // number of reflections flagged free (test set)
|
|
};
|
|
|
|
// Load reference reflections from an MTZ. With no column requested the smart default is used:
|
|
// a calculated structure factor F-model (squared to an intensity), else a merged/observed
|
|
// intensity column (IMEAN/I/IOBS/...), else any mean-intensity (J) column - this also lets
|
|
// reference-based scaling be self-seeded from the data's own previous merge. A requested column overrides
|
|
// the default (an 'F'-type column is squared, a 'J'-type used directly). Throws if the requested
|
|
// column is missing or no usable column exists.
|
|
ReferenceMtzData LoadReferenceMtz(const std::string& path,
|
|
const std::optional<std::string>& column = std::nullopt);
|
|
|
|
// Compare a loaded reference against the data it will scale. Returns an empty string when they are
|
|
// consistent (or when the data cell / space group is unknown, so nothing can be said); otherwise a
|
|
// one-line, human-readable description of the mismatch to warn the user about. Reference intensities
|
|
// keyed in a different point group or cell do not correspond to the data, so this is the check that
|
|
// makes reference-based scaling and CCref trustworthy.
|
|
std::string ReferenceConsistencyWarning(const ReferenceMtzData& reference,
|
|
const std::optional<UnitCell>& data_cell,
|
|
std::optional<int> data_space_group_number);
|