#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