From df1536db7f7ce43bdc1f019ee5f0f74268b151ba Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Sat, 12 Sep 2026 18:16:15 +0200 Subject: [PATCH] unmerged export: the comments name the FLIGHT column they forgot The header and the two in-function comments describing what the unmerged MTZ carries still said "two columns" and "raw counts are I / LP * QE", written before the flight-path term and its FLIGHT column were added. The code, the test and docs/RUGNUX_INTEGRATION.md all say I / LP * QE * FLIGHT; only these comments did not. Also drops the self-referential note in Reflection.h about a comment having been overtaken, and states the flight factor's symbols and the medium rather than assuming air. No behaviour change. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_011GxZqDiFP3KqriBhNdcR56 --- common/Reflection.h | 12 +++++++----- image_analysis/WriteReflections.cpp | 11 ++++++----- image_analysis/WriteReflections.h | 9 +++++---- 3 files changed, 18 insertions(+), 14 deletions(-) diff --git a/common/Reflection.h b/common/Reflection.h index 7f547f5fa..beb7aacf9 100644 --- a/common/Reflection.h +++ b/common/Reflection.h @@ -35,12 +35,14 @@ struct Reflection { // sensor is opaque or its material and thickness are unknown. It is carried BESIDE // prescaling_corr rather than inside it, because LP and detector response are two different // things and every file the field reads keeps them apart. It is one of the three factors whose - // product is the total deterministic correction - see flight_corr below, which arrived after - // this comment was written and made "the two" wrong. Defaulted to 1 so a reflection read from a - // file written before this existed is a no-op rather than a zero. + // product is the total deterministic correction, with prescaling_corr above and flight_corr + // below. Defaulted to 1 so a reflection read from a file written before this existed is a no-op + // rather than a zero. float qe_corr = 1.0f; - // The air in the sample-to-pixel flight path, exp(D/L * (1/cos(alpha) - 1)): always >= 1, and - // exactly 1 when the air correction is switched off. Carried beside the two above for the same + // The medium in the sample-to-pixel flight path, exp(D/L * (1/cos(alpha) - 1)) with D the + // normal-incidence distance, L the medium's attenuation length and alpha the angle of incidence + // on the detector: always >= 1, because an oblique reflection crossed more of the medium than + // one arriving head-on. Exactly 1 under --flight-path vacuum. Carried beside the two above for the same // reason they are carried apart - it is neither beam geometry nor detector response but the // medium in between, and unlike either of them it is set by the flight distance. The total // deterministic correction on a reflection is prescaling_corr * qe_corr * flight_corr, and every diff --git a/image_analysis/WriteReflections.cpp b/image_analysis/WriteReflections.cpp index 75faba113..2a7b6a4c4 100644 --- a/image_analysis/WriteReflections.cpp +++ b/image_analysis/WriteReflections.cpp @@ -733,7 +733,7 @@ void WriteUnmergedMtzReflections(const std::vector &outcomes ds.wavelength = experiment.GetWavelength_A(); // Every data column belongs to HKL_base and only the batches carry a dataset id, as in a - // POINTLESS file. Down to FLAG this is POINTLESS's own column set, plus QE; the four after it + // POINTLESS file. Down to FLAG this is POINTLESS's own column set, plus QE and FLIGHT; the four after it // are what rugnux measures beyond it - the offset of the reflection from the centre of its // rocking curve, the Lorentz geometry of that curve, and the background that was subtracted. // @@ -787,10 +787,11 @@ void WriteUnmergedMtzReflections(const std::vector &outcomes // crystal-frame information careless scales on, and what makes the file unmerged rather than a // merge waiting to happen. // I and SIGI are the integrated intensity with every deterministic per-reflection correction - // applied and nothing else, which is what IOBS means in every unmerged format. Two columns - // record what was applied, so the raw count sum is recoverable exactly as I / LP * QE: - // LP is Lorentz x polarization and QE the sensor efficiency (a divisor, hence the multiply). - // Neither is a scale, and a program that reads this file has no way to recompute them. The + // applied and nothing else, which is what IOBS means in every unmerged format. Three columns + // record what was applied, so the raw count sum is recoverable exactly as I / LP * QE * FLIGHT: + // LP is Lorentz x polarization, QE the sensor efficiency and FLIGHT the attenuation of the + // flight-path medium (both divisors, hence the multiplies). + // None of the three is a scale, and a program that reads this file has no way to recompute them. The // partiality is NOT divided out - that IS a scale, FRACTIONCALC carries it, and every program // this file is for wants to handle it its own way. gemmi::UnmergedHklMover hkl_mover(mtz.spacegroup); diff --git a/image_analysis/WriteReflections.h b/image_analysis/WriteReflections.h index 9b439f3d0..a6c59010e 100644 --- a/image_analysis/WriteReflections.h +++ b/image_analysis/WriteReflections.h @@ -56,10 +56,11 @@ void WriteShelxHklReflections(const std::vector &reflections, // 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 deterministic per-reflection corrections and nothing else - Lorentz, -// polarization and the sensor's angle-dependent efficiency, recorded in the LP and QE columns, so -// raw counts are I / LP * QE. 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 intensities carry the deterministic per-reflection corrections and nothing else - Lorentz +// and polarization in LP, the sensor's angle-dependent efficiency in QE, and the attenuation of the +// flight-path medium in FLIGHT - so raw counts are I / LP * QE * FLIGHT. 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. void WriteUnmergedMtzReflections(const std::vector &outcomes, const UnitCell &unitCell, const DiffractionExperiment &experiment,