From 9b1ab02c41e89fe54a94df5a5097506ea70c5577 Mon Sep 17 00:00:00 2001 From: leonarski_f Date: Sat, 11 Jul 2026 09:42:23 +0200 Subject: [PATCH] viewer: control _process.h5 and merged .mtz/.cif output independently The 'Save _process.h5' checkbox drove output_prefix, so unchecking it also suppressed the merged .mtz/.cif, and there was no way to run for the ISa/R-meas numbers only. Split it into two checkboxes wired to independent flags: - Save _process.h5 -> ProcessConfig::write_process_h5 (also drives the viewer snapshot, so unchecking it means the viewer is not updated with spots/results) - Write merged .mtz/.cif -> new ProcessConfig::write_merged output_prefix is set when either is wanted; both off = process for stats only. Scaling/merge statistics (hence the ISa/R-meas window) are independent of file writing, so they show in every case. RugnuxCommandLine now emits --write-process-h5 so a copied command matches the GUI's choice. Co-Authored-By: Claude Opus 4.8 --- rugnux/Rugnux.cpp | 2 +- rugnux/Rugnux.h | 5 ++++ rugnux/RugnuxCommandLine.cpp | 5 ++++ viewer/windows/JFJochProcessingJobsWindow.cpp | 25 ++++++++++++++----- viewer/windows/JFJochProcessingJobsWindow.h | 3 ++- 5 files changed, 32 insertions(+), 8 deletions(-) diff --git a/rugnux/Rugnux.cpp b/rugnux/Rugnux.cpp index 8c1d3ad86..b7179a020 100644 --- a/rugnux/Rugnux.cpp +++ b/rugnux/Rugnux.cpp @@ -831,7 +831,7 @@ ProcessResult Rugnux::Run(RugnuxObserver *observer) { result.merge_statistics = sm.statistics; result.has_reference = !config_.reference_data.empty(); - if (result.consensus_cell && write_files) { + if (result.consensus_cell && write_files && config_.write_merged) { phase("Writing reflections"); WriteReflections(sm.merged, *result.consensus_cell, experiment_, sm.statistics, result.error_model_isa > 0 ? fmt::format("{:.2f}", result.error_model_isa) : "?", diff --git a/rugnux/Rugnux.h b/rugnux/Rugnux.h index 69e9a0597..efa6f41e7 100644 --- a/rugnux/Rugnux.h +++ b/rugnux/Rugnux.h @@ -46,6 +46,11 @@ struct ProcessConfig { // (the .mtz/.cif is the wanted output and the h5 is large) unless --write-process-h5 is given. bool write_process_h5 = true; + // Write the merged reflections (.mtz/.cif). Defaults true (the CLI always writes them when + // merging); the viewer can turn them off independently of the _process.h5 (e.g. a quick run that + // only wants the ISa/R-meas numbers). Only relevant to FullAnalysis with scaling. + bool write_merged = true; + SpotFindingSettings spot_finding; // FullAnalysis spot finding // Rotation indexing (FullAnalysis) diff --git a/rugnux/RugnuxCommandLine.cpp b/rugnux/RugnuxCommandLine.cpp index 18408bbef..3ea8f241d 100644 --- a/rugnux/RugnuxCommandLine.cpp +++ b/rugnux/RugnuxCommandLine.cpp @@ -127,6 +127,11 @@ std::string RugnuxCommandLine(const ProcessConfig &config, args.emplace_back("-A"); if (sc.GetRefineB()) args.emplace_back("-B"); + // When merging, the CLI skips the large _process.h5 unless asked; emit the flag when it is + // wanted so a copied command matches the GUI's "Save _process.h5" choice. (write_merged has + // no CLI equivalent - the CLI always writes the .mtz/.cif when merging.) + if (config.write_process_h5) + args.emplace_back("--write-process-h5"); } else { args.emplace_back("--no-merge"); } diff --git a/viewer/windows/JFJochProcessingJobsWindow.cpp b/viewer/windows/JFJochProcessingJobsWindow.cpp index 8bf569ae1..0f2f2c665 100644 --- a/viewer/windows/JFJochProcessingJobsWindow.cpp +++ b/viewer/windows/JFJochProcessingJobsWindow.cpp @@ -138,8 +138,15 @@ int JFJochProcessingJobsWindow::askJob(const ReprocessingInputs &inputs, JobSpec threads->setRange(1, 256); threads->setValue(default_threads()); - auto *save = new QCheckBox("Save _process.h5", &dlg); - save->setChecked(true); + // Two independent outputs: the large per-image _process.h5 (updates the viewer with spots/results) + // and the small merged .mtz/.cif. Either can be turned off; the ISa/R-meas window is shown + // regardless (it needs only the in-memory merge statistics), so a stats-only run turns both off. + auto *save_h5 = new QCheckBox("Save _process.h5 (per-image results; updates viewer)", &dlg); + save_h5->setChecked(true); + + auto *save_merged = new QCheckBox("Write merged .mtz/.cif", &dlg); + save_merged->setChecked(true); + save_merged->setEnabled(!azint); // no merged output in azimuthal-integration mode // Default the output next to the input file, not the viewer's working directory (the viewer starts // wherever it was installed). This is an absolute path; Rugnux writes it via the trusted setter, @@ -160,7 +167,8 @@ int JFJochProcessingJobsWindow::askJob(const ReprocessingInputs &inputs, JobSpec form->addRow("Start image", start_image); form->addRow("End image", end_image); form->addRow("Threads", threads); - form->addRow(save); + form->addRow(save_h5); + form->addRow(save_merged); form->addRow("Output prefix", prefix); form->addRow(scaling); @@ -189,7 +197,8 @@ int JFJochProcessingJobsWindow::askJob(const ReprocessingInputs &inputs, JobSpec spec.start_image = start_image->value(); spec.end_image = end_image->value(); spec.threads = threads->value(); - spec.save = save->isChecked(); + spec.save_h5 = save_h5->isChecked(); + spec.save_merged = save_merged->isEnabled() && save_merged->isChecked(); spec.prefix = prefix->text(); spec.scaling = scaling->isEnabled() && scaling->isChecked(); } @@ -202,7 +211,11 @@ ProcessConfig JFJochProcessingJobsWindow::buildConfig(const JobSpec &spec, const config.nthreads = spec.threads; config.start_image = spec.start_image; config.end_image = spec.end_image > 0 ? spec.end_image : -1; // 0 => to the end - config.output_prefix = spec.save ? spec.prefix.toStdString() : std::string(); + // Files land at output_prefix; leave it empty (write nothing, stats only) when neither output is + // wanted. The two flags then select which files are actually written there. + config.output_prefix = (spec.save_h5 || spec.save_merged) ? spec.prefix.toStdString() : std::string(); + config.write_process_h5 = spec.save_h5; + config.write_merged = spec.save_merged; config.spot_finding = inputs.spot_finding; if (spec.mode == ProcessMode::FullAnalysis) { // Rotation indexing follows the panel's "Process as stills" (= the experiment's indexing @@ -256,7 +269,7 @@ void JFJochProcessingJobsWindow::newJob(bool azint) { JobInfo info; info.id = id; info.label = label; - if (spec.save) + if (spec.save_h5) info.snapshot_path = QString::fromStdString(config.output_prefix) + "_process.h5"; const int row = table_->rowCount(); diff --git a/viewer/windows/JFJochProcessingJobsWindow.h b/viewer/windows/JFJochProcessingJobsWindow.h index 6857fdd08..f24e21db2 100644 --- a/viewer/windows/JFJochProcessingJobsWindow.h +++ b/viewer/windows/JFJochProcessingJobsWindow.h @@ -71,7 +71,8 @@ private: int start_image = 0; int end_image = 0; // 0 == to the end int threads = 4; - bool save = true; + bool save_h5 = true; // write the per-image _process.h5 (also drives the viewer snapshot) + bool save_merged = true; // write the merged .mtz/.cif QString prefix; bool rotation = false; int rotation_images = 30; // images used to find the rotation lattice (first pass)