-
Elliot Oram authored
Refs #14090
Elliot Oram authoredRefs #14090
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
ContainerSubtraction.cpp 11.10 KiB
#include "MantidQtCustomInterfaces/Indirect/ContainerSubtraction.h"
#include "MantidQtCustomInterfaces/UserInputValidator.h"
using namespace Mantid::API;
namespace {
Mantid::Kernel::Logger g_log("ContainerSubtraction");
}
namespace MantidQt {
namespace CustomInterfaces {
ContainerSubtraction::ContainerSubtraction(QWidget *parent)
: CorrectionsTab(parent) {
m_uiForm.setupUi(parent);
// Connect slots
connect(m_uiForm.dsSample, SIGNAL(dataReady(const QString &)), this,
SLOT(newData(const QString &)));
connect(m_uiForm.spPreviewSpec, SIGNAL(valueChanged(int)), this,
SLOT(plotPreview(int)));
m_uiForm.spPreviewSpec->setMinimum(0);
m_uiForm.spPreviewSpec->setMaximum(0);
}
void ContainerSubtraction::setup() {}
void ContainerSubtraction::run() {
API::BatchAlgorithmRunner::AlgorithmRuntimeProps absCorProps;
IAlgorithm_sptr applyCorrAlg =
AlgorithmManager::Instance().create("ApplyPaalmanPingsCorrection");
applyCorrAlg->initialize();
QString sampleWsName = m_uiForm.dsSample->getCurrentDataName();
MatrixWorkspace_sptr sampleWs =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
sampleWsName.toStdString());
m_originalSampleUnits = sampleWs->getAxis(0)->unit()->unitID();
// If not in wavelength then do conversion
if (m_originalSampleUnits != "Wavelength") {
g_log.information(
"Sample workspace not in wavelength, need to convert to continue.");
absCorProps["SampleWorkspace"] =
addConvertUnitsStep(sampleWs, "Wavelength");
} else {
absCorProps["SampleWorkspace"] = sampleWsName.toStdString();
}
QString canWsName = m_uiForm.dsContainer->getCurrentDataName();
MatrixWorkspace_sptr canWs =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
canWsName.toStdString());
QString canCloneName = canWsName + "_Shifted";
IAlgorithm_sptr clone = AlgorithmManager::Instance().create("CloneWorkspace");
clone->initialize();
clone->setProperty("InputWorkspace", canWs);
clone->setProperty("Outputworkspace", canCloneName.toStdString());
clone->execute();
MatrixWorkspace_sptr canCloneWs =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
canCloneName.toStdString());
if (m_uiForm.ckShiftCan->isChecked()) {
IAlgorithm_sptr scaleX = AlgorithmManager::Instance().create("ScaleX");
scaleX->initialize();
scaleX->setProperty("InputWorkspace", canCloneWs);
scaleX->setProperty("OutputWorkspace", canCloneName.toStdString());
scaleX->setProperty("Factor", m_uiForm.spShift->value());
scaleX->setProperty("Operation", "Add");
scaleX->execute();
IAlgorithm_sptr rebin =
AlgorithmManager::Instance().create("RebinToWorkspace");
rebin->initialize();
rebin->setProperty("WorkspaceToRebin", canCloneWs);
rebin->setProperty("WorkspaceToMatch", sampleWs);
rebin->setProperty("OutputWorkspace", canCloneName.toStdString());
rebin->execute();
}
// If not in wavelength then do conversion
std::string originalCanUnits = canCloneWs->getAxis(0)->unit()->unitID();
if (originalCanUnits != "Wavelength") {
g_log.information("Container workspace not in wavelength, need to "
"convert to continue.");
absCorProps["CanWorkspace"] = addConvertUnitsStep(canCloneWs, "Wavelength");
} else {
absCorProps["CanWorkspace"] = canCloneName.toStdString();
}
bool useCanScale = m_uiForm.ckScaleCan->isChecked();
if (useCanScale) {
double canScaleFactor = m_uiForm.spCanScale->value();
applyCorrAlg->setProperty("CanScaleFactor", canScaleFactor);
}
// Check for same binning across sample and container
if (m_uiForm.ckShiftCan->isChecked()) {
addRebinStep(canCloneName, sampleWsName);
} else {
if (!checkWorkspaceBinningMatches(sampleWs, canCloneWs)) {
QString text =
"Binning on sample and container does not match."
"Would you like to rebin the sample to match the container?";
int result = QMessageBox::question(NULL, tr("Rebin sample?"), tr(text),
QMessageBox::Yes, QMessageBox::No,
QMessageBox::NoButton);
if (result == QMessageBox::Yes) {
addRebinStep(canCloneName, sampleWsName);
} else {
m_batchAlgoRunner->clearQueue();
g_log.error("Cannot apply absorption corrections using a sample and "
"container with different binning.");
return;
}
}
}
// Generate output workspace name
QString containerWsName = m_uiForm.dsContainer->getCurrentDataName();
int sampleNameCutIndex = sampleWsName.lastIndexOf("_");
if (sampleNameCutIndex == -1)
sampleNameCutIndex = sampleWsName.length();
int containerNameCutIndex = containerWsName.indexOf("_");
if (containerNameCutIndex == -1)
containerNameCutIndex = containerWsName.length();
const QString outputWsName = sampleWsName.left(sampleNameCutIndex) +
"_Subtract_" +
containerWsName.left(containerNameCutIndex);
applyCorrAlg->setProperty("OutputWorkspace", outputWsName.toStdString());
// Add corrections algorithm to queue
m_batchAlgoRunner->addAlgorithm(applyCorrAlg, absCorProps);
// Run algorithm queue
connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
SLOT(absCorComplete(bool)));
m_batchAlgoRunner->executeBatchAsync();
// Set the result workspace for Python script export
m_pythonExportWsName = outputWsName.toStdString();
}
/**
* Adds a rebin to workspace step to the calculation for when using a sample and
*container that
* have different binning.
*
* @param toRebin
* @param toMatch
*/
void ContainerSubtraction::addRebinStep(QString toRebin, QString toMatch) {
API::BatchAlgorithmRunner::AlgorithmRuntimeProps rebinProps;
rebinProps["WorkspaceToMatch"] = toMatch.toStdString();
IAlgorithm_sptr rebinAlg =
AlgorithmManager::Instance().create("RebinToWorkspace");
rebinAlg->initialize();
rebinAlg->setProperty("WorkspaceToRebin", toRebin.toStdString());
rebinAlg->setProperty("OutputWorkspace", toRebin.toStdString());
m_batchAlgoRunner->addAlgorithm(rebinAlg, rebinProps);
}
/**
* Validates the user input in the UI
* @return if the input was valid
*/
bool ContainerSubtraction::validate() {
UserInputValidator uiv;
uiv.checkDataSelectorIsValid("Sample", m_uiForm.dsSample);
uiv.checkDataSelectorIsValid("Container", m_uiForm.dsContainer);
MatrixWorkspace_sptr sampleWs;
QString sample = m_uiForm.dsSample->getCurrentDataName();
QString sampleType = sample.right(sample.length() - sample.lastIndexOf("_"));
QString container = m_uiForm.dsContainer->getCurrentDataName();
QString containerType =
container.right(sample.length() - container.lastIndexOf("_"));
g_log.debug() << "Sample type is: " << sampleType.toStdString() << std::endl;
g_log.debug() << "Container type is: " << containerType.toStdString()
<< std::endl;
if (containerType != sampleType)
uiv.addErrorMessage(
"Sample and can workspaces must contain the same type of data.");
// Show errors if there are any
if (!uiv.isAllInputValid())
emit showMessageBox(uiv.generateErrorMessage());
return uiv.isAllInputValid();
}
void ContainerSubtraction::loadSettings(const QSettings &settings) {
m_uiForm.dsContainer->readSettings(settings.group());
m_uiForm.dsSample->readSettings(settings.group());
}
/**
* Displays the sample data on the plot preview
* @param dataName Name of new data source
*/
void ContainerSubtraction::newData(const QString &dataName) {
const MatrixWorkspace_sptr sampleWs =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
dataName.toStdString());
m_uiForm.spPreviewSpec->setMaximum(
static_cast<int>(sampleWs->getNumberHistograms()) - 1);
// Plot the sample curve
m_uiForm.ppPreview->clear();
m_uiForm.ppPreview->addSpectrum("Sample", sampleWs, 0, Qt::black);
}
/**
* Replots the preview plot.
*
* @param specIndex Spectrum index to plot
*/
void ContainerSubtraction::plotPreview(int specIndex) {
m_uiForm.ppPreview->clear();
// Plot sample
m_uiForm.ppPreview->addSpectrum(
"Sample", m_uiForm.dsSample->getCurrentDataName(), specIndex, Qt::black);
// Plot result
if (!m_pythonExportWsName.empty())
m_uiForm.ppPreview->addSpectrum(
"Subtracted", QString::fromStdString(m_pythonExportWsName), specIndex,
Qt::green);
// Plot container
if (m_uiForm.ckShiftCan->isChecked()) {
m_uiForm.ppPreview->addSpectrum(
"Container", (m_uiForm.dsContainer->getCurrentDataName() + "_Shifted"),
specIndex, Qt::red);
} else {
m_uiForm.ppPreview->addSpectrum("Container",
m_uiForm.dsContainer->getCurrentDataName(),
specIndex, Qt::red);
}
}
void ContainerSubtraction::postProcessComplete(bool error) {
disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
SLOT(postProcessComplete(bool)));
if (error) {
emit showMessageBox("Unable to process corrected workspace.\nSee Results "
"Log for more details.");
return;
}
// Handle preview plot
plotPreview(m_uiForm.spPreviewSpec->value());
// Handle Mantid plotting
QString plotType = m_uiForm.cbPlotOutput->currentText();
if (plotType == "Spectra" || plotType == "Both")
plotSpectrum(QString::fromStdString(m_pythonExportWsName));
if (plotType == "Contour" || plotType == "Both")
plot2D(QString::fromStdString(m_pythonExportWsName));
}
/**
* Handles completion of the abs. correction algorithm.
*
* @param error True if algorithm failed.
*/
void ContainerSubtraction::absCorComplete(bool error) {
disconnect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
SLOT(absCorComplete(bool)));
if (error) {
emit showMessageBox(
"Unable to apply corrections.\nSee Results Log for more details.");
return;
}
// Convert back to original sample units
if (m_originalSampleUnits != "Wavelength") {
auto ws = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
m_pythonExportWsName);
std::string eMode("");
if (m_originalSampleUnits == "dSpacing")
eMode = "Elastic";
addConvertUnitsStep(ws, m_originalSampleUnits, "", eMode);
}
// Add save algorithms if required
bool save = m_uiForm.ckSave->isChecked();
if (save)
addSaveWorkspaceToQueue(QString::fromStdString(m_pythonExportWsName));
if (m_uiForm.ckShiftCan->isChecked()) {
IAlgorithm_sptr shiftLog =
AlgorithmManager::Instance().create("AddSampleLog");
shiftLog->initialize();
shiftLog->setProperty("Workspace", m_pythonExportWsName);
shiftLog->setProperty("LogName", "container_shift");
shiftLog->setProperty("LogType", "Number");
shiftLog->setProperty(
"LogText", boost::lexical_cast<std::string>(m_uiForm.spShift->value()));
m_batchAlgoRunner->addAlgorithm(shiftLog);
}
// Run algorithm queue
connect(m_batchAlgoRunner, SIGNAL(batchComplete(bool)), this,
SLOT(postProcessComplete(bool)));
m_batchAlgoRunner->executeBatchAsync();
}
} // namespace CustomInterfaces
} // namespace MantidQt