Files
Jungfraujoch/viewer/windows/JFJochProcessingJobsWindow.h
T
leonarski_fandClaude Opus 4.8 0ed943dd4d viewer: show the space group in the merge-statistics window
The de-novo space-group search (SearchSpaceGroup) already ran inside Rugnux but
only its chosen number survived on ProcessResult, and the viewer dropped even
that. Carry the structured SearchSpaceGroupResult (point group + ranked
candidate scores) on ProcessResult and thread it into JFJochMergeStatsWindow,
which now shows a 'Space group' hero card (the final group, searched or fixed)
plus a compact table of candidate groups and their absence scores.

The library no longer renders the search to text (it used to embed it in
merge_statistics_text); rugnux_cli formats it for stdout instead, so the CLI
keeps its text table while the viewer draws a proper table and does not spew it
to stdout. Also surface a user-fixed space group on the result so the card
shows it too.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 09:52:25 +02:00

106 lines
4.8 KiB
C++

// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
// SPDX-License-Identifier: GPL-3.0-only
#pragma once
#include <QElapsedTimer>
#include <QString>
#include <QWidget>
#include <cstdint>
#include <optional>
#include <vector>
#include "../JFJochProcessController.h"
#include "../JFJochImageReadingWorker.h" // ReprocessingInputs
class QTableWidget;
class QProgressBar;
class QStackedWidget;
class QToolBar;
class QToolButton;
// Makes processing a first-class GUI activity: a dockable panel with a table of processing jobs run
// on the current dataset. A job can be run locally (off the GUI thread, via JFJochProcessController)
// or its rugnux command line copied for a cluster. A finished local run is registered as a
// reader snapshot so its results become a selectable view of the dataset. Re-processing reads a
// stored HDF5 file, so the panel shows an explanatory message while connected to a live HTTP stream.
class JFJochProcessingJobsWindow : public QWidget {
Q_OBJECT
public:
explicit JFJochProcessingJobsWindow(JFJochImageReadingWorker *worker, QWidget *parent = nullptr);
signals:
void registerSnapshot(QString id, QString label, QString master_path);
void activateSnapshot(QString id);
void renameRun(QString id, QString label);
void removeRun(QString id);
void writeStatusBar(QString message, int timeout_ms = 0);
// Live per-image results while a job runs, for the dataset-info plots (nullptr clears it).
void liveDataset(std::shared_ptr<const JFJochReaderDataset> dataset);
void jobStarted(); // a reprocessing job was launched — reveal the (hidden-by-default) panel
public slots:
void onHttpConnectionChanged(bool connected, QString addr);
void clearJobs(); // reset the table on a new file (re-adds the Original row)
void setActiveRun(QString active_id); // bold the row of the run currently shown in the plots
void newJob(bool azint = false); // the panel's "Analyze dataset" action; azint = AzInt page
private slots:
void cancelJob();
void removeResult();
void viewResults();
void onPhase(QString phase);
void onProgress(quint64 done, quint64 total);
void onFinished(ProcessResult result);
void onFailed(QString error);
private:
struct JobInfo {
QString id; // stable reader-snapshot key
QString label; // editable display name (legend / table)
QString snapshot_path; // empty unless saved
bool has_result = false;
// Merge statistics captured when a scaling/merging job finished (drive the analysis window).
bool has_merge_stats = false;
MergeStatistics merge_stats;
double isa = 0.0;
bool merge_has_reference = false;
TwinningAnalysisResult twinning; // twinning test of the merged intensities
std::optional<int64_t> space_group_number; // final space group (searched or fixed)
std::optional<SearchSpaceGroupResult> space_group_search; // ranked candidates, when a search ran
QToolButton *graph_btn = nullptr; // per-row "show statistics" button (enabled once stats exist)
};
struct JobSpec {
ProcessMode mode = ProcessMode::FullAnalysis;
int start_image = 0;
int end_image = 0; // 0 == to the end
int threads = 4;
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)
bool scaling = false;
};
// Returns 0 = cancel, 1 = run locally, 2 = copy command line; fills spec from the dialog.
int askJob(const ReprocessingInputs &inputs, JobSpec &spec, bool azint);
ProcessConfig buildConfig(const JobSpec &spec, const ReprocessingInputs &inputs) const;
void setStatus(int row, const QString &text);
void addOriginalRow(); // the file's own data as the first, always-present run
void addRowActions(int row, const QString &id); // per-row graph (stats) + trash (remove) buttons
void showStats(const QString &id); // open the merge-statistics window for a run
void removeRunById(const QString &id); // remove a run from the table + reader
JFJochImageReadingWorker *worker_;
JFJochProcessController *controller_;
QToolBar *toolbar_;
QStackedWidget *stack_; // page 0: jobs table, page 1: HTTP-mode message
QTableWidget *table_;
QProgressBar *running_bar_ = nullptr; // lives in the running row's Status cell
QElapsedTimer job_timer_; // running job wall-clock, for rate + ETA
int running_row_ = -1;
int job_counter_ = 0;
std::vector<JobInfo> jobs_;
};