The factor multiplied into each integrated intensity was called rlp, for reciprocal Lorentz-polarization, and until this week that is all it held. It now also carries the sensor efficiency at the angle the beam arrives, and on the stills path it holds that efficiency and the polarization with no Lorentz term at all - correctly, since the Lorentz factor of a still is one. Three different products under one name that promises exactly one of them, in code where the neighbouring member is the total correction. Rename it prescaling_corr: multiplicative, applied before scaling, therefore not a scale, and silent about its contents - which is the point, since the contents have now grown twice. It is also what DIALS calls the same product. The stills refinement member spelled "1 / rlp" becomes inv_corr, and the comments and usage text that promised "the Lorentz-polarization factor and nothing else" now say what is actually there. The Lorentz term keeps its own name where it is computed, because that name is correct. The two external spellings are untouched: the CBOR key and the reflection dataset are a published format, and a reader that meets an unknown key would take the factor as zero, which both the merge key and the ingest treat as a reflection to drop - so every reflection would vanish and the run would still exit zero. No output changes: the merged and unmerged files of two full runs are byte for byte what the previous binary wrote, four stored files from before the efficiency correction still re-scale identically, and the reflection datasets of the process file are unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EFEJG6WBQv8th4UJFNe53N
77 lines
4.1 KiB
C++
77 lines
4.1 KiB
C++
// SPDX-FileCopyrightText: 2025 Paul Scherrer Institute
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "../common/Reflection.h"
|
|
#include "../common/UnitCell.h"
|
|
#include "../common/DiffractionExperiment.h"
|
|
#include "IntegrationOutcome.h"
|
|
|
|
struct MergeStatistics;
|
|
struct TwinningAnalysisResult;
|
|
|
|
// The error model as it is reported, already formatted. `isa` is the whole-range 1/sqrt(a*b), the
|
|
// same quantity XDS's ISa denotes, so a file written here is directly comparable with a CORRECT.LP;
|
|
// `isa_asymptotic` is the strong-reflection tier, which only the rotation path has. `a` and `b` are
|
|
// in XDS's convention, sigma^2 = a*(sigma0^2 + b*I^2). Empty strings are written as unknown.
|
|
struct ErrorModelReport {
|
|
std::string isa;
|
|
std::string isa_asymptotic;
|
|
std::string a;
|
|
std::string b;
|
|
};
|
|
|
|
// nthreads: workers for the per-reflection row formatting, which is the bulk of the file.
|
|
void WriteMmcifReflections(const std::vector<MergedReflection> &reflections,
|
|
const UnitCell &unitCell,
|
|
const DiffractionExperiment &experiment,
|
|
const MergeStatistics &statistics,
|
|
const ErrorModelReport &error_model,
|
|
const TwinningAnalysisResult &twinning,
|
|
const std::string &filename,
|
|
size_t nthreads);
|
|
|
|
void WriteMtzReflections(const std::vector<MergedReflection> &reflections,
|
|
const UnitCell &unitCell,
|
|
const DiffractionExperiment &experiment,
|
|
const std::string &filename);
|
|
|
|
// SHELX HKLF-4 text file (h k l I sigma(I), Bijvoet mates separate) for SHELXC / ANODE.
|
|
// nthreads: workers for the per-reflection row formatting, as for the mmCIF.
|
|
void WriteShelxHklReflections(const std::vector<MergedReflection> &reflections,
|
|
const DiffractionExperiment &experiment,
|
|
const std::string &filename,
|
|
size_t nthreads);
|
|
|
|
// Unmerged observations in the column and batch-header layout POINTLESS writes: aimless, pointless,
|
|
// careless and iotbx.merging_statistics all read that layout. H K L are the ASU indices and M/ISYM
|
|
// recovers the index the reflection was measured at (which is what careless needs to see the crystal
|
|
// frame) and says whether the observation is a partial.
|
|
// sum_partials: add the partials of each rocking event into one full, written at the batch of the
|
|
// event's centroid with the summed rocking-curve fraction in FRACTIONCALC - the plain sum every
|
|
// rotation program writes, over the events the combine would assemble (--min-partiality). False
|
|
// writes one row per integrated box instead, flagged as partials for the reading program to sum.
|
|
// Stills have no rocking events and are unaffected either way.
|
|
// The intensities carry the prescaling correction and nothing else - the partiality and the
|
|
// per-image scale are left for the reading program to fit, since every program this file is for fits
|
|
// a scale model of its own. The factor that was applied is in the LP column, so raw counts are I/LP;
|
|
// note that the prescaling correction now also carries the sensor efficiency term, which XDS keeps
|
|
// out of RLP and DIALS writes in a separate QE column.
|
|
void WriteUnmergedMtzReflections(const std::vector<IntegrationOutcome> &outcomes,
|
|
const UnitCell &unitCell,
|
|
const DiffractionExperiment &experiment,
|
|
bool sum_partials,
|
|
const std::string &filename);
|
|
|
|
void WriteReflections(const std::vector<MergedReflection> &reflections,
|
|
const UnitCell &unitCell,
|
|
const DiffractionExperiment &experiment,
|
|
const MergeStatistics &statistics,
|
|
const ErrorModelReport &error_model,
|
|
const TwinningAnalysisResult &twinning,
|
|
const std::string &filename,
|
|
size_t nthreads); |