process/viewer: command-line generator + JFJochProcessController (GUI engine)
Foundation for making processing a first-class GUI activity: - process/JFJochProcessCommandLine: reconstruct the equivalent jfjoch_process / jfjoch_azint command line from a ProcessConfig + DiffractionExperiment + input path, for handing a job off to a cluster. Unit-tested (full + azint). - viewer/JFJochProcessController: runs one JFJochProcess job off the GUI thread (its own private reader; HDF5 access is globally serialized so it is safe next to the interactive reader) and reports back via queued Qt signals (started/phaseChanged/progress/finished/failed). Cancel() forwards to JFJochProcess::Cancel(). Progress is throttled to ~200 updates per run. The visible processing UI (jobs window + snapshot switcher + converged settings) builds on this. Verified: tests/jfjoch_test [process]; jfjoch_viewer links and builds against JFJochProcess. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "JFJochProcessController.h"
|
||||
#include "../reader/JFJochHDF5Reader.h"
|
||||
|
||||
#include <QMetaType>
|
||||
|
||||
JFJochProcessController::JFJochProcessController(QObject *parent) : QObject(parent) {
|
||||
qRegisterMetaType<ProcessResult>("ProcessResult");
|
||||
}
|
||||
|
||||
JFJochProcessController::~JFJochProcessController() {
|
||||
cancel();
|
||||
joinWorker_();
|
||||
}
|
||||
|
||||
void JFJochProcessController::joinWorker_() {
|
||||
if (worker_.joinable())
|
||||
worker_.join();
|
||||
}
|
||||
|
||||
void JFJochProcessController::start(const QString &file_path, DiffractionExperiment experiment,
|
||||
PixelMask pixel_mask, ProcessConfig config) {
|
||||
if (running_.exchange(true))
|
||||
return; // a job is already running
|
||||
|
||||
cancel_pending_ = false;
|
||||
joinWorker_(); // reap the previous (finished) worker, if any
|
||||
worker_ = std::thread(&JFJochProcessController::run_, this,
|
||||
file_path, std::move(experiment), std::move(pixel_mask), std::move(config));
|
||||
emit started();
|
||||
}
|
||||
|
||||
void JFJochProcessController::cancel() {
|
||||
cancel_pending_ = true;
|
||||
if (auto *p = active_.load())
|
||||
p->Cancel();
|
||||
}
|
||||
|
||||
void JFJochProcessController::run_(QString file_path, DiffractionExperiment experiment,
|
||||
PixelMask pixel_mask, ProcessConfig config) {
|
||||
try {
|
||||
JFJochHDF5Reader reader;
|
||||
reader.ReadFile(file_path.toStdString());
|
||||
|
||||
JFJochProcess process(reader, std::move(experiment), std::move(pixel_mask), std::move(config));
|
||||
active_ = &process;
|
||||
if (cancel_pending_)
|
||||
process.Cancel();
|
||||
|
||||
ProcessResult result = process.Run(this);
|
||||
|
||||
active_ = nullptr;
|
||||
running_ = false;
|
||||
emit finished(result);
|
||||
} catch (const std::exception &e) {
|
||||
active_ = nullptr;
|
||||
running_ = false;
|
||||
emit failed(QString::fromStdString(e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
void JFJochProcessController::OnPhase(const std::string &phase) {
|
||||
emit phaseChanged(QString::fromStdString(phase));
|
||||
}
|
||||
|
||||
void JFJochProcessController::OnProgress(uint64_t done, uint64_t total) {
|
||||
// Throttle to ~200 updates so a long run does not flood the GUI event queue.
|
||||
const uint64_t step = total > 200 ? total / 200 : 1;
|
||||
if (done == total || done % step == 0)
|
||||
emit progress(done, total);
|
||||
}
|
||||
Reference in New Issue
Block a user