Files
Jungfraujoch/writer/RugnuxReflectionFile.h
leonarski_fandClaude Opus 5.5 d9d939ae44 RESULT-CHANGING: --mode refine: the test set of a structure-factor mmCIF whose free flags are classes, decided by the model as given
A deposited structure-factor mmCIF marks the free set with _refln.status 'f', and the reader took that mark over
_refln.pdbx_r_free_flag. Where the flags are classes (0-19), the status can mark a class the depositors' refinement
did not hold out: the deposited model then fits the marked class like working data, R-work comes out above R-free,
and refinement seems to make the model worse.

The reader now keeps the numeric classes beside the status (RugnuxReflections::free_class, an extra FreeR_class
column in the conversion). Where there are more than two classes, RunRefineOnly scores the model as given on each
class (score-only, untwinned, no solvent build), within the resolution range the model file records its refinement
to, and counts each class's reflections in that range:

- STATUS: the marked class is the one the model fits worst, or its count is the nearest to the model file's test-set
  count (REMARK 3 FREE R VALUE TEST SET COUNT / _refine.ls_number_reflns_R_free);
- REMARK3_COUNT: else the worst-fit class, where its count is the nearest;
- WORST_FIT: else the worst-fit class, where it is above the marked one by more than twice the scatter of the other
  classes' R (the marked class is fitted like a working one); otherwise the mark stands.

The count is corroboration only: over the battery's PDB cache (106 files with 20 classes) the marked class is within
a few reflections of the count on nearly all, and another class has the count exactly on about 7 of them (20 classes
of about the same size), so the count alone would move correct marks. The choice is logged with R per class and
reported as REFINE_FREE_SET_SOURCE / REFINE_FREE_SET_CLASS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVeDQqN9qRD57vnShzTC37
2026-10-28 16:06:50 +01:00

55 lines
3.1 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <string>
#include <vector>
#include "gemmi/mtz.hpp"
#include "gemmi/unitcell.hpp"
#include "../common/Reflection.h"
// Merged reflections a refinement is given (rugnux --mode refine), as their file held them: an MTZ or a
// structure-factor mmCIF (as the PDB holds them), gzipped or not, the format taken from the content. The
// columns are found, not named: amplitudes with their sigmas where the file has them, else intensities (the
// caller turns those into amplitudes), and the free-set flags where there are any. The caller parses; the
// analysis reads no file.
struct RugnuxReflections {
std::string name; // what the report calls the file
std::string source; // "MTZ" or "mmCIF block <name>"
gemmi::UnitCell cell;
std::string space_group; // extended Hermann-Mauguin symbol
double wavelength_A = 0; // 0: the file does not say
// h, k, l and d, with F/sigmaF where amplitudes were read, I/sigma where intensities were; rfree_flag
// where the file has free-set flags.
std::vector<MergedReflection> reflections;
bool amplitudes = true; // false: intensities, no amplitudes in the file
std::string value_column, sigma_column;
std::string free_column; // empty: the file has no free-set flags
int n_free = 0;
// A structure-factor mmCIF's numeric free-set classes (_refln.pdbx_r_free_flag) per reflection, -1 where it
// gives none; empty for an MTZ or where the file has no such column. free_column marks one class of them
// (_refln.status 'f', or the flag by the convention above), which need not be the depositors' test set.
std::vector<int> free_class;
};
// The columns of `mtz` (an MTZ, or an mmCIF converted to one), found as RugnuxReflections describes:
// - amplitudes: a type-F column followed by its type-Q sigma, by the usual names first (F, FP, FOBS, F-obs,
// FMEAN, ...), then any such pair that is not a calculated or map coefficient (FC, FWT, DELFWT, F-model ...);
// - else intensities: a type-J column with its type-Q sigma (IMEAN, I, IOBS, I-obs, ... first); the
// anomalous pairs F(+)/F(-) (G/L) or I(+)/I(-) (K/M) averaged where there is nothing else;
// - free flags: a type-I column named as a free set (FreeR_flag, FREE, R-free-flags, ...: any with "free" in
// its name). The test set is flag 0 in the CCP4 convention (0-19 thin shells included); where 0 marks the
// majority (1 marks the test set, as phenix and CNS write it), the minority is taken.
// Throws where there is neither.
RugnuxReflections RugnuxReflectionsFromMtz(const gemmi::Mtz &mtz, const std::string &name);
// The reflections of a file's bytes, the format from the content (MTZ by its magic, else mmCIF: the first
// merged block that holds amplitudes or intensities). Throws where the bytes hold none.
RugnuxReflections ParseRugnuxReflections(const std::string &bytes, const std::string &name);
// The file at `path`, named by it.
RugnuxReflections ReadRugnuxReflectionFile(const std::string &path);