32#include "MantidQtWidgets/Common/QtPropertyBrowser/FilenameDialogEditor.h"
33#include "MantidQtWidgets/Common/QtPropertyBrowser/FormulaDialogEditor.h"
34#include "MantidQtWidgets/Common/QtPropertyBrowser/StringEditorFactory.h"
36#include "MantidQtWidgets/Common/QtPropertyBrowser/DoubleEditorFactory.h"
37#include "MantidQtWidgets/Common/QtPropertyBrowser/ParameterPropertyManager.h"
38#include "MantidQtWidgets/Common/QtPropertyBrowser/qteditorfactory.h"
39#include "MantidQtWidgets/Common/QtPropertyBrowser/qttreepropertybrowser.h"
41#include <Poco/ActiveResult.h>
43#include <QApplication>
46#include <QInputDialog>
52#include <QSignalMapper>
61using API::MantidDesktopServices;
63namespace MantidWidgets {
71 return static_cast<int>(
workspace->getNumberHistograms());
81 : QDockWidget(
"Fit Function", parent), m_workspaceIndex(nullptr), m_startX(nullptr), m_endX(nullptr),
82 m_output(nullptr), m_minimizer(nullptr), m_ignoreInvalidData(nullptr),
m_costFunction(nullptr),
83 m_maxIterations(nullptr), m_peakRadius(nullptr), m_plotDiff(nullptr), m_excludeRange(nullptr),
84 m_plotCompositeMembers(nullptr), m_convolveMembers(nullptr), m_rawData(nullptr), m_xColumn(nullptr),
85 m_yColumn(nullptr), m_errColumn(nullptr), m_showParamErrors(nullptr), m_evaluationType(nullptr),
86 m_compositeFunction(), m_browser(nullptr), m_fitActionUndoFit(nullptr), m_fitActionSeqFit(nullptr),
87 m_fitActionFit(nullptr), m_fitActionEvaluate(nullptr), m_functionsGroup(nullptr), m_settingsGroup(nullptr),
88 m_customSettingsGroup(nullptr), m_changeSlotsEnabled(false), m_guessOutputName(true),
89 m_updateObserver(*this, &
FitPropertyBrowser::handleFactoryUpdate), m_fitMapper(nullptr), m_fitMenu(nullptr),
90 m_displayActionPlotGuess(nullptr), m_displayActionQuality(nullptr), m_displayActionClearAll(nullptr),
91 m_setupActionCustomSetup(nullptr), m_setupActionRemove(nullptr), m_tip(nullptr), m_fitSelector(nullptr),
92 m_fitTree(nullptr), m_currentHandler(nullptr), m_defaultFunction(
"Gaussian"), m_defaultPeak(
"Gaussian"),
93 m_defaultBackground(
"LinearBackground"), m_peakToolOn(false), m_hideWsListWidget(false), m_auto_back(false),
95 QString::fromStdString(
Mantid::Kernel::
ConfigService::Instance().getString(
"curvefitting.autoBackground"))),
96 m_autoBackground(nullptr), m_decimals(-1), m_mantidui(mantidui), m_shouldBeNormalised(false),
97 m_fitAlgParameters(
""), m_oldWorkspaceIndex(-1) {
102 throw std::runtime_error(
"FitPropertyBrowser: Unable to find Gaussian function\n"
103 "Has the CurveFitting plugin loaded?");
122 setObjectName(
"FitFunction");
123 setMinimumHeight(150);
124 setMinimumWidth(200);
126 QWidget *w =
new QWidget(
this);
150 QWidget *w =
new QWidget(
this);
153 settings.beginGroup(
"Mantid/FitBrowser");
156 QtProperty *functionsGroup =
m_groupManager->addProperty(
"Functions");
162 QtProperty *settingsGroup =
m_groupManager->addProperty(
"Settings");
170 <<
"Levenberg-MarquardtMD"
174 <<
"Conjugate gradient (Fletcher-Reeves imp.)"
175 <<
"Conjugate gradient (Polak-Ribiere imp.)"
177 <<
"Damped GaussNewton";
186 <<
"Unweighted least squares"
196 bool plotDiff = settings.value(
"Plot Difference", QVariant(
true)).toBool();
200 m_excludeRange->setToolTip(
"A list of pairs of real numbers which define the region to exclude");
203 bool plotCompositeItems = settings.value(
m_plotCompositeMembers->propertyName(), QVariant(
false)).toBool();
207 bool convolveCompositeItems = settings.value(
m_plotCompositeMembers->propertyName(), QVariant(
false)).toBool();
211 bool showParamErrors = settings.value(
m_showParamErrors->propertyName(),
false).toBool();
216 m_evaluationType->setToolTip(
"Consider using Histogram fit which may produce more accurate results.");
220 int evaluationType = settings.value(
m_evaluationType->propertyName(), 0).toInt();
228 settingsGroup->addSubProperty(
m_startX);
229 settingsGroup->addSubProperty(
m_endX);
234 settingsGroup->addSubProperty(
m_output);
278 auto *btnFit =
new QPushButton(
"Fit");
279 m_tip =
new QLabel(
"", w);
310 connect(
m_fitActionFit, SIGNAL(triggered()), fitMapper, SLOT(map()));
318 fitMenu->addSeparator();
320 fitMenu->addSeparator();
333 btnFit->setObjectName(
"button_Fit");
335 connect(
this, SIGNAL(
changeWindowTitle(
const QString &)),
this, SLOT(setWindowTitle(
const QString &)));
353 auto *layout =
new QVBoxLayout(w);
354 layout->setObjectName(
"vlayout");
355 auto *buttonsLayout =
new QGridLayout();
357 auto *btnDisplay =
new QPushButton(
"Display");
358 btnDisplay->setObjectName(
"button_Display");
359 QMenu *displayMenu =
new QMenu(
this);
360 displayMenu->setObjectName(
"menu_Display");
368 QSignalMapper *displayMapper =
new QSignalMapper(
this);
369 displayMapper->setObjectName(
"mapper_Display");
377 connect(displayMapper, SIGNAL(mapped(
const QString &)),
this, SLOT(
executeDisplayMenu(
const QString &)));
381 btnDisplay->setMenu(displayMenu);
383 auto *btnSetup =
new QPushButton(
"Setup");
384 btnSetup->setObjectName(
"button_Setup");
385 QMenu *setupMenu =
new QMenu(
this);
386 setupMenu->setObjectName(
"menu_Setup");
389 QAction *setupActionManageSetup =
new QAction(
"Manage Setup",
this);
390 setupActionManageSetup->setObjectName(
"action_ManageSetup");
391 QAction *setupActionFindPeaks =
new QAction(
"Find Peaks",
this);
392 setupActionFindPeaks->setObjectName(
"action_FindPeaks");
393 QAction *setupActionClearFit =
new QAction(
"Clear Model",
this);
394 setupActionClearFit->setObjectName(
"action_ClearModel");
396 QMenu *setupSubMenuCustom =
new QMenu(
this);
401 QMenu *setupSubMenuManage =
new QMenu(
this);
402 QAction *setupActionSave =
new QAction(
"Save Setup",
this);
404 QAction *setupActionClear =
new QAction(
"Clear Setups",
this);
405 setupActionClear->setObjectName(
"action_ClearSetups");
406 QAction *setupActionCopyToClipboard =
new QAction(
"Copy To Clipboard",
this);
407 setupActionCopyToClipboard->setObjectName(
"action_CopyToClipboard");
408 QAction *setupActionLoadFromString =
new QAction(
"Load From String",
this);
409 setupActionLoadFromString->setObjectName(
"action_LoadFromString");
410 QSignalMapper *setupManageMapper =
new QSignalMapper(
this);
411 setupManageMapper->setMapping(setupActionSave,
"SaveSetup");
412 setupManageMapper->setMapping(setupActionCopyToClipboard,
"CopyToClipboard");
413 setupManageMapper->setMapping(setupActionLoadFromString,
"LoadFromString");
414 setupManageMapper->setMapping(setupActionClear,
"ClearSetups");
415 connect(setupActionSave, SIGNAL(triggered()), setupManageMapper, SLOT(map()));
416 connect(setupActionCopyToClipboard, SIGNAL(triggered()), setupManageMapper, SLOT(map()));
417 connect(setupActionLoadFromString, SIGNAL(triggered()), setupManageMapper, SLOT(map()));
418 connect(setupActionClear, SIGNAL(triggered()), setupManageMapper, SLOT(map()));
419 connect(setupManageMapper, SIGNAL(mapped(
const QString &)),
this, SLOT(
executeSetupManageMenu(
const QString &)));
420 setupSubMenuManage->addAction(setupActionSave);
422 setupSubMenuManage->addAction(setupActionClear);
423 setupSubMenuManage->addAction(setupActionCopyToClipboard);
424 setupSubMenuManage->addAction(setupActionLoadFromString);
425 setupActionManageSetup->setMenu(setupSubMenuManage);
427 QMenu *setupSubMenuRemove =
new QMenu(
this);
432 QSignalMapper *setupMapper =
new QSignalMapper(
this);
433 setupMapper->setMapping(setupActionClearFit,
"ClearFit");
434 setupMapper->setMapping(setupActionFindPeaks,
"FindPeaks");
435 connect(setupActionClearFit, SIGNAL(triggered()), setupMapper, SLOT(map()));
436 connect(setupActionFindPeaks, SIGNAL(triggered()), setupMapper, SLOT(map()));
437 connect(setupMapper, SIGNAL(mapped(
const QString &)),
this, SLOT(
executeSetupMenu(
const QString &)));
440 setupMenu->addAction(setupActionManageSetup);
441 setupMenu->addSeparator();
442 setupMenu->addAction(setupActionFindPeaks);
443 setupMenu->addSeparator();
444 setupMenu->addAction(setupActionClearFit);
445 btnSetup->setMenu(setupMenu);
449 buttonsLayout->addWidget(btnFit, 0, 0);
450 buttonsLayout->addWidget(btnDisplay, 0, 1);
451 buttonsLayout->addWidget(btnSetup, 0, 2);
453 m_status =
new QLabel(
"Status:", w);
456 Qt::QueuedConnection);
458 layout->addLayout(buttonsLayout);
459 layout->addWidget(
m_tip);
461 m_browser->setObjectName(
"tree_browser");
472 m_browser->setContextMenuPolicy(Qt::CustomContextMenu);
473 connect(
m_browser, SIGNAL(customContextMenuRequested(
const QPoint &)),
this, SLOT(
popupMenu(
const QPoint &)));
506 const std::vector<std::string> workspaceNames{outName +
"_NormalisedCovarianceMatrix", outName +
"_Parameters",
507 outName +
"_Workspace"};
509 for (
const auto &name : workspaceNames) {
511 auto foundInList =
m_wsListWidget->findItems(QString::fromStdString(name), Qt::MatchExactly);
513 new QListWidgetItem(QString::fromStdString(name),
m_wsListWidget);
527 auto wsName = item->text();
539 QtCheckBoxFactory *checkBoxFactory =
new QtCheckBoxFactory(w);
540 QtEnumEditorFactory *comboBoxFactory =
new QtEnumEditorFactory(w);
541 QtSpinBoxFactory *spinBoxFactory =
new QtSpinBoxFactory(w);
542 DoubleEditorFactory *doubleEditorFactory =
new DoubleEditorFactory(w);
543 StringEditorFactory *stringEditFactory =
new StringEditorFactory(w);
545 FormulaDialogEditorFactory *formulaDialogEditFactory =
new FormulaDialogEditorFactory(w);
570 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
571 QStringList names = settings.childKeys();
573 QSignalMapper *mapperLoad =
new QSignalMapper(
this);
574 QSignalMapper *mapperRemove =
new QSignalMapper(
this);
579 for (
int i = 0; i < names.size(); i++) {
580 QAction *itemLoad =
new QAction(names.at(i),
this);
581 QAction *itemRemove =
new QAction(names.at(i),
this);
582 mapperLoad->setMapping(itemLoad, names.at(i));
583 mapperRemove->setMapping(itemRemove, names.at(i));
584 connect(itemLoad, SIGNAL(triggered()), mapperLoad, SLOT(map()));
585 connect(itemRemove, SIGNAL(triggered()), mapperRemove, SLOT(map()));
586 menuLoad->addAction(itemLoad);
587 menuRemove->addAction(itemRemove);
589 connect(mapperLoad, SIGNAL(mapped(
const QString &)),
this, SLOT(
executeCustomSetupLoad(
const QString &)));
595 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
597 QString str = settings.value(name).toString();
603 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
605 settings.remove(name);
611 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
628 }
else if (item ==
"SeqFit") {
630 }
else if (item ==
"UndoFit") {
632 }
else if (item ==
"Evaluate") {
638 if (item ==
"PlotGuess") {
640 }
else if (item ==
"ClearAll") {
646 if (item ==
"ClearFit")
648 if (item ==
"FindPeaks")
653 if (item ==
"SaveSetup")
655 if (item ==
"ClearSetups")
657 if (item ==
"CopyToClipboard")
659 if (item ==
"LoadFromString")
708 QtBrowserItem *ci =
m_browser->currentItem();
723 QtBrowserItem *ci =
m_browser->currentItem();
728 if (function.isEmpty()) {
752 auto cf = std::dynamic_pointer_cast<Mantid::API::CompositeFunction>(func);
753 if (!cf || (cf->name() !=
"CompositeFunction" && cf->name() !=
"MultiBG" && cf->name() !=
"MultiDomainFunction")) {
795 }
catch (
const std::exception &ex) {
796 QMessageBox::critical(
this,
"Mantid - Error",
"Unexpected exception caught:\n\n" + QString(ex.what()));
802 QtBrowserItem *ci =
m_browser->currentItem();
805 QMenu *menu =
new QMenu(
this);
816 if (isFunctionsGroup) {
817 action =
new QAction(
"Add function",
this);
818 connect(action, SIGNAL(triggered()),
this, SLOT(
addFunction()));
819 menu->addAction(action);
823 action =
new QAction(
"Setup multifit",
this);
824 connect(action, SIGNAL(triggered()),
this, SLOT(
setupMultifit()));
825 menu->addAction(action);
830 action =
new QAction(
"Remove plot",
this);
831 connect(action, SIGNAL(triggered()),
this, SLOT(
removeGuessAll()));
832 menu->addAction(action);
834 action =
new QAction(
"Plot",
this);
835 connect(action, SIGNAL(triggered()),
this, SLOT(
plotGuessAll()));
836 menu->addAction(action);
840 menu->addSeparator();
842 action =
new QAction(
"Save",
this);
843 connect(action, SIGNAL(triggered()),
this, SLOT(
saveFunction()));
844 menu->addAction(action);
846 action =
new QAction(
"Load",
this);
847 connect(action, SIGNAL(triggered()),
this, SLOT(
loadFunction()));
848 menu->addAction(action);
850 action =
new QAction(
"Copy To Clipboard",
this);
851 connect(action, SIGNAL(triggered()),
this, SLOT(
copy()));
852 menu->addAction(action);
854 menu->addSeparator();
856 action =
new QAction(
"Help",
this);
857 connect(action, SIGNAL(triggered()),
this, SLOT(
browserHelp()));
858 menu->addAction(action);
859 }
else if (isSettingsGroup || isASetting) {
861 action =
new QAction(
"Fit",
this);
862 connect(action, SIGNAL(triggered()),
this, SLOT(
fit()));
863 menu->addAction(action);
867 action =
new QAction(
"Undo Fit",
this);
868 connect(action, SIGNAL(triggered()),
this, SLOT(
undoFit()));
869 menu->addAction(action);
872 action =
new QAction(
"Clear all",
this);
873 connect(action, SIGNAL(triggered()),
this, SLOT(
clear()));
874 menu->addAction(action);
876 action =
new QAction(
"Help",
this);
877 connect(action, SIGNAL(triggered()),
this, SLOT(
browserHelp()));
878 menu->addAction(action);
880 }
else if (isFunction) {
881 if (isCompositeFunction) {
882 action =
new QAction(
"Add function",
this);
883 connect(action, SIGNAL(triggered()),
this, SLOT(
addFunction()));
884 menu->addAction(action);
887 action =
new QAction(
"Remove",
this);
888 connect(action, SIGNAL(triggered()),
this, SLOT(
deleteFunction()));
889 menu->addAction(action);
893 action =
new QAction(
"Remove plot",
this);
895 menu->addAction(action);
897 action =
new QAction(
"Plot",
this);
899 menu->addAction(action);
903 action =
new QAction(
"Help",
this);
904 connect(action, SIGNAL(triggered()),
this, SLOT(
functionHelp()));
905 menu->addAction(action);
907 menu->addSeparator();
910 bool isTie = !isParameter && ci->property()->propertyName() ==
"Tie";
911 bool isLowerBound = !isParameter && ci->property()->propertyName() ==
"Lower Bound";
912 bool isUpperBound = !isParameter && ci->property()->propertyName() ==
"Upper Bound";
913 bool isType = isParameter && ci->property()->propertyName() ==
"Type";
918 action =
new QAction(
"Remove",
this);
919 connect(action, SIGNAL(triggered()),
this, SLOT(
deleteTie()));
920 menu->addAction(action);
921 }
else if (isLowerBound || isUpperBound) {
922 action =
new QAction(
"Remove",
this);
923 connect(action, SIGNAL(triggered()),
this, SLOT(
removeBounds()));
924 menu->addAction(action);
925 }
else if (
count() > 0 && isParameter) {
930 if (!hasTies && !hasBounds) {
931 action =
new QAction(
"Fix",
this);
932 connect(action, SIGNAL(triggered()),
this, SLOT(
addFixTie()));
933 menu->addAction(action);
937 QMenu *constraintMenu = menu->addMenu(
"Constraint");
939 QMenu *detailMenu = constraintMenu->addMenu(
"Lower Bound");
941 action =
new QAction(
"10%",
this);
943 detailMenu->addAction(action);
945 action =
new QAction(
"50%",
this);
947 detailMenu->addAction(action);
949 action =
new QAction(
"Custom",
this);
950 connect(action, SIGNAL(triggered()),
this, SLOT(
addLowerBound()));
951 detailMenu->addAction(action);
952 detailMenu = constraintMenu->addMenu(
"Upper Bound");
954 action =
new QAction(
"10%",
this);
956 detailMenu->addAction(action);
958 action =
new QAction(
"50%",
this);
960 detailMenu->addAction(action);
962 action =
new QAction(
"Custom",
this);
963 connect(action, SIGNAL(triggered()),
this, SLOT(
addUpperBound()));
964 detailMenu->addAction(action);
965 detailMenu = constraintMenu->addMenu(
"Both Bounds");
967 action =
new QAction(
"10%",
this);
969 detailMenu->addAction(action);
971 action =
new QAction(
"50%",
this);
973 detailMenu->addAction(action);
975 action =
new QAction(
"Custom",
this);
976 connect(action, SIGNAL(triggered()),
this, SLOT(
addBothBounds()));
977 detailMenu->addAction(action);
981 action =
new QAction(
"Remove constraints",
this);
982 connect(action, SIGNAL(triggered()),
this, SLOT(
removeBounds()));
983 menu->addAction(action);
986 if (!hasTies && !hasBounds) {
988 action =
new QAction(
"Tie",
this);
989 connect(action, SIGNAL(triggered()),
this, SLOT(
addTie()));
990 menu->addAction(action);
992 QMenu *detail = menu->addMenu(
"Tie");
994 action =
new QAction(
"To function",
this);
996 detail->addAction(action);
998 action =
new QAction(
"Custom Tie",
this);
999 connect(action, SIGNAL(triggered()),
this, SLOT(
addTie()));
1000 detail->addAction(action);
1002 }
else if (hasTies) {
1003 action =
new QAction(
"Remove tie",
this);
1004 connect(action, SIGNAL(triggered()),
this, SLOT(
deleteTie()));
1005 menu->addAction(action);
1010 menu->popup(QCursor::pos());
1016 QtBrowserItem *ci =
m_browser->currentItem();
1054 return std::shared_ptr<Mantid::API::Workspace>();
1058 return std::shared_ptr<Mantid::API::Workspace>();
1065 std::string res =
"";
1085 mws = std::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(
1091 if (wi < mws->getNumberHistograms() && !mws->x(wi).empty()) {
1126 if (withProperties) {
1130 if (!
value.isEmpty()) {
1131 minimStr +=
"," + prop->propertyName() +
"=" +
value;
1134 minimStr +=
"," + prop->propertyName() +
"=";
1136 minimStr += QString::number(
m_intManager->value(prop));
1142 throw std::runtime_error(
"The fit browser doesn't support the type "
1143 "of minimizer's property " +
1144 prop->propertyName().toStdString());
1149 return minimStr.toStdString();
1198 for (
const auto &fnName : names) {
1199 if (fnName ==
"MultiBG")
1203 function = functionFactory.createFunction(fnName);
1204 }
catch (std::exception &exc) {
1205 g_log.
warning() <<
"Unable to create " << fnName <<
": " << exc.what() <<
"\n";
1208 QString qfnName = QString::fromStdString(fnName);
1227 bool storeSettings =
false;
1233 }
else if (prop->propertyName() ==
"Type") {
1250 storeSettings =
true;
1253 if (storeSettings) {
1255 settings.beginGroup(
"Mantid/FitBrowser");
1257 settings.setValue(prop->propertyName(), val);
1273 settings.beginGroup(
"Mantid/FitBrowser");
1274 settings.setValue(prop->propertyName(), val);
1299 if (allowedIndex != currentIndex) {
1304 }
else if (prop->propertyName() ==
"Workspace Index") {
1310 }
else if (prop->propertyName() ==
"WorkspaceIndex") {
1313 auto const index = prop->valueText().toInt();
1322 settings.beginGroup(
"Mantid/FitBrowser");
1324 settings.setValue(prop->propertyName(), val);
1352 }
else if (prop ==
m_endX) {
1367 if (prop->propertyName() ==
"LowerBound") {
1370 }
else if (prop->propertyName() ==
"UpperBound") {
1382 if (vectorAttribute) {
1388 std::stringstream err_str;
1389 err_str << prop->propertyName().toStdString() <<
" - " << ve.what();
1416 if (oName.find_first_not_of(
' ') == std::string::npos) {
1423 }
else if (prop->propertyName() ==
"Tie") {
1432 QString parName = h->
functionPrefix() +
"." + parProp->propertyName();
1436 const auto parIndex =
compositeFunction()->parameterIndex(parName.toStdString());
1438 const auto oldTieStr = oldTie->asString();
1439 const auto oldExp = QString::fromStdString(oldTieStr.substr(oldTieStr.find(
"=") + 1));
1448 tie->
set(exp.toStdString());
1449 h->
addTie(parName +
"=" + exp);
1452 "Failed to update tie on " + parName.toStdString() +
". Expression " + exp.toStdString() +
" is invalid.";
1453 QMessageBox::critical(
this,
"Mantid - Error", msg.c_str());
1458 }
else if (
getHandler()->setAttribute(prop)) {
1563 if (wsName.empty()) {
1564 QMessageBox::critical(
this,
"Mantid - Error",
"Workspace name is not set");
1584 alg->setProperty(
"EvaluationType",
"Histogram");
1586 alg->setProperty(
"Function", std::dynamic_pointer_cast<Mantid::API::IFunction>(
compositeFunction())->clone());
1587 alg->setProperty(
"InputWorkspace", ws);
1588 auto tbl = std::dynamic_pointer_cast<ITableWorkspace>(ws);
1592 alg->setPropertyValue(
"XColumn",
getXColumnName().toStdString());
1593 alg->setPropertyValue(
"YColumn",
getYColumnName().toStdString());
1597 alg->setProperty(
"StartX",
startX());
1598 alg->setProperty(
"EndX",
endX());
1599 alg->setPropertyValue(
"Output",
outputName());
1600 alg->setPropertyValue(
"Minimizer",
minimizer(
true));
1610 alg->setProperty(
"OutputCompositeMembers",
true);
1611 if (alg->existsProperty(
"ConvolveMembers")) {
1616 if (alg->getPropertyValue(
"EvaluationType") !=
"Histogram")
1619 g_log.
warning(
"Exclude property not avaliable when evaluating as a histogram.");
1623 alg->executeAsync();
1625 }
catch (
const std::exception &e) {
1626 QString msg =
"Fit algorithm failed.\n\n" + QString(e.what()) +
"\n";
1627 QMessageBox::critical(
this,
"Mantid - Error", msg);
1654 QString name(QString::fromStdString(alg->
getProperty(
"InputWorkspace")));
1655 if (name.contains(
'_'))
1664 std::string out = alg->
getProperty(
"OutputWorkspace");
1673 double quality = alg->
getProperty(
"OutputChi2overDoF");
1675 std::shared_ptr<Mantid::API::ICostFunction> costfun =
1677 status = (status ==
"success") ?
"success" :
"failed";
1678 emit
changeWindowTitle(QString(
"Fit Function (") + costfun->shortName().c_str() +
" = " + QString::number(quality) +
1679 ", " + status +
")");
1689 return function->asString();
1696 text.replace(
"\n",
"<br>");
1697 QString color(
"green");
1698 if (status !=
"success") {
1702 m_status->setText(QString(
"Status: <span style='color:%2'>%1</span>").arg(text, color));
1717 QStringList allowedNames;
1719 for (
const auto &wsName : wsList) {
1720 auto const &name = QString::fromStdString(wsName);
1722 allowedNames << name;
1726 for (
const auto &name : allowedNames) {
1767 auto const qName = QString::fromStdString(wsName);
1774 bool initialSignalsBlocked =
m_enumManager->signalsBlocked();
1805 bool initialSignalsBlocked =
m_enumManager->signalsBlocked();
1807 if (QString::fromStdString(wsName) != oldName) {
1822 if (item->text().toStdString() == wsName) {
1834 QString oldNameQ = QString::fromStdString(oldName);
1835 QString newNameQ = QString::fromStdString(newName);
1843 if (iWorkspace >= 0) {
1851 if (item->text().toStdString() == oldName) {
1905 auto tbl = std::dynamic_pointer_cast<ITableWorkspace>(ws);
1906 auto mws = std::dynamic_pointer_cast<MatrixWorkspace>(ws);
1907 QVector<double> range;
1910 std::vector<double> xColumnData;
1911 auto col = tbl->getColumn(xColumnIndex);
1913 for (
size_t i = 0; i < tbl->rowCount(); ++i) {
1914 xColumnData.emplace_back(col->toDouble(i));
1916 }
catch (std::invalid_argument &err) {
1917 QMessageBox::critical(
this,
"Mantid - Error",
"The X column is not a number");
1918 throw std::invalid_argument(err);
1920 std::sort(xColumnData.begin(), xColumnData.end());
1921 range.push_back(xColumnData.front());
1922 range.push_back(xColumnData.back());
1925 range.push_back(xData.front());
1926 range.push_back(xData.back());
1933 auto tbl = std::dynamic_pointer_cast<ITableWorkspace>(ws);
1934 QString columnName =
"";
1936 auto columns = tbl->getColumnNames();
1938 if (xIndex >=
static_cast<int>(columns.size())) {
1939 QMessageBox::critical(
nullptr,
"Mantid - Error",
"X column was not found.");
1941 columnName = QString::fromStdString(columns[xIndex]);
1948 auto tbl = std::dynamic_pointer_cast<ITableWorkspace>(ws);
1949 QString columnName =
"";
1951 auto columns = tbl->getColumnNames();
1953 if (yIndex >=
static_cast<int>(columns.size())) {
1954 QMessageBox::critical(
nullptr,
"Mantid - Error",
"Y column was not found.");
1956 columnName = QString::fromStdString(columns[yIndex]);
1963 auto tbl = std::dynamic_pointer_cast<ITableWorkspace>(ws);
1964 QString columnName =
"";
1966 auto columns = tbl->getColumnNames();
1969 if (errIndex >=
static_cast<int>(columns.size())) {
1970 QMessageBox::warning(
nullptr,
"Mantid - Warning",
"Error column was not found.");
1971 }
else if (errIndex != -1) {
1972 columnName = QString::fromStdString(columns[errIndex]);
1981 QtBrowserItem *res =
nullptr;
1982 for (
auto &child : children) {
1983 if (child->property() == prop) {
1987 if (grand_children.size() > 0)
2051 foreach (QtProperty *prop, props) {
m_functionsGroup->property()->removeSubProperty(prop); }
2056 for (
auto paramIndex = 0u; paramIndex < finalFunction->nParams(); ++paramIndex) {
2057 compositeFunction()->setParameter(paramIndex, finalFunction->getParameter(paramIndex));
2104 QtBrowserItem *ci =
m_browser->currentItem();
2105 QtProperty *paramProp = ci->property();
2117 QString tieStr = QInputDialog::getText(
this,
"Mantid - Fit",
"Enter tie expression", QLineEdit::Normal,
"", &ok);
2119 tieStr = tieStr.trimmed();
2120 if (!tieStr.contains(
'=')) {
2121 tieStr = h->
functionPrefix() +
"." + paramProp->propertyName() +
"=" + tieStr;
2132 QtBrowserItem *ci =
m_browser->currentItem();
2133 QtProperty *paramProp = ci->property();
2139 std::string parName = paramProp->propertyName().toStdString();
2140 QStringList fnNames;
2149 if (iPar == -1 && fun == h->
function().get())
2158 if (fnNames.empty() || iPar < 0) {
2159 QMessageBox::information(
this,
"Mantid - information",
"Cannot tie this parameter to any function");
2164 QString tieName = QInputDialog::getItem(
this,
"Mantid - Fit",
"Select function", fnNames, 0,
false, &ok);
2169 QString tieExpr = QString::fromStdString(
m_compositeFunction->parameterName(iPar)) +
"=" + tieName;
2178 QtBrowserItem *ci =
m_browser->currentItem();
2179 QtProperty *paramProp = ci->property();
2185 h->
fix(paramProp->propertyName());
2192 QtBrowserItem *ci =
m_browser->currentItem();
2193 QtProperty *paramProp = ci->property();
2198 if (paramProp->propertyName() !=
"Tie") {
2199 auto parameterMap = h->
getTies();
2200 auto match = parameterMap.find(paramProp->propertyName());
2201 if (match != parameterMap.end()) {
2202 paramProp = match.value();
2205 if (paramProp->propertyName() ==
"Tie") {
2207 QString qParName = ties.key(paramProp,
"");
2208 std::string parName = qParName.toStdString();
2209 QStringList functionNames;
2211 int ithParameter = -1;
2217 if (ithParameter == -1 && function == h->
function().get())
2220 ithParameter =
static_cast<int>(i);
2227 if (functionNames.empty() && ithParameter < 0) {
2228 QMessageBox::information(
this,
"Mantid - information",
"Cannot find a parameter with this tie");
2230 QString tieExpr = QString::fromStdString(
m_compositeFunction->parameterName(ithParameter));
2231 h->
removeTie(paramProp, tieExpr.toStdString());
2234 h->
removeTie(ci->property()->propertyName());
2247 for (
auto &sub : subs) {
2248 if (sub->propertyName() ==
"Tie") {
2251 if (sub->propertyName() ==
"LowerBound") {
2254 if (sub->propertyName() ==
"UpperBound") {
2265 for (
auto &sub : subs) {
2266 if (sub->propertyName() ==
"Tie") {
2294 QtBrowserItem *ci =
m_browser->currentItem();
2295 QtProperty *parProp = ci->property();
2300 double x = parProp->valueText().toDouble();
2301 double loBound =
x * (1 - 0.01 * f);
2302 double upBound =
x * (1 + 0.01 * f);
2358 QtBrowserItem *ci =
m_browser->currentItem();
2359 QtProperty *parProp = ci->property();
2404 if (manager ==
nullptr)
2406 QtProperty *prop = manager->addProperty(name);
2408 manager->setRange(prop, -DBL_MAX, DBL_MAX);
2419 QString propName = name.toLower();
2420 if (propName ==
"filename") {
2422 }
else if (propName ==
"formula") {
2439 const std::vector<std::string> &allowed_values)
const {
2440 QStringList qAllowedValues;
2443 for (
const auto &values : allowed_values) {
2444 qAllowedValues << QString::fromStdString(values);
2457 auto *manager =
dynamic_cast<QtStringPropertyManager *
>(prop->propertyManager());
2459 manager->setValue(prop,
value);
2464 auto *manager =
dynamic_cast<QtStringPropertyManager *
>(prop->propertyManager());
2466 return manager->value(prop);
2486 auto const allowedIndices =
2488 auto const firstIndex =
m_allowedSpectra.empty() ? 0 : allowedIndices.front();
2491 auto allowedIndex = currentIndex;
2492 if (currentIndex < firstIndex) {
2493 allowedIndex = firstIndex;
2494 }
else if (currentIndex > lastIndex) {
2495 allowedIndex = lastIndex;
2496 }
else if (!
m_allowedSpectra.empty() && !allowedIndices.contains(currentIndex)) {
2501 if (i >= 0 && i < allowedIndices.size()) {
2502 allowedIndex = allowedIndices[i];
2506 return allowedIndex;
2511 QString fnName = QInputDialog::getText(
this, tr(
"Mantid - Input"), tr(
"Please select a name for the function"),
2512 QLineEdit::Normal,
"", &ok);
2513 if (ok && !fnName.isEmpty()) {
2520 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
2521 QStringList names = settings.childKeys();
2522 if (names.contains(fnName) && QMessageBox::question(
this,
"Mantid - Question",
2523 "Function with this name already exists.\n"
2524 "Would you like to replace it?",
2525 QMessageBox::Yes) != QMessageBox::Yes) {
2528 settings.setValue(fnName, QString::fromStdString(
theFunction()->asString()));
2534 settings.beginGroup(
"Mantid/FitBrowser/SavedFunctions");
2535 QStringList names = settings.childKeys();
2536 if (names.isEmpty()) {
2537 QMessageBox::information(
this,
"Mantid - Information",
"There are no saved functions");
2540 QString name = QInputDialog::getItem(
this,
"Mantid - Input",
"Please select a function to load", names, 0,
false);
2541 if (!name.isEmpty()) {
2542 QString str = settings.value(name).toString();
2549 QString str = QInputDialog::getText(
this,
"Mantid - Input",
"Specify fit function string");
2551 if (!str.isEmpty()) {
2559 bool isAutoBGset =
false;
2575 QClipboard *clipboard = QApplication::clipboard();
2576 clipboard->setText(QString::fromStdString(
theFunction()->asString()));
2580 QClipboard *clipboard = QApplication::clipboard();
2581 QString str = clipboard->text();
2586 QString str = QString::fromStdString(
theFunction()->asString());
2594 if (!wsName.empty()) {
2597 auto mws = std::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
2601 function->setWorkspace(ws);
2611 bool hasPlot =
false;
2627 foreach (QString att, attList) {
2628 QStringList name_value = att.split(
'=');
2629 if (name_value.size() == 2) {
2630 QString name = name_value[0].trimmed();
2631 QString
value = name_value[1].trimmed();
2632 if (h->
function()->hasAttribute(name.toStdString())) {
2664 QStringList nameList = aName.split(
' ');
2665 if (nameList.isEmpty())
2667 QString name = nameList[0];
2668 std::shared_ptr<Mantid::API::IFunction> f = std::shared_ptr<Mantid::API::IFunction>(
2672 if (nameList.size() > 1) {
2673 nameList.removeFirst();
2685 if (!wsName.empty() && dlg->addWorkspaces(QStringList(QString::fromStdString(wsName)))) {
2692 if (wsName.empty()) {
2693 QMessageBox::critical(
this,
"Mantid - Error",
"Workspace name is not set");
2697 std::string peakListName = wsName +
"_PeakList_tmp";
2702 FWHM = setting.isEmpty() ? 7 : setting.toInt();
2706 Tolerance = setting.isEmpty() ? 4 : setting.toInt();
2710 alg->setPropertyValue(
"InputWorkspace", wsName);
2712 alg->setPropertyValue(
"PeaksList", peakListName);
2713 alg->setProperty(
"FWHM", FWHM);
2714 alg->setProperty(
"Tolerance",
Tolerance);
2716 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
2730 for (
size_t i = 0; i <
centre.size(); ++i) {
2733 auto f = std::dynamic_pointer_cast<Mantid::API::IPeakFunction>(
2739 f->setFwhm(width[i]);
2744 QApplication::restoreOverrideCursor();
2748 QApplication::restoreOverrideCursor();
2762 settings.beginGroup(
"Mantid/FitBrowser");
2763 m_decimals = settings.value(
"decimals", 6).toInt();
2772 settings.beginGroup(
"Mantid/FitBrowser");
2773 settings.setValue(
"decimals",
d);
2809 QStringList ties = dlg->getParameterTies();
2811 if (!ties.isEmpty()) {
2817 QString fun1Ini = QString::fromStdString(fun->asString());
2818 QString funIni =
"composite=MultiBG;" + fun1Ini +
",Workspace=" + wsName +
",WSParam=(WorkspaceIndex=0);";
2820 for (
size_t i = 1; i < mws->getNumberHistograms(); ++i) {
2821 QString comma = i > 1 ?
"," :
"";
2822 QString fi = comma +
"f" + QString::number(i) +
".";
2823 for (
int j = 0; j < static_cast<int>(fun->nParams()); ++j) {
2824 if (!ties[j].isEmpty()) {
2825 tieStr += fi + QString::fromStdString(fun->parameterName(j)) +
"=" + ties[j];
2828 QString wsParam =
",WSParam=(WorkspaceIndex=" + QString::number(i);
2829 wsParam +=
",StartX=" + QString::number(
startX()) +
",EndX=" + QString::number(
endX()) +
")";
2830 funIni += fun1Ini +
",Workspace=" + wsName + wsParam +
";";
2832 if (!tieStr.isEmpty()) {
2833 funIni +=
"ties=(" + tieStr +
")";
2849 QStringList parNames;
2852 throw std::runtime_error(
"IFunction expected but func function of another type");
2854 for (
size_t i = 0; i < fun0->nParams(); ++i) {
2855 parNames << QString::fromStdString(fun0->parameterName(i));
2861 throw std::runtime_error(
"IFunction expected but func function of another type");
2863 for (
size_t j = 0; j < fun->nParams(); ++j) {
2864 if (parNames.indexOf(QString::fromStdString(fun->parameterName(j))) < 0) {
2871 QApplication::setOverrideCursor(Qt::WaitCursor);
2875 table->addColumn(
"int",
"Index");
2876 foreach (QString par, parNames) { table->addColumn(
"double", par.toStdString()); }
2900 group->setProperty(
"InputWorkspaces", worspaceNames);
2901 group->setPropertyValue(
"OutputWorkspace",
workspaceName() +
"_Workspace");
2905 QApplication::restoreOverrideCursor();
2944 auto mws = std::dynamic_pointer_cast<Mantid::API::MatrixWorkspace>(ws);
2947 auto isHistogram = mws->isHistogramData();
2957 auto tws = std::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(ws);
2969 auto names = tws->getColumnNames();
2970 QStringList columns;
2971 for (
const auto &name : names) {
2972 columns << QString::fromStdString(name);
2973 auto col = tws->getColumn(name);
2974 if (xName.isEmpty() && col->getPlotType() == 1 ) {
2975 xName = QString::fromStdString(name);
2977 if (yName.isEmpty() && col->getPlotType() == 2 ) {
2978 yName = QString::fromStdString(name);
2980 if (errName.isEmpty() && col->getPlotType() == 5 ) {
2981 errName = QString::fromStdString(name);
2987 if (!xName.isEmpty()) {
2990 foreach (QString name, columns) {
2991 if (name != yName) {
2997 if (!yName.isEmpty()) {
3000 foreach (QString name, columns) {
3001 if (name != xName) {
3007 columns.prepend(
"");
3009 if (!errName.isEmpty()) {
3052 for (
auto &prop : props) {
3053 if (propsToRemove.contains(prop->propertyName())) {
3070 auto tws = std::dynamic_pointer_cast<Mantid::API::ITableWorkspace>(ws);
3074 if (i < 0 || i >=
static_cast<int>(tws->rowCount()) || tws->rowCount() == 0)
3076 auto col = tws->getColumn(
static_cast<size_t>(i));
3077 const double startX = col->toDouble(0);
3078 const double endX = col->toDouble(tws->rowCount() - 1);
3096 auto &properties = minzer->getProperties();
3097 for (
auto property : properties) {
3098 QString propName = QString::fromStdString((*property).name());
3099 QtProperty *prop =
nullptr;
3118 QString val = QString::fromStdString(prp->value());
3122 m_stringManager->setValue(prop, QString::fromStdString((*property).value()));
3124 QMessageBox::warning(
this,
"Mantid - Error",
3125 "Type of minimizer's property " + propName +
" is not yet supported by the browser.");
3132 QString toolTip = QString::fromStdString((*property).documentation());
3133 if (!toolTip.isEmpty()) {
3134 prop->setToolTip(toolTip);
3146 size_t np = fun->nParams();
3148 for (
size_t i = 0; i < np; ++i) {
3149 const double parValue = fun->getParameter(i);
3150 out.append(parValue);
3160 size_t np = fun->nParams();
3162 for (
size_t i = 0; i < np; ++i) {
3163 std::string parName = fun->parameterName(i);
3164 out.append(QString::fromStdString(parName));
3193 "MantidPlot:_Simple_Peak_Fitting_with_the_Fit_"
3194 "Wizard#Fit_Properties_Browser"));
3221 return m_functionsGroup->children().size();
3225 auto const name = wsName.toStdString();
3229 indices.reserve(wsSpectra.size());
3230 std::transform(wsSpectra.cbegin(), wsSpectra.cend(), std::back_inserter(indices),
3231 [&ws](
const auto i) { return static_cast<int>(ws->getIndexFromSpectrumNumber(i)); });
3244 throw std::runtime_error(
"Workspace " + name +
" is not a MatrixWorkspace");
3251 QString qWsName = QString::fromStdString(wsName);
3256 auto const name = wsName.toStdString();
3261 throw std::runtime_error(
"Workspace " + name +
" is not a TableWorkspace");
3274 return addFunction(fnName.toStdString())->functionPrefix();
3278 if (prefix.isEmpty())
3279 throw std::runtime_error(
"Peak function prefix cannot be empty");
3280 auto const indexList = prefix.split(
".");
3281 auto const n = indexList.size() - 1;
3283 for (
int i = 0; i <
n; ++i) {
3284 auto const index = indexList[i].mid(1).toInt();
3285 handler = handler->getHandler(
index);
3287 return handler->getHandler(indexList[
n].mid(1).toInt());
3292 handler->setCentre(
value);
3293 handler->updateParameters();
3298 return handler->centre();
3303 handler->setHeight(
value);
3304 handler->updateParameters();
3309 return handler->height();
3314 handler->setFwhm(
value);
3315 handler->updateParameters();
3320 return handler->fwhm();
3325 return handler->getWidthParameterName();
3330 return handler->getCentreParameterName();
3335 return handler->isParameterExplicitlySet(param);
3341 auto nFunctions = parentHandler->cfun()->nFunctions();
3342 for (
size_t i = 0; i < nFunctions; ++i) {
3343 auto handler = parentHandler->getHandler(i);
3344 if (handler->pfun()) {
3345 peaks << handler->functionPrefix();
CostFunctions::CostFuncFitting & m_costFunction
The cost function.
double value
The value of the point.
IPeaksWorkspace_sptr workspace
std::map< DeltaEMode::Type, std::string > index
static void showFitFunction(const std::string &name=std::string())
static bool openUrl(const QUrl &url)
Opens a url in the appropriate web browser.
void observeAdd(bool on=true)
Observe additions.
void observePostDelete(bool on=true)
Observe workspace deletes.
void observeRename(bool on=true)
Observe renaming.
void observeFinish(const IAlgorithm_const_sptr &alg)
Connect to algorithm alg and observe its finish notification.
ColumnVector gives access to the column elements without alowing its resizing.
A composite function is a function containing other functions.
IFunction_sptr function() const
Return the handled function.
IAlgorithm is the interface implemented by the Algorithm base class.
An interface to a background function.
This is an interface to a fitting function - a semi-abstarct class.
virtual std::string parameterName(size_t i) const =0
Returns the name of parameter i.
An interface to a peak function, which extend the interface of IFunctionWithLocation by adding method...
ITableWorkspace is an implementation of Workspace in which the data are organised in columns of same ...
An interface that is implemented by WorkspaceProperty.
Base MatrixWorkspace Abstract Class.
A reference to a parameter in a function.
std::size_t getLocalIndex() const
Return parameter index in the local function.
IFunction * getLocalFunction() const
Return pointer to the local function.
virtual void set(const std::string &expr)
Set the tie expression.
Exception for when an item is not found in a collection.
virtual bool existsProperty(const std::string &name) const =0
Checks whether the named property is already in the list of managed property.
virtual TypedValue getProperty(const std::string &name) const =0
Get the value of a property.
virtual std::string getPropertyValue(const std::string &name) const =0
Get the value of a property as a string.
The Logger class is in charge of the publishing messages from the framework through various channels.
void warning(const std::string &msg)
Logs at warning level.
The concrete, templated class for properties.
Manage the lifetime of a class intended to be a singleton.
static T & Instance()
Return a reference to the Singleton instance, creating it if it does not already exist Creation is do...
The AlgorithmProgressDialogPresenter keeps track of the running algorithms and displays a progress ba...
std::shared_ptr< IAlgorithm > IAlgorithm_sptr
shared pointer to Mantid::API::IAlgorithm
const Poco::AutoPtr< FunctionFactoryUpdateNotification > & FunctionFactoryUpdateNotification_ptr
Convenient typedef for an UpdateNotification AutoPtr.
std::shared_ptr< ITableWorkspace > ITableWorkspace_sptr
shared pointer to Mantid::API::ITableWorkspace
std::shared_ptr< Workspace > Workspace_sptr
shared pointer to Mantid::API::Workspace
Kernel::Logger g_log("ExperimentInfo")
static logger object
std::shared_ptr< IFunction > IFunction_sptr
shared pointer to the function base class
std::shared_ptr< const IFunction > IFunction_const_sptr
shared pointer to the function base class (const version)
std::shared_ptr< MatrixWorkspace > MatrixWorkspace_sptr
shared pointer to the matrix workspace base class
std::shared_ptr< CompositeFunction > CompositeFunction_sptr
shared pointer to the composite function base class
constexpr double Tolerance
Standard tolerance value.
Helper class which provides the Collimation Length for SANS instruments.
Simple Exception Struct to differentiate validation error from other exceptions.