Commit 3ee7b168 authored by Samuel Jones's avatar Samuel Jones
Browse files

Merge branch '25431_ISISReflectometryGUIPlotting' into 25383_PortReflectometryGUIToWorkbench

parents 5e4f4183 e711a4ce
......@@ -49,6 +49,7 @@ set ( TEST_FILES
test/UserInputValidatorTest.h
test/ISISReflectometry/Batch/BatchJobRunnerTest.h
test/ISISReflectometry/Batch/BatchPresenterTest.h
test/ISISReflectometry/Batch/GroupProcessingAlgorithmTest.h
test/ISISReflectometry/Batch/RowProcessingAlgorithmTest.h
test/ISISReflectometry/Reduction/GroupTest.h
test/ISISReflectometry/Reduction/ValidateRowTest.h
......
......@@ -6,6 +6,7 @@
// SPDX - License - Identifier: GPL - 3.0 +
#include "BatchJobRunner.h"
#include "BatchJobAlgorithm.h"
#include "GroupProcessingAlgorithm.h"
#include "MantidAPI/AnalysisDataService.h"
#include "RowProcessingAlgorithm.h"
......@@ -29,6 +30,7 @@ void BatchJobRunner::reductionResumed() {
m_reprocessFailed = m_batch.hasSelection();
// If there are no selected rows, process everything
m_processAll = !m_batch.hasSelection();
m_batch.resetSkippedItems();
}
void BatchJobRunner::reductionPaused() { m_isProcessing = false; }
......@@ -38,6 +40,7 @@ void BatchJobRunner::autoreductionResumed() {
m_isProcessing = true;
m_reprocessFailed = true;
m_processAll = true;
m_batch.resetSkippedItems();
}
void BatchJobRunner::autoreductionPaused() { m_isAutoreducing = false; }
......@@ -46,19 +49,56 @@ void BatchJobRunner::setReprocessFailedItems(bool reprocessFailed) {
m_reprocessFailed = reprocessFailed;
}
/** Get algorithms and related properties for processing rows and groups
* in the table
template <typename T> bool BatchJobRunner::isSelected(T const &item) {
return m_processAll || m_batch.isSelected(item);
}
bool BatchJobRunner::hasSelectedRows(Group const &group) {
// If the group itself is selected, consider its rows to also be selected
if (m_processAll || isSelected(group))
return true;
for (auto const &row : group.rows()) {
if (row && isSelected(row.get()))
return true;
}
return false;
}
/** Get algorithms and related properties for processing a batch of rows and
* groups in the table
*/
std::deque<IConfiguredAlgorithm_sptr> BatchJobRunner::getAlgorithms() {
auto algorithms = std::deque<IConfiguredAlgorithm_sptr>();
auto &groups =
m_batch.mutableRunsTable().mutableReductionJobs().mutableGroups();
for (auto &group : groups) {
addAlgorithmsForProcessingRowsInGroup(group, algorithms);
// Process the rows in the group or, if there are no rows to process,
// postprocess the group. If that's also done, continue to the next group
if (hasSelectedRows(group) && group.requiresProcessing(m_reprocessFailed)) {
addAlgorithmsForProcessingRowsInGroup(group, algorithms);
return algorithms;
} else if (isSelected(group) &&
group.requiresPostprocessing(m_reprocessFailed)) {
addAlgorithmForPostprocessingGroup(group, algorithms);
return algorithms;
}
}
return algorithms;
}
/** Add the algorithms and related properties for postprocessing a group
* @param group : the group to get the row algorithms for
* @param algorithms : the list of configured algorithms to add this group to
* @returns : true if algorithms were added, false if there was nothing to do
*/
void BatchJobRunner::addAlgorithmForPostprocessingGroup(
Group &group, std::deque<IConfiguredAlgorithm_sptr> &algorithms) {
auto algorithm = createConfiguredAlgorithm(m_batch, group);
algorithms.emplace_back(std::move(algorithm));
}
/** Add the algorithms and related properties for processing all the rows
* in a group
* @param group : the group to get the row algorithms for
......@@ -70,10 +110,9 @@ void BatchJobRunner::addAlgorithmsForProcessingRowsInGroup(
Group &group, std::deque<IConfiguredAlgorithm_sptr> &algorithms) {
auto &rows = group.mutableRows();
for (auto &row : rows) {
if (row && row->requiresProcessing(m_reprocessFailed) &&
(m_processAll || m_batch.isSelected(row.get()))) {
if (row && isSelected(row.get()) &&
row->requiresProcessing(m_reprocessFailed))
addAlgorithmForProcessingRow(row.get(), algorithms);
}
}
}
......@@ -91,25 +130,34 @@ void BatchJobRunner::addAlgorithmForProcessingRow(
void BatchJobRunner::algorithmStarted(IConfiguredAlgorithm_sptr algorithm) {
auto jobAlgorithm =
boost::dynamic_pointer_cast<IBatchJobAlgorithm>(algorithm);
jobAlgorithm->item()->algorithmStarted();
jobAlgorithm->item()->resetOutputNames();
jobAlgorithm->item()->setRunning();
}
void BatchJobRunner::algorithmComplete(IConfiguredAlgorithm_sptr algorithm) {
auto jobAlgorithm =
boost::dynamic_pointer_cast<IBatchJobAlgorithm>(algorithm);
jobAlgorithm->item()->algorithmComplete(jobAlgorithm->outputWorkspaceNames());
// The workspaces are not in the ADS by default, so add them
for (auto &kvp : jobAlgorithm->outputWorkspaceNameToWorkspace()) {
Mantid::API::AnalysisDataService::Instance().addOrReplace(kvp.first,
kvp.second);
}
jobAlgorithm->item()->setOutputNames(jobAlgorithm->outputWorkspaceNames());
jobAlgorithm->item()->setSuccess();
}
void BatchJobRunner::algorithmError(IConfiguredAlgorithm_sptr algorithm,
std::string const &message) {
auto jobAlgorithm =
boost::dynamic_pointer_cast<IBatchJobAlgorithm>(algorithm);
jobAlgorithm->item()->algorithmError(message);
auto *item = jobAlgorithm->item();
item->resetOutputNames();
item->setError(message);
// Mark the item as skipped so we don't reprocess it in the current round of
// reductions.
item->setSkipped(true);
}
std::vector<std::string> BatchJobRunner::algorithmOutputWorkspacesToSave(
......
......@@ -63,6 +63,11 @@ private:
std::vector<std::string> getWorkspacesToSave(Group const &group) const;
std::vector<std::string> getWorkspacesToSave(Row const &row) const;
template <typename T> bool isSelected(T const &item);
bool hasSelectedRows(Group const &group);
void addAlgorithmForPostprocessingGroup(
Group &group,
std::deque<MantidQt::API::IConfiguredAlgorithm_sptr> &algorithms);
void addAlgorithmsForProcessingRowsInGroup(
Group &group,
std::deque<MantidQt::API::IConfiguredAlgorithm_sptr> &algorithms);
......
......@@ -90,8 +90,16 @@ void BatchPresenter::notifyAutoreductionCompleted() {
void BatchPresenter::notifyBatchComplete(bool error) {
UNUSED_ARG(error);
reductionPaused();
// Make sure views are up to date with any changes in state
m_runsPresenter->notifyRowStateChanged();
// Continue processing the next batch of algorithms, if there is more to do
auto algorithms = m_jobRunner->getAlgorithms();
if (algorithms.size() > 0)
startBatch(std::move(algorithms));
else
reductionPaused();
}
void BatchPresenter::notifyBatchCancelled() {
......@@ -126,16 +134,32 @@ void BatchPresenter::notifyAlgorithmError(IConfiguredAlgorithm_sptr algorithm,
m_runsPresenter->notifyRowStateChanged();
}
void BatchPresenter::resumeReduction() {
reductionResumed();
/** Start processing the next batch of algorithms.
* @returns : true if processing was started, false if there was nothing to do
*/
bool BatchPresenter::startBatch(
std::deque<IConfiguredAlgorithm_sptr> algorithms) {
m_view->clearAlgorithmQueue();
m_view->setAlgorithmQueue(m_jobRunner->getAlgorithms());
m_view->setAlgorithmQueue(std::move(algorithms));
m_view->executeAlgorithmQueue();
return true;
}
void BatchPresenter::reductionResumed() {
void BatchPresenter::resumeReduction() {
// Update the model
m_jobRunner->reductionResumed();
// Get the algorithms to process
auto algorithms = m_jobRunner->getAlgorithms();
if (algorithms.size() < 1) {
m_jobRunner->reductionPaused();
return;
}
// Start processing
reductionResumed();
startBatch(std::move(algorithms));
}
void BatchPresenter::reductionResumed() {
// Notify child presenters
m_savePresenter->reductionResumed();
m_eventPresenter->reductionResumed();
......@@ -158,15 +182,20 @@ void BatchPresenter::reductionPaused() {
}
void BatchPresenter::resumeAutoreduction() {
// Update the model
m_jobRunner->autoreductionResumed();
// Get the algorithms to run
auto algorithms = m_jobRunner->getAlgorithms();
if (algorithms.size() < 1) {
m_jobRunner->autoreductionPaused();
return;
}
// Start processing
autoreductionResumed();
m_view->clearAlgorithmQueue();
m_view->setAlgorithmQueue(m_jobRunner->getAlgorithms());
m_view->executeAlgorithmQueue();
startBatch(std::move(algorithms));
}
void BatchPresenter::autoreductionResumed() {
// Update the model
m_jobRunner->autoreductionResumed();
// Notify child presenters
m_savePresenter->autoreductionResumed();
m_eventPresenter->autoreductionResumed();
......
......@@ -74,6 +74,8 @@ public:
void clearADSHandle() override;
private:
bool
startBatch(std::deque<MantidQt::API::IConfiguredAlgorithm_sptr> algorithms);
void resumeReduction();
void reductionResumed();
void pauseReduction();
......
......@@ -5,6 +5,7 @@
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "BatchView.h"
#include "../MainWindow/MainWindowView.h"
#include "GUI/Event/EventView.h"
#include "GUI/Runs/RunsView.h"
#include "GUI/Save/SaveView.h"
......@@ -22,8 +23,8 @@ namespace CustomInterfaces {
using API::BatchAlgorithmRunner;
using Mantid::API::IAlgorithm_sptr;
BatchView::BatchView(QWidget *parent)
: QWidget(parent), m_batchAlgoRunner(this) {
BatchView::BatchView(QWidget *parent, MainWindowView *mainView)
: QWidget(parent), m_batchAlgoRunner(this), m_mainView(mainView) {
qRegisterMetaType<API::IConfiguredAlgorithm_sptr>(
"MantidQt::API::IConfiguredAlgorithm_sptr");
initLayout();
......@@ -119,7 +120,7 @@ std::unique_ptr<RunsView> BatchView::createRunsTab() {
auto instruments = std::vector<std::string>(
{{"INTER", "SURF", "CRISP", "POLREF", "OFFSPEC"}});
return Mantid::Kernel::make_unique<RunsView>(
this, RunsTableViewFactory(instruments));
this, RunsTableViewFactory(instruments), this);
}
std::unique_ptr<EventView> BatchView::createEventTab() {
......@@ -134,5 +135,9 @@ IAlgorithm_sptr BatchView::createReductionAlg() {
std::unique_ptr<SaveView> BatchView::createSaveTab() {
return Mantid::Kernel::make_unique<SaveView>(this);
}
void BatchView::executePythonCode(const std::string &pythonCode) {
m_mainView->runPythonAlgorithm(pythonCode);
}
} // namespace CustomInterfaces
} // namespace MantidQt
......@@ -23,10 +23,12 @@
namespace MantidQt {
namespace CustomInterfaces {
class MainWindowView;
class BatchView : public QWidget, public IBatchView {
Q_OBJECT
public:
explicit BatchView(QWidget *parent = nullptr);
explicit BatchView(QWidget *parent, MainWindowView *mainView);
void subscribe(BatchViewSubscriber *notifyee) override;
IRunsView *runs() const override;
......@@ -39,6 +41,7 @@ public:
std::deque<MantidQt::API::IConfiguredAlgorithm_sptr> algorithms) override;
void executeAlgorithmQueue() override;
void cancelAlgorithmQueue() override;
void executePythonCode(const std::string &pythonCode);
private slots:
void onBatchComplete(bool error);
......@@ -64,6 +67,7 @@ private:
std::unique_ptr<ExperimentView> m_experiment;
std::unique_ptr<InstrumentView> m_instrument;
API::BatchAlgorithmRunner m_batchAlgoRunner;
MainWindowView *m_mainView;
};
} // namespace CustomInterfaces
} // namespace MantidQt
......
......@@ -4,6 +4,7 @@ set ( BATCH_SRC_FILES
BatchJobAlgorithm.cpp
BatchJobRunner.cpp
AlgorithmProperties.cpp
GroupProcessingAlgorithm.cpp
RowProcessingAlgorithm.cpp
)
......@@ -20,6 +21,7 @@ set ( BATCH_INC_FILES
BatchJobAlgorithm.h
BatchJobRunner.h
AlgorithmProperties.h
GroupProcessingAlgorithm.h
RowProcessingAlgorithm.h
)
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "GroupProcessingAlgorithm.h"
#include "../../Reduction/Batch.h"
#include "../../Reduction/Group.h"
#include "AlgorithmProperties.h"
#include "BatchJobAlgorithm.h"
#include "MantidAPI/AlgorithmManager.h"
#include "MantidQtWidgets/Common/BatchAlgorithmRunner.h"
namespace MantidQt {
namespace CustomInterfaces {
using API::IConfiguredAlgorithm_sptr;
using AlgorithmRuntimeProps = std::map<std::string, std::string>;
namespace { // unnamed namespace
std::string removePrefix(std::string const &value, std::string const &prefix) {
// Just return the original value if it doesn't contain the prefix
if (value.size() <= prefix.size() || value.substr(0, prefix.size()) != prefix)
return value;
return value.substr(prefix.size());
}
void updateWorkspaceProperties(AlgorithmRuntimeProps &properties,
Group const &group) {
// There must be more than workspace to stitch
if (group.rows().size() < 2)
throw std::runtime_error("Must have at least two workspaces for stitching");
// Get the list of input workspaces from the output of each row
auto workspaces = std::vector<std::string>();
std::transform(group.rows().cbegin(), group.rows().cend(),
std::back_inserter(workspaces),
[](boost::optional<Row> const &row) -> std::string {
return row->reducedWorkspaceNames().iVsQ();
});
AlgorithmProperties::update("InputWorkspaces", workspaces, properties);
// The stitched name is the row output names concatenated but without the
// individual IvsQ prefixes. Just add one IvsQ prefix at the start.
auto outputName = std::string("IvsQ");
auto const prefix = std::string("IvsQ_");
auto const separator = std::string("_");
for (auto const &workspace : workspaces) {
auto name = removePrefix(workspace, prefix);
outputName += separator + name;
}
AlgorithmProperties::update("OutputWorkspace", outputName, properties);
}
} // unnamed namespace
/** Create a configured algorithm for processing a group. The algorithm
* properties are set from the reduction configuration model.
* @param model : the reduction configuration model
* @param group : the row from the runs table
*/
IConfiguredAlgorithm_sptr createConfiguredAlgorithm(Batch const &model,
Group &group) {
// Create the algorithm
auto alg = Mantid::API::AlgorithmManager::Instance().create("Stitch1DMany");
alg->setRethrows(true);
// Set the algorithm properties from the model
auto properties = createAlgorithmRuntimeProps(model, group);
// Store expected output property name
std::vector<std::string> outputWorkspaceProperties = {"OutputWorkspace"};
// Return the configured algorithm
auto jobAlgorithm = boost::make_shared<BatchJobAlgorithm>(
alg, properties, outputWorkspaceProperties, &group);
return jobAlgorithm;
}
AlgorithmRuntimeProps createAlgorithmRuntimeProps(Batch const &model,
Group const &group) {
auto properties = AlgorithmRuntimeProps();
updateWorkspaceProperties(properties, group);
AlgorithmProperties::updateFromMap(properties,
model.experiment().stitchParameters());
return properties;
}
} // namespace CustomInterfaces
} // namespace MantidQt
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#ifndef MANTID_CUSTOMINTERFACES_GROUPPROCESSINGALGORITHM_H_
#define MANTID_CUSTOMINTERFACES_GROUPPROCESSINGALGORITHM_H_
#include "Common/DllConfig.h"
#include "MantidQtWidgets/Common/BatchAlgorithmRunner.h"
#include <boost/optional.hpp>
#include <map>
#include <string>
#include <vector>
namespace MantidQt {
namespace CustomInterfaces {
class Batch;
class Group;
class IConfiguredAlgorithm;
using AlgorithmRuntimeProps = std::map<std::string, std::string>;
MANTIDQT_ISISREFLECTOMETRY_DLL MantidQt::API::IConfiguredAlgorithm_sptr
createConfiguredAlgorithm(Batch const &model, Group &group);
MANTIDQT_ISISREFLECTOMETRY_DLL AlgorithmRuntimeProps
createAlgorithmRuntimeProps(Batch const &model, Group const &group);
} // namespace CustomInterfaces
} // namespace MantidQt
#endif // MANTID_CUSTOMINTERFACES_GROUPPROCESSINGALGORITHM_H_
......@@ -34,7 +34,7 @@ MainWindowView::MainWindowView(QWidget *parent)
IBatchView *MainWindowView::newBatch() {
auto index = m_ui.mainTabs->count();
auto *newTab = new BatchView(this);
auto *newTab = new BatchView(this, this);
m_ui.mainTabs->addTab(newTab, QString("Batch ") + QString::number(index));
m_batchViews.emplace_back(newTab);
return newTab;
......
......@@ -5,6 +5,7 @@
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "RunsView.h"
#include "../Batch/BatchView.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidQtWidgets/Common/AlgorithmRunner.h"
#include "MantidQtWidgets/Common/FileDialogHandler.h"
......@@ -24,9 +25,11 @@ using namespace MantidQt::MantidWidgets;
* @param parent :: The parent of this view
* @param makeRunsTableView :: The factory for the RunsTableView.
*/
RunsView::RunsView(QWidget *parent, RunsTableViewFactory makeRunsTableView)
RunsView::RunsView(QWidget *parent, RunsTableViewFactory makeRunsTableView,
BatchView *batchView)
: MantidWidget(parent), m_notifyee(nullptr),
m_calculator(new SlitCalculator(this)), m_tableView(makeRunsTableView()) {
m_calculator(new SlitCalculator(this)),
m_tableView(makeRunsTableView(this)), m_batchView(batchView) {
initLayout();
}
void RunsView::loginFailed(std::string const &fullError) {
......@@ -420,5 +423,9 @@ void RunsView::setSelected(QComboBox &box, std::string const &str) {
if (index != -1)
box.setCurrentIndex(index);
}
void RunsView::executePythonCode(const std::string &pythonCode) {
m_batchView->executePythonCode(pythonCode);
}
} // namespace CustomInterfaces
} // namespace MantidQt
......@@ -35,6 +35,7 @@ namespace CustomInterfaces {
// Forward decs
class SearchModel;
class BatchView;
using MantidWidgets::SlitCalculator;
namespace DataProcessor = MantidWidgets::DataProcessor;
......@@ -47,7 +48,8 @@ class MANTIDQT_ISISREFLECTOMETRY_DLL RunsView
public IRunsView {
Q_OBJECT
public:
RunsView(QWidget *parent, RunsTableViewFactory makeView);
RunsView(QWidget *parent, RunsTableViewFactory makeView,
BatchView *batchView);
void subscribe(RunsViewSubscriber *notifyee) override;
IRunsTableView *table() const override;
......@@ -99,6 +101,8 @@ public:
void startMonitor() override;
void stopMonitor() override;
void executePythonCode(const std::string &pythonCode);
private:
/// initialise the interface
void initLayout();
......@@ -123,6 +127,7 @@ private:
QBasicTimer m_timer;
RunsTableView *m_tableView;
BatchView *m_batchView;
private slots:
void on_actionSearch_triggered();
......
......@@ -5,6 +5,7 @@ set ( RUNS_TABLE_SRC_FILES
RunsTableView.cpp
IRunsTableView.h
RunsTableView.h
Plotter.cpp
)
# Include files aren't required, but this makes them appear in Visual Studio
......@@ -16,6 +17,7 @@ set ( RUNS_TABLE_INC_FILES
RegexRowFilter.h
RunsTablePresenter.h
RunsTablePresenterFactory.h
Plotter.h
)
set ( RUNS_TABLE_MOC_FILES
......
......@@ -26,6 +26,8 @@ public:
virtual void notifyInstrumentChanged() = 0;
virtual void notifyExpandAllRequested() = 0;
virtual void notifyCollapseAllRequested() = 0;
virtual void notifyPlotSelectedPressed() = 0;
virtual void notifyPlotSelectedStitchedOutputPressed() = 0;
virtual ~RunsTableViewSubscriber() = default;
};
......@@ -50,7 +52,9 @@ public:
Paste,
Cut,
Expand,
Collapse
Collapse,
PlotSelected,
PlotSelectedStitchedOutput
};
virtual void subscribe(RunsTableViewSubscriber *notifyee) = 0;
......
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright &copy; 2019 ISIS Rutherford Appleton Laboratory UKRI,
// NScD Oak Ridge National Laboratory, European Spallation Source
// & Institut Laue - Langevin
// SPDX - License - Identifier: GPL - 3.0 +
#include "Plotter.h"
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
#include "RunsTableView.h"
#endif
namespace MantidQt {
namespace CustomInterfaces {
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
Plotter::Plotter(RunsTableView *runsTableView)