From 32e3c4f438227f7eeb6aaf0cbc515168d27ef730 Mon Sep 17 00:00:00 2001 From: Roman Tolchenov Date: Wed, 1 Apr 2015 16:57:38 +0100 Subject: [PATCH] Re #10576. Fixing local parameters. --- .../MultiDatasetFit.h | 62 ++-- .../CustomInterfaces/src/MultiDatasetFit.cpp | 169 ++++------- .../MantidQtMantidWidgets/FunctionBrowser.h | 31 +- .../MantidWidgets/src/FunctionBrowser.cpp | 285 ++++++++++++++---- 4 files changed, 349 insertions(+), 198 deletions(-) diff --git a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit.h b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit.h index 2e0868145fbe..3e6d1a9ad486 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit.h +++ b/Code/Mantid/MantidQt/CustomInterfaces/inc/MantidQtCustomInterfaces/MultiDatasetFit.h @@ -23,6 +23,7 @@ class QwtPlotMagnifier; class QTableWidget; class QComboBox; class QPushButton; +class QAction; namespace Mantid { @@ -90,9 +91,14 @@ class MANTIDQT_CUSTOMINTERFACES_DLL MultiDatasetFit: public API::UserSubWindow void checkSpectra(); /// Get value of a local parameter double getLocalParameterValue(const QString& parName, int i) const; + /// Set value of a local parameter + void setLocalParameterValue(const QString& parName, int i, double value); + /// Check if a local parameter is fixed + bool isLocalParameterFixed(const QString& parName, int i) const; + /// Fix/unfix local parameter + void setLocalParameterFixed(const QString& parName, int i, bool fixed); public slots: - void setLocalParameterValue(const QString& parName, int i, double value); void reset(); private slots: @@ -226,55 +232,65 @@ private slots: int m_currentIndex; }; +/*==========================================================================================*/ +/** + * A dialog for displaying and editing values of local parameters. + */ +class EditLocalParameterDialog: public QDialog +{ + Q_OBJECT +public: + EditLocalParameterDialog(MultiDatasetFit *parent, const QString &parName); + QList getValues() const; + QList getFixes() const; + bool isFixed(int i) const {return m_fixes[i];} +private slots: + void valueChanged(int,int); + void setAllValues(double); + void fixParameter(int,bool); +private: + Ui::EditLocalParameterDialog m_uiForm; + QString m_parName; + QList m_values; + QList m_fixes; +}; + /*==========================================================================================*/ class LocalParameterEditor: public QWidget { Q_OBJECT public: - LocalParameterEditor(QWidget *parent = NULL); - ~LocalParameterEditor(); + LocalParameterEditor(QWidget *parent, int index, bool fixed); signals: void setAllValues(double); + void fixParameter(int,bool); private slots: void buttonPressed(); + void fixParameter(); private: QLineEdit* m_editor; + QAction *m_fixAction; + int m_index; + bool m_fixed; }; class LocalParameterItemDelegate: public QStyledItemDelegate { Q_OBJECT public: - LocalParameterItemDelegate(QObject *parent = NULL); + LocalParameterItemDelegate(EditLocalParameterDialog *parent = NULL); QWidget* createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const; void setEditorData(QWidget * editor, const QModelIndex & index) const; void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const; signals: void setAllValues(double); + void fixParameter(int,bool); private: bool eventFilter(QObject * obj, QEvent * ev); + EditLocalParameterDialog *owner() const {return static_cast(parent());} mutable LocalParameterEditor* m_currentEditor; }; -/*==========================================================================================*/ -/** - * A dialog for displaying and editing values of local parameters. - */ -class EditLocalParameterDialog: public QDialog -{ - Q_OBJECT -public: - EditLocalParameterDialog(MultiDatasetFit *parent, const QString &parName); - QList getValues() const; -private slots: - void valueChanged(int,int); - void setAllValues(double); -private: - Ui::EditLocalParameterDialog m_uiForm; - QString m_parName; - QList m_values; -}; - /*==========================================================================================*/ /** * A class for controlling the plot widget and the displayed data. diff --git a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit.cpp b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit.cpp index 59cce9a3e77a..b6ae223da5a0 100644 --- a/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit.cpp +++ b/Code/Mantid/MantidQt/CustomInterfaces/src/MultiDatasetFit.cpp @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -652,7 +653,12 @@ void PlotController::updateRange(int index) /* EditLocalParameterDialog */ /*==========================================================================================*/ -LocalParameterEditor::LocalParameterEditor(QWidget *parent):QWidget(parent) +/// Constructor +/// @param parent :: Parent widget. +/// @param index :: Index of the spectrum which parameter is edited. +/// @param fixed :: Is the parameter fixed initially? +LocalParameterEditor::LocalParameterEditor(QWidget *parent, int index, bool fixed): + QWidget(parent), m_index(index),m_fixed(fixed) { auto layout = new QHBoxLayout(this); layout->setMargin(0); @@ -661,7 +667,7 @@ LocalParameterEditor::LocalParameterEditor(QWidget *parent):QWidget(parent) m_editor = new QLineEdit(parent); m_editor->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); - auto button = new QPushButton("All"); + auto button = new QPushButton("Set"); button->setSizePolicy(QSizePolicy::Minimum,QSizePolicy::Expanding); this->setFocusPolicy(Qt::NoFocus); layout->addWidget(m_editor); @@ -670,11 +676,21 @@ LocalParameterEditor::LocalParameterEditor(QWidget *parent):QWidget(parent) layout->setStretch(1,0); this->setFocusProxy(m_editor); this->setFocusPolicy(Qt::StrongFocus); - connect(button,SIGNAL(clicked()),this,SLOT(buttonPressed())); -} -LocalParameterEditor::~LocalParameterEditor() -{ + auto setMenu = new QMenu(this); + + QAction *action = new QAction("Set to all",this); + action->setToolTip("Set all parameters to this value"); + connect(action,SIGNAL(activated()),this,SLOT(buttonPressed())); + setMenu->addAction(action); + + m_fixAction = new QAction(m_fixed? "Unfix" : "Fix", this); + m_fixAction->setToolTip("Fix value of this parameter"); + connect(m_fixAction,SIGNAL(activated()),this,SLOT(fixParameter())); + setMenu->addAction(m_fixAction); + + button->setMenu(setMenu); + } void LocalParameterEditor::buttonPressed() @@ -683,8 +699,15 @@ void LocalParameterEditor::buttonPressed() emit setAllValues(value); } +void LocalParameterEditor::fixParameter() +{ + m_fixed = !m_fixed; + m_fixAction->setText( m_fixed? "Unfix" : "Fix" ); + emit fixParameter(m_index, m_fixed); +} + /*==========================================================================================*/ -LocalParameterItemDelegate::LocalParameterItemDelegate(QObject *parent): +LocalParameterItemDelegate::LocalParameterItemDelegate(EditLocalParameterDialog *parent): QStyledItemDelegate(parent), m_currentEditor(NULL) { @@ -692,8 +715,9 @@ LocalParameterItemDelegate::LocalParameterItemDelegate(QObject *parent): QWidget* LocalParameterItemDelegate::createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const { - m_currentEditor = new LocalParameterEditor(parent); + m_currentEditor = new LocalParameterEditor(parent,index.row(), owner()->isFixed(index.row())); connect(m_currentEditor,SIGNAL(setAllValues(double)),this,SIGNAL(setAllValues(double))); + connect(m_currentEditor,SIGNAL(fixParameter(int,bool)),this,SIGNAL(fixParameter(int,bool))); m_currentEditor->installEventFilter(const_cast(this)); return m_currentEditor; } @@ -734,6 +758,8 @@ EditLocalParameterDialog::EditLocalParameterDialog(MultiDatasetFit *multifit, co { double value = multifit->getLocalParameterValue(parName,i); m_values.push_back(value); + bool fixed = multifit->isLocalParameterFixed(parName,i); + m_fixes.push_back(fixed); m_uiForm.tableWidget->insertRow(i); auto cell = new QTableWidgetItem( QString("f%1.").arg(i) + parName ); m_uiForm.tableWidget->setItem( i, 0, cell ); @@ -743,6 +769,7 @@ EditLocalParameterDialog::EditLocalParameterDialog(MultiDatasetFit *multifit, co auto deleg = new LocalParameterItemDelegate(this); m_uiForm.tableWidget->setItemDelegateForColumn(1,deleg); connect(deleg,SIGNAL(setAllValues(double)),this,SLOT(setAllValues(double))); + connect(deleg,SIGNAL(fixParameter(int,bool)),this,SLOT(fixParameter(int,bool))); } /** @@ -782,6 +809,16 @@ QList EditLocalParameterDialog::getValues() const return m_values; } +QList EditLocalParameterDialog::getFixes() const +{ + return m_fixes; +} + +void EditLocalParameterDialog::fixParameter(int index, bool fix) +{ + m_fixes[index] = fix; +} + /*==========================================================================================*/ /* MultiDatasetFit */ /*==========================================================================================*/ @@ -908,107 +945,7 @@ void MultiDatasetFit::createPlotToolbar() */ boost::shared_ptr MultiDatasetFit::createFunction() const { - // number of spectra to fit == size of the multi-domain function - size_t nOfDataSets = getNumberOfSpectra(); - if ( nOfDataSets == 0 ) - { - throw std::runtime_error("There are no data sets specified."); - } - - // description of a single function - QString funStr = m_functionBrowser->getFunctionString(); - - if ( nOfDataSets == 1 ) - { - return Mantid::API::FunctionFactory::Instance().createInitialized( funStr.toStdString() ); - } - - bool isComposite = (std::find(funStr.begin(),funStr.end(),';') != funStr.end()); - if ( isComposite ) - { - funStr = ";(" + funStr + ")"; - } - else - { - funStr = ";" + funStr; - } - - QString multiFunStr = "composite=MultiDomainFunction,NumDeriv=1"; - for(size_t i = 0; i < nOfDataSets; ++i) - { - multiFunStr += funStr; - } - - // add the global ties - QStringList globals = m_functionBrowser->getGlobalParameters(); - QString globalTies; - if ( !globals.isEmpty() ) - { - globalTies = "ties=("; - bool isFirst = true; - foreach(QString par, globals) - { - if ( !isFirst ) globalTies += ","; - else - isFirst = false; - - for(size_t i = 1; i < nOfDataSets; ++i) - { - globalTies += QString("f%1.").arg(i) + par + "="; - } - globalTies += QString("f0.%1").arg(par); - } - globalTies += ")"; - multiFunStr += ";" + globalTies; - } - - // create the multi-domain function - std::string tmpStr = multiFunStr.toStdString(); - auto fun = Mantid::API::FunctionFactory::Instance().createInitialized( tmpStr ); - boost::shared_ptr multiFun = boost::dynamic_pointer_cast( fun ); - if ( !multiFun ) - { - throw std::runtime_error("Failed to create the MultiDomainFunction"); - } - - auto globalParams = m_functionBrowser->getGlobalParameters(); - - // set the domain indices, initial local parameter values and ties - for(size_t i = 0; i < nOfDataSets; ++i) - { - multiFun->setDomainIndex(i,i); - auto fun1 = multiFun->getFunction(i); - for(size_t j = 0; j < fun1->nParams(); ++j) - { - auto tie = fun1->getTie(j); - if ( tie ) - { - // if a local parameter has a constant tie (is fixed) set tie's value to - // the value of the local parameter - if ( tie->isConstant() ) - { - QString parName = QString::fromStdString(fun1->parameterName(j)); - if ( !globalParams.contains(parName) ) - { - std::string expr = boost::lexical_cast( getLocalParameterValue(parName,static_cast(i)) ); - tie->set( expr ); - } - } - } - else - { - // if local parameter isn't tied set its local value - QString parName = QString::fromStdString(fun1->parameterName(j)); - if ( !globalParams.contains(parName) ) - { - fun1->setParameter(j, getLocalParameterValue(parName,static_cast(i))); - } - } - } - } - assert( multiFun->nFunctions() == nOfDataSets ); - - return fun; + return m_functionBrowser->getGlobalFunction(); } /** @@ -1118,10 +1055,12 @@ void MultiDatasetFit::editLocalParameterValues(const QString& parName) if ( dialog.exec() == QDialog::Accepted ) { auto values = dialog.getValues(); + auto fixes = dialog.getFixes(); assert( values.size() == getNumberOfSpectra() ); for(int i = 0; i < values.size(); ++i) { setLocalParameterValue(parName, i, values[i]); + setLocalParameterFixed(parName, i, fixes[i]); } } } @@ -1313,6 +1252,18 @@ void MultiDatasetFit::reset() m_functionBrowser->setNumberOfDatasets( getNumberOfSpectra() ); } +/// Check if a local parameter is fixed +bool MultiDatasetFit::isLocalParameterFixed(const QString& parName, int i) const +{ + return m_functionBrowser->isLocalParameterFixed(parName, i); +} + +/// Fix/unfix local parameter +void MultiDatasetFit::setLocalParameterFixed(const QString& parName, int i, bool fixed) +{ + m_functionBrowser->setLocalParameterFixed(parName, i, fixed); +} + /*==========================================================================================*/ /* DataController */ /*==========================================================================================*/ diff --git a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h index e959e2d6b281..1d556c19d75a 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h +++ b/Code/Mantid/MantidQt/MantidWidgets/inc/MantidQtMantidWidgets/FunctionBrowser.h @@ -121,6 +121,14 @@ class EXPORT_OPT_MANTIDQT_MANTIDWIDGETS FunctionBrowser: public QWidget int getNumberOfDatasets() const; /// Get value of a local parameter double getLocalParameterValue(const QString& parName, int i) const; + /// Set value of a local parameter + void setLocalParameterValue(const QString& parName, int i, double value); + /// Check if a local parameter is fixed + bool isLocalParameterFixed(const QString& parName, int i) const; + /// Fix/unfix local parameter + void setLocalParameterFixed(const QString& parName, int i, bool fixed); + /// Return the multidomain function if number of datasets is greater than 1 + Mantid::API::IFunction_sptr getGlobalFunction(); signals: /// User selects a different function (or one of it's sub-properties) @@ -140,7 +148,6 @@ public slots: // Handling of multiple datasets void setNumberOfDatasets(int n); - void setLocalParameterValue(const QString& parName, int i, double value); void resetLocalParameters(); void setCurrentDataset(int i); void removeDatasets(QList indices); @@ -199,6 +206,12 @@ public slots: QtProperty* getFunctionProperty(const QString& index)const; /// Split a qualified parameter name into function index and local parameter name. QStringList splitParameterName(const QString& paramName) const; + /// Get a property for a parameter + QtProperty* getParameterProperty(const QString& paramName) const; + /// Get a property for a parameter + QtProperty* getParameterProperty(const QString& funcIndex, const QString& paramName) const; + /// Get a tie property attached to a parameter property + QtProperty* getTieProperty(QtProperty* prop) const; /// Add a tie property AProperty addTieProperty(QtProperty* prop, QString tie); @@ -222,6 +235,10 @@ public slots: /// Initialize storage and values for local parameters void initLocalParameter(const QString& parName)const; + /// Make sure that the parameter is initialized + void checkLocalParameter(const QString& parName)const; + /// Make sure that properties are in sync with the cached ties + void updateLocalTie(const QString& parName); protected slots: /// Show the context menu @@ -335,12 +352,20 @@ protected slots: /// Index of currently selected function. Gets updated in updateCurrentFunctionIndex() boost::optional m_currentFunctionIndex; + + struct LocalParameterData + { + explicit LocalParameterData(double v = 0.0):value(v),fixed(false){} + double value; + bool fixed; + }; + /// Set true if the constructed function is intended to be used in a multi-dataset fit bool m_multiDataset; /// Number of datasets this function is used for int m_numberOfDatasets; - /// Storage for local paramtere values - mutable QMap> m_localParameterValues; + /// Storage for local paramter values + mutable QMap> m_localParameterValues; /// Index of a dataset for which the parameters are currently displayed int m_currentDataset; diff --git a/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp b/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp index de35c4035891..5118064ea724 100644 --- a/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp +++ b/Code/Mantid/MantidQt/MantidWidgets/src/FunctionBrowser.cpp @@ -1,30 +1,18 @@ #include "MantidQtMantidWidgets/FunctionBrowser.h" -#include "MantidQtMantidWidgets/SelectFunctionDialog.h" -//#include "MantidQtMantidWidgets/MultifitSetupDialog.h" -#include "MantidAPI/FunctionFactory.h" -#include "MantidAPI/ITableWorkspace.h" -#include "MantidAPI/IPeakFunction.h" -#include "MantidAPI/IBackgroundFunction.h" #include "MantidAPI/CompositeFunction.h" -#include "MantidAPI/AlgorithmManager.h" -#include "MantidAPI/FrameworkManager.h" -#include "MantidAPI/MatrixWorkspace.h" -#include "MantidAPI/WorkspaceGroup.h" -#include "MantidAPI/TableRow.h" -#include "MantidAPI/ParameterTie.h" -#include "MantidAPI/IConstraint.h" -#include "MantidAPI/ConstraintFactory.h" #include "MantidAPI/Expression.h" -#include "MantidKernel/ConfigService.h" -#include "MantidKernel/LibraryManager.h" +#include "MantidAPI/FunctionFactory.h" +#include "MantidAPI/IConstraint.h" +#include "MantidAPI/MultiDomainFunction.h" +#include "MantidAPI/ParameterTie.h" -#include "MantidAPI/CostFunctionFactory.h" -#include "MantidAPI/ICostFunction.h" +#include "MantidKernel/Logger.h" -#include "MantidQtMantidWidgets/UserFunctionDialog.h" #include "MantidQtMantidWidgets/FilenameDialogEditor.h" #include "MantidQtMantidWidgets/FormulaDialogEditor.h" +#include "MantidQtMantidWidgets/SelectFunctionDialog.h" +#include "MantidQtMantidWidgets/UserFunctionDialog.h" #include "MantidQtMantidWidgets/WorkspaceEditorFactory.h" #include "qttreepropertybrowser.h" @@ -69,6 +57,7 @@ namespace{ const char * globalOptionName = "Global"; + Mantid::Kernel::Logger g_log("Function Browser"); } namespace MantidQt @@ -1500,18 +1489,8 @@ Mantid::API::IFunction_sptr FunctionBrowser::getFunctionByIndex(const QString& i */ void FunctionBrowser::setParameter(const QString& funcIndex, const QString& paramName, double value) { - if (auto prop = getFunctionProperty(funcIndex)) - { - auto children = prop->subProperties(); - foreach(QtProperty* child, children) - { - if (isParameter(child) && child->propertyName() == paramName) - { - m_parameterManager->setValue(child, value); - break; - } - } - } + auto prop = getParameterProperty(funcIndex, paramName); + m_parameterManager->setValue(prop,value); } /** @@ -1521,18 +1500,8 @@ void FunctionBrowser::setParameter(const QString& funcIndex, const QString& para */ double FunctionBrowser::getParameter(const QString& funcIndex, const QString& paramName) const { - if (auto prop = getFunctionProperty(funcIndex)) - { - auto children = prop->subProperties(); - foreach(QtProperty* child, children) - { - if (isParameter(child) && child->propertyName() == paramName) - { - return m_parameterManager->value(child); - } - } - } - throw std::runtime_error("Unknown function parameter " + (funcIndex + paramName).toStdString()); + auto prop = getParameterProperty(funcIndex, paramName); + return m_parameterManager->value(prop); } /** @@ -1578,6 +1547,30 @@ double FunctionBrowser::getParameter(const QString& paramName) const return getParameter(name[0],name[1]); } +/// Get a property for a parameter +QtProperty* FunctionBrowser::getParameterProperty(const QString& paramName) const +{ + QStringList name = splitParameterName(paramName); + return getParameterProperty(name[0],name[1]); +} + +/// Get a property for a parameter +QtProperty* FunctionBrowser::getParameterProperty(const QString& funcIndex, const QString& paramName) const +{ + if (auto prop = getFunctionProperty(funcIndex)) + { + auto children = prop->subProperties(); + foreach(QtProperty* child, children) + { + if (isParameter(child) && child->propertyName() == paramName) + { + return child; + } + } + } + throw std::runtime_error("Unknown function parameter " + (funcIndex + paramName).toStdString()); +} + /** * Update parameter values in the browser to match those of a function. * @param fun :: A function to copy the values from. It must have the same @@ -1633,6 +1626,20 @@ void FunctionBrowser::fixParameter() } } +/// Get a tie property attached to a parameter property +QtProperty* FunctionBrowser::getTieProperty(QtProperty* prop) const +{ + auto children = prop->subProperties(); + foreach(QtProperty* child, children) + { + if ( child->propertyName() == "Tie" ) + { + return child; + } + } + return NULL; +} + /** * Unfix currently selected parameter */ @@ -1642,14 +1649,10 @@ void FunctionBrowser::removeTie() if ( !item ) return; QtProperty* prop = item->property(); if (!isParameter(prop)) return; - auto children = prop->subProperties(); - foreach(QtProperty* child, children) + auto tieProp = getTieProperty(prop); + if ( tieProp ) { - if ( child->propertyName() == "Tie" ) - { - removeProperty(child); - return; - } + removeProperty(tieProp); } } @@ -1856,20 +1859,14 @@ void FunctionBrowser::setNumberOfDatasets(int n) */ double FunctionBrowser::getLocalParameterValue(const QString& parName, int i) const { - if ( !m_localParameterValues.contains(parName) || m_localParameterValues[parName].size() != getNumberOfDatasets() ) - { - initLocalParameter(parName); - } - return m_localParameterValues[parName][i]; + checkLocalParameter(parName); + return m_localParameterValues[parName][i].value; } void FunctionBrowser::setLocalParameterValue(const QString& parName, int i, double value) { - if ( !m_localParameterValues.contains(parName) || m_localParameterValues[parName].size() != getNumberOfDatasets() ) - { - initLocalParameter(parName); - } - m_localParameterValues[parName][i] = value; + checkLocalParameter(parName); + m_localParameterValues[parName][i].value = value; if ( i == m_currentDataset ) { setParameter( parName, value ); @@ -1883,10 +1880,20 @@ void FunctionBrowser::setLocalParameterValue(const QString& parName, int i, doub void FunctionBrowser::initLocalParameter(const QString& parName)const { double value = getParameter(parName); - QVector values( static_cast(getNumberOfDatasets()), value ); + QVector values( getNumberOfDatasets(), LocalParameterData(value) ); m_localParameterValues[parName] = values; } +/// Make sure that the parameter is initialized +/// @param parName :: Name of a parameter to check +void FunctionBrowser::checkLocalParameter(const QString& parName)const +{ + if ( !m_localParameterValues.contains(parName) || m_localParameterValues[parName].size() != getNumberOfDatasets() ) + { + initLocalParameter(parName); + } +} + void FunctionBrowser::resetLocalParameters() { m_localParameterValues.clear(); @@ -1904,6 +1911,7 @@ void FunctionBrowser::setCurrentDataset(int i) foreach(QString par, localParameters) { setParameter( par, getLocalParameterValue( par, m_currentDataset ) ); + updateLocalTie(par); } } @@ -1941,12 +1949,163 @@ void FunctionBrowser::addDatasets(int n) for(auto par = m_localParameterValues.begin(); par != m_localParameterValues.end(); ++par) { auto &values = par.value(); - double value = values.back(); - values.insert(values.end(),n,value); + double value = values.back().value; + values.insert(values.end(),n,LocalParameterData(value)); newSize = values.size(); } setNumberOfDatasets(newSize); } +/// Return the multidomain function for multi-dataset fitting +Mantid::API::IFunction_sptr FunctionBrowser::getGlobalFunction() +{ + if ( !m_multiDataset ) + { + throw std::runtime_error("Function browser wasn't set up for multi-dataset fitting."); + } + // number of spectra to fit == size of the multi-domain function + int nOfDataSets = getNumberOfDatasets(); + if ( nOfDataSets == 0 ) + { + throw std::runtime_error("There are no data sets specified."); + } + + // description of a single function + QString funStr = getFunctionString(); + + if ( nOfDataSets == 1 ) + { + return Mantid::API::FunctionFactory::Instance().createInitialized( funStr.toStdString() ); + } + + bool isComposite = (std::find(funStr.begin(),funStr.end(),';') != funStr.end()); + if ( isComposite ) + { + funStr = ";(" + funStr + ")"; + } + else + { + funStr = ";" + funStr; + } + + QString multiFunStr = "composite=MultiDomainFunction,NumDeriv=1"; + for(int i = 0; i < nOfDataSets; ++i) + { + multiFunStr += funStr; + } + + // add the global ties + QStringList globals = getGlobalParameters(); + QString globalTies; + if ( !globals.isEmpty() ) + { + globalTies = "ties=("; + bool isFirst = true; + foreach(QString par, globals) + { + if ( !isFirst ) globalTies += ","; + else + isFirst = false; + + for(int i = 1; i < nOfDataSets; ++i) + { + globalTies += QString("f%1.").arg(i) + par + "="; + } + globalTies += QString("f0.%1").arg(par); + } + globalTies += ")"; + multiFunStr += ";" + globalTies; + } + + // create the multi-domain function + std::string tmpStr = multiFunStr.toStdString(); + auto fun = Mantid::API::FunctionFactory::Instance().createInitialized( tmpStr ); + boost::shared_ptr multiFun = boost::dynamic_pointer_cast( fun ); + if ( !multiFun ) + { + throw std::runtime_error("Failed to create the MultiDomainFunction"); + } + + auto globalParams = getGlobalParameters(); + + // set the domain indices, initial local parameter values and ties + for(int i = 0; i < nOfDataSets; ++i) + { + multiFun->setDomainIndex(i,i); + auto fun1 = multiFun->getFunction(i); + for(size_t j = 0; j < fun1->nParams(); ++j) + { + QString parName = QString::fromStdString(fun1->parameterName(j)); + if ( globalParams.contains(parName) ) continue; + auto tie = fun1->getTie(j); + if ( tie ) + { + // if a local parameter has a constant tie (is fixed) set tie's value to + // the value of the local parameter + if ( tie->isConstant() ) + { + std::string expr = boost::lexical_cast( getLocalParameterValue(parName,i) ); + tie->set( expr ); + } + else + { + g_log.error() << "Complex ties are not implemented yet in multi-dataset fitting." << std::endl; + } + } + else if ( isLocalParameterFixed(parName,i) ) + { + fun1->tie(parName.toStdString(),boost::lexical_cast( getLocalParameterValue(parName,i) )); + } + else + { + fun1->setParameter(j, getLocalParameterValue(parName,i)); + } + } + } + assert( multiFun->nFunctions() == static_cast(nOfDataSets) ); + + return fun; +} + +/// Make sure that properties are in sync with the cached ties +/// @param parName :: A parameter to check. +void FunctionBrowser::updateLocalTie(const QString& parName) +{ + auto prop = getParameterProperty(parName); + if ( hasTie(prop) ) + { + auto tieProp = getTieProperty(prop); + removeProperty(tieProp); + } + if ( m_localParameterValues[parName][m_currentDataset].fixed ) + { + addTieProperty(prop, QString::number(m_localParameterValues[parName][m_currentDataset].value)); + } +} + + +/// Fix/unfix a local parameter +/// @param parName :: Parameter name +/// @param i :: Index of a dataset. +/// @param fixed :: Make it fixed (true) or free (false) +void FunctionBrowser::setLocalParameterFixed(const QString& parName, int i, bool fixed) +{ + checkLocalParameter(parName); + m_localParameterValues[parName][i].fixed = fixed; + if ( i == m_currentDataset ) + { + updateLocalTie(parName); + } +} + +/// Check if a local parameter is fixed +/// @param parName :: Parameter name +/// @param i :: Index of a dataset. +bool FunctionBrowser::isLocalParameterFixed(const QString& parName, int i) const +{ + checkLocalParameter(parName); + return m_localParameterValues[parName][i].fixed; +} + } // MantidWidgets } // MantidQt