Newer
Older
#include "MantidQtWidgets/Common/MuonFitPropertyBrowser.h"
#include "MantidAPI/FunctionFactory.h"
#include "MantidAPI/ITableWorkspace.h"
#include "MantidAPI/TableRow.h"
#include "MantidAPI/WorkspaceFactory.h"
#include "MantidAPI/WorkspaceGroup.h"
#include "MantidKernel/VectorHelper.h"
#include "MantidQtWidgets/Common/PropertyHandler.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h"
#include "MantidAPI/MultiDomainFunction.h"
#include "MantidQtWidgets/Common/MuonFitDataSelector.h"
// Suppress a warning coming out of code that isn't ours
#if defined(__INTEL_COMPILER)
#pragma warning disable 1125
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic push
#endif
#pragma GCC diagnostic ignored "-Woverloaded-virtual"
#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
#if defined(__INTEL_COMPILER)
#pragma warning enable 1125
#if (__GNUC__ >= 4 && __GNUC_MINOR__ >= 6)
#pragma GCC diagnostic pop
#endif
#endif
#include "MantidAPI/AlgorithmManager.h"
#include "MantidAPI/CompositeFunction.h"
#include "MantidAPI/Expression.h"
#include "MantidAPI/IBackgroundFunction.h"
#include "MantidAPI/IPeakFunction.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/qtpropertymanager.h"
#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
#include <QAction>
#include <QPushButton>
#include <QSignalMapper>
#include <QTableWidgetItem>
namespace {
Mantid::Kernel::Logger g_log("MuonFitPropertyBrowser");
const QString CUSTOM_LABEL{"Custom"};
const QString ALL_GROUPS_LABEL{"All Groups"};
const QString ALL_PAIRS_LABEL{"All Pairs"};
const QString ALL_PERIODS_LABEL{"All Periods"};
const std::string UNNORM = "_unNorm";
namespace MantidQt {
namespace MantidWidgets {
using namespace Mantid::API;
const std::string MuonFitPropertyBrowser::SIMULTANEOUS_PREFIX{"MuonSimulFit_"};
/**
* Constructor
* @param parent :: The parent widget - must be an ApplicationWindow
* @param mantidui :: The UI form for MantidPlot
MuonFitPropertyBrowser::MuonFitPropertyBrowser(QWidget *parent,
QObject *mantidui)
: FitPropertyBrowser(parent, mantidui), m_widgetSplitter(nullptr),
m_mainSplitter(nullptr), m_isMultiFittingMode(false) {}
* Initialise the muon fit property browser.
*/
void MuonFitPropertyBrowser::init() {
QWidget *w = new QWidget(this);
QSettings settings;
settings.beginGroup("Mantid/FitBrowser");
/* Create function group */
QtProperty *functionsGroup = m_groupManager->addProperty("Functions");
QtProperty *settingsGroup(nullptr);
// Seperates the data and the settings into two seperate categories
settingsGroup = m_groupManager->addProperty("Data");
QSettings multiFitSettings;
multiFitSettings.beginGroup("");
/* Create function group */
QtProperty *multiFitSettingsGroup(nullptr);
// Seperates the data and the settings into two seperate categories
multiFitSettingsGroup = m_groupManager->addProperty("Data");
// Have slightly different names as requested by the muon scientists.
m_startX =
addDoubleProperty(QString("Start (%1s)").arg(QChar(0x03BC))); //(mu);
m_endX = addDoubleProperty(QString("End (%1s)").arg(QChar(0x03BC)));
m_normalization = m_enumManager->addProperty("Normalization");
setNormalization();
m_keepNorm = m_boolManager->addProperty("Fix Normalization");
bool keepNorm = settings.value("Fix Normalization", QVariant(false)).toBool();
m_boolManager->setValue(m_keepNorm, keepNorm);
m_workspace = m_enumManager->addProperty("Workspace");
m_workspaceIndex = m_intManager->addProperty("Workspace Index");
m_output = m_stringManager->addProperty("Output");
m_minimizer = m_enumManager->addProperty("Minimizer");
m_minimizers << "Levenberg-Marquardt"
<< "Simplex"
<< "Conjugate gradient (Fletcher-Reeves imp.)"
<< "Conjugate gradient (Polak-Ribiere imp.)"
<< "BFGS";
m_enumManager->setEnumNames(m_minimizer, m_minimizers);
m_costFunction = m_enumManager->addProperty("Cost function");
m_costFunctions << "Least squares"
<< "Ignore positive peaks";
m_enumManager->setEnumNames(m_costFunction, m_costFunctions);
m_plotDiff = m_boolManager->addProperty("Plot Difference");
bool plotDiff = settings.value("Plot Difference", QVariant(true)).toBool();
m_boolManager->setValue(m_plotDiff, plotDiff);
m_evaluationType = m_enumManager->addProperty("Evaluate Function As");
m_evaluationType->setToolTip(
"Consider using Histogram fit which may produce more accurate results.");
m_evaluationTypes << "CentrePoint"
<< "Histogram";
m_enumManager->setEnumNames(m_evaluationType, m_evaluationTypes);
int evaluationType =
settings.value(m_evaluationType->propertyName(), 0).toInt();
m_enumManager->setValue(m_evaluationType, evaluationType);
settingsGroup->addSubProperty(m_workspace);
settingsGroup->addSubProperty(m_workspaceIndex);
settingsGroup->addSubProperty(m_startX);
settingsGroup->addSubProperty(m_normalization);
settingsGroup->addSubProperty(m_keepNorm);
// Disable "Browse" button - use case is that first run will always be the one
// selected on front tab. User will type in the runs they want rather than
// using the Browse button. (If they want to "Browse" they can use front tab).
multiFitSettingsGroup->addSubProperty(m_startX);
multiFitSettingsGroup->addSubProperty(m_endX);
m_groupsToFit = m_enumManager->addProperty("Groups/Pairs to fit");
m_groupsToFitOptions << ALL_GROUPS_LABEL << ALL_PAIRS_LABEL << CUSTOM_LABEL;
m_showGroupValue << "groups";
m_showGroup = m_enumManager->addProperty("Selected Groups");
m_enumManager->setEnumNames(m_groupsToFit, m_groupsToFitOptions);
multiFitSettingsGroup->addSubProperty(m_groupsToFit);
multiFitSettingsGroup->addSubProperty(m_showGroup);
m_enumManager->setEnumNames(m_showGroup, m_showGroupValue);
m_enumManager->setValue(m_groupsToFit, 2);
clearChosenGroups();
addGroupCheckbox(tmp);
tmp = "bwd";
addGroupCheckbox(tmp);
m_periodsToFit = m_enumManager->addProperty("Periods to fit");
m_periodsToFitOptions << ALL_PERIODS_LABEL << CUSTOM_LABEL << "1"
<< "2";
m_showPeriodValue << "1";
m_showPeriods = m_enumManager->addProperty("Selected Periods");
m_enumManager->setEnumNames(m_periodsToFit, m_periodsToFitOptions);
multiFitSettingsGroup->addSubProperty(m_periodsToFit);
multiFitSettingsGroup->addSubProperty(m_showPeriods);
m_enumManager->setEnumNames(m_showPeriods, m_showPeriodValue);
multiFitSettingsGroup->addSubProperty(m_normalization);
/* Create editors and assign them to the managers */
createEditors(w);
updateDecimals();
m_functionsGroup = m_browser->addProperty(functionsGroup);
m_settingsGroup = m_browser->addProperty(settingsGroup);
m_multiFitSettingsGroup = m_browser->addProperty(multiFitSettingsGroup);
connect(m_browser, SIGNAL(currentItemChanged(QtBrowserItem *)), this,
QHBoxLayout *btnLayout = new QHBoxLayout;
m_reselectGroupBtn = new QPushButton("Groups/Pairs");
m_reselectPeriodBtn = new QPushButton("Periods");
m_generateBtn = new QPushButton("Combine Periods");
m_groupWindow = new QDialog(this);
m_periodWindow = new QDialog(this);
m_comboWindow = new QDialog(this);
m_reselectGroupBtn->setEnabled(false);
m_reselectPeriodBtn->setEnabled(false);
connect(m_reselectGroupBtn, SIGNAL(released()), this,
SLOT(groupBtnPressed()));
connect(m_reselectPeriodBtn, SIGNAL(released()), this,
SLOT(periodBtnPressed()));
connect(m_generateBtn, SIGNAL(released()), this, SLOT(generateBtnPressed()));
btnLayout->addWidget(m_reselectGroupBtn);
btnLayout->addWidget(m_reselectPeriodBtn);
btnLayout->addWidget(m_generateBtn);
// Don't show "Function" or "Data" sections as they have separate widgets
m_browser->setItemVisible(m_functionsGroup, false);
m_browser->setItemVisible(m_settingsGroup, false);
m_browser->setItemVisible(m_multiFitSettingsGroup, true);
// Custom settings that are specific and asked for by the muon scientists.
QtProperty *customSettingsGroup = m_groupManager->addProperty("Settings");
m_rawData = m_boolManager->addProperty("Fit To Raw Data");
bool data = settings.value("Fit To Raw Data", QVariant(false)).toBool();
m_boolManager->setValue(m_rawData, data);
m_showParamErrors = m_boolManager->addProperty("Show Parameter Errors");
// XXX: showParamErrors is true by default for Muons
bool showParamErrors =
settings.value(m_showParamErrors->propertyName(), true).toBool();
m_boolManager->setValue(m_showParamErrors, showParamErrors);
m_parameterManager->setErrorsEnabled(showParamErrors);
m_TFAsymmMode = m_boolManager->addProperty("TF Asymmetry Mode");
bool TFAsymmMode =
settings.value("TF Asymmetry Mode", QVariant(false)).toBool();
m_boolManager->setValue(m_TFAsymmMode, TFAsymmMode);
customSettingsGroup->addSubProperty(m_minimizer);
customSettingsGroup->addSubProperty(m_TFAsymmMode);
customSettingsGroup->addSubProperty(m_plotDiff);
customSettingsGroup->addSubProperty(m_rawData);
customSettingsGroup->addSubProperty(m_showParamErrors);
customSettingsGroup->addSubProperty(m_evaluationType);
m_customSettingsGroup = m_browser->addProperty(customSettingsGroup);
// Initialise the layout.
// Create an empty splitter that can hold extra widgets
m_widgetSplitter = new QSplitter(Qt::Vertical, w);
m_widgetSplitter->setSizePolicy(QSizePolicy::Policy::Expanding,
QSizePolicy::Policy::Expanding);
// This splitter separates the "extra widgets" region from the browser
m_mainSplitter = new QSplitter(Qt::Vertical, w);
m_mainSplitter->insertWidget(0, m_widgetSplitter);
m_mainSplitter->insertWidget(1, m_browser);
m_mainSplitter->setStretchFactor(0, 1);
m_mainSplitter->setStretchFactor(1, 0);
// Insert after the buttons
auto parentLayout = qobject_cast<QVBoxLayout *>(w->layout());
if (parentLayout) {
const int index = parentLayout->count() - 1;
constexpr int stretchFactor = 10; // so these widgets get any extra space
parentLayout->insertWidget(index, m_mainSplitter, stretchFactor);
parentLayout->setSpacing(0);
parentLayout->setMargin(0);
parentLayout->setContentsMargins(0, 0, 0, 0);
parentLayout->insertWidget(index + 1, m_btnGroup);
// Update tooltips when function structure is (or might've been) changed in
// any way
connect(this, SIGNAL(functionChanged()), SLOT(updateStructureTooltips()));
setTFAsymmMode(TFAsymmMode);
m_autoBackground = getAutoBackgroundString();
void MuonFitPropertyBrowser::executeFitMenu(const QString &item) {
if (item == "Fit" && m_boolManager->value(m_TFAsymmMode)) {
} else {
FitPropertyBrowser::executeFitMenu(item);
}
// Create group/pair selection pop up
void MuonFitPropertyBrowser::groupBtnPressed() { genGroupWindow(); }
void MuonFitPropertyBrowser::periodBtnPressed() { genPeriodWindow(); }
void MuonFitPropertyBrowser::generateBtnPressed() { genCombinePeriodWindow(); }
/// Enable/disable the Fit button;
void MuonFitPropertyBrowser::setFitEnabled(bool yes) {
m_fitActionFit->setEnabled(yes);
m_fitActionSeqFit->setEnabled(yes);
void MuonFitPropertyBrowser::checkFitEnabled() {
if (count() == 0) {
setFitEnabled(false);
} else {
setFitEnabled(true);
}
void MuonFitPropertyBrowser::setWorkspaceName(const QString &wsName) {
int i = m_workspaceNames.indexOf(wsName);
if (i < 0) {
// workspace may not be found because add notification hasn't been processed
// yet
populateWorkspaceNames();
i = m_workspaceNames.indexOf(wsName);
}
if (i >= 0)
m_enumManager->setValue(m_workspace, i);
* @param prop :: A pointer to the function name property
*/
void MuonFitPropertyBrowser::enumChanged(QtProperty *prop) {
if (m_workspaceNames.empty()) {
if (this->isVisible()) {
g_log.error("No Data available. Please load Some data.");
}
if (!m_changeSlotsEnabled)
return;
if (prop == m_groupsToFit) {
int j = m_enumManager->value(m_groupsToFit);
QString option = m_groupsToFitOptions[j];
if (option == ALL_GROUPS_LABEL) {
setAllGroups();
m_reselectGroupBtn->setEnabled(false);
} else if (option == ALL_PAIRS_LABEL) {
setAllPairs();
m_reselectGroupBtn->setEnabled(false);
} else if (option == CUSTOM_LABEL) {
m_reselectGroupBtn->setEnabled(true);
genGroupWindow();
}
updateGroupDisplay();
} else if (prop == m_periodsToFit) {
int j = m_enumManager->value(m_periodsToFit);
QString option = m_periodsToFitOptions[j];
if (option == CUSTOM_LABEL) {
m_reselectPeriodBtn->setEnabled(true);
genPeriodWindow();
} else if (option == ALL_PERIODS_LABEL) {
setAllPeriods();
m_reselectPeriodBtn->setEnabled(false);
} else {
for (auto iter = m_periodBoxes.constBegin();
iter != m_periodBoxes.constEnd(); ++iter) {
m_boolManager->setValue(iter.value(), true);
} else {
m_boolManager->setValue(iter.value(), false);
}
m_reselectPeriodBtn->setEnabled(false);
}
}
updatePeriodDisplay();
} else if (prop == m_workspace) {
int j = m_enumManager->value(m_workspace);
std::string option = m_workspaceNames[j].toStdString();
// update plot
emit workspaceNameChanged(QString::fromStdString(option));
// only do this if in single fit mode
if (m_periodBoxes.size() > 1 &&
!m_browser->isItemVisible(m_multiFitSettingsGroup)) {
size_t end = 0;
// assumed structure of name
// isolate the period
for (int k = 0; k < 4; k++) {
end = option.find_first_of(";");
option = option.substr(end + 1, option.size());
}
end = option.find_first_of(";");
QString selectedPeriod = QString::fromStdString(option.substr(0, end));
// turn on only the relevant box
for (auto iter = m_periodBoxes.constBegin();
iter != m_periodBoxes.constEnd(); ++iter) {
m_boolManager->setValue(iter.value(), selectedPeriod == iter.key());
}
}
if (!m_browser->isItemVisible(m_multiFitSettingsGroup)) {
size_t end = 0;
// assumed structure of name
// isolate the group/pair
for (int k = 0; k < 2; k++) {
end = option.find_first_of(";");
option = option.substr(end + 1, option.size());
}
end = option.find_first_of(";");
boost::erase_all(option, " ");
auto tmp = option.substr(0, end - 1);
QString selectedGroup = QString::fromStdString(tmp);
// turn on only the relevant box
for (auto iter = m_groupBoxes.constBegin();
iter != m_groupBoxes.constEnd(); ++iter) {
m_boolManager->setValue(iter.value(), selectedGroup == iter.key());
}
}
// update plot for TF Asymm mode
updateTFPlot();
void MuonFitPropertyBrowser::updateGroupDisplay() {
m_showGroupValue.clear();
m_showGroupValue << getChosenGroups().join(",");
m_enumManager->setEnumNames(m_showGroup, m_showGroupValue);
m_multiFitSettingsGroup->property()->addSubProperty(m_showGroup);
void MuonFitPropertyBrowser::updatePeriodDisplay() {
m_showPeriodValue.clear();
auto tmp = getChosenPeriods();
tmp.replaceInStrings(QRegExp(","), "+");
m_showPeriodValue << tmp.join(",");
m_enumManager->setEnumNames(m_showPeriods, m_showPeriodValue);
if (m_periodsToFitOptions.size() > 1) {
m_multiFitSettingsGroup->property()->addSubProperty(m_showPeriods);
}
/** Called when a double property changed
* @param prop :: A pointer to the property
void MuonFitPropertyBrowser::doubleChanged(QtProperty *prop) {
if (!m_changeSlotsEnabled)
return;
double value = m_doubleManager->value(prop);
if (prop == m_startX) {
// call setWorkspace to change maxX in functions
setWorkspace(m_compositeFunction);
getHandler()->setAttribute(QString("Start (%1s)").arg(QChar(0x03BC)),
value); // (mu)
emit startXChanged(startX());
emit xRangeChanged(startX(), endX());
return;
} else if (prop == m_endX) {
// call setWorkspace to change minX in functions
setWorkspace(m_compositeFunction);
getHandler()->setAttribute(QString("End (%1s)").arg(QChar(0x03BC)), value);
emit endXChanged(endX());
emit xRangeChanged(startX(), endX());
return;
MantidQt::MantidWidgets::PropertyHandler *h =
getHandler()->findHandler(prop);
if (!h)
return;
QtProperty *parProp = h->getParameterProperty(prop);
if (parProp) {
if (prop->propertyName() == "LowerBound") {
double loBound = m_doubleManager->value(prop);
h->addConstraint(parProp, true, false, loBound, 0);
} else if (prop->propertyName() == "UpperBound") {
double upBound = m_doubleManager->value(prop);
h->addConstraint(parProp, false, true, 0, upBound);
} else { // it could be an attribute
h->setAttribute(prop);
}
}
}
void MuonFitPropertyBrowser::setNormalization() {
setNormalization(workspaceName());
}
/**
* @param name :: the ws name to get normalization for
* @returns the normalization
*/
void MuonFitPropertyBrowser::setNormalization(const std::string name) {
QString label;
auto norms = readMultipleNormalization();
std::string tmp = name;
// stored with ; instead of spaces
std::replace(tmp.begin(), tmp.end(), ' ', ';');
auto it = norms.find(tmp);
if (it == norms.end()) {
label = QString::fromStdString("N/A");
} else {
label = QString::number(it->second);
}
m_normalizationValue.append(label);
m_enumManager->setEnumNames(m_normalization, m_normalizationValue);
/** Called when a bool property changed
* @param prop :: A pointer to the property
*/
void MuonFitPropertyBrowser::boolChanged(QtProperty *prop) {
if (prop == m_rawData) {
const bool val = m_boolManager->value(prop);
emit fitRawDataClicked(val);
if (prop == m_TFAsymmMode) {
if (prop == m_keepNorm) {
const bool val = m_boolManager->value(prop);
if (val) { // record data for later
double norm = 0.0;
int j = m_enumManager->value(m_workspace);
std::string name = m_workspaceNames[j].toStdString();
auto norms = readMultipleNormalization();
std::string tmp = name;
if (rawData()) {
tmp = tmp + "_Raw";
}
// stored with ; instead of spaces
std::replace(tmp.begin(), tmp.end(), ' ', ';');
auto it = norms.find(tmp);
if (it != norms.end()) {
norm = it->second;
}
ITableWorkspace_sptr table = WorkspaceFactory::Instance().createTable();
AnalysisDataService::Instance().addOrReplace("__keepNorm__", table);
table->addColumn("double", "norm");
table->addColumn("int", "spectra");
TableRow row = table->appendRow();
row << norm << 0;
} else { // remove data so it is not used later
AnalysisDataService::Instance().remove("__keepNorm__");
}
// search map for group/pair change
bool done = false;
for (auto iter = m_groupBoxes.constBegin(); iter != m_groupBoxes.constEnd();
++iter) {
if (iter.value() == prop) {
done = true;
updateGroupDisplay();
emit groupBoxClicked();
}
}
// search map for period change
if (done == false) {
for (auto iter = m_periodBoxes.constBegin();
iter != m_periodBoxes.constEnd(); ++iter) {
if (iter.value() == prop) {
done = true;
updatePeriodDisplay();
emit periodBoxClicked();
}
}
}
if (done == false) {
// defer to parent class
FitPropertyBrowser::boolChanged(prop);
}
void MuonFitPropertyBrowser::populateFunctionNames() {
const std::vector<std::string> names = FunctionFactory::Instance().getKeys();
m_registeredFunctions.clear();
m_registeredPeaks.clear();
m_registeredBackgrounds.clear();
for (size_t i = 0; i < names.size(); i++) {
std::string fnName = names[i];
QString qfnName = QString::fromStdString(fnName);
if (qfnName == "MultiBG")
continue;
auto f = FunctionFactory::Instance().createFunction(fnName);
const std::vector<std::string> categories = f->categories();
bool muon = false;
for (size_t j = 0; j < categories.size(); ++j) {
if ((categories[j] == "Muon") || (categories[j] == "General") ||
(categories[j] == "Background"))
m_registeredFunctions << qfnName;
}
IPeakFunction *pf = dynamic_cast<IPeakFunction *>(f.get());
// CompositeFunction* cf = dynamic_cast<CompositeFunction*>(f.get());
if (pf) {
m_registeredPeaks << qfnName;
} else if (dynamic_cast<IBackgroundFunction *>(f.get())) {
m_registeredBackgrounds << qfnName;
m_registeredOther << qfnName;
}
}
}
std::string MuonFitPropertyBrowser::getUnnormName(std::string wsName) {
if (wsName.find(UNNORM) == std::string::npos) {
auto raw = wsName.find("_Raw");
if (raw == std::string::npos) {
wsName += TFExtension();
} else {
wsName.insert(raw, UNNORM);
}
}
if (rawData() && wsName.find("_Raw") == std::string::npos) {
wsName += "_Raw";
}
return wsName;
* Creates an instance of Fit algorithm, sets its properties and launches it.
*/
void MuonFitPropertyBrowser::doTFAsymmFit() {
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
std::string wsName = workspaceName();
wsName = getUnnormName(wsName);
if (wsName.empty()) {
QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
return;
}
try {
m_initialParameters.resize(compositeFunction()->nParams());
for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
m_initialParameters[i] = compositeFunction()->getParameter(i);
}
m_fitActionUndoFit->setEnabled(true);
// Delete any existing results for this workspace, UNLESS we are doing a
// simultaneous fit
if (m_workspacesToFit.size() < 2) {
if (AnalysisDataService::Instance().doesExist(
wsName + "_NormalisedCovarianceMatrix")) {
FrameworkManager::Instance().deleteWorkspace(
wsName + "_NormalisedCovarianceMatrix");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Parameters")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Parameters");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Workspace")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Workspace");
}
}
IAlgorithm_sptr alg =
AlgorithmManager::Instance().create("CalculateMuonAsymmetry");
alg->initialize();
auto fa = m_compositeFunction->asString();
if (m_compositeFunction->nFunctions() > 1) {
alg->setProperty("InputFunction",
boost::dynamic_pointer_cast<IFunction>(
m_functionBrowser->getGlobalFunction()));
} else {
alg->setProperty("InputFunction",
boost::dynamic_pointer_cast<IFunction>(
m_compositeFunction->getFunction(0)));
}
auto unnorm = m_workspacesToFit;
std::string tmp = UNNORM;
bool raw = rawData();
std::for_each(unnorm.begin(), unnorm.end(),
[tmp, raw](std::string &wsName) {
if (wsName.find(UNNORM) == std::string::npos) {
auto rawIndex = wsName.find("_Raw");
if (rawIndex == std::string::npos) {
wsName += UNNORM;
} else {
wsName.insert(rawIndex, UNNORM);
}
}
if (raw && wsName.find("_Raw") == std::string::npos) {
wsName += "_Raw";
}
});
alg->setProperty("UnNormalizedWorkspaceList", unnorm);
alg->setProperty("ReNormalizedWorkspaceList", m_workspacesToFit);
alg->setProperty("NormalizationTable", "MuonAnalysisTFNormalizations");
alg->setProperty("StartX", startX());
alg->setProperty("EndX", endX());
alg->setPropertyValue("Minimizer", minimizer());
// If we are doing a simultaneous fit, set this up here
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
std::string output = outputName();
if (nWorkspaces == 1) {
setSingleFitLabel(wsName);
output = getUnnormName(output);
}
alg->setPropertyValue("OutputFitWorkspace", output);
observeFinish(alg);
alg->execute();
} catch (const std::exception &e) {
QString msg = "CalculateMuonAsymmetry algorithm failed.\n\n" +
QString(e.what()) + "\n";
QMessageBox::critical(this, "Mantid - Error", msg);
}
/** Reads the normalization constants and which WS
* they belong to
* @returns :: A map of normalization constants and WS names
*/
std::map<std::string, double> readMultipleNormalization() {
std::map<std::string, double> norm;
if (AnalysisDataService::Instance().doesExist(
"MuonAnalysisTFNormalizations")) {
Mantid::API::ITableWorkspace_sptr table =
boost::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(
Mantid::API::AnalysisDataService::Instance().retrieve(
"MuonAnalysisTFNormalizations"));
auto colNorm = table->getColumn("norm");
auto colName = table->getColumn("name");
for (size_t j = 0; j < table->rowCount(); j++) {
norm[colName->cell<std::string>(j)] = ((*colNorm)[j]); // read norm
}
}
return norm;
* Requests checks and updates prior to running a fit
void MuonFitPropertyBrowser::fit() { emit preFitChecksRequested(false); }
/**
* Creates an instance of Fit algorithm, sets its properties and launches it.
*/
void MuonFitPropertyBrowser::runFit() {
std::string wsName = workspaceName();
if (wsName.empty()) {
QMessageBox::critical(this, "Mantid - Error", "Workspace name is not set");
m_initialParameters.resize(compositeFunction()->nParams());
for (size_t i = 0; i < compositeFunction()->nParams(); i++) {
m_initialParameters[i] = compositeFunction()->getParameter(i);
}
m_fitActionUndoFit->setEnabled(true);
// Delete any existing results for this workspace, UNLESS we are doing a
// simultaneous fit
if (m_workspacesToFit.size() < 2) {
if (AnalysisDataService::Instance().doesExist(
wsName + "_NormalisedCovarianceMatrix")) {
FrameworkManager::Instance().deleteWorkspace(
wsName + "_NormalisedCovarianceMatrix");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Parameters")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Parameters");
}
if (AnalysisDataService::Instance().doesExist(wsName + "_Workspace")) {
FrameworkManager::Instance().deleteWorkspace(wsName + "_Workspace");
}
IAlgorithm_sptr alg = AlgorithmManager::Instance().create("Fit");
alg->initialize();
if (m_compositeFunction->name() == "MultiBG") {
alg->setPropertyValue("Function", "");
} else if (m_compositeFunction->nFunctions() > 1) {
alg->setProperty("Function", boost::dynamic_pointer_cast<IFunction>(
m_compositeFunction));
} else {
alg->setProperty("Function", boost::dynamic_pointer_cast<IFunction>(
m_compositeFunction->getFunction(0)));
}
if (rawData())
alg->setPropertyValue("InputWorkspace", wsName + "_Raw");
else
alg->setPropertyValue("InputWorkspace", wsName);
alg->setProperty("WorkspaceIndex", workspaceIndex());
alg->setProperty("StartX", startX());
alg->setProperty("EndX", endX());
alg->setPropertyValue("Minimizer", minimizer());
alg->setPropertyValue("CostFunction", costFunction());
// If we are doing a simultaneous fit, set this up here
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
alg->setPropertyValue("InputWorkspace", m_workspacesToFit[0]);
for (int i = 1; i < nWorkspaces; i++) {
std::string suffix = boost::lexical_cast<std::string>(i);
alg->setPropertyValue("InputWorkspace_" + suffix, m_workspacesToFit[i]);
alg->setProperty("WorkspaceIndex_" + suffix, workspaceIndex());
alg->setProperty("StartX_" + suffix, startX());
alg->setProperty("EndX_" + suffix, endX());
}
observeFinish(alg);
alg->executeAsync();
} catch (const std::exception &e) {
QString msg = "Fit algorithm failed.\n\n" + QString(e.what()) + "\n";
QMessageBox::critical(this, "Mantid - Error", msg);
/**
* Show sequential fit dialog.
*/
void MuonFitPropertyBrowser::runSequentialFit() {
emit sequentialFitRequested();
}
/**
* Requests checks and updates prior to running a sequential fit
*/
void MuonFitPropertyBrowser::sequentialFit() {
emit preFitChecksRequested(true);
* Connect to the AnalysisDataService when shown
void MuonFitPropertyBrowser::showEvent(QShowEvent *e) {
(void)e;
observePostDelete();
populateWorkspaceNames();
}
/** Check if the workspace can be used in the fit. The accepted types are
* MatrixWorkspaces same size and that it isn't the generated raw file.
* @param ws :: The workspace
*/
bool MuonFitPropertyBrowser::isWorkspaceValid(Workspace_sptr ws) const {
QString workspaceName(QString::fromStdString(ws->getName()));
if ((workspaceName.contains("_Raw")) ||
(workspaceName.contains("MuonAnalysis")))
return false;
// Exclude fitting results
if (workspaceName.endsWith("_Workspace"))
return dynamic_cast<MatrixWorkspace *>(ws.get()) != nullptr;
}
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
void MuonFitPropertyBrowser::setFitWorkspaces(const std::string input) {
// Copy experiment info to output workspace
if (AnalysisDataService::Instance().doesExist(outputName() + "_Workspace")) {
// Input workspace should be a MatrixWorkspace according to isWorkspaceValid
auto inWs =
AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(input);
auto outWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
outputName() + "_Workspace");
if (inWs && outWs) {
outWs->copyExperimentInfoFrom(inWs.get());
}
} else if (AnalysisDataService::Instance().doesExist(outputName() +
"_Workspaces")) {
// Output workspace was a group
auto outGroup = AnalysisDataService::Instance().retrieveWS<WorkspaceGroup>(
outputName() + "_Workspaces");
if (outGroup->size() == m_workspacesToFit.size()) {
for (size_t i = 0; i < outGroup->size(); i++) {
auto outWs =
boost::dynamic_pointer_cast<MatrixWorkspace>(outGroup->getItem(i));
auto inWs = AnalysisDataService::Instance().retrieveWS<MatrixWorkspace>(
m_workspacesToFit[i]);
if (inWs && outWs) {
outWs->copyExperimentInfoFrom(inWs.get());
}
}
}
}
void MuonFitPropertyBrowser::finishHandle(const IAlgorithm *alg) {
if (alg->name() == "CalculateMuonAsymmetry") {
finishHandleTF(alg);
} else {
finishHandleNormal(alg);
}
}
void MuonFitPropertyBrowser::finishHandleTF(const IAlgorithm *alg) {
setFitWorkspaces(
static_cast<std::string>(alg->getProperty("UnNormalizedWorkspaceList")));
auto status = QString::fromStdString(alg->getPropertyValue("OutputStatus"));
emit fitResultsChanged(status);
FitPropertyBrowser::fitResultsChanged(status);
// If fit was simultaneous, insert extra information into params table
// and group the output workspaces
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
std::string baseName = outputName();
finishAfterTFSimultaneousFit(alg, baseName);
getFitResults();
std::vector<std::string> wsList =
alg->getProperty("UnNormalizedWorkspaceList");
emit fittingDone(QString::fromStdString(wsList[0]));
double quality = alg->getProperty("ChiSquared");
//std::string costFunction =
emit changeWindowTitle(QString("Fit Function (") +
"Chi-sq " + " = " +
QString::number(quality) + ", " + status + ")");
emit algorithmFinished(QString::fromStdString(wsList[0] + "_workspace"));
}
}
void MuonFitPropertyBrowser::finishHandleNormal(const IAlgorithm *alg) {
// Copy experiment info to output workspace
setFitWorkspaces(
static_cast<std::string>(alg->getProperty("InputWorkspace")));
// If fit was simultaneous, insert extra information into params table
const int nWorkspaces = static_cast<int>(m_workspacesToFit.size());
if (nWorkspaces > 1) {
finishAfterSimultaneousFit(alg, nWorkspaces);
FitPropertyBrowser::finishHandle(alg);
}
/**
* After a simultaneous fit, insert extra information into parameters table
* (i.e. what runs, groups, periods "f0", "f1" etc were)
* @param fitAlg :: [input] Pointer to fit algorithm that just finished
* @param nWorkspaces :: [input] Number of workspaces that were fitted
*/
void MuonFitPropertyBrowser::finishAfterSimultaneousFit(
const Mantid::API::IAlgorithm *fitAlg, const int nWorkspaces) const {
AnalysisDataServiceImpl &ads = AnalysisDataService::Instance();
try {
const std::string paramTableName = fitAlg->getProperty("OutputParameters");
const auto paramTable = ads.retrieveWS<ITableWorkspace>(paramTableName);
if (paramTable) {
Mantid::API::TableRow f0Row = paramTable->appendRow();
f0Row << "f0=" + fitAlg->getPropertyValue("InputWorkspace") << 0.0 << 0.0;
for (int i = 1; i < nWorkspaces; i++) {
const std::string suffix = boost::lexical_cast<std::string>(i);
const auto wsName =
fitAlg->getPropertyValue("InputWorkspace_" + suffix);
Mantid::API::TableRow row = paramTable->appendRow();
row << "f" + suffix + "=" + wsName << 0.0 << 0.0;
}
}
} catch (const Mantid::Kernel::Exception::NotFoundError &) {
// Not a fatal error, but shouldn't happen
g_log.warning(
"Could not find output parameters table for simultaneous fit");
}