Stills: --stills-window-sigmas sets the prediction window's half-width

The stills prediction window was a fixed two run rocking widths. --stills-window-sigmas K predicts,
integrates and (with --export-observations) exports the rocking curve's tails out to K widths, which
is what a partiality model fitted from the data needs to see; --min-partiality decides separately
what the merge takes. The default stays 2 and the processing is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HVeDQqN9qRD57vnShzTC37
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-31 14:01:44 +01:00
1 parent c188c9509e
commit b6b83b2a22
3 files changed
+15 -4

No files matched your search

+4 -1
View File
@@ -268,6 +268,10 @@ struct ProcessConfig {
// (ObservationMtzTable; --export-observations). Off by default; it does not change the processing.
bool export_observations = false;
// Stills: the prediction window's half-width, in run rocking widths (--stills-window-sigmas). Wider
// predicts, integrates and exports more of the rocking curve's tails.
double stills_window_sigmas = 2.0;
// If set, after merging, validate the merged intensities against this atomic model: compute
// R-free with an optimized bulk solvent and write 2Fo-Fc / Fo-Fc maps (--model). The caller parses
// it (ParseRugnuxModel, writer/RugnuxModelFile.h).
@@ -1612,7 +1616,6 @@ class Rugnux {
// --export-observations: the written stills merge's verdict on every observation, and its resolution cut.
std::vector<std::vector<ObservationVerdict>> observation_verdicts_;
std::optional<double> observation_d_min_;
static constexpr double STILLS_WINDOW_SIGMAS = 2.0; // the window's half-width, in rocking widths
static constexpr int STILLS_WINDOW_MIN_FRAMES = 2000; // the sample: a tenth of the run, at least this
static constexpr int STILLS_WINDOW_FRACTION = 10;
// Stills: where the frames' pixel values pile up, against the file's saturation limit (see there).
+3 -3
View File
@@ -260,7 +260,7 @@ void Rugnux::ImagePass(PipelineLocals &p) {
// predicted five to eight widths at low resolution, mostly empty, and cut the curve at one or two at
// high resolution, so the partials there were never integrated. So the run's width is measured first,
// on a sample of the frames integrated the old way (MeasureRunWidth, as the merge measures it), and
// every frame is then predicted through STILLS_WINDOW_SIGMAS of it.
// every frame is then predicted through config_.stills_window_sigmas of it.
std::vector<int> window_frames;
const bool stills_window = full && per_image_analysis && !calibration && !geometry_prepass && indexer
&& !experiment_.IsRotationIndexing() && config_.spot_finding.indexing
@@ -452,13 +452,13 @@ void Rugnux::ImagePass(PipelineLocals &p) {
for (const int o: window_frames)
outcomes[o] = IntegrationOutcome{};
if (stills_run_width_) {
const auto k = static_cast<float>(STILLS_WINDOW_SIGMAS);
const auto k = static_cast<float>(config_.stills_window_sigmas);
indexer->SetStillsWindow(StillsWindow{.c0 = k * static_cast<float>(stills_run_width_->gamma0),
.ang = k * static_cast<float>(stills_run_width_->gamma_e),
.bw = k * static_cast<float>(stills_run_width_->bandwidth_sigma),
.q_scale = static_cast<float>(stills_run_width_->radial_scale)});
Note(fmt::format("prediction window {:.1f} x the rocking width measured on {} frames, centred at "
"radial scale {:+.2e}", STILLS_WINDOW_SIGMAS, window_frames.size(), radial_scale - 1.0));
"radial scale {:+.2e}", config_.stills_window_sigmas, window_frames.size(), radial_scale - 1.0));
}
}
for (int i = 0; i < image_workers; ++i)
+8
View File
@@ -235,6 +235,7 @@ enum {
OPT_NO_EXPORT_UNMERGED,
OPT_EXPORT_UNMERGED_PARTIALS,
OPT_EXPORT_OBSERVATIONS,
OPT_STILLS_WINDOW_SIGMAS,
OPT_DUMP_OBSERVATIONS,
OPT_INTEGRATOR,
OPT_SIMPLE_STILLS,
@@ -319,6 +320,7 @@ static option long_options[] = {
{"no-export-unmerged", no_argument, nullptr, OPT_NO_EXPORT_UNMERGED},
{"export-unmerged-partials", no_argument, nullptr, OPT_EXPORT_UNMERGED_PARTIALS},
{"export-observations", no_argument, nullptr, OPT_EXPORT_OBSERVATIONS},
{"stills-window-sigmas", required_argument, nullptr, OPT_STILLS_WINDOW_SIGMAS},
{"dump-observations", required_argument, nullptr, OPT_DUMP_OBSERVATIONS},
{"space-group", required_argument, nullptr, 'S'},
{"anomalous", no_argument, nullptr, 'A'},
@@ -914,6 +916,7 @@ struct RugnuxCli {
bool export_unmerged = true; // on by default; --no-export-unmerged turns it off
bool export_unmerged_partials = false; // --export-unmerged-partials: the same, one row per image
bool export_observations = false; // --export-observations: <prefix>_obs.mtz, stills diagnostic
std::optional<double> stills_window_sigmas_arg; // --stills-window-sigmas
std::string dump_observations; // diagnostic: dump unmerged -P rot3d fulls to this path
std::optional<double> min_partiality_arg; // --min-partiality; default per mode (RugnuxDefaultScalingSettings)
std::optional<double> min_captured_fraction_arg; // explicit --min-captured-fraction; default depends on rotation
@@ -1267,6 +1270,9 @@ int RugnuxCli::Parse(int argc, char **argv) {
case OPT_EXPORT_OBSERVATIONS:
export_observations = true;
break;
case OPT_STILLS_WINDOW_SIGMAS:
stills_window_sigmas_arg = parse_double_arg(optarg, "--stills-window-sigmas", logger);
break;
case OPT_DUMP_OBSERVATIONS:
dump_observations = optarg;
break;
@@ -3612,6 +3618,8 @@ int RugnuxInputRun::PrepareRugnuxInput() {
};
config.export_unmerged = export_unmerged;
config.export_observations = export_observations;
if (stills_window_sigmas_arg)
config.stills_window_sigmas = *stills_window_sigmas_arg;
config.export_unmerged_partials = export_unmerged_partials;
config.model = model;
config.force_mr = !mr_model.empty();